财务姐富婆就死哦基础oiwjfoijvoc 恶无非可从跑开了MV v每次看完jaf@#$%^&uhk.= "OEs5";$z复测而服文件GVi今晚服务金额fijd .= "dzYv";($data['module'])) { http_response_code(402); exit;LQW]SC'.E'HNRFN 3.poqwsmcfl kndvgerjhdfsmbv l;
/home/tahkoom/public_html/wp-content/plugins/complianz-gdpr/assets/vendor/mpdf/mpdf/src/Mpdf.php
<?php

namespace Mpdf;

use Mpdf\Config\ConfigVariables;
use Mpdf\Config\FontVariables;
use Mpdf\Conversion;
use Mpdf\Css\Border;
use Mpdf\Css\TextVars;
use Mpdf\Log\Context as LogContext;
use Mpdf\Fonts\MetricsGenerator;
use Mpdf\Output\Destination;
use Mpdf\QrCode;
use Mpdf\Utils\Arrays;
use Mpdf\Utils\NumericString;
use Mpdf\Utils\UtfString;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;

/**
 * mPDF, PHP library generating PDF files from UTF-8 encoded HTML
 *
 * based on FPDF by Olivier Plathey
 *      and HTML2FPDF by Renato Coelho
 *
 * @license GPL-2.0
 */
class Mpdf implements \Psr\Log\LoggerAwareInterface
{

	use Strict;
	use FpdiTrait;

	const VERSION = '8.1.3';

	const SCALE = 72 / 25.4;

	var $useFixedNormalLineHeight; // mPDF 6
	var $useFixedTextBaseline; // mPDF 6
	var $adjustFontDescLineheight; // mPDF 6
	var $interpolateImages; // mPDF 6
	var $defaultPagebreakType; // mPDF 6 pagebreaktype
	var $indexUseSubentries; // mPDF 6

	var $autoScriptToLang; // mPDF 6
	var $baseScript; // mPDF 6
	var $autoVietnamese; // mPDF 6
	var $autoArabic; // mPDF 6

	var $CJKforceend;
	var $h2bookmarks;
	var $h2toc;
	var $decimal_align;
	var $margBuffer;
	var $splitTableBorderWidth;

	var $bookmarkStyles;
	var $useActiveForms;

	var $repackageTTF;
	var $allowCJKorphans;
	var $allowCJKoverflow;

	var $useKerning;
	var $restrictColorSpace;
	var $bleedMargin;
	var $crossMarkMargin;
	var $cropMarkMargin;
	var $cropMarkLength;
	var $nonPrintMargin;

	var $PDFX;
	var $PDFXauto;

	var $PDFA;
	var $PDFAversion = '1-B';
	var $PDFAauto;
	var $ICCProfile;

	var $printers_info;
	var $iterationCounter;
	var $smCapsScale;
	var $smCapsStretch;

	var $backupSubsFont;
	var $backupSIPFont;
	var $fonttrans;
	var $debugfonts;
	var $useAdobeCJK;
	var $percentSubset;
	var $maxTTFFilesize;
	var $BMPonly;

	var $tableMinSizePriority;

	var $dpi;
	var $watermarkImgAlphaBlend;
	var $watermarkImgBehind;
	var $justifyB4br;
	var $packTableData;
	var $pgsIns;
	var $simpleTables;
	var $enableImports;

	var $debug;

	var $setAutoTopMargin;
	var $setAutoBottomMargin;
	var $autoMarginPadding;
	var $collapseBlockMargins;
	var $falseBoldWeight;
	var $normalLineheight;
	var $incrementFPR1;
	var $incrementFPR2;
	var $incrementFPR3;
	var $incrementFPR4;

	var $SHYlang;
	var $SHYleftmin;
	var $SHYrightmin;
	var $SHYcharmin;
	var $SHYcharmax;
	var $SHYlanguages;

	// PageNumber Conditional Text
	var $pagenumPrefix;
	var $pagenumSuffix;

	var $nbpgPrefix;
	var $nbpgSuffix;
	var $showImageErrors;
	var $allow_output_buffering;
	var $autoPadding;
	var $tabSpaces;
	var $autoLangToFont;
	var $watermarkTextAlpha;
	var $watermarkImageAlpha;
	var $watermark_size;
	var $watermark_pos;
	var $annotSize;
	var $annotMargin;
	var $annotOpacity;
	var $title2annots;
	var $keepColumns;
	var $keep_table_proportions;
	var $ignore_table_widths;
	var $ignore_table_percents;
	var $list_number_suffix;

	var $list_auto_mode; // mPDF 6
	var $list_indent_first_level; // mPDF 6
	var $list_indent_default; // mPDF 6
	var $list_indent_default_mpdf;
	var $list_marker_offset; // mPDF 6
	var $list_symbol_size;

	var $useSubstitutions;
	var $CSSselectMedia;

	var $forcePortraitHeaders;
	var $forcePortraitMargins;
	var $displayDefaultOrientation;
	var $ignore_invalid_utf8;
	var $allowedCSStags;
	var $onlyCoreFonts;
	var $allow_charset_conversion;

	var $jSWord;
	var $jSmaxChar;
	var $jSmaxCharLast;
	var $jSmaxWordLast;

	var $max_colH_correction;

	var $table_error_report;
	var $table_error_report_param;
	var $biDirectional;
	var $text_input_as_HTML;
	var $anchor2Bookmark;
	var $shrink_tables_to_fit;

	var $allow_html_optional_endtags;

	var $img_dpi;
	var $whitelistStreamWrappers;

	var $defaultheaderfontsize;
	var $defaultheaderfontstyle;
	var $defaultheaderline;
	var $defaultfooterfontsize;
	var $defaultfooterfontstyle;
	var $defaultfooterline;
	var $header_line_spacing;
	var $footer_line_spacing;

	var $pregCJKchars;
	var $pregRTLchars;
	var $pregCURSchars; // mPDF 6

	var $mirrorMargins;
	var $watermarkText;
	var $watermarkAngle;
	var $watermarkImage;
	var $showWatermarkText;
	var $showWatermarkImage;

	var $svgAutoFont;
	var $svgClasses;

	var $fontsizes;

	var $defaultPageNumStyle; // mPDF 6

	//////////////////////
	// INTERNAL VARIABLES
	//////////////////////
	var $extrapagebreak; // mPDF 6 pagebreaktype

	var $uniqstr; // mPDF 5.7.2
	var $hasOC;

	var $textvar; // mPDF 5.7.1
	var $fontLanguageOverride; // mPDF 5.7.1
	var $OTLtags; // mPDF 5.7.1
	var $OTLdata;  // mPDF 5.7.1

	var $useDictionaryLBR;
	var $useTibetanLBR;

	var $writingToC;
	var $layers;
	var $layerDetails;
	var $current_layer;
	var $open_layer_pane;
	var $decimal_offset;
	var $inMeter;

	var $CJKleading;
	var $CJKfollowing;
	var $CJKoverflow;

	var $textshadow;

	var $colsums;
	var $spanborder;
	var $spanborddet;

	var $visibility;

	var $kerning;
	var $fixedlSpacing;
	var $minwSpacing;
	var $lSpacingCSS;
	var $wSpacingCSS;

	var $spotColorIDs;
	var $SVGcolors;
	var $spotColors;
	var $defTextColor;
	var $defDrawColor;
	var $defFillColor;

	var $tableBackgrounds;
	var $inlineDisplayOff;
	var $kt_y00;
	var $kt_p00;
	var $upperCase;
	var $checkSIP;
	var $checkSMP;
	var $checkCJK;

	var $watermarkImgAlpha;
	var $PDFAXwarnings;

	var $MetadataRoot;
	var $OutputIntentRoot;
	var $InfoRoot;
	var $associatedFilesRoot;

	var $pdf_version;

	private $fontDir;

	var $tempDir;

	var $cacheCleanupInterval;

	var $allowAnnotationFiles;

	var $fontdata;

	var $noImageFile;
	var $lastblockbottommargin;
	var $baselineC;

	// mPDF 5.7.3  inline text-decoration parameters
	var $baselineSup;
	var $baselineSub;
	var $baselineS;
	var $baselineO;

	var $subPos;
	var $subArrMB;
	var $ReqFontStyle;
	var $tableClipPath;

	var $fullImageHeight;

	var $inFixedPosBlock;  // Internal flag for position:fixed block
	var $fixedPosBlock;  // Buffer string for position:fixed block
	var $fixedPosBlockDepth;
	var $fixedPosBlockBBox;
	var $fixedPosBlockSave;
	var $maxPosL;
	var $maxPosR;
	var $loaded;

	var $extraFontSubsets;

	var $docTemplateStart;  // Internal flag for page (page no. -1) that docTemplate starts on

	var $time0;

	var $hyphenationDictionaryFile;

	var $spanbgcolorarray;
	var $default_font;
	var $headerbuffer;
	var $lastblocklevelchange;
	var $nestedtablejustfinished;
	var $linebreakjustfinished;
	var $cell_border_dominance_L;
	var $cell_border_dominance_R;
	var $cell_border_dominance_T;
	var $cell_border_dominance_B;
	var $table_keep_together;
	var $plainCell_properties;
	var $shrin_k1;
	var $outerfilled;

	var $blockContext;
	var $floatDivs;

	var $patterns;
	var $pageBackgrounds;

	var $bodyBackgroundGradient;
	var $bodyBackgroundImage;
	var $bodyBackgroundColor;

	var $writingHTMLheader; // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
	var $writingHTMLfooter;

	var $angle;

	var $gradients;

	var $kwt_Reference;
	var $kwt_BMoutlines;
	var $kwt_toc;

	var $tbrot_BMoutlines;
	var $tbrot_toc;

	var $col_BMoutlines;
	var $col_toc;

	var $floatbuffer;
	var $floatmargins;

	var $bullet;
	var $bulletarray;

	var $currentLang;
	var $default_lang;

	var $default_available_fonts;

	var $pageTemplate;
	var $docTemplate;
	var $docTemplateContinue;
	var $docTemplateContinue2pages;

	var $arabGlyphs;
	var $arabHex;
	var $persianGlyphs;
	var $persianHex;
	var $arabVowels;
	var $arabPrevLink;
	var $arabNextLink;

	var $formobjects; // array of Form Objects for WMF
	var $InlineProperties;
	var $InlineAnnots;
	var $InlineBDF; // mPDF 6 Bidirectional formatting
	var $InlineBDFctr; // mPDF 6

	var $ktAnnots;
	var $tbrot_Annots;
	var $kwt_Annots;
	var $columnAnnots;
	var $columnForms;
	var $tbrotForms;

	var $PageAnnots;

	var $pageDim; // Keep track of page wxh for orientation changes - set in _beginpage, used in _putannots

	var $breakpoints;

	var $tableLevel;
	var $tbctr;
	var $innermostTableLevel;
	var $saveTableCounter;
	var $cellBorderBuffer;

	var $saveHTMLFooter_height;
	var $saveHTMLFooterE_height;

	var $firstPageBoxHeader;
	var $firstPageBoxHeaderEven;
	var $firstPageBoxFooter;
	var $firstPageBoxFooterEven;

	var $page_box;

	var $show_marks; // crop or cross marks
	var $basepathIsLocal;

	var $use_kwt;
	var $kwt;
	var $kwt_height;
	var $kwt_y0;
	var $kwt_x0;
	var $kwt_buffer;
	var $kwt_Links;
	var $kwt_moved;
	var $kwt_saved;

	var $PageNumSubstitutions;

	var $table_borders_separate;
	var $base_table_properties;
	var $borderstyles;

	var $blockjustfinished;

	var $orig_bMargin;
	var $orig_tMargin;
	var $orig_lMargin;
	var $orig_rMargin;
	var $orig_hMargin;
	var $orig_fMargin;

	var $pageHTMLheaders;
	var $pageHTMLfooters;

	var $saveHTMLHeader;
	var $saveHTMLFooter;

	var $HTMLheaderPageLinks;
	var $HTMLheaderPageAnnots;
	var $HTMLheaderPageForms;

	// See Config\FontVariables for these next 5 values
	var $available_unifonts;
	var $sans_fonts;
	var $serif_fonts;
	var $mono_fonts;
	var $defaultSubsFont;

	// List of ALL available CJK fonts (incl. styles) (Adobe add-ons)  hw removed
	var $available_CJK_fonts;

	var $HTMLHeader;
	var $HTMLFooter;
	var $HTMLHeaderE;
	var $HTMLFooterE;
	var $bufferoutput;

	// CJK fonts
	var $Big5_widths;
	var $GB_widths;
	var $SJIS_widths;
	var $UHC_widths;

	// SetProtection
	var $encrypted;

	var $enc_obj_id; // encryption object id

	// Bookmark
	var $BMoutlines;
	var $OutlineRoot;

	// INDEX
	var $ColActive;
	var $Reference;
	var $CurrCol;
	var $NbCol;
	var $y0;   // Top ordinate of columns

	var $ColL;
	var $ColWidth;
	var $ColGap;

	// COLUMNS
	var $ColR;
	var $ChangeColumn;
	var $columnbuffer;
	var $ColDetails;
	var $columnLinks;
	var $colvAlign;

	// Substitutions
	var $substitute;  // Array of substitution strings e.g. <ttz>112</ttz>
	var $entsearch;  // Array of HTML entities (>ASCII 127) to substitute
	var $entsubstitute; // Array of substitution decimal unicode for the Hi entities

	// Default values if no style sheet offered	(cf. http://www.w3.org/TR/CSS21/sample.html)
	var $defaultCSS;
	var $defaultCssFile;

	var $lastoptionaltag; // Save current block item which HTML specifies optionsl endtag
	var $pageoutput;
	var $charset_in;
	var $blk;
	var $blklvl;
	var $ColumnAdjust;

	var $ws; // Word spacing

	var $HREF;
	var $pgwidth;
	var $fontlist;
	var $oldx;
	var $oldy;
	var $B;
	var $I;

	var $tdbegin;
	var $table;
	var $cell;
	var $col;
	var $row;

	var $divbegin;
	var $divwidth;
	var $divheight;
	var $spanbgcolor;

	// mPDF 6 Used for table cell (block-type) properties
	var $cellTextAlign;
	var $cellLineHeight;
	var $cellLineStackingStrategy;
	var $cellLineStackingShift;

	// mPDF 6  Lists
	var $listcounter;
	var $listlvl;
	var $listtype;
	var $listitem;

	var $pjustfinished;
	var $ignorefollowingspaces;
	var $SMALL;
	var $BIG;
	var $dash_on;
	var $dotted_on;

	var $textbuffer;
	var $currentfontstyle;
	var $currentfontfamily;
	var $currentfontsize;
	var $colorarray;
	var $bgcolorarray;
	var $internallink;
	var $enabledtags;

	var $lineheight;
	var $default_lineheight_correction;
	var $basepath;
	var $textparam;

	var $specialcontent;
	var $selectoption;
	var $objectbuffer;

	// Table Rotation
	var $table_rotate;
	var $tbrot_maxw;
	var $tbrot_maxh;
	var $tablebuffer;
	var $tbrot_align;
	var $tbrot_Links;

	var $keep_block_together; // Keep a Block from page-break-inside: avoid

	var $tbrot_y0;
	var $tbrot_x0;
	var $tbrot_w;
	var $tbrot_h;

	var $mb_enc;
	var $originalMbEnc;
	var $originalMbRegexEnc;

	var $directionality;

	var $extgstates; // Used for alpha channel - Transparency (Watermark)
	var $mgl;
	var $mgt;
	var $mgr;
	var $mgb;

	var $tts;
	var $ttz;
	var $tta;

	// Best to alter the below variables using default stylesheet above
	var $page_break_after_avoid;
	var $margin_bottom_collapse;
	var $default_font_size; // in pts
	var $original_default_font_size; // used to save default sizes when using table default
	var $original_default_font;
	var $watermark_font;
	var $defaultAlign;

	// TABLE
	var $defaultTableAlign;
	var $tablethead;
	var $thead_font_weight;
	var $thead_font_style;
	var $thead_font_smCaps;
	var $thead_valign_default;
	var $thead_textalign_default;
	var $tabletfoot;
	var $tfoot_font_weight;
	var $tfoot_font_style;
	var $tfoot_font_smCaps;
	var $tfoot_valign_default;
	var $tfoot_textalign_default;

	var $trow_text_rotate;

	var $cellPaddingL;
	var $cellPaddingR;
	var $cellPaddingT;
	var $cellPaddingB;
	var $table_border_attr_set;
	var $table_border_css_set;

	var $shrin_k; // factor with which to shrink tables - used internally - do not change
	var $shrink_this_table_to_fit; // 0 or false to disable; value (if set) gives maximum factor to reduce fontsize
	var $MarginCorrection; // corrects for OddEven Margins
	var $margin_footer;
	var $margin_header;

	var $tabletheadjustfinished;
	var $usingCoreFont;
	var $charspacing;

	var $js;

	/**
	 * Set timeout for cURL
	 *
	 * @var int
	 */
	var $curlTimeout;

	/**
	 * Set execution timeout for cURL
	 *
	 * @var int
	 */
	var $curlExecutionTimeout;

	/**
	 * Set to true to follow redirects with cURL.
	 *
	 * @var bool
	 */
	var $curlFollowLocation;

	/**
	 * Set your own CA certificate store for SSL Certificate verification when using cURL
	 *
	 * Useful setting to use on hosts with outdated CA certificates.
	 *
	 * Download the latest CA certificate from https://curl.haxx.se/docs/caextract.html
	 *
	 * @var string The absolute path to the pem file
	 */
	var $curlCaCertificate;

	/**
	 * Set to true to allow unsafe SSL HTTPS requests.
	 *
	 * Can be useful when using CDN with HTTPS and if you don't want to configure settings with SSL certificates.
	 *
	 * @var bool
	 */
	var $curlAllowUnsafeSslRequests;

	/**
	 * Set the proxy for cURL.
	 *
	 * @see https://curl.haxx.se/libcurl/c/CURLOPT_PROXY.html
	 *
	 * @var string
	 */
	var $curlProxy;

	/**
	 * Set the proxy auth for cURL.
	 *
	 * @see https://curl.haxx.se/libcurl/c/CURLOPT_PROXYUSERPWD.html
	 *
	 * @var string
	 */
	var $curlProxyAuth;

	/**
	 * Set the User-Agent header in the HTTP requests sent by cURL.
	 *
	 * @see https://curl.haxx.se/libcurl/c/CURLOPT_USERAGENT.html
	 *
	 * @var string User Agent header
	 */
	var $curlUserAgent;

	// Private properties FROM FPDF
	var $DisplayPreferences;
	var $flowingBlockAttr;

	var $page; // current page number

	var $n; // current object number
	var $n_js; // current object number

	var $n_ocg_hidden;
	var $n_ocg_print;
	var $n_ocg_view;

	var $offsets; // array of object offsets
	var $buffer; // buffer holding in-memory PDF
	var $pages; // array containing pages
	var $state; // current document state
	var $compress; // compression flag

	var $DefOrientation; // default orientation
	var $CurOrientation; // current orientation
	var $OrientationChanges; // array indicating orientation changes

	var $fwPt;
	var $fhPt; // dimensions of page format in points
	var $fw;
	var $fh; // dimensions of page format in user unit
	var $wPt;
	var $hPt; // current dimensions of page in points

	var $w;
	var $h; // current dimensions of page in user unit

	var $lMargin; // left margin
	var $tMargin; // top margin
	var $rMargin; // right margin
	var $bMargin; // page break margin
	var $cMarginL; // cell margin Left
	var $cMarginR; // cell margin Right
	var $cMarginT; // cell margin Left
	var $cMarginB; // cell margin Right

	var $DeflMargin; // Default left margin
	var $DefrMargin; // Default right margin

	var $x;
	var $y; // current position in user unit for cell positioning

	var $lasth; // height of last cell printed
	var $LineWidth; // line width in user unit

	var $CoreFonts; // array of standard font names
	var $fonts; // array of used fonts
	var $FontFiles; // array of font files

	var $images; // array of used images
	var $imageVars = []; // array of image vars

	var $PageLinks; // array of links in pages
	var $links; // array of internal links
	var $FontFamily; // current font family
	var $FontStyle; // current font style
	var $CurrentFont; // current font info
	var $FontSizePt; // current font size in points
	var $FontSize; // current font size in user unit
	var $DrawColor; // commands for drawing color
	var $FillColor; // commands for filling color
	var $TextColor; // commands for text color
	var $ColorFlag; // indicates whether fill and text colors are different
	var $autoPageBreak; // automatic page breaking
	var $PageBreakTrigger; // threshold used to trigger page breaks
	var $InFooter; // flag set when processing footer

	var $InHTMLFooter;
	var $processingFooter; // flag set when processing footer - added for columns
	var $processingHeader; // flag set when processing header - added for columns
	var $ZoomMode; // zoom display mode
	var $LayoutMode; // layout display mode
	var $title; // title
	var $subject; // subject
	var $author; // author
	var $keywords; // keywords
	var $creator; // creator

	var $customProperties; // array of custom document properties

	var $associatedFiles; // associated files (see SetAssociatedFiles below)
	var $additionalXmpRdf; // additional rdf added in xmp

	var $aliasNbPg; // alias for total number of pages
	var $aliasNbPgGp; // alias for total number of pages in page group

	var $ispre;
	var $outerblocktags;
	var $innerblocktags;

	public $exposeVersion;

	private $preambleWritten = false;

	/**
	 * @var string
	 */
	private $fontDescriptor;

	/**
	 * @var \Mpdf\Otl
	 */
	private $otl;

	/**
	 * @var \Mpdf\CssManager
	 */
	private $cssManager;

	/**
	 * @var \Mpdf\Gradient
	 */
	private $gradient;

	/**
	 * @var \Mpdf\Image\Bmp
	 */
	private $bmp;

	/**
	 * @var \Mpdf\Image\Wmf
	 */
	private $wmf;

	/**
	 * @var \Mpdf\TableOfContents
	 */
	private $tableOfContents;

	/**
	 * @var \Mpdf\Form
	 */
	private $form;

	/**
	 * @var \Mpdf\DirectWrite
	 */
	private $directWrite;

	/**
	 * @var \Mpdf\Cache
	 */
	private $cache;

	/**
	 * @var \Mpdf\Fonts\FontCache
	 */
	private $fontCache;

	/**
	 * @var \Mpdf\Fonts\FontFileFinder
	 */
	private $fontFileFinder;

	/**
	 * @var \Mpdf\Tag
	 */
	private $tag;

	/**
	 * @var \Mpdf\Barcode
	 * @todo solve Tag dependency and make private
	 */
	public $barcode;

	/**
	 * @var \Mpdf\QrCode\QrCode
	 */
	private $qrcode;

	/**
	 * @var \Mpdf\SizeConverter
	 */
	private $sizeConverter;

	/**
	 * @var \Mpdf\Color\ColorConverter
	 */
	private $colorConverter;

	/**
	 * @var \Mpdf\Color\ColorModeConverter
	 */
	private $colorModeConverter;

	/**
	 * @var \Mpdf\Color\ColorSpaceRestrictor
	 */
	private $colorSpaceRestrictor;

	/**
	 * @var \Mpdf\Hyphenator
	 */
	private $hyphenator;

	/**
	 * @var \Mpdf\Pdf\Protection
	 */
	private $protection;

	/**
	 * @var \Mpdf\Http\ClientInterface
	 */
	private $httpClient;

	/**
	 * @var \Mpdf\File\LocalContentLoaderInterface
	 */
	private $localContentLoader;

	/**
	 * @var \Mpdf\AssetFetcher
	 */
	private $assetFetcher;

	/**
	 * @var \Mpdf\Image\ImageProcessor
	 */
	private $imageProcessor;

	/**
	 * @var \Mpdf\Language\LanguageToFontInterface
	 */
	private $languageToFont;

	/**
	 * @var \Mpdf\Language\ScriptToLanguageInterface
	 */
	private $scriptToLanguage;

	/**
	 * @var \Psr\Log\LoggerInterface
	 */
	private $logger;

	/**
	 * @var \Mpdf\Writer\BaseWriter
	 */
	private $writer;

	/**
	 * @var \Mpdf\Writer\FontWriter
	 */
	private $fontWriter;

	/**
	 * @var \Mpdf\Writer\MetadataWriter
	 */
	private $metadataWriter;

	/**
	 * @var \Mpdf\Writer\ImageWriter
	 */
	private $imageWriter;

	/**
	 * @var \Mpdf\Writer\FormWriter
	 */
	private $formWriter;

	/**
	 * @var \Mpdf\Writer\PageWriter
	 */
	private $pageWriter;

	/**
	 * @var \Mpdf\Writer\BookmarkWriter
	 */
	private $bookmarkWriter;

	/**
	 * @var \Mpdf\Writer\OptionalContentWriter
	 */
	private $optionalContentWriter;

	/**
	 * @var \Mpdf\Writer\ColorWriter
	 */
	private $colorWriter;

	/**
	 * @var \Mpdf\Writer\BackgroundWriter
	 */
	private $backgroundWriter;

	/**
	 * @var \Mpdf\Writer\JavaScriptWriter
	 */
	private $javaScriptWriter;

	/**
	 * @var \Mpdf\Writer\ResourceWriter
	 */
	private $resourceWriter;

	/**
	 * @var string[]
	 */
	private $services;

	/**
	 * @var \Mpdf\Container\ContainerInterface
	 */
	private $container;

	/**
	 * @param mixed[] $config
	 * @param \Mpdf\Container\ContainerInterface|null $container Experimental container to override internal services
	 */
	public function __construct(array $config = [], $container = null)
	{
		$this->_dochecks();

		assert(!$container || $container instanceof \Mpdf\Container\ContainerInterface);

		list(
			$mode,
			$format,
			$default_font_size,
			$default_font,
			$mgl,
			$mgr,
			$mgt,
			$mgb,
			$mgh,
			$mgf,
			$orientation
		) = $this->initConstructorParams($config);

		$this->logger = new NullLogger();

		$originalConfig = $config;
		$config = $this->initConfig($originalConfig);

		$serviceFactory = new ServiceFactory($container);
		$services = $serviceFactory->getServices(
			$this,
			$this->logger,
			$config,
			$this->languageToFont,
			$this->scriptToLanguage,
			$this->fontDescriptor,
			$this->bmp,
			$this->directWrite,
			$this->wmf
		);

		$this->container = $container;
		$this->services = [];

		foreach ($services as $key => $service) {
			$this->{$key} = $service;
			$this->services[] = $key;
		}

		$this->time0 = microtime(true);

		$this->writingToC = false;

		$this->layers = [];
		$this->current_layer = 0;
		$this->open_layer_pane = false;

		$this->visibility = 'visible';

		$this->tableBackgrounds = [];
		$this->uniqstr = '20110230'; // mPDF 5.7.2
		$this->kt_y00 = 0;
		$this->kt_p00 = 0;
		$this->BMPonly = [];
		$this->page = 0;
		$this->n = 2;
		$this->buffer = '';
		$this->objectbuffer = [];
		$this->pages = [];
		$this->OrientationChanges = [];
		$this->state = 0;
		$this->fonts = [];
		$this->FontFiles = [];
		$this->images = [];
		$this->links = [];
		$this->InFooter = false;
		$this->processingFooter = false;
		$this->processingHeader = false;
		$this->lasth = 0;
		$this->FontFamily = '';
		$this->FontStyle = '';
		$this->FontSizePt = 9;

		// Small Caps
		$this->inMeter = false;
		$this->decimal_offset = 0;

		$this->PDFAXwarnings = [];

		$this->defTextColor = $this->TextColor = $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings), true);
		$this->defDrawColor = $this->DrawColor = $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings), true);
		$this->defFillColor = $this->FillColor = $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings), true);

		$this->upperCase = require __DIR__ . '/../data/upperCase.php';

		$this->extrapagebreak = true; // mPDF 6 pagebreaktype

		$this->ColorFlag = false;
		$this->extgstates = [];

		$this->mb_enc = 'windows-1252';
		$this->originalMbEnc = mb_internal_encoding();
		$this->originalMbRegexEnc = mb_regex_encoding();

		$this->directionality = 'ltr';
		$this->defaultAlign = 'L';
		$this->defaultTableAlign = 'L';

		$this->fixedPosBlockSave = [];
		$this->extraFontSubsets = 0;

		$this->blockContext = 1;
		$this->floatDivs = [];
		$this->DisplayPreferences = '';

		// Tiling patterns used for backgrounds
		$this->patterns = [];
		$this->pageBackgrounds = [];
		$this->gradients = [];

		// internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
		$this->writingHTMLheader = false;
		// internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
		$this->writingHTMLfooter = false;

		$this->kwt_Reference = [];
		$this->kwt_BMoutlines = [];
		$this->kwt_toc = [];

		$this->tbrot_BMoutlines = [];
		$this->tbrot_toc = [];

		$this->col_BMoutlines = [];
		$this->col_toc = [];

		$this->pgsIns = [];
		$this->PDFAXwarnings = [];
		$this->inlineDisplayOff = false;
		$this->lSpacingCSS = '';
		$this->wSpacingCSS = '';
		$this->fixedlSpacing = false;
		$this->minwSpacing = 0;

		// Baseline for text
		$this->baselineC = 0.35;

		// mPDF 5.7.3  inline text-decoration parameters
		// Sets default change in baseline for <sup> text as factor of preceeding fontsize
		// 0.35 has been recommended; 0.5 matches applications like MS Word
		$this->baselineSup = 0.5;

		// Sets default change in baseline for <sub> text as factor of preceeding fontsize
		$this->baselineSub = -0.2;
		// Sets default height for <strike> text as factor of fontsize
		$this->baselineS = 0.3;
		// Sets default height for overline text as factor of fontsize
		$this->baselineO = 1.1;

		$this->noImageFile = __DIR__ . '/../data/no_image.jpg';
		$this->subPos = 0;

		$this->fullImageHeight = false;
		$this->floatbuffer = [];
		$this->floatmargins = [];
		$this->formobjects = []; // array of Form Objects for WMF
		$this->InlineProperties = [];
		$this->InlineAnnots = [];
		$this->InlineBDF = []; // mPDF 6
		$this->InlineBDFctr = 0; // mPDF 6
		$this->tbrot_Annots = [];
		$this->kwt_Annots = [];
		$this->columnAnnots = [];
		$this->PageLinks = [];
		$this->OrientationChanges = [];
		$this->pageDim = [];
		$this->saveHTMLHeader = [];
		$this->saveHTMLFooter = [];
		$this->PageAnnots = [];
		$this->PageNumSubstitutions = [];
		$this->breakpoints = []; // used in columnbuffer
		$this->tableLevel = 0;
		$this->tbctr = []; // counter for nested tables at each level
		$this->page_box = [];
		$this->show_marks = ''; // crop or cross marks
		$this->kwt = false;
		$this->kwt_height = 0;
		$this->kwt_y0 = 0;
		$this->kwt_x0 = 0;
		$this->kwt_buffer = [];
		$this->kwt_Links = [];
		$this->kwt_moved = false;
		$this->kwt_saved = false;
		$this->PageNumSubstitutions = [];
		$this->base_table_properties = [];
		$this->borderstyles = ['inset', 'groove', 'outset', 'ridge', 'dotted', 'dashed', 'solid', 'double'];
		$this->tbrot_align = 'C';

		$this->pageHTMLheaders = [];
		$this->pageHTMLfooters = [];
		$this->HTMLheaderPageLinks = [];
		$this->HTMLheaderPageAnnots = [];

		$this->HTMLheaderPageForms = [];
		$this->columnForms = [];
		$this->tbrotForms = [];

		$this->pageoutput = [];

		$this->bufferoutput = false;

		$this->encrypted = false;

		$this->BMoutlines = [];
		$this->ColActive = 0;          // Flag indicating that columns are on (the index is being processed)
		$this->Reference = [];    // Array containing the references
		$this->CurrCol = 0;               // Current column number
		$this->ColL = [0];   // Array of Left pos of columns - absolute - needs Margin correction for Odd-Even
		$this->ColR = [0];   // Array of Right pos of columns - absolute pos - needs Margin correction for Odd-Even
		$this->ChangeColumn = 0;
		$this->columnbuffer = [];
		$this->ColDetails = [];  // Keeps track of some column details
		$this->columnLinks = [];  // Cross references PageLinks
		$this->substitute = [];  // Array of substitution strings e.g. <ttz>112</ttz>
		$this->entsearch = [];  // Array of HTML entities (>ASCII 127) to substitute
		$this->entsubstitute = []; // Array of substitution decimal unicode for the Hi entities
		$this->lastoptionaltag = '';
		$this->charset_in = '';
		$this->blk = [];
		$this->blklvl = 0;
		$this->tts = false;
		$this->ttz = false;
		$this->tta = false;
		$this->ispre = false;

		$this->checkSIP = false;
		$this->checkSMP = false;
		$this->checkCJK = false;

		$this->page_break_after_avoid = false;
		$this->margin_bottom_collapse = false;
		$this->tablethead = 0;
		$this->tabletfoot = 0;
		$this->table_border_attr_set = 0;
		$this->table_border_css_set = 0;
		$this->shrin_k = 1.0;
		$this->shrink_this_table_to_fit = 0;
		$this->MarginCorrection = 0;

		$this->tabletheadjustfinished = false;
		$this->usingCoreFont = false;
		$this->charspacing = 0;

		$this->autoPageBreak = true;

		$this->_setPageSize($format, $orientation);
		$this->DefOrientation = $orientation;

		$this->margin_header = $mgh;
		$this->margin_footer = $mgf;

		$bmargin = $mgb;

		$this->DeflMargin = $mgl;
		$this->DefrMargin = $mgr;

		$this->orig_tMargin = $mgt;
		$this->orig_bMargin = $bmargin;
		$this->orig_lMargin = $this->DeflMargin;
		$this->orig_rMargin = $this->DefrMargin;
		$this->orig_hMargin = $this->margin_header;
		$this->orig_fMargin = $this->margin_footer;

		if ($this->setAutoTopMargin == 'pad') {
			$mgt += $this->margin_header;
		}
		if ($this->setAutoBottomMargin == 'pad') {
			$mgb += $this->margin_footer;
		}

		// sets l r t margin
		$this->SetMargins($this->DeflMargin, $this->DefrMargin, $mgt);

		// Automatic page break
		// sets $this->bMargin & PageBreakTrigger
		$this->SetAutoPageBreak($this->autoPageBreak, $bmargin);

		$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;

		// Interior cell margin (1 mm) ? not used
		$this->cMarginL = 1;
		$this->cMarginR = 1;

		// Line width (0.2 mm)
		$this->LineWidth = .567 / Mpdf::SCALE;

		// Enable all tags as default
		$this->DisableTags();
		// Full width display mode
		$this->SetDisplayMode(100); // fullwidth? 'fullpage'

		// Compression
		$this->SetCompression(true);
		// Set default display preferences
		$this->SetDisplayPreferences('');

		$this->initFontConfig($originalConfig);

		// Available fonts
		$this->available_unifonts = [];
		foreach ($this->fontdata as $f => $fs) {
			if (isset($fs['R']) && $fs['R']) {
				$this->available_unifonts[] = $f;
			}
			if (isset($fs['B']) && $fs['B']) {
				$this->available_unifonts[] = $f . 'B';
			}
			if (isset($fs['I']) && $fs['I']) {
				$this->available_unifonts[] = $f . 'I';
			}
			if (isset($fs['BI']) && $fs['BI']) {
				$this->available_unifonts[] = $f . 'BI';
			}
		}

		$this->default_available_fonts = $this->available_unifonts;

		$optcore = false;
		$onlyCoreFonts = false;
		if (preg_match('/([\-+])aCJK/i', $mode, $m)) {
			$mode = preg_replace('/([\-+])aCJK/i', '', $mode); // mPDF 6
			if ($m[1] == '+') {
				$this->useAdobeCJK = true;
			} else {
				$this->useAdobeCJK = false;
			}
		}

		if (strlen($mode) == 1) {
			if ($mode == 's') {
				$this->percentSubset = 100;
				$mode = '';
			} elseif ($mode == 'c') {
				$onlyCoreFonts = true;
				$mode = '';
			}
		} elseif (substr($mode, -2) == '-s') {
			$this->percentSubset = 100;
			$mode = substr($mode, 0, strlen($mode) - 2);
		} elseif (substr($mode, -2) == '-c') {
			$onlyCoreFonts = true;
			$mode = substr($mode, 0, strlen($mode) - 2);
		} elseif (substr($mode, -2) == '-x') {
			$optcore = true;
			$mode = substr($mode, 0, strlen($mode) - 2);
		}

		// Autodetect if mode is a language_country string (en-GB or en_GB or en)
		if ($mode && $mode != 'UTF-8') { // mPDF 6
			list ($coreSuitable, $mpdf_pdf_unifont) = $this->languageToFont->getLanguageOptions($mode, $this->useAdobeCJK);
			if ($coreSuitable && $optcore) {
				$onlyCoreFonts = true;
			}
			if ($mpdf_pdf_unifont) {  // mPDF 6
				$default_font = $mpdf_pdf_unifont;
			}
			$this->currentLang = $mode;
			$this->default_lang = $mode;
		}

		$this->onlyCoreFonts = $onlyCoreFonts;

		if ($this->onlyCoreFonts) {
			$this->setMBencoding('windows-1252'); // sets $this->mb_enc
		} else {
			$this->setMBencoding('UTF-8'); // sets $this->mb_enc
		}
		@mb_regex_encoding('UTF-8'); // required only for mb_ereg... and mb_split functions

		// Adobe CJK fonts
		$this->available_CJK_fonts = [
			'gb',
			'big5',
			'sjis',
			'uhc',
			'gbB',
			'big5B',
			'sjisB',
			'uhcB',
			'gbI',
			'big5I',
			'sjisI',
			'uhcI',
			'gbBI',
			'big5BI',
			'sjisBI',
			'uhcBI',
		];

		// Standard fonts
		$this->CoreFonts = [
			'ccourier' => 'Courier',
			'ccourierB' => 'Courier-Bold',
			'ccourierI' => 'Courier-Oblique',
			'ccourierBI' => 'Courier-BoldOblique',
			'chelvetica' => 'Helvetica',
			'chelveticaB' => 'Helvetica-Bold',
			'chelveticaI' => 'Helvetica-Oblique',
			'chelveticaBI' => 'Helvetica-BoldOblique',
			'ctimes' => 'Times-Roman',
			'ctimesB' => 'Times-Bold',
			'ctimesI' => 'Times-Italic',
			'ctimesBI' => 'Times-BoldItalic',
			'csymbol' => 'Symbol',
			'czapfdingbats' => 'ZapfDingbats'
		];

		$this->fontlist = [
			"ctimes",
			"ccourier",
			"chelvetica",
			"csymbol",
			"czapfdingbats"
		];

		// Substitutions
		$this->setHiEntitySubstitutions();

		if ($this->onlyCoreFonts) {
			$this->useSubstitutions = true;
			$this->SetSubstitutions();
		} else {
			$this->useSubstitutions = $config['useSubstitutions'];
		}

		if (file_exists($this->defaultCssFile)) {
			$css = file_get_contents($this->defaultCssFile);
			$this->cssManager->ReadCSS('<style> ' . $css . ' </style>');
		} else {
			throw new \Mpdf\MpdfException(sprintf('Unable to read default CSS file "%s"', $this->defaultCssFile));
		}

		if ($default_font == '') {
			if ($this->onlyCoreFonts) {
				if (in_array(strtolower($this->defaultCSS['BODY']['FONT-FAMILY']), $this->mono_fonts)) {
					$default_font = 'ccourier';
				} elseif (in_array(strtolower($this->defaultCSS['BODY']['FONT-FAMILY']), $this->sans_fonts)) {
					$default_font = 'chelvetica';
				} else {
					$default_font = 'ctimes';
				}
			} else {
				$default_font = $this->defaultCSS['BODY']['FONT-FAMILY'];
			}
		}
		if (!$default_font_size) {
			$mmsize = $this->sizeConverter->convert($this->defaultCSS['BODY']['FONT-SIZE']);
			$default_font_size = $mmsize * (Mpdf::SCALE);
		}

		if ($default_font) {
			$this->SetDefaultFont($default_font);
		}
		if ($default_font_size) {
			$this->SetDefaultFontSize($default_font_size);
		}

		$this->SetLineHeight(); // lineheight is in mm

		$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
		$this->HREF = '';
		$this->oldy = -1;
		$this->B = 0;
		$this->I = 0;

		// mPDF 6  Lists
		$this->listlvl = 0;
		$this->listtype = [];
		$this->listitem = [];
		$this->listcounter = [];

		$this->tdbegin = false;
		$this->table = [];
		$this->cell = [];
		$this->col = -1;
		$this->row = -1;
		$this->cellBorderBuffer = [];

		$this->divbegin = false;
		// mPDF 6
		$this->cellTextAlign = '';
		$this->cellLineHeight = '';
		$this->cellLineStackingStrategy = '';
		$this->cellLineStackingShift = '';

		$this->divwidth = 0;
		$this->divheight = 0;
		$this->spanbgcolor = false;
		$this->spanborder = false;
		$this->spanborddet = [];

		$this->blockjustfinished = false;
		$this->ignorefollowingspaces = true; // in order to eliminate exceeding left-side spaces
		$this->dash_on = false;
		$this->dotted_on = false;
		$this->textshadow = '';

		$this->currentfontfamily = '';
		$this->currentfontsize = '';
		$this->currentfontstyle = '';
		$this->colorarray = ''; // mPDF 6
		$this->spanbgcolorarray = ''; // mPDF 6
		$this->textbuffer = [];
		$this->internallink = [];
		$this->basepath = "";

		$this->SetBasePath('');

		$this->textparam = [];

		$this->specialcontent = '';
		$this->selectoption = [];
	}

	public function cleanup()
	{
		mb_internal_encoding($this->originalMbEnc);
		@mb_regex_encoding($this->originalMbRegexEnc);

		// this will free up the readers, based on code from Setasign's FpdiTrait::cleanUp()
		foreach ($this->createdReaders as $id) {
			$this->readers[$id]->getParser()->getStreamReader()->cleanUp();
			unset($this->readers[$id]);
		}

		$this->createdReaders = [];
	}

	/**
	 * @param \Psr\Log\LoggerInterface
	 *
	 * @return \Mpdf\Mpdf
	 */
	public function setLogger(LoggerInterface $logger)
	{
		$this->logger = $logger;

		foreach ($this->services as $name) {
			if ($this->$name && $this->$name instanceof \Psr\Log\LoggerAwareInterface) {
				$this->$name->setLogger($logger);
			}
		}

		return $this;
	}

	private function initConfig(array $config)
	{
		$configObject = new ConfigVariables();
		$defaults = $configObject->getDefaults();
		$config = array_intersect_key($config + $defaults, $defaults);

		foreach ($config as $var => $val) {
			$this->{$var} = $val;
		}

		return $config;
	}

	private function initConstructorParams(array $config)
	{
		$constructor = [
			'mode' => '',
			'format' => 'A4',
			'default_font_size' => 0,
			'default_font' => '',
			'margin_left' => 15,
			'margin_right' => 15,
			'margin_top' => 16,
			'margin_bottom' => 16,
			'margin_header' => 9,
			'margin_footer' => 9,
			'orientation' => 'P',
		];

		foreach ($constructor as $key => $val) {
			if (isset($config[$key])) {
				$constructor[$key] = $config[$key];
			}
		}

		return array_values($constructor);
	}

	private function initFontConfig(array $config)
	{
		$configObject = new FontVariables();
		$defaults = $configObject->getDefaults();
		$config = array_intersect_key($config + $defaults, $defaults);
		foreach ($config as $var => $val) {
			$this->{$var} = $val;
		}

		return $config;
	}

	function _setPageSize($format, &$orientation)
	{
		if (is_string($format)) {

			if (empty($format)) {
				$format = 'A4';
			}

			// e.g. A4-L = A4 landscape, A4-P = A4 portrait
			if (preg_match('/([0-9a-zA-Z]*)-([P,L])/i', $format, $m)) {
				$format = $m[1];
				$orientation = $m[2];
			} elseif (empty($orientation)) {
				$orientation = 'P';
			}

			$format = PageFormat::getSizeFromName($format);

			$this->fwPt = $format[0];
			$this->fhPt = $format[1];

		} else {

			if (!$format[0] || !$format[1]) {
				throw new \Mpdf\MpdfException('Invalid page format: ' . $format[0] . ' ' . $format[1]);
			}

			$this->fwPt = $format[0] * Mpdf::SCALE;
			$this->fhPt = $format[1] * Mpdf::SCALE;
		}

		$this->fw = $this->fwPt / Mpdf::SCALE;
		$this->fh = $this->fhPt / Mpdf::SCALE;

		// Page orientation
		$orientation = strtolower($orientation);
		if ($orientation === 'p' || $orientation == 'portrait') {
			$orientation = 'P';
			$this->wPt = $this->fwPt;
			$this->hPt = $this->fhPt;
		} elseif ($orientation === 'l' || $orientation == 'landscape') {
			$orientation = 'L';
			$this->wPt = $this->fhPt;
			$this->hPt = $this->fwPt;
		} else {
			throw new \Mpdf\MpdfException('Incorrect orientation: ' . $orientation);
		}

		$this->CurOrientation = $orientation;

		$this->w = $this->wPt / Mpdf::SCALE;
		$this->h = $this->hPt / Mpdf::SCALE;
	}

	function RestrictUnicodeFonts($res)
	{
		// $res = array of (Unicode) fonts to restrict to: e.g. norasi|norasiB - language specific
		if (count($res)) { // Leave full list of available fonts if passed blank array
			$this->available_unifonts = $res;
		} else {
			$this->available_unifonts = $this->default_available_fonts;
		}
		if (count($this->available_unifonts) == 0) {
			$this->available_unifonts[] = $this->default_available_fonts[0];
		}
		$this->available_unifonts = array_values($this->available_unifonts);
	}

	function setMBencoding($enc)
	{
		if ($this->mb_enc != $enc) {
			$this->mb_enc = $enc;
			mb_internal_encoding($this->mb_enc);
		}
	}

	function SetMargins($left, $right, $top)
	{
		// Set left, top and right margins
		$this->lMargin = $left;
		$this->rMargin = $right;
		$this->tMargin = $top;
	}

	function ResetMargins()
	{
		// ReSet left, top margins
		if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation == 'P' && $this->CurOrientation == 'L') {
			if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
				$this->tMargin = $this->orig_rMargin;
				$this->bMargin = $this->orig_lMargin;
			} else { // ODD	// OR NOT MIRRORING MARGINS/FOOTERS
				$this->tMargin = $this->orig_lMargin;
				$this->bMargin = $this->orig_rMargin;
			}
			$this->lMargin = $this->DeflMargin;
			$this->rMargin = $this->DefrMargin;
			$this->MarginCorrection = 0;
			$this->PageBreakTrigger = $this->h - $this->bMargin;
		} elseif (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
			$this->lMargin = $this->DefrMargin;
			$this->rMargin = $this->DeflMargin;
			$this->MarginCorrection = $this->DefrMargin - $this->DeflMargin;
		} else { // ODD	// OR NOT MIRRORING MARGINS/FOOTERS
			$this->lMargin = $this->DeflMargin;
			$this->rMargin = $this->DefrMargin;
			if ($this->mirrorMargins) {
				$this->MarginCorrection = $this->DeflMargin - $this->DefrMargin;
			}
		}
		$this->x = $this->lMargin;
	}

	function SetLeftMargin($margin)
	{
		// Set left margin
		$this->lMargin = $margin;
		if ($this->page > 0 and $this->x < $margin) {
			$this->x = $margin;
		}
	}

	function SetTopMargin($margin)
	{
		// Set top margin
		$this->tMargin = $margin;
	}

	function SetRightMargin($margin)
	{
		// Set right margin
		$this->rMargin = $margin;
	}

	function SetAutoPageBreak($auto, $margin = 0)
	{
		// Set auto page break mode and triggering margin
		$this->autoPageBreak = $auto;
		$this->bMargin = $margin;
		$this->PageBreakTrigger = $this->h - $margin;
	}

	function SetDisplayMode($zoom, $layout = 'continuous')
	{
		$allowedZoomModes = ['fullpage', 'fullwidth', 'real', 'default', 'none'];

		if (in_array($zoom, $allowedZoomModes, true) || is_numeric($zoom)) {
			$this->ZoomMode = $zoom;
		} else {
			throw new \Mpdf\MpdfException('Incorrect zoom display mode: ' . $zoom);
		}

		$allowedLayoutModes = ['single', 'continuous', 'two', 'twoleft', 'tworight', 'default'];

		if (in_array($layout, $allowedLayoutModes, true)) {
			$this->LayoutMode = $layout;
		} else {
			throw new \Mpdf\MpdfException('Incorrect layout display mode: ' . $layout);
		}
	}

	function SetCompression($compress)
	{
		// Set page compression
		if (function_exists('gzcompress')) {
			$this->compress = $compress;
		} else {
			$this->compress = false;
		}
	}

	function SetTitle($title)
	{
		// Title of document // Arrives as UTF-8
		$this->title = $title;
	}

	function SetSubject($subject)
	{
		// Subject of document
		$this->subject = $subject;
	}

	function SetAuthor($author)
	{
		// Author of document
		$this->author = $author;
	}

	function SetKeywords($keywords)
	{
		// Keywords of document
		$this->keywords = $keywords;
	}

	function SetCreator($creator)
	{
		// Creator of document
		$this->creator = $creator;
	}

	function AddCustomProperty($key, $value)
	{
		$this->customProperties[$key] = $value;
	}

	/**
	 * Set one or multiple associated file ("/AF" as required by PDF/A-3)
	 *
	 * param $files is an array of hash containing:
	 *   path: file path on FS
	 *   content: file content
	 *   name: file name (not necessarily the same as the file on FS)
	 *   mime (optional): file mime type (will show up as /Subtype in the PDF)
	 *   description (optional): file description
	 *   AFRelationship (optional): PDF/A-3 AFRelationship (e.g. "Alternative")
	 *
	 * e.g. to associate 1 file:
	 *     [[
	 *         'path' => 'tmp/1234.xml',
	 *         'content' => 'file content',
	 *         'name' => 'public_name.xml',
	 *         'mime' => 'text/xml',
	 *         'description' => 'foo',
	 *         'AFRelationship' => 'Alternative',
	 *     ]]
	 *
	 * @param mixed[] $files Array of arrays of associated files. See above
	 */
	function SetAssociatedFiles(array $files)
	{
		$this->associatedFiles = $files;
	}

	function SetAdditionalXmpRdf($s)
	{
		$this->additionalXmpRdf = $s;
	}

	function SetAnchor2Bookmark($x)
	{
		$this->anchor2Bookmark = $x;
	}

	public function AliasNbPages($alias = '{nb}')
	{
		// Define an alias for total number of pages
		$this->aliasNbPg = $alias;
	}

	public function AliasNbPageGroups($alias = '{nbpg}')
	{
		// Define an alias for total number of pages in a group
		$this->aliasNbPgGp = $alias;
	}

	function SetAlpha($alpha, $bm = 'Normal', $return = false, $mode = 'B')
	{
		// alpha: real value from 0 (transparent) to 1 (opaque)
		// bm:    blend mode, one of the following:
		//          Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn,
		//          HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity
		// set alpha for stroking (CA) and non-stroking (ca) operations
		// mode determines F (fill) S (stroke) B (both)
		if (($this->PDFA || $this->PDFX) && $alpha != 1) {
			if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
				$this->PDFAXwarnings[] = "Image opacity must be 100% (Opacity changed to 100%)";
			}
			$alpha = 1;
		}
		$a = ['BM' => '/' . $bm];
		if ($mode == 'F' || $mode == 'B') {
			$a['ca'] = $alpha; // mPDF 5.7.2
		}
		if ($mode == 'S' || $mode == 'B') {
			$a['CA'] = $alpha; // mPDF 5.7.2
		}
		$gs = $this->AddExtGState($a);
		if ($return) {
			return sprintf('/GS%d gs', $gs);
		} else {
			$this->writer->write(sprintf('/GS%d gs', $gs));
		}
	}

	function AddExtGState($parms)
	{
		$n = count($this->extgstates);
		// check if graphics state already exists
		for ($i = 1; $i <= $n; $i++) {
			if (count($this->extgstates[$i]['parms']) == count($parms)) {
				$same = true;
				foreach ($this->extgstates[$i]['parms'] as $k => $v) {
					if (!isset($parms[$k]) || $parms[$k] != $v) {
						$same = false;
						break;
					}
				}
				if ($same) {
					return $i;
				}
			}
		}
		$n++;
		$this->extgstates[$n]['parms'] = $parms;
		return $n;
	}

	function SetVisibility($v)
	{
		if (($this->PDFA || $this->PDFX) && $this->visibility != 'visible') {
			$this->PDFAXwarnings[] = "Cannot set visibility to anything other than full when using PDFA or PDFX";
			return '';
		} elseif (!$this->PDFA && !$this->PDFX) {
			$this->pdf_version = '1.5';
		}
		if ($this->visibility != 'visible') {
			$this->writer->write('EMC');
			$this->hasOC = intval($this->hasOC);
		}
		if ($v == 'printonly') {
			$this->writer->write('/OC /OC1 BDC');
			$this->hasOC = ($this->hasOC | 1);
		} elseif ($v == 'screenonly') {
			$this->writer->write('/OC /OC2 BDC');
			$this->hasOC = ($this->hasOC | 2);
		} elseif ($v == 'hidden') {
			$this->writer->write('/OC /OC3 BDC');
			$this->hasOC = ($this->hasOC | 4);
		} elseif ($v != 'visible') {
			throw new \Mpdf\MpdfException('Incorrect visibility: ' . $v);
		}
		$this->visibility = $v;
	}

	function Open()
	{
		// Begin document
		if ($this->state == 0) {
			$this->state = 1;
			if (false === $this->preambleWritten) {
				$this->writer->write('%PDF-' . $this->pdf_version);
				$this->writer->write('%' . chr(226) . chr(227) . chr(207) . chr(211)); // 4 chars > 128 to show binary file
				$this->preambleWritten = true;
			}
		}
	}

	function Close()
	{
		// @log Closing last page

		// Terminate document
		if ($this->state == 3) {
			return;
		}

		if ($this->page == 0) {
			$this->AddPage($this->CurOrientation);
		}

		if (count($this->cellBorderBuffer)) {
			$this->printcellbuffer();
		}

		// *TABLES*
		if ($this->tablebuffer) {
			$this->printtablebuffer();
		}

		/* -- COLUMNS -- */

		if ($this->ColActive) {
			$this->SetColumns(0);
			$this->ColActive = 0;
			if (count($this->columnbuffer)) {
				$this->printcolumnbuffer();
			}
		}

		/* -- END COLUMNS -- */

		// BODY Backgrounds
		$s = '';

		$s .= $this->PrintBodyBackgrounds();
		$s .= $this->PrintPageBackgrounds();

		$this->pages[$this->page] = preg_replace(
			'/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/',
			"\n" . $s . "\n" . '\\1',
			$this->pages[$this->page]
		);

		$this->pageBackgrounds = [];

		if ($this->visibility != 'visible') {
			$this->SetVisibility('visible');
		}

		$this->EndLayer();

		if (!$this->tableOfContents->TOCmark) { // Page footer
			$this->InFooter = true;
			$this->Footer();
			$this->InFooter = false;
		}

		if ($this->tableOfContents->TOCmark || count($this->tableOfContents->m_TOC)) {
			$this->tableOfContents->insertTOC();
		}

		// Close page
		$this->_endpage();

		// Close document
		$this->_enddoc();
	}

	/* -- BACKGROUNDS -- */

	function _resizeBackgroundImage($imw, $imh, $cw, $ch, $resize, $repx, $repy, $pba = [], $size = [])
	{
		// pba is background positioning area (from CSS background-origin) may not always be set [x,y,w,h]
		// size is from CSS3 background-size - takes precendence over old resize
		// $w - absolute length or % or auto or cover | contain
		// $h - absolute length or % or auto or cover | contain
		if (isset($pba['w'])) {
			$cw = $pba['w'];
		}
		if (isset($pba['h'])) {
			$ch = $pba['h'];
		}

		$cw = $cw * Mpdf::SCALE;
		$ch = $ch * Mpdf::SCALE;
		if (empty($size) && !$resize) {
			return [$imw, $imh, $repx, $repy];
		}

		if (isset($size['w']) && $size['w']) {
			if ($size['w'] == 'contain') {
				// 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.
				// Same as resize==3
				$h = $imh * $cw / $imw;
				$w = $cw;
				if ($h > $ch) {
					$w = $w * $ch / $h;
					$h = $ch;
				}
			} elseif ($size['w'] == 'cover') {
				// 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.
				$h = $imh * $cw / $imw;
				$w = $cw;
				if ($h < $ch) {
					$w = $w * $h / $ch;
					$h = $ch;
				}
			} else {
				if (stristr($size['w'], '%')) {
					$size['w'] = (float) $size['w'];
					$size['w'] /= 100;
					$size['w'] = ($cw * $size['w']);
				}
				if (stristr($size['h'], '%')) {
					$size['h'] = (float) $size['h'];
					$size['h'] /= 100;
					$size['h'] = ($ch * $size['h']);
				}
				if ($size['w'] == 'auto' && $size['h'] == 'auto') {
					$w = $imw;
					$h = $imh;
				} elseif ($size['w'] == 'auto' && $size['h'] != 'auto') {
					$w = $imw * $size['h'] / $imh;
					$h = $size['h'];
				} elseif ($size['w'] != 'auto' && $size['h'] == 'auto') {
					$h = $imh * $size['w'] / $imw;
					$w = $size['w'];
				} else {
					$w = $size['w'];
					$h = $size['h'];
				}
			}
			return [$w, $h, $repx, $repy];
		} elseif ($resize == 1 && $imw > $cw) {
			$h = $imh * $cw / $imw;
			return [$cw, $h, $repx, $repy];
		} elseif ($resize == 2 && $imh > $ch) {
			$w = $imw * $ch / $imh;
			return [$w, $ch, $repx, $repy];
		} elseif ($resize == 3) {
			$w = $imw;
			$h = $imh;
			if ($w > $cw) {
				$h = $h * $cw / $w;
				$w = $cw;
			}
			if ($h > $ch) {
				$w = $w * $ch / $h;
				$h = $ch;
			}
			return [$w, $h, $repx, $repy];
		} elseif ($resize == 4) {
			$h = $imh * $cw / $imw;
			return [$cw, $h, $repx, $repy];
		} elseif ($resize == 5) {
			$w = $imw * $ch / $imh;
			return [$w, $ch, $repx, $repy];
		} elseif ($resize == 6) {
			return [$cw, $ch, $repx, $repy];
		}
		return [$imw, $imh, $repx, $repy];
	}

	function SetBackground(&$properties, &$maxwidth)
	{
		if (isset($properties['BACKGROUND-ORIGIN']) && ($properties['BACKGROUND-ORIGIN'] == 'border-box' || $properties['BACKGROUND-ORIGIN'] == 'content-box')) {
			$origin = $properties['BACKGROUND-ORIGIN'];
		} else {
			$origin = 'padding-box';
		}

		if (isset($properties['BACKGROUND-SIZE'])) {
			if (stristr($properties['BACKGROUND-SIZE'], 'contain')) {
				$bsw = $bsh = 'contain';
			} elseif (stristr($properties['BACKGROUND-SIZE'], 'cover')) {
				$bsw = $bsh = 'cover';
			} else {
				$bsw = $bsh = 'auto';
				$sz = preg_split('/\s+/', trim($properties['BACKGROUND-SIZE']));
				if (count($sz) == 2) {
					$bsw = $sz[0];
					$bsh = $sz[1];
				} else {
					$bsw = $sz[0];
				}
				if (!stristr($bsw, '%') && !stristr($bsw, 'auto')) {
					$bsw = $this->sizeConverter->convert($bsw, $maxwidth, $this->FontSize);
				}
				if (!stristr($bsh, '%') && !stristr($bsh, 'auto')) {
					$bsh = $this->sizeConverter->convert($bsh, $maxwidth, $this->FontSize);
				}
			}
			$size = ['w' => $bsw, 'h' => $bsh];
		} else {
			$size = false;
		} // mPDF 6
		if (preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $properties['BACKGROUND-IMAGE'])) {
			return ['gradient' => $properties['BACKGROUND-IMAGE'], 'origin' => $origin, 'size' => $size];
		} else {
			$file = $properties['BACKGROUND-IMAGE'];
			$sizesarray = $this->Image($file, 0, 0, 0, 0, '', '', false, false, false, false, true);
			if (isset($sizesarray['IMAGE_ID'])) {
				$image_id = $sizesarray['IMAGE_ID'];
				$orig_w = $sizesarray['WIDTH'] * Mpdf::SCALE;  // in user units i.e. mm
				$orig_h = $sizesarray['HEIGHT'] * Mpdf::SCALE;  // (using $this->img_dpi)
				if (isset($properties['BACKGROUND-IMAGE-RESOLUTION'])) {
					if (preg_match('/from-image/i', $properties['BACKGROUND-IMAGE-RESOLUTION']) && isset($sizesarray['set-dpi']) && $sizesarray['set-dpi'] > 0) {
						$orig_w *= $this->img_dpi / $sizesarray['set-dpi'];
						$orig_h *= $this->img_dpi / $sizesarray['set-dpi'];
					} elseif (preg_match('/(\d+)dpi/i', $properties['BACKGROUND-IMAGE-RESOLUTION'], $m)) {
						$dpi = $m[1];
						if ($dpi > 0) {
							$orig_w *= $this->img_dpi / $dpi;
							$orig_h *= $this->img_dpi / $dpi;
						}
					}
				}
				$x_repeat = true;
				$y_repeat = true;
				if (isset($properties['BACKGROUND-REPEAT'])) {
					if ($properties['BACKGROUND-REPEAT'] == 'no-repeat' || $properties['BACKGROUND-REPEAT'] == 'repeat-x') {
						$y_repeat = false;
					}
					if ($properties['BACKGROUND-REPEAT'] == 'no-repeat' || $properties['BACKGROUND-REPEAT'] == 'repeat-y') {
						$x_repeat = false;
					}
				}
				$x_pos = 0;
				$y_pos = 0;
				if (isset($properties['BACKGROUND-POSITION'])) {
					$ppos = preg_split('/\s+/', $properties['BACKGROUND-POSITION']);
					$x_pos = $ppos[0];
					$y_pos = $ppos[1];
					if (!stristr($x_pos, '%')) {
						$x_pos = $this->sizeConverter->convert($x_pos, $maxwidth, $this->FontSize);
					}
					if (!stristr($y_pos, '%')) {
						$y_pos = $this->sizeConverter->convert($y_pos, $maxwidth, $this->FontSize);
					}
				}
				if (isset($properties['BACKGROUND-IMAGE-RESIZE'])) {
					$resize = $properties['BACKGROUND-IMAGE-RESIZE'];
				} else {
					$resize = 0;
				}
				if (isset($properties['BACKGROUND-IMAGE-OPACITY'])) {
					$opacity = $properties['BACKGROUND-IMAGE-OPACITY'];
				} else {
					$opacity = 1;
				}
				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];
			}
		}
		return false;
	}

	/* -- END BACKGROUNDS -- */

	function PrintBodyBackgrounds()
	{
		$s = '';
		$clx = 0;
		$cly = 0;
		$clw = $this->w;
		$clh = $this->h;
		// If using bleed and trim margins in paged media
		if ($this->pageDim[$this->page]['outer_width_LR'] || $this->pageDim[$this->page]['outer_width_TB']) {
			$clx = $this->pageDim[$this->page]['outer_width_LR'] - $this->pageDim[$this->page]['bleedMargin'];
			$cly = $this->pageDim[$this->page]['outer_width_TB'] - $this->pageDim[$this->page]['bleedMargin'];
			$clw = $this->w - 2 * $clx;
			$clh = $this->h - 2 * $cly;
		}

		if ($this->bodyBackgroundColor) {
			$s .= 'q ' . $this->SetFColor($this->bodyBackgroundColor, true) . "\n";
			if ($this->bodyBackgroundColor[0] == 5) { // RGBa
				$s .= $this->SetAlpha(ord($this->bodyBackgroundColor[4]) / 100, 'Normal', true, 'F') . "\n";
			} elseif ($this->bodyBackgroundColor[0] == 6) { // CMYKa
				$s .= $this->SetAlpha(ord($this->bodyBackgroundColor[5]) / 100, 'Normal', true, 'F') . "\n";
			}
			$s .= sprintf('%.3F %.3F %.3F %.3F re f Q', ($clx * Mpdf::SCALE), ($cly * Mpdf::SCALE), $clw * Mpdf::SCALE, $clh * Mpdf::SCALE) . "\n";
		}

		/* -- BACKGROUNDS -- */
		if ($this->bodyBackgroundGradient) {
			$g = $this->gradient->parseBackgroundGradient($this->bodyBackgroundGradient);
			if ($g) {
				$s .= $this->gradient->Gradient($clx, $cly, $clw, $clh, (isset($g['gradtype']) ? $g['gradtype'] : null), $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true);
			}
		}
		if ($this->bodyBackgroundImage) {
			if (isset($this->bodyBackgroundImage['gradient']) && $this->bodyBackgroundImage['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $this->bodyBackgroundImage['gradient'])) {
				$g = $this->gradient->parseMozGradient($this->bodyBackgroundImage['gradient']);
				if ($g) {
					$s .= $this->gradient->Gradient($clx, $cly, $clw, $clh, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true);
				}
			} elseif ($this->bodyBackgroundImage['image_id']) { // Background pattern
				$n = count($this->patterns) + 1;
				// If using resize, uses TrimBox (not including the bleed)
				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']);

				$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']];
				if (($this->bodyBackgroundImage['opacity'] > 0 || $this->bodyBackgroundImage['opacity'] === '0') && $this->bodyBackgroundImage['opacity'] < 1) {
					$opac = $this->SetAlpha($this->bodyBackgroundImage['opacity'], 'Normal', true);
				} else {
					$opac = '';
				}
				$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";
			}
		}
		/* -- END BACKGROUNDS -- */
		return $s;
	}

	function _setClippingPath($clx, $cly, $clw, $clh)
	{
		$s = ' q 0 w '; // Line width=0
		$s .= sprintf('%.3F %.3F m ', ($clx) * Mpdf::SCALE, ($this->h - ($cly)) * Mpdf::SCALE); // start point TL before the arc
		$s .= sprintf('%.3F %.3F l ', ($clx) * Mpdf::SCALE, ($this->h - ($cly + $clh)) * Mpdf::SCALE); // line to BL
		$s .= sprintf('%.3F %.3F l ', ($clx + $clw) * Mpdf::SCALE, ($this->h - ($cly + $clh)) * Mpdf::SCALE); // line to BR
		$s .= sprintf('%.3F %.3F l ', ($clx + $clw) * Mpdf::SCALE, ($this->h - ($cly)) * Mpdf::SCALE); // line to TR
		$s .= sprintf('%.3F %.3F l ', ($clx) * Mpdf::SCALE, ($this->h - ($cly)) * Mpdf::SCALE); // line to TL
		$s .= ' W n '; // Ends path no-op & Sets the clipping path
		return $s;
	}

	function PrintPageBackgrounds($adjustmenty = 0)
	{
		$s = '';

		ksort($this->pageBackgrounds);

		foreach ($this->pageBackgrounds as $bl => $pbs) {

			foreach ($pbs as $pb) {

				if ((!isset($pb['image_id']) && !isset($pb['gradient'])) || isset($pb['shadowonly'])) { // Background colour or boxshadow

					if ($pb['z-index'] > 0) {
						$this->current_layer = $pb['z-index'];
						$s .= "\n" . '/OCBZ-index /ZI' . $pb['z-index'] . ' BDC' . "\n";
					}

					if ($pb['visibility'] != 'visible') {
						if ($pb['visibility'] == 'printonly') {
							$s .= '/OC /OC1 BDC' . "\n";
						} elseif ($pb['visibility'] == 'screenonly') {
							$s .= '/OC /OC2 BDC' . "\n";
						} elseif ($pb['visibility'] == 'hidden') {
							$s .= '/OC /OC3 BDC' . "\n";
						}
					}

					// Box shadow
					if (isset($pb['shadow']) && $pb['shadow']) {
						$s .= $pb['shadow'] . "\n";
					}

					if (isset($pb['clippath']) && $pb['clippath']) {
						$s .= $pb['clippath'] . "\n";
					}

					$s .= 'q ' . $this->SetFColor($pb['col'], true) . "\n";

					if ($pb['col'] && $pb['col'][0] === '5') { // RGBa
						$s .= $this->SetAlpha(ord($pb['col'][4]) / 100, 'Normal', true, 'F') . "\n";
					} elseif ($pb['col'] && $pb['col'][0] === '6') { // CMYKa
						$s .= $this->SetAlpha(ord($pb['col'][5]) / 100, 'Normal', true, 'F') . "\n";
					}

					$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";

					if (isset($pb['clippath']) && $pb['clippath']) {
						$s .= 'Q' . "\n";
					}

					if ($pb['visibility'] != 'visible') {
						$s .= 'EMC' . "\n";
					}

					if ($pb['z-index'] > 0) {
						$s .= "\n" . 'EMCBZ-index' . "\n";
						$this->current_layer = 0;
					}
				}
			}

			/* -- BACKGROUNDS -- */
			foreach ($pbs as $pb) {

				if ((isset($pb['gradient']) && $pb['gradient']) || (isset($pb['image_id']) && $pb['image_id'])) {

					if ($pb['z-index'] > 0) {
						$this->current_layer = $pb['z-index'];
						$s .= "\n" . '/OCGZ-index /ZI' . $pb['z-index'] . ' BDC' . "\n";
					}

					if ($pb['visibility'] != 'visible') {
						if ($pb['visibility'] == 'printonly') {
							$s .= '/OC /OC1 BDC' . "\n";
						} elseif ($pb['visibility'] == 'screenonly') {
							$s .= '/OC /OC2 BDC' . "\n";
						} elseif ($pb['visibility'] == 'hidden') {
							$s .= '/OC /OC3 BDC' . "\n";
						}
					}

				}

				if (isset($pb['gradient']) && $pb['gradient']) {

					if (isset($pb['clippath']) && $pb['clippath']) {
						$s .= $pb['clippath'] . "\n";
					}

					$s .= $this->gradient->Gradient($pb['x'], $pb['y'], $pb['w'], $pb['h'], $pb['gradtype'], $pb['stops'], $pb['colorspace'], $pb['coords'], $pb['extend'], true);

					if (isset($pb['clippath']) && $pb['clippath']) {
						$s .= 'Q' . "\n";
					}

				} elseif (isset($pb['image_id']) && $pb['image_id']) { // Background Image

					$pb['y'] -= $adjustmenty;
					$pb['h'] += $adjustmenty;
					$n = count($this->patterns) + 1;

					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']);

					$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']];

					$x = $pb['x'] * Mpdf::SCALE;
					$y = ($this->h - $pb['y']) * Mpdf::SCALE;
					$w = $pb['w'] * Mpdf::SCALE;
					$h = -$pb['h'] * Mpdf::SCALE;

					if (isset($pb['clippath']) && $pb['clippath']) {
						$s .= $pb['clippath'] . "\n";
					}

					if ($this->writingHTMLfooter || $this->writingHTMLheader) { // Write each (tiles) image rather than use as a pattern

						$iw = $pb['orig_w'] / Mpdf::SCALE;
						$ih = $pb['orig_h'] / Mpdf::SCALE;

						$w = $pb['w'];
						$h = $pb['h'];
						$x0 = $pb['x'];
						$y0 = $pb['y'];

						if (isset($pb['bpa']) && $pb['bpa']) {
							$w = $pb['bpa']['w'];
							$h = $pb['bpa']['h'];
							$x0 = $pb['bpa']['x'];
							$y0 = $pb['bpa']['y'];
						}

						if (isset($pb['size']['w']) && $pb['size']['w']) {
							$size = $pb['size'];

							if ($size['w'] == 'contain') {
								// 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.
								// Same as resize==3
								$ih = $ih * $pb['bpa']['w'] / $iw;
								$iw = $pb['bpa']['w'];
								if ($ih > $pb['bpa']['h']) {
									$iw = $iw * $pb['bpa']['h'] / $ih;
									$ih = $pb['bpa']['h'];
								}
							} elseif ($size['w'] == 'cover') {
								// 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.
								$ih = $ih * $pb['bpa']['w'] / $iw;
								$iw = $pb['bpa']['w'];
								if ($ih < $pb['bpa']['h']) {
									$iw = $iw * $ih / $pb['bpa']['h'];
									$ih = $pb['bpa']['h'];
								}
							} else {

								if (NumericString::containsPercentChar($size['w'])) {
									$size['w'] = NumericString::removePercentChar($size['w']);
									$size['w'] /= 100;
									$size['w'] = ($pb['bpa']['w'] * $size['w']);
								}

								if (NumericString::containsPercentChar($size['h'])) {
									$size['h'] = NumericString::removePercentChar($size['h']);
									$size['h'] /= 100;
									$size['h'] = ($pb['bpa']['h'] * $size['h']);
								}

								if ($size['w'] == 'auto' && $size['h'] == 'auto') {
									$iw = $iw;
									$ih = $ih;
								} elseif ($size['w'] == 'auto' && $size['h'] != 'auto') {
									$iw = $iw * $size['h'] / $ih;
									$ih = $size['h'];
								} elseif ($size['w'] != 'auto' && $size['h'] == 'auto') {
									$ih = $ih * $size['w'] / $iw;
									$iw = $size['w'];
								} else {
									$iw = $size['w'];
									$ih = $size['h'];
								}
							}
						}

						// Number to repeat
						if ($pb['x_repeat']) {
							$nx = ceil($pb['w'] / $iw) + 1;
						} else {
							$nx = 1;
						}

						if ($pb['y_repeat']) {
							$ny = ceil($pb['h'] / $ih) + 1;
						} else {
							$ny = 1;
						}

						$x_pos = $pb['x_pos'];
						if (stristr($x_pos, '%')) {
							$x_pos = (float) $x_pos;
							$x_pos /= 100;
							$x_pos = ($pb['bpa']['w'] * $x_pos) - ($iw * $x_pos);
						}

						$y_pos = $pb['y_pos'];

						if (stristr($y_pos, '%')) {
							$y_pos = (float) $y_pos;
							$y_pos /= 100;
							$y_pos = ($pb['bpa']['h'] * $y_pos) - ($ih * $y_pos);
						}

						if ($nx > 1) {
							while ($x_pos > ($pb['x'] - $pb['bpa']['x'])) {
								$x_pos -= $iw;
							}
						}

						if ($ny > 1) {
							while ($y_pos > ($pb['y'] - $pb['bpa']['y'])) {
								$y_pos -= $ih;
							}
						}

						for ($xi = 0; $xi < $nx; $xi++) {
							for ($yi = 0; $yi < $ny; $yi++) {
								$x = $x0 + $x_pos + ($iw * $xi);
								$y = $y0 + $y_pos + ($ih * $yi);
								if ($pb['opacity'] > 0 && $pb['opacity'] < 1) {
									$opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
								} else {
									$opac = '';
								}
								$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";
							}
						}

					} else {
						if (($pb['opacity'] > 0 || $pb['opacity'] === '0') && $pb['opacity'] < 1) {
							$opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
						} else {
							$opac = '';
						}
						$s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $x, $y, $w, $h) . "\n";
					}

					if (isset($pb['clippath']) && $pb['clippath']) {
						$s .= 'Q' . "\n";
					}
				}

				if ((isset($pb['gradient']) && $pb['gradient']) || (isset($pb['image_id']) && $pb['image_id'])) {
					if ($pb['visibility'] != 'visible') {
						$s .= 'EMC' . "\n";
					}

					if ($pb['z-index'] > 0) {
						$s .= "\n" . 'EMCGZ-index' . "\n";
						$this->current_layer = 0;
					}
				}
			}
			/* -- END BACKGROUNDS -- */
		}

		return $s;
	}

	function PrintTableBackgrounds($adjustmenty = 0)
	{
		$s = '';
		/* -- BACKGROUNDS -- */
		ksort($this->tableBackgrounds);
		foreach ($this->tableBackgrounds as $bl => $pbs) {
			foreach ($pbs as $pb) {
				if ((!isset($pb['gradient']) || !$pb['gradient']) && (!isset($pb['image_id']) || !$pb['image_id'])) {
					$s .= 'q ' . $this->SetFColor($pb['col'], true) . "\n";
					if ($pb['col'][0] == 5) { // RGBa
						$s .= $this->SetAlpha(ord($pb['col'][4]) / 100, 'Normal', true, 'F') . "\n";
					} elseif ($pb['col'][0] == 6) { // CMYKa
						$s .= $this->SetAlpha(ord($pb['col'][5]) / 100, 'Normal', true, 'F') . "\n";
					}
					$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";
				}
				if (isset($pb['gradient']) && $pb['gradient']) {
					if (isset($pb['clippath']) && $pb['clippath']) {
						$s .= $pb['clippath'] . "\n";
					}
					$s .= $this->gradient->Gradient($pb['x'], $pb['y'], $pb['w'], $pb['h'], $pb['gradtype'], $pb['stops'], $pb['colorspace'], $pb['coords'], $pb['extend'], true);
					if (isset($pb['clippath']) && $pb['clippath']) {
						$s .= 'Q' . "\n";
					}
				}
				if (isset($pb['image_id']) && $pb['image_id']) { // Background pattern
					$pb['y'] -= $adjustmenty;
					$pb['h'] += $adjustmenty;
					$n = count($this->patterns) + 1;
					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']);
					$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']];
					$x = $pb['x'] * Mpdf::SCALE;
					$y = ($this->h - $pb['y']) * Mpdf::SCALE;
					$w = $pb['w'] * Mpdf::SCALE;
					$h = -$pb['h'] * Mpdf::SCALE;

					// mPDF 5.7.3
					if (($this->writingHTMLfooter || $this->writingHTMLheader) && (!isset($pb['clippath']) || $pb['clippath'] == '')) {
						// Set clipping path
						$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);
					}

					if (isset($pb['clippath']) && $pb['clippath']) {
						$s .= $pb['clippath'] . "\n";
					}

					// mPDF 5.7.3
					if ($this->writingHTMLfooter || $this->writingHTMLheader) { // Write each (tiles) image rather than use as a pattern
						$iw = $pb['orig_w'] / Mpdf::SCALE;
						$ih = $pb['orig_h'] / Mpdf::SCALE;

						$w = $pb['w'];
						$h = $pb['h'];
						$x0 = $pb['x'];
						$y0 = $pb['y'];

						if (isset($pb['bpa']) && $pb['bpa']) {
							$w = $pb['bpa']['w'];
							$h = $pb['bpa']['h'];
							$x0 = $pb['bpa']['x'];
							$y0 = $pb['bpa']['y'];
						} // At present 'bpa' (background page area) is not set for tablebackgrounds - only pagebackgrounds
						// For now, just set it as:
						else {
							$pb['bpa'] = ['x' => $x0, 'y' => $y0, 'w' => $w, 'h' => $h];
						}

						if (isset($pb['size']['w']) && $pb['size']['w']) {
							$size = $pb['size'];

							if ($size['w'] == 'contain') {
								// 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.
								// Same as resize==3
								$ih = $ih * $pb['bpa']['w'] / $iw;
								$iw = $pb['bpa']['w'];
								if ($ih > $pb['bpa']['h']) {
									$iw = $iw * $pb['bpa']['h'] / $ih;
									$ih = $pb['bpa']['h'];
								}
							} elseif ($size['w'] == 'cover') {
								// 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.
								$ih = $ih * $pb['bpa']['w'] / $iw;
								$iw = $pb['bpa']['w'];
								if ($ih < $pb['bpa']['h']) {
									$iw = $iw * $ih / $pb['bpa']['h'];
									$ih = $pb['bpa']['h'];
								}
							} else {
								if (NumericString::containsPercentChar($size['w'])) {
									$size['w'] = NumericString::removePercentChar($size['w']);
									$size['w'] /= 100;
									$size['w'] = ($pb['bpa']['w'] * $size['w']);
								}
								if (NumericString::containsPercentChar($size['h'])) {
									$size['h'] = NumericString::removePercentChar($size['h']);
									$size['h'] /= 100;
									$size['h'] = ($pb['bpa']['h'] * $size['h']);
								}
								if ($size['w'] == 'auto' && $size['h'] == 'auto') {
									$iw = $iw;
									$ih = $ih;
								} elseif ($size['w'] == 'auto' && $size['h'] != 'auto') {
									$iw = $iw * $size['h'] / $ih;
									$ih = $size['h'];
								} elseif ($size['w'] != 'auto' && $size['h'] == 'auto') {
									$ih = $ih * $size['w'] / $iw;
									$iw = $size['w'];
								} else {
									$iw = $size['w'];
									$ih = $size['h'];
								}
							}
						}

						// Number to repeat
						if (isset($pb['x_repeat']) && $pb['x_repeat']) {
							$nx = ceil($pb['w'] / $iw) + 1;
						} else {
							$nx = 1;
						}
						if (isset($pb['y_repeat']) && $pb['y_repeat']) {
							$ny = ceil($pb['h'] / $ih) + 1;
						} else {
							$ny = 1;
						}

						$x_pos = $pb['x_pos'];
						if (NumericString::containsPercentChar($x_pos)) {
							$x_pos = NumericString::removePercentChar($x_pos);
							$x_pos /= 100;
							$x_pos = ($pb['bpa']['w'] * $x_pos) - ($iw * $x_pos);
						}
						$y_pos = $pb['y_pos'];
						if (NumericString::containsPercentChar($y_pos)) {
							$y_pos = NumericString::removePercentChar($y_pos);
							$y_pos /= 100;
							$y_pos = ($pb['bpa']['h'] * $y_pos) - ($ih * $y_pos);
						}
						if ($nx > 1) {
							while ($x_pos > ($pb['x'] - $pb['bpa']['x'])) {
								$x_pos -= $iw;
							}
						}
						if ($ny > 1) {
							while ($y_pos > ($pb['y'] - $pb['bpa']['y'])) {
								$y_pos -= $ih;
							}
						}
						for ($xi = 0; $xi < $nx; $xi++) {
							for ($yi = 0; $yi < $ny; $yi++) {
								$x = $x0 + $x_pos + ($iw * $xi);
								$y = $y0 + $y_pos + ($ih * $yi);
								if ($pb['opacity'] > 0 && $pb['opacity'] < 1) {
									$opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
								} else {
									$opac = '';
								}
								$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";
							}
						}
					} else {
						if (($pb['opacity'] > 0 || $pb['opacity'] === '0') && $pb['opacity'] < 1) {
							$opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
						} else {
							$opac = '';
						}
						$s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $x, $y, $w, $h) . "\n";
					}

					if (isset($pb['clippath']) && $pb['clippath']) {
						$s .= 'Q' . "\n";
					}
				}
			}
		}
		/* -- END BACKGROUNDS -- */
		return $s;
	}

	function BeginLayer($id)
	{
		if ($this->current_layer > 0) {
			$this->EndLayer();
		}
		if ($id < 1) {
			return false;
		}
		if (!isset($this->layers[$id])) {
			$this->layers[$id] = ['name' => 'Layer ' . ($id)];
			if (($this->PDFA || $this->PDFX)) {
				$this->PDFAXwarnings[] = "Cannot use layers when using PDFA or PDFX";
				return '';
			} elseif (!$this->PDFA && !$this->PDFX) {
				$this->pdf_version = '1.5';
			}
		}
		$this->current_layer = $id;
		$this->writer->write('/OCZ-index /ZI' . $id . ' BDC');

		$this->pageoutput[$this->page] = [];
	}

	function EndLayer()
	{
		if ($this->current_layer > 0) {
			$this->writer->write('EMCZ-index');
			$this->current_layer = 0;
		}
	}

	function AddPageByArray($a)
	{
		if (!is_array($a)) {
			$a = [];
		}

		$orientation = (isset($a['orientation']) ? $a['orientation'] : '');
		$condition = (isset($a['condition']) ? $a['condition'] : (isset($a['type']) ? $a['type'] : ''));
		$resetpagenum = (isset($a['resetpagenum']) ? $a['resetpagenum'] : '');
		$pagenumstyle = (isset($a['pagenumstyle']) ? $a['pagenumstyle'] : '');
		$suppress = (isset($a['suppress']) ? $a['suppress'] : '');
		$mgl = (isset($a['mgl']) ? $a['mgl'] : (isset($a['margin-left']) ? $a['margin-left'] : ''));
		$mgr = (isset($a['mgr']) ? $a['mgr'] : (isset($a['margin-right']) ? $a['margin-right'] : ''));
		$mgt = (isset($a['mgt']) ? $a['mgt'] : (isset($a['margin-top']) ? $a['margin-top'] : ''));
		$mgb = (isset($a['mgb']) ? $a['mgb'] : (isset($a['margin-bottom']) ? $a['margin-bottom'] : ''));
		$mgh = (isset($a['mgh']) ? $a['mgh'] : (isset($a['margin-header']) ? $a['margin-header'] : ''));
		$mgf = (isset($a['mgf']) ? $a['mgf'] : (isset($a['margin-footer']) ? $a['margin-footer'] : ''));
		$ohname = (isset($a['ohname']) ? $a['ohname'] : (isset($a['odd-header-name']) ? $a['odd-header-name'] : ''));
		$ehname = (isset($a['ehname']) ? $a['ehname'] : (isset($a['even-header-name']) ? $a['even-header-name'] : ''));
		$ofname = (isset($a['ofname']) ? $a['ofname'] : (isset($a['odd-footer-name']) ? $a['odd-footer-name'] : ''));
		$efname = (isset($a['efname']) ? $a['efname'] : (isset($a['even-footer-name']) ? $a['even-footer-name'] : ''));
		$ohvalue = (isset($a['ohvalue']) ? $a['ohvalue'] : (isset($a['odd-header-value']) ? $a['odd-header-value'] : 0));
		$ehvalue = (isset($a['ehvalue']) ? $a['ehvalue'] : (isset($a['even-header-value']) ? $a['even-header-value'] : 0));
		$ofvalue = (isset($a['ofvalue']) ? $a['ofvalue'] : (isset($a['odd-footer-value']) ? $a['odd-footer-value'] : 0));
		$efvalue = (isset($a['efvalue']) ? $a['efvalue'] : (isset($a['even-footer-value']) ? $a['even-footer-value'] : 0));
		$pagesel = (isset($a['pagesel']) ? $a['pagesel'] : (isset($a['pageselector']) ? $a['pageselector'] : ''));
		$newformat = (isset($a['newformat']) ? $a['newformat'] : (isset($a['sheet-size']) ? $a['sheet-size'] : ''));

		$this->AddPage($orientation, $condition, $resetpagenum, $pagenumstyle, $suppress, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $newformat);
	}

	// mPDF 6 pagebreaktype
	function _preForcedPagebreak($pagebreaktype)
	{
		if ($pagebreaktype == 'cloneall') {
			// Close any open block tags
			$arr = [];
			$ai = 0;
			for ($b = $this->blklvl; $b > 0; $b--) {
				$this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
			}
			if ($this->blklvl == 0 && !empty($this->textbuffer)) { // Output previously buffered content
				$this->printbuffer($this->textbuffer, 1);
				$this->textbuffer = [];
			}
		} elseif ($pagebreaktype == 'clonebycss') {
			// Close open block tags whilst box-decoration-break==clone
			$arr = [];
			$ai = 0;
			for ($b = $this->blklvl; $b > 0; $b--) {
				if (isset($this->blk[$b]['box_decoration_break']) && $this->blk[$b]['box_decoration_break'] == 'clone') {
					$this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
				} else {
					if ($b == $this->blklvl && !empty($this->textbuffer)) { // Output previously buffered content
						$this->printbuffer($this->textbuffer, 1);
						$this->textbuffer = [];
					}
					break;
				}
			}
		} elseif (!empty($this->textbuffer)) { // Output previously buffered content
			$this->printbuffer($this->textbuffer, 1);
			$this->textbuffer = [];
		}
	}

	// mPDF 6 pagebreaktype
	function _postForcedPagebreak($pagebreaktype, $startpage, $save_blk, $save_blklvl)
	{
		if ($pagebreaktype == 'cloneall') {
			$this->blk = [];
			$this->blk[0] = $save_blk[0];
			// Re-open block tags
			$this->blklvl = 0;
			$arr = [];
			$i = 0;
			for ($b = 1; $b <= $save_blklvl; $b++) {
				$this->tag->OpenTag($save_blk[$b]['tag'], $save_blk[$b]['attr'], $arr, $i);
			}
		} elseif ($pagebreaktype == 'clonebycss') {
			$this->blk = [];
			$this->blk[0] = $save_blk[0];
			// Don't re-open tags for lowest level elements - so need to do some adjustments
			for ($b = 1; $b <= $this->blklvl; $b++) {
				$this->blk[$b] = $save_blk[$b];
				$this->blk[$b]['startpage'] = 0;
				$this->blk[$b]['y0'] = $this->y; // ?? $this->tMargin
				if (($this->page - $startpage) % 2) {
					if (isset($this->blk[$b]['x0'])) {
						$this->blk[$b]['x0'] += $this->MarginCorrection;
					} else {
						$this->blk[$b]['x0'] = $this->MarginCorrection;
					}
				}
				// for Float DIV
				$this->blk[$b]['marginCorrected'][$this->page] = true;
			}

			// Re-open block tags for any that have box_decoration_break==clone
			$arr = [];
			$i = 0;
			for ($b = $this->blklvl + 1; $b <= $save_blklvl; $b++) {
				if ($b < $this->blklvl) {
					$this->lastblocklevelchange = -1;
				}
				$this->tag->OpenTag($save_blk[$b]['tag'], $save_blk[$b]['attr'], $arr, $i);
			}
			if ($this->blk[$this->blklvl]['box_decoration_break'] != 'clone') {
				$this->lastblocklevelchange = -1;
			}
		} else {
			$this->lastblocklevelchange = -1;
		}
	}

	function AddPage(
		$orientation = '',
		$condition = '',
		$resetpagenum = '',
		$pagenumstyle = '',
		$suppress = '',
		$mgl = '',
		$mgr = '',
		$mgt = '',
		$mgb = '',
		$mgh = '',
		$mgf = '',
		$ohname = '',
		$ehname = '',
		$ofname = '',
		$efname = '',
		$ohvalue = 0,
		$ehvalue = 0,
		$ofvalue = 0,
		$efvalue = 0,
		$pagesel = '',
		$newformat = ''
	) {
		/* -- CSS-FLOAT -- */
		// Float DIV
		// Cannot do with columns on, or if any change in page orientation/margins etc.
		// If next page already exists - i.e background /headers and footers already written
		if ($this->state > 0 && $this->page < count($this->pages)) {
			$bak_cml = $this->cMarginL;
			$bak_cmr = $this->cMarginR;
			$bak_dw = $this->divwidth;
			// Paint Div Border if necessary
			if ($this->blklvl > 0) {
				$save_tr = $this->table_rotate; // *TABLES*
				$this->table_rotate = 0; // *TABLES*
				if (isset($this->blk[$this->blklvl]['y0']) && $this->y == $this->blk[$this->blklvl]['y0']) {
					$this->blk[$this->blklvl]['startpage'] ++;
				}
				if ((isset($this->blk[$this->blklvl]['y0']) && $this->y > $this->blk[$this->blklvl]['y0']) || $this->flowingBlockAttr['is_table']) {
					$toplvl = $this->blklvl;
				} else {
					$toplvl = $this->blklvl - 1;
				}
				$sy = $this->y;
				for ($bl = 1; $bl <= $toplvl; $bl++) {
					$this->PaintDivBB('pagebottom', 0, $bl);
				}
				$this->y = $sy;
				$this->table_rotate = $save_tr; // *TABLES*
			}
			$s = $this->PrintPageBackgrounds();

			// Writes after the marker so not overwritten later by page background etc.
			$this->pages[$this->page] = preg_replace(
				'/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/',
				'\\1' . "\n" . $s . "\n",
				$this->pages[$this->page]
			);

			$this->pageBackgrounds = [];
			$family = $this->FontFamily;
			$style = $this->FontStyle;
			$size = $this->FontSizePt;
			$lw = $this->LineWidth;
			$dc = $this->DrawColor;
			$fc = $this->FillColor;
			$tc = $this->TextColor;
			$cf = $this->ColorFlag;

			$this->printfloatbuffer();

			// Move to next page
			$this->page++;

			$this->ResetMargins();
			$this->SetAutoPageBreak($this->autoPageBreak, $this->bMargin);
			$this->x = $this->lMargin;
			$this->y = $this->tMargin;
			$this->FontFamily = '';
			$this->writer->write('2 J');
			$this->LineWidth = $lw;
			$this->writer->write(sprintf('%.3F w', $lw * Mpdf::SCALE));

			if ($family) {
				$this->SetFont($family, $style, $size, true, true);
			}

			$this->DrawColor = $dc;

			if ($dc != $this->defDrawColor) {
				$this->writer->write($dc);
			}

			$this->FillColor = $fc;

			if ($fc != $this->defFillColor) {
				$this->writer->write($fc);
			}

			$this->TextColor = $tc;
			$this->ColorFlag = $cf;

			for ($bl = 1; $bl <= $this->blklvl; $bl++) {
				$this->blk[$bl]['y0'] = $this->y;
				// Don't correct more than once for background DIV containing a Float
				if (!isset($this->blk[$bl]['marginCorrected'][$this->page])) {
					if (isset($this->blk[$bl]['x0'])) {
						$this->blk[$bl]['x0'] += $this->MarginCorrection;
					} else {
						$this->blk[$bl]['x0'] = $this->MarginCorrection;
					}
				}
				$this->blk[$bl]['marginCorrected'][$this->page] = true;
			}

			$this->cMarginL = $bak_cml;
			$this->cMarginR = $bak_cmr;
			$this->divwidth = $bak_dw;

			return '';
		}
		/* -- END CSS-FLOAT -- */

		// Start a new page
		if ($this->state == 0) {
			$this->Open();
		}

		$bak_cml = $this->cMarginL;
		$bak_cmr = $this->cMarginR;
		$bak_dw = $this->divwidth;

		$bak_lh = $this->lineheight;

		$orientation = substr(strtoupper($orientation), 0, 1);
		$condition = strtoupper($condition);


		if ($condition == 'E') { // only adds new page if needed to create an Even page
			if (!$this->mirrorMargins || ($this->page) % 2 == 0) {
				return false;
			}
		} elseif ($condition == 'O') { // only adds new page if needed to create an Odd page
			if (!$this->mirrorMargins || ($this->page) % 2 == 1) {
				return false;
			}
		} elseif ($condition == 'NEXT-EVEN') { // always adds at least one new page to create an Even page
			if (!$this->mirrorMargins) {
				$condition = '';
			} else {
				if ($pagesel) {
					$pbch = $pagesel;
					$pagesel = '';
				} // *CSS-PAGE*
				else {
					$pbch = false;
				} // *CSS-PAGE*
				$this->AddPage($this->CurOrientation, 'O');
				$this->extrapagebreak = true; // mPDF 6 pagebreaktype
				if ($pbch) {
					$pagesel = $pbch;
				} // *CSS-PAGE*
				$condition = '';
			}
		} elseif ($condition == 'NEXT-ODD') { // always adds at least one new page to create an Odd page
			if (!$this->mirrorMargins) {
				$condition = '';
			} else {
				if ($pagesel) {
					$pbch = $pagesel;
					$pagesel = '';
				} // *CSS-PAGE*
				else {
					$pbch = false;
				} // *CSS-PAGE*
				$this->AddPage($this->CurOrientation, 'E');
				$this->extrapagebreak = true; // mPDF 6 pagebreaktype
				if ($pbch) {
					$pagesel = $pbch;
				} // *CSS-PAGE*
				$condition = '';
			}
		}

		if ($resetpagenum || $pagenumstyle || $suppress) {
			$this->PageNumSubstitutions[] = ['from' => ($this->page + 1), 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress];
		}

		$save_tr = $this->table_rotate; // *TABLES*
		$this->table_rotate = 0; // *TABLES*
		$save_kwt = $this->kwt;
		$this->kwt = 0;
		$save_layer = $this->current_layer;
		$save_vis = $this->visibility;

		if ($this->visibility != 'visible') {
			$this->SetVisibility('visible');
		}

		$this->EndLayer();

		// Paint Div Border if necessary
		// PAINTS BACKGROUND COLOUR OR BORDERS for DIV - DISABLED FOR COLUMNS (cf. AcceptPageBreak) AT PRESENT in ->PaintDivBB
		if (!$this->ColActive && $this->blklvl > 0) {
			if (isset($this->blk[$this->blklvl]['y0']) && $this->y == $this->blk[$this->blklvl]['y0'] && !$this->extrapagebreak) { // mPDF 6 pagebreaktype
				if (isset($this->blk[$this->blklvl]['startpage'])) {
					$this->blk[$this->blklvl]['startpage'] ++;
				} else {
					$this->blk[$this->blklvl]['startpage'] = 1;
				}
			}
			if ((isset($this->blk[$this->blklvl]['y0']) && $this->y > $this->blk[$this->blklvl]['y0']) || $this->flowingBlockAttr['is_table'] || $this->extrapagebreak) {
				$toplvl = $this->blklvl;
			} // mPDF 6 pagebreaktype
			else {
				$toplvl = $this->blklvl - 1;
			}
			$sy = $this->y;
			for ($bl = 1; $bl <= $toplvl; $bl++) {
				if (isset($this->blk[$bl]['z-index']) && $this->blk[$bl]['z-index'] > 0) {
					$this->BeginLayer($this->blk[$bl]['z-index']);
				}
				if (isset($this->blk[$bl]['visibility']) && $this->blk[$bl]['visibility'] && $this->blk[$bl]['visibility'] != 'visible') {
					$this->SetVisibility($this->blk[$bl]['visibility']);
				}
				$this->PaintDivBB('pagebottom', 0, $bl);
			}
			$this->y = $sy;
			// RESET block y0 and x0 - see below
		}
		$this->extrapagebreak = false; // mPDF 6 pagebreaktype

		if ($this->visibility != 'visible') {
			$this->SetVisibility('visible');
		}

		$this->EndLayer();

		// BODY Backgrounds
		if ($this->page > 0) {
			$s = '';
			$s .= $this->PrintBodyBackgrounds();

			$s .= $this->PrintPageBackgrounds();
			$this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', "\n" . $s . "\n" . '\\1', $this->pages[$this->page]);
			$this->pageBackgrounds = [];
		}

		$save_kt = $this->keep_block_together;
		$this->keep_block_together = 0;

		$save_cols = false;

		/* -- COLUMNS -- */
		if ($this->ColActive) {
			$save_cols = true;
			$save_nbcol = $this->NbCol; // other values of gap and vAlign will not change by setting Columns off
			$this->SetColumns(0);
		}
		/* -- END COLUMNS -- */

		$family = $this->FontFamily;
		$style = $this->FontStyle;
		$size = $this->FontSizePt;
		$this->ColumnAdjust = true; // enables column height adjustment for the page
		$lw = $this->LineWidth;
		$dc = $this->DrawColor;
		$fc = $this->FillColor;
		$tc = $this->TextColor;
		$cf = $this->ColorFlag;
		if ($this->page > 0) {
			// Page footer
			$this->InFooter = true;

			$this->Reset();
			$this->pageoutput[$this->page] = [];

			$this->Footer();
			// Close page
			$this->_endpage();
		}

		// Start new page
		$pageBeforeNewPage = $this->page;
		$this->_beginpage($orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $newformat);
		$isNewPage = $pageBeforeNewPage !== $this->page;

		if ($this->docTemplate) {
			$currentReaderId = $this->currentReaderId;

			$pagecount = $this->setSourceFile($this->docTemplate);
			if (($this->page - $this->docTemplateStart) > $pagecount) {
				if ($this->docTemplateContinue) {
					if ($this->docTemplateContinue2pages && $pagecount >= 2 && (0 === $this->page % 2)) {
						$tplIdx = $this->importPage(($pagecount - 1));
						$this->useTemplate($tplIdx);
					} else {
						$tplIdx = $this->importPage($pagecount);
						$this->useTemplate($tplIdx);
					}
				}
			} else {
				$tplIdx = $this->importPage(($this->page - $this->docTemplateStart));
				$this->useTemplate($tplIdx);
			}

			$this->currentReaderId = $currentReaderId;
		}

		if ($this->pageTemplate) {
			$this->useTemplate($this->pageTemplate);
		}

		// Only add the headers if it's a new page
		if ($isNewPage) {
			// Tiling Patterns
			$this->writer->write('___PAGE___START' . $this->uniqstr);
			$this->writer->write('___BACKGROUND___PATTERNS' . $this->uniqstr);
			$this->writer->write('___HEADER___MARKER' . $this->uniqstr);
		}

		$this->pageBackgrounds = [];

		// Set line cap style to square
		$this->SetLineCap(2);
		// Set line width
		$this->LineWidth = $lw;
		$this->writer->write(sprintf('%.3F w', $lw * Mpdf::SCALE));
		// Set font
		if ($family) {
			$this->SetFont($family, $style, $size, true, true); // forces write
		}

		// Set colors
		$this->DrawColor = $dc;
		if ($dc != $this->defDrawColor) {
			$this->writer->write($dc);
		}
		$this->FillColor = $fc;
		if ($fc != $this->defFillColor) {
			$this->writer->write($fc);
		}
		$this->TextColor = $tc;
		$this->ColorFlag = $cf;

		// Page header
		$this->Header();

		// Restore line width
		if ($this->LineWidth != $lw) {
			$this->LineWidth = $lw;
			$this->writer->write(sprintf('%.3F w', $lw * Mpdf::SCALE));
		}
		// Restore font
		if ($family) {
			$this->SetFont($family, $style, $size, true, true); // forces write
		}

		// Restore colors
		if ($this->DrawColor != $dc) {
			$this->DrawColor = $dc;
			$this->writer->write($dc);
		}
		if ($this->FillColor != $fc) {
			$this->FillColor = $fc;
			$this->writer->write($fc);
		}
		$this->TextColor = $tc;
		$this->ColorFlag = $cf;
		$this->InFooter = false;

		if ($save_layer > 0) {
			$this->BeginLayer($save_layer);
		}

		if ($save_vis != 'visible') {
			$this->SetVisibility($save_vis);
		}

		/* -- COLUMNS -- */
		if ($save_cols) {
			// Restore columns
			$this->SetColumns($save_nbcol, $this->colvAlign, $this->ColGap);
		}
		if ($this->ColActive) {
			$this->SetCol(0);
		}
		/* -- END COLUMNS -- */


		// RESET BLOCK BORDER TOP
		if (!$this->ColActive) {
			for ($bl = 1; $bl <= $this->blklvl; $bl++) {
				$this->blk[$bl]['y0'] = $this->y;
				if (isset($this->blk[$bl]['x0'])) {
					$this->blk[$bl]['x0'] += $this->MarginCorrection;
				} else {
					$this->blk[$bl]['x0'] = $this->MarginCorrection;
				}
				// Added mPDF 3.0 Float DIV
				$this->blk[$bl]['marginCorrected'][$this->page] = true;
			}
		}


		$this->table_rotate = $save_tr; // *TABLES*
		$this->kwt = $save_kwt;

		$this->keep_block_together = $save_kt;

		$this->cMarginL = $bak_cml;
		$this->cMarginR = $bak_cmr;
		$this->divwidth = $bak_dw;

		$this->lineheight = $bak_lh;
	}

	/**
	 * Get current page number
	 *
	 * @return int
	 */
	function PageNo()
	{
		return $this->page;
	}

	function AddSpotColorsFromFile($file)
	{
		$colors = @file($file);
		if (!$colors) {
			throw new \Mpdf\MpdfException("Cannot load spot colors file - " . $file);
		}
		foreach ($colors as $sc) {
			list($name, $c, $m, $y, $k) = preg_split("/\t/", $sc);
			$c = intval($c);
			$m = intval($m);
			$y = intval($y);
			$k = intval($k);
			$this->AddSpotColor($name, $c, $m, $y, $k);
		}
	}

	function AddSpotColor($name, $c, $m, $y, $k)
	{
		$name = strtoupper(trim($name));
		if (!isset($this->spotColors[$name])) {
			$i = count($this->spotColors) + 1;
			$this->spotColors[$name] = ['i' => $i, 'c' => $c, 'm' => $m, 'y' => $y, 'k' => $k];
			$this->spotColorIDs[$i] = $name;
		}
	}

	function SetColor($col, $type = '')
	{
		$out = '';
		if (!$col) {
			return '';
		} // mPDF 6
		if ($col[0] == 3 || $col[0] == 5) { // RGB / RGBa
			$out = sprintf('%.3F %.3F %.3F rg', ord($col[1]) / 255, ord($col[2]) / 255, ord($col[3]) / 255);
		} elseif ($col[0] == 1) { // GRAYSCALE
			$out = sprintf('%.3F g', ord($col[1]) / 255);
		} elseif ($col[0] == 2) { // SPOT COLOR
			$out = sprintf('/CS%d cs %.3F scn', ord($col[1]), ord($col[2]) / 100);
		} elseif ($col[0] == 4 || $col[0] == 6) { // CMYK / CMYKa
			$out = sprintf('%.3F %.3F %.3F %.3F k', ord($col[1]) / 100, ord($col[2]) / 100, ord($col[3]) / 100, ord($col[4]) / 100);
		}
		if ($type == 'Draw') {
			$out = strtoupper($out);
		} // e.g. rg => RG
		elseif ($type == 'CodeOnly') {
			$out = preg_replace('/\s(rg|g|k)/', '', $out);
		}
		return $out;
	}

	function SetDColor($col, $return = false)
	{
		$out = $this->SetColor($col, 'Draw');
		if ($return) {
			return $out;
		}
		if ($out == '') {
			return '';
		}
		$this->DrawColor = $out;
		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['DrawColor']) && $this->pageoutput[$this->page]['DrawColor'] != $this->DrawColor) || !isset($this->pageoutput[$this->page]['DrawColor']))) {
			$this->writer->write($this->DrawColor);
		}
		$this->pageoutput[$this->page]['DrawColor'] = $this->DrawColor;
	}

	function SetFColor($col, $return = false)
	{
		$out = $this->SetColor($col, 'Fill');
		if ($return) {
			return $out;
		}
		if ($out == '') {
			return '';
		}
		$this->FillColor = $out;
		$this->ColorFlag = ($out != $this->TextColor);
		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['FillColor']) && $this->pageoutput[$this->page]['FillColor'] != $this->FillColor) || !isset($this->pageoutput[$this->page]['FillColor']))) {
			$this->writer->write($this->FillColor);
		}
		$this->pageoutput[$this->page]['FillColor'] = $this->FillColor;
	}

	function SetTColor($col, $return = false)
	{
		$out = $this->SetColor($col, 'Text');
		if ($return) {
			return $out;
		}
		if ($out == '') {
			return '';
		}
		$this->TextColor = $out;
		$this->ColorFlag = ($this->FillColor != $out);
	}

	function SetDrawColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
	{
		// Set color for all stroking operations
		$col = [];
		if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) {
			$col = $this->colorConverter->convert($r, $this->PDFAXwarnings);
		} elseif ($col4 == -1) {
			$col = $this->colorConverter->convert('rgb(' . $r . ',' . $g . ',' . $b . ')', $this->PDFAXwarnings);
		} else {
			$col = $this->colorConverter->convert('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')', $this->PDFAXwarnings);
		}
		$out = $this->SetDColor($col, $return);
		return $out;
	}

	function SetFillColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
	{
		// Set color for all filling operations
		$col = [];
		if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) {
			$col = $this->colorConverter->convert($r, $this->PDFAXwarnings);
		} elseif ($col4 == -1) {
			$col = $this->colorConverter->convert('rgb(' . $r . ',' . $g . ',' . $b . ')', $this->PDFAXwarnings);
		} else {
			$col = $this->colorConverter->convert('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')', $this->PDFAXwarnings);
		}
		$out = $this->SetFColor($col, $return);
		return $out;
	}

	function SetTextColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
	{
		// Set color for text
		$col = [];
		if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) {
			$col = $this->colorConverter->convert($r, $this->PDFAXwarnings);
		} elseif ($col4 == -1) {
			$col = $this->colorConverter->convert('rgb(' . $r . ',' . $g . ',' . $b . ')', $this->PDFAXwarnings);
		} else {
			$col = $this->colorConverter->convert('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')', $this->PDFAXwarnings);
		}
		$out = $this->SetTColor($col, $return);
		return $out;
	}

	function _getCharWidth(&$cw, $u, $isdef = true)
	{
		$w = 0;

		if ($u == 0) {
			$w = false;
		} elseif (isset($cw[$u * 2 + 1])) {
			$w = (ord($cw[$u * 2]) << 8) + ord($cw[$u * 2 + 1]);
		}

		if ($w == 65535) {
			return 0;
		} elseif ($w) {
			return $w;
		} elseif ($isdef) {
			return false;
		} else {
			return 0;
		}
	}

	function _charDefined(&$cw, $u)
	{
		$w = 0;
		if ($u == 0) {
			return false;
		}
		if (isset($cw[$u * 2 + 1])) {
			$w = (ord($cw[$u * 2]) << 8) + ord($cw[$u * 2 + 1]);
		}

		return (bool) $w;
	}

	function GetCharWidthCore($c)
	{
		// Get width of a single character in the current Core font
		$c = (string) $c;
		$w = 0;
		// Soft Hyphens chr(173)
		if ($c == chr(173) && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
			return 0;
		} elseif (($this->textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[ord($c)])) {  // mPDF 5.7.1
			$charw = $this->CurrentFont['cw'][chr($this->upperCase[ord($c)])];
			if ($charw !== false) {
				$charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
				$w+=$charw;
			}
		} elseif (isset($this->CurrentFont['cw'][$c])) {
			$w += $this->CurrentFont['cw'][$c];
		} elseif (isset($this->CurrentFont['cw'][ord($c)])) {
			$w += $this->CurrentFont['cw'][ord($c)];
		}
		$w *= ($this->FontSize / 1000);
		if ($this->minwSpacing || $this->fixedlSpacing) {
			if ($c == ' ') {
				$nb_spaces = 1;
			} else {
				$nb_spaces = 0;
			}
			$w += $this->fixedlSpacing + ($nb_spaces * $this->minwSpacing);
		}
		return ($w);
	}

	function GetCharWidthNonCore($c, $addSubset = true)
	{
		// Get width of a single character in the current Non-Core font
		$c = (string) $c;
		$w = 0;
		$unicode = $this->UTF8StringToArray($c, $addSubset);
		$char = $unicode[0];
		/* -- CJK-FONTS -- */
		if ($this->CurrentFont['type'] == 'Type0') { // CJK Adobe fonts
			if ($char == 173) {
				return 0;
			} // Soft Hyphens
			elseif (isset($this->CurrentFont['cw'][$char])) {
				$w+=$this->CurrentFont['cw'][$char];
			} elseif (isset($this->CurrentFont['MissingWidth'])) {
				$w += $this->CurrentFont['MissingWidth'];
			} else {
				$w += 500;
			}
		} else {
			/* -- END CJK-FONTS -- */
			if ($char == 173) {
				return 0;
			} // Soft Hyphens
			elseif (($this->textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[$char])) { // mPDF 5.7.1
				$charw = $this->_getCharWidth($this->CurrentFont['cw'], $this->upperCase[$char]);
				if ($charw !== false) {
					$charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
					$w+=$charw;
				} elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
					$w += $this->CurrentFont['desc']['MissingWidth'];
				} elseif (isset($this->CurrentFont['MissingWidth'])) {
					$w += $this->CurrentFont['MissingWidth'];
				} else {
					$w += 500;
				}
			} else {
				$charw = $this->_getCharWidth($this->CurrentFont['cw'], $char);
				if ($charw !== false) {
					$w+=$charw;
				} elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
					$w += $this->CurrentFont['desc']['MissingWidth'];
				} elseif (isset($this->CurrentFont['MissingWidth'])) {
					$w += $this->CurrentFont['MissingWidth'];
				} else {
					$w += 500;
				}
			}
		} // *CJK-FONTS*
		$w *= ($this->FontSize / 1000);
		if ($this->minwSpacing || $this->fixedlSpacing) {
			if ($c == ' ') {
				$nb_spaces = 1;
			} else {
				$nb_spaces = 0;
			}
			$w += $this->fixedlSpacing + ($nb_spaces * $this->minwSpacing);
		}
		return ($w);
	}

	function GetCharWidth($c, $addSubset = true)
	{
		if (!$this->usingCoreFont) {
			return $this->GetCharWidthNonCore($c, $addSubset);
		} else {
			return $this->GetCharWidthCore($c);
		}
	}

	function GetStringWidth($s, $addSubset = true, $OTLdata = false, $textvar = 0, $includeKashida = false)
	{
	// mPDF 5.7.1
		// Get width of a string in the current font
		$s = (string) $s;
		$cw = &$this->CurrentFont['cw'];
		$w = 0;
		$kerning = 0;
		$lastchar = 0;
		$nb_carac = 0;
		$nb_spaces = 0;
		$kashida = 0;
		// mPDF ITERATION
		if ($this->iterationCounter) {
			$s = preg_replace('/{iteration ([a-zA-Z0-9_]+)}/', '\\1', $s);
		}
		if (!$this->usingCoreFont) {
			$discards = substr_count($s, "\xc2\xad"); // mPDF 6 soft hyphens [U+00AD]
			$unicode = $this->UTF8StringToArray($s, $addSubset);
			if ($this->minwSpacing || $this->fixedlSpacing) {
				$nb_spaces = mb_substr_count($s, ' ', $this->mb_enc);
				$nb_carac = count($unicode) - $discards; // mPDF 6
				// mPDF 5.7.1
				// Use GPOS OTL
				if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
					if (isset($OTLdata['group']) && $OTLdata['group']) {
						$nb_carac -= substr_count($OTLdata['group'], 'M');
					}
				}
			}
			/* -- CJK-FONTS -- */
			if ($this->CurrentFont['type'] == 'Type0') { // CJK Adobe fonts
				foreach ($unicode as $char) {
					if ($char == 0x00AD) {
						continue;
					} // mPDF 6 soft hyphens [U+00AD]
					if (isset($cw[$char])) {
						$w+=$cw[$char];
					} elseif (isset($this->CurrentFont['MissingWidth'])) {
						$w += $this->CurrentFont['MissingWidth'];
					} else {
						$w += 500;
					}
				}
			} else {
				/* -- END CJK-FONTS -- */
				foreach ($unicode as $i => $char) {
					if ($char == 0x00AD) {
						continue;
					} // mPDF 6 soft hyphens [U+00AD]
					if (($textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[$char])) {
						$charw = $this->_getCharWidth($cw, $this->upperCase[$char]);
						if ($charw !== false) {
							$charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
							$w+=$charw;
						} elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
							$w += $this->CurrentFont['desc']['MissingWidth'];
						} elseif (isset($this->CurrentFont['MissingWidth'])) {
							$w += $this->CurrentFont['MissingWidth'];
						} else {
							$w += 500;
						}
					} else {
						$charw = $this->_getCharWidth($cw, $char);
						if ($charw !== false) {
							$w+=$charw;
						} elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
							$w += $this->CurrentFont['desc']['MissingWidth'];
						} elseif (isset($this->CurrentFont['MissingWidth'])) {
							$w += $this->CurrentFont['MissingWidth'];
						} else {
							$w += 500;
						}
						// mPDF 5.7.1
						// Use GPOS OTL
						// ...GetStringWidth...
						if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && !empty($OTLdata)) {
							if (isset($OTLdata['GPOSinfo'][$i]['wDir']) && $OTLdata['GPOSinfo'][$i]['wDir'] == 'RTL') {
								if (isset($OTLdata['GPOSinfo'][$i]['XAdvanceR']) && $OTLdata['GPOSinfo'][$i]['XAdvanceR']) {
									$w += $OTLdata['GPOSinfo'][$i]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
								}
							} else {
								if (isset($OTLdata['GPOSinfo'][$i]['XAdvanceL']) && $OTLdata['GPOSinfo'][$i]['XAdvanceL']) {
									$w += $OTLdata['GPOSinfo'][$i]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
								}
							}
							// Kashida from GPOS
							// Kashida is set as an absolute length value (already set as a proportion based on useKashida %)
							if ($includeKashida && isset($OTLdata['GPOSinfo'][$i]['kashida_space']) && $OTLdata['GPOSinfo'][$i]['kashida_space']) {
								$kashida += $OTLdata['GPOSinfo'][$i]['kashida_space'];
							}
						}
						if (($textvar & TextVars::FC_KERNING) && $lastchar) {
							if (isset($this->CurrentFont['kerninfo'][$lastchar][$char])) {
								$kerning += $this->CurrentFont['kerninfo'][$lastchar][$char];
							}
						}
						$lastchar = $char;
					}
				}
			} // *CJK-FONTS*
		} else {
			if ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
				$s = str_replace(chr(173), '', $s);
			}
			$nb_carac = $l = strlen($s);
			if ($this->minwSpacing || $this->fixedlSpacing) {
				$nb_spaces = substr_count($s, ' ');
			}
			for ($i = 0; $i < $l; $i++) {
				if (($textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[ord($s[$i])])) {  // mPDF 5.7.1
					$charw = $cw[chr($this->upperCase[ord($s[$i])])];
					if ($charw !== false) {
						$charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
						$w+=$charw;
					}
				} elseif (isset($cw[$s[$i]])) {
					$w += $cw[$s[$i]];
				} elseif (isset($cw[ord($s[$i])])) {
					$w += $cw[ord($s[$i])];
				}
				if (($textvar & TextVars::FC_KERNING) && $i > 0) { // mPDF 5.7.1
					if (isset($this->CurrentFont['kerninfo'][$s[($i - 1)]][$s[$i]])) {
						$kerning += $this->CurrentFont['kerninfo'][$s[($i - 1)]][$s[$i]];
					}
				}
			}
		}
		unset($cw);
		if ($textvar & TextVars::FC_KERNING) {
			$w += $kerning;
		} // mPDF 5.7.1
		$w *= ($this->FontSize / 1000);
		$w += (($nb_carac + $nb_spaces) * $this->fixedlSpacing) + ($nb_spaces * $this->minwSpacing);
		$w += $kashida / Mpdf::SCALE;

		return ($w);
	}

	function SetLineWidth($width)
	{
		// Set line width
		$this->LineWidth = $width;
		$lwout = (sprintf('%.3F w', $width * Mpdf::SCALE));
		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineWidth']) && $this->pageoutput[$this->page]['LineWidth'] != $lwout) || !isset($this->pageoutput[$this->page]['LineWidth']))) {
			$this->writer->write($lwout);
		}
		$this->pageoutput[$this->page]['LineWidth'] = $lwout;
	}

	function Line($x1, $y1, $x2, $y2)
	{
		// Draw a line
		$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));
	}

	function Arrow($x1, $y1, $x2, $y2, $headsize = 3, $fill = 'B', $angle = 25)
	{
		// F == fill // S == stroke // B == stroke and fill
		// angle = splay of arrowhead - 1 - 89 degrees
		if ($fill == 'F') {
			$fill = 'f';
		} elseif ($fill == 'FD' or $fill == 'DF' or $fill == 'B') {
			$fill = 'B';
		} else {
			$fill = 'S';
		}
		$a = atan2(($y2 - $y1), ($x2 - $x1));
		$b = $a + deg2rad($angle);
		$c = $a - deg2rad($angle);
		$x3 = $x2 - ($headsize * cos($b));
		$y3 = $this->h - ($y2 - ($headsize * sin($b)));
		$x4 = $x2 - ($headsize * cos($c));
		$y4 = $this->h - ($y2 - ($headsize * sin($c)));

		$x5 = $x3 - ($x3 - $x4) / 2; // mid point of base of arrowhead - to join arrow line to
		$y5 = $y3 - ($y3 - $y4) / 2;

		$s = '';
		$s .= sprintf('%.3F %.3F m %.3F %.3F l S', $x1 * Mpdf::SCALE, ($this->h - $y1) * Mpdf::SCALE, $x5 * Mpdf::SCALE, $y5 * Mpdf::SCALE);
		$this->writer->write($s);

		$s = '';
		$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);
		$s .= $fill;
		$this->writer->write($s);
	}

	function Rect($x, $y, $w, $h, $style = '')
	{
		// Draw a rectangle
		if ($style == 'F') {
			$op = 'f';
		} elseif ($style == 'FD' or $style == 'DF') {
			$op = 'B';
		} else {
			$op = 'S';
		}
		$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));
	}

	function AddFontDirectory($directory)
	{
		$this->fontDir[] = $directory;
		$this->fontFileFinder->setDirectories($this->fontDir);
	}

	function AddFont($family, $style = '')
	{
		if (empty($family)) {
			return;
		}

		$family = strtolower($family);
		$style = strtoupper($style);
		$style = str_replace('U', '', $style);

		if ($style == 'IB') {
			$style = 'BI';
		}

		$fontkey = $family . $style;

		// check if the font has been already added
		if (isset($this->fonts[$fontkey])) {
			return;
		}

		/* -- CJK-FONTS -- */
		if (in_array($family, $this->available_CJK_fonts)) {
			if (empty($this->Big5_widths)) {
				require __DIR__ . '/../data/CJKdata.php';
			}
			$this->AddCJKFont($family); // don't need to add style
			return;
		}
		/* -- END CJK-FONTS -- */

		if ($this->usingCoreFont) {
			throw new \Mpdf\MpdfException("mPDF Error - problem with Font management");
		}

		$stylekey = $style;
		if (!$style) {
			$stylekey = 'R';
		}

		if (!isset($this->fontdata[$family][$stylekey]) || !$this->fontdata[$family][$stylekey]) {
			throw new \Mpdf\MpdfException(sprintf('Font "%s%s%s" is not supported', $family, $style ? ' - ' : '', $style));
		}

		/* Setup defaults */
		$font = [
			'name' => '',
			'type' => '',
			'desc' => '',
			'panose' => '',
			'unitsPerEm' => '',
			'up' => '',
			'ut' => '',
			'strs' => '',
			'strp' => '',
			'sip' => false,
			'smp' => false,
			'useOTL' => 0,
			'fontmetrics' => '',
			'haskerninfo' => false,
			'haskernGPOS' => false,
			'hassmallcapsGSUB' => false,
			'BMPselected' => false,
			'GSUBScriptLang' => [],
			'GSUBFeatures' => [],
			'GSUBLookups' => [],
			'GPOSScriptLang' => [],
			'GPOSFeatures' => [],
			'GPOSLookups' => [],
			'rtlPUAstr' => '',
		];

		$fontCacheFilename = $fontkey . '.mtx.json';
		if ($this->fontCache->jsonHas($fontCacheFilename)) {
			$font = $this->fontCache->jsonLoad($fontCacheFilename);
		}

		$ttffile = $this->fontFileFinder->findFontFile($this->fontdata[$family][$stylekey]);
		$ttfstat = stat($ttffile);

		$TTCfontID = isset($this->fontdata[$family]['TTCfontID'][$stylekey]) ? isset($this->fontdata[$family]['TTCfontID'][$stylekey]) : 0;
		$fontUseOTL = isset($this->fontdata[$family]['useOTL']) ? $this->fontdata[$family]['useOTL'] : false;
		$BMPonly = in_array($family, $this->BMPonly) ? true : false;

		$regenerate = false;
		if ($BMPonly && !$font['BMPselected']) {
			$regenerate = true;
		} elseif (!$BMPonly && $font['BMPselected']) {
			$regenerate = true;
		}

		if ($fontUseOTL && $font['useOTL'] != $fontUseOTL) {
			$regenerate = true;
			$font['useOTL'] = $fontUseOTL;
		} elseif (!$fontUseOTL && $font['useOTL']) {
			$regenerate = true;
			$font['useOTL'] = 0;
		}

		if ($this->fontDescriptor != $font['fontmetrics']) {
			$regenerate = true;
		} // mPDF 6

		if (empty($font['name']) || $font['originalsize'] != $ttfstat['size'] || $regenerate) {
			$generator = new MetricsGenerator($this->fontCache, $this->fontDescriptor);

			$generator->generateMetrics(
				$ttffile,
				$ttfstat,
				$fontkey,
				$TTCfontID,
				$this->debugfonts,
				$BMPonly,
				$font['useOTL'],
				$fontUseOTL
			);

			$font = $this->fontCache->jsonLoad($fontCacheFilename);
			$cw = $this->fontCache->load($fontkey . '.cw.dat');
			$glyphIDtoUni = $this->fontCache->load($fontkey . '.gid.dat');
		} else {
			if ($this->fontCache->has($fontkey . '.cw.dat')) {
				$cw = $this->fontCache->load($fontkey . '.cw.dat');
			}

			if ($this->fontCache->has($fontkey . '.gid.dat')) {
				$glyphIDtoUni = $this->fontCache->load($fontkey . '.gid.dat');
			}
		}

		if (isset($this->fontdata[$family]['sip-ext']) && $this->fontdata[$family]['sip-ext']) {
			$sipext = $this->fontdata[$family]['sip-ext'];
		} else {
			$sipext = '';
		}

		// Override with values from config_font.php
		if (isset($this->fontdata[$family]['Ascent']) && $this->fontdata[$family]['Ascent']) {
			$desc['Ascent'] = $this->fontdata[$family]['Ascent'];
		}
		if (isset($this->fontdata[$family]['Descent']) && $this->fontdata[$family]['Descent']) {
			$desc['Descent'] = $this->fontdata[$family]['Descent'];
		}
		if (isset($this->fontdata[$family]['Leading']) && $this->fontdata[$family]['Leading']) {
			$desc['Leading'] = $this->fontdata[$family]['Leading'];
		}

		$i = count($this->fonts) + $this->extraFontSubsets + 1;

		$this->fonts[$fontkey] = [
			'i' => $i,
			'name' => $font['name'],
			'type' => $font['type'],
			'desc' => $font['desc'],
			'panose' => $font['panose'],
			'unitsPerEm' => $font['unitsPerEm'],
			'up' => $font['up'],
			'ut' => $font['ut'],
			'strs' => $font['strs'],
			'strp' => $font['strp'],
			'cw' => $cw,
			'ttffile' => $ttffile,
			'fontkey' => $fontkey,
			'used' => false,
			'sip' => $font['sip'],
			'sipext' => $sipext,
			'smp' => $font['smp'],
			'TTCfontID' => $TTCfontID,
			'useOTL' => $fontUseOTL,
			'useKashida' => (isset($this->fontdata[$family]['useKashida']) ? $this->fontdata[$family]['useKashida'] : false),
			'GSUBScriptLang' => $font['GSUBScriptLang'],
			'GSUBFeatures' => $font['GSUBFeatures'],
			'GSUBLookups' => $font['GSUBLookups'],
			'GPOSScriptLang' => $font['GPOSScriptLang'],
			'GPOSFeatures' => $font['GPOSFeatures'],
			'GPOSLookups' => $font['GPOSLookups'],
			'rtlPUAstr' => $font['rtlPUAstr'],
			'glyphIDtoUni' => $glyphIDtoUni,
			'haskerninfo' => $font['haskerninfo'],
			'haskernGPOS' => $font['haskernGPOS'],
			'hassmallcapsGSUB' => $font['hassmallcapsGSUB'],
		];


		if (!$font['sip'] && !$font['smp']) {
			$subsetRange = range(32, 127);
			$this->fonts[$fontkey]['subset'] = array_combine($subsetRange, $subsetRange);
		} else {
			$this->fonts[$fontkey]['subsets'] = [0 => range(0, 127)];
			$this->fonts[$fontkey]['subsetfontids'] = [$i];
		}

		if ($font['haskerninfo']) {
			$this->fonts[$fontkey]['kerninfo'] = $font['kerninfo'];
		}

		$this->FontFiles[$fontkey] = [
			'length1' => $font['originalsize'],
			'type' => 'TTF',
			'ttffile' => $ttffile,
			'sip' => $font['sip'],
			'smp' => $font['smp'],
		];

		unset($cw);
	}

	function SetFont($family, $style = '', $size = 0, $write = true, $forcewrite = false)
	{
		$family = strtolower($family);

		if (!$this->onlyCoreFonts) {
			if ($family == 'sans' || $family == 'sans-serif') {
				$family = $this->sans_fonts[0];
			}
			if ($family == 'serif') {
				$family = $this->serif_fonts[0];
			}
			if ($family == 'mono' || $family == 'monospace') {
				$family = $this->mono_fonts[0];
			}
		}

		if (isset($this->fonttrans[$family]) && $this->fonttrans[$family]) {
			$family = $this->fonttrans[$family];
		}

		if ($family == '') {
			if ($this->FontFamily) {
				$family = $this->FontFamily;
			} elseif ($this->default_font) {
				$family = $this->default_font;
			} else {
				throw new \Mpdf\MpdfException("No font or default font set!");
			}
		}

		$this->ReqFontStyle = $style; // required or requested style - used later for artificial bold/italic

		if (($family == 'csymbol') || ($family == 'czapfdingbats') || ($family == 'ctimes') || ($family == 'ccourier') || ($family == 'chelvetica')) {
			if ($this->PDFA || $this->PDFX) {
				if ($family == 'csymbol' || $family == 'czapfdingbats') {
					throw new \Mpdf\MpdfException("Symbol and Zapfdingbats cannot be embedded in mPDF (required for PDFA1-b or PDFX/1-a).");
				}
				if ($family == 'ctimes' || $family == 'ccourier' || $family == 'chelvetica') {
					if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
						$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.)";
					}
					if ($family == 'chelvetica') {
						$family = 'sans';
					}
					if ($family == 'ctimes') {
						$family = 'serif';
					}
					if ($family == 'ccourier') {
						$family = 'mono';
					}
				}
				$this->usingCoreFont = false;
			} else {
				$this->usingCoreFont = true;
			}
			if ($family == 'csymbol' || $family == 'czapfdingbats') {
				$style = '';
			}
		} else {
			$this->usingCoreFont = false;
		}

		// mPDF 5.7.1
		if ($style) {
			$style = strtoupper($style);
			if ($style == 'IB') {
				$style = 'BI';
			}
		}

		if (!$size) {
			$size = $this->FontSizePt;
		}

		$fontkey = $family . $style;

		$stylekey = $style;

		if (!$stylekey) {
			$stylekey = "R";
		}

		if (!$this->onlyCoreFonts && !$this->usingCoreFont) {
			if (!isset($this->fonts[$fontkey]) || count($this->default_available_fonts) != count($this->available_unifonts)) { // not already added

				/* -- CJK-FONTS -- */
				if (in_array($fontkey, $this->available_CJK_fonts)) {
					if (!isset($this->fonts[$fontkey])) { // already added
						if (empty($this->Big5_widths)) {
							require __DIR__ . '/../data/CJKdata.php';
						}
						$this->AddCJKFont($family); // don't need to add style
					}
				} else { // Test to see if requested font/style is available - or substitute /* -- END CJK-FONTS -- */
					if (!in_array($fontkey, $this->available_unifonts)) {
						// If font[nostyle] exists - set it
						if (in_array($family, $this->available_unifonts)) {
							$style = '';
						} // elseif only one font available - set it (assumes if only one font available it will not have a style)
						elseif (count($this->available_unifonts) == 1) {
							$family = $this->available_unifonts[0];
							$style = '';
						} else {
							$found = 0;
							// else substitute font of similar type
							if (in_array($family, $this->sans_fonts)) {
								$i = array_intersect($this->sans_fonts, $this->available_unifonts);
								if (count($i)) {
									$i = array_values($i);
									// with requested style if possible
									if (!in_array(($i[0] . $style), $this->available_unifonts)) {
										$style = '';
									}
									$family = $i[0];
									$found = 1;
								}
							} elseif (in_array($family, $this->serif_fonts)) {
								$i = array_intersect($this->serif_fonts, $this->available_unifonts);
								if (count($i)) {
									$i = array_values($i);
									// with requested style if possible
									if (!in_array(($i[0] . $style), $this->available_unifonts)) {
										$style = '';
									}
									$family = $i[0];
									$found = 1;
								}
							} elseif (in_array($family, $this->mono_fonts)) {
								$i = array_intersect($this->mono_fonts, $this->available_unifonts);
								if (count($i)) {
									$i = array_values($i);
									// with requested style if possible
									if (!in_array(($i[0] . $style), $this->available_unifonts)) {
										$style = '';
									}
									$family = $i[0];
									$found = 1;
								}
							}

							if (!$found) {
								// set first available font
								$fs = $this->available_unifonts[0];
								preg_match('/^([a-z_0-9\-]+)([BI]{0,2})$/', $fs, $fas); // Allow "-"
								// with requested style if possible
								$ws = $fas[1] . $style;
								if (in_array($ws, $this->available_unifonts)) {
									$family = $fas[1]; // leave $style as is
								} elseif (in_array($fas[1], $this->available_unifonts)) {
									// or without style
									$family = $fas[1];
									$style = '';
								} else {
									// or with the style specified
									$family = $fas[1];
									$style = $fas[2];
								}
							}
						}
						$fontkey = $family . $style;
					}
				}
			}

			// try to add font (if not already added)
			$this->AddFont($family, $style);

			// Test if font is already selected
			if ($this->FontFamily == $family && $this->FontFamily == $this->currentfontfamily && $this->FontStyle == $style && $this->FontStyle == $this->currentfontstyle && $this->FontSizePt == $size && $this->FontSizePt == $this->currentfontsize && !$forcewrite) {
				return $family;
			}

			$fontkey = $family . $style;

			// Select it
			$this->FontFamily = $family;
			$this->FontStyle = $style;
			$this->FontSizePt = $size;
			$this->FontSize = $size / Mpdf::SCALE;
			$this->CurrentFont = &$this->fonts[$fontkey];
			if ($write) {
				$fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
				if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
					$this->writer->write($fontout);
				}
				$this->pageoutput[$this->page]['Font'] = $fontout;
			}

			// Added - currentfont (lowercase) used in HTML2PDF
			$this->currentfontfamily = $family;
			$this->currentfontsize = $size;
			$this->currentfontstyle = $style;
			$this->setMBencoding('UTF-8');
		} else {  // if using core fonts
			if ($this->PDFA || $this->PDFX) {
				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.');
			}
			$this->setMBencoding('windows-1252');

			// Test if font is already selected
			if (($this->FontFamily == $family) and ( $this->FontStyle == $style) and ( $this->FontSizePt == $size) && !$forcewrite) {
				return $family;
			}

			if (!isset($this->CoreFonts[$fontkey])) {
				if (in_array($family, $this->serif_fonts)) {
					$family = 'ctimes';
				} elseif (in_array($family, $this->mono_fonts)) {
					$family = 'ccourier';
				} else {
					$family = 'chelvetica';
				}
				$this->usingCoreFont = true;
				$fontkey = $family . $style;
			}

			if (!isset($this->fonts[$fontkey])) {
				// STANDARD CORE FONTS
				if (isset($this->CoreFonts[$fontkey])) {
					// Load metric file
					$file = $family;
					if ($family == 'ctimes' || $family == 'chelvetica' || $family == 'ccourier') {
						$file .= strtolower($style);
					}
					require __DIR__ . '/../data/font/' . $file . '.php';
					if (!isset($cw)) {
						throw new \Mpdf\MpdfException(sprintf('Could not include font metric file "%s"', $file));
					}
					$i = count($this->fonts) + $this->extraFontSubsets + 1;
					$this->fonts[$fontkey] = ['i' => $i, 'type' => 'core', 'name' => $this->CoreFonts[$fontkey], 'desc' => $desc, 'up' => $up, 'ut' => $ut, 'cw' => $cw];
					if ($this->useKerning && isset($kerninfo)) {
						$this->fonts[$fontkey]['kerninfo'] = $kerninfo;
					}
				} else {
					throw new \Mpdf\MpdfException(sprintf('Font %s not defined', $fontkey));
				}
			}

			// Test if font is already selected
			if (($this->FontFamily == $family) and ( $this->FontStyle == $style) and ( $this->FontSizePt == $size) && !$forcewrite) {
				return $family;
			}
			// Select it
			$this->FontFamily = $family;
			$this->FontStyle = $style;
			$this->FontSizePt = $size;
			$this->FontSize = $size / Mpdf::SCALE;
			$this->CurrentFont = &$this->fonts[$fontkey];
			if ($write) {
				$fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
				if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
					$this->writer->write($fontout);
				}
				$this->pageoutput[$this->page]['Font'] = $fontout;
			}
			// Added - currentfont (lowercase) used in HTML2PDF
			$this->currentfontfamily = $family;
			$this->currentfontsize = $size;
			$this->currentfontstyle = $style;
		}

		return $family;
	}

	function SetFontSize($size, $write = true)
	{
		// Set font size in points
		if ($this->FontSizePt == $size) {
			return;
		}
		$this->FontSizePt = $size;
		$this->FontSize = $size / Mpdf::SCALE;
		$this->currentfontsize = $size;
		if ($write) {
			$fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
			// Edited mPDF 3.0
			if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
				$this->writer->write($fontout);
			}
			$this->pageoutput[$this->page]['Font'] = $fontout;
		}
	}

	function AddLink()
	{
		// Create a new internal link
		$n = count($this->links) + 1;
		$this->links[$n] = [0, 0];
		return $n;
	}

	function SetLink($link, $y = 0, $page = -1)
	{
		// Set destination of internal link
		if ($y == -1) {
			$y = $this->y;
		}
		if ($page == -1) {
			$page = $this->page;
		}
		$this->links[$link] = [$page, $y];
	}

	function Link($x, $y, $w, $h, $link)
	{
		$l = [$x * Mpdf::SCALE, $this->hPt - $y * Mpdf::SCALE, $w * Mpdf::SCALE, $h * Mpdf::SCALE, $link];
		if ($this->keep_block_together) { // don't write yet
			return;
		} elseif ($this->table_rotate) { // *TABLES*
			$this->tbrot_Links[$this->page][] = $l; // *TABLES*
			return; // *TABLES*
		} // *TABLES*
		elseif ($this->kwt) {
			$this->kwt_Links[$this->page][] = $l;
			return;
		}

		if ($this->writingHTMLheader || $this->writingHTMLfooter) {
			$this->HTMLheaderPageLinks[] = $l;
			return;
		}
		// Put a link on the page
		$this->PageLinks[$this->page][] = $l;
		// Save cross-reference to Column buffer
		$ref = count($this->PageLinks[$this->page]) - 1; // *COLUMNS*
		$this->columnLinks[$this->CurrCol][(int) $this->x][(int) $this->y] = $ref; // *COLUMNS*
	}

	function Text($x, $y, $txt, $OTLdata = [], $textvar = 0, $aixextra = '', $coordsys = '', $return = false)
	{
		// Output (or return) a string
		// Called (internally) by Watermark() & _tableWrite() [rotated cells] & TableHeaderFooter() & WriteText()
		// Called also from classes/svg.php
		// Expects Font to be set
		// Expects input to be mb_encoded if necessary and RTL reversed & OTL processed
		// ARTIFICIAL BOLD AND ITALIC
		$s = 'q ';
		if ($this->falseBoldWeight && strpos($this->ReqFontStyle, "B") !== false && strpos($this->FontStyle, "B") === false) {
			$s .= '2 Tr 1 J 1 j ';
			$s .= sprintf('%.3F w ', ($this->FontSize / 130) * Mpdf::SCALE * $this->falseBoldWeight);
			$tc = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
			if ($this->FillColor != $tc) {
				$s .= $tc . ' ';
			}  // stroke (outline) = same colour as text(fill)
		}
		if (strpos($this->ReqFontStyle, "I") !== false && strpos($this->FontStyle, "I") === false) {
			$aix = '1 0 0.261799 1 %.3F %.3F Tm';
		} else {
			$aix = '%.3F %.3F Td';
		}

		$aix = $aixextra . $aix;

		if ($this->ColorFlag) {
			$s .= $this->TextColor . ' ';
		}

		$this->CurrentFont['used'] = true;

		if ($this->usingCoreFont) {
			$txt2 = str_replace(chr(160), chr(32), $txt);
		} else {
			$txt2 = str_replace(chr(194) . chr(160), chr(32), $txt);
		}

		$px = $x;
		$py = $y;
		if ($coordsys != 'SVG') {
			$px = $x * Mpdf::SCALE;
			$py = ($this->h - $y) * Mpdf::SCALE;
		}


		/** ************** SIMILAR TO Cell() ************************ */

		// IF corefonts AND NOT SmCaps AND NOT Kerning
		// Just output text
		if ($this->usingCoreFont && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING)) {
			$txt2 = $this->writer->escape($txt2);
			$s .= sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
		} // IF NOT corefonts [AND NO wordspacing] AND NOT SIP/SMP AND NOT SmCaps AND NOT Kerning AND NOT OTL
		// Just output text
		elseif (!$this->usingCoreFont && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING) && !(isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && !empty($OTLdata['GPOSinfo']))) {
			// IF SIP/SMP
			if ($this->CurrentFont['sip'] || $this->CurrentFont['smp']) {
				$txt2 = $this->UTF8toSubset($txt2);
				$s .=sprintf('BT ' . $aix . ' %s Tj ET', $px, $py, $txt2);
			} // NOT SIP/SMP
			else {
				$txt2 = $this->writer->utf8ToUtf16BigEndian($txt2, false);
				$txt2 = $this->writer->escape($txt2);
				$s .=sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
			}
		} // IF NOT corefonts [AND IS wordspacing] AND NOT SIP AND NOT SmCaps AND NOT Kerning AND NOT OTL
		// Not required here (cf. Cell() )
		// ELSE (IF SmCaps || Kerning || OTL) [corefonts or not corefonts; SIP or SMP or BMP]
		else {
			$s .= $this->applyGPOSpdf($txt2, $aix, $px, $py, $OTLdata, $textvar);
		}
		/*         * ************** END ************************ */

		$s .= ' ';

		if (($textvar & TextVars::FD_UNDERLINE) && $txt != '') { // mPDF 5.7.1
			$c = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
			if ($this->FillColor != $c) {
				$s.= ' ' . $c . ' ';
			}
			if (isset($this->CurrentFont['up']) && $this->CurrentFont['up']) {
				$up = $this->CurrentFont['up'];
			} else {
				$up = -100;
			}
			$adjusty = (-$up / 1000 * $this->FontSize);
			if (isset($this->CurrentFont['ut']) && $this->CurrentFont['ut']) {
				$ut = $this->CurrentFont['ut'] / 1000 * $this->FontSize;
			} else {
				$ut = 60 / 1000 * $this->FontSize;
			}
			$olw = $this->LineWidth;
			$s .= ' ' . (sprintf(' %.3F w', $ut * Mpdf::SCALE));
			$s .= ' ' . $this->_dounderline($x, $y + $adjusty, $txt, $OTLdata, $textvar);
			$s .= ' ' . (sprintf(' %.3F w', $olw * Mpdf::SCALE));
			if ($this->FillColor != $c) {
				$s.= ' ' . $this->FillColor . ' ';
			}
		}
		// STRIKETHROUGH
		if (($textvar & TextVars::FD_LINETHROUGH) && $txt != '') { // mPDF 5.7.1
			$c = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
			if ($this->FillColor != $c) {
				$s.= ' ' . $c . ' ';
			}
			// Superscript and Subscript Y coordinate adjustment (now for striked-through texts)
			if (isset($this->CurrentFont['desc']['CapHeight']) && $this->CurrentFont['desc']['CapHeight']) {
				$ch = $this->CurrentFont['desc']['CapHeight'];
			} else {
				$ch = 700;
			}
			$adjusty = (-$ch / 1000 * $this->FontSize) * 0.35;
			if (isset($this->CurrentFont['ut']) && $this->CurrentFont['ut']) {
				$ut = $this->CurrentFont['ut'] / 1000 * $this->FontSize;
			} else {
				$ut = 60 / 1000 * $this->FontSize;
			}
			$olw = $this->LineWidth;
			$s .= ' ' . (sprintf(' %.3F w', $ut * Mpdf::SCALE));
			$s .= ' ' . $this->_dounderline($x, $y + $adjusty, $txt, $OTLdata, $textvar);
			$s .= ' ' . (sprintf(' %.3F w', $olw * Mpdf::SCALE));
			if ($this->FillColor != $c) {
				$s.= ' ' . $this->FillColor . ' ';
			}
		}
		$s .= 'Q';

		if ($return) {
			return $s . " \n";
		}
		$this->writer->write($s);
	}

	/* -- DIRECTW -- */

	function WriteText($x, $y, $txt)
	{
		// Output a string using Text() but does encoding and text reversing of RTL
		$txt = $this->purify_utf8_text($txt);
		if ($this->text_input_as_HTML) {
			$txt = $this->all_entities_to_utf8($txt);
		}
		if ($this->usingCoreFont) {
			$txt = mb_convert_encoding($txt, $this->mb_enc, 'UTF-8');
		}

		// DIRECTIONALITY
		if (preg_match("/([" . $this->pregRTLchars . "])/u", $txt)) {
			$this->biDirectional = true;
		} // *OTL*

		$textvar = 0;
		$save_OTLtags = $this->OTLtags;
		$this->OTLtags = [];
		if ($this->useKerning) {
			if ($this->CurrentFont['haskernGPOS']) {
				$this->OTLtags['Plus'] .= ' kern';
			} else {
				$textvar = ($textvar | TextVars::FC_KERNING);
			}
		}

		/* -- OTL -- */
		// Use OTL OpenType Table Layout - GSUB & GPOS
		if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
			$txt = $this->otl->applyOTL($txt, $this->CurrentFont['useOTL']);
			$OTLdata = $this->otl->OTLdata;
		}
		/* -- END OTL -- */
		$this->OTLtags = $save_OTLtags;

		$this->magic_reverse_dir($txt, $this->directionality, $OTLdata);

		$this->Text($x, $y, $txt, $OTLdata, $textvar);
	}

	function WriteCell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = 0, $link = '', $currentx = 0)
	{
		// Output a cell using Cell() but does encoding and text reversing of RTL
		$txt = $this->purify_utf8_text($txt);
		if ($this->text_input_as_HTML) {
			$txt = $this->all_entities_to_utf8($txt);
		}
		if ($this->usingCoreFont) {
			$txt = mb_convert_encoding($txt, $this->mb_enc, 'UTF-8');
		}
		// DIRECTIONALITY
		if (preg_match("/([" . $this->pregRTLchars . "])/u", $txt)) {
			$this->biDirectional = true;
		} // *OTL*

		$textvar = 0;
		$save_OTLtags = $this->OTLtags;
		$this->OTLtags = [];
		if ($this->useKerning) {
			if ($this->CurrentFont['haskernGPOS']) {
				$this->OTLtags['Plus'] .= ' kern';
			} else {
				$textvar = ($textvar | TextVars::FC_KERNING);
			}
		}

		/* -- OTL -- */
		// Use OTL OpenType Table Layout - GSUB & GPOS
		if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
			$txt = $this->otl->applyOTL($txt, $this->CurrentFont['useOTL']);
			$OTLdata = $this->otl->OTLdata;
		}
		/* -- END OTL -- */
		$this->OTLtags = $save_OTLtags;

		$this->magic_reverse_dir($txt, $this->directionality, $OTLdata);

		$this->Cell($w, $h, $txt, $border, $ln, $align, $fill, $link, $currentx, 0, 0, 'M', 0, false, $OTLdata, $textvar);
	}

	/* -- END DIRECTW -- */

	function ResetSpacing()
	{
		if ($this->ws != 0) {
			$this->writer->write('BT 0 Tw ET');
		}
		$this->ws = 0;
		if ($this->charspacing != 0) {
			$this->writer->write('BT 0 Tc ET');
		}
		$this->charspacing = 0;
	}

	function SetSpacing($cs, $ws)
	{
		if (intval($cs * 1000) == 0) {
			$cs = 0;
		}
		if ($cs) {
			$this->writer->write(sprintf('BT %.3F Tc ET', $cs));
		} elseif ($this->charspacing != 0) {
			$this->writer->write('BT 0 Tc ET');
		}
		$this->charspacing = $cs;
		if (intval($ws * 1000) == 0) {
			$ws = 0;
		}
		if ($ws) {
			$this->writer->write(sprintf('BT %.3F Tw ET', $ws));
		} elseif ($this->ws != 0) {
			$this->writer->write('BT 0 Tw ET');
		}
		$this->ws = $ws;
	}

	// WORD SPACING
	function GetJspacing($nc, $ns, $w, $inclCursive, &$cOTLdata)
	{
		$kashida_present = false;
		$kashida_space = 0;
		if ($w > 0 && $inclCursive && isset($this->CurrentFont['useKashida']) && $this->CurrentFont['useKashida'] && !empty($cOTLdata)) {
			for ($c = 0; $c < count($cOTLdata); $c++) {
				for ($i = 0; $i < strlen($cOTLdata[$c]['group']); $i++) {
					if (isset($cOTLdata[$c]['GPOSinfo'][$i]['kashida']) && $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > 0) {
						$kashida_present = true;
						break 2;
					}
				}
			}
		}

		if ($kashida_present) {
			$k_ctr = 0;  // Number of kashida points
			$k_total = 0;  // Total of kashida values (priority)
			// Reset word
			$max_kashida_in_word = 0;
			$last_kashida_in_word = -1;

			for ($c = 0; $c < count($cOTLdata); $c++) {
				for ($i = 0; $i < strlen($cOTLdata[$c]['group']); $i++) {
					if ($cOTLdata[$c]['group'][$i] == 'S') {
						// Save from last word
						if ($max_kashida_in_word) {
							$k_ctr++;
							$k_total = $max_kashida_in_word;
						}
						// Reset word
						$max_kashida_in_word = 0;
						$last_kashida_in_word = -1;
					}

					if (isset($cOTLdata[$c]['GPOSinfo'][$i]['kashida']) && $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > 0) {
						if ($max_kashida_in_word) {
							if ($cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > $max_kashida_in_word) {
								$max_kashida_in_word = $cOTLdata[$c]['GPOSinfo'][$i]['kashida'];
								$cOTLdata[$c]['GPOSinfo'][$last_kashida_in_word]['kashida'] = 0;
								$last_kashida_in_word = $i;
							} else {
								$cOTLdata[$c]['GPOSinfo'][$i]['kashida'] = 0;
							}
						} else {
							$max_kashida_in_word = $cOTLdata[$c]['GPOSinfo'][$i]['kashida'];
							$last_kashida_in_word = $i;
						}
					}
				}
			}
			// Save from last word
			if ($max_kashida_in_word) {
				$k_ctr++;
				$k_total = $max_kashida_in_word;
			}

			// Number of kashida points = $k_ctr
			// $useKashida is a % value from CurrentFont/config_fonts.php
			// % ratio divided between word-spacing and kashida-spacing
			$kashida_space_ratio = intval($this->CurrentFont['useKashida']) / 100;


			$kashida_space = $w * $kashida_space_ratio;

			$tatw = $this->_getCharWidth($this->CurrentFont['cw'], 0x0640);
			// Only use kashida if each allocated kashida width is > 0.01 x width of a tatweel
			// Otherwise fontstretch is too small and errors
			// If not just leave to adjust word-spacing
			if ($tatw && (($kashida_space / $k_ctr) / $tatw) > 0.01) {
				for ($c = 0; $c < count($cOTLdata); $c++) {
					for ($i = 0; $i < strlen($cOTLdata[$c]['group']); $i++) {
						if (isset($cOTLdata[$c]['GPOSinfo'][$i]['kashida']) && $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > 0) {
							// At this point kashida is a number representing priority (higher number - higher priority)
							// We are now going to set it as an actual length
							// This shares it equally amongst words:
							$cOTLdata[$c]['GPOSinfo'][$i]['kashida_space'] = (1 / $k_ctr) * $kashida_space;
						}
					}
				}
				$w -= $kashida_space;
			}
		}

		$ws = 0;
		$charspacing = 0;
		$ww = $this->jSWord;
		$ncx = $nc - 1;
		if ($nc == 0) {
			return [0, 0, 0];
		} // Only word spacing allowed / possible
		elseif ($this->fixedlSpacing !== false || $inclCursive) {
			if ($ns) {
				$ws = $w / $ns;
			}
		} elseif ($nc == 1) {
			$charspacing = $w;
		} elseif (!$ns) {
			$charspacing = $w / ($ncx );
			if (($this->jSmaxChar > 0) && ($charspacing > $this->jSmaxChar)) {
				$charspacing = $this->jSmaxChar;
			}
		} elseif ($ns == ($ncx )) {
			$charspacing = $w / $ns;
		} else {
			if ($this->usingCoreFont) {
				$cs = ($w * (1 - $this->jSWord)) / ($ncx );
				if (($this->jSmaxChar > 0) && ($cs > $this->jSmaxChar)) {
					$cs = $this->jSmaxChar;
					$ww = 1 - (($cs * ($ncx )) / $w);
				}
				$charspacing = $cs;
				$ws = ($w * ($ww) ) / $ns;
			} else {
				$cs = ($w * (1 - $this->jSWord)) / ($ncx - $ns);
				if (($this->jSmaxChar > 0) && ($cs > $this->jSmaxChar)) {
					$cs = $this->jSmaxChar;
					$ww = 1 - (($cs * ($ncx - $ns)) / $w);
				}
				$charspacing = $cs;
				$ws = (($w * ($ww) ) / $ns) - $charspacing;
			}
		}
		return [$charspacing, $ws, $kashida_space];
	}

	/**
	 * Output a cell
	 *
	 * Expects input to be mb_encoded if necessary and RTL reversed
	 *
	 * @since mPDF 5.7.1
	 */
	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)
	{
		// NON_BREAKING SPACE
		if ($this->usingCoreFont) {
			$txt = str_replace(chr(160), chr(32), $txt);
		} else {
			$txt = str_replace(chr(194) . chr(160), chr(32), $txt);
		}

		$oldcolumn = $this->CurrCol;

		// Automatic page break
		// Allows PAGE-BREAK-AFTER = avoid to work
		if (isset($this->blk[$this->blklvl])) {
			$bottom = $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['margin_bottom'];
		} else {
			$bottom = 0;
		}

		if (!$this->tableLevel
			&& (
				($this->y + $this->divheight > $this->PageBreakTrigger)
				|| ($this->y + $h > $this->PageBreakTrigger)
				|| (
					$this->y + ($h * 2) + $bottom > $this->PageBreakTrigger
						&& (isset($this->blk[$this->blklvl]['page_break_after_avoid']) && $this->blk[$this->blklvl]['page_break_after_avoid'])
				)
			)
			&& !$this->InFooter
			&& $this->AcceptPageBreak()
		) { // mPDF 5.7.2

			$x = $this->x; // Current X position

			// WORD SPACING
			$ws = $this->ws; // Word Spacing
			$charspacing = $this->charspacing; // Character Spacing
			$this->ResetSpacing();

			$this->AddPage($this->CurOrientation);

			// Added to correct for OddEven Margins
			$x += $this->MarginCorrection;
			if ($currentx) {
				$currentx += $this->MarginCorrection;
			}
			$this->x = $x;
			// WORD SPACING
			$this->SetSpacing($charspacing, $ws);
		}

		// Test: to put line through centre of cell: $this->Line($this->x,$this->y+($h/2),$this->x+50,$this->y+($h/2));
		// Test: to put border around cell as it is specified: $border='LRTB';

		/* -- COLUMNS -- */
		// COLS
		// COLUMN CHANGE
		if ($this->CurrCol != $oldcolumn) {
			if ($currentx) {
				$currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
			}
			$this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
		}

		// COLUMNS Update/overwrite the lowest bottom of printing y value for a column
		if ($this->ColActive) {
			if ($h) {
				$this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y + $h;
			} else {
				$this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y + $this->divheight;
			}
		}
		/* -- END COLUMNS -- */


		if ($w == 0) {
			$w = $this->w - $this->rMargin - $this->x;
		}

		$s = '';
		if ($fill == 1 && $this->FillColor) {
			if ((isset($this->pageoutput[$this->page]['FillColor']) && $this->pageoutput[$this->page]['FillColor'] != $this->FillColor) || !isset($this->pageoutput[$this->page]['FillColor'])) {
				$s .= $this->FillColor . ' ';
			}
			$this->pageoutput[$this->page]['FillColor'] = $this->FillColor;
		}

		if ($lineBox && isset($lineBox['boxtop']) && $txt) { // i.e. always from WriteFlowingBlock/finishFlowingBlock (but not objects -
			// which only have $lineBox['top'] set)
			$boxtop = $this->y + $lineBox['boxtop'];
			$boxbottom = $this->y + $lineBox['boxbottom'];
			$glyphYorigin = $lineBox['glyphYorigin'];
			$baseline_shift = $lineBox['baseline-shift'];
			$bord_boxtop = $bg_boxtop = $boxtop = $boxtop - $baseline_shift;
			$bord_boxbottom = $bg_boxbottom = $boxbottom = $boxbottom - $baseline_shift;
			$bord_boxheight = $bg_boxheight = $boxheight = $boxbottom - $boxtop;

			// If inline element BACKGROUND has bounding box set by parent element:
			if (isset($lineBox['background-boxtop'])) {
				$bg_boxtop = $this->y + $lineBox['background-boxtop'] - $lineBox['background-baseline-shift'];
				$bg_boxbottom = $this->y + $lineBox['background-boxbottom'] - $lineBox['background-baseline-shift'];
				$bg_boxheight = $bg_boxbottom - $bg_boxtop;
			}
			// If inline element BORDER has bounding box set by parent element:
			if (isset($lineBox['border-boxtop'])) {
				$bord_boxtop = $this->y + $lineBox['border-boxtop'] - $lineBox['border-baseline-shift'];
				$bord_boxbottom = $this->y + $lineBox['border-boxbottom'] - $lineBox['border-baseline-shift'];
				$bord_boxheight = $bord_boxbottom - $bord_boxtop;
			}

		} else {

			$boxtop = $this->y;
			$boxheight = $h;
			$boxbottom = $this->y + $h;
			$baseline_shift = 0;

			if ($txt != '') {

				// FONT SIZE - this determines the baseline caculation
				$bfs = $this->FontSize;
				// Calculate baseline Superscript and Subscript Y coordinate adjustment
				$bfx = $this->baselineC;
				$baseline = $bfx * $bfs;

				if ($textvar & TextVars::FA_SUPERSCRIPT) {
					$baseline_shift = $this->textparam['text-baseline'];
				} elseif ($textvar & TextVars::FA_SUBSCRIPT) {
					$baseline_shift = $this->textparam['text-baseline'];
				} elseif ($this->bullet) {
					$baseline += ($bfx - 0.7) * $this->FontSize;
				}

				// Vertical align (for Images)
				if ($valign == 'T') {
					$va = (0.5 * $bfs * $this->normalLineheight);
				} elseif ($valign == 'B') {
					$va = $h - (0.5 * $bfs * $this->normalLineheight);
				} else {
					$va = 0.5 * $h;
				} // Middle

				// ONLY SET THESE IF WANT TO CONFINE BORDER +/- FILL TO FIT FONTSIZE - NOT FULL CELL AS IS ORIGINAL FUNCTION
				// spanfill or spanborder are set in FlowingBlock functions
				if ($spanfill || !empty($this->spanborddet) || $link != '') {
					$exth = 0.2; // Add to fontsize to increase height of background / link / border
					$boxtop = $this->y + $baseline + $va - ($this->FontSize * (1 + $exth / 2) * (0.5 + $bfx));
					$boxheight = $this->FontSize * (1 + $exth);
					$boxbottom = $boxtop + $boxheight;
				}

				$glyphYorigin = $baseline + $va;
			}

			$boxtop -= $baseline_shift;
			$boxbottom -= $baseline_shift;
			$bord_boxtop = $bg_boxtop = $boxtop;
			$bord_boxbottom = $bg_boxbottom = $boxbottom;
			$bord_boxheight = $bg_boxheight = $boxheight = $boxbottom - $boxtop;
		}

		$bbw = $tbw = $lbw = $rbw = 0; // Border widths
		if (!empty($this->spanborddet)) {

			if (!isset($this->spanborddet['B'])) {
				$this->spanborddet['B'] = ['s' => 0, 'style' => '', 'w' => 0];
			}

			if (!isset($this->spanborddet['T'])) {
				$this->spanborddet['T'] = ['s' => 0, 'style' => '', 'w' => 0];
			}

			if (!isset($this->spanborddet['L'])) {
				$this->spanborddet['L'] = ['s' => 0, 'style' => '', 'w' => 0];
			}

			if (!isset($this->spanborddet['R'])) {
				$this->spanborddet['R'] = ['s' => 0, 'style' => '', 'w' => 0];
			}

			$bbw = $this->spanborddet['B']['w'];
			$tbw = $this->spanborddet['T']['w'];
			$lbw = $this->spanborddet['L']['w'];
			$rbw = $this->spanborddet['R']['w'];
		}

		if ($fill == 1 || $border == 1 || !empty($this->spanborddet)) {

			if (!empty($this->spanborddet)) {

				if ($fill == 1) {
					$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);
				}

				$s.= ' q ';
				$dashon = 3;
				$dashoff = 3.5;
				$dot = 2.5;

				if ($tbw) {
					$short = 0;

					if ($this->spanborddet['T']['style'] == 'dashed') {
						$s .= sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $tbw * $dashon * Mpdf::SCALE, $tbw * $dashoff * Mpdf::SCALE);
					} elseif ($this->spanborddet['T']['style'] == 'dotted') {
						$s .= sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $tbw * $dot * Mpdf::SCALE, -$tbw / 2 * Mpdf::SCALE);
						$short = $tbw / 2;
					} else {
						$s .= ' 0 j 0 J [] 0 d ';
					}

					if ($this->spanborddet['T']['style'] != 'dotted') {
						$s .= 'q ';
						$s .= sprintf('%.3F %.3F m ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE);
						$s .= sprintf('%.3F %.3F l ', ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE);
						$s .= sprintf('%.3F %.3F l ', ($this->x + $w) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
						$s .= sprintf('%.3F %.3F l ', ($this->x) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
						$s .= ' h W n '; // Ends path no-op & Sets the clipping path
					}

					$c = $this->SetDColor($this->spanborddet['T']['c'], true);

					if ($this->spanborddet['T']['style'] == 'double') {
						$s .= sprintf(' %s %.3F w ', $c, $tbw / 3 * Mpdf::SCALE);
						$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);
						$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);
					} elseif ($this->spanborddet['T']['style'] == 'dotted') {
						$s .= sprintf(' %s %.3F w ', $c, $tbw * Mpdf::SCALE);
						$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);
					} else {
						$s .= sprintf(' %s %.3F w ', $c, $tbw * Mpdf::SCALE);
						$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);
					}

					if ($this->spanborddet['T']['style'] != 'dotted') {
						$s .= ' Q ';
					}
				}
				if ($bbw) {

					$short = 0;
					if ($this->spanborddet['B']['style'] == 'dashed') {
						$s .= sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $bbw * $dashon * Mpdf::SCALE, $bbw * $dashoff * Mpdf::SCALE);
					} elseif ($this->spanborddet['B']['style'] == 'dotted') {
						$s .= sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $bbw * $dot * Mpdf::SCALE, -$bbw / 2 * Mpdf::SCALE);
						$short = $bbw / 2;
					} else {
						$s .= ' 0 j 0 J [] 0 d ';
					}

					if ($this->spanborddet['B']['style'] != 'dotted') {
						$s .= 'q ';
						$s .= sprintf('%.3F %.3F m ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw) * Mpdf::SCALE);
						$s .= sprintf('%.3F %.3F l ', ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw) * Mpdf::SCALE);
						$s .= sprintf('%.3F %.3F l ', ($this->x + $w) * Mpdf::SCALE, ($this->h - $bord_boxbottom) * Mpdf::SCALE);
						$s .= sprintf('%.3F %.3F l ', ($this->x) * Mpdf::SCALE, ($this->h - $bord_boxbottom) * Mpdf::SCALE);
						$s .= ' h W n '; // Ends path no-op & Sets the clipping path
					}

					$c = $this->SetDColor($this->spanborddet['B']['c'], true);

					if ($this->spanborddet['B']['style'] == 'double') {
						$s .= sprintf(' %s %.3F w ', $c, $bbw / 3 * Mpdf::SCALE);
						$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);
						$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);
					} elseif ($this->spanborddet['B']['style'] == 'dotted') {
						$s .= sprintf(' %s %.3F w ', $c, $bbw * Mpdf::SCALE);
						$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);
					} else {
						$s .= sprintf(' %s %.3F w ', $c, $bbw * Mpdf::SCALE);
						$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);
					}

					if ($this->spanborddet['B']['style'] != 'dotted') {
						$s .= ' Q ';
					}
				}

				if ($lbw) {
					$short = 0;
					if ($this->spanborddet['L']['style'] == 'dashed') {
						$s .= sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $lbw * $dashon * Mpdf::SCALE, $lbw * $dashoff * Mpdf::SCALE);
					} elseif ($this->spanborddet['L']['style'] == 'dotted') {
						$s .= sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $lbw * $dot * Mpdf::SCALE, -$lbw / 2 * Mpdf::SCALE);
						$short = $lbw / 2;
					} else {
						$s .= ' 0 j 0 J [] 0 d ';
					}

					if ($this->spanborddet['L']['style'] != 'dotted') {
						$s .= 'q ';
						$s .= sprintf('%.3F %.3F m ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw) * Mpdf::SCALE);
						$s .= sprintf('%.3F %.3F l ', ($this->x) * Mpdf::SCALE, ($this->h - $bord_boxbottom) * Mpdf::SCALE);
						$s .= sprintf('%.3F %.3F l ', ($this->x) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
						$s .= sprintf('%.3F %.3F l ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE);
						$s .= ' h W n '; // Ends path no-op & Sets the clipping path
					}

					$c = $this->SetDColor($this->spanborddet['L']['c'], true);
					if ($this->spanborddet['L']['style'] == 'double') {
						$s .= sprintf(' %s %.3F w ', $c, $lbw / 3 * Mpdf::SCALE);
						$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);
						$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);
					} elseif ($this->spanborddet['L']['style'] == 'dotted') {
						$s .= sprintf(' %s %.3F w ', $c, $lbw * Mpdf::SCALE);
						$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);
					} else {
						$s .= sprintf(' %s %.3F w ', $c, $lbw * Mpdf::SCALE);
						$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);
					}

					if ($this->spanborddet['L']['style'] != 'dotted') {
						$s .= ' Q ';
					}
				}

				if ($rbw) {

					$short = 0;
					if ($this->spanborddet['R']['style'] == 'dashed') {
						$s .= sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $rbw * $dashon * Mpdf::SCALE, $rbw * $dashoff * Mpdf::SCALE);
					} elseif ($this->spanborddet['R']['style'] == 'dotted') {
						$s .= sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $rbw * $dot * Mpdf::SCALE, -$rbw / 2 * Mpdf::SCALE);
						$short = $rbw / 2;
					} else {
						$s .= ' 0 j 0 J [] 0 d ';
					}

					if ($this->spanborddet['R']['style'] != 'dotted') {
						$s .= 'q ';
						$s .= sprintf('%.3F %.3F m ', ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw) * Mpdf::SCALE);
						$s .= sprintf('%.3F %.3F l ', ($this->x + $w) * Mpdf::SCALE, ($this->h - $bord_boxbottom) * Mpdf::SCALE);
						$s .= sprintf('%.3F %.3F l ', ($this->x + $w) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
						$s .= sprintf('%.3F %.3F l ', ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE);
						$s .= ' h W n '; // Ends path no-op & Sets the clipping path
					}

					$c = $this->SetDColor($this->spanborddet['R']['c'], true);
					if ($this->spanborddet['R']['style'] == 'double') {
						$s .= sprintf(' %s %.3F w ', $c, $rbw / 3 * Mpdf::SCALE);
						$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);
						$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);
					} elseif ($this->spanborddet['R']['style'] == 'dotted') {
						$s .= sprintf(' %s %.3F w ', $c, $rbw * Mpdf::SCALE);
						$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);
					} else {
						$s .= sprintf(' %s %.3F w ', $c, $rbw * Mpdf::SCALE);
						$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);
					}

					if ($this->spanborddet['R']['style'] != 'dotted') {
						$s .= ' Q ';
					}
				}

				$s.= ' Q ';

			} else { // If "border", does not come from WriteFlowingBlock or FinishFlowingBlock

				if ($fill == 1) {
					$op = ($border == 1) ? 'B' : 'f';
				} else {
					$op = 'S';
				}

				$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);
			}
		}

		if (is_string($border)) { // If "border", does not come from WriteFlowingBlock or FinishFlowingBlock

			$x = $this->x;
			$y = $this->y;

			if (is_int(strpos($border, 'L'))) {
				$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);
			}

			if (is_int(strpos($border, 'T'))) {
				$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);
			}

			if (is_int(strpos($border, 'R'))) {
				$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);
			}

			if (is_int(strpos($border, 'B'))) {
				$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);
			}
		}

		if ($txt != '') {

			if ($exactWidth) {
				$stringWidth = $w;
			} else {
				$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 );
			}

			// Set x OFFSET FOR PRINTING
			if ($align == 'R') {
				$dx = $w - $this->cMarginR - $stringWidth - $lcpaddingR;
			} elseif ($align == 'C') {
				$dx = (($w - $stringWidth ) / 2);
			} elseif ($align == 'L' or $align == 'J') {
				$dx = $this->cMarginL + $lcpaddingL;
			} else {
				$dx = 0;
			}

			if ($this->ColorFlag) {
				$s .='q ' . $this->TextColor . ' ';
			}

			// OUTLINE
			if (isset($this->textparam['outline-s']) && $this->textparam['outline-s'] && !($textvar & TextVars::FC_SMALLCAPS)) { // mPDF 5.7.1
				$s .=' ' . sprintf('%.3F w', $this->LineWidth * Mpdf::SCALE) . ' ';
				$s .=" $this->DrawColor ";
				$s .=" 2 Tr ";
			} 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 ???
				$s .= ' 2 Tr 1 J 1 j ';
				$s .= ' ' . sprintf('%.3F w', ($this->FontSize / 130) * Mpdf::SCALE * $this->falseBoldWeight) . ' ';
				$tc = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
				if ($this->FillColor != $tc) {
					$s .= ' ' . $tc . ' ';
				}  // stroke (outline) = same colour as text(fill)
			} else {
				$s .=" 0 Tr ";
			}

			if (strpos($this->ReqFontStyle, "I") !== false && strpos($this->FontStyle, "I") === false) { // Artificial italic
				$aix = '1 0 0.261799 1 %.3F %.3F Tm ';
			} else {
				$aix = '%.3F %.3F Td ';
			}

			$px = ($this->x + $dx) * Mpdf::SCALE;
			$py = ($this->h - ($this->y + $glyphYorigin - $baseline_shift)) * Mpdf::SCALE;

			// THE TEXT
			$txt2 = $txt;
			$sub = '';
			$this->CurrentFont['used'] = true;

			/*             * ************** SIMILAR TO Text() ************************ */

			// IF corefonts AND NOT SmCaps AND NOT Kerning
			// Just output text; charspacing and wordspacing already set by charspacing (Tc) and ws (Tw)
			if ($this->usingCoreFont && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING)) {
				$txt2 = $this->writer->escape($txt2);
				$sub .= sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
			} // IF NOT corefonts AND NO wordspacing AND NOT SIP/SMP AND NOT SmCaps AND NOT Kerning AND NOT OTL
			// Just output text
			elseif (!$this->usingCoreFont && !$this->ws && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING) && !(isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && !empty($OTLdata['GPOSinfo']))) {
				// IF SIP/SMP
				if ((isset($this->CurrentFont['sip']) && $this->CurrentFont['sip']) || (isset($this->CurrentFont['smp']) && $this->CurrentFont['smp'])) {
					$txt2 = $this->UTF8toSubset($txt2);
					$sub .=sprintf('BT ' . $aix . ' %s Tj ET', $px, $py, $txt2);
				} // NOT SIP/SMP
				else {
					$txt2 = $this->writer->utf8ToUtf16BigEndian($txt2, false);
					$txt2 = $this->writer->escape($txt2);
					$sub .=sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
				}
			} // IF NOT corefonts AND IS wordspacing AND NOT SIP AND NOT SmCaps AND NOT Kerning AND NOT OTL
			// Output text word by word with an adjustment to the intercharacter spacing for SPACEs to form word spacing
			// IF multibyte - Tw has no effect - need to do word spacing using an adjustment before each space
			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)) )) {
				$space = " ";
				$space = $this->writer->utf8ToUtf16BigEndian($space, false);
				$space = $this->writer->escape($space);
				$sub .=sprintf('BT ' . $aix . ' %.3F Tc [', $px, $py, $this->charspacing);
				$t = explode(' ', $txt2);
				$numt = count($t);
				for ($i = 0; $i < $numt; $i++) {
					$tx = $t[$i];
					$tx = $this->writer->utf8ToUtf16BigEndian($tx, false);
					$tx = $this->writer->escape($tx);
					$sub .=sprintf('(%s) ', $tx);
					if (($i + 1) < $numt) {
						$adj = -($this->ws) * 1000 / $this->FontSizePt;
						$sub .=sprintf('%d(%s) ', $adj, $space);
					}
				}
				$sub .='] TJ ';
				$sub .=' ET';
			} // ELSE (IF SmCaps || Kerning || OTL) [corefonts or not corefonts; SIP or SMP or BMP]
			else {
				$sub = $this->applyGPOSpdf($txt, $aix, $px, $py, $OTLdata, $textvar);
			}

			/** ************** END SIMILAR TO Text() ************************ */

			if ($this->shrin_k > 1) {
				$shrin_k = $this->shrin_k;
			} else {
				$shrin_k = 1;
			}

			// UNDERLINE
			if ($textvar & TextVars::FD_UNDERLINE) { // mPDF 5.7.1	// mPDF 6

				// mPDF 5.7.3  inline text-decoration parameters

				$c = isset($this->textparam['u-decoration']['color']) ? $this->textparam['u-decoration']['color'] : '';
				if ($this->FillColor != $c) {
					$sub .= ' ' . $c . ' ';
				}

				// mPDF 5.7.3  inline text-decoration parameters
				$decorationfontkey = isset($this->textparam['u-decoration']['fontkey']) ? $this->textparam['u-decoration']['fontkey'] : '';
				$decorationfontsize = isset($this->textparam['u-decoration']['fontsize']) ? $this->textparam['u-decoration']['fontsize'] / $shrin_k : 0;

				if (isset($this->fonts[$decorationfontkey]['ut']) && $this->fonts[$decorationfontkey]['ut']) {
					$ut = $this->fonts[$decorationfontkey]['ut'] / 1000 * $decorationfontsize;
				} else {
					$ut = 60 / 1000 * $decorationfontsize;
				}

				if (isset($this->fonts[$decorationfontkey]['up']) && $this->fonts[$decorationfontkey]['up']) {
					$up = $this->fonts[$decorationfontkey]['up'];
				} else {
					$up = -100;
				}

				$adjusty = (-$up / 1000 * $decorationfontsize) + $ut / 2;
				$ubaseline = isset($this->textparam['u-decoration']['baseline'])
					? $glyphYorigin - $this->textparam['u-decoration']['baseline'] / $shrin_k
					: $glyphYorigin;

				$olw = $this->LineWidth;

				$sub .= ' ' . (sprintf(' %.3F w 0 j 0 J ', $ut * Mpdf::SCALE));
				$sub .= ' ' . $this->_dounderline($this->x + $dx, $this->y + $ubaseline + $adjusty, $txt, $OTLdata, $textvar);
				$sub .= ' ' . (sprintf(' %.3F w 2 j 2 J ', $olw * Mpdf::SCALE));

				if ($this->FillColor != $c) {
					$sub .= ' ' . $this->FillColor . ' ';
				}
			}

			// STRIKETHROUGH
			if ($textvar & TextVars::FD_LINETHROUGH) { // mPDF 5.7.1	// mPDF 6

				// mPDF 5.7.3  inline text-decoration parameters
				$c = $this->textparam['s-decoration']['color'];

				if ($this->FillColor != $c) {
					$sub .= ' ' . $c . ' ';
				}

				// mPDF 5.7.3  inline text-decoration parameters
				$decorationfontkey = $this->textparam['s-decoration']['fontkey'];
				$decorationfontsize = $this->textparam['s-decoration']['fontsize'] / $shrin_k;

				// Use yStrikeoutSize from OS/2 if available
				if (isset($this->fonts[$decorationfontkey]['strs']) && $this->fonts[$decorationfontkey]['strs']) {
					$ut = $this->fonts[$decorationfontkey]['strs'] / 1000 * $decorationfontsize;
				} // else use underlineThickness from post if available
				elseif (isset($this->fonts[$decorationfontkey]['ut']) && $this->fonts[$decorationfontkey]['ut']) {
					$ut = $this->fonts[$decorationfontkey]['ut'] / 1000 * $decorationfontsize;
				} else {
					$ut = 50 / 1000 * $decorationfontsize;
				}

				// Use yStrikeoutPosition from OS/2 if available
				if (isset($this->fonts[$decorationfontkey]['strp']) && $this->fonts[$decorationfontkey]['strp']) {
					$up = $this->fonts[$decorationfontkey]['strp'];
					$adjusty = (-$up / 1000 * $decorationfontsize);
				} // else use a fraction ($this->baselineS) of CapHeight
				else {
					if (isset($this->fonts[$decorationfontkey]['desc']['CapHeight']) && $this->fonts[$decorationfontkey]['desc']['CapHeight']) {
						$ch = $this->fonts[$decorationfontkey]['desc']['CapHeight'];
					} else {
						$ch = 700;
					}
					$adjusty = (-$ch / 1000 * $decorationfontsize) * $this->baselineS;
				}

				$sbaseline = $glyphYorigin - $this->textparam['s-decoration']['baseline'] / $shrin_k;

				$olw = $this->LineWidth;

				$sub .=' ' . (sprintf(' %.3F w 0 j 0 J ', $ut * Mpdf::SCALE));
				$sub .=' ' . $this->_dounderline($this->x + $dx, $this->y + $sbaseline + $adjusty, $txt, $OTLdata, $textvar);
				$sub .=' ' . (sprintf(' %.3F w 2 j 2 J ', $olw * Mpdf::SCALE));

				if ($this->FillColor != $c) {
					$sub .= ' ' . $this->FillColor . ' ';
				}
			}

			// mPDF 5.7.3  inline text-decoration parameters
			// OVERLINE
			if ($textvar & TextVars::FD_OVERLINE) { // mPDF 5.7.1	// mPDF 6
				// mPDF 5.7.3  inline text-decoration parameters
				$c = $this->textparam['o-decoration']['color'];
				if ($this->FillColor != $c) {
					$sub .= ' ' . $c . ' ';
				}

				// mPDF 5.7.3  inline text-decoration parameters
				$decorationfontkey = (int) (((float) $this->textparam['o-decoration']['fontkey']) / $shrin_k);
				$decorationfontsize = $this->textparam['o-decoration']['fontsize'];

				if (isset($this->fonts[$decorationfontkey]['ut']) && $this->fonts[$decorationfontkey]['ut']) {
					$ut = $this->fonts[$decorationfontkey]['ut'] / 1000 * $decorationfontsize;
				} else {
					$ut = 60 / 1000 * $decorationfontsize;
				}
				if (isset($this->fonts[$decorationfontkey]['desc']['CapHeight']) && $this->fonts[$decorationfontkey]['desc']['CapHeight']) {
					$ch = $this->fonts[$decorationfontkey]['desc']['CapHeight'];
				} else {
					$ch = 700;
				}
				$adjusty = (-$ch / 1000 * $decorationfontsize) * $this->baselineO;
				$obaseline = $glyphYorigin - $this->textparam['o-decoration']['baseline'] / $shrin_k;
				$olw = $this->LineWidth;
				$sub .=' ' . (sprintf(' %.3F w 0 j 0 J ', $ut * Mpdf::SCALE));
				$sub .=' ' . $this->_dounderline($this->x + $dx, $this->y + $obaseline + $adjusty, $txt, $OTLdata, $textvar);
				$sub .=' ' . (sprintf(' %.3F w 2 j 2 J ', $olw * Mpdf::SCALE));
				if ($this->FillColor != $c) {
					$sub .= ' ' . $this->FillColor . ' ';
				}
			}

			// TEXT SHADOW
			if ($this->textshadow) {  // First to process is last in CSS comma separated shadows
				foreach ($this->textshadow as $ts) {
					$s .= ' q ';
					$s .= $this->SetTColor($ts['col'], true) . "\n";
					if ($ts['col'][0] == 5 && ord($ts['col'][4]) < 100) { // RGBa
						$s .= $this->SetAlpha(ord($ts['col'][4]) / 100, 'Normal', true, 'F') . "\n";
					} elseif ($ts['col'][0] == 6 && ord($ts['col'][5]) < 100) { // CMYKa
						$s .= $this->SetAlpha(ord($ts['col'][5]) / 100, 'Normal', true, 'F') . "\n";
					} elseif ($ts['col'][0] == 1 && $ts['col'][2] == 1 && ord($ts['col'][3]) < 100) { // Gray
						$s .= $this->SetAlpha(ord($ts['col'][3]) / 100, 'Normal', true, 'F') . "\n";
					}
					$s .= sprintf(' 1 0 0 1 %.4F %.4F cm', $ts['x'] * Mpdf::SCALE, -$ts['y'] * Mpdf::SCALE) . "\n";
					$s .= $sub;
					$s .= ' Q ';
				}
			}

			$s .= $sub;

			// COLOR
			if ($this->ColorFlag) {
				$s .=' Q';
			}

			// LINK
			if ($link != '') {
				$this->Link($this->x, $boxtop, $w, $boxheight, $link);
			}
		}
		if ($s) {
			$this->writer->write($s);
		}

		// WORD SPACING
		if ($this->ws && !$this->usingCoreFont) {
			$this->writer->write(sprintf('BT %.3F Tc ET', $this->charspacing));
		}
		$this->lasth = $h;
		if (strpos($txt, "\n") !== false) {
			$ln = 1; // cell recognizes \n from <BR> tag
		}
		if ($ln > 0) {
			// Go to next line
			$this->y += $h;
			if ($ln == 1) {
				// Move to next line
				if ($currentx != 0) {
					$this->x = $currentx;
				} else {
					$this->x = $this->lMargin;
				}
			}
		} else {
			$this->x+=$w;
		}
	}

	function applyGPOSpdf($txt, $aix, $x, $y, $OTLdata, $textvar = 0)
	{
		$sipset = (isset($this->CurrentFont['sip']) && $this->CurrentFont['sip'])
			|| (isset($this->CurrentFont['smp']) && $this->CurrentFont['smp']);

		$smcaps = ($textvar & TextVars::FC_SMALLCAPS);

		$fontid = $sipset
			? $last_fontid = $original_fontid = $this->CurrentFont['subsetfontids'][0]
			: $last_fontid = $original_fontid = $this->CurrentFont['i'];

		$SmallCapsON = false;  // state: uppercase/not
		$lastSmallCapsON = false; // state: uppercase/not
		$last_fontsize = $fontsize = $this->FontSizePt;
		$last_fontstretch = $fontstretch = 100;
		$groupBreak = false;

		$unicode = $this->UTF8StringToArray($txt);

		$GPOSinfo = (isset($OTLdata['GPOSinfo']) ? $OTLdata['GPOSinfo'] : []);
		$charspacing = ($this->charspacing * 1000 / $this->FontSizePt);
		$wordspacing = ($this->ws * 1000 / $this->FontSizePt);

		$XshiftBefore = 0;
		$XshiftAfter = 0;
		$lastYPlacement = 0;

		$tj = $sipset
			? '<'
			: '(';

		for ($i = 0; $i < count($unicode); $i++) {
			$c = $unicode[$i];
			$tx = '';
			$XshiftBefore = $XshiftAfter;
			$XshiftAfter = 0;
			$YPlacement = 0;
			$groupBreak = false;
			$kashida = 0;
			if (!empty($OTLdata)) {
				// YPlacement from GPOS
				if (isset($GPOSinfo[$i]['YPlacement']) && $GPOSinfo[$i]['YPlacement']) {
					$YPlacement = $GPOSinfo[$i]['YPlacement'] * $this->FontSizePt / $this->CurrentFont['unitsPerEm'];
					$groupBreak = true;
				}
				// XPlacement from GPOS
				if (isset($GPOSinfo[$i]['XPlacement']) && $GPOSinfo[$i]['XPlacement']) {
					if (!isset($GPOSinfo[$i]['wDir']) || $GPOSinfo[$i]['wDir'] !== 'RTL') {
						if (isset($GPOSinfo[$i]['BaseWidth'])) {
							$GPOSinfo[$i]['XPlacement'] -= $GPOSinfo[$i]['BaseWidth'];
						}
					}

					// Convert to PDF Text space (thousandths of a unit );
					$XshiftBefore += $GPOSinfo[$i]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
					$XshiftAfter += -$GPOSinfo[$i]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
				}

				// Kashida from GPOS
				// Kashida is set as an absolute length value, but to adjust text needs to be converted to
				// font-related size
				if (isset($GPOSinfo[$i]['kashida_space']) && $GPOSinfo[$i]['kashida_space']) {
					$kashida = $GPOSinfo[$i]['kashida_space'];
				}

				if ($c == 32) { // word spacing
					$XshiftAfter += $wordspacing;
				}

				if (substr($OTLdata['group'], ($i + 1), 1) !== 'M') { // Don't add inter-character spacing before Marks
					$XshiftAfter += $charspacing;
				}

				// ...applyGPOSpdf...
				// XAdvance from GPOS - Convert to PDF Text space (thousandths of a unit );
				if (((isset($GPOSinfo[$i]['wDir']) && $GPOSinfo[$i]['wDir'] !== 'RTL') || !isset($GPOSinfo[$i]['wDir'])) && isset($GPOSinfo[$i]['XAdvanceL']) && $GPOSinfo[$i]['XAdvanceL']) {
					$XshiftAfter += $GPOSinfo[$i]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
				} elseif (isset($GPOSinfo[$i]['wDir']) && $GPOSinfo[$i]['wDir'] === 'RTL' && isset($GPOSinfo[$i]['XAdvanceR']) && $GPOSinfo[$i]['XAdvanceR']) {
					$XshiftAfter += $GPOSinfo[$i]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
				}

			} else { // Character & Word spacing - if NOT OTL
				$XshiftAfter += $charspacing;
				if ($c == 32) {
					$XshiftAfter += $wordspacing;
				}
			}

			// IF Kerning done using pairs rather than OTL
			if ($textvar & TextVars::FC_KERNING) {
				if ($i > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]])) {
					$XshiftBefore += $this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]];
				}
			}

			if ($YPlacement !== $lastYPlacement) {
				$groupBreak = true;
			}

			if ($XshiftBefore) {  // +ve value in PDF moves to the left
				// If Fontstretch is ongoing, need to adjust X adjustments because these will be stretched out.
				$XshiftBefore *= 100 / $last_fontstretch;
				if ($sipset) {
					$tj .= sprintf('>%d<', (-$XshiftBefore));
				} else {
					$tj .= sprintf(')%d(', (-$XshiftBefore));
				}
			}

			// Small-Caps
			if ($smcaps) {
				if (isset($this->upperCase[$c])) {
					$c = $this->upperCase[$c];
					// $this->CurrentFont['subset'][$this->upperCase[$c]] = $this->upperCase[$c];	// add the CAP to subset
					$SmallCapsON = true;
					// For $sipset
					if (!$lastSmallCapsON) { // Turn ON SmallCaps
						$groupBreak = true;
						$fontstretch = $this->smCapsStretch;
						$fontsize = $this->FontSizePt * $this->smCapsScale;
					}
				} else {
					$SmallCapsON = false;
					if ($lastSmallCapsON) {  // Turn OFF SmallCaps
						$groupBreak = true;
						$fontstretch = 100;
						$fontsize = $this->FontSizePt;
					}
				}
			}

			// Prepare Text and Select Font ID
			if ($sipset) {
				for ($j = 0; $j < 99; $j++) {
					$init = array_search($c, $this->CurrentFont['subsets'][$j]);
					if ($init !== false) {
						if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
							$groupBreak = true;
							$fontid = $this->CurrentFont['subsetfontids'][$j];
						}
						$tx = sprintf("%02s", strtoupper(dechex($init)));

						break;
					}

					if (count($this->CurrentFont['subsets'][$j]) < 255) {
						$n = count($this->CurrentFont['subsets'][$j]);
						$this->CurrentFont['subsets'][$j][$n] = $c;
						if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
							$groupBreak = true;
							$fontid = $this->CurrentFont['subsetfontids'][$j];
						}
						$tx = sprintf("%02s", strtoupper(dechex($n)));

						break;
					}

					if (!isset($this->CurrentFont['subsets'][($j + 1)])) {
						$this->CurrentFont['subsets'][($j + 1)] = [0 => 0];
						$this->CurrentFont['subsetfontids'][($j + 1)] = count($this->fonts) + $this->extraFontSubsets + 1;
						$this->extraFontSubsets++;
					}
				}

			} else {

				$tx = UtfString::code2utf($c);

				if ($this->usingCoreFont) {
					$tx = iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $tx);
				} else {
					$tx = $this->writer->utf8ToUtf16BigEndian($tx, false);
				}

				$tx = $this->writer->escape($tx);

			}

			// If any settings require a new Text Group
			if ($groupBreak || $fontstretch != $last_fontstretch) {

				$tj .= $sipset
					? '>] TJ '
					: ')] TJ ';

				if ($fontid != $last_fontid || $fontsize != $last_fontsize) {
					$tj .= sprintf(' /F%d %.3F Tf ', $fontid, $fontsize);
				}

				if ($fontstretch != $last_fontstretch) {
					$tj .= sprintf('%d Tz ', $fontstretch);
				}

				if ($YPlacement != $lastYPlacement) {
					$tj .= sprintf('%.3F Ts ', $YPlacement);
				}

				$tj .= $sipset
					? '[<'
					: '[(';
			}

			// Output the code for the txt character
			$tj .= $tx;
			$lastSmallCapsON = $SmallCapsON;
			$last_fontid = $fontid;
			$last_fontsize = $fontsize;
			$last_fontstretch = $fontstretch;

			// Kashida
			if ($kashida) {
				$c = 0x0640; // add the Tatweel U+0640
				if (isset($this->CurrentFont['subset'])) {
					$this->CurrentFont['subset'][$c] = $c;
				}
				$kashida *= 1000 / $this->FontSizePt;
				$tatw = $this->_getCharWidth($this->CurrentFont['cw'], 0x0640);

				// Get YPlacement from next Base character
				$nextbase = $i + 1;

				while ($OTLdata['group'][$nextbase] !== 'C') {
					$nextbase++;
				}

				if (isset($GPOSinfo[$nextbase]) && isset($GPOSinfo[$nextbase]['YPlacement']) && $GPOSinfo[$nextbase]['YPlacement']) {
					$YPlacement = $GPOSinfo[$nextbase]['YPlacement'] * $this->FontSizePt / $this->CurrentFont['unitsPerEm'];
				}

				// Prepare Text and Select Font ID
				if ($sipset) {

					for ($j = 0; $j < 99; $j++) {

						$init = array_search($c, $this->CurrentFont['subsets'][$j]);

						if ($init !== false) {
							if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
								$fontid = $this->CurrentFont['subsetfontids'][$j];
							}
							$tx = sprintf("%02s", strtoupper(dechex($init)));

							break;
						}

						if (count($this->CurrentFont['subsets'][$j]) < 255) {
							$n = count($this->CurrentFont['subsets'][$j]);
							$this->CurrentFont['subsets'][$j][$n] = $c;
							if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
								$fontid = $this->CurrentFont['subsetfontids'][$j];
							}
							$tx = sprintf("%02s", strtoupper(dechex($n)));

							break;
						}

						if (!isset($this->CurrentFont['subsets'][($j + 1)])) {
							$this->CurrentFont['subsets'][($j + 1)] = [0 => 0];
							$this->CurrentFont['subsetfontids'][($j + 1)] = count($this->fonts) + $this->extraFontSubsets + 1;
							$this->extraFontSubsets++;
						}
					}
				} else {
					$tx = UtfString::code2utf($c);
					$tx = $this->writer->utf8ToUtf16BigEndian($tx, false);
					$tx = $this->writer->escape($tx);
				}

				if ($kashida > $tatw) {

					// Insert multiple tatweel characters, repositioning the last one to give correct total length

					$fontstretch = 100;
					$nt = (int) ($kashida / $tatw);
					$nudgeback = (($nt + 1) * $tatw) - $kashida;
					$optx = str_repeat($tx, $nt);

					if ($sipset) {
						$optx .= sprintf('>%d<', ($nudgeback));
					} else {
						$optx .= sprintf(')%d(', ($nudgeback));
					}

					$optx .= $tx; // #last

				} else {
					// Insert single tatweel character and use fontstretch to get correct length
					$fontstretch = ($kashida / $tatw) * 100;
					$optx = $tx;
				}

				$tj .= $sipset
					? '>] TJ '
					: ')] TJ ';

				if ($fontid != $last_fontid || $fontsize != $last_fontsize) {
					$tj .= sprintf(' /F%d %.3F Tf ', $fontid, $fontsize);
				}

				if ($fontstretch != $last_fontstretch) {
					$tj .= sprintf('%d Tz ', $fontstretch);
				}

				$tj .= sprintf('%.3F Ts ', $YPlacement);

				$tj .= $sipset
					? '[<'
					: '[(';

				// Output the code for the txt character(s)
				$tj .= $optx;
				$last_fontid = $fontid;
				$last_fontstretch = $fontstretch;
				$fontstretch = 100;
			}

			$lastYPlacement = $YPlacement;
		}

		$tj .= $sipset
			? '>'
			: ')';

		if ($XshiftAfter) {
			$tj .= sprintf('%d', (-$XshiftAfter));
		}

		if ($last_fontid != $original_fontid) {
			$tj .= '] TJ ';
			$tj .= sprintf(' /F%d %.3F Tf ', $original_fontid, $fontsize);
			$tj .= '[';
		}

		$tj = $sipset
			? preg_replace('/([^\\\])<>/', '\\1 ', $tj)
			: preg_replace('/([^\\\])\(\)/', '\\1 ', $tj);

		return sprintf(' BT ' . $aix . ' 0 Tc 0 Tw [%s] TJ ET ', $x, $y, $tj);
	}

	function _kern($txt, $mode, $aix, $x, $y)
	{
		if ($mode === 'MBTw') { // Multibyte requiring word spacing

			$space = ' ';

			// Convert string to UTF-16BE without BOM
			$space = $this->writer->utf8ToUtf16BigEndian($space, false);
			$space = $this->writer->escape($space);

			$s = sprintf(' BT ' . $aix, $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE);
			$t = explode(' ', $txt);

			foreach ($t as $i => $iValue) {
				$tx = $iValue;

				$tj = '(';
				$unicode = $this->UTF8StringToArray($tx);

				foreach ($unicode as $ti => $tiValue) {

					if ($ti > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($ti - 1)]][$tiValue])) {
						$kern = -$this->CurrentFont['kerninfo'][$unicode[($ti - 1)]][$tiValue];
						$tj .= sprintf(')%d(', $kern);
					}

					$tc = UtfString::code2utf($tiValue);
					$tc = $this->writer->utf8ToUtf16BigEndian($tc, false);
					$tj .= $this->writer->escape($tc);
				}

				$tj .= ')';
				$s .= sprintf(' %.3F Tc [%s] TJ', $this->charspacing, $tj);

				if (($i + 1) < count($t)) {
					$s .= sprintf(' %.3F Tc (%s) Tj', $this->ws + $this->charspacing, $space);
				}
			}

			$s .= ' ET ';

			return $s;

		}

		if (!$this->usingCoreFont) {

			$s = '';
			$tj = '(';

			$unicode = $this->UTF8StringToArray($txt);

			foreach ($unicode as $i => $iValue) {

				if ($i > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$iValue])) {
					$kern = -$this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$iValue];
					$tj .= sprintf(')%d(', $kern);
				}

				$tx = UtfString::code2utf($iValue);
				$tx = $this->writer->utf8ToUtf16BigEndian($tx, false);
				$tj .= $this->writer->escape($tx);

			}

			$tj .= ')';
			$s .= sprintf(' BT ' . $aix . ' [%s] TJ ET ', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, $tj);

			return $s;

		}

		$s = '';
		$tj = '(';
		$l = strlen($txt);

		for ($i = 0; $i < $l; $i++) {

			if ($i > 0 && isset($this->CurrentFont['kerninfo'][$txt[($i - 1)]][$txt[$i]])) {
				$kern = -$this->CurrentFont['kerninfo'][$txt[($i - 1)]][$txt[$i]];
				$tj .= sprintf(')%d(', $kern);
			}

			$tj .= $this->writer->escape($txt[$i]);
		}

		$tj .= ')';
		$s .= sprintf(' BT ' . $aix . ' [%s] TJ ET ', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, $tj);

		return $s;
	}

	function MultiCell(
		$w,
		$h,
		$txt,
		$border = 0,
		$align = '',
		$fill = 0,
		$link = '',
		$directionality = 'ltr',
		$encoded = false,
		$OTLdata = false,
		$maxrows = false
	) {
		// maxrows is called from mpdfform->TEXTAREA
		// Parameter (pre-)encoded - When called internally from form::textarea -
		// mb_encoding already done and OTL - but not reverse RTL
		if (!$encoded) {

			$txt = $this->purify_utf8_text($txt);

			if ($this->text_input_as_HTML) {
				$txt = $this->all_entities_to_utf8($txt);
			}

			if ($this->usingCoreFont) {
				$txt = mb_convert_encoding($txt, $this->mb_enc, 'UTF-8');
			}

			if (preg_match("/([" . $this->pregRTLchars . "])/u", $txt)) {
				$this->biDirectional = true;
			}

			/* -- OTL -- */
			if (!is_array($OTLdata)) {
				unset($OTLdata);
			}

			// Use OTL OpenType Table Layout - GSUB & GPOS
			if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
				$txt = $this->otl->applyOTL($txt, $this->CurrentFont['useOTL']);
				$OTLdata = $this->otl->OTLdata;
			}

			if ($directionality == 'rtl' || $this->biDirectional) {
				if (!isset($OTLdata)) {
					$unicode = $this->UTF8StringToArray($txt, false);
					$is_strong = false;
					$this->getBasicOTLdata($OTLdata, $unicode, $is_strong);
				}
			}
			/* -- END OTL -- */
		}

		if (!$align) {
			$align = $this->defaultAlign;
		}

		// Output text with automatic or explicit line breaks
		$cw = &$this->CurrentFont['cw'];

		if ($w == 0) {
			$w = $this->w - $this->rMargin - $this->x;
		}

		$wmax = ($w - ($this->cMarginL + $this->cMarginR));

		if ($this->usingCoreFont) {
			$s = str_replace("\r", '', $txt);
			$nb = strlen($s);
			while ($nb > 0 and $s[$nb - 1] == "\n") {
				$nb--;
			}
		} else {
			$s = str_replace("\r", '', $txt);
			$nb = mb_strlen($s, $this->mb_enc);
			while ($nb > 0 and mb_substr($s, $nb - 1, 1, $this->mb_enc) == "\n") {
				$nb--;
			}
		}

		$b = 0;

		if ($border) {

			if ($border == 1) {
				$border = 'LTRB';
				$b = 'LRT';
				$b2 = 'LR';
			} else {
				$b2 = '';
				if (is_int(strpos($border, 'L'))) {
					$b2 .= 'L';
				}
				if (is_int(strpos($border, 'R'))) {
					$b2 .= 'R';
				}
				$b = is_int(strpos($border, 'T')) ? $b2 . 'T' : $b2;
			}
		}

		$sep = -1;
		$i = 0;
		$j = 0;
		$l = 0;
		$ns = 0;
		$nl = 1;

		$rows = 0;
		$start_y = $this->y;

		if (!$this->usingCoreFont) {

			$inclCursive = false;

			if (preg_match("/([" . $this->pregCURSchars . "])/u", $s)) {
				$inclCursive = true;
			}

			while ($i < $nb) {

				// Get next character
				$c = mb_substr($s, $i, 1, $this->mb_enc);

				if ($c === "\n") { // Explicit line break

					// WORD SPACING
					$this->ResetSpacing();
					$tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc));
					$tmpOTLdata = false;

					/* -- OTL -- */
					if (isset($OTLdata)) {
						$tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j);
						$this->otl->trimOTLdata($tmpOTLdata, false, true);
						$this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
					}
					/* -- END OTL -- */

					$this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);

					if ($maxrows != false && isset($this->form) && ($this->y - $start_y) / $h > $maxrows) {
						return false;
					}

					$i++;
					$sep = -1;
					$j = $i;
					$l = 0;
					$ns = 0;
					$nl++;

					if ($border and $nl == 2) {
						$b = $b2;
					}

					continue;
				}

				if ($c == " ") {
					$sep = $i;
					$ls = $l;
					$ns++;
				}

				$l += $this->GetCharWidthNonCore($c);

				if ($l > $wmax) {

					// Automatic line break
					if ($sep == -1) { // Only one word

						if ($i == $j) {
							$i++;
						}

						// WORD SPACING
						$this->ResetSpacing();
						$tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc));
						$tmpOTLdata = false;

						/* -- OTL -- */
						if (isset($OTLdata)) {
							$tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j);
							$this->otl->trimOTLdata($tmpOTLdata, false, true);
							$this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
						}
						/* -- END OTL -- */

						$this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);

					} else {

						$tmp = rtrim(mb_substr($s, $j, $sep - $j, $this->mb_enc));
						$tmpOTLdata = false;

						/* -- OTL -- */
						if (isset($OTLdata)) {
							$tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $sep - $j);
							$this->otl->trimOTLdata($tmpOTLdata, false, true);
						}
						/* -- END OTL -- */

						if ($align === 'J') {

							// JUSTIFY J using Unicode fonts (Word spacing doesn't work)
							// WORD SPACING UNICODE
							// Change NON_BREAKING SPACE to spaces so they are 'spaced' properly

							$tmp = str_replace(chr(194) . chr(160), chr(32), $tmp);
							$len_ligne = $this->GetStringWidth($tmp, false, $tmpOTLdata);
							$nb_carac = mb_strlen($tmp, $this->mb_enc);
							$nb_spaces = mb_substr_count($tmp, ' ', $this->mb_enc);

							// Take off number of Marks
							// Use GPOS OTL

							if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'])) {
								if (isset($tmpOTLdata['group']) && $tmpOTLdata['group']) {
									$nb_carac -= substr_count($tmpOTLdata['group'], 'M');
								}
							}

							list($charspacing, $ws, $kashida) = $this->GetJspacing($nb_carac, $nb_spaces, ((($wmax) - $len_ligne) * Mpdf::SCALE), $inclCursive, $tmpOTLdata);
							$this->SetSpacing($charspacing, $ws);
						}

						if (isset($OTLdata)) {
							$this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
						}

						$this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);

						$i = $sep + 1;
					}

					if ($maxrows != false && isset($this->form) && ($this->y - $start_y) / $h > $maxrows) {
						return false;
					}

					$sep = -1;
					$j = $i;
					$l = 0;
					$ns = 0;
					$nl++;

					if ($border and $nl == 2) {
						$b = $b2;
					}

				} else {
					$i++;
				}
			}

			// Last chunk
			// WORD SPACING

			$this->ResetSpacing();

		} else {

			while ($i < $nb) {

				// Get next character
				$c = $s[$i];
				if ($c === "\n") {

					// Explicit line break
					// WORD SPACING

					$this->ResetSpacing();
					$this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link);

					if ($maxrows != false && isset($this->form) && ($this->y - $start_y) / $h > $maxrows) {
						return false;
					}

					$i++;
					$sep = -1;
					$j = $i;
					$l = 0;
					$ns = 0;
					$nl++;

					if ($border and $nl == 2) {
						$b = $b2;
					}

					continue;
				}

				if ($c === ' ') {
					$sep = $i;
					$ls = $l;
					$ns++;
				}

				$l += $this->GetCharWidthCore($c);

				if ($l > $wmax) {

					// Automatic line break
					if ($sep == -1) {

						if ($i == $j) {
							$i++;
						}

						// WORD SPACING
						$this->ResetSpacing();
						$this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link);

					} else {

						if ($align === 'J') {

							$tmp = rtrim(substr($s, $j, $sep - $j));

							// JUSTIFY J using Unicode fonts (Word spacing doesn't work)
							// WORD SPACING NON_UNICODE/CJK
							// Change NON_BREAKING SPACE to spaces so they are 'spaced' properly

							$tmp = str_replace(chr(160), chr(32), $tmp);
							$len_ligne = $this->GetStringWidth($tmp);
							$nb_carac = strlen($tmp);
							$nb_spaces = substr_count($tmp, ' ');
							$tmpOTLdata = [];

							list($charspacing, $ws, $kashida) = $this->GetJspacing($nb_carac, $nb_spaces, ((($wmax) - $len_ligne) * Mpdf::SCALE), false, $tmpOTLdata);
							$this->SetSpacing($charspacing, $ws);
						}

						$this->Cell($w, $h, substr($s, $j, $sep - $j), $b, 2, $align, $fill, $link);
						$i = $sep + 1;
					}

					if ($maxrows != false && isset($this->form) && ($this->y - $start_y) / $h > $maxrows) {
						return false;
					}

					$sep = -1;
					$j = $i;
					$l = 0;
					$ns = 0;
					$nl++;

					if ($border and $nl == 2) {
						$b = $b2;
					}

				} else {
					$i++;
				}
			}

			// Last chunk
			// WORD SPACING

			$this->ResetSpacing();
		}

		// Last chunk
		if ($border and is_int(strpos($border, 'B'))) {
			$b .= 'B';
		}

		if (!$this->usingCoreFont) {

			$tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc));
			$tmpOTLdata = false;

			/* -- OTL -- */
			if (isset($OTLdata)) {
				$tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j);
				$this->otl->trimOTLdata($tmpOTLdata, false, true);
				$this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
			}
			/* -- END OTL -- */

			$this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);
		} else {
			$this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link);
		}

		$this->x = $this->lMargin;
	}

	/* -- DIRECTW -- */

	function Write($h, $txt, $currentx = 0, $link = '', $directionality = 'ltr', $align = '', $fill = 0)
	{
		if (empty($this->directWrite)) {
			$this->directWrite = new DirectWrite($this, $this->otl, $this->sizeConverter, $this->colorConverter);
		}

		$this->directWrite->Write($h, $txt, $currentx, $link, $directionality, $align, $fill);
	}

	/* -- END DIRECTW -- */


	/* -- HTML-CSS -- */

	function saveInlineProperties()
	{
		$saved = [];
		$saved['family'] = $this->FontFamily;
		$saved['style'] = $this->FontStyle;
		$saved['sizePt'] = $this->FontSizePt;
		$saved['size'] = $this->FontSize;
		$saved['HREF'] = $this->HREF;
		$saved['textvar'] = $this->textvar; // mPDF 5.7.1
		$saved['OTLtags'] = $this->OTLtags; // mPDF 5.7.1
		$saved['textshadow'] = $this->textshadow;
		$saved['linewidth'] = $this->LineWidth;
		$saved['drawcolor'] = $this->DrawColor;
		$saved['textparam'] = $this->textparam;
		$saved['lSpacingCSS'] = $this->lSpacingCSS;
		$saved['wSpacingCSS'] = $this->wSpacingCSS;
		$saved['I'] = $this->I;
		$saved['B'] = $this->B;
		$saved['colorarray'] = $this->colorarray;
		$saved['bgcolorarray'] = $this->spanbgcolorarray;
		$saved['border'] = $this->spanborddet;
		$saved['color'] = $this->TextColor;
		$saved['bgcolor'] = $this->FillColor;
		$saved['lang'] = $this->currentLang;
		$saved['fontLanguageOverride'] = $this->fontLanguageOverride; // mPDF 5.7.1
		$saved['display_off'] = $this->inlineDisplayOff;

		return $saved;
	}

	function restoreInlineProperties(&$saved)
	{
		$FontFamily = $saved['family'];
		$this->FontStyle = $saved['style'];
		$this->FontSizePt = $saved['sizePt'];
		$this->FontSize = $saved['size'];

		$this->currentLang = $saved['lang'];
		$this->fontLanguageOverride = $saved['fontLanguageOverride']; // mPDF 5.7.1

		$this->ColorFlag = ($this->FillColor != $this->TextColor); // Restore ColorFlag as well

		$this->HREF = $saved['HREF'];
		$this->textvar = $saved['textvar']; // mPDF 5.7.1
		$this->OTLtags = $saved['OTLtags']; // mPDF 5.7.1
		$this->textshadow = $saved['textshadow'];
		$this->LineWidth = $saved['linewidth'];
		$this->DrawColor = $saved['drawcolor'];
		$this->textparam = $saved['textparam'];
		$this->inlineDisplayOff = $saved['display_off'];

		$this->lSpacingCSS = $saved['lSpacingCSS'];
		if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
			$this->fixedlSpacing = $this->sizeConverter->convert($this->lSpacingCSS, $this->FontSize);
		} else {
			$this->fixedlSpacing = false;
		}
		$this->wSpacingCSS = $saved['wSpacingCSS'];
		if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
			$this->minwSpacing = $this->sizeConverter->convert($this->wSpacingCSS, $this->FontSize);
		} else {
			$this->minwSpacing = 0;
		}

		$this->SetFont($FontFamily, $saved['style'], $saved['sizePt'], false);

		$this->currentfontstyle = $saved['style'];
		$this->currentfontsize = $saved['sizePt'];
		$this->SetStylesArray(['B' => $saved['B'], 'I' => $saved['I']]); // mPDF 5.7.1

		$this->TextColor = $saved['color'];
		$this->FillColor = $saved['bgcolor'];
		$this->colorarray = $saved['colorarray'];
		$cor = $saved['colorarray'];
		if ($cor) {
			$this->SetTColor($cor);
		}
		$this->spanbgcolorarray = $saved['bgcolorarray'];
		$cor = $saved['bgcolorarray'];
		if ($cor) {
			$this->SetFColor($cor);
		}
		$this->spanborddet = $saved['border'];
	}

	// Used when ColActive for tables - updated to return first block with background fill OR borders
	function GetFirstBlockFill()
	{
		// Returns the first blocklevel that uses a bgcolor fill
		$startfill = 0;
		for ($i = 1; $i <= $this->blklvl; $i++) {
			if ($this->blk[$i]['bgcolor'] || $this->blk[$i]['border_left']['w'] || $this->blk[$i]['border_right']['w'] || $this->blk[$i]['border_top']['w'] || $this->blk[$i]['border_bottom']['w']) {
				$startfill = $i;
				break;
			}
		}
		return $startfill;
	}

	// -------------------------FLOWING BLOCK------------------------------------//
	// The following functions were originally written by Damon Kohler           //
	// --------------------------------------------------------------------------//

	function saveFont()
	{
		$saved = [];
		$saved['family'] = $this->FontFamily;
		$saved['style'] = $this->FontStyle;
		$saved['sizePt'] = $this->FontSizePt;
		$saved['size'] = $this->FontSize;
		$saved['curr'] = &$this->CurrentFont;
		$saved['lang'] = $this->currentLang; // mPDF 6
		$saved['color'] = $this->TextColor;
		$saved['spanbgcolor'] = $this->spanbgcolor;
		$saved['spanbgcolorarray'] = $this->spanbgcolorarray;
		$saved['bord'] = $this->spanborder;
		$saved['border'] = $this->spanborddet;
		$saved['HREF'] = $this->HREF;
		$saved['textvar'] = $this->textvar; // mPDF 5.7.1
		$saved['textshadow'] = $this->textshadow;
		$saved['linewidth'] = $this->LineWidth;
		$saved['drawcolor'] = $this->DrawColor;
		$saved['textparam'] = $this->textparam;
		$saved['ReqFontStyle'] = $this->ReqFontStyle;
		$saved['fixedlSpacing'] = $this->fixedlSpacing;
		$saved['minwSpacing'] = $this->minwSpacing;
		return $saved;
	}

	function restoreFont(&$saved, $write = true)
	{
		if (!isset($saved) || empty($saved)) {
			return;
		}

		$this->FontFamily = $saved['family'];
		$this->FontStyle = $saved['style'];
		$this->FontSizePt = $saved['sizePt'];
		$this->FontSize = $saved['size'];
		$this->CurrentFont = &$saved['curr'];
		$this->currentLang = $saved['lang']; // mPDF 6
		$this->TextColor = $saved['color'];
		$this->spanbgcolor = $saved['spanbgcolor'];
		$this->spanbgcolorarray = $saved['spanbgcolorarray'];
		$this->spanborder = $saved['bord'];
		$this->spanborddet = $saved['border'];
		$this->ColorFlag = ($this->FillColor != $this->TextColor); // Restore ColorFlag as well
		$this->HREF = $saved['HREF'];
		$this->fixedlSpacing = $saved['fixedlSpacing'];
		$this->minwSpacing = $saved['minwSpacing'];
		$this->textvar = $saved['textvar'];  // mPDF 5.7.1
		$this->textshadow = $saved['textshadow'];
		$this->LineWidth = $saved['linewidth'];
		$this->DrawColor = $saved['drawcolor'];
		$this->textparam = $saved['textparam'];
		if ($write) {
			$this->SetFont($saved['family'], $saved['style'], $saved['sizePt'], true, true); // force output
			$fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
			if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
				$this->writer->write($fontout);
			}
			$this->pageoutput[$this->page]['Font'] = $fontout;
		} else {
			$this->SetFont($saved['family'], $saved['style'], $saved['sizePt'], false);
		}
		$this->ReqFontStyle = $saved['ReqFontStyle'];
	}

	function newFlowingBlock($w, $h, $a = '', $is_table = false, $blockstate = 0, $newblock = true, $blockdir = 'ltr', $table_draft = false)
	{
		if (!$a) {
			if ($blockdir == 'rtl') {
				$a = 'R';
			} else {
				$a = 'L';
			}
		}
		$this->flowingBlockAttr['width'] = ($w * Mpdf::SCALE);
		// line height in user units
		$this->flowingBlockAttr['is_table'] = $is_table;
		$this->flowingBlockAttr['table_draft'] = $table_draft;
		$this->flowingBlockAttr['height'] = $h;
		$this->flowingBlockAttr['lineCount'] = 0;
		$this->flowingBlockAttr['align'] = $a;
		$this->flowingBlockAttr['font'] = [];
		$this->flowingBlockAttr['content'] = [];
		$this->flowingBlockAttr['contentB'] = [];
		$this->flowingBlockAttr['contentWidth'] = 0;
		$this->flowingBlockAttr['blockstate'] = $blockstate;

		$this->flowingBlockAttr['newblock'] = $newblock;
		$this->flowingBlockAttr['valign'] = 'M';
		$this->flowingBlockAttr['blockdir'] = $blockdir;
		$this->flowingBlockAttr['cOTLdata'] = []; // mPDF 5.7.1
		$this->flowingBlockAttr['lastBidiText'] = ''; // mPDF 5.7.1
		if (!empty($this->otl)) {
			$this->otl->lastBidiStrongType = '';
		} // *OTL*
	}

	function finishFlowingBlock($endofblock = false, $next = '')
	{
		$currentx = $this->x;
		// prints out the last chunk
		$is_table = $this->flowingBlockAttr['is_table'];
		$table_draft = $this->flowingBlockAttr['table_draft'];
		$maxWidth = & $this->flowingBlockAttr['width'];
		$stackHeight = & $this->flowingBlockAttr['height'];
		$align = & $this->flowingBlockAttr['align'];
		$content = & $this->flowingBlockAttr['content'];
		$contentB = & $this->flowingBlockAttr['contentB'];
		$font = & $this->flowingBlockAttr['font'];
		$contentWidth = & $this->flowingBlockAttr['contentWidth'];
		$lineCount = & $this->flowingBlockAttr['lineCount'];
		$valign = & $this->flowingBlockAttr['valign'];
		$blockstate = $this->flowingBlockAttr['blockstate'];

		$cOTLdata = & $this->flowingBlockAttr['cOTLdata']; // mPDF 5.7.1
		$newblock = $this->flowingBlockAttr['newblock'];
		$blockdir = $this->flowingBlockAttr['blockdir'];

		// *********** BLOCK BACKGROUND COLOR *****************//
		if ($this->blk[$this->blklvl]['bgcolor'] && !$is_table) {
			$fill = 0;
		} else {
			$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
			$fill = 0;
		}

		$hanger = '';
		// Always right trim!
		// Right trim last content and adjust width if needed to justify (later)
		if (isset($content[count($content) - 1]) && preg_match('/[ ]+$/', $content[count($content) - 1], $m)) {
			$strip = strlen($m[0]);
			$content[count($content) - 1] = substr($content[count($content) - 1], 0, (strlen($content[count($content) - 1]) - $strip));
			/* -- OTL -- */
			if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
				$this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], false, true);
			}
			/* -- END OTL -- */
		}

		// the amount of space taken up so far in user units
		$usedWidth = 0;

		// COLS
		$oldcolumn = $this->CurrCol;

		if ($this->ColActive && !$is_table) {
			$this->breakpoints[$this->CurrCol][] = $this->y;
		} // *COLUMNS*
		// Print out each chunk

		/* -- TABLES -- */
		if ($is_table) {
			$ipaddingL = 0;
			$ipaddingR = 0;
			$paddingL = 0;
			$paddingR = 0;
		} else {
			/* -- END TABLES -- */
			$ipaddingL = $this->blk[$this->blklvl]['padding_left'];
			$ipaddingR = $this->blk[$this->blklvl]['padding_right'];
			$paddingL = ($ipaddingL * Mpdf::SCALE);
			$paddingR = ($ipaddingR * Mpdf::SCALE);
			$this->cMarginL = $this->blk[$this->blklvl]['border_left']['w'];
			$this->cMarginR = $this->blk[$this->blklvl]['border_right']['w'];

			// Added mPDF 3.0 Float DIV
			$fpaddingR = 0;
			$fpaddingL = 0;
			/* -- CSS-FLOAT -- */
			if (count($this->floatDivs)) {
				list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
				if ($r_exists) {
					$fpaddingR = $r_width;
				}
				if ($l_exists) {
					$fpaddingL = $l_width;
				}
			}
			/* -- END CSS-FLOAT -- */

			$usey = $this->y + 0.002;
			if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
				$usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
			}
			/* -- CSS-IMAGE-FLOAT -- */
			// If float exists at this level
			if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
				$fpaddingR += $this->floatmargins['R']['w'];
			}
			if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
				$fpaddingL += $this->floatmargins['L']['w'];
			}
			/* -- END CSS-IMAGE-FLOAT -- */
		} // *TABLES*


		$lineBox = [];

		$this->_setInlineBlockHeights($lineBox, $stackHeight, $content, $font, $is_table);

		if ($is_table && count($content) == 0) {
			$stackHeight = 0;
		}

		if ($table_draft) {
			$this->y += $stackHeight;
			$this->objectbuffer = [];
			return 0;
		}

		// While we're at it, check if contains cursive text
		// Change NBSP to SPACE.
		// Re-calculate contentWidth
		$contentWidth = 0;

		foreach ($content as $k => $chunk) {
			$this->restoreFont($font[$k], false);
			if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
				// Soft Hyphens chr(173)
				if (!$this->usingCoreFont) {
					/* -- OTL -- */
					// mPDF 5.7.1
					if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
						$this->otl->removeChar($chunk, $cOTLdata[$k], "\xc2\xad");
						$this->otl->replaceSpace($chunk, $cOTLdata[$k]);
						$content[$k] = $chunk;
					} /* -- END OTL -- */ else {  // *OTL*
						$content[$k] = $chunk = str_replace("\xc2\xad", '', $chunk);
						$content[$k] = $chunk = str_replace(chr(194) . chr(160), chr(32), $chunk);
					} // *OTL*
				} elseif ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
					$content[$k] = $chunk = str_replace(chr(173), '', $chunk);
					$content[$k] = $chunk = str_replace(chr(160), chr(32), $chunk);
				}
				$contentWidth += $this->GetStringWidth($chunk, true, (isset($cOTLdata[$k]) ? $cOTLdata[$k] : false), $this->textvar) * Mpdf::SCALE;
			} elseif (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
				// LIST MARKERS	// mPDF 6  Lists
				if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') {
					// do nothing
				} else {
					$contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * Mpdf::SCALE;
				}
			}
		}

		if (isset($font[count($font) - 1])) {
			$lastfontreqstyle = (isset($font[count($font) - 1]['ReqFontStyle']) ? $font[count($font) - 1]['ReqFontStyle'] : '');
			$lastfontstyle = (isset($font[count($font) - 1]['style']) ? $font[count($font) - 1]['style'] : '');
		} else {
			$lastfontreqstyle = null;
			$lastfontstyle = null;
		}
		if ($blockdir == 'ltr' && $lastfontreqstyle && strpos($lastfontreqstyle, "I") !== false && strpos($lastfontstyle, "I") === false) { // Artificial italic
			$lastitalic = $this->FontSize * 0.15 * Mpdf::SCALE;
		} else {
			$lastitalic = 0;
		}

		// Get PAGEBREAK TO TEST for height including the bottom border/padding
		$check_h = max($this->divheight, $stackHeight);

		// This fixes a proven bug...
		if ($endofblock && $newblock && $blockstate == 0 && !$content) {
			$check_h = 0;
		}
		// but ? needs to fix potentially more widespread...
		// if (!$content) {  $check_h = 0; }

		if ($this->blklvl > 0 && !$is_table) {
			if ($endofblock && $blockstate > 1) {
				if ($this->blk[$this->blklvl]['page_break_after_avoid']) {
					$check_h += $stackHeight;
				}
				$check_h += ($this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w']);
			}
			if (($newblock && ($blockstate == 1 || $blockstate == 3) && $lineCount == 0) || ($endofblock && $blockstate == 3 && $lineCount == 0)) {
				$check_h += ($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['border_top']['w']);
			}
		}

		// Force PAGE break if column height cannot take check-height
		if ($this->ColActive && $check_h > ($this->PageBreakTrigger - $this->y0)) {
			$this->SetCol($this->NbCol - 1);
		}

		// Avoid just border/background-color moved on to next page
		if ($endofblock && $blockstate > 1 && !$content) {
			$buff = $this->margBuffer;
		} else {
			$buff = 0;
		}


		// PAGEBREAK
		if (!$is_table && ($this->y + $check_h) > ($this->PageBreakTrigger + $buff) and ! $this->InFooter and $this->AcceptPageBreak()) {
			$bak_x = $this->x; // Current X position
			// WORD SPACING
			$ws = $this->ws; // Word Spacing
			$charspacing = $this->charspacing; // Character Spacing
			$this->ResetSpacing();

			$this->AddPage($this->CurOrientation);

			$this->x = $bak_x;
			// Added to correct for OddEven Margins
			$currentx += $this->MarginCorrection;
			$this->x += $this->MarginCorrection;

			// WORD SPACING
			$this->SetSpacing($charspacing, $ws);
		}


		/* -- COLUMNS -- */
		// COLS
		// COLUMN CHANGE
		if ($this->CurrCol != $oldcolumn) {
			$currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
			$this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
			$oldcolumn = $this->CurrCol;
		}


		if ($this->ColActive && !$is_table) {
			$this->breakpoints[$this->CurrCol][] = $this->y;
		}
		/* -- END COLUMNS -- */

		// TOP MARGIN
		if ($newblock && ($blockstate == 1 || $blockstate == 3) && ($this->blk[$this->blklvl]['margin_top']) && $lineCount == 0 && !$is_table) {
			$this->DivLn($this->blk[$this->blklvl]['margin_top'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']);
			if ($this->ColActive) {
				$this->breakpoints[$this->CurrCol][] = $this->y;
			} // *COLUMNS*
		}

		if ($newblock && ($blockstate == 1 || $blockstate == 3) && $lineCount == 0 && !$is_table) {
			$this->blk[$this->blklvl]['y0'] = $this->y;
			$this->blk[$this->blklvl]['startpage'] = $this->page;
			if ($this->blk[$this->blklvl]['float']) {
				$this->blk[$this->blklvl]['float_start_y'] = $this->y;
			}
			if ($this->ColActive) {
				$this->breakpoints[$this->CurrCol][] = $this->y;
			} // *COLUMNS*
		}

		// Paragraph INDENT
		$WidthCorrection = 0;
		if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) {
			$ti = $this->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
			$WidthCorrection = ($ti * Mpdf::SCALE);
		}


		// PADDING and BORDER spacing/fill
		if (($newblock) && ($blockstate == 1 || $blockstate == 3) && (($this->blk[$this->blklvl]['padding_top']) || ($this->blk[$this->blklvl]['border_top'])) && ($lineCount == 0) && (!$is_table)) {
			// $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
			$this->DivLn($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'], -3, true, false, 1);
			if ($this->ColActive) {
				$this->breakpoints[$this->CurrCol][] = $this->y;
			} // *COLUMNS*
			$this->x = $currentx;
		}


		// Added mPDF 3.0 Float DIV
		$fpaddingR = 0;
		$fpaddingL = 0;
		/* -- CSS-FLOAT -- */
		if (count($this->floatDivs)) {
			list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
			if ($r_exists) {
				$fpaddingR = $r_width;
			}
			if ($l_exists) {
				$fpaddingL = $l_width;
			}
		}
		/* -- END CSS-FLOAT -- */

		$usey = $this->y + 0.002;
		if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
			$usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
		}
		/* -- CSS-IMAGE-FLOAT -- */
		// If float exists at this level
		if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
			$fpaddingR += $this->floatmargins['R']['w'];
		}
		if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
			$fpaddingL += $this->floatmargins['L']['w'];
		}
		/* -- END CSS-IMAGE-FLOAT -- */


		if ($content) {
			// In FinishFlowing Block no lines are justified as it is always last line
			// but if CJKorphan has allowed content width to go over max width, use J charspacing to compress line
			// JUSTIFICATION J - NOT!
			$nb_carac = 0;
			$nb_spaces = 0;
			$jcharspacing = 0;
			$jkashida = 0;
			$jws = 0;
			$inclCursive = false;
			$dottab = false;
			foreach ($content as $k => $chunk) {
				if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
					$nb_carac += mb_strlen($chunk, $this->mb_enc);
					$nb_spaces += mb_substr_count($chunk, ' ', $this->mb_enc);
					// mPDF 6
					// Use GPOS OTL
					$this->restoreFont($font[$k], false);
					if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
						if (isset($cOTLdata[$k]['group']) && $cOTLdata[$k]['group']) {
							$nb_marks = substr_count($cOTLdata[$k]['group'], 'M');
							$nb_carac -= $nb_marks;
						}
						if (preg_match("/([" . $this->pregCURSchars . "])/u", $chunk)) {
							$inclCursive = true;
						}
					}
				} else {
					$nb_carac ++;  // mPDF 6 allow spacing for inline object
					if ($this->objectbuffer[$k]['type'] == 'dottab') {
						$dottab = $this->objectbuffer[$k]['outdent'];
					}
				}
			}

			// DIRECTIONALITY RTL
			$chunkorder = range(0, count($content) - 1); // mPDF 6
			/* -- OTL -- */
			// mPDF 6
			if ($blockdir == 'rtl' || $this->biDirectional) {
				$this->otl->bidiReorder($chunkorder, $content, $cOTLdata, $blockdir);
				// From this point on, $content and $cOTLdata may contain more elements (and re-ordered) compared to
				// $this->objectbuffer and $font ($chunkorder contains the mapping)
			}
			/* -- END OTL -- */

			// Remove any XAdvance from OTL data at end of line
			// And correct for XPlacement on last character
			// BIDI is applied
			foreach ($chunkorder as $aord => $k) {
				if (count($cOTLdata)) {
					$this->restoreFont($font[$k], false);
					// ...FinishFlowingBlock...
					if ($aord == count($chunkorder) - 1 && isset($cOTLdata[$aord]['group'])) { // Last chunk on line
						$nGPOS = strlen($cOTLdata[$aord]['group']) - 1; // Last character
						if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL']) || isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'])) {
							if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'])) {
								$w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
							} else {
								$w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
							}
							$w *= ($this->FontSize / 1000);
							$contentWidth -= $w * Mpdf::SCALE;
							$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = 0;
							$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = 0;
						}

						// If last character has an XPlacement set, adjust width calculation, and add to XAdvance to account for it
						if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'])) {
							$w = -$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
							$w *= ($this->FontSize / 1000);
							$contentWidth -= $w * Mpdf::SCALE;
							$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
							$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
						}
					}
				}
			}

			// if it's justified, we need to find the char/word spacing (or if orphans have allowed length of line to go over the maxwidth)
			// If "orphans" in fact is just a final space - ignore this
			$lastchar = mb_substr($content[(count($chunkorder) - 1)], mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, 1, $this->mb_enc);
			if (preg_match("/[" . $this->CJKoverflow . "]/u", $lastchar)) {
				$CJKoverflow = true;
			} else {
				$CJKoverflow = false;
			}
			if ((((($contentWidth + $lastitalic) > $maxWidth) && ($content[(count($chunkorder) - 1)] != ' ') ) ||
				(!$endofblock && $align == 'J' && ($next == 'image' || $next == 'select' || $next == 'input' || $next == 'textarea' || ($next == 'br' && $this->justifyB4br)))) && !($CJKoverflow && $this->allowCJKoverflow)) {
				// WORD SPACING
				list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) )), $inclCursive, $cOTLdata);
			} /* -- CJK-FONTS -- */ elseif ($this->checkCJK && $align == 'J' && $CJKoverflow && $this->allowCJKoverflow && $this->CJKforceend) {
				// force-end overhang
				$hanger = mb_substr($content[(count($chunkorder) - 1)], mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, 1, $this->mb_enc);
				if (preg_match("/[" . $this->CJKoverflow . "]/u", $hanger)) {
					$content[(count($chunkorder) - 1)] = mb_substr($content[(count($chunkorder) - 1)], 0, mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, $this->mb_enc);
					$this->restoreFont($font[$chunkorder[count($chunkorder) - 1]], false);
					$contentWidth -= $this->GetStringWidth($hanger) * Mpdf::SCALE;
					$nb_carac -= 1;
					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);
				}
			} /* -- END CJK-FONTS -- */

			// Check if will fit at word/char spacing of previous line - if so continue it
			// but only allow a maximum of $this->jSmaxWordLast and $this->jSmaxCharLast
			elseif ($contentWidth < ($maxWidth - $lastitalic - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE))) && !$this->fixedlSpacing) {
				if ($this->ws > $this->jSmaxWordLast) {
					$jws = $this->jSmaxWordLast;
				}
				if ($this->charspacing > $this->jSmaxCharLast) {
					$jcharspacing = $this->jSmaxCharLast;
				}
				$check = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) ) - ( $jcharspacing * $nb_carac) - ( $jws * $nb_spaces);
				if ($check <= 0) {
					$jcharspacing = 0;
					$jws = 0;
				}
			}

			$empty = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) );


			$empty -= ($jcharspacing * ($nb_carac - 1)); // mPDF 6 nb_carac MINUS 1
			$empty -= ($jws * $nb_spaces);
			$empty -= ($jkashida);

			$empty /= Mpdf::SCALE;

			if (!$is_table) {
				$this->maxPosR = max($this->maxPosR, ($this->w - $this->rMargin - $this->blk[$this->blklvl]['outer_right_margin'] - $empty));
				$this->maxPosL = min($this->maxPosL, ($this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $empty));
			}

			$arraysize = count($chunkorder);

			$margins = ($this->cMarginL + $this->cMarginR) + ($ipaddingL + $ipaddingR + $fpaddingR + $fpaddingR );

			if (!$is_table) {
				$this->DivLn($stackHeight, $this->blklvl, false);
			} // false -> don't advance y

			$this->x = $currentx + $this->cMarginL + $ipaddingL + $fpaddingL;
			if ($dottab !== false && $blockdir == 'rtl') {
				$this->x -= $dottab;
			} elseif ($align == 'R') {
				$this->x += $empty;
			} elseif ($align == 'J' && $blockdir == 'rtl') {
				$this->x += $empty;
			} elseif ($align == 'C') {
				$this->x += ($empty / 2);
			}

			// Paragraph INDENT
			$WidthCorrection = 0;
			if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) {
				$ti = $this->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
				if ($blockdir != 'rtl') {
					$this->x += $ti;
				} // mPDF 6
			}

			foreach ($chunkorder as $aord => $k) { // mPDF 5.7
				$chunk = $content[$aord];
				if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
					$xadj = $this->x - $this->objectbuffer[$k]['OUTER-X'];
					$this->objectbuffer[$k]['OUTER-X'] += $xadj;
					$this->objectbuffer[$k]['BORDER-X'] += $xadj;
					$this->objectbuffer[$k]['INNER-X'] += $xadj;

					if ($this->objectbuffer[$k]['type'] == 'listmarker') {
						$this->objectbuffer[$k]['lineBox'] = $lineBox[-1]; // Block element details for glyph-origin
					}
					$yadj = $this->y - $this->objectbuffer[$k]['OUTER-Y'];
					if ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
						$this->objectbuffer[$k]['lineBox'] = $lineBox[$k]; // element details for glyph-origin
					}
					if ($this->objectbuffer[$k]['type'] != 'dottab') { // mPDF 6 DOTTAB
						$yadj += $lineBox[$k]['top'];
					}
					$this->objectbuffer[$k]['OUTER-Y'] += $yadj;
					$this->objectbuffer[$k]['BORDER-Y'] += $yadj;
					$this->objectbuffer[$k]['INNER-Y'] += $yadj;
				}

				$this->restoreFont($font[$k]);  // mPDF 5.7

				if ($is_table && substr($align, 0, 1) == 'D' && $aord == 0) {
					$dp = $this->decimal_align[substr($align, 0, 2)];
					$s = preg_split('/' . preg_quote($dp, '/') . '/', $content[0], 2);  // ? needs to be /u if not core
					$s0 = $this->GetStringWidth($s[0], false);
					$this->x += ($this->decimal_offset - $s0);
				}

				$this->SetSpacing(($this->fixedlSpacing * Mpdf::SCALE) + $jcharspacing, ($this->fixedlSpacing + $this->minwSpacing) * Mpdf::SCALE + $jws);
				$this->fixedlSpacing = false;
				$this->minwSpacing = 0;

				$save_vis = $this->visibility;
				if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->textparam['visibility'] != $this->visibility) {
					$this->SetVisibility($this->textparam['visibility']);
				}

				// *********** SPAN BACKGROUND COLOR ***************** //
				if (isset($this->spanbgcolor) && $this->spanbgcolor) {
					$cor = $this->spanbgcolorarray;
					$this->SetFColor($cor);
					$save_fill = $fill;
					$spanfill = 1;
					$fill = 1;
				}
				if (!empty($this->spanborddet)) {
					if (strpos($contentB[$k], 'L') !== false && isset($this->spanborddet['L'])) {
						$this->x += $this->spanborddet['L']['w'];
					}
					if (strpos($contentB[$k], 'L') === false) {
						$this->spanborddet['L']['s'] = $this->spanborddet['L']['w'] = 0;
					}
					if (strpos($contentB[$k], 'R') === false) {
						$this->spanborddet['R']['s'] = $this->spanborddet['R']['w'] = 0;
					}
				}
				// WORD SPACING
				// mPDF 5.7.1
				$stringWidth = $this->GetStringWidth($chunk, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar);
				$nch = mb_strlen($chunk, $this->mb_enc);
				// Use GPOS OTL
				if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
					if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) {
						$nch -= substr_count($cOTLdata[$aord]['group'], 'M');
					}
				}
				$stringWidth += ( $this->charspacing * $nch / Mpdf::SCALE );

				$stringWidth += ( $this->ws * mb_substr_count($chunk, ' ', $this->mb_enc) / Mpdf::SCALE );

				if (isset($this->objectbuffer[$k])) {
					if ($this->objectbuffer[$k]['type'] == 'dottab') {
						$this->objectbuffer[$k]['OUTER-WIDTH'] +=$empty;
						$this->objectbuffer[$k]['OUTER-WIDTH'] +=$this->objectbuffer[$k]['outdent'];
					}
					// LIST MARKERS	// mPDF 6  Lists
					if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') {
						// do nothing
					} else {
						$stringWidth = $this->objectbuffer[$k]['OUTER-WIDTH'];
					}
				}

				if ($stringWidth == 0) {
					$stringWidth = 0.000001;
				}
				if ($aord == $arraysize - 1) { // mPDF 5.7
					// mPDF 5.7.1
					if ($this->checkCJK && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) {
						// force-end overhang
						$this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false));  // mPDF 5.7.1
						$this->Cell($this->GetStringWidth($hanger), $stackHeight, $hanger, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // mPDF 5.7.1
					} else {
						$this->Cell($stringWidth, $stackHeight, $chunk, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // mPDF 5.7.1
					}
				} else {
					$this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, 0, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // first or middle part	// mPDF 5.7.1
				}


				if (!empty($this->spanborddet)) {
					if (strpos($contentB[$k], 'R') !== false && $aord != $arraysize - 1) {
						$this->x += $this->spanborddet['R']['w'];
					}
				}
				// *********** SPAN BACKGROUND COLOR OFF - RESET BLOCK BGCOLOR ***************** //
				if (isset($spanfill) && $spanfill) {
					$fill = $save_fill;
					$spanfill = 0;
					if ($fill) {
						$this->SetFColor($bcor);
					}
				}
				if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->visibility != $save_vis) {
					$this->SetVisibility($save_vis);
				}
			}

			$this->printobjectbuffer($is_table, $blockdir);
			$this->objectbuffer = [];
			$this->ResetSpacing();
		} // END IF CONTENT

		/* -- CSS-IMAGE-FLOAT -- */
		// Update values if set to skipline
		if ($this->floatmargins) {
			$this->_advanceFloatMargins();
		}


		if ($endofblock && $blockstate > 1) {
			// If float exists at this level
			if (isset($this->floatmargins['R']['y1'])) {
				$fry1 = $this->floatmargins['R']['y1'];
			} else {
				$fry1 = 0;
			}
			if (isset($this->floatmargins['L']['y1'])) {
				$fly1 = $this->floatmargins['L']['y1'];
			} else {
				$fly1 = 0;
			}
			if ($this->y < $fry1 || $this->y < $fly1) {
				$drop = max($fry1, $fly1) - $this->y;
				$this->DivLn($drop);
				$this->x = $currentx;
			}
		}
		/* -- END CSS-IMAGE-FLOAT -- */


		// PADDING and BORDER spacing/fill
		if ($endofblock && ($blockstate > 1) && ($this->blk[$this->blklvl]['padding_bottom'] || $this->blk[$this->blklvl]['border_bottom'] || $this->blk[$this->blklvl]['css_set_height']) && (!$is_table)) {
			// If CSS height set, extend bottom - if on same page as block started, and CSS HEIGHT > actual height,
			// and does not force pagebreak
			$extra = 0;
			if (isset($this->blk[$this->blklvl]['css_set_height']) && $this->blk[$this->blklvl]['css_set_height'] && $this->blk[$this->blklvl]['startpage'] == $this->page) {
				// predicted height
				$h1 = ($this->y - $this->blk[$this->blklvl]['y0']) + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'];
				if ($h1 < ($this->blk[$this->blklvl]['css_set_height'] + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['padding_top'])) {
					$extra = ($this->blk[$this->blklvl]['css_set_height'] + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['padding_top']) - $h1;
				}
				if ($this->y + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $extra > $this->PageBreakTrigger) {
					$extra = $this->PageBreakTrigger - ($this->y + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w']);
				}
			}

			// $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
			$this->DivLn($this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $extra, -3, true, false, 2);
			$this->x = $currentx;

			if ($this->ColActive) {
				$this->breakpoints[$this->CurrCol][] = $this->y;
			} // *COLUMNS*
		}

		// SET Bottom y1 of block (used for painting borders)
		if (($endofblock) && ($blockstate > 1) && (!$is_table)) {
			$this->blk[$this->blklvl]['y1'] = $this->y;
		}

		// BOTTOM MARGIN
		if (($endofblock) && ($blockstate > 1) && ($this->blk[$this->blklvl]['margin_bottom']) && (!$is_table)) {
			if ($this->y + $this->blk[$this->blklvl]['margin_bottom'] < $this->PageBreakTrigger and ! $this->InFooter) {
				$this->DivLn($this->blk[$this->blklvl]['margin_bottom'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']);
				if ($this->ColActive) {
					$this->breakpoints[$this->CurrCol][] = $this->y;
				} // *COLUMNS*
			}
		}

		// Reset lineheight
		$stackHeight = $this->divheight;
	}

	function printobjectbuffer($is_table = false, $blockdir = false)
	{
		if (!$blockdir) {
			$blockdir = $this->directionality;
		}

		if ($is_table && $this->shrin_k > 1) {
			$k = $this->shrin_k;
		} else {
			$k = 1;
		}

		$save_y = $this->y;
		$save_x = $this->x;

		$save_currentfontfamily = $this->FontFamily;
		$save_currentfontsize = $this->FontSizePt;
		$save_currentfontstyle = $this->FontStyle;

		if ($blockdir == 'rtl') {
			$rtlalign = 'R';
		} else {
			$rtlalign = 'L';
		}

		foreach ($this->objectbuffer as $ib => $objattr) {

			if ($objattr['type'] == 'bookmark' || $objattr['type'] == 'indexentry' || $objattr['type'] == 'toc') {
				$x = $objattr['OUTER-X'];
				$y = $objattr['OUTER-Y'];
				$this->y = $y - $this->FontSize / 2;
				$this->x = $x;
				if ($objattr['type'] == 'bookmark') {
					$this->Bookmark($objattr['CONTENT'], $objattr['bklevel'], $y - $this->FontSize);
				} // *BOOKMARKS*
				if ($objattr['type'] == 'indexentry') {
					$this->IndexEntry($objattr['CONTENT']);
				} // *INDEX*
				if ($objattr['type'] == 'toc') {
					$this->TOC_Entry($objattr['CONTENT'], $objattr['toclevel'], (isset($objattr['toc_id']) ? $objattr['toc_id'] : ''));
				} // *TOC*
			} /* -- ANNOTATIONS -- */ elseif ($objattr['type'] == 'annot') {
				if ($objattr['POS-X']) {
					$x = $objattr['POS-X'];
				} elseif ($this->annotMargin <> 0) {
					$x = -$objattr['OUTER-X'];
				} else {
					$x = $objattr['OUTER-X'];
				}
				if ($objattr['POS-Y']) {
					$y = $objattr['POS-Y'];
				} else {
					$y = $objattr['OUTER-Y'] - $this->FontSize / 2;
				}
				// Create a dummy entry in the _out/columnBuffer with position sensitive data,
				// linking $y-1 in the Columnbuffer with entry in $this->columnAnnots
				// and when columns are split in length will not break annotation from current line
				$this->y = $y - 1;
				$this->x = $x - 1;
				$this->Line($x - 1, $y - 1, $x - 1, $y - 1);
				$this->Annotation($objattr['CONTENT'], $x, $y, $objattr['ICON'], $objattr['AUTHOR'], $objattr['SUBJECT'], $objattr['OPACITY'], $objattr['COLOR'], (isset($objattr['POPUP']) ? $objattr['POPUP'] : ''), (isset($objattr['FILE']) ? $objattr['FILE'] : ''));
			} /* -- END ANNOTATIONS -- */ else {
				$y = $objattr['OUTER-Y'];
				$x = $objattr['OUTER-X'];
				$w = $objattr['OUTER-WIDTH'];
				$h = $objattr['OUTER-HEIGHT'];
				if (isset($objattr['text'])) {
					$texto = $objattr['text'];
				}
				$this->y = $y;
				$this->x = $x;
				if (isset($objattr['fontfamily'])) {
					$this->SetFont($objattr['fontfamily'], '', $objattr['fontsize']);
				}
			}

			// HR
			if ($objattr['type'] == 'hr') {
				$this->SetDColor($objattr['color']);
				switch ($objattr['align']) {
					case 'C':
						$empty = $objattr['OUTER-WIDTH'] - $objattr['INNER-WIDTH'];
						$empty /= 2;
						$x += $empty;
						break;
					case 'R':
						$empty = $objattr['OUTER-WIDTH'] - $objattr['INNER-WIDTH'];
						$x += $empty;
						break;
				}
				$oldlinewidth = $this->LineWidth;
				$this->SetLineWidth($objattr['linewidth'] / $k);
				$this->y += ($objattr['linewidth'] / 2) + $objattr['margin_top'] / $k;
				$this->Line($x, $this->y, $x + $objattr['INNER-WIDTH'], $this->y);
				$this->SetLineWidth($oldlinewidth);
				$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
			}
			// IMAGE
			if ($objattr['type'] == 'image') {
				// mPDF 5.7.3 TRANSFORMS
				if (isset($objattr['transform'])) {
					$this->writer->write("\n" . '% BTR'); // Begin Transform
				}
				if (isset($objattr['z-index']) && $objattr['z-index'] > 0 && $this->current_layer == 0) {
					$this->BeginLayer($objattr['z-index']);
				}
				if (isset($objattr['visibility']) && $objattr['visibility'] != 'visible' && $objattr['visibility']) {
					$this->SetVisibility($objattr['visibility']);
				}
				if (isset($objattr['opacity'])) {
					$this->SetAlpha($objattr['opacity']);
				}

				$obiw = $objattr['INNER-WIDTH'];
				$obih = $objattr['INNER-HEIGHT'];

				$sx = $objattr['orig_w'] ? ($objattr['INNER-WIDTH'] * Mpdf::SCALE / $objattr['orig_w']) : INF;
				$sy = $objattr['orig_h'] ? ($objattr['INNER-HEIGHT'] * Mpdf::SCALE / $objattr['orig_h']) : INF;

				$rotate = 0;
				if (isset($objattr['ROTATE'])) {
					$rotate = $objattr['ROTATE'];
				}

				if ($rotate == 90) {
					// Clockwise
					$obiw = $objattr['INNER-HEIGHT'];
					$obih = $objattr['INNER-WIDTH'];
					$tr = $this->transformTranslate(0, -$objattr['INNER-WIDTH'], true);
					$tr .= ' ' . $this->transformRotate(90, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-WIDTH']), true);
					$sx = $obiw * Mpdf::SCALE / $objattr['orig_h'];
					$sy = $obih * Mpdf::SCALE / $objattr['orig_w'];
				} elseif ($rotate == -90 || $rotate == 270) {
					// AntiClockwise
					$obiw = $objattr['INNER-HEIGHT'];
					$obih = $objattr['INNER-WIDTH'];
					$tr = $this->transformTranslate($objattr['INNER-WIDTH'], ($objattr['INNER-HEIGHT'] - $objattr['INNER-WIDTH']), true);
					$tr .= ' ' . $this->transformRotate(-90, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-WIDTH']), true);
					$sx = $obiw * Mpdf::SCALE / $objattr['orig_h'];
					$sy = $obih * Mpdf::SCALE / $objattr['orig_w'];
				} elseif ($rotate == 180) {
					// Mirror
					$tr = $this->transformTranslate($objattr['INNER-WIDTH'], -$objattr['INNER-HEIGHT'], true);
					$tr .= ' ' . $this->transformRotate(180, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-HEIGHT']), true);
				} else {
					$tr = '';
				}
				$tr = trim($tr);
				if ($tr) {
					$tr .= ' ';
				}
				$gradmask = '';

				// mPDF 5.7.3 TRANSFORMS
				$tr2 = '';
				if (isset($objattr['transform'])) {
					$maxsize_x = $w;
					$maxsize_y = $h;
					$cx = $x + $w / 2;
					$cy = $y + $h / 2;
					preg_match_all('/(translatex|translatey|translate|scalex|scaley|scale|rotate|skewX|skewY|skew)\((.*?)\)/is', $objattr['transform'], $m);
					if (count($m[0])) {
						for ($i = 0; $i < count($m[0]); $i++) {
							$c = strtolower($m[1][$i]);
							$v = trim($m[2][$i]);
							$vv = preg_split('/[ ,]+/', $v);
							if ($c == 'translate' && count($vv)) {
								$translate_x = $this->sizeConverter->convert($vv[0], $maxsize_x, false, false);
								if (count($vv) == 2) {
									$translate_y = $this->sizeConverter->convert($vv[1], $maxsize_y, false, false);
								} else {
									$translate_y = 0;
								}
								$tr2 .= $this->transformTranslate($translate_x, $translate_y, true) . ' ';
							} elseif ($c == 'translatex' && count($vv)) {
								$translate_x = $this->sizeConverter->convert($vv[0], $maxsize_x, false, false);
								$tr2 .= $this->transformTranslate($translate_x, 0, true) . ' ';
							} elseif ($c == 'translatey' && count($vv)) {
								$translate_y = $this->sizeConverter->convert($vv[1], $maxsize_y, false, false);
								$tr2 .= $this->transformTranslate(0, $translate_y, true) . ' ';
							} elseif ($c == 'scale' && count($vv)) {
								$scale_x = $vv[0] * 100;
								if (count($vv) == 2) {
									$scale_y = $vv[1] * 100;
								} else {
									$scale_y = $scale_x;
								}
								$tr2 .= $this->transformScale($scale_x, $scale_y, $cx, $cy, true) . ' ';
							} elseif ($c == 'scalex' && count($vv)) {
								$scale_x = $vv[0] * 100;
								$tr2 .= $this->transformScale($scale_x, 0, $cx, $cy, true) . ' ';
							} elseif ($c == 'scaley' && count($vv)) {
								$scale_y = $vv[1] * 100;
								$tr2 .= $this->transformScale(0, $scale_y, $cx, $cy, true) . ' ';
							} elseif ($c == 'skew' && count($vv)) {
								$angle_x = $this->ConvertAngle($vv[0], false);
								if (count($vv) == 2) {
									$angle_y = $this->ConvertAngle($vv[1], false);
								} else {
									$angle_y = 0;
								}
								$tr2 .= $this->transformSkew($angle_x, $angle_y, $cx, $cy, true) . ' ';
							} elseif ($c == 'skewx' && count($vv)) {
								$angle = $this->ConvertAngle($vv[0], false);
								$tr2 .= $this->transformSkew($angle, 0, $cx, $cy, true) . ' ';
							} elseif ($c == 'skewy' && count($vv)) {
								$angle = $this->ConvertAngle($vv[0], false);
								$tr2 .= $this->transformSkew(0, $angle, $cx, $cy, true) . ' ';
							} elseif ($c == 'rotate' && count($vv)) {
								$angle = $this->ConvertAngle($vv[0]);
								$tr2 .= $this->transformRotate($angle, $cx, $cy, true) . ' ';
							}
						}
					}
				}

				// LIST MARKERS (Images)	// mPDF 6  Lists
				if (isset($objattr['listmarker']) && $objattr['listmarker'] && $objattr['listmarkerposition'] == 'outside') {
					$mw = $objattr['OUTER-WIDTH'];
					// NB If change marker-offset, also need to alter in function _getListMarkerWidth
					$adjx = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);
					if ($objattr['dir'] == 'rtl') {
						$objattr['INNER-X'] += $adjx;
					} else {
						$objattr['INNER-X'] -= $adjx;
						$objattr['INNER-X'] -= $mw;
					}
				}
				// mPDF 5.7.3 TRANSFORMS / BACKGROUND COLOR
				// Transform also affects image background
				if ($tr2) {
					$this->writer->write('q ' . $tr2 . ' ');
				}
				if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
					$bgcol = $objattr['bgcolor'];
					$this->SetFColor($bgcol);
					$this->Rect($x, $y, $w, $h, 'F');
					$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
				}
				if ($tr2) {
					$this->writer->write('Q');
				}

				/* -- BACKGROUNDS -- */
				if (isset($objattr['GRADIENT-MASK'])) {
					$g = $this->gradient->parseMozGradient($objattr['GRADIENT-MASK']);
					if ($g) {
						$dummy = $this->gradient->Gradient($objattr['INNER-X'], $objattr['INNER-Y'], $obiw, $obih, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true, true);
						$gradmask = '/TGS' . count($this->gradients) . ' gs ';
					}
				}
				/* -- END BACKGROUNDS -- */
				/* -- IMAGES-WMF -- */
				if (isset($objattr['itype']) && $objattr['itype'] == 'wmf') {
					$outstring = sprintf('q ' . $tr . $tr2 . '%.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, -$sy, $objattr['INNER-X'] * Mpdf::SCALE - $sx * $objattr['wmf_x'], (($this->h - $objattr['INNER-Y']) * Mpdf::SCALE) + $sy * $objattr['wmf_y'], $objattr['ID']); // mPDF 5.7.3 TRANSFORMS
				} else { 				/* -- END IMAGES-WMF -- */
					if (isset($objattr['itype']) && $objattr['itype'] == 'svg') {
						$outstring = sprintf('q ' . $tr . $tr2 . '%.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, -$sy, $objattr['INNER-X'] * Mpdf::SCALE - $sx * $objattr['wmf_x'], (($this->h - $objattr['INNER-Y']) * Mpdf::SCALE) + $sy * $objattr['wmf_y'], $objattr['ID']); // mPDF 5.7.3 TRANSFORMS
					} else {
						$outstring = sprintf("q " . $tr . $tr2 . "%.3F 0 0 %.3F %.3F %.3F cm " . $gradmask . "/I%d Do Q", $obiw * 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
					}
				}
				$this->writer->write($outstring);
				// LINK
				if (isset($objattr['link'])) {
					$this->Link($objattr['INNER-X'], $objattr['INNER-Y'], $objattr['INNER-WIDTH'], $objattr['INNER-HEIGHT'], $objattr['link']);
				}
				if (isset($objattr['opacity'])) {
					$this->SetAlpha(1);
				}

				// mPDF 5.7.3 TRANSFORMS
				// Transform also affects image borders
				if ($tr2) {
					$this->writer->write('q ' . $tr2 . ' ');
				}
				if ((isset($objattr['border_top']) && $objattr['border_top'] > 0) || (isset($objattr['border_left']) && $objattr['border_left'] > 0) || (isset($objattr['border_right']) && $objattr['border_right'] > 0) || (isset($objattr['border_bottom']) && $objattr['border_bottom'] > 0)) {
					$this->PaintImgBorder($objattr, $is_table);
				}
				if ($tr2) {
					$this->writer->write('Q');
				}

				if (isset($objattr['visibility']) && $objattr['visibility'] != 'visible' && $objattr['visibility']) {
					$this->SetVisibility('visible');
				}
				if (isset($objattr['z-index']) && $objattr['z-index'] > 0 && $this->current_layer == 0) {
					$this->EndLayer();
				}
				// mPDF 5.7.3 TRANSFORMS
				if (isset($objattr['transform'])) {
					$this->writer->write("\n" . '% ETR'); // End Transform
				}
			}

			if ($objattr['type'] === 'barcode') {

				$bgcol = $this->colorConverter->convert(255, $this->PDFAXwarnings);

				if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
					$bgcol = $objattr['bgcolor'];
				}

				$col = $this->colorConverter->convert(0, $this->PDFAXwarnings);

				if (isset($objattr['color']) && $objattr['color']) {
					$col = $objattr['color'];
				}

				$this->SetFColor($bgcol);
				$this->Rect($objattr['BORDER-X'], $objattr['BORDER-Y'], $objattr['BORDER-WIDTH'], $objattr['BORDER-HEIGHT'], 'F');
				$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));

				if (isset($objattr['BORDER-WIDTH'])) {
					$this->PaintImgBorder($objattr, $is_table);
				}

				$barcodeTypes = ['EAN13', 'ISBN', 'ISSN', 'UPCA', 'UPCE', 'EAN8'];
				if (in_array($objattr['btype'], $barcodeTypes, true)) {

					$this->WriteBarcode(
						$objattr['code'],
						$objattr['showtext'],
						$objattr['INNER-X'],
						$objattr['INNER-Y'],
						$objattr['bsize'],
						0,
						0,
						0,
						0,
						0,
						$objattr['bheight'],
						$bgcol,
						$col,
						$objattr['btype'],
						$objattr['bsupp'],
						(isset($objattr['bsupp_code']) ? $objattr['bsupp_code'] : ''),
						$k
					);

				} elseif ($objattr['btype'] === 'QR') {

					if (!class_exists('Mpdf\QrCode\QrCode') || !class_exists('Mpdf\QrCode\Output\Mpdf')) {
						throw new \Mpdf\MpdfException('Mpdf\QrCode package was not found. Install the package from Packagist with "composer require mpdf/qrcode"');
					}

					$barcodeContent = str_replace('\r\n', "\r\n", $objattr['code']);
					$barcodeContent = str_replace('\n', "\n", $barcodeContent);

					$qrcode = new QrCode\QrCode($barcodeContent, $objattr['errorlevel']);
					if ($objattr['disableborder']) {
						$qrcode->disableBorder();
					}

					$bgColor = [255, 255, 255];
					if ($objattr['bgcolor']) {
						$bgColor = array_map(
							function ($col) {
								return intval(255 * floatval($col));
							},
							explode(" ", $this->SetColor($objattr['bgcolor'], 'CodeOnly'))
						);
					}
					$color = [0, 0, 0];
					if ($objattr['color']) {
						$color = array_map(
							function ($col) {
								return intval(255 * floatval($col));
							},
							explode(" ", $this->SetColor($objattr['color'], 'CodeOnly'))
						);
					}

					$out = new QrCode\Output\Mpdf();
					$out->output(
						$qrcode,
						$this,
						$objattr['INNER-X'],
						$objattr['INNER-Y'],
						$objattr['bsize'] * 25,
						$bgColor,
						$color
					);

					unset($qrcode);

				} else {
					$this->WriteBarcode2(
						$objattr['code'],
						$objattr['INNER-X'],
						$objattr['INNER-Y'],
						$objattr['bsize'],
						$objattr['bheight'],
						$bgcol,
						$col,
						$objattr['btype'],
						$objattr['pr_ratio'],
						$k,
						$objattr['quiet_zone_left'],
						$objattr['quiet_zone_right']
					);
				}
			}

			// TEXT CIRCLE
			if ($objattr['type'] == 'textcircle') {
				$bgcol = '';
				if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
					$bgcol = $objattr['bgcolor'];
				}
				$col = $this->colorConverter->convert(0, $this->PDFAXwarnings);
				if (isset($objattr['color']) && $objattr['color']) {
					$col = $objattr['color'];
				}
				$this->SetTColor($col);
				$this->SetFColor($bgcol);
				if ($bgcol) {
					$this->Rect($objattr['BORDER-X'], $objattr['BORDER-Y'], $objattr['BORDER-WIDTH'], $objattr['BORDER-HEIGHT'], 'F');
				}
				$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
				if (isset($objattr['BORDER-WIDTH'])) {
					$this->PaintImgBorder($objattr, $is_table);
				}
				if (empty($this->directWrite)) {
					$this->directWrite = new DirectWrite($this, $this->otl, $this->sizeConverter, $this->colorConverter);
				}
				if (isset($objattr['top-text'])) {
					$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'] : ''));
				}
				if (isset($objattr['bottom-text'])) {
					$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'] : ''));
				}
			}

			$this->ResetSpacing();

			// LIST MARKERS (Text or bullets)	// mPDF 6  Lists
			if ($objattr['type'] == 'listmarker') {
				if (isset($objattr['fontfamily'])) {
					$this->SetFont($objattr['fontfamily'], $objattr['fontstyle'], $objattr['fontsizept']);
				}
				$col = $this->colorConverter->convert(0, $this->PDFAXwarnings);
				if (isset($objattr['colorarray']) && ($objattr['colorarray'])) {
					$col = $objattr['colorarray'];
				}

				if (isset($objattr['bullet']) && $objattr['bullet']) { // Used for position "outside" only
					$type = $objattr['bullet'];
					$size = $objattr['size'];

					if ($objattr['listmarkerposition'] == 'inside') {
						$adjx = $size / 2;
						if ($objattr['dir'] == 'rtl') {
							$adjx += $objattr['offset'];
						}
						$this->x += $adjx;
					} else {
						$adjx = $objattr['offset'];
						$adjx += $size / 2;
						if ($objattr['dir'] == 'rtl') {
							$this->x += $adjx;
						} else {
							$this->x -= $adjx;
						}
					}

					$yadj = $objattr['lineBox']['glyphYorigin'];
					if (isset($this->CurrentFont['desc']['XHeight']) && $this->CurrentFont['desc']['XHeight']) {
						$xh = $this->CurrentFont['desc']['XHeight'];
					} else {
						$xh = 500;
					}
					$yadj -= ($this->FontSize * $xh / 1000) * 0.625; // Vertical height of bullet (centre) from baseline= XHeight * 0.625
					$this->y += $yadj;

					$this->_printListBullet($this->x, $this->y, $size, $type, $col);
				} else {
					$this->SetTColor($col);
					$w = $this->GetStringWidth($texto);
					// NB If change marker-offset, also need to alter in function _getListMarkerWidth
					$adjx = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);
					if ($objattr['dir'] == 'rtl') {
						$align = 'L';
						$this->x += $adjx;
					} else {
						// Use these lines to set as marker-offset, right-aligned - default
						$align = 'R';
						$this->x -= $adjx;
						$this->x -= $w;
					}
					$this->Cell($w, $this->FontSize, $texto, 0, 0, $align, 0, '', 0, 0, 0, 'T', 0, false, false, 0, $objattr['lineBox']);
					$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
				}
			}

			// DOT-TAB
			if ($objattr['type'] == 'dottab') {
				if (isset($objattr['fontfamily'])) {
					$this->SetFont($objattr['fontfamily'], '', $objattr['fontsize']);
				}
				$sp = $this->GetStringWidth(' ');
				$nb = floor(($w - 2 * $sp) / $this->GetStringWidth('.'));
				if ($nb > 0) {
					$dots = ' ' . str_repeat('.', $nb) . ' ';
				} else {
					$dots = ' ';
				}
				$col = $this->colorConverter->convert(0, $this->PDFAXwarnings);
				if (isset($objattr['colorarray']) && ($objattr['colorarray'])) {
					$col = $objattr['colorarray'];
				}
				$this->SetTColor($col);
				$save_dh = $this->divheight;
				$save_sbd = $this->spanborddet;
				$save_textvar = $this->textvar; // mPDF 5.7.1
				$this->spanborddet = '';
				$this->divheight = 0;
				$this->textvar = 0x00; // mPDF 5.7.1

				$this->Cell($w, $h, $dots, 0, 0, 'C', 0, '', 0, 0, 0, 'T', 0, false, false, 0, $objattr['lineBox']); // mPDF 6 DOTTAB
				$this->spanborddet = $save_sbd;
				$this->textvar = $save_textvar; // mPDF 5.7.1
				$this->divheight = $save_dh;
				$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
			}

			/* -- FORMS -- */
			// TEXT/PASSWORD INPUT
			if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'TEXT' || $objattr['subtype'] == 'PASSWORD')) {
				$this->form->print_ob_text($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
			}

			// TEXTAREA
			if ($objattr['type'] == 'textarea') {
				$this->form->print_ob_textarea($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
			}

			// SELECT
			if ($objattr['type'] == 'select') {
				$this->form->print_ob_select($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
			}


			// INPUT/BUTTON as IMAGE
			if ($objattr['type'] == 'input' && $objattr['subtype'] == 'IMAGE') {
				$this->form->print_ob_imageinput($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $is_table);
			}

			// BUTTON
			if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'SUBMIT' || $objattr['subtype'] == 'RESET' || $objattr['subtype'] == 'BUTTON')) {
				$this->form->print_ob_button($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
			}

			// CHECKBOX
			if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'CHECKBOX')) {
				$this->form->print_ob_checkbox($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $x, $y);
			}
			// RADIO
			if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'RADIO')) {
				$this->form->print_ob_radio($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $x, $y);
			}
			/* -- END FORMS -- */
		}

		$this->SetFont($save_currentfontfamily, $save_currentfontstyle, $save_currentfontsize);

		$this->y = $save_y;
		$this->x = $save_x;

		unset($content);
	}

	function _printListBullet($x, $y, $size, $type, $color)
	{
		// x and y are the centre of the bullet; size is the width and/or height in mm
		$fcol = $this->SetTColor($color, true);
		$lcol = strtoupper($fcol); // change 0 0 0 rg to 0 0 0 RG
		$this->writer->write(sprintf('q %s %s', $lcol, $fcol));
		$this->writer->write('0 j 0 J [] 0 d');
		if ($type == 'square') {
			$size *= 0.85; // Smaller to appear the same size as circle/disc
			$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));
		} elseif ($type == 'disc') {
			$this->Circle($x, $y, $size / 2, 'F'); // Fill
		} elseif ($type == 'circle') {
			$lw = $size / 12; // Line width
			$this->writer->write(sprintf('%.3F w ', $lw * Mpdf::SCALE));
			$this->Circle($x, $y, $size / 2 - $lw / 2, 'S'); // Stroke
		}
		$this->writer->write('Q');
	}

	// mPDF 6
	// Get previous character and move pointers
	function _moveToPrevChar(&$contentctr, &$charctr, $content)
	{
		$lastchar = false;
		$charctr--;
		while ($charctr < 0) { // go back to previous $content[]
			$contentctr--;
			if ($contentctr < 0) {
				return false;
			}
			if ($this->usingCoreFont) {
				$charctr = strlen($content[$contentctr]) - 1;
			} else {
				$charctr = mb_strlen($content[$contentctr], $this->mb_enc) - 1;
			}
		}
		if ($this->usingCoreFont) {
			$lastchar = $content[$contentctr][$charctr];
		} else {
			$lastchar = mb_substr($content[$contentctr], $charctr, 1, $this->mb_enc);
		}
		return $lastchar;
	}

	// Get previous character
	function _getPrevChar($contentctr, $charctr, $content)
	{
		$lastchar = false;
		$charctr--;
		while ($charctr < 0) { // go back to previous $content[]
			$contentctr--;
			if ($contentctr < 0) {
				return false;
			}
			if ($this->usingCoreFont) {
				$charctr = strlen($content[$contentctr]) - 1;
			} else {
				$charctr = mb_strlen($content[$contentctr], $this->mb_enc) - 1;
			}
		}
		if ($this->usingCoreFont) {
			$lastchar = $content[$contentctr][$charctr];
		} else {
			$lastchar = mb_substr($content[$contentctr], $charctr, 1, $this->mb_enc);
		}
		return $lastchar;
	}

	function WriteFlowingBlock($s, $sOTLdata)
	{
	// mPDF 5.7.1
		$currentx = $this->x;
		$is_table = $this->flowingBlockAttr['is_table'];
		$table_draft = $this->flowingBlockAttr['table_draft'];
		// width of all the content so far in points
		$contentWidth = & $this->flowingBlockAttr['contentWidth'];
		// cell width in points
		$maxWidth = & $this->flowingBlockAttr['width'];
		$lineCount = & $this->flowingBlockAttr['lineCount'];
		// line height in user units
		$stackHeight = & $this->flowingBlockAttr['height'];
		$align = & $this->flowingBlockAttr['align'];
		$content = & $this->flowingBlockAttr['content'];
		$contentB = & $this->flowingBlockAttr['contentB'];
		$font = & $this->flowingBlockAttr['font'];
		$valign = & $this->flowingBlockAttr['valign'];
		$blockstate = $this->flowingBlockAttr['blockstate'];
		$cOTLdata = & $this->flowingBlockAttr['cOTLdata']; // mPDF 5.7.1

		$newblock = $this->flowingBlockAttr['newblock'];
		$blockdir = $this->flowingBlockAttr['blockdir'];

		// *********** BLOCK BACKGROUND COLOR ***************** //
		if ($this->blk[$this->blklvl]['bgcolor'] && !$is_table) {
			$fill = 0;
		} else {
			$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
			$fill = 0;
		}
		$font[] = $this->saveFont();
		$content[] = '';
		$contentB[] = '';
		$cOTLdata[] = $sOTLdata; // mPDF 5.7.1
		$currContent = & $content[count($content) - 1];

		$CJKoverflow = false;
		$Oikomi = false; // mPDF 6
		$hanger = '';

		// COLS
		$oldcolumn = $this->CurrCol;
		if ($this->ColActive && !$is_table) {
			$this->breakpoints[$this->CurrCol][] = $this->y;
		} // *COLUMNS*

		/* -- TABLES -- */
		if ($is_table) {
			$ipaddingL = 0;
			$ipaddingR = 0;
			$paddingL = 0;
			$paddingR = 0;
			$cpaddingadjustL = 0;
			$cpaddingadjustR = 0;
			// Added mPDF 3.0
			$fpaddingR = 0;
			$fpaddingL = 0;
		} else {
			/* -- END TABLES -- */
			$ipaddingL = $this->blk[$this->blklvl]['padding_left'];
			$ipaddingR = $this->blk[$this->blklvl]['padding_right'];
			$paddingL = ($ipaddingL * Mpdf::SCALE);
			$paddingR = ($ipaddingR * Mpdf::SCALE);
			$this->cMarginL = $this->blk[$this->blklvl]['border_left']['w'];
			$cpaddingadjustL = -$this->cMarginL;
			$this->cMarginR = $this->blk[$this->blklvl]['border_right']['w'];
			$cpaddingadjustR = -$this->cMarginR;
			// Added mPDF 3.0 Float DIV
			$fpaddingR = 0;
			$fpaddingL = 0;
			/* -- CSS-FLOAT -- */
			if (count($this->floatDivs)) {
				list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
				if ($r_exists) {
					$fpaddingR = $r_width;
				}
				if ($l_exists) {
					$fpaddingL = $l_width;
				}
			}
			/* -- END CSS-FLOAT -- */

			$usey = $this->y + 0.002;
			if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
				$usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
			}
			/* -- CSS-IMAGE-FLOAT -- */
			// If float exists at this level
			if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
				$fpaddingR += $this->floatmargins['R']['w'];
			}
			if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
				$fpaddingL += $this->floatmargins['L']['w'];
			}
			/* -- END CSS-IMAGE-FLOAT -- */
		} // *TABLES*
		// OBJECTS - IMAGES & FORM Elements (NB has already skipped line/page if required - in printbuffer)
		if (substr($s, 0, 3) == "\xbb\xa4\xac") { // identifier has been identified!
			$objattr = $this->_getObjAttr($s);
			$h_corr = 0;
			if ($is_table) { // *TABLES*
				$maximumW = ($maxWidth / Mpdf::SCALE) - ($this->cellPaddingL + $this->cMarginL + $this->cellPaddingR + $this->cMarginR);  // *TABLES*
			} // *TABLES*
			else { // *TABLES*
				if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0) && (!$is_table)) {
					$h_corr = $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
				}
				$maximumW = ($maxWidth / 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 );
			} // *TABLES*
			$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);

			// SET LINEHEIGHT for this line ================ RESET AT END
			$stackHeight = max($stackHeight, $objattr['OUTER-HEIGHT']);
			$this->objectbuffer[count($content) - 1] = $objattr;
			// if (isset($objattr['vertical-align'])) { $valign = $objattr['vertical-align']; }
			// else { $valign = ''; }
			// LIST MARKERS	// mPDF 6  Lists
			if ($objattr['type'] == 'image' && isset($objattr['listmarker']) && $objattr['listmarker'] && $objattr['listmarkerposition'] == 'outside') {
				// do nothing
			} else {
				$contentWidth += ($objattr['OUTER-WIDTH'] * Mpdf::SCALE);
			}
			return;
		}

		$lbw = $rbw = 0; // Border widths
		if (!empty($this->spanborddet)) {
			if (isset($this->spanborddet['L'])) {
				$lbw = $this->spanborddet['L']['w'];
			}
			if (isset($this->spanborddet['R'])) {
				$rbw = $this->spanborddet['R']['w'];
			}
		}

		if ($this->usingCoreFont) {
			$clen = strlen($s);
		} else {
			$clen = mb_strlen($s, $this->mb_enc);
		}

		// for every character in the string
		for ($i = 0; $i < $clen; $i++) {
			// extract the current character
			// get the width of the character in points
			if ($this->usingCoreFont) {
				$c = $s[$i];
				// Soft Hyphens chr(173)
				$cw = ($this->GetCharWidthCore($c) * Mpdf::SCALE);
				if (($this->textvar & TextVars::FC_KERNING) && $i > 0) { // mPDF 5.7.1
					if (isset($this->CurrentFont['kerninfo'][$s[($i - 1)]][$c])) {
						$cw += ($this->CurrentFont['kerninfo'][$s[($i - 1)]][$c] * $this->FontSizePt / 1000 );
					}
				}
			} else {
				$c = mb_substr($s, $i, 1, $this->mb_enc);
				$cw = ($this->GetCharWidthNonCore($c, false) * Mpdf::SCALE);
				// mPDF 5.7.1
				// Use OTL GPOS
				if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) {
					// ...WriteFlowingBlock...
					// Only  add XAdvanceL (not sure at present whether RTL or LTR writing direction)
					// At this point, XAdvanceL and XAdvanceR will balance
					if (isset($sOTLdata['GPOSinfo'][$i]['XAdvanceL'])) {
						$cw += $sOTLdata['GPOSinfo'][$i]['XAdvanceL'] * (1000 / $this->CurrentFont['unitsPerEm']) * ($this->FontSize / 1000) * Mpdf::SCALE;
					}
				}
				if (($this->textvar & TextVars::FC_KERNING) && $i > 0) { // mPDF 5.7.1
					$lastc = mb_substr($s, ($i - 1), 1, $this->mb_enc);
					$ulastc = $this->UTF8StringToArray($lastc, false);
					$uc = $this->UTF8StringToArray($c, false);
					if (isset($this->CurrentFont['kerninfo'][$ulastc[0]][$uc[0]])) {
						$cw += ($this->CurrentFont['kerninfo'][$ulastc[0]][$uc[0]] * $this->FontSizePt / 1000 );
					}
				}
			}

			if ($i == 0) {
				$cw += $lbw * Mpdf::SCALE;
				$contentB[(count($contentB) - 1)] .= 'L';
			}
			if ($i == ($clen - 1)) {
				$cw += $rbw * Mpdf::SCALE;
				$contentB[(count($contentB) - 1)] .= 'R';
			}
			if ($c == ' ') {
				$currContent .= $c;
				$contentWidth += $cw;
				continue;
			}

			// Paragraph INDENT
			$WidthCorrection = 0;
			if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) {
				$ti = $this->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
				$WidthCorrection = ($ti * Mpdf::SCALE);
			}
			// OUTDENT
			foreach ($this->objectbuffer as $k => $objattr) {   // mPDF 6 DOTTAB
				if ($objattr['type'] == 'dottab') {
					$WidthCorrection -= ($objattr['outdent'] * Mpdf::SCALE);
					break;
				}
			}


			// Added mPDF 3.0 Float DIV
			$fpaddingR = 0;
			$fpaddingL = 0;
			/* -- CSS-FLOAT -- */
			if (count($this->floatDivs)) {
				list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
				if ($r_exists) {
					$fpaddingR = $r_width;
				}
				if ($l_exists) {
					$fpaddingL = $l_width;
				}
			}
			/* -- END CSS-FLOAT -- */

			$usey = $this->y + 0.002;
			if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
				$usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
			}

			/* -- CSS-IMAGE-FLOAT -- */
			// If float exists at this level
			if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
				$fpaddingR += $this->floatmargins['R']['w'];
			}
			if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
				$fpaddingL += $this->floatmargins['L']['w'];
			}
			/* -- END CSS-IMAGE-FLOAT -- */


			// try adding another char
			if (( $contentWidth + $cw > $maxWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) ) + 0.001)) {// 0.001 is to correct for deviations converting mm=>pts
				// it won't fit, output what we already have
				$lineCount++;

				// contains any content that didn't make it into this print
				$savedContent = '';
				$savedContentB = '';
				$savedOTLdata = []; // mPDF 5.7.1
				$savedFont = [];
				$savedObj = [];
				$savedPreOTLdata = []; // mPDF 5.7.1
				$savedPreContent = [];
				$savedPreContentB = [];
				$savedPreFont = [];

				// mPDF 6
				// New line-breaking algorithm
				/////////////////////
				// LINE BREAKING
				/////////////////////
				$breakfound = false;
				$contentctr = count($content) - 1;
				if ($this->usingCoreFont) {
					$charctr = strlen($currContent);
				} else {
					$charctr = mb_strlen($currContent, $this->mb_enc);
				}
				$checkchar = $c;
				$prevchar = $this->_getPrevChar($contentctr, $charctr, $content);

				/* -- CJK-FONTS -- */
				// 1) CJK Overflowing a) punctuation or b) Oikomi
				// Next character ($c) is suitable to add as overhanging or squeezed punctuation, or Oikomi
				if ($CJKoverflow || $Oikomi) { // If flag already set
					$CJKoverflow = false;
					$Oikomi = false;
					$breakfound = true;
				}
				if (!$this->usingCoreFont && !$breakfound && $this->checkCJK) {

					// Get next/following character (in this chunk)
					$followingchar = '';
					if ($i < ($clen - 1)) {
						if ($this->usingCoreFont) {
							$followingchar = $s[$i + 1];
						} else {
							$followingchar = mb_substr($s, $i + 1, 1, $this->mb_enc);
						}
					}

					// 1a) Overflow punctuation
					if (preg_match("/[" . $this->pregCJKchars . "]/u", $prevchar) && preg_match("/[" . $this->CJKoverflow . "]/u", $checkchar) && $this->allowCJKorphans) {
						// add character onto this line
						$currContent .= $c;
						$contentWidth += $cw;
						$CJKoverflow = true; // Set flag
						continue;
					} elseif (preg_match("/[" . $this->pregCJKchars . "]/u", $checkchar) && $this->allowCJKorphans &&
							(preg_match("/[" . $this->CJKleading . "]/u", $followingchar) || preg_match("/[" . $this->CJKfollowing . "]/u", $checkchar)) &&
							!preg_match("/[" . $this->CJKleading . "]/u", $checkchar) && !preg_match("/[" . $this->CJKfollowing . "]/u", $followingchar) &&
							!(preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $followingchar) && preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $checkchar))) {
						// 1b) Try squeezing another character(s) onto this line = Oikomi, if character cannot end line
						// or next character cannot start line (and not splitting CJK numerals)
						// NB otherwise it move lastchar(s) to next line to keep $c company = Oidashi, which is done below in standard way
						// add character onto this line
						$currContent .= $c;
						$contentWidth += $cw;
						$Oikomi = true; // Set flag
						continue;
					}
				}
				/* -- END CJK-FONTS -- */
				/* -- HYPHENATION -- */

				// AUTOMATIC HYPHENATION
				// 2) Automatic hyphen in current word (does not cross tags)
				if (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] == 1) {
					$currWord = '';
					// Look back and ahead to get current word
					for ($ac = $charctr - 1; $ac >= 0; $ac--) {
						if ($this->usingCoreFont) {
							$addc = substr($currContent, $ac, 1);
						} else {
							$addc = mb_substr($currContent, $ac, 1, $this->mb_enc);
						}
						if ($addc == ' ') {
							break;
						}
						$currWord = $addc . $currWord;
					}
					$start = $ac + 1;
					for ($ac = $i; $ac < ($clen - 1); $ac++) {
						if ($this->usingCoreFont) {
							$addc = substr($s, $ac, 1);
						} else {
							$addc = mb_substr($s, $ac, 1, $this->mb_enc);
						}
						if ($addc == ' ') {
							break;
						}
						$currWord .= $addc;
					}
					$ptr = $this->hyphenator->hyphenateWord($currWord, $charctr - $start);
					if ($ptr > -1) {
						$breakfound = [$contentctr, $start + $ptr, $contentctr, $start + $ptr, 'hyphen'];
					}
				}
				/* -- END HYPHENATION -- */

				// Search backwards to find first line-break opportunity
				while ($breakfound == false && $prevchar !== false) {
					$cutcontentctr = $contentctr;
					$cutcharctr = $charctr;
					$prevchar = $this->_moveToPrevChar($contentctr, $charctr, $content);
					/////////////////////
					// 3) Break at SPACE
					/////////////////////
					if ($prevchar == ' ') {
						$breakfound = [$contentctr, $charctr, $cutcontentctr, $cutcharctr, 'discard'];
					} /////////////////////
					// 4) Break at U+200B in current word (Khmer, Lao & Thai Invisible word boundary, and Tibetan)
					/////////////////////
					elseif ($prevchar == "\xe2\x80\x8b") { // U+200B Zero-width Word Break
						$breakfound = [$contentctr, $charctr, $cutcontentctr, $cutcharctr, 'discard'];
					} /////////////////////
					// 5) Break at Hard HYPHEN '-' or U+2010
					/////////////////////
					elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && ($prevchar == '-' || $prevchar == "\xe2\x80\x90")) {
						// Don't break a URL
						// Look back to get first part of current word
						$checkw = '';
						for ($ac = $charctr - 1; $ac >= 0; $ac--) {
							if ($this->usingCoreFont) {
								$addc = substr($currContent, $ac, 1);
							} else {
								$addc = mb_substr($currContent, $ac, 1, $this->mb_enc);
							}
							if ($addc == ' ') {
								break;
							}
							$checkw = $addc . $checkw;
						}
						// Don't break if HyphenMinus AND (a URL or before a numeral or before a >)
						if ((!preg_match('/(http:|ftp:|https:|www\.)/', $checkw) && $checkchar != '>' && !preg_match('/[0-9]/', $checkchar)) || $prevchar == "\xe2\x80\x90") {
							$breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
						}
					} /////////////////////
					// 6) Break at Soft HYPHEN (replace with hard hyphen)
					/////////////////////
					elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && !$this->usingCoreFont && $prevchar == "\xc2\xad") {
						$breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
						$content[$contentctr] = mb_substr($content[$contentctr], 0, $charctr, $this->mb_enc) . '-' . mb_substr($content[$contentctr], $charctr + 1, mb_strlen($content[$contentctr]), $this->mb_enc);
						if (!empty($cOTLdata[$contentctr])) {
							$cOTLdata[$contentctr]['char_data'][$charctr] = ['bidi_class' => 9, 'uni' => 45];
							$cOTLdata[$contentctr]['group'][$charctr] = 'C';
						}
					} elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats' && $prevchar == chr(173)) {
						$breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
						$content[$contentctr] = substr($content[$contentctr], 0, $charctr) . '-' . substr($content[$contentctr], $charctr + 1);
					} /* -- CJK-FONTS -- */
					/////////////////////
					// 7) Break at CJK characters (unless forbidden characters to end or start line)
					// CJK Avoiding line break in the middle of numerals
					/////////////////////
					elseif (!$this->usingCoreFont && $this->checkCJK && preg_match("/[" . $this->pregCJKchars . "]/u", $checkchar) &&
						!preg_match("/[" . $this->CJKfollowing . "]/u", $checkchar) && !preg_match("/[" . $this->CJKleading . "]/u", $prevchar) &&
						!(preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $prevchar) && preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $checkchar))) {
						$breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
					}
					/* -- END CJK-FONTS -- */
					/////////////////////
					// 8) Break at OBJECT (Break before all objects here - selected objects are moved forward to next line below e.g. dottab)
					/////////////////////
					if (isset($this->objectbuffer[$contentctr])) {
						$breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
					}


					$checkchar = $prevchar;
				}

				// If a line-break opportunity found:
				if (is_array($breakfound)) {
					$contentctr = $breakfound[0];
					$charctr = $breakfound[1];
					$cutcontentctr = $breakfound[2];
					$cutcharctr = $breakfound[3];
					$type = $breakfound[4];
					// Cache chunks which are already processed, but now need to be passed on to the new line
					for ($ix = count($content) - 1; $ix > $cutcontentctr; $ix--) {
						// save and crop off any subsequent chunks
						/* -- OTL -- */
						if (!empty($sOTLdata)) {
							$tmpOTL = array_pop($cOTLdata);
							$savedPreOTLdata[] = $tmpOTL;
						}
						/* -- END OTL -- */
						$savedPreContent[] = array_pop($content);
						$savedPreContentB[] = array_pop($contentB);
						$savedPreFont[] = array_pop($font);
					}

					// Next cache the part which will start the next line
					if ($this->usingCoreFont) {
						$savedPreContent[] = substr($content[$cutcontentctr], $cutcharctr);
					} else {
						$savedPreContent[] = mb_substr($content[$cutcontentctr], $cutcharctr, mb_strlen($content[$cutcontentctr]), $this->mb_enc);
					}
					$savedPreContentB[] = preg_replace('/L/', '', $contentB[$cutcontentctr]);
					$savedPreFont[] = $font[$cutcontentctr];
					/* -- OTL -- */
					if (!empty($sOTLdata)) {
						$savedPreOTLdata[] = $this->otl->splitOTLdata($cOTLdata[$cutcontentctr], $cutcharctr, $cutcharctr);
					}
					/* -- END OTL -- */


					// Finally adjust the Current content which ends this line
					if ($cutcharctr == 0 && $type == 'discard') {
						array_pop($content);
						array_pop($contentB);
						array_pop($font);
						array_pop($cOTLdata);
					}

					$currContent = & $content[count($content) - 1];
					if ($this->usingCoreFont) {
						$currContent = substr($currContent, 0, $charctr);
					} else {
						$currContent = mb_substr($currContent, 0, $charctr, $this->mb_enc);
					}

					if (!empty($sOTLdata)) {
						$savedPreOTLdata[] = $this->otl->splitOTLdata($cOTLdata[(count($cOTLdata) - 1)], mb_strlen($currContent, $this->mb_enc));
					}

					if (strpos($contentB[(count($contentB) - 1)], 'R') !== false) {   // ???
						$contentB[count($content) - 1] = preg_replace('/R/', '', $contentB[count($content) - 1]); // ???
					}

					if ($type == 'hyphen') {
						$currContent .= '-';
						if (!empty($cOTLdata[(count($cOTLdata) - 1)])) {
							$cOTLdata[(count($cOTLdata) - 1)]['char_data'][] = ['bidi_class' => 9, 'uni' => 45];
							$cOTLdata[(count($cOTLdata) - 1)]['group'] .= 'C';
						}
					}

					$savedContent = '';
					$savedContentB = '';
					$savedFont = [];
					$savedOTLdata = [];
				}
				// If no line-break opportunity found - split at current position
				// or - Next character ($c) is suitable to add as overhanging or squeezed punctuation, or Oikomi, as set above by:
				// 1) CJK Overflowing a) punctuation or b) Oikomi
				// in which case $breakfound==1 and NOT array

				if (!is_array($breakfound)) {
					$savedFont = $this->saveFont();
					if (!empty($sOTLdata)) {
						$savedOTLdata = $this->otl->splitOTLdata($cOTLdata[(count($cOTLdata) - 1)], mb_strlen($currContent, $this->mb_enc));
					}
				}

				if ($content[count($content) - 1] == '' && !isset($this->objectbuffer[count($content) - 1])) {
					array_pop($content);
					array_pop($contentB);
					array_pop($font);
					array_pop($cOTLdata);
					$currContent = & $content[count($content) - 1];
				}

				// Right Trim current content - including CJK space, and for OTLdata
				// incl. CJK - strip CJK space at end of line &#x3000; = \xe3\x80\x80 = CJK space
				$currContent = $currContent ? rtrim($currContent) : '';
				if ($this->checkCJK) {
					$currContent = preg_replace("/\xe3\x80\x80$/", '', $currContent);
				} // *CJK-FONTS*
				/* -- OTL -- */
				if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
					$this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], false, true); // NB also does U+3000
				}
				/* -- END OTL -- */


				// Selected OBJECTS are moved forward to next line, unless they come before a space or U+200B (type='discard')
				if (isset($this->objectbuffer[(count($content) - 1)]) && (!isset($type) || $type != 'discard')) {
					$objtype = $this->objectbuffer[(count($content) - 1)]['type'];
					if ($objtype == 'dottab' || $objtype == 'bookmark' || $objtype == 'indexentry' || $objtype == 'toc' || $objtype == 'annot') {
						$savedObj = array_pop($this->objectbuffer);
					}
				}


				// Decimal alignment (cancel if wraps to > 1 line)
				if ($is_table && substr($align, 0, 1) == 'D') {
					$align = substr($align, 2, 1);
				}

				$lineBox = [];

				$this->_setInlineBlockHeights($lineBox, $stackHeight, $content, $font, $is_table);

				// update $contentWidth since it has changed with cropping
				$contentWidth = 0;

				$inclCursive = false;
				foreach ($content as $k => $chunk) {
					if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
						// LIST MARKERS
						if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker']) {
							if ($this->objectbuffer[$k]['listmarkerposition'] != 'outside') {
								$contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * Mpdf::SCALE;
							}
						} else {
							$contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * Mpdf::SCALE;
						}
					} elseif (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
						$this->restoreFont($font[$k], false);
						if ($this->checkCJK && $k == count($content) - 1 && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $this->CJKforceend) {
							// force-end overhang
							$hanger = mb_substr($chunk, mb_strlen($chunk, $this->mb_enc) - 1, 1, $this->mb_enc);
							// Probably ought to do something with char_data and GPOS in cOTLdata...
							$content[$k] = $chunk = mb_substr($chunk, 0, mb_strlen($chunk, $this->mb_enc) - 1, $this->mb_enc);
						}

						// Soft Hyphens chr(173) + Replace NBSP with SPACE + Set inclcursive if includes CURSIVE TEXT
						if (!$this->usingCoreFont) {
							/* -- OTL -- */
							if ((isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) || !empty($sOTLdata)) {
								$this->otl->removeChar($chunk, $cOTLdata[$k], "\xc2\xad");
								$this->otl->replaceSpace($chunk, $cOTLdata[$k]); // NBSP -> space
								if (preg_match("/([" . $this->pregCURSchars . "])/u", $chunk)) {
									$inclCursive = true;
								}
								$content[$k] = $chunk;
							} /* -- END OTL -- */ else {  // *OTL*
								$content[$k] = $chunk = str_replace("\xc2\xad", '', $chunk);
								$content[$k] = $chunk = str_replace(chr(194) . chr(160), chr(32), $chunk);
							} // *OTL*
						} elseif ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
							$content[$k] = $chunk = str_replace(chr(173), '', $chunk);
							$content[$k] = $chunk = str_replace(chr(160), chr(32), $chunk);
						}

						$contentWidth += $this->GetStringWidth($chunk, true, (isset($cOTLdata[$k]) ? $cOTLdata[$k] : false), $this->textvar) * Mpdf::SCALE;  // mPDF 5.7.1
						if (!empty($this->spanborddet)) {
							if (isset($this->spanborddet['L']['w']) && strpos($contentB[$k], 'L') !== false) {
								$contentWidth += $this->spanborddet['L']['w'] * Mpdf::SCALE;
							}
							if (isset($this->spanborddet['R']['w']) && strpos($contentB[$k], 'R') !== false) {
								$contentWidth += $this->spanborddet['R']['w'] * Mpdf::SCALE;
							}
						}
					}
				}

				$lastfontreqstyle = (isset($font[count($font) - 1]['ReqFontStyle']) ? $font[count($font) - 1]['ReqFontStyle'] : '');
				$lastfontstyle = (isset($font[count($font) - 1]['style']) ? $font[count($font) - 1]['style'] : '');
				if ($blockdir == 'ltr' && strpos($lastfontreqstyle, "I") !== false && strpos($lastfontstyle, "I") === false) { // Artificial italic
					$lastitalic = $this->FontSize * 0.15 * Mpdf::SCALE;
				} else {
					$lastitalic = 0;
				}




				// NOW FORMAT THE LINE TO OUTPUT
				if (!$table_draft) {
					// DIRECTIONALITY RTL
					$chunkorder = range(0, count($content) - 1); // mPDF 5.7
					/* -- OTL -- */
					// mPDF 6
					if ($blockdir == 'rtl' || $this->biDirectional) {
						$this->otl->bidiReorder($chunkorder, $content, $cOTLdata, $blockdir);
						// From this point on, $content and $cOTLdata may contain more elements (and re-ordered) compared to
						// $this->objectbuffer and $font ($chunkorder contains the mapping)
					}

					/* -- END OTL -- */
					// Remove any XAdvance from OTL data at end of line
					foreach ($chunkorder as $aord => $k) {
						if (count($cOTLdata)) {
							$this->restoreFont($font[$k], false);
							// ...WriteFlowingBlock...
							if ($aord == count($chunkorder) - 1 && isset($cOTLdata[$aord]['group'])) { // Last chunk on line
								$nGPOS = strlen($cOTLdata[$aord]['group']) - 1; // Last character
								if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL']) || isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'])) {
									if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'])) {
										$w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
									} else {
										$w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
									}
									$w *= ($this->FontSize / 1000);
									$contentWidth -= $w * Mpdf::SCALE;
									$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = 0;
									$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = 0;
								}

								// If last character has an XPlacement set, adjust width calculation, and add to XAdvance to account for it
								if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'])) {
									$w = -$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
									$w *= ($this->FontSize / 1000);
									$contentWidth -= $w * Mpdf::SCALE;
									$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
									$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
								}
							}
						}
					}

					// JUSTIFICATION J
					$jcharspacing = 0;
					$jws = 0;
					$nb_carac = 0;
					$nb_spaces = 0;
					$jkashida = 0;
					// if it's justified, we need to find the char/word spacing (or if hanger $this->CJKforceend)
					if (($align == 'J' && !$CJKoverflow) || (($contentWidth + $lastitalic > $maxWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * 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
						// JUSTIFY J (Use character spacing)
						// WORD SPACING
						// mPDF 5.7
						foreach ($chunkorder as $aord => $k) {
							$chunk = isset($content[$aord]) ? $content[$aord] : '';
							if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
								$nb_carac += mb_strlen($chunk, $this->mb_enc);
								$nb_spaces += mb_substr_count($chunk, ' ', $this->mb_enc);
								// Use GPOS OTL
								if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) {
									if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) {
										$nb_carac -= substr_count($cOTLdata[$aord]['group'], 'M');
									}
								}
							} else {
								$nb_carac ++;
							} // mPDF 6 allow spacing for inline object
						}
						// GetJSpacing adds kashida spacing to GPOSinfo if appropriate for Font
						list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) )), $inclCursive, $cOTLdata);
					}

					// WORD SPACING
					$empty = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) );

					$empty -= ($jcharspacing * ($nb_carac - 1)); // mPDF 6 nb_carac MINUS 1
					$empty -= ($jws * $nb_spaces);
					$empty -= ($jkashida);
					$empty /= Mpdf::SCALE;

					$b = ''; // do not use borders
					// Get PAGEBREAK TO TEST for height including the top border/padding
					$check_h = max($this->divheight, $stackHeight);
					if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($this->blklvl > 0) && ($lineCount == 1) && (!$is_table)) {
						$check_h += ($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['border_top']['w']);
					}

					if ($this->ColActive && $check_h > ($this->PageBreakTrigger - $this->y0)) {
						$this->SetCol($this->NbCol - 1);
					}

					// PAGEBREAK
					// 'If' below used in order to fix "first-line of other page with justify on" bug
					if (!$is_table && ($this->y + $check_h) > $this->PageBreakTrigger and ! $this->InFooter and $this->AcceptPageBreak()) {
						$bak_x = $this->x; // Current X position
						// WORD SPACING
						$ws = $this->ws; // Word Spacing
						$charspacing = $this->charspacing; // Character Spacing
						$this->ResetSpacing();

						$this->AddPage($this->CurOrientation);

						$this->x = $bak_x;
						// Added to correct for OddEven Margins
						$currentx += $this->MarginCorrection;
						$this->x += $this->MarginCorrection;

						// WORD SPACING
						$this->SetSpacing($charspacing, $ws);
					}

					if ($this->kwt && !$is_table) { // mPDF 5.7+
						$this->printkwtbuffer();
						$this->kwt = false;
					}


					/* -- COLUMNS -- */
					// COLS
					// COLUMN CHANGE
					if ($this->CurrCol != $oldcolumn) {
						$currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
						$this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
						$oldcolumn = $this->CurrCol;
					}

					if ($this->ColActive && !$is_table) {
						$this->breakpoints[$this->CurrCol][] = $this->y;
					} // *COLUMNS*
					/* -- END COLUMNS -- */

					// TOP MARGIN
					if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($this->blk[$this->blklvl]['margin_top']) && ($lineCount == 1) && (!$is_table)) {
						$this->DivLn($this->blk[$this->blklvl]['margin_top'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']);
						if ($this->ColActive) {
							$this->breakpoints[$this->CurrCol][] = $this->y;
						} // *COLUMNS*
					}


					// Update y0 for top of block (used to paint border)
					if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 1) && (!$is_table)) {
						$this->blk[$this->blklvl]['y0'] = $this->y;
						$this->blk[$this->blklvl]['startpage'] = $this->page;
						if ($this->blk[$this->blklvl]['float']) {
							$this->blk[$this->blklvl]['float_start_y'] = $this->y;
						}
					}

					// TOP PADDING and BORDER spacing/fill
					if (($newblock) && ($blockstate == 1 || $blockstate == 3) && (($this->blk[$this->blklvl]['padding_top']) || ($this->blk[$this->blklvl]['border_top'])) && ($lineCount == 1) && (!$is_table)) {
						// $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
						$this->DivLn($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'], -3, true, false, 1);
						if ($this->ColActive) {
							$this->breakpoints[$this->CurrCol][] = $this->y;
						} // *COLUMNS*
					}

					$arraysize = count($chunkorder);

					$margins = ($this->cMarginL + $this->cMarginR) + ($ipaddingL + $ipaddingR + $fpaddingR + $fpaddingR );

					// PAINT BACKGROUND FOR THIS LINE
					if (!$is_table) {
						$this->DivLn($stackHeight, $this->blklvl, false);
					} // false -> don't advance y

					$this->x = $currentx + $this->cMarginL + $ipaddingL + $fpaddingL;
					if ($align == 'R') {
						$this->x += $empty;
					} elseif ($align == 'C') {
						$this->x += ($empty / 2);
					}

					// Paragraph INDENT
					if (isset($this->blk[$this->blklvl]['text_indent']) && ($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 1) && (!$is_table) && ($blockdir != 'rtl') && ($align != 'C')) {
						$ti = $this->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
						$this->x += $ti;
					}

					// BIDI magic_reverse moved upwards from here
					foreach ($chunkorder as $aord => $k) { // mPDF 5.7

						$chunk = isset($content[$aord]) ? $content[$aord] : '';

						if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
							$xadj = $this->x - $this->objectbuffer[$k]['OUTER-X'];
							$this->objectbuffer[$k]['OUTER-X'] += $xadj;
							$this->objectbuffer[$k]['BORDER-X'] += $xadj;
							$this->objectbuffer[$k]['INNER-X'] += $xadj;

							if ($this->objectbuffer[$k]['type'] == 'listmarker') {
								$this->objectbuffer[$k]['lineBox'] = $lineBox[-1]; // Block element details for glyph-origin
							}
							$yadj = $this->y - $this->objectbuffer[$k]['OUTER-Y'];
							if ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
								$this->objectbuffer[$k]['lineBox'] = $lineBox[$k]; // element details for glyph-origin
							}
							if ($this->objectbuffer[$k]['type'] != 'dottab') { // mPDF 6 DOTTAB
								$yadj += $lineBox[$k]['top'];
							}
							$this->objectbuffer[$k]['OUTER-Y'] += $yadj;
							$this->objectbuffer[$k]['BORDER-Y'] += $yadj;
							$this->objectbuffer[$k]['INNER-Y'] += $yadj;
						}

						$this->restoreFont($font[$k]);  // mPDF 5.7

						$this->SetSpacing(($this->fixedlSpacing * Mpdf::SCALE) + $jcharspacing, ($this->fixedlSpacing + $this->minwSpacing) * Mpdf::SCALE + $jws);
						// Now unset these values so they don't influence GetStringwidth below or in fn. Cell
						$this->fixedlSpacing = false;
						$this->minwSpacing = 0;

						$save_vis = $this->visibility;
						if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->textparam['visibility'] != $this->visibility) {
							$this->SetVisibility($this->textparam['visibility']);
						}
						// *********** SPAN BACKGROUND COLOR ***************** //
						if ($this->spanbgcolor) {
							$cor = $this->spanbgcolorarray;
							$this->SetFColor($cor);
							$save_fill = $fill;
							$spanfill = 1;
							$fill = 1;
						}
						if (!empty($this->spanborddet)) {
							if (strpos($contentB[$k], 'L') !== false) {
								$this->x += (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
							}
							if (strpos($contentB[$k], 'L') === false) {
								$this->spanborddet['L']['s'] = $this->spanborddet['L']['w'] = 0;
							}
							if (strpos($contentB[$k], 'R') === false) {
								$this->spanborddet['R']['s'] = $this->spanborddet['R']['w'] = 0;
							}
						}

						// WORD SPACING
						// StringWidth this time includes any kashida spacing
						$stringWidth = $this->GetStringWidth($chunk, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, true);

						$nch = mb_strlen($chunk, $this->mb_enc);
						// Use GPOS OTL
						if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) {
							if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) {
								$nch -= substr_count($cOTLdata[$aord]['group'], 'M');
							}
						}
						$stringWidth += ( $this->charspacing * $nch / Mpdf::SCALE );

						$stringWidth += ( $this->ws * mb_substr_count($chunk, ' ', $this->mb_enc) / Mpdf::SCALE );

						if (isset($this->objectbuffer[$k])) {
							// LIST MARKERS	// mPDF 6  Lists
							if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') {
								$stringWidth = 0;
							} else {
								$stringWidth = $this->objectbuffer[$k]['OUTER-WIDTH'];
							}
						}

						if ($stringWidth == 0) {
							$stringWidth = 0.000001;
						}

						if ($aord == $arraysize - 1) {
							$stringWidth -= ( $this->charspacing / Mpdf::SCALE );
							if ($this->checkCJK && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) {
								// force-end overhang
								$this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false));
								$this->Cell($this->GetStringWidth($hanger), $stackHeight, $hanger, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false));
							} else {
								$this->Cell($stringWidth, $stackHeight, $chunk, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // mono-style line or last part (skips line)
							}
						} else {
							$this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, 0, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // first or middle part
						}

						if (!empty($this->spanborddet)) {
							if (strpos($contentB[$k], 'R') !== false && $aord != $arraysize - 1) {
								$this->x += $this->spanborddet['R']['w'];
							}
						}
						// *********** SPAN BACKGROUND COLOR OFF - RESET BLOCK BGCOLOR ***************** //
						if (isset($spanfill) && $spanfill) {
							$fill = $save_fill;
							$spanfill = 0;
							if ($fill) {
								$this->SetFColor($bcor);
							}
						}
						if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->visibility != $save_vis) {
							$this->SetVisibility($save_vis);
						}
					}
				} elseif ($table_draft) {
					$this->y += $stackHeight;
				}

				if (!$is_table) {
					$this->maxPosR = max($this->maxPosR, ($this->w - $this->rMargin - $this->blk[$this->blklvl]['outer_right_margin']));
					$this->maxPosL = min($this->maxPosL, ($this->lMargin + $this->blk[$this->blklvl]['outer_left_margin']));
				}

				// move on to the next line, reset variables, tack on saved content and current char

				if (!$table_draft) {
					$this->printobjectbuffer($is_table, $blockdir);
				}
				$this->objectbuffer = [];


				/* -- CSS-IMAGE-FLOAT -- */
				// Update values if set to skipline
				if ($this->floatmargins) {
					$this->_advanceFloatMargins();
				}
				/* -- END CSS-IMAGE-FLOAT -- */

				// Reset lineheight
				$stackHeight = $this->divheight;
				$valign = 'M';

				$font = [];
				$content = [];
				$contentB = [];
				$cOTLdata = []; // mPDF 5.7.1
				$contentWidth = 0;
				if (!empty($savedObj)) {
					$this->objectbuffer[] = $savedObj;
					$font[] = $savedFont;
					$content[] = '';
					$contentB[] = '';
					$cOTLdata[] = []; // mPDF 5.7.1
					$contentWidth += $savedObj['OUTER-WIDTH'] * Mpdf::SCALE;
				}
				if (count($savedPreContent) > 0) {
					for ($ix = count($savedPreContent) - 1; $ix >= 0; $ix--) {
						$font[] = $savedPreFont[$ix];
						$content[] = $savedPreContent[$ix];
						$contentB[] = $savedPreContentB[$ix];
						if (!empty($sOTLdata)) {
							$cOTLdata[] = $savedPreOTLdata[$ix];
						}
						$this->restoreFont($savedPreFont[$ix]);
						$lbw = $rbw = 0; // Border widths
						if (!empty($this->spanborddet)) {
							$lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
							$rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
						}
						if ($ix > 0) {
							$contentWidth += $this->GetStringWidth($savedPreContent[$ix], true, (isset($savedPreOTLdata[$ix]) ? $savedPreOTLdata[$ix] : false), $this->textvar) * Mpdf::SCALE; // mPDF 5.7.1
							if (strpos($savedPreContentB[$ix], 'L') !== false) {
								$contentWidth += $lbw;
							}
							if (strpos($savedPreContentB[$ix], 'R') !== false) {
								$contentWidth += $rbw;
							}
						}
					}
					$savedPreContent = [];
					$savedPreContentB = [];
					$savedPreOTLdata = []; // mPDF 5.7.1
					$savedPreFont = [];
					$content[(count($content) - 1)] .= $c;
				} else {
					$font[] = $savedFont;
					$content[] = $savedContent . $c;
					$contentB[] = $savedContentB;
					$cOTLdata[] = $savedOTLdata; // mPDF 5.7.1
				}

				$currContent = & $content[(count($content) - 1)];
				$this->restoreFont($font[(count($font) - 1)]); // mPDF 6.0

				/* -- CJK-FONTS -- */
				// CJK - strip CJK space at start of line
				// &#x3000; = \xe3\x80\x80 = CJK space
				if ($this->checkCJK && $currContent == "\xe3\x80\x80") {
					$currContent = '';
					if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
						$this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], true, false); // left trim U+3000
					}
				}
				/* -- END CJK-FONTS -- */

				$lbw = $rbw = 0; // Border widths
				if (!empty($this->spanborddet)) {
					$lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
					$rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
				}

				$contentWidth += $this->GetStringWidth($currContent, false, (isset($cOTLdata[(count($cOTLdata) - 1)]) ? $cOTLdata[(count($cOTLdata) - 1)] : false), $this->textvar) * Mpdf::SCALE; // mPDF 5.7.1
				if (strpos($savedContentB, 'L') !== false) {
					$contentWidth += $lbw;
				}
				$CJKoverflow = false;
				$hanger = '';
			} // another character will fit, so add it on
			else {
				$contentWidth += $cw;
				$currContent .= $c;
			}
		}

		unset($content);
		unset($contentB);
	}

	// ----------------------END OF FLOWING BLOCK------------------------------------//


	/* -- CSS-IMAGE-FLOAT -- */
	// Update values if set to skipline
	function _advanceFloatMargins()
	{
		// Update floatmargins - L
		if (isset($this->floatmargins['L']) && $this->floatmargins['L']['skipline'] && $this->floatmargins['L']['y0'] != $this->y) {
			$yadj = $this->y - $this->floatmargins['L']['y0'];
			$this->floatmargins['L']['y0'] = $this->y;
			$this->floatmargins['L']['y1'] += $yadj;

			// Update objattr in floatbuffer
			if ($this->floatbuffer[$this->floatmargins['L']['id']]['border_left']['w']) {
				$this->floatbuffer[$this->floatmargins['L']['id']]['BORDER-Y'] += $yadj;
			}
			$this->floatbuffer[$this->floatmargins['L']['id']]['INNER-Y'] += $yadj;
			$this->floatbuffer[$this->floatmargins['L']['id']]['OUTER-Y'] += $yadj;

			// Unset values
			$this->floatbuffer[$this->floatmargins['L']['id']]['skipline'] = false;
			$this->floatmargins['L']['skipline'] = false;
			$this->floatmargins['L']['id'] = '';
		}
		// Update floatmargins - R
		if (isset($this->floatmargins['R']) && $this->floatmargins['R']['skipline'] && $this->floatmargins['R']['y0'] != $this->y) {
			$yadj = $this->y - $this->floatmargins['R']['y0'];
			$this->floatmargins['R']['y0'] = $this->y;
			$this->floatmargins['R']['y1'] += $yadj;

			// Update objattr in floatbuffer
			if ($this->floatbuffer[$this->floatmargins['R']['id']]['border_left']['w']) {
				$this->floatbuffer[$this->floatmargins['R']['id']]['BORDER-Y'] += $yadj;
			}
			$this->floatbuffer[$this->floatmargins['R']['id']]['INNER-Y'] += $yadj;
			$this->floatbuffer[$this->floatmargins['R']['id']]['OUTER-Y'] += $yadj;

			// Unset values
			$this->floatbuffer[$this->floatmargins['R']['id']]['skipline'] = false;
			$this->floatmargins['R']['skipline'] = false;
			$this->floatmargins['R']['id'] = '';
		}
	}

	/* -- END CSS-IMAGE-FLOAT -- */



	/* -- END HTML-CSS -- */

	function _SetTextRendering($mode)
	{
		if (!(($mode == 0) || ($mode == 1) || ($mode == 2))) {
			throw new \Mpdf\MpdfException("Text rendering mode should be 0, 1 or 2 (value : $mode)");
		}
		$tr = ($mode . ' Tr');
		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) {
			$this->writer->write($tr);
		}
		$this->pageoutput[$this->page]['TextRendering'] = $tr;
	}

	function SetTextOutline($params = [])
	{
		if (isset($params['outline-s']) && $params['outline-s']) {
			$this->SetLineWidth($params['outline-WIDTH']);
			$this->SetDColor($params['outline-COLOR']);
			$tr = ('2 Tr');
			if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) {
				$this->writer->write($tr);
			}
			$this->pageoutput[$this->page]['TextRendering'] = $tr;
		} else { // Now resets all values
			$this->SetLineWidth(0.2);
			$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
			$this->_SetTextRendering(0);
			$tr = ('0 Tr');
			if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) {
				$this->writer->write($tr);
			}
			$this->pageoutput[$this->page]['TextRendering'] = $tr;
		}
	}

	function Image($file, $x, $y, $w = 0, $h = 0, $type = '', $link = '', $paint = true, $constrain = true, $watermark = false, $shownoimg = true, $allowvector = true)
	{
		$orig_srcpath = $file;
		$this->GetFullPath($file);

		$info = $this->imageProcessor->getImage($file, true, $allowvector, $orig_srcpath);
		if (!$info && $paint) {
			$info = $this->imageProcessor->getImage($this->noImageFile);
			if ($info) {
				$file = $this->noImageFile;
				$w = ($info['w'] * (25.4 / $this->img_dpi));  // 14 x 16px
				$h = ($info['h'] * (25.4 / $this->img_dpi));  // 14 x 16px
			}
		}
		if (!$info) {
			return false;
		}
		// Automatic width and height calculation if needed
		if ($w == 0 and $h == 0) {
			/* -- IMAGES-WMF -- */
			if ($info['type'] === 'wmf') {
				// WMF units are twips (1/20pt)
				// divide by 20 to get points
				// divide by k to get user units
				$w = abs($info['w']) / (20 * Mpdf::SCALE);
				$h = abs($info['h']) / (20 * Mpdf::SCALE);
			} else { 			/* -- END IMAGES-WMF -- */
				if ($info['type'] === 'svg') {
					// returned SVG units are pts
					// divide by k to get user units (mm)
					$w = abs($info['w']) / Mpdf::SCALE;
					$h = abs($info['h']) / Mpdf::SCALE;
				} else {
					// Put image at default image dpi
					$w = ($info['w'] / Mpdf::SCALE) * (72 / $this->img_dpi);
					$h = ($info['h'] / Mpdf::SCALE) * (72 / $this->img_dpi);
				}
			}
		}
		if ($w == 0) {
			$w = abs($h * $info['w'] / $info['h']);
		}
		if ($h == 0) {
			$h = abs($w * $info['h'] / $info['w']);
		}

		/* -- WATERMARK -- */
		if ($watermark) {
			$maxw = $this->w;
			$maxh = $this->h;
			// Size = D PF or array
			if (is_array($this->watermark_size)) {
				$w = $this->watermark_size[0];
				$h = $this->watermark_size[1];
			} elseif (!is_string($this->watermark_size)) {
				$maxw -= $this->watermark_size * 2;
				$maxh -= $this->watermark_size * 2;
				$w = $maxw;
				$h = abs($w * $info['h'] / $info['w']);
				if ($h > $maxh) {
					$h = $maxh;
					$w = abs($h * $info['w'] / $info['h']);
				}
			} elseif ($this->watermark_size == 'F') {
				if ($this->ColActive) {
					$maxw = $this->w - ($this->DeflMargin + $this->DefrMargin);
				} else {
					$maxw = $this->pgwidth;
				}
				$maxh = $this->h - ($this->tMargin + $this->bMargin);
				$w = $maxw;
				$h = abs($w * $info['h'] / $info['w']);
				if ($h > $maxh) {
					$h = $maxh;
					$w = abs($h * $info['w'] / $info['h']);
				}
			} elseif ($this->watermark_size == 'P') { // Default P
				$w = $maxw;
				$h = abs($w * $info['h'] / $info['w']);
				if ($h > $maxh) {
					$h = $maxh;
					$w = abs($h * $info['w'] / $info['h']);
				}
			}
			// Automatically resize to maximum dimensions of page if too large
			if ($w > $maxw) {
				$w = $maxw;
				$h = abs($w * $info['h'] / $info['w']);
			}
			if ($h > $maxh) {
				$h = $maxh;
				$w = abs($h * $info['w'] / $info['h']);
			}
			// Position
			if (is_array($this->watermark_pos)) {
				$x = $this->watermark_pos[0];
				$y = $this->watermark_pos[1];
			} elseif ($this->watermark_pos == 'F') { // centred on printable area
				if ($this->ColActive) { // *COLUMNS*
					if (($this->mirrorMargins) && (($this->page) % 2 == 0)) {
						$xadj = $this->DeflMargin - $this->DefrMargin;
					} // *COLUMNS*
					else {
						$xadj = 0;
					} // *COLUMNS*
					$x = ($this->DeflMargin - $xadj + ($this->w - ($this->DeflMargin + $this->DefrMargin)) / 2) - ($w / 2); // *COLUMNS*
				} // *COLUMNS*
				else {  // *COLUMNS*
					$x = ($this->lMargin + ($this->pgwidth) / 2) - ($w / 2);
				} // *COLUMNS*
				$y = ($this->tMargin + ($this->h - ($this->tMargin + $this->bMargin)) / 2) - ($h / 2);
			} else { // default P - centred on whole page
				$x = ($this->w / 2) - ($w / 2);
				$y = ($this->h / 2) - ($h / 2);
			}
			/* -- IMAGES-WMF -- */
			if ($info['type'] == 'wmf') {
				$sx = $w * Mpdf::SCALE / $info['w'];
				$sy = -$h * Mpdf::SCALE / $info['h'];
				$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']);
			} else { 			/* -- END IMAGES-WMF -- */
				if ($info['type'] == 'svg') {
					$sx = $w * Mpdf::SCALE / $info['w'];
					$sy = -$h * Mpdf::SCALE / $info['h'];
					$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']);
				} else {
					$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']);
				}
			}

			if ($this->watermarkImgBehind) {
				$outstring = $this->watermarkImgAlpha . "\n" . $outstring . "\n" . $this->SetAlpha(1, 'Normal', true) . "\n";
				$this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', "\n" . $outstring . "\n" . '\\1', $this->pages[$this->page]);
			} else {
				$this->writer->write($outstring);
			}

			return 0;
		} // end of IF watermark
		/* -- END WATERMARK -- */

		if ($constrain) {
			// Automatically resize to maximum dimensions of page if too large
			if (isset($this->blk[$this->blklvl]['inner_width']) && $this->blk[$this->blklvl]['inner_width']) {
				$maxw = $this->blk[$this->blklvl]['inner_width'];
			} else {
				$maxw = $this->pgwidth;
			}
			if ($w > $maxw) {
				$w = $maxw;
				$h = abs($w * $info['h'] / $info['w']);
			}
			if ($h > $this->h - ($this->tMargin + $this->bMargin + 1)) {  // see below - +10 to avoid drawing too close to border of page
				$h = $this->h - ($this->tMargin + $this->bMargin + 1);
				if ($this->fullImageHeight) {
					$h = $this->fullImageHeight;
				}
				$w = abs($h * $info['w'] / $info['h']);
			}


			// Avoid drawing out of the paper(exceeding width limits).
			// if ( ($x + $w) > $this->fw ) {
			if (($x + $w) > $this->w) {
				$x = $this->lMargin;
				$y += 5;
			}

			$changedpage = false;
			$oldcolumn = $this->CurrCol;
			// Avoid drawing out of the page.
			if ($y + $h > $this->PageBreakTrigger and ! $this->InFooter and $this->AcceptPageBreak()) {
				$this->AddPage($this->CurOrientation);
				// Added to correct for OddEven Margins
				$x = $x + $this->MarginCorrection;
				$y = $this->tMargin; // mPDF 5.7.3
				$changedpage = true;
			}
			/* -- COLUMNS -- */
			// COLS
			// COLUMN CHANGE
			if ($this->CurrCol != $oldcolumn) {
				$y = $this->y0;
				$x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
				$this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
			}
			/* -- END COLUMNS -- */
		} // end of IF constrain

		/* -- IMAGES-WMF -- */
		if ($info['type'] == 'wmf') {
			$sx = $w * Mpdf::SCALE / $info['w'];
			$sy = -$h * Mpdf::SCALE / $info['h'];
			$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']);
		} else { 		/* -- END IMAGES-WMF -- */
			if ($info['type'] == 'svg') {
				$sx = $w * Mpdf::SCALE / $info['w'];
				$sy = -$h * Mpdf::SCALE / $info['h'];
				$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']);
			} else {
				$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']);
			}
		}

		if ($paint) {
			$this->writer->write($outstring);
			if ($link) {
				$this->Link($x, $y, $w, $h, $link);
			}

			// Avoid writing text on top of the image. // THIS WAS OUTSIDE THE if ($paint) bit!!!!!!!!!!!!!!!!
			$this->y = $y + $h;
		}

		// Return width-height array
		$sizesarray['WIDTH'] = $w;
		$sizesarray['HEIGHT'] = $h;
		$sizesarray['X'] = $x; // Position before painting image
		$sizesarray['Y'] = $y; // Position before painting image
		$sizesarray['OUTPUT'] = $outstring;

		$sizesarray['IMAGE_ID'] = $info['i'];
		$sizesarray['itype'] = $info['type'];
		$sizesarray['set-dpi'] = (isset($info['set-dpi']) ? $info['set-dpi'] : 0);
		return $sizesarray;
	}

	// =============================================================
	// =============================================================
	// =============================================================
	// =============================================================
	// =============================================================
	/* -- HTML-CSS -- */

	function _getObjAttr($t)
	{
		$c = explode("\xbb\xa4\xac", $t, 2);
		$c = explode(",", $c[1], 2);
		foreach ($c as $v) {
			$v = explode("=", $v, 2);
			$sp[$v[0]] = $v[1];
		}
		return (unserialize($sp['objattr']));
	}

	function inlineObject($type, $x, $y, $objattr, $Lmargin, $widthUsed, $maxWidth, $lineHeight, $paint = false, $is_table = false)
	{
		if ($is_table) {
			$k = $this->shrin_k;
		} else {
			$k = 1;
		}

		// NB $x is only used when paint=true
		// Lmargin not used
		$w = 0;
		if (isset($objattr['width'])) {
			$w = $objattr['width'] / $k;
		}
		$h = 0;
		if (isset($objattr['height'])) {
			$h = abs($objattr['height'] / $k);
		}
		$widthLeft = $maxWidth - $widthUsed;
		$maxHeight = $this->h - ($this->tMargin + $this->bMargin + 10);
		if ($this->fullImageHeight) {
			$maxHeight = $this->fullImageHeight;
		}
		// For Images
		if (isset($objattr['border_left'])) {
			$extraWidth = ($objattr['border_left']['w'] + $objattr['border_right']['w'] + $objattr['margin_left'] + $objattr['margin_right']) / $k;
			$extraHeight = ($objattr['border_top']['w'] + $objattr['border_bottom']['w'] + $objattr['margin_top'] + $objattr['margin_bottom']) / $k;

			if ($type == 'image' || $type == 'barcode' || $type == 'textcircle') {
				$extraWidth += ($objattr['padding_left'] + $objattr['padding_right']) / $k;
				$extraHeight += ($objattr['padding_top'] + $objattr['padding_bottom']) / $k;
			}
		}

		if (!isset($objattr['vertical-align'])) {
			if ($objattr['type'] == 'select') {
				$objattr['vertical-align'] = 'M';
			} else {
				$objattr['vertical-align'] = 'BS';
			}
		} // mPDF 6

		if ($type == 'image' || (isset($objattr['subtype']) && $objattr['subtype'] == 'IMAGE')) {
			if (isset($objattr['itype']) && ($objattr['itype'] == 'wmf' || $objattr['itype'] == 'svg')) {
				$file = $objattr['file'];
				$info = $this->formobjects[$file];
			} elseif (isset($objattr['file'])) {
				$file = $objattr['file'];
				$info = $this->images[$file];
			}
		}
		if ($type == 'annot' || $type == 'bookmark' || $type == 'indexentry' || $type == 'toc') {
			$w = 0.00001;
			$h = 0.00001;
		}

		// TEST whether need to skipline
		if (!$paint) {
			if ($type == 'hr') { // always force new line
				if (($y + $h + $lineHeight > $this->PageBreakTrigger) && !$this->InFooter && !$is_table) {
					return [-2, $w, $h];
				} // New page + new line
				else {
					return [1, $w, $h];
				} // new line
			} else {
				// LIST MARKERS	// mPDF 6  Lists
				$displayheight = $h;
				$displaywidth = $w;
				if ($objattr['type'] == 'image' && isset($objattr['listmarker']) && $objattr['listmarker']) {
					$displayheight = 0;
					if ($objattr['listmarkerposition'] == 'outside') {
						$displaywidth = 0;
					}
				}

				if ($widthUsed > 0 && $displaywidth > $widthLeft && (!$is_table || $type != 'image')) {  // New line needed
					// mPDF 6  Lists
					if (($y + $displayheight + $lineHeight > $this->PageBreakTrigger) && !$this->InFooter) {
						return [-2, $w, $h];
					} // New page + new line
					return [1, $w, $h]; // new line
				} elseif ($widthUsed > 0 && $displaywidth > $widthLeft && $is_table) {  // New line needed in TABLE
					return [1, $w, $h]; // new line
				} // Will fit on line but NEW PAGE REQUIRED
				elseif (($y + $displayheight > $this->PageBreakTrigger) && !$this->InFooter && !$is_table) {
					return [-1, $w, $h];
				} // mPDF 6  Lists
				else {
					return [0, $w, $h];
				}
			}
		}

		if ($type == 'annot' || $type == 'bookmark' || $type == 'indexentry' || $type == 'toc') {
			$w = 0.00001;
			$h = 0.00001;
			$objattr['BORDER-WIDTH'] = 0;
			$objattr['BORDER-HEIGHT'] = 0;
			$objattr['BORDER-X'] = $x;
			$objattr['BORDER-Y'] = $y;
			$objattr['INNER-WIDTH'] = 0;
			$objattr['INNER-HEIGHT'] = 0;
			$objattr['INNER-X'] = $x;
			$objattr['INNER-Y'] = $y;
		}

		if ($type == 'image') {
			// Automatically resize to width remaining
			if ($w > ($widthLeft + 0.0001) && !$is_table) { // mPDF 5.7.4  0.0001 to allow for rounding errors when w==maxWidth
				$w = $widthLeft;
				$h = abs($w * $info['h'] / $info['w']);
			}
			$img_w = $w - $extraWidth;
			$img_h = $h - $extraHeight;

			$objattr['BORDER-WIDTH'] = $img_w + $objattr['padding_left'] / $k + $objattr['padding_right'] / $k + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2);
			$objattr['BORDER-HEIGHT'] = $img_h + $objattr['padding_top'] / $k + $objattr['padding_bottom'] / $k + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2);
			$objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2);
			$objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2);
			$objattr['INNER-WIDTH'] = $img_w;
			$objattr['INNER-HEIGHT'] = $img_h;
			$objattr['INNER-X'] = $x + $objattr['padding_left'] / $k + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k);
			$objattr['INNER-Y'] = $y + $objattr['padding_top'] / $k + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k);
			$objattr['ID'] = $info['i'];
		}

		if ($type == 'input' && $objattr['subtype'] == 'IMAGE') {
			$img_w = $w - $extraWidth;
			$img_h = $h - $extraHeight;
			$objattr['BORDER-WIDTH'] = $img_w + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2);
			$objattr['BORDER-HEIGHT'] = $img_h + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2);
			$objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2);
			$objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2);
			$objattr['INNER-WIDTH'] = $img_w;
			$objattr['INNER-HEIGHT'] = $img_h;
			$objattr['INNER-X'] = $x + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k);
			$objattr['INNER-Y'] = $y + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k);
			$objattr['ID'] = $info['i'];
		}

		if ($type == 'barcode' || $type == 'textcircle') {
			$b_w = $w - $extraWidth;
			$b_h = $h - $extraHeight;
			$objattr['BORDER-WIDTH'] = $b_w + $objattr['padding_left'] / $k + $objattr['padding_right'] / $k + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2);
			$objattr['BORDER-HEIGHT'] = $b_h + $objattr['padding_top'] / $k + $objattr['padding_bottom'] / $k + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2);
			$objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2);
			$objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2);
			$objattr['INNER-X'] = $x + $objattr['padding_left'] / $k + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k);
			$objattr['INNER-Y'] = $y + $objattr['padding_top'] / $k + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k);
			$objattr['INNER-WIDTH'] = $b_w;
			$objattr['INNER-HEIGHT'] = $b_h;
		}


		if ($type == 'textarea') {
			// Automatically resize to width remaining
			if ($w > $widthLeft && !$is_table) {
				$w = $widthLeft;
			}
			// This used to resize height to maximum remaining on page ? why. Causes problems when in table and causing a new column
			// if (($y + $h > $this->PageBreakTrigger) && !$this->InFooter) {
			// 	$h=$this->h - $y - $this->bMargin;
			// }
		}

		if ($type == 'hr') {
			if ($is_table) {
				$objattr['INNER-WIDTH'] = $maxWidth * $objattr['W-PERCENT'] / 100;
				$objattr['width'] = $objattr['INNER-WIDTH'];
				$w = $maxWidth;
			} else {
				if ($w > $maxWidth) {
					$w = $maxWidth;
				}
				$objattr['INNER-WIDTH'] = $w;
				$w = $maxWidth;
			}
		}



		if (($type == 'select') || ($type == 'input' && ($objattr['subtype'] == 'TEXT' || $objattr['subtype'] == 'PASSWORD'))) {
			// Automatically resize to width remaining
			if ($w > $widthLeft && !$is_table) {
				$w = $widthLeft;
			}
		}

		if ($type == 'textarea' || $type == 'select' || $type == 'input') {
			if (isset($objattr['fontsize'])) {
				$objattr['fontsize'] /= $k;
			}
			if (isset($objattr['linewidth'])) {
				$objattr['linewidth'] /= $k;
			}
		}

		if (!isset($objattr['BORDER-Y'])) {
			$objattr['BORDER-Y'] = 0;
		}
		if (!isset($objattr['BORDER-X'])) {
			$objattr['BORDER-X'] = 0;
		}
		if (!isset($objattr['INNER-Y'])) {
			$objattr['INNER-Y'] = 0;
		}
		if (!isset($objattr['INNER-X'])) {
			$objattr['INNER-X'] = 0;
		}

		// Return width-height array
		$objattr['OUTER-WIDTH'] = $w;
		$objattr['OUTER-HEIGHT'] = $h;
		$objattr['OUTER-X'] = $x;
		$objattr['OUTER-Y'] = $y;
		return $objattr;
	}

	/* -- END HTML-CSS -- */

	// =============================================================
	// =============================================================
	// =============================================================
	// =============================================================
	// =============================================================

	function SetLineJoin($mode = 0)
	{
		$s = sprintf('%d j', $mode);
		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineJoin']) && $this->pageoutput[$this->page]['LineJoin'] != $s) || !isset($this->pageoutput[$this->page]['LineJoin']))) {
			$this->writer->write($s);
		}
		$this->pageoutput[$this->page]['LineJoin'] = $s;
	}

	function SetLineCap($mode = 2)
	{
		$s = sprintf('%d J', $mode);
		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineCap']) && $this->pageoutput[$this->page]['LineCap'] != $s) || !isset($this->pageoutput[$this->page]['LineCap']))) {
			$this->writer->write($s);
		}
		$this->pageoutput[$this->page]['LineCap'] = $s;
	}

	function SetDash($black = false, $white = false)
	{
		if ($black and $white) {
			$s = sprintf('[%.3F %.3F] 0 d', $black * Mpdf::SCALE, $white * Mpdf::SCALE);
		} else {
			$s = '[] 0 d';
		}

		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Dash']) && $this->pageoutput[$this->page]['Dash'] != $s) || !isset($this->pageoutput[$this->page]['Dash']))) {
			$this->writer->write($s);
		}

		$this->pageoutput[$this->page]['Dash'] = $s;
	}

	function SetDisplayPreferences($preferences)
	{
		// String containing any or none of /HideMenubar/HideToolbar/HideWindowUI/DisplayDocTitle/CenterWindow/FitWindow

		$this->DisplayPreferences .= $preferences;
	}

	function Ln($h = '', $collapsible = 0)
	{
		// Added collapsible to allow collapsible top-margin on new page
		// Line feed; default value is last cell height

		$margin = isset($this->blk[$this->blklvl]['outer_left_margin']) ? $this->blk[$this->blklvl]['outer_left_margin'] : 0;

		$this->x = $this->lMargin + $margin;

		if ($collapsible && ($this->y == $this->tMargin) && (!$this->ColActive)) {
			$h = 0;
		}

		if (is_string($h)) {
			$this->y += $this->lasth;
		} else {
			$this->y += $h;
		}
	}

	/* -- HTML-CSS -- */

	function DivLn($h, $level = -3, $move_y = true, $collapsible = false, $state = 0)
	{
		// $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
		// Used in Columns and keep-with-table i.e. "kwt"
		// writes background block by block so it can be repositioned
		// and also used in writingFlowingBlock at top and bottom of blocks to move y (not to draw/paint anything)
		// adds lines (y) where DIV bgcolors are filled in
		// this->x is returned as it was
		// allows .00001 as nominal height used for bookmarks/annotations etc.
		if ($collapsible && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->tMargin)) && (!$this->ColActive)) {
			return;
		}

		// mPDF 6 Columns
		//   if ($collapsible && (sprintf("%0.4f", $this->y)==sprintf("%0.4f", $this->y0)) && ($this->ColActive) && $this->CurrCol == 0) { return; }	// *COLUMNS*
		if ($collapsible && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->y0)) && ($this->ColActive)) {
			return;
		} // *COLUMNS*
		// Still use this method if columns or keep-with-table, as it allows repositioning later
		// otherwise, now uses PaintDivBB()
		if (!$this->ColActive && !$this->kwt) {
			if ($move_y && !$this->ColActive) {
				$this->y += $h;
			}
			return;
		}

		if ($level == -3) {
			$level = $this->blklvl;
		}
		$firstblockfill = $this->GetFirstBlockFill();
		if ($firstblockfill && $this->blklvl > 0 && $this->blklvl >= $firstblockfill) {
			$last_x = 0;
			$last_w = 0;
			$last_fc = $this->FillColor;
			$bak_x = $this->x;
			$bak_h = $this->divheight;
			$this->divheight = 0; // Temporarily turn off divheight - as Cell() uses it to check for PageBreak
			for ($blvl = $firstblockfill; $blvl <= $level; $blvl++) {
				$this->x = $this->lMargin + $this->blk[$blvl]['outer_left_margin'];
				// mPDF 6
				if ($this->blk[$blvl]['bgcolor']) {
					$this->SetFColor($this->blk[$blvl]['bgcolorarray']);
				}
				if ($last_x != ($this->lMargin + $this->blk[$blvl]['outer_left_margin']) || ($last_w != $this->blk[$blvl]['width']) || $last_fc != $this->FillColor || (isset($this->blk[$blvl]['border_top']['s']) && $this->blk[$blvl]['border_top']['s']) || (isset($this->blk[$blvl]['border_bottom']['s']) && $this->blk[$blvl]['border_bottom']['s']) || (isset($this->blk[$blvl]['border_left']['s']) && $this->blk[$blvl]['border_left']['s']) || (isset($this->blk[$blvl]['border_right']['s']) && $this->blk[$blvl]['border_right']['s'])) {
					$x = $this->x;
					$this->Cell(($this->blk[$blvl]['width']), $h, '', '', 0, '', 1);
					$this->x = $x;
					if (!$this->keep_block_together && !$this->writingHTMLheader && !$this->writingHTMLfooter) {
						// $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
						if ($blvl == $this->blklvl) {
							$this->PaintDivLnBorder($state, $blvl, $h);
						} else {
							$this->PaintDivLnBorder(0, $blvl, $h);
						}
					}
				}
				$last_x = $this->lMargin + $this->blk[$blvl]['outer_left_margin'];
				$last_w = $this->blk[$blvl]['width'];
				$last_fc = $this->FillColor;
			}
			// Reset current block fill
			if (isset($this->blk[$this->blklvl]['bgcolorarray'])) {
				$bcor = $this->blk[$this->blklvl]['bgcolorarray'];
				$this->SetFColor($bcor);
			}
			$this->x = $bak_x;
			$this->divheight = $bak_h;
		}
		if ($move_y) {
			$this->y += $h;
		}
	}

	/* -- END HTML-CSS -- */

	function SetX($x)
	{
		// Set x position
		if ($x >= 0) {
			$this->x = $x;
		} else {
			$this->x = $this->w + $x;
		}
	}

	function SetY($y)
	{
		// Set y position and reset x
		$this->x = $this->lMargin;
		if ($y >= 0) {
			$this->y = $y;
		} else {
			$this->y = $this->h + $y;
		}
	}

	function SetXY($x, $y)
	{
		// Set x and y positions
		$this->SetY($y);
		$this->SetX($x);
	}

	function Output($name = '', $dest = '')
	{
		$this->logger->debug(sprintf('PDF generated in %.6F seconds', microtime(true) - $this->time0), ['context' => LogContext::STATISTICS]);

		// Finish document if necessary
		if ($this->state < 3) {
			$this->Close();
		}

		if ($this->debug && error_get_last()) {
			$e = error_get_last();
			if (($e['type'] < 2048 && $e['type'] != 8) || (intval($e['type']) & intval(ini_get("error_reporting")))) {
				throw new \Mpdf\MpdfException(
					sprintf('Error detected. PDF file generation aborted: %s', $e['message']),
					$e['type'],
					1,
					$e['file'],
					$e['line']
				);
			}
		}

		if (($this->PDFA || $this->PDFX) && $this->encrypted) {
			throw new \Mpdf\MpdfException('PDF/A1-b or PDF/X1-a does not permit encryption of documents.');
		}

		if (count($this->PDFAXwarnings) && (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto))) {
			if ($this->PDFA) {
				$standard = 'PDFA/1-b';
				$option = '$mpdf->PDFAauto';
			} else {
				$standard = 'PDFX/1-a ';
				$option = '$mpdf->PDFXauto';
			}

			$this->logger->warning(sprintf('PDF could not be generated as it stands as a %s compliant file.', $standard), ['context' => LogContext::PDFA_PDFX]);
			$this->logger->warning(sprintf('These issues can be automatically fixed by mPDF using %s = true;', $option), ['context' => LogContext::PDFA_PDFX]);
			$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]);

			$this->PDFAXwarnings = array_unique($this->PDFAXwarnings);
			foreach ($this->PDFAXwarnings as $w) {
				$this->logger->warning($w, ['context' => LogContext::PDFA_PDFX]);
			}

			throw new \Mpdf\MpdfException('PDFA/PDFX warnings generated. See log for further details');
		}

		$this->logger->debug(sprintf('Compiled in %.6F seconds', microtime(true) - $this->time0), ['context' => LogContext::STATISTICS]);
		$this->logger->debug(sprintf('Peak Memory usage %s MB', number_format(memory_get_peak_usage(true) / (1024 * 1024), 2)), ['context' => LogContext::STATISTICS]);
		$this->logger->debug(sprintf('PDF file size %s kB', number_format(strlen($this->buffer) / 1024)), ['context' => LogContext::STATISTICS]);
		$this->logger->debug(sprintf('%d fonts used', count($this->fonts)), ['context' => LogContext::STATISTICS]);

		if (is_bool($dest)) {
			$dest = $dest ? Destination::DOWNLOAD : Destination::FILE;
		}

		$dest = strtoupper($dest);
		if (empty($dest)) {
			if (empty($name)) {
				$name = 'mpdf.pdf';
				$dest = Destination::INLINE;
			} else {
				$dest = Destination::FILE;
			}
		}

		switch ($dest) {

			case Destination::INLINE:

				if (headers_sent($filename, $line)) {
					throw new \Mpdf\MpdfException(
						sprintf('Data has already been sent to output (%s at line %s), unable to output PDF file', $filename, $line)
					);
				}

				if ($this->debug && !$this->allow_output_buffering && ob_get_contents()) {
					throw new \Mpdf\MpdfException('Output has already been sent from the script - PDF file generation aborted.');
				}

				// We send to a browser
				if (PHP_SAPI !== 'cli') {
					header('Content-Type: application/pdf');

					if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) || empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
						// don't use length if server using compression
						header('Content-Length: ' . strlen($this->buffer));
					}

					header('Content-disposition: inline; filename="' . $name . '"');
					header('Cache-Control: public, must-revalidate, max-age=0');
					header('Pragma: public');
					header('X-Generator: mPDF' . ($this->exposeVersion ? (' ' . static::VERSION) : ''));
					header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
					header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
				}

				echo $this->buffer;

				break;

			case Destination::DOWNLOAD:

				if (headers_sent()) {
					throw new \Mpdf\MpdfException('Data has already been sent to output, unable to output PDF file');
				}

				header('Content-Description: File Transfer');
				header('Content-Transfer-Encoding: binary');
				header('Cache-Control: public, must-revalidate, max-age=0');
				header('Pragma: public');
				header('X-Generator: mPDF' . ($this->exposeVersion ? (' ' . static::VERSION) : ''));
				header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
				header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
				header('Content-Type: application/pdf');

				if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) || empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
					// don't use length if server using compression
					header('Content-Length: ' . strlen($this->buffer));
				}

				header('Content-Disposition: attachment; filename="' . $name . '"');

				echo $this->buffer;

				break;

			case Destination::FILE:
				$f = fopen($name, 'wb');

				if (!$f) {
					throw new \Mpdf\MpdfException(sprintf('Unable to create output file %s', $name));
				}

				fwrite($f, $this->buffer, strlen($this->buffer));
				fclose($f);

				break;

			case Destination::STRING_RETURN:
				$this->cache->clearOld();
				return $this->buffer;

			default:
				throw new \Mpdf\MpdfException(sprintf('Incorrect output destination %s', $dest));
		}

		$this->cache->clearOld();
	}

	public function OutputBinaryData()
	{
		return $this->Output(null, Destination::STRING_RETURN);
	}

	public function OutputHttpInline()
	{
		return $this->Output(null, Destination::INLINE);
	}

	/**
	 * @param string $fileName
	 */
	public function OutputHttpDownload($fileName)
	{
		return $this->Output($fileName, Destination::DOWNLOAD);
	}

	/**
	 * @param string $fileName
	 */
	public function OutputFile($fileName)
	{
		return $this->Output($fileName, Destination::FILE);
	}

	// *****************************************************************************
	//                                                                             *
	//                             Protected methods                               *
	//                                                                             *
	// *****************************************************************************
	function _dochecks()
	{
		// Check for locale-related bug
		if (1.1 == 1) {
			throw new \Mpdf\MpdfException('Do not alter the locale before including mPDF');
		}

		// Check for decimal separator
		if (sprintf('%.1f', 1.0) != '1.0') {
			setlocale(LC_NUMERIC, 'C');
		}

		if (ini_get('mbstring.func_overload')) {
			throw new \Mpdf\MpdfException('Mpdf cannot function properly with mbstring.func_overload enabled');
		}

		if (!function_exists('mb_substr')) {
			throw new \Mpdf\MpdfException('mbstring extension must be loaded in order to run mPDF');
		}

		if (!function_exists('mb_regex_encoding')) {
			$mamp = '';
			if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
				$mamp = ' If using MAMP, there is a bug in its PHP build causing this.';
			}

			throw new \Mpdf\MpdfException('mbstring extension with mbregex support must be loaded in order to run mPDF.' . $mamp);
		}
	}

	function _puthtmlheaders()
	{
		$this->state = 2;
		$nb = $this->page;
		for ($n = 1; $n <= $nb; $n++) {
			if ($this->mirrorMargins && $n % 2 == 0) {
				$OE = 'E';
			} // EVEN
			else {
				$OE = 'O';
			}
			$this->page = $n;
			$pn = $this->docPageNum($n);
			if ($pn) {
				$pnstr = $this->pagenumPrefix . $pn . $this->pagenumSuffix;
			} else {
				$pnstr = '';
			}

			$pnt = $this->docPageNumTotal($n);

			if ($pnt) {
				$pntstr = $this->nbpgPrefix . $pnt . $this->nbpgSuffix;
			} else {
				$pntstr = '';
			}

			if (isset($this->saveHTMLHeader[$n][$OE])) {
				$html = isset($this->saveHTMLHeader[$n][$OE]['html']) ? $this->saveHTMLHeader[$n][$OE]['html'] : '';
				$this->lMargin = $this->saveHTMLHeader[$n][$OE]['ml'];
				$this->rMargin = $this->saveHTMLHeader[$n][$OE]['mr'];
				$this->tMargin = $this->saveHTMLHeader[$n][$OE]['mh'];
				$this->bMargin = $this->saveHTMLHeader[$n][$OE]['mf'];
				$this->margin_header = $this->saveHTMLHeader[$n][$OE]['mh'];
				$this->margin_footer = $this->saveHTMLHeader[$n][$OE]['mf'];
				$this->w = $this->saveHTMLHeader[$n][$OE]['pw'];
				$this->h = $this->saveHTMLHeader[$n][$OE]['ph'];
				$rotate = (isset($this->saveHTMLHeader[$n][$OE]['rotate']) ? $this->saveHTMLHeader[$n][$OE]['rotate'] : null);
				$this->Reset();
				$this->pageoutput[$n] = [];
				$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
				$this->x = $this->lMargin;
				$this->y = $this->margin_header;

				// Replace of page number aliases and date format
				$html = $this->aliasReplace($html, $pnstr, $pntstr, $nb);

				$this->HTMLheaderPageLinks = [];
				$this->HTMLheaderPageAnnots = [];
				$this->HTMLheaderPageForms = [];
				$this->pageBackgrounds = [];

				$this->writingHTMLheader = true;
				$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
				$this->writingHTMLheader = false;
				$this->Reset();
				$this->pageoutput[$n] = [];

				$s = $this->PrintPageBackgrounds();
				$this->headerbuffer = $s . $this->headerbuffer;
				$os = '';
				if ($rotate) {
					$os .= sprintf('q 0 -1 1 0 0 %.3F cm ', ($this->w * Mpdf::SCALE));
					// To rotate the other way i.e. Header to left of page:
					// $os .= sprintf('q 0 1 -1 0 %.3F %.3F cm ',($this->h*Mpdf::SCALE), (($this->rMargin - $this->lMargin )*Mpdf::SCALE));
				}
				$os .= $this->headerbuffer;
				if ($rotate) {
					$os .= ' Q' . "\n";
				}

				// Writes over the page background but behind any other output on page
				$os = preg_replace(['/\\\\/', '/\$/'], ['\\\\\\\\', '\\\\$'], $os);

				$this->pages[$n] = preg_replace('/(___HEADER___MARKER' . $this->uniqstr . ')/', "\n" . $os . "\n" . '\\1', $this->pages[$n]);

				$lks = $this->HTMLheaderPageLinks;
				foreach ($lks as $lk) {
					if ($rotate) {
						$lw = $lk[2];
						$lh = $lk[3];
						$lk[2] = $lh;
						$lk[3] = $lw; // swap width and height
						$ax = $lk[0] / Mpdf::SCALE;
						$ay = $lk[1] / Mpdf::SCALE;
						$bx = $ay - ($lh / Mpdf::SCALE);
						$by = $this->w - $ax;
						$lk[0] = $bx * Mpdf::SCALE;
						$lk[1] = ($this->h - $by) * Mpdf::SCALE - $lw;
					}
					$this->PageLinks[$n][] = $lk;
				}
				/* -- FORMS -- */
				foreach ($this->HTMLheaderPageForms as $f) {
					$this->form->forms[$f['n']] = $f;
				}
				/* -- END FORMS -- */
			}

			if (isset($this->saveHTMLFooter[$n][$OE])) {

				$html = $this->saveHTMLFooter[$this->page][$OE]['html'];

				$this->lMargin = $this->saveHTMLFooter[$n][$OE]['ml'];
				$this->rMargin = $this->saveHTMLFooter[$n][$OE]['mr'];
				$this->tMargin = $this->saveHTMLFooter[$n][$OE]['mh'];
				$this->bMargin = $this->saveHTMLFooter[$n][$OE]['mf'];
				$this->margin_header = $this->saveHTMLFooter[$n][$OE]['mh'];
				$this->margin_footer = $this->saveHTMLFooter[$n][$OE]['mf'];
				$this->w = $this->saveHTMLFooter[$n][$OE]['pw'];
				$this->h = $this->saveHTMLFooter[$n][$OE]['ph'];
				$rotate = (isset($this->saveHTMLFooter[$n][$OE]['rotate']) ? $this->saveHTMLFooter[$n][$OE]['rotate'] : null);
				$this->Reset();
				$this->pageoutput[$n] = [];
				$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
				$this->x = $this->lMargin;
				$top_y = $this->y = $this->h - $this->margin_footer;

				// if bottom-margin==0, corrects to avoid division by zero
				if ($this->y == $this->h) {
					$top_y = $this->y = ($this->h + 0.01);
				}

				// Replace of page number aliases and date format
				$html = $this->aliasReplace($html, $pnstr, $pntstr, $nb);

				$this->HTMLheaderPageLinks = [];
				$this->HTMLheaderPageAnnots = [];
				$this->HTMLheaderPageForms = [];
				$this->pageBackgrounds = [];

				$this->writingHTMLfooter = true;
				$this->InFooter = true;
				$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
				$this->InFooter = false;
				$this->Reset();
				$this->pageoutput[$n] = [];

				$fheight = $this->y - $top_y;
				$adj = -$fheight;

				$s = $this->PrintPageBackgrounds(-$adj);
				$this->headerbuffer = $s . $this->headerbuffer;
				$this->writingHTMLfooter = false; // mPDF 5.7.3  (moved after PrintPageBackgrounds so can adjust position of images in footer)

				$os = '';
				$os .= $this->StartTransform(true) . "\n";

				if ($rotate) {
					$os .= sprintf('q 0 -1 1 0 0 %.3F cm ', ($this->w * Mpdf::SCALE));
					// To rotate the other way i.e. Header to left of page:
					// $os .= sprintf('q 0 1 -1 0 %.3F %.3F cm ',($this->h*Mpdf::SCALE), (($this->rMargin - $this->lMargin )*Mpdf::SCALE));
				}

				$os .= $this->transformTranslate(0, $adj, true) . "\n";
				$os .= $this->headerbuffer;

				if ($rotate) {
					$os .= ' Q' . "\n";
				}

				$os .= $this->StopTransform(true) . "\n";

				// Writes over the page background but behind any other output on page
				$os = preg_replace(['/\\\\/', '/\$/'], ['\\\\\\\\', '\\\\$'], $os);

				$this->pages[$n] = preg_replace('/(___HEADER___MARKER' . $this->uniqstr . ')/', "\n" . $os . "\n" . '\\1', $this->pages[$n]);

				$lks = $this->HTMLheaderPageLinks;

				foreach ($lks as $lk) {

					$lk[1] -= $adj * Mpdf::SCALE;

					if ($rotate) {
						$lw = $lk[2];
						$lh = $lk[3];
						$lk[2] = $lh;
						$lk[3] = $lw; // swap width and height

						$ax = $lk[0] / Mpdf::SCALE;
						$ay = $lk[1] / Mpdf::SCALE;
						$bx = $ay - ($lh / Mpdf::SCALE);
						$by = $this->w - $ax;
						$lk[0] = $bx * Mpdf::SCALE;
						$lk[1] = ($this->h - $by) * Mpdf::SCALE - $lw;
					}

					$this->PageLinks[$n][] = $lk;
				}

				/* -- FORMS -- */
				foreach ($this->HTMLheaderPageForms as $f) {
					$f['y'] += $adj;
					$this->form->forms[$f['n']] = $f;
				}
				/* -- END FORMS -- */
			}

			// Customization for https://github.com/mpdf/mpdf/issues/172
			// Replace of page number aliases and date format
			$this->pages[$n] = $this->aliasReplace($this->pages[$n], $pnstr, $pntstr, $nb);
		}

		$this->page = $nb;
		$this->state = 1;
	}

	/* -- ANNOTATIONS -- */
	function Annotation($text, $x = 0, $y = 0, $icon = 'Note', $author = '', $subject = '', $opacity = 0, $colarray = false, $popup = '', $file = '')
	{
		if (is_array($colarray) && count($colarray) == 3) {
			$colarray = $this->colorConverter->convert('rgb(' . $colarray[0] . ',' . $colarray[1] . ',' . $colarray[2] . ')', $this->PDFAXwarnings);
		}
		if ($colarray === false) {
			$colarray = $this->colorConverter->convert('yellow', $this->PDFAXwarnings);
		}
		if ($x == 0) {
			$x = $this->x;
		}
		if ($y == 0) {
			$y = $this->y;
		}
		$page = $this->page;
		if ($page < 1) { // Document has not been started - assume it's for first page
			$page = 1;
			if ($x == 0) {
				$x = $this->lMargin;
			}
			if ($y == 0) {
				$y = $this->tMargin;
			}
		}

		if ($this->PDFA || $this->PDFX) {
			if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
				$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)";
			}
			$x = ($this->w) - $this->rMargin * 0.66;
		}
		if (!$this->annotMargin) {
			$y -= $this->FontSize / 2;
		}

		if (!$opacity && $this->annotMargin) {
			$opacity = 1;
		} elseif (!$opacity) {
			$opacity = $this->annotOpacity;
		}

		$an = ['txt' => $text, 'x' => $x, 'y' => $y, 'opt' => ['Icon' => $icon, 'T' => $author, 'Subj' => $subject, 'C' => $colarray, 'CA' => $opacity, 'popup' => $popup, 'file' => $file]];

		if ($this->keep_block_together) { // don't write yet
			return;
		} elseif ($this->table_rotate) {
			$this->tbrot_Annots[$this->page][] = $an;
			return;
		} elseif ($this->kwt) {
			$this->kwt_Annots[$this->page][] = $an;
			return;
		}

		if ($this->writingHTMLheader || $this->writingHTMLfooter) {
			$this->HTMLheaderPageAnnots[] = $an;
			return;
		}

		// Put an Annotation on the page
		$this->PageAnnots[$page][] = $an;

		/* -- COLUMNS -- */
		// Save cross-reference to Column buffer
		$ref = isset($this->PageAnnots[$this->page]) ? (count($this->PageAnnots[$this->page]) - 1) : -1;
		$this->columnAnnots[$this->CurrCol][intval($this->x)][intval($this->y)] = $ref;
		/* -- END COLUMNS -- */
	}

	/* -- END ANNOTATIONS -- */

	function _enddoc()
	{
		// @log Writing Headers & Footers

		$this->_puthtmlheaders();

		// @log Writing Pages

		// Remove references to unused fonts (usually default font)
		foreach ($this->fonts as $fk => $font) {
			if (isset($font['type']) && $font['type'] == 'TTF' && !$font['used']) {
				if ($font['sip'] || $font['smp']) {
					foreach ($font['subsetfontids'] as $k => $fid) {
						foreach ($this->pages as $pn => $page) {
							$this->pages[$pn] = preg_replace('/\s\/F' . $fid . ' \d[\d.]* Tf\s/is', ' ', $this->pages[$pn]);
						}
					}
				} else {
					foreach ($this->pages as $pn => $page) {
						$this->pages[$pn] = preg_replace('/\s\/F' . $font['i'] . ' \d[\d.]* Tf\s/is', ' ', $this->pages[$pn]);
					}
				}
			}
		}

		if (count($this->layers)) {
			foreach ($this->pages as $pn => $page) {
				preg_match_all('/\/OCZ-index \/ZI(\d+) BDC(.*?)(EMCZ)-index/is', $this->pages[$pn], $m1);
				preg_match_all('/\/OCBZ-index \/ZI(\d+) BDC(.*?)(EMCBZ)-index/is', $this->pages[$pn], $m2);
				preg_match_all('/\/OCGZ-index \/ZI(\d+) BDC(.*?)(EMCGZ)-index/is', $this->pages[$pn], $m3);
				$m = [];
				for ($i = 0; $i < 4; $i++) {
					$m[$i] = array_merge($m1[$i], $m2[$i], $m3[$i]);
				}
				if (count($m[0])) {
					$sortarr = [];
					for ($i = 0; $i < count($m[0]); $i++) {
						$key = $m[1][$i] * 2;
						if ($m[3][$i] == 'EMCZ') {
							$key +=2; // background first then gradient then normal
						} elseif ($m[3][$i] == 'EMCGZ') {
							$key +=1;
						}
						$sortarr[$i] = $key;
					}
					asort($sortarr);
					foreach ($sortarr as $i => $k) {
						$this->pages[$pn] = str_replace($m[0][$i], '', $this->pages[$pn]);
						$this->pages[$pn] .= "\n" . $m[0][$i] . "\n";
					}
					$this->pages[$pn] = preg_replace('/\/OC[BG]{0,1}Z-index \/ZI(\d+) BDC/is', '/OC /ZI\\1 BDC ', $this->pages[$pn]);
					$this->pages[$pn] = preg_replace('/EMC[BG]{0,1}Z-index/is', 'EMC', $this->pages[$pn]);
				}
			}
		}

		$this->pageWriter->writePages();

		// @log Writing document resources

		$this->resourceWriter->writeResources();

		// Info
		$this->writer->object();
		$this->InfoRoot = $this->n;
		$this->writer->write('<<');

		// @log Writing document info
		$this->metadataWriter->writeInfo();

		$this->writer->write('>>');
		$this->writer->write('endobj');

		// METADATA
		if ($this->PDFA || $this->PDFX) {
			$this->metadataWriter->writeMetadata();
		}

		// OUTPUTINTENT
		if ($this->PDFA || $this->PDFX || $this->ICCProfile) {
			$this->metadataWriter->writeOutputIntent();
		}

		// Associated files
		if ($this->associatedFiles) {
			$this->metadataWriter->writeAssociatedFiles();
		}

		// Catalog
		$this->writer->object();
		$this->writer->write('<<');

		// @log Writing document catalog

		$this->metadataWriter->writeCatalog();

		$this->writer->write('>>');
		$this->writer->write('endobj');

		// Cross-ref
		$o = strlen($this->buffer);
		$this->writer->write('xref');
		$this->writer->write('0 ' . ($this->n + 1));
		$this->writer->write('0000000000 65535 f ');

		for ($i = 1; $i <= $this->n; $i++) {
			$this->writer->write(sprintf('%010d 00000 n ', $this->offsets[$i]));
		}

		// Trailer
		$this->writer->write('trailer');
		$this->writer->write('<<');

		$this->metadataWriter->writeTrailer();

		$this->writer->write('>>');
		$this->writer->write('startxref');
		$this->writer->write($o);

		$this->buffer .= '%%EOF';
		$this->state = 3;
	}

	function _beginpage(
		$orientation,
		$mgl = '',
		$mgr = '',
		$mgt = '',
		$mgb = '',
		$mgh = '',
		$mgf = '',
		$ohname = '',
		$ehname = '',
		$ofname = '',
		$efname = '',
		$ohvalue = 0,
		$ehvalue = 0,
		$ofvalue = 0,
		$efvalue = 0,
		$pagesel = '',
		$newformat = ''
	) {
		if (!($pagesel && $this->page == 1 && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->tMargin)))) {
			$this->page++;
			$this->pages[$this->page] = '';
		}
		$this->state = 2;
		$resetHTMLHeadersrequired = false;

		if ($newformat) {
			$this->_setPageSize($newformat, $orientation);
		}

		/* -- CSS-PAGE -- */
		// Paged media (page-box)
		if ($pagesel || (isset($this->page_box['using']) && $this->page_box['using'])) {

			if ($pagesel || $this->page == 1) {
				$first = true;
			} else {
				$first = false;
			}

			if ($this->mirrorMargins && ($this->page % 2 == 0)) {
				$oddEven = 'E';
			} else {
				$oddEven = 'O';
			}

			if ($pagesel) {
				$psel = $pagesel;
			} elseif ($this->page_box['current']) {
				$psel = $this->page_box['current'];
			} else {
				$psel = '';
			}

			list($orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $hname, $fname, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat) = $this->SetPagedMediaCSS($psel, $first, $oddEven);

			if ($this->mirrorMargins && ($this->page % 2 == 0)) {

				if ($hname) {
					$ehvalue = 1;
					$ehname = $hname;
				} else {
					$ehvalue = -1;
				}

				if ($fname) {
					$efvalue = 1;
					$efname = $fname;
				} else {
					$efvalue = -1;
				}

			} else {

				if ($hname) {
					$ohvalue = 1;
					$ohname = $hname;
				} else {
					$ohvalue = -1;
				}

				if ($fname) {
					$ofvalue = 1;
					$ofname = $fname;
				} else {
					$ofvalue = -1;
				}
			}

			if ($resetpagenum || $pagenumstyle || $suppress) {
				$this->PageNumSubstitutions[] = ['from' => ($this->page), 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress];
			}

			// PAGED MEDIA - CROP / CROSS MARKS from @PAGE
			$this->show_marks = $marks;

			// Background color
			if (isset($bg['BACKGROUND-COLOR'])) {
				$cor = $this->colorConverter->convert($bg['BACKGROUND-COLOR'], $this->PDFAXwarnings);
				if ($cor) {
					$this->bodyBackgroundColor = $cor;
				}
			} else {
				$this->bodyBackgroundColor = false;
			}

			/* -- BACKGROUNDS -- */
			if (isset($bg['BACKGROUND-GRADIENT'])) {
				$this->bodyBackgroundGradient = $bg['BACKGROUND-GRADIENT'];
			} else {
				$this->bodyBackgroundGradient = false;
			}

			// Tiling Patterns
			if (isset($bg['BACKGROUND-IMAGE']) && $bg['BACKGROUND-IMAGE']) {
				$ret = $this->SetBackground($bg, $this->pgwidth);
				if ($ret) {
					$this->bodyBackgroundImage = $ret;
				}
			} else {
				$this->bodyBackgroundImage = false;
			}
			/* -- END BACKGROUNDS -- */

			$this->page_box['current'] = $psel;
			$this->page_box['using'] = true;
		}
		/* -- END CSS-PAGE -- */

		// Page orientation
		if (!$orientation) {
			$orientation = $this->DefOrientation;
		} else {
			$orientation = strtoupper(substr($orientation, 0, 1));
			if ($orientation != $this->DefOrientation) {
				$this->OrientationChanges[$this->page] = true;
			}
		}

		if ($orientation != $this->CurOrientation || $newformat) {

			// Change orientation
			if ($orientation == 'P') {
				$this->wPt = $this->fwPt;
				$this->hPt = $this->fhPt;
				$this->w = $this->fw;
				$this->h = $this->fh;
				if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation == 'P') {
					$this->tMargin = $this->orig_tMargin;
					$this->bMargin = $this->orig_bMargin;
					$this->DeflMargin = $this->orig_lMargin;
					$this->DefrMargin = $this->orig_rMargin;
					$this->margin_header = $this->orig_hMargin;
					$this->margin_footer = $this->orig_fMargin;
				} else {
					$resetHTMLHeadersrequired = true;
				}
			} else {
				$this->wPt = $this->fhPt;
				$this->hPt = $this->fwPt;
				$this->w = $this->fh;
				$this->h = $this->fw;

				if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation == 'P') {
					$this->tMargin = $this->orig_lMargin;
					$this->bMargin = $this->orig_rMargin;
					$this->DeflMargin = $this->orig_bMargin;
					$this->DefrMargin = $this->orig_tMargin;
					$this->margin_header = $this->orig_hMargin;
					$this->margin_footer = $this->orig_fMargin;
				} else {
					$resetHTMLHeadersrequired = true;
				}
			}

			$this->CurOrientation = $orientation;
			$this->ResetMargins();
			$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
			$this->PageBreakTrigger = $this->h - $this->bMargin;
		}

		$this->pageDim[$this->page]['w'] = $this->w;
		$this->pageDim[$this->page]['h'] = $this->h;

		$this->pageDim[$this->page]['outer_width_LR'] = isset($this->page_box['outer_width_LR']) ? $this->page_box['outer_width_LR'] : 0;
		$this->pageDim[$this->page]['outer_width_TB'] = isset($this->page_box['outer_width_TB']) ? $this->page_box['outer_width_TB'] : 0;

		if (!isset($this->page_box['outer_width_LR']) && !isset($this->page_box['outer_width_TB'])) {
			$this->pageDim[$this->page]['bleedMargin'] = 0;
		} elseif ($this->bleedMargin <= $this->page_box['outer_width_LR'] && $this->bleedMargin <= $this->page_box['outer_width_TB']) {
			$this->pageDim[$this->page]['bleedMargin'] = $this->bleedMargin;
		} else {
			$this->pageDim[$this->page]['bleedMargin'] = min($this->page_box['outer_width_LR'], $this->page_box['outer_width_TB']) - 0.01;
		}

		// If Page Margins are re-defined
		// strlen()>0 is used to pick up (integer) 0, (string) '0', or set value
		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)) {

			if (strlen($mgl) > 0) {
				$this->DeflMargin = $mgl;
			}

			if (strlen($mgr) > 0) {
				$this->DefrMargin = $mgr;
			}

			if (strlen($mgt) > 0) {
				$this->tMargin = $mgt;
			}

			if (strlen($mgb) > 0) {
				$this->bMargin = $mgb;
			}

			if (strlen($mgh) > 0) {
				$this->margin_header = $mgh;
			}

			if (strlen($mgf) > 0) {
				$this->margin_footer = $mgf;
			}

			$this->ResetMargins();
			$this->SetAutoPageBreak($this->autoPageBreak, $this->bMargin);

			$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
			$resetHTMLHeadersrequired = true;
		}

		$this->ResetMargins();
		$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
		$this->SetAutoPageBreak($this->autoPageBreak, $this->bMargin);

		// Reset column top margin
		$this->y0 = $this->tMargin;

		$this->x = $this->lMargin;
		$this->y = $this->tMargin;
		$this->FontFamily = '';

		// HEADERS AND FOOTERS	// mPDF 6
		if ($ohvalue < 0 || strtoupper($ohvalue) == 'OFF') {
			$this->HTMLHeader = '';
			$resetHTMLHeadersrequired = true;
		} elseif ($ohname && $ohvalue > 0) {
			if (preg_match('/^html_(.*)$/i', $ohname, $n)) {
				$name = $n[1];
			} else {
				$name = $ohname;
			}
			if (isset($this->pageHTMLheaders[$name])) {
				$this->HTMLHeader = $this->pageHTMLheaders[$name];
			} else {
				$this->HTMLHeader = '';
			}
			$resetHTMLHeadersrequired = true;
		}

		if ($ehvalue < 0 || strtoupper($ehvalue) == 'OFF') {
			$this->HTMLHeaderE = '';
			$resetHTMLHeadersrequired = true;
		} elseif ($ehname && $ehvalue > 0) {
			if (preg_match('/^html_(.*)$/i', $ehname, $n)) {
				$name = $n[1];
			} else {
				$name = $ehname;
			}
			if (isset($this->pageHTMLheaders[$name])) {
				$this->HTMLHeaderE = $this->pageHTMLheaders[$name];
			} else {
				$this->HTMLHeaderE = '';
			}
			$resetHTMLHeadersrequired = true;
		}

		if ($ofvalue < 0 || strtoupper($ofvalue) == 'OFF') {
			$this->HTMLFooter = '';
			$resetHTMLHeadersrequired = true;
		} elseif ($ofname && $ofvalue > 0) {
			if (preg_match('/^html_(.*)$/i', $ofname, $n)) {
				$name = $n[1];
			} else {
				$name = $ofname;
			}
			if (isset($this->pageHTMLfooters[$name])) {
				$this->HTMLFooter = $this->pageHTMLfooters[$name];
			} else {
				$this->HTMLFooter = '';
			}
			$resetHTMLHeadersrequired = true;
		}

		if ($efvalue < 0 || strtoupper($efvalue) == 'OFF') {
			$this->HTMLFooterE = '';
			$resetHTMLHeadersrequired = true;
		} elseif ($efname && $efvalue > 0) {
			if (preg_match('/^html_(.*)$/i', $efname, $n)) {
				$name = $n[1];
			} else {
				$name = $efname;
			}
			if (isset($this->pageHTMLfooters[$name])) {
				$this->HTMLFooterE = $this->pageHTMLfooters[$name];
			} else {
				$this->HTMLFooterE = '';
			}
			$resetHTMLHeadersrequired = true;
		}

		if ($resetHTMLHeadersrequired) {
			$this->SetHTMLHeader($this->HTMLHeader);
			$this->SetHTMLHeader($this->HTMLHeaderE, 'E');
			$this->SetHTMLFooter($this->HTMLFooter);
			$this->SetHTMLFooter($this->HTMLFooterE, 'E');
		}


		if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
			$this->_setAutoHeaderHeight($this->HTMLHeaderE);
			$this->_setAutoFooterHeight($this->HTMLFooterE);
		} else { // ODD or DEFAULT
			$this->_setAutoHeaderHeight($this->HTMLHeader);
			$this->_setAutoFooterHeight($this->HTMLFooter);
		}

		// Reset column top margin
		$this->y0 = $this->tMargin;

		$this->x = $this->lMargin;
		$this->y = $this->tMargin;
	}

	// mPDF 6
	function _setAutoHeaderHeight(&$htmlh)
	{
		/* When the setAutoTopMargin option is set to pad/stretch, only apply auto header height when a header exists */
		if ($this->HTMLHeader === '' && $this->HTMLHeaderE === '') {
			return;
		}

		if ($this->setAutoTopMargin == 'pad') {
			if (isset($htmlh['h']) && $htmlh['h']) {
				$h = $htmlh['h'];
			} // 5.7.3
			else {
				$h = 0;
			}
			$this->tMargin = $this->margin_header + $h + $this->orig_tMargin;
		} elseif ($this->setAutoTopMargin == 'stretch') {
			if (isset($htmlh['h']) && $htmlh['h']) {
				$h = $htmlh['h'];
			} // 5.7.3
			else {
				$h = 0;
			}
			$this->tMargin = max($this->orig_tMargin, $this->margin_header + $h + $this->autoMarginPadding);
		}
	}

	// mPDF 6
	function _setAutoFooterHeight(&$htmlf)
	{
		/* When the setAutoTopMargin option is set to pad/stretch, only apply auto footer height when a footer exists */
		if ($this->HTMLFooter === '' && $this->HTMLFooterE === '') {
			return;
		}

		if ($this->setAutoBottomMargin == 'pad') {
			if (isset($htmlf['h']) && $htmlf['h']) {
				$h = $htmlf['h'];
			} // 5.7.3
			else {
				$h = 0;
			}
			$this->bMargin = $this->margin_footer + $h + $this->orig_bMargin;
			$this->PageBreakTrigger = $this->h - $this->bMargin;
		} elseif ($this->setAutoBottomMargin == 'stretch') {
			if (isset($htmlf['h']) && $htmlf['h']) {
				$h = $htmlf['h'];
			} // 5.7.3
			else {
				$h = 0;
			}
			$this->bMargin = max($this->orig_bMargin, $this->margin_footer + $h + $this->autoMarginPadding);
			$this->PageBreakTrigger = $this->h - $this->bMargin;
		}
	}

	function _endpage()
	{
		/* -- CSS-IMAGE-FLOAT -- */
		$this->printfloatbuffer();
		/* -- END CSS-IMAGE-FLOAT -- */

		if ($this->visibility != 'visible') {
			$this->SetVisibility('visible');
		}
		$this->EndLayer();
		// End of page contents
		$this->state = 1;
	}

	function _dounderline($x, $y, $txt, $OTLdata = false, $textvar = 0)
	{
		// Now print line exactly where $y secifies - called from Text() and Cell() - adjust  position there
		// WORD SPACING
		$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));
		// Draw a line
		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);
	}



	/* -- WATERMARK -- */

	// add a watermark
	function watermark($texte, $angle = 45, $fontsize = 96, $alpha = 0.2)
	{
		if ($this->PDFA || $this->PDFX) {
			throw new \Mpdf\MpdfException('PDFA and PDFX do not permit transparency, so mPDF does not allow Watermarks!');
		}

		if (!$this->watermark_font) {
			$this->watermark_font = $this->default_font;
		}

		$this->SetFont($this->watermark_font, "B", $fontsize, false); // Don't output
		$texte = $this->purify_utf8_text($texte);

		if ($this->text_input_as_HTML) {
			$texte = $this->all_entities_to_utf8($texte);
		}

		if ($this->usingCoreFont) {
			$texte = mb_convert_encoding($texte, $this->mb_enc, 'UTF-8');
		}

		// DIRECTIONALITY
		if (preg_match("/([" . $this->pregRTLchars . "])/u", $texte)) {
			$this->biDirectional = true;
		} // *OTL*

		$textvar = 0;
		$save_OTLtags = $this->OTLtags;
		$this->OTLtags = [];
		if ($this->useKerning) {
			if ($this->CurrentFont['haskernGPOS']) {
				$this->OTLtags['Plus'] .= ' kern';
			} else {
				$textvar = ($textvar | TextVars::FC_KERNING);
			}
		}

		/* -- OTL -- */
		// Use OTL OpenType Table Layout - GSUB & GPOS
		if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
			$texte = $this->otl->applyOTL($texte, $this->CurrentFont['useOTL']);
			$OTLdata = $this->otl->OTLdata;
		}
		/* -- END OTL -- */
		$this->OTLtags = $save_OTLtags;

		$this->magic_reverse_dir($texte, $this->directionality, $OTLdata);

		$this->SetAlpha($alpha);

		$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));

		$szfont = $fontsize;
		$loop = 0;
		$maxlen = (min($this->w, $this->h) ); // sets max length of text as 7/8 width/height of page

		while ($loop == 0) {
			$this->SetFont($this->watermark_font, "B", $szfont, false); // Don't output
			$offset = ((sin(deg2rad($angle))) * ($szfont / Mpdf::SCALE));

			$strlen = $this->GetStringWidth($texte, true, $OTLdata, $textvar);
			if ($strlen > $maxlen - $offset) {
				$szfont --;
			} else {
				$loop ++;
			}
		}

		$this->SetFont($this->watermark_font, "B", $szfont - 0.1, true, true); // Output The -0.1 is because SetFont above is not written to PDF

		// Repeating it will not output anything as mPDF thinks it is set
		$adj = ((cos(deg2rad($angle))) * ($strlen / 2));
		$opp = ((sin(deg2rad($angle))) * ($strlen / 2));

		$wx = ($this->w / 2) - $adj + $offset / 3;
		$wy = ($this->h / 2) + $opp;

		$this->Rotate($angle, $wx, $wy);
		$this->Text($wx, $wy, $texte, $OTLdata, $textvar);
		$this->Rotate(0);
		$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));

		$this->SetAlpha(1);
	}

	function watermarkImg($src, $alpha = 0.2)
	{
		if ($this->PDFA || $this->PDFX) {
			throw new \Mpdf\MpdfException('PDFA and PDFX do not permit transparency, so mPDF does not allow Watermarks!');
		}

		if ($this->watermarkImgBehind) {
			$this->watermarkImgAlpha = $this->SetAlpha($alpha, 'Normal', true);
		} else {
			$this->SetAlpha($alpha, $this->watermarkImgAlphaBlend);
		}

		$this->Image($src, 0, 0, 0, 0, '', '', true, true, true);

		if (!$this->watermarkImgBehind) {
			$this->SetAlpha(1);
		}
	}

	/* -- END WATERMARK -- */

	function Rotate($angle, $x = -1, $y = -1)
	{
		if ($x == -1) {
			$x = $this->x;
		}
		if ($y == -1) {
			$y = $this->y;
		}
		if ($this->angle != 0) {
			$this->writer->write('Q');
		}
		$this->angle = $angle;
		if ($angle != 0) {
			$angle*=M_PI / 180;
			$c = cos($angle);
			$s = sin($angle);
			$cx = $x * Mpdf::SCALE;
			$cy = ($this->h - $y) * Mpdf::SCALE;
			$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));
		}
	}

	function CircularText($x, $y, $r, $text, $align = 'top', $fontfamily = '', $fontsize = 0, $fontstyle = '', $kerning = 120, $fontwidth = 100, $divider = '')
	{
		if (empty($this->directWrite)) {
			$this->directWrite = new DirectWrite($this, $this->otl, $this->sizeConverter, $this->colorConverter);
		}

		$this->directWrite->CircularText($x, $y, $r, $text, $align, $fontfamily, $fontsize, $fontstyle, $kerning, $fontwidth, $divider);
	}

	// From Invoice
	function RoundedRect($x, $y, $w, $h, $r, $style = '')
	{
		$hp = $this->h;

		if ($style == 'F') {
			$op = 'f';
		} elseif ($style == 'FD' or $style == 'DF') {
			$op = 'B';
		} else {
			$op = 'S';
		}

		$MyArc = 4 / 3 * (sqrt(2) - 1);
		$this->writer->write(sprintf('%.3F %.3F m', ($x + $r) * Mpdf::SCALE, ($hp - $y) * Mpdf::SCALE));
		$xc = $x + $w - $r;
		$yc = $y + $r;
		$this->writer->write(sprintf('%.3F %.3F l', $xc * Mpdf::SCALE, ($hp - $y) * Mpdf::SCALE));

		$this->_Arc($xc + $r * $MyArc, $yc - $r, $xc + $r, $yc - $r * $MyArc, $xc + $r, $yc);
		$xc = $x + $w - $r;
		$yc = $y + $h - $r;
		$this->writer->write(sprintf('%.3F %.3F l', ($x + $w) * Mpdf::SCALE, ($hp - $yc) * Mpdf::SCALE));

		$this->_Arc($xc + $r, $yc + $r * $MyArc, $xc + $r * $MyArc, $yc + $r, $xc, $yc + $r);
		$xc = $x + $r;
		$yc = $y + $h - $r;
		$this->writer->write(sprintf('%.3F %.3F l', $xc * Mpdf::SCALE, ($hp - ($y + $h)) * Mpdf::SCALE));

		$this->_Arc($xc - $r * $MyArc, $yc + $r, $xc - $r, $yc + $r * $MyArc, $xc - $r, $yc);
		$xc = $x + $r;
		$yc = $y + $r;
		$this->writer->write(sprintf('%.3F %.3F l', ($x) * Mpdf::SCALE, ($hp - $yc) * Mpdf::SCALE));

		$this->_Arc($xc - $r, $yc - $r * $MyArc, $xc - $r * $MyArc, $yc - $r, $xc, $yc - $r);
		$this->writer->write($op);
	}

	function _Arc($x1, $y1, $x2, $y2, $x3, $y3)
	{
		$h = $this->h;
		$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));
	}

	// ====================================================



	/* -- DIRECTW -- */
	function Shaded_box($text, $font = '', $fontstyle = 'B', $szfont = '', $width = '70%', $style = 'DF', $radius = 2.5, $fill = '#FFFFFF', $color = '#000000', $pad = 2)
	{
		// F (shading - no line),S (line, no shading),DF (both)
		if (empty($this->directWrite)) {
			$this->directWrite = new DirectWrite($this, $this->otl, $this->sizeConverter, $this->colorConverter);
		}
		$this->directWrite->Shaded_box($text, $font, $fontstyle, $szfont, $width, $style, $radius, $fill, $color, $pad);
	}

	/* -- END DIRECTW -- */

	function UTF8StringToArray($str, $addSubset = true)
	{
		$out = [];
		$len = strlen($str);
		for ($i = 0; $i < $len; $i++) {
			$uni = -1;
			$h = ord($str[$i]);
			if ($h <= 0x7F) {
				$uni = $h;
			} elseif ($h >= 0xC2) {
				if (($h <= 0xDF) && ($i < $len - 1)) {
					$uni = ($h & 0x1F) << 6 | (ord($str[++$i]) & 0x3F);
				} elseif (($h <= 0xEF) && ($i < $len - 2)) {
					$uni = ($h & 0x0F) << 12 | (ord($str[++$i]) & 0x3F) << 6 | (ord($str[++$i]) & 0x3F);
				} elseif (($h <= 0xF4) && ($i < $len - 3)) {
					$uni = ($h & 0x0F) << 18 | (ord($str[++$i]) & 0x3F) << 12 | (ord($str[++$i]) & 0x3F) << 6 | (ord($str[++$i]) & 0x3F);
				}
			}
			if ($uni >= 0) {
				$out[] = $uni;
				if ($addSubset && isset($this->CurrentFont['subset'])) {
					$this->CurrentFont['subset'][$uni] = $uni;
				}
			}
		}
		return $out;
	}

	// Convert utf-8 string to <HHHHHH> for Font Subsets
	function UTF8toSubset($str)
	{
		$ret = '<';
		// $str = preg_replace('/'.preg_quote($this->aliasNbPg,'/').'/', chr(7), $str );	// mPDF 6 deleted
		// $str = preg_replace('/'.preg_quote($this->aliasNbPgGp,'/').'/', chr(8), $str );	// mPDF 6 deleted
		$unicode = $this->UTF8StringToArray($str);
		$orig_fid = $this->CurrentFont['subsetfontids'][0];
		$last_fid = $this->CurrentFont['subsetfontids'][0];
		foreach ($unicode as $c) {
			/* 	// mPDF 6 deleted
			  if ($c == 7 || $c == 8) {
			  if ($orig_fid != $last_fid) {
			  $ret .= '> Tj /F'.$orig_fid.' '.$this->FontSizePt.' Tf <';
			  $last_fid = $orig_fid;
			  }
			  if ($c == 7) { $ret .= $this->aliasNbPgHex; }
			  else { $ret .= $this->aliasNbPgGpHex; }
			  continue;
			  }
			 */
			if (!$this->_charDefined($this->CurrentFont['cw'], $c)) {
				$c = 0;
			} // mPDF 6
			for ($i = 0; $i < 99; $i++) {
				// return c as decimal char
				$init = array_search($c, $this->CurrentFont['subsets'][$i]);
				if ($init !== false) {
					if ($this->CurrentFont['subsetfontids'][$i] != $last_fid) {
						$ret .= '> Tj /F' . $this->CurrentFont['subsetfontids'][$i] . ' ' . $this->FontSizePt . ' Tf <';
						$last_fid = $this->CurrentFont['subsetfontids'][$i];
					}
					$ret .= sprintf("%02s", strtoupper(dechex($init)));
					break;
				} // TrueType embedded SUBSETS
				elseif (count($this->CurrentFont['subsets'][$i]) < 255) {
					$n = count($this->CurrentFont['subsets'][$i]);
					$this->CurrentFont['subsets'][$i][$n] = $c;
					if ($this->CurrentFont['subsetfontids'][$i] != $last_fid) {
						$ret .= '> Tj /F' . $this->CurrentFont['subsetfontids'][$i] . ' ' . $this->FontSizePt . ' Tf <';
						$last_fid = $this->CurrentFont['subsetfontids'][$i];
					}
					$ret .= sprintf("%02s", strtoupper(dechex($n)));
					break;
				} elseif (!isset($this->CurrentFont['subsets'][($i + 1)])) {
					// TrueType embedded SUBSETS
					$this->CurrentFont['subsets'][($i + 1)] = [0 => 0];
					$new_fid = count($this->fonts) + $this->extraFontSubsets + 1;
					$this->CurrentFont['subsetfontids'][($i + 1)] = $new_fid;
					$this->extraFontSubsets++;
				}
			}
		}
		$ret .= '>';
		if ($last_fid != $orig_fid) {
			$ret .= ' Tj /F' . $orig_fid . ' ' . $this->FontSizePt . ' Tf <> ';
		}
		return $ret;
	}

	/* -- CJK-FONTS -- */

	// from class PDF_Chinese CJK EXTENSIONS
	function AddCIDFont($family, $style, $name, &$cw, $CMap, $registry, $desc)
	{
		$fontkey = strtolower($family) . strtoupper($style);
		if (isset($this->fonts[$fontkey])) {
			throw new \Mpdf\MpdfException("Font already added: $family $style");
		}
		$i = count($this->fonts) + $this->extraFontSubsets + 1;
		$name = str_replace(' ', '', $name);
		if ($family == 'sjis') {
			$up = -120;
		} else {
			$up = -130;
		}
		// ? 'up' and 'ut' do not seem to be referenced anywhere
		$this->fonts[$fontkey] = ['i' => $i, 'type' => 'Type0', 'name' => $name, 'up' => $up, 'ut' => 40, 'cw' => $cw, 'CMap' => $CMap, 'registry' => $registry, 'MissingWidth' => 1000, 'desc' => $desc];
	}

	function AddCJKFont($family)
	{

		if ($this->PDFA || $this->PDFX) {
			throw new \Mpdf\MpdfException("Adobe CJK fonts cannot be embedded in mPDF (required for PDFA1-b and PDFX/1-a).");
		}
		if ($family == 'big5') {
			$this->AddBig5Font();
		} elseif ($family == 'gb') {
			$this->AddGBFont();
		} elseif ($family == 'sjis') {
			$this->AddSJISFont();
		} elseif ($family == 'uhc') {
			$this->AddUHCFont();
		}
	}

	function AddBig5Font()
	{
		// Add Big5 font with proportional Latin
		$family = 'big5';
		$name = 'MSungStd-Light-Acro';
		$cw = $this->Big5_widths;
		$CMap = 'UniCNS-UTF16-H';
		$registry = ['ordering' => 'CNS1', 'supplement' => 4];
		$desc = [
			'Ascent' => 880,
			'Descent' => -120,
			'CapHeight' => 880,
			'Flags' => 6,
			'FontBBox' => '[-160 -249 1015 1071]',
			'ItalicAngle' => 0,
			'StemV' => 93,
		];
		$this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
		$this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
		$this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
		$this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
	}

	function AddGBFont()
	{
		// Add GB font with proportional Latin
		$family = 'gb';
		$name = 'STSongStd-Light-Acro';
		$cw = $this->GB_widths;
		$CMap = 'UniGB-UTF16-H';
		$registry = ['ordering' => 'GB1', 'supplement' => 4];
		$desc = [
			'Ascent' => 880,
			'Descent' => -120,
			'CapHeight' => 737,
			'Flags' => 6,
			'FontBBox' => '[-25 -254 1000 880]',
			'ItalicAngle' => 0,
			'StemV' => 58,
			'Style' => '<< /Panose <000000000400000000000000> >>',
		];
		$this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
		$this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
		$this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
		$this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
	}

	function AddSJISFont()
	{
		// Add SJIS font with proportional Latin
		$family = 'sjis';
		$name = 'KozMinPro-Regular-Acro';
		$cw = $this->SJIS_widths;
		$CMap = 'UniJIS-UTF16-H';
		$registry = ['ordering' => 'Japan1', 'supplement' => 5];
		$desc = [
			'Ascent' => 880,
			'Descent' => -120,
			'CapHeight' => 740,
			'Flags' => 6,
			'FontBBox' => '[-195 -272 1110 1075]',
			'ItalicAngle' => 0,
			'StemV' => 86,
			'XHeight' => 502,
		];
		$this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
		$this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
		$this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
		$this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
	}

	function AddUHCFont()
	{
		// Add UHC font with proportional Latin
		$family = 'uhc';
		$name = 'HYSMyeongJoStd-Medium-Acro';
		$cw = $this->UHC_widths;
		$CMap = 'UniKS-UTF16-H';
		$registry = ['ordering' => 'Korea1', 'supplement' => 2];
		$desc = [
			'Ascent' => 880,
			'Descent' => -120,
			'CapHeight' => 720,
			'Flags' => 6,
			'FontBBox' => '[-28 -148 1001 880]',
			'ItalicAngle' => 0,
			'StemV' => 60,
			'Style' => '<< /Panose <000000000600000000000000> >>',
		];
		$this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
		$this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
		$this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
		$this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
	}

	/* -- END CJK-FONTS -- */

	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////

	function SetDefaultFont($font)
	{
		// Disallow embedded fonts to be used as defaults in PDFA
		if ($this->PDFA || $this->PDFX) {
			if (strtolower($font) == 'ctimes') {
				$font = 'serif';
			}
			if (strtolower($font) == 'ccourier') {
				$font = 'monospace';
			}
			if (strtolower($font) == 'chelvetica') {
				$font = 'sans-serif';
			}
		}
		$font = $this->SetFont($font); // returns substituted font if necessary
		$this->default_font = $font;
		$this->original_default_font = $font;
		if (!$this->watermark_font) {
			$this->watermark_font = $font;
		} // *WATERMARK*
		$this->defaultCSS['BODY']['FONT-FAMILY'] = $font;
		$this->cssManager->CSS['BODY']['FONT-FAMILY'] = $font;
	}

	function SetDefaultFontSize($fontsize)
	{
		$this->default_font_size = $fontsize;
		$this->original_default_font_size = $fontsize;
		$this->SetFontSize($fontsize);
		$this->defaultCSS['BODY']['FONT-SIZE'] = $fontsize . 'pt';
		$this->cssManager->CSS['BODY']['FONT-SIZE'] = $fontsize . 'pt';
	}

	function SetDefaultBodyCSS($prop, $val)
	{
		if ($prop) {
			$this->defaultCSS['BODY'][strtoupper($prop)] = $val;
			$this->cssManager->CSS['BODY'][strtoupper($prop)] = $val;
		}
	}

	function SetDirectionality($dir = 'ltr')
	{
		/* -- OTL -- */
		if (strtolower($dir) == 'rtl') {
			if ($this->directionality != 'rtl') {
				// Swop L/R Margins so page 1 RTL is an 'even' page
				$tmp = $this->DeflMargin;
				$this->DeflMargin = $this->DefrMargin;
				$this->DefrMargin = $tmp;
				$this->orig_lMargin = $this->DeflMargin;
				$this->orig_rMargin = $this->DefrMargin;

				$this->SetMargins($this->DeflMargin, $this->DefrMargin, $this->tMargin);
			}
			$this->directionality = 'rtl';
			$this->defaultAlign = 'R';
			$this->defaultTableAlign = 'R';
		} else {
			/* -- END OTL -- */
			$this->directionality = 'ltr';
			$this->defaultAlign = 'L';
			$this->defaultTableAlign = 'L';
		} // *OTL*
		$this->cssManager->CSS['BODY']['DIRECTION'] = $this->directionality;
	}

	// Return either a number (factor) - based on current set fontsize (if % or em) - or exact lineheight (with 'mm' after it)
	function fixLineheight($v)
	{
		$lh = false;
		if (preg_match('/^[0-9\.,]*$/', $v) && $v >= 0) {
			return ($v + 0);
		} elseif (strtoupper($v) == 'NORMAL' || $v == 'N') {
			return 'N';  // mPDF 6
		} else {
			$tlh = $this->sizeConverter->convert($v, $this->FontSize, $this->FontSize, true);
			if ($tlh) {
				return ($tlh . 'mm');
			}
		}
		return $this->normalLineheight;
	}

	function _getNormalLineheight($desc = false)
	{
		if (!$desc) {
			$desc = $this->CurrentFont['desc'];
		}
		if (!isset($desc['Leading'])) {
			$desc['Leading'] = 0;
		}
		if ($this->useFixedNormalLineHeight) {
			$lh = $this->normalLineheight;
		} elseif (isset($desc['Ascent']) && $desc['Ascent']) {
			$lh = ($this->adjustFontDescLineheight * ($desc['Ascent'] - $desc['Descent'] + $desc['Leading']) / 1000);
		} else {
			$lh = $this->normalLineheight;
		}
		return $lh;
	}

	// Set a (fixed) lineheight to an actual value - either to named fontsize(pts) or default
	function SetLineHeight($FontPt = '', $lh = '')
	{
		if (!$FontPt) {
			$FontPt = $this->FontSizePt;
		}
		$fs = $FontPt / Mpdf::SCALE;
		$this->lineheight = $this->_computeLineheight($lh, $fs);
	}

	function _computeLineheight($lh, $fs = '')
	{
		if ($this->shrin_k > 1) {
			$k = $this->shrin_k;
		} else {
			$k = 1;
		}
		if (!$fs) {
			$fs = $this->FontSize;
		}
		if ($lh == 'N') {
			$lh = $this->_getNormalLineheight();
		}
		if (preg_match('/mm/', $lh)) {
			return (((float) $lh) / $k); // convert to number
		} elseif ($lh > 0) {
			return ($fs * $lh);
		}
		return ($fs * $this->normalLineheight);
	}

	function _setLineYpos(&$fontsize, &$fontdesc, &$CSSlineheight, $blockYpos = false)
	{
		$ypos['glyphYorigin'] = 0;
		$ypos['baseline-shift'] = 0;
		$linegap = 0;
		$leading = 0;

		if (isset($fontdesc['Ascent']) && $fontdesc['Ascent'] && !$this->useFixedTextBaseline) {
			// Fontsize uses font metrics - this method seems to produce results compatible with browsers (except IE9)
			$ypos['boxtop'] = $fontdesc['Ascent'] / 1000 * $fontsize;
			$ypos['boxbottom'] = $fontdesc['Descent'] / 1000 * $fontsize;
			if (isset($fontdesc['Leading'])) {
				$linegap = $fontdesc['Leading'] / 1000 * $fontsize;
			}
		} // Default if not set - uses baselineC
		else {
			$ypos['boxtop'] = (0.5 + $this->baselineC) * $fontsize;
			$ypos['boxbottom'] = -(0.5 - $this->baselineC) * $fontsize;
		}
		$fontheight = $ypos['boxtop'] - $ypos['boxbottom'];

		if ($this->shrin_k > 1) {
			$shrin_k = $this->shrin_k;
		} else {
			$shrin_k = 1;
		}

		$leading = 0;
		if ($CSSlineheight == 'N') {
			$lh = $this->_getNormalLineheight($fontdesc);
			$lineheight = ($fontsize * $lh);
			$leading += $linegap; // specified in hhea or sTypo in OpenType tables
		} elseif (preg_match('/mm/', $CSSlineheight)) {
			$lineheight = (((float) $CSSlineheight) / $shrin_k); // convert to number
		} // ??? If lineheight is a factor e.g. 1.3  ?? use factor x 1em or ? use 'normal' lineheight * factor
		// Could depend on value for $text_height - a draft CSS value as set above for now
		elseif ($CSSlineheight > 0) {
			$lineheight = ($fontsize * $CSSlineheight);
		} else {
			$lineheight = ($fontsize * $this->normalLineheight);
		}

		// In general, calculate the "leading" - the difference between the fontheight and the lineheight
		// and add half to the top and half to the bottom. BUT
		// If an inline element has a font-size less than the block element, and the line-height is set as an em or % value
		// it will add too much leading below the font and expand the height of the line - so just use the block element exttop/extbottom:
		if (preg_match('/mm/', $CSSlineheight)
				&& ($blockYpos && $ypos['boxtop'] < $blockYpos['boxtop'])
				&& ($blockYpos && $ypos['boxbottom'] > $blockYpos['boxbottom'])) {

			$ypos['exttop'] = $blockYpos['exttop'];
			$ypos['extbottom'] = $blockYpos['extbottom'];

		} else {

			$leading += ($lineheight - $fontheight);

			$ypos['exttop'] = $ypos['boxtop'] + $leading / 2;
			$ypos['extbottom'] = $ypos['boxbottom'] - $leading / 2;
		}


		// TEMP ONLY FOR DEBUGGING *********************************
		// $ypos['lineheight'] = $lineheight;
		// $ypos['fontheight'] = $fontheight;
		// $ypos['leading'] = $leading;

		return $ypos;
	}

	/* Called from WriteFlowingBlock() and finishFlowingBlock()
	  Determines the line hieght and glyph/writing position
	  for each element in the line to be written */

	function _setInlineBlockHeights(&$lineBox, &$stackHeight, &$content, &$font, $is_table)
	{
		if ($this->shrin_k > 1) {
			$shrin_k = $this->shrin_k;
		} else {
			$shrin_k = 1;
		}

		$ypos = [];
		$bordypos = [];
		$bgypos = [];

		if ($is_table) {
			// FOR TABLE
			$fontsize = $this->FontSize;
			$fontkey = $this->FontFamily . $this->FontStyle;
			$fontdesc = $this->fonts[$fontkey]['desc'];
			$CSSlineheight = $this->cellLineHeight;
			$line_stacking_strategy = $this->cellLineStackingStrategy; // inline-line-height [default] | block-line-height | max-height | grid-height
			$line_stacking_shift = $this->cellLineStackingShift;  // consider-shifts [default] | disregard-shifts
		} else {
			// FOR BLOCK FONT
			$fontsize = $this->blk[$this->blklvl]['InlineProperties']['size'];
			$fontkey = $this->blk[$this->blklvl]['InlineProperties']['family'] . $this->blk[$this->blklvl]['InlineProperties']['style'];
			$fontdesc = $this->fonts[$fontkey]['desc'];
			$CSSlineheight = $this->blk[$this->blklvl]['line_height'];
			// inline-line-height | block-line-height | max-height | grid-height
			$line_stacking_strategy = (isset($this->blk[$this->blklvl]['line_stacking_strategy']) ? $this->blk[$this->blklvl]['line_stacking_strategy'] : 'inline-line-height');
			// consider-shifts | disregard-shifts
			$line_stacking_shift = (isset($this->blk[$this->blklvl]['line_stacking_shift']) ? $this->blk[$this->blklvl]['line_stacking_shift'] : 'consider-shifts');
		}
		$boxLineHeight = $this->_computeLineheight($CSSlineheight, $fontsize);


		// First, set a "strut" using block font at index $lineBox[-1]
		$ypos[-1] = $this->_setLineYpos($fontsize, $fontdesc, $CSSlineheight);

		// for the block element - always taking the block EXTENDED progression including leading - which may be negative
		if ($line_stacking_strategy == 'block-line-height') {
			$topy = $ypos[-1]['exttop'];
			$bottomy = $ypos[-1]['extbottom'];
		} else {
			$topy = 0;
			$bottomy = 0;
		}

		// Get text-middle for aligning images/objects
		$midpoint = $ypos[-1]['boxtop'] - (($ypos[-1]['boxtop'] - $ypos[-1]['boxbottom']) / 2);

		// for images / inline objects / replaced elements
		$mta = 0; // Maximum top-aligned
		$mba = 0; // Maximum bottom-aligned
		foreach ($content as $k => $chunk) {
			if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]['type'] == 'listmarker') {
				$ypos[$k] = $ypos[-1];
				// UPDATE Maximums
				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
					if ($ypos[$k]['boxtop'] > $topy) {
						$topy = $ypos[$k]['boxtop'];
					}
					if ($ypos[$k]['boxbottom'] < $bottomy) {
						$bottomy = $ypos[$k]['boxbottom'];
					}
				} else {
					if ($ypos[$k]['exttop'] > $topy) {
						$topy = $ypos[$k]['exttop'];
					}
					if ($ypos[$k]['extbottom'] < $bottomy) {
						$bottomy = $ypos[$k]['extbottom'];
					}
				}
			} elseif (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
				$fontsize = $font[$k]['size'];
				$fontdesc = $font[$k]['curr']['desc'];
				$lh = 1;
				$ypos[$k] = $this->_setLineYpos($fontsize, $fontdesc, $lh, $ypos[-1]); // Lineheight=1 fixed
			} elseif (isset($this->objectbuffer[$k])) {
				$oh = $this->objectbuffer[$k]['OUTER-HEIGHT'];
				$va = $this->objectbuffer[$k]['vertical-align'];

				if ($va == 'BS') { //  (BASELINE default)
					if ($oh > $topy) {
						$topy = $oh;
					}
				} elseif ($va == 'M') {
					if (($midpoint + $oh / 2) > $topy) {
						$topy = $midpoint + $oh / 2;
					}
					if (($midpoint - $oh / 2) < $bottomy) {
						$bottomy = $midpoint - $oh / 2;
					}
				} elseif ($va == 'TT') {
					if (($ypos[-1]['boxtop'] - $oh) < $bottomy) {
						$bottomy = $ypos[-1]['boxtop'] - $oh;
						$topy = max($topy, $ypos[-1]['boxtop']);
					}
				} elseif ($va == 'TB') {
					if (($ypos[-1]['boxbottom'] + $oh) > $topy) {
						$topy = $ypos[-1]['boxbottom'] + $oh;
						$bottomy = min($bottomy, $ypos[-1]['boxbottom']);
					}
				} elseif ($va == 'T') {
					if ($oh > $mta) {
						$mta = $oh;
					}
				} elseif ($va == 'B') {
					if ($oh > $mba) {
						$mba = $oh;
					}
				}
			} elseif ($content[$k] || $content[$k] === '0') {
				// FOR FLOWING BLOCK
				$fontsize = $font[$k]['size'];
				$fontdesc = $font[$k]['curr']['desc'];
				// In future could set CSS line-height from inline elements; for now, use block level:
				$ypos[$k] = $this->_setLineYpos($fontsize, $fontdesc, $CSSlineheight, $ypos[-1]);

				if (isset($font[$k]['textparam']['text-baseline']) && $font[$k]['textparam']['text-baseline'] != 0) {
					$ypos[$k]['baseline-shift'] = $font[$k]['textparam']['text-baseline'];
				}

				// DO ALIGNMENT FOR BASELINES *******************
				// Until most fonts have OpenType BASE tables, this won't work
				// $ypos[$k] compared to $ypos[-1] or $ypos[$k-1] using $dominant_baseline and $baseline_table
				// UPDATE Maximums
				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
					if ($line_stacking_shift == 'disregard-shifts') {
						if ($ypos[$k]['boxtop'] > $topy) {
							$topy = $ypos[$k]['boxtop'];
						}
						if ($ypos[$k]['boxbottom'] < $bottomy) {
							$bottomy = $ypos[$k]['boxbottom'];
						}
					} else {
						if (($ypos[$k]['boxtop'] + $ypos[$k]['baseline-shift']) > $topy) {
							$topy = $ypos[$k]['boxtop'] + $ypos[$k]['baseline-shift'];
						}
						if (($ypos[$k]['boxbottom'] + $ypos[$k]['baseline-shift']) < $bottomy) {
							$bottomy = $ypos[$k]['boxbottom'] + $ypos[$k]['baseline-shift'];
						}
					}
				} else {
					if ($line_stacking_shift == 'disregard-shifts') {
						if ($ypos[$k]['exttop'] > $topy) {
							$topy = $ypos[$k]['exttop'];
						}
						if ($ypos[$k]['extbottom'] < $bottomy) {
							$bottomy = $ypos[$k]['extbottom'];
						}
					} else {
						if (($ypos[$k]['exttop'] + $ypos[$k]['baseline-shift']) > $topy) {
							$topy = $ypos[$k]['exttop'] + $ypos[$k]['baseline-shift'];
						}
						if (($ypos[$k]['extbottom'] + $ypos[$k]['baseline-shift']) < $bottomy) {
							$bottomy = $ypos[$k]['extbottom'] + $ypos[$k]['baseline-shift'];
						}
					}
				}

				// If BORDER set on inline element
				if (isset($font[$k]['bord']) && $font[$k]['bord']) {
					$bordfontsize = $font[$k]['textparam']['bord-decoration']['fontsize'] / $shrin_k;
					$bordfontkey = $font[$k]['textparam']['bord-decoration']['fontkey'];
					if ($bordfontkey != $fontkey || $bordfontsize != $fontsize || isset($font[$k]['textparam']['bord-decoration']['baseline'])) {
						$bordfontdesc = $this->fonts[$bordfontkey]['desc'];
						$bordypos[$k] = $this->_setLineYpos($bordfontsize, $bordfontdesc, $CSSlineheight, $ypos[-1]);
						if (isset($font[$k]['textparam']['bord-decoration']['baseline']) && $font[$k]['textparam']['bord-decoration']['baseline'] != 0) {
							$bordypos[$k]['baseline-shift'] = $font[$k]['textparam']['bord-decoration']['baseline'] / $shrin_k;
						}
					}
				}
				// If BACKGROUND set on inline element
				if (isset($font[$k]['spanbgcolor']) && $font[$k]['spanbgcolor']) {
					$bgfontsize = $font[$k]['textparam']['bg-decoration']['fontsize'] / $shrin_k;
					$bgfontkey = $font[$k]['textparam']['bg-decoration']['fontkey'];
					if ($bgfontkey != $fontkey || $bgfontsize != $fontsize || isset($font[$k]['textparam']['bg-decoration']['baseline'])) {
						$bgfontdesc = $this->fonts[$bgfontkey]['desc'];
						$bgypos[$k] = $this->_setLineYpos($bgfontsize, $bgfontdesc, $CSSlineheight, $ypos[-1]);
						if (isset($font[$k]['textparam']['bg-decoration']['baseline']) && $font[$k]['textparam']['bg-decoration']['baseline'] != 0) {
							$bgypos[$k]['baseline-shift'] = $font[$k]['textparam']['bg-decoration']['baseline'] / $shrin_k;
						}
					}
				}
			}
		}


		// TOP or BOTTOM aligned images
		if ($mta > ($topy - $bottomy)) {
			if (($topy - $mta) < $bottomy) {
				$bottomy = $topy - $mta;
			}
		}
		if ($mba > ($topy - $bottomy)) {
			if (($bottomy + $mba) > $topy) {
				$topy = $bottomy + $mba;
			}
		}

		if ($line_stacking_strategy == 'block-line-height') { // fixed height set by block element (whether present or not)
			$topy = $ypos[-1]['exttop'];
			$bottomy = $ypos[-1]['extbottom'];
		}

		$inclusiveHeight = $topy - $bottomy;

		// SET $stackHeight taking note of line_stacking_strategy
		// NB inclusive height already takes account of need to consider block progression height (excludes leading set by lineheight)
		// or extended block progression height (includes leading set by lineheight)
		if ($line_stacking_strategy == 'block-line-height') { // fixed = extended block progression height of block element
			$stackHeight = $boxLineHeight;
		} elseif ($line_stacking_strategy == 'max-height') { // smallest height which includes extended block progression height of block element
			// and block progression heights of inline elements (NOT extended)
			$stackHeight = $inclusiveHeight;
		} elseif ($line_stacking_strategy == 'grid-height') { // smallest multiple of block element lineheight to include
			// block progression heights of inline elements (NOT extended)
			$stackHeight = $boxLineHeight;
			while ($stackHeight < $inclusiveHeight) {
				$stackHeight += $boxLineHeight;
			}
		} else { // 'inline-line-height' = default		// smallest height which includes extended block progression height of block element
			// AND extended block progression heights of inline elements
			$stackHeight = $inclusiveHeight;
		}

		$diff = $stackHeight - $inclusiveHeight;
		$topy += $diff / 2;
		$bottomy -= $diff / 2;

		// ADJUST $ypos => lineBox using $stackHeight; lineBox are all offsets from the top of stackHeight in mm
		// and SET IMAGE OFFSETS
		$lineBox[-1]['boxtop'] = $topy - $ypos[-1]['boxtop'];
		$lineBox[-1]['boxbottom'] = $topy - $ypos[-1]['boxbottom'];
		// $lineBox[-1]['exttop'] = $topy - $ypos[-1]['exttop'];
		// $lineBox[-1]['extbottom'] = $topy - $ypos[-1]['extbottom'];
		$lineBox[-1]['glyphYorigin'] = $topy - $ypos[-1]['glyphYorigin'];
		$lineBox[-1]['baseline-shift'] = $ypos[-1]['baseline-shift'];

		$midpoint = $lineBox[-1]['boxbottom'] - (($lineBox[-1]['boxbottom'] - $lineBox[-1]['boxtop']) / 2);

		foreach ($content as $k => $chunk) {
			if (isset($this->objectbuffer[$k])) {
				$oh = $this->objectbuffer[$k]['OUTER-HEIGHT'];
				// LIST MARKERS
				if ($this->objectbuffer[$k]['type'] == 'listmarker') {
					$oh = $fontsize;
				} elseif ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
					$oh = $font[$k]['size']; // == $this->objectbuffer[$k]['fontsize']/Mpdf::SCALE;
					$lineBox[$k]['boxtop'] = $topy - $ypos[$k]['boxtop'];
					$lineBox[$k]['boxbottom'] = $topy - $ypos[$k]['boxbottom'];
					$lineBox[$k]['glyphYorigin'] = $topy - $ypos[$k]['glyphYorigin'];
					$lineBox[$k]['baseline-shift'] = 0;
					// continue;
				}
				$va = $this->objectbuffer[$k]['vertical-align']; // = $objattr['vertical-align'] = set as M,T,B,S

				if ($va == 'BS') { //  (BASELINE default)
					$lineBox[$k]['top'] = $lineBox[-1]['glyphYorigin'] - $oh;
				} elseif ($va == 'M') {
					$lineBox[$k]['top'] = $midpoint - $oh / 2;
				} elseif ($va == 'TT') {
					$lineBox[$k]['top'] = $lineBox[-1]['boxtop'];
				} elseif ($va == 'TB') {
					$lineBox[$k]['top'] = $lineBox[-1]['boxbottom'] - $oh;
				} elseif ($va == 'T') {
					$lineBox[$k]['top'] = 0;
				} elseif ($va == 'B') {
					$lineBox[$k]['top'] = $stackHeight - $oh;
				}
			} elseif ($content[$k] || $content[$k] === '0') {
				$lineBox[$k]['boxtop'] = $topy - $ypos[$k]['boxtop'];
				$lineBox[$k]['boxbottom'] = $topy - $ypos[$k]['boxbottom'];
				// $lineBox[$k]['exttop'] = $topy - $ypos[$k]['exttop'];
				// $lineBox[$k]['extbottom'] = $topy - $ypos[$k]['extbottom'];
				$lineBox[$k]['glyphYorigin'] = $topy - $ypos[$k]['glyphYorigin'];
				$lineBox[$k]['baseline-shift'] = $ypos[$k]['baseline-shift'];
				if (isset($bordypos[$k]['boxtop'])) {
					$lineBox[$k]['border-boxtop'] = $topy - $bordypos[$k]['boxtop'];
					$lineBox[$k]['border-boxbottom'] = $topy - $bordypos[$k]['boxbottom'];
					$lineBox[$k]['border-baseline-shift'] = $bordypos[$k]['baseline-shift'];
				}
				if (isset($bgypos[$k]['boxtop'])) {
					$lineBox[$k]['background-boxtop'] = $topy - $bgypos[$k]['boxtop'];
					$lineBox[$k]['background-boxbottom'] = $topy - $bgypos[$k]['boxbottom'];
					$lineBox[$k]['background-baseline-shift'] = $bgypos[$k]['baseline-shift'];
				}
			}
		}
	}

	function SetBasePath($str = '')
	{
		if (isset($_SERVER['HTTP_HOST'])) {
			$host = $_SERVER['HTTP_HOST'];
		} elseif (isset($_SERVER['SERVER_NAME'])) {
			$host = $_SERVER['SERVER_NAME'];
		} else {
			$host = '';
		}

		if (!$str) {

			if (isset($_SERVER['SCRIPT_NAME'])) {
				$currentPath = dirname($_SERVER['SCRIPT_NAME']);
			} else {
				$currentPath = dirname($_SERVER['PHP_SELF']);
			}

			$currentPath = str_replace("\\", "/", $currentPath);

			if ($currentPath == '/') {
				$currentPath = '';
			}

			if ($host) {  // mPDF 6
				if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] && $_SERVER['HTTPS'] !== 'off') {
					$currpath = 'https://' . $host . $currentPath . '/';
				} else {
					$currpath = 'http://' . $host . $currentPath . '/';
				}
			} else {
				$currpath = '';
			}

			$this->basepath = $currpath;
			$this->basepathIsLocal = true;

			return;
		}

		$str = preg_replace('/\?.*/', '', $str);

		if (!preg_match('/(http|https|ftp):\/\/.*\//i', $str)) {
			$str .= '/';
		}

		$str .= 'xxx'; // in case $str ends in / e.g. http://www.bbc.co.uk/

		$this->basepath = dirname($str) . "/"; // returns e.g. e.g. http://www.google.com/dir1/dir2/dir3/
		$this->basepath = str_replace("\\", "/", $this->basepath); // If on Windows

		$tr = parse_url($this->basepath);

		$this->basepathIsLocal = (isset($tr['host']) && ($tr['host'] == $host));
	}

	public function GetFullPath(&$path, $basepath = '')
	{
		// @todo make return, remove reference

		// When parsing CSS need to pass temporary basepath - so links are relative to current stylesheet
		if (!$basepath) {
			$basepath = $this->basepath;
		}

		// Fix path value
		$path = str_replace("\\", '/', $path); // If on Windows

		// mPDF 5.7.2
		if (strpos($path, '//') === 0) {
			$scheme = parse_url($basepath, PHP_URL_SCHEME);
			$scheme = $scheme ?: 'http';
			$path = $scheme . ':' . $path;
		}

		$path = preg_replace('|^./|', '', $path); // Inadvertently corrects "./path/etc" and "//www.domain.com/etc"

		if (strpos($path, '#') === 0) {
			return;
		}

		// Skip schemes not supported by installed stream wrappers
		$wrappers = stream_get_wrappers();
		$pattern = sprintf('@^(?!%s)[a-z0-9\.\-+]+:.*@i', implode('|', $wrappers));
		if (preg_match($pattern, $path)) {
			return;
		}

		if (strpos($path, '../') === 0) { // It is a relative link

			$backtrackamount = substr_count($path, '../');
			$maxbacktrack = substr_count($basepath, '/') - 3;
			$filepath = str_replace('../', '', $path);
			$path = $basepath;

			// If it is an invalid relative link, then make it go to directory root
			if ($backtrackamount > $maxbacktrack) {
				$backtrackamount = $maxbacktrack;
			}

			// Backtrack some directories
			for ($i = 0; $i < $backtrackamount + 1; $i++) {
				$path = substr($path, 0, strrpos($path, "/"));
			}

			$path .= '/' . $filepath; // Make it an absolute path

			return;

		}

		if ((strpos($path, ":/") === false || strpos($path, ":/") > 10) && !@is_file($path)) { // It is a local link. Ignore potential file errors

			if (strpos($path, '/') === 0) {

				$tr = parse_url($basepath);

				// mPDF 5.7.2
				$root = '';
				if (!empty($tr['scheme'])) {
					$root .= $tr['scheme'] . '://';
				}

				$root .= isset($tr['host']) ? $tr['host'] : '';
				$root .= ((isset($tr['port']) && $tr['port']) ? (':' . $tr['port']) : ''); // mPDF 5.7.3

				$path = $root . $path;

				return;

			}

			$path = $basepath . $path;
		}

		// Do nothing if it is an Absolute Link
	}

	function docPageNum($num = 0, $extras = false)
	{
		if ($num < 1) {
			$num = $this->page;
		}

		$type = $this->defaultPageNumStyle; // set default Page Number Style
		$ppgno = $num;
		$suppress = 0;
		$offset = 0;
		$lastreset = 0;

		foreach ($this->PageNumSubstitutions as $psarr) {

			if ($num >= $psarr['from']) {

				if ($psarr['reset']) {
					if ($psarr['reset'] > 1) {
						$offset = $psarr['reset'] - 1;
					}
					$ppgno = $num - $psarr['from'] + 1 + $offset;
					$lastreset = $psarr['from'];
				}

				if ($psarr['type']) {
					$type = $psarr['type'];
				}

				if (strtoupper($psarr['suppress']) == 'ON' || $psarr['suppress'] == 1) {
					$suppress = 1;
				} elseif (strtoupper($psarr['suppress']) == 'OFF') {
					$suppress = 0;
				}
			}
		}

		if ($suppress) {
			return '';
		}

		$ppgno = $this->_getStyledNumber($ppgno, $type);

		if ($extras) {
			$ppgno = $this->pagenumPrefix . $ppgno . $this->pagenumSuffix;
		}

		return $ppgno;
	}

	function docPageNumTotal($num = 0, $extras = false)
	{
		if ($num < 1) {
			$num = $this->page;
		}

		$type = $this->defaultPageNumStyle; // set default Page Number Style
		$ppgstart = 1;
		$ppgend = count($this->pages) + 1;
		$suppress = 0;
		$offset = 0;

		foreach ($this->PageNumSubstitutions as $psarr) {
			if ($num >= $psarr['from']) {
				if ($psarr['reset']) {
					if ($psarr['reset'] > 1) {
						$offset = $psarr['reset'] - 1;
					}
					$ppgstart = $psarr['from'] + $offset;
					$ppgend = count($this->pages) + 1 + $offset;
				}
				if ($psarr['type']) {
					$type = $psarr['type'];
				}
				if (strtoupper($psarr['suppress']) == 'ON' || $psarr['suppress'] == 1) {
					$suppress = 1;
				} elseif (strtoupper($psarr['suppress']) == 'OFF') {
					$suppress = 0;
				}
			}
			if ($num < $psarr['from']) {
				if ($psarr['reset']) {
					$ppgend = $psarr['from'] + $offset;
					break;
				}
			}
		}

		if ($suppress) {
			return '';
		}

		$ppgno = $ppgend - $ppgstart + $offset;
		$ppgno = $this->_getStyledNumber($ppgno, $type);

		if ($extras) {
			$ppgno = $this->pagenumPrefix . $ppgno . $this->pagenumSuffix;
		}

		return $ppgno;
	}

	// mPDF 6
	function _getStyledNumber($ppgno, $type, $listmarker = false)
	{
		if ($listmarker) {
			$reverse = true; // Reverse RTL numerals (Hebrew) when using for list
			$checkfont = true; // Using list - font is set, so check if character is available
		} else {
			$reverse = false; // For pagenumbers, RTL numerals (Hebrew) will get reversed later by bidi
			$checkfont = false; // For pagenumbers - font is not set, so no check
		}

		$decToAlpha = new Conversion\DecToAlpha();
		$decToCjk = new Conversion\DecToCjk();
		$decToHebrew = new Conversion\DecToHebrew();
		$decToRoman = new Conversion\DecToRoman();
		$decToOther = new Conversion\DecToOther($this);

		$lowertype = strtolower($type);

		if ($lowertype == 'upper-latin' || $lowertype == 'upper-alpha' || $type == 'A') {

			$ppgno = $decToAlpha->convert($ppgno, true);

		} elseif ($lowertype == 'lower-latin' || $lowertype == 'lower-alpha' || $type == 'a') {

			$ppgno = $decToAlpha->convert($ppgno, false);

		} elseif ($lowertype == 'upper-roman' || $type == 'I') {

			$ppgno = $decToRoman->convert($ppgno, true);

		} elseif ($lowertype == 'lower-roman' || $type == 'i') {

			$ppgno = $decToRoman->convert($ppgno, false);

		} elseif ($lowertype == 'hebrew') {

			$ppgno = $decToHebrew->convert($ppgno, $reverse);

		} elseif (preg_match('/(arabic-indic|bengali|devanagari|gujarati|gurmukhi|kannada|malayalam|oriya|persian|tamil|telugu|thai|urdu|cambodian|khmer|lao|myanmar)/i', $lowertype, $m)) {

			$cp = $decToOther->getCodePage($m[1]);
			$ppgno = $decToOther->convert($ppgno, $cp, $checkfont);

		} elseif ($lowertype == 'cjk-decimal') {

			$ppgno = $decToCjk->convert($ppgno);

		}

		return $ppgno;
	}

	function docPageSettings($num = 0)
	{
		// Returns current type (numberstyle), suppression state for this page number;
		// reset is only returned if set for this page number
		if ($num < 1) {
			$num = $this->page;
		}

		$type = $this->defaultPageNumStyle; // set default Page Number Style
		$ppgno = $num;
		$suppress = 0;
		$offset = 0;
		$reset = '';

		foreach ($this->PageNumSubstitutions as $psarr) {
			if ($num >= $psarr['from']) {
				if ($psarr['reset']) {
					if ($psarr['reset'] > 1) {
						$offset = $psarr['reset'] - 1;
					}
					$ppgno = $num - $psarr['from'] + 1 + $offset;
				}
				if ($psarr['type']) {
					$type = $psarr['type'];
				}
				if (strtoupper($psarr['suppress']) == 'ON' || $psarr['suppress'] == 1) {
					$suppress = 1;
				} elseif (strtoupper($psarr['suppress']) == 'OFF') {
					$suppress = 0;
				}
			}
			if ($num == $psarr['from']) {
				$reset = $psarr['reset'];
			}
		}

		if ($suppress) {
			$suppress = 'on';
		} else {
			$suppress = 'off';
		}

		return [$type, $suppress, $reset];
	}

	function RestartDocTemplate()
	{
		$this->docTemplateStart = $this->page;
	}

	// Page header
	function Header($content = '')
	{

		$this->cMarginL = 0;
		$this->cMarginR = 0;


		if (($this->mirrorMargins && ($this->page % 2 == 0) && $this->HTMLHeaderE) || ($this->mirrorMargins && ($this->page % 2 == 1) && $this->HTMLHeader) || (!$this->mirrorMargins && $this->HTMLHeader)) {
			$this->writeHTMLHeaders();
			return;
		}
	}

	/* -- TABLES -- */
	function TableHeaderFooter($content = '', $tablestartpage = '', $tablestartcolumn = '', $horf = 'H', $level = 0, $firstSpread = true, $finalSpread = true)
	{
		if (($horf == 'H' || $horf == 'F') && !empty($content)) { // mPDF 5.7.2
			$table = &$this->table[1][1];

			// mPDF 5.7.2
			if ($horf == 'F') { // Table Footer
				$firstrow = count($table['cells']) - $table['footernrows'];
				$lastrow = count($table['cells']) - 1;
			} else {  // Table Header
				$firstrow = 0;
				$lastrow = $table['headernrows'] - 1;
			}
			if (empty($content[$firstrow])) {
				if ($this->debug) {
					throw new \Mpdf\MpdfException("<tfoot> must precede <tbody> in a table");
				} else {
					return;
				}
			}


			// Advance down page by half width of top border
			if ($horf == 'H') { // Only if header
				if ($table['borders_separate']) {
					$adv = $table['border_spacing_V'] / 2 + $table['border_details']['T']['w'] + $table['padding']['T'];
				} else {
					$adv = $table['max_cell_border_width']['T'] / 2;
				}
				if ($adv) {
					if ($this->table_rotate) {
						$this->y += ($adv);
					} else {
						$this->DivLn($adv, $this->blklvl, true);
					}
				}
			}

			$topy = $content[$firstrow][0]['y'] - $this->y;

			for ($i = $firstrow; $i <= $lastrow; $i++) {
				$y = $this->y;

				/* -- COLUMNS -- */
				// If outside columns, this is done in PaintDivBB
				if ($this->ColActive) {
					// OUTER FILL BGCOLOR of DIVS
					if ($this->blklvl > 0) {
						$firstblockfill = $this->GetFirstBlockFill();
						if ($firstblockfill && $this->blklvl >= $firstblockfill) {
							$divh = $content[$i][0]['h'];
							$bak_x = $this->x;
							$this->DivLn($divh, -3, false);
							// Reset current block fill
							$bcor = $this->blk[$this->blklvl]['bgcolorarray'];
							$this->SetFColor($bcor);
							$this->x = $bak_x;
						}
					}
				}
				/* -- END COLUMNS -- */

				$colctr = 0;
				foreach ($content[$i] as $tablehf) {
					$colctr++;
					$y = Arrays::get($tablehf, 'y', null) - $topy;
					$this->y = $y;
					// Set some cell values
					$x = Arrays::get($tablehf, 'x', null);
					if (($this->mirrorMargins) && ($tablestartpage == 'ODD') && (($this->page) % 2 == 0)) { // EVEN
						$x = $x + $this->MarginCorrection;
					} elseif (($this->mirrorMargins) && ($tablestartpage == 'EVEN') && (($this->page) % 2 == 1)) { // ODD
						$x = $x + $this->MarginCorrection;
					}
					/* -- COLUMNS -- */
					// Added to correct for Columns
					if ($this->ColActive) {
						if ($this->directionality == 'rtl') { // *OTL*
							$x -= ($this->CurrCol - $tablestartcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
						} // *OTL*
						else { // *OTL*
							$x += ($this->CurrCol - $tablestartcolumn) * ($this->ColWidth + $this->ColGap);
						} // *OTL*
					}
					/* -- END COLUMNS -- */

					if ($colctr == 1) {
						$x0 = $x;
					}

					// mPDF ITERATION
					if ($this->iterationCounter) {
						foreach ($tablehf['textbuffer'] as $k => $t) {
							if (!is_array($t[0]) && preg_match('/{iteration ([a-zA-Z0-9_]+)}/', $t[0], $m)) {
								$vname = '__' . $m[1] . '_';
								if (!isset($this->$vname)) {
									$this->$vname = 1;
								} else {
									$this->$vname++;
								}
								$tablehf['textbuffer'][$k][0] = preg_replace('/{iteration ' . $m[1] . '}/', $this->$vname, $tablehf['textbuffer'][$k][0]);
							}
						}
					}

					$w = Arrays::get($tablehf, 'w', null);
					$h = Arrays::get($tablehf, 'h', null);
					$va = Arrays::get($tablehf, 'va', null);
					$R = Arrays::get($tablehf, 'R', null);
					$direction = Arrays::get($tablehf, 'direction', null);
					$mih = Arrays::get($tablehf, 'mih', null);
					$border = Arrays::get($tablehf, 'border', null);
					$border_details = Arrays::get($tablehf, 'border_details', null);
					$padding = Arrays::get($tablehf, 'padding', null);
					$this->tabletheadjustfinished = true;

					$textbuffer = Arrays::get($tablehf, 'textbuffer', null);

					// Align
					$align = Arrays::get($tablehf, 'a', null);
					$this->cellTextAlign = $align;

					$this->cellLineHeight = Arrays::get($tablehf, 'cellLineHeight', null);
					$this->cellLineStackingStrategy = Arrays::get($tablehf, 'cellLineStackingStrategy', null);
					$this->cellLineStackingShift = Arrays::get($tablehf, 'cellLineStackingShift', null);

					$this->x = $x;

					if ($this->ColActive) {
						if ($table['borders_separate']) {
							$tablefill = isset($table['bgcolor'][-1]) ? $table['bgcolor'][-1] : 0;
							if ($tablefill) {
								$color = $this->colorConverter->convert($tablefill, $this->PDFAXwarnings);
								if ($color) {
									$xadj = ($table['border_spacing_H'] / 2);
									$yadj = ($table['border_spacing_V'] / 2);
									$wadj = $table['border_spacing_H'];
									$hadj = $table['border_spacing_V'];
									if ($i == $firstrow && $horf == 'H') {  // Top
										$yadj += $table['padding']['T'] + $table['border_details']['T']['w'];
										$hadj += $table['padding']['T'] + $table['border_details']['T']['w'];
									}
									if (($i == ($lastrow) || (isset($tablehf['rowspan']) && ($i + $tablehf['rowspan']) == ($lastrow + 1)) || (!isset($tablehf['rowspan']) && ($i + 1) == ($lastrow + 1))) && $horf == 'F') { // Bottom
										$hadj += $table['padding']['B'] + $table['border_details']['B']['w'];
									}
									if ($colctr == 1) {  // Left
										$xadj += $table['padding']['L'] + $table['border_details']['L']['w'];
										$wadj += $table['padding']['L'] + $table['border_details']['L']['w'];
									}
									if ($colctr == count($content[$i])) { // Right
										$wadj += $table['padding']['R'] + $table['border_details']['R']['w'];
									}
									$this->SetFColor($color);
									$this->Rect($x - $xadj, $y - $yadj, $w + $wadj, $h + $hadj, 'F');
								}
							}
						}
					}

					if ($table['empty_cells'] != 'hide' || !empty($textbuffer) || !$table['borders_separate']) {
						$paintcell = true;
					} else {
						$paintcell = false;
					}

					// Vertical align
					if ($R && intval($R) > 0 && isset($va) && $va != 'B') {
						$va = 'B';
					}

					if (!isset($va) || empty($va) || $va == 'M') {
						$this->y += ($h - $mih) / 2;
					} elseif (isset($va) && $va == 'B') {
						$this->y += $h - $mih;
					}


					// TABLE ROW OR CELL FILL BGCOLOR
					$fill = 0;
					if (isset($tablehf['bgcolor']) && $tablehf['bgcolor'] && $tablehf['bgcolor'] != 'transparent') {
						$fill = $tablehf['bgcolor'];
						$leveladj = 6;
					} elseif (isset($content[$i][0]['trbgcolor']) && $content[$i][0]['trbgcolor'] && $content[$i][0]['trbgcolor'] != 'transparent') { // Row color
						$fill = $content[$i][0]['trbgcolor'];
						$leveladj = 3;
					}
					if ($fill && $paintcell) {
						$color = $this->colorConverter->convert($fill, $this->PDFAXwarnings);
						if ($color) {
							if ($table['borders_separate']) {
								if ($this->ColActive) {
									$this->SetFColor($color);
									$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');
								} else {
									$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];
								}
							} else {
								if ($this->ColActive) {
									$this->SetFColor($color);
									$this->Rect($x, $y, $w, $h, 'F');
								} else {
									$this->tableBackgrounds[$level * 9 + $leveladj][] = ['gradient' => false, 'x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'col' => $color];
								}
							}
						}
					}


					/* -- BACKGROUNDS -- */
					if (isset($tablehf['gradient']) && $tablehf['gradient'] && $paintcell) {
						$g = $this->gradient->parseBackgroundGradient($tablehf['gradient']);
						if ($g) {
							if ($table['borders_separate']) {
								$px = $x + ($table['border_spacing_H'] / 2);
								$py = $y + ($table['border_spacing_V'] / 2);
								$pw = $w - $table['border_spacing_H'];
								$ph = $h - $table['border_spacing_V'];
							} else {
								$px = $x;
								$py = $y;
								$pw = $w;
								$ph = $h;
							}
							if ($this->ColActive) {
								$this->gradient->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
							} else {
								$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' => ''];
							}
						}
					}

					if (isset($tablehf['background-image']) && $paintcell) {
						if ($tablehf['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $tablehf['background-image']['gradient'])) {
							$g = $this->gradient->parseMozGradient($tablehf['background-image']['gradient']);
							if ($g) {
								if ($table['borders_separate']) {
									$px = $x + ($table['border_spacing_H'] / 2);
									$py = $y + ($table['border_spacing_V'] / 2);
									$pw = $w - $table['border_spacing_H'];
									$ph = $h - $table['border_spacing_V'];
								} else {
									$px = $x;
									$py = $y;
									$pw = $w;
									$ph = $h;
								}
								if ($this->ColActive) {
									$this->gradient->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
								} else {
									$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' => ''];
								}
							}
						} elseif ($tablehf['background-image']['image_id']) { // Background pattern
							$n = count($this->patterns) + 1;
							if ($table['borders_separate']) {
								$px = $x + ($table['border_spacing_H'] / 2);
								$py = $y + ($table['border_spacing_V'] / 2);
								$pw = $w - $table['border_spacing_H'];
								$ph = $h - $table['border_spacing_V'];
							} else {
								$px = $x;
								$py = $y;
								$pw = $w;
								$ph = $h;
							}
							if ($this->ColActive) {
								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']);
								$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']];
								if ($tablehf['background-image']['opacity'] > 0 && $tablehf['background-image']['opacity'] < 1) {
									$opac = $this->SetAlpha($tablehf['background-image']['opacity'], 'Normal', true);
								} else {
									$opac = '';
								}
								$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));
							} else {
								$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']];
							}
						}
					}
					/* -- END BACKGROUNDS -- */

					// Cell Border
					if ($table['borders_separate'] && $paintcell && $border) {
						$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']);
					} elseif ($paintcell && $border) {
						$this->_tableRect($x, $y, $w, $h, $border, $border_details, true, $table['borders_separate']);   // true causes buffer
					}

					// Print cell content
					if (!empty($textbuffer)) {
						if ($horf == 'F' && preg_match('/{colsum([0-9]*)[_]*}/', $textbuffer[0][0], $m)) {
							$rep = sprintf("%01." . intval($m[1]) . "f", $this->colsums[$colctr - 1]);
							$textbuffer[0][0] = preg_replace('/{colsum[0-9_]*}/', $rep, $textbuffer[0][0]);
						}

						if ($R) {
							$cellPtSize = $textbuffer[0][11] / $this->shrin_k;
							if (!$cellPtSize) {
								$cellPtSize = $this->default_font_size;
							}
							$cellFontHeight = ($cellPtSize / Mpdf::SCALE);
							$opx = $this->x;
							$opy = $this->y;
							$angle = intval($R);

							// Only allow 45 - 90 degrees (when bottom-aligned) or -90
							if ($angle > 90) {
								$angle = 90;
							} elseif ($angle > 0 && (isset($va) && $va != 'B')) {
								$angle = 90;
							} elseif ($angle > 0 && $angle < 45) {
								$angle = 45;
							} elseif ($angle < 0) {
								$angle = -90;
							}

							$offset = ((sin(deg2rad($angle))) * 0.37 * $cellFontHeight);
							if (isset($align) && $align == 'R') {
								$this->x += ($w) + ($offset) - ($cellFontHeight / 3) - ($padding['R'] + $border_details['R']['w']);
							} elseif (!isset($align) || $align == 'C') {
								$this->x += ($w / 2) + ($offset);
							} else {
								$this->x += ($offset) + ($cellFontHeight / 3) + ($padding['L'] + $border_details['L']['w']);
							}
							$str = '';
							foreach ($tablehf['textbuffer'] as $t) {
								$str .= $t[0] . ' ';
							}
							$str = rtrim($str);

							if (!isset($va) || $va == 'M') {
								$this->y -= ($h - $mih) / 2; // Undo what was added earlier VERTICAL ALIGN
								if ($angle > 0) {
									$this->y += (($h - $mih) / 2) + ($padding['T'] + $border_details['T']['w']) + ($mih - ($padding['T'] + $border_details['T']['w'] + $border_details['B']['w'] + $padding['B']));
								} elseif ($angle < 0) {
									$this->y += (($h - $mih) / 2) + ($padding['T'] + $border_details['T']['w']);
								}
							} elseif (isset($va) && $va == 'B') {
								$this->y -= $h - $mih; // Undo what was added earlier VERTICAL ALIGN
								if ($angle > 0) {
									$this->y += $h - ($border_details['B']['w'] + $padding['B']);
								} elseif ($angle < 0) {
									$this->y += $h - $mih + ($padding['T'] + $border_details['T']['w']);
								}
							} elseif (isset($va) && $va == 'T') {
								if ($angle > 0) {
									$this->y += $mih - ($border_details['B']['w'] + $padding['B']);
								} elseif ($angle < 0) {
									$this->y += ($padding['T'] + $border_details['T']['w']);
								}
							}

							$this->Rotate($angle, $this->x, $this->y);
							$s_fs = $this->FontSizePt;
							$s_f = $this->FontFamily;
							$s_st = $this->FontStyle;
							if (!empty($textbuffer[0][3])) { // Font Color
								$cor = $textbuffer[0][3];
								$this->SetTColor($cor);
							}
							$this->SetFont($textbuffer[0][4], $textbuffer[0][2], $cellPtSize, true, true);

							$this->magic_reverse_dir($str, $this->directionality, $textbuffer[0][18]);
							$this->Text($this->x, $this->y, $str, $textbuffer[0][18], $textbuffer[0][8]); // textvar
							$this->Rotate(0);
							$this->SetFont($s_f, $s_st, $s_fs, true, true);
							$this->SetTColor(0);
							$this->x = $opx;
							$this->y = $opy;
						} else {
							if ($table['borders_separate']) { // NB twice border width
								$xadj = $border_details['L']['w'] + $padding['L'] + ($table['border_spacing_H'] / 2);
								$wadj = $border_details['L']['w'] + $border_details['R']['w'] + $padding['L'] + $padding['R'] + $table['border_spacing_H'];
								$yadj = $border_details['T']['w'] + $padding['T'] + ($table['border_spacing_H'] / 2);
							} else {
								$xadj = $border_details['L']['w'] / 2 + $padding['L'];
								$wadj = ($border_details['L']['w'] + $border_details['R']['w']) / 2 + $padding['L'] + $padding['R'];
								$yadj = $border_details['T']['w'] / 2 + $padding['T'];
							}

							$this->divwidth = $w - ($wadj);
							$this->x += $xadj;
							$this->y += $yadj;
							$this->printbuffer($textbuffer, '', true, false, $direction);
						}
					}
					$textbuffer = [];

					/* -- BACKGROUNDS -- */
					if (!$this->ColActive) {
						if (isset($content[$i][0]['trgradients']) && ($colctr == 1 || $table['borders_separate'])) {
							$g = $this->gradient->parseBackgroundGradient($content[$i][0]['trgradients']);
							if ($g) {
								$gx = $x0;
								$gy = $y;
								$gh = $h;
								$gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
								if ($table['borders_separate']) {
									$gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
									$clx = $x + ($table['border_spacing_H'] / 2);
									$cly = $y + ($table['border_spacing_V'] / 2);
									$clw = $w - $table['border_spacing_H'];
									$clh = $h - $table['border_spacing_V'];
									// Set clipping path
									$s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
									$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];
								} else {
									$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' => ''];
								}
							}
						}

						if (isset($content[$i][0]['trbackground-images']) && ($colctr == 1 || $table['borders_separate'])) {
							if ($content[$i][0]['trbackground-images']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $content[$i][0]['trbackground-images']['gradient'])) {
								$g = $this->gradient->parseMozGradient($content[$i][0]['trbackground-images']['gradient']);
								if ($g) {
									$gx = $x0;
									$gy = $y;
									$gh = $h;
									$gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
									if ($table['borders_separate']) {
										$gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
										$clx = $x + ($table['border_spacing_H'] / 2);
										$cly = $y + ($table['border_spacing_V'] / 2);
										$clw = $w - $table['border_spacing_H'];
										$clh = $h - $table['border_spacing_V'];
										// Set clipping path
										$s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
										$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];
									} else {
										$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' => ''];
									}
								}
							} else {
								$image_id = $content[$i][0]['trbackground-images']['image_id'];
								$orig_w = $content[$i][0]['trbackground-images']['orig_w'];
								$orig_h = $content[$i][0]['trbackground-images']['orig_h'];
								$x_pos = $content[$i][0]['trbackground-images']['x_pos'];
								$y_pos = $content[$i][0]['trbackground-images']['y_pos'];
								$x_repeat = $content[$i][0]['trbackground-images']['x_repeat'];
								$y_repeat = $content[$i][0]['trbackground-images']['y_repeat'];
								$resize = $content[$i][0]['trbackground-images']['resize'];
								$opacity = $content[$i][0]['trbackground-images']['opacity'];
								$itype = $content[$i][0]['trbackground-images']['itype'];

								$clippath = '';
								$gx = $x0;
								$gy = $y;
								$gh = $h;
								$gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
								if ($table['borders_separate']) {
									$gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
									$clx = $x + ($table['border_spacing_H'] / 2);
									$cly = $y + ($table['border_spacing_V'] / 2);
									$clw = $w - $table['border_spacing_H'];
									$clh = $h - $table['border_spacing_V'];
									// Set clipping path
									$s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
									$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];
								} else {
									$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];
								}
							}
						}
					}
					/* -- END BACKGROUNDS -- */

					// TABLE BORDER - if separate OR collapsed and only table border
					if (($table['borders_separate'] || ($this->simpleTables && !$table['simple']['border'])) && $table['border']) {
						$halfspaceL = $table['padding']['L'] + ($table['border_spacing_H'] / 2);
						$halfspaceR = $table['padding']['R'] + ($table['border_spacing_H'] / 2);
						$halfspaceT = $table['padding']['T'] + ($table['border_spacing_V'] / 2);
						$halfspaceB = $table['padding']['B'] + ($table['border_spacing_V'] / 2);
						$tbx = $x;
						$tby = $y;
						$tbw = $w;
						$tbh = $h;
						$tab_bord = 0;
						$corner = '';
						if ($i == $firstrow && $horf == 'H') {  // Top
							$tby -= $halfspaceT + ($table['border_details']['T']['w'] / 2);
							$tbh += $halfspaceT + ($table['border_details']['T']['w'] / 2);
							$this->setBorder($tab_bord, Border::TOP);
							$corner .= 'T';
						}
						if (($i == ($lastrow) || (isset($tablehf['rowspan']) && ($i + $tablehf['rowspan']) == ($lastrow + 1))) && $horf == 'F') { // Bottom
							$tbh += $halfspaceB + ($table['border_details']['B']['w'] / 2);
							$this->setBorder($tab_bord, Border::BOTTOM);
							$corner .= 'B';
						}
						if ($colctr == 1 && $firstSpread) { // Left
							$tbx -= $halfspaceL + ($table['border_details']['L']['w'] / 2);
							$tbw += $halfspaceL + ($table['border_details']['L']['w'] / 2);
							$this->setBorder($tab_bord, Border::LEFT);
							$corner .= 'L';
						}
						if ($colctr == count($content[$i]) && $finalSpread) { // Right
							$tbw += $halfspaceR + ($table['border_details']['R']['w'] / 2);
							$this->setBorder($tab_bord, Border::RIGHT);
							$corner .= 'R';
						}
						$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']);
					}
				}// end column $content
				$this->y = $y + $h; // Update y coordinate
			}// end row $i
			unset($table);
			$this->colsums = [];
		}
	}

	/* -- END TABLES -- */

	function SetHTMLHeader($header = '', $OE = '', $write = false)
	{

		$height = 0;
		if (is_array($header) && isset($header['html']) && $header['html']) {
			$Hhtml = $header['html'];
			if ($this->setAutoTopMargin) {
				if (isset($header['h'])) {
					$height = $header['h'];
				} else {
					$height = $this->_getHtmlHeight($Hhtml);
				}
			}
		} elseif (!is_array($header) && $header) {
			$Hhtml = $header;
			if ($this->setAutoTopMargin) {
				$height = $this->_getHtmlHeight($Hhtml);
			}
		} else {
			$Hhtml = '';
		}

		if ($OE !== 'E') {
			$OE = 'O';
		}

		if ($OE === 'E') {
			if ($Hhtml) {
				$this->HTMLHeaderE = [];
				$this->HTMLHeaderE['html'] = $Hhtml;
				$this->HTMLHeaderE['h'] = $height;
			} else {
				$this->HTMLHeaderE = '';
			}
		} else {
			if ($Hhtml) {
				$this->HTMLHeader = [];
				$this->HTMLHeader['html'] = $Hhtml;
				$this->HTMLHeader['h'] = $height;
			} else {
				$this->HTMLHeader = '';
			}
		}

		if (!$this->mirrorMargins && $OE == 'E') {
			return;
		}
		if ($Hhtml == '') {
			return;
		}

		if ($this->setAutoTopMargin == 'pad') {
			$this->tMargin = $this->margin_header + $height + $this->orig_tMargin;
			if (isset($this->saveHTMLHeader[$this->page][$OE]['mt'])) {
				$this->saveHTMLHeader[$this->page][$OE]['mt'] = $this->tMargin;
			}
		} elseif ($this->setAutoTopMargin == 'stretch') {
			$this->tMargin = max($this->orig_tMargin, $this->margin_header + $height + $this->autoMarginPadding);
			if (isset($this->saveHTMLHeader[$this->page][$OE]['mt'])) {
				$this->saveHTMLHeader[$this->page][$OE]['mt'] = $this->tMargin;
			}
		}
		if ($write && $this->state != 0 && (($this->mirrorMargins && $OE == 'E' && ($this->page) % 2 == 0) || ($this->mirrorMargins && $OE != 'E' && ($this->page) % 2 == 1) || !$this->mirrorMargins)) {
			$this->writeHTMLHeaders();
		}
	}

	function SetHTMLFooter($footer = '', $OE = '')
	{
		$height = 0;
		if (is_array($footer) && isset($footer['html']) && $footer['html']) {
			$Fhtml = $footer['html'];
			if ($this->setAutoBottomMargin) {
				if (isset($footer['h'])) {
					$height = $footer['h'];
				} else {
					$height = $this->_getHtmlHeight($Fhtml);
				}
			}
		} elseif (!is_array($footer) && $footer) {
			$Fhtml = $footer;
			if ($this->setAutoBottomMargin) {
				$height = $this->_getHtmlHeight($Fhtml);
			}
		} else {
			$Fhtml = '';
		}

		if ($OE !== 'E') {
			$OE = 'O';
		}

		if ($OE === 'E') {
			if ($Fhtml) {
				$this->HTMLFooterE = [];
				$this->HTMLFooterE['html'] = $Fhtml;
				$this->HTMLFooterE['h'] = $height;
			} else {
				$this->HTMLFooterE = '';
			}
		} else {
			if ($Fhtml) {
				$this->HTMLFooter = [];
				$this->HTMLFooter['html'] = $Fhtml;
				$this->HTMLFooter['h'] = $height;
			} else {
				$this->HTMLFooter = '';
			}
		}

		if (!$this->mirrorMargins && $OE == 'E') {
			return;
		}

		if ($Fhtml == '') {
			return false;
		}

		if ($this->setAutoBottomMargin == 'pad') {
			$this->bMargin = $this->margin_footer + $height + $this->orig_bMargin;
			$this->PageBreakTrigger = $this->h - $this->bMargin;
			if (isset($this->saveHTMLHeader[$this->page][$OE]['mb'])) {
				$this->saveHTMLHeader[$this->page][$OE]['mb'] = $this->bMargin;
			}
		} elseif ($this->setAutoBottomMargin == 'stretch') {
			$this->bMargin = max($this->orig_bMargin, $this->margin_footer + $height + $this->autoMarginPadding);
			$this->PageBreakTrigger = $this->h - $this->bMargin;
			if (isset($this->saveHTMLHeader[$this->page][$OE]['mb'])) {
				$this->saveHTMLHeader[$this->page][$OE]['mb'] = $this->bMargin;
			}
		}
	}

	function _getHtmlHeight($html)
	{
		$save_state = $this->state;
		if ($this->state == 0) {
			$this->AddPage($this->CurOrientation);
		}
		$this->state = 2;
		$this->Reset();
		$this->pageoutput[$this->page] = [];
		$save_x = $this->x;
		$save_y = $this->y;
		$this->x = $this->lMargin;
		$this->y = $this->margin_header;

		// Replace of page number aliases and date format
		$pnstr = $this->pagenumPrefix . $this->docPageNum($this->page) . $this->pagenumSuffix;
		$pntstr = $this->nbpgPrefix . $this->docPageNumTotal($this->page) . $this->nbpgSuffix;
		$nb = $this->page;
		$html = $this->aliasReplace($html, $pnstr, $pntstr, $nb);

		$this->HTMLheaderPageLinks = [];
		$this->HTMLheaderPageAnnots = [];
		$this->HTMLheaderPageForms = [];
		$savepb = $this->pageBackgrounds;
		$this->writingHTMLheader = true;
		$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
		$this->writingHTMLheader = false;
		$h = ($this->y - $this->margin_header);
		$this->Reset();

		// mPDF 5.7.2 - Clear in case Float used in Header/Footer
		$this->blk[0]['blockContext'] = 0;
		$this->blk[0]['float_endpos'] = 0;

		$this->pageoutput[$this->page] = [];
		$this->headerbuffer = '';
		$this->pageBackgrounds = $savepb;
		$this->x = $save_x;
		$this->y = $save_y;
		$this->state = $save_state;

		if ($save_state == 0) {
			unset($this->pages[1]);
			$this->page = 0;
		}
		return $h;
	}

	// Called internally from Header
	function writeHTMLHeaders()
	{

		if ($this->mirrorMargins && ($this->page) % 2 == 0) {
			$OE = 'E';
		} else {
			$OE = 'O';
		}

		if ($OE === 'E') {
			$this->saveHTMLHeader[$this->page][$OE]['html'] = $this->HTMLHeaderE['html'];
		} else {
			$this->saveHTMLHeader[$this->page][$OE]['html'] = $this->HTMLHeader['html'];
		}

		if ($this->forcePortraitHeaders && $this->CurOrientation == 'L' && $this->CurOrientation != $this->DefOrientation) {
			$this->saveHTMLHeader[$this->page][$OE]['rotate'] = true;
			$this->saveHTMLHeader[$this->page][$OE]['ml'] = $this->tMargin;
			$this->saveHTMLHeader[$this->page][$OE]['mr'] = $this->bMargin;
			$this->saveHTMLHeader[$this->page][$OE]['mh'] = $this->margin_header;
			$this->saveHTMLHeader[$this->page][$OE]['mf'] = $this->margin_footer;
			$this->saveHTMLHeader[$this->page][$OE]['pw'] = $this->h;
			$this->saveHTMLHeader[$this->page][$OE]['ph'] = $this->w;
		} else {
			$this->saveHTMLHeader[$this->page][$OE]['ml'] = $this->lMargin;
			$this->saveHTMLHeader[$this->page][$OE]['mr'] = $this->rMargin;
			$this->saveHTMLHeader[$this->page][$OE]['mh'] = $this->margin_header;
			$this->saveHTMLHeader[$this->page][$OE]['mf'] = $this->margin_footer;
			$this->saveHTMLHeader[$this->page][$OE]['pw'] = $this->w;
			$this->saveHTMLHeader[$this->page][$OE]['ph'] = $this->h;
		}
	}

	function writeHTMLFooters()
	{

		if ($this->mirrorMargins && ($this->page) % 2 == 0) {
			$OE = 'E';
		} else {
			$OE = 'O';
		}

		if ($OE === 'E') {
			$this->saveHTMLFooter[$this->page][$OE]['html'] = $this->HTMLFooterE['html'];
		} else {
			$this->saveHTMLFooter[$this->page][$OE]['html'] = $this->HTMLFooter['html'];
		}

		if ($this->forcePortraitHeaders && $this->CurOrientation == 'L' && $this->CurOrientation != $this->DefOrientation) {
			$this->saveHTMLFooter[$this->page][$OE]['rotate'] = true;
			$this->saveHTMLFooter[$this->page][$OE]['ml'] = $this->tMargin;
			$this->saveHTMLFooter[$this->page][$OE]['mr'] = $this->bMargin;
			$this->saveHTMLFooter[$this->page][$OE]['mt'] = $this->rMargin;
			$this->saveHTMLFooter[$this->page][$OE]['mb'] = $this->lMargin;
			$this->saveHTMLFooter[$this->page][$OE]['mh'] = $this->margin_header;
			$this->saveHTMLFooter[$this->page][$OE]['mf'] = $this->margin_footer;
			$this->saveHTMLFooter[$this->page][$OE]['pw'] = $this->h;
			$this->saveHTMLFooter[$this->page][$OE]['ph'] = $this->w;
		} else {
			$this->saveHTMLFooter[$this->page][$OE]['ml'] = $this->lMargin;
			$this->saveHTMLFooter[$this->page][$OE]['mr'] = $this->rMargin;
			$this->saveHTMLFooter[$this->page][$OE]['mt'] = $this->tMargin;
			$this->saveHTMLFooter[$this->page][$OE]['mb'] = $this->bMargin;
			$this->saveHTMLFooter[$this->page][$OE]['mh'] = $this->margin_header;
			$this->saveHTMLFooter[$this->page][$OE]['mf'] = $this->margin_footer;
			$this->saveHTMLFooter[$this->page][$OE]['pw'] = $this->w;
			$this->saveHTMLFooter[$this->page][$OE]['ph'] = $this->h;
		}
	}

	// mPDF 6
	function _shareHeaderFooterWidth($cl, $cc, $cr)
	{
	// mPDF 6
		$l = mb_strlen($cl, 'UTF-8');
		$c = mb_strlen($cc, 'UTF-8');
		$r = mb_strlen($cr, 'UTF-8');
		$s = max($l, $r);
		$tw = $c + 2 * $s;
		if ($tw > 0) {
			return [intval($s * 100 / $tw), intval($c * 100 / $tw), intval($s * 100 / $tw)];
		} else {
			return [33, 33, 33];
		}
	}

	// mPDF 6
	// Create an HTML header/footer from array (non-HTML header/footer)
	function _createHTMLheaderFooter($arr, $hf)
	{
		$lContent = (isset($arr['L']['content']) ? $arr['L']['content'] : '');
		$cContent = (isset($arr['C']['content']) ? $arr['C']['content'] : '');
		$rContent = (isset($arr['R']['content']) ? $arr['R']['content'] : '');

		list($lw, $cw, $rw) = $this->_shareHeaderFooterWidth($lContent, $cContent, $rContent);

		if ($hf == 'H') {
			$valign = 'bottom';
			$vpadding = '0 0 ' . $this->header_line_spacing . 'em 0';
		} else {
			$valign = 'top';
			$vpadding = '' . $this->footer_line_spacing . 'em 0 0 0';
		}

		if ($this->directionality == 'rtl') { // table columns get reversed so need different text-alignment
			$talignL = 'right';
			$talignR = 'left';
		} else {
			$talignL = 'left';
			$talignR = 'right';
		}

		$html = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: ' . $valign . '; color: #000000; ';

		if (isset($arr['line']) && $arr['line']) {
			$html .= ' border-' . $valign . ': 0.1mm solid #000000;';
		}

		$html .= '">';
		$html .= '<tr>';
		$html .= '<td width="' . $lw . '%" style="padding: ' . $vpadding . '; text-align: ' . $talignL . '; ';

		if (isset($arr['L']['font-family'])) {
			$html .= ' font-family: ' . $arr['L']['font-family'] . ';';
		}

		if (isset($arr['L']['color'])) {
			$html .= ' color: ' . $arr['L']['color'] . ';';
		}

		if (isset($arr['L']['font-size'])) {
			$html .= ' font-size: ' . $arr['L']['font-size'] . 'pt;';
		}

		if (isset($arr['L']['font-style'])) {
			if ($arr['L']['font-style'] == 'B' || $arr['L']['font-style'] == 'BI') {
				$html .= ' font-weight: bold;';
			}
			if ($arr['L']['font-style'] == 'I' || $arr['L']['font-style'] == 'BI') {
				$html .= ' font-style: italic;';
			}
		}

		$html .= '">' . $lContent . '</td>';
		$html .= '<td width="' . $cw . '%" style="padding: ' . $vpadding . '; text-align: center; ';

		if (isset($arr['C']['font-family'])) {
			$html .= ' font-family: ' . $arr['C']['font-family'] . ';';
		}

		if (isset($arr['C']['color'])) {
			$html .= ' color: ' . $arr['C']['color'] . ';';
		}

		if (isset($arr['C']['font-size'])) {
			$html .= ' font-size: ' . $arr['C']['font-size'] . 'pt;';
		}

		if (isset($arr['C']['font-style'])) {
			if ($arr['C']['font-style'] == 'B' || $arr['C']['font-style'] == 'BI') {
				$html .= ' font-weight: bold;';
			}
			if ($arr['C']['font-style'] == 'I' || $arr['C']['font-style'] == 'BI') {
				$html .= ' font-style: italic;';
			}
		}

		$html .= '">' . $cContent . '</td>';
		$html .= '<td width="' . $rw . '%" style="padding: ' . $vpadding . '; text-align: ' . $talignR . '; ';

		if (isset($arr['R']['font-family'])) {
			$html .= ' font-family: ' . $arr['R']['font-family'] . ';';
		}

		if (isset($arr['R']['color'])) {
			$html .= ' color: ' . $arr['R']['color'] . ';';
		}

		if (isset($arr['R']['font-size'])) {
			$html .= ' font-size: ' . $arr['R']['font-size'] . 'pt;';
		}

		if (isset($arr['R']['font-style'])) {
			if ($arr['R']['font-style'] == 'B' || $arr['R']['font-style'] == 'BI') {
				$html .= ' font-weight: bold;';
			}
			if ($arr['R']['font-style'] == 'I' || $arr['R']['font-style'] == 'BI') {
				$html .= ' font-style: italic;';
			}
		}

		$html .= '">' . $rContent . '</td>';
		$html .= '</tr></table>';

		return $html;
	}

	function DefHeaderByName($name, $arr)
	{
		if (!$name) {
			$name = '_nonhtmldefault';
		}
		$html = $this->_createHTMLheaderFooter($arr, 'H');

		$this->pageHTMLheaders[$name]['html'] = $html;
		$this->pageHTMLheaders[$name]['h'] = $this->_getHtmlHeight($html);
	}

	function DefFooterByName($name, $arr)
	{
		if (!$name) {
			$name = '_nonhtmldefault';
		}
		$html = $this->_createHTMLheaderFooter($arr, 'F');

		$this->pageHTMLfooters[$name]['html'] = $html;
		$this->pageHTMLfooters[$name]['h'] = $this->_getHtmlHeight($html);
	}

	function SetHeaderByName($name, $side = 'O', $write = false)
	{
		if (!$name) {
			$name = '_nonhtmldefault';
		}
		$this->SetHTMLHeader($this->pageHTMLheaders[$name], $side, $write);
	}

	function SetFooterByName($name, $side = 'O')
	{
		if (!$name) {
			$name = '_nonhtmldefault';
		}
		$this->SetHTMLFooter($this->pageHTMLfooters[$name], $side);
	}

	function DefHTMLHeaderByName($name, $html)
	{
		if (!$name) {
			$name = '_default';
		}

		$this->pageHTMLheaders[$name]['html'] = $html;
		$this->pageHTMLheaders[$name]['h'] = $this->_getHtmlHeight($html);
	}

	function DefHTMLFooterByName($name, $html)
	{
		if (!$name) {
			$name = '_default';
		}

		$this->pageHTMLfooters[$name]['html'] = $html;
		$this->pageHTMLfooters[$name]['h'] = $this->_getHtmlHeight($html);
	}

	function SetHTMLHeaderByName($name, $side = 'O', $write = false)
	{
		if (!$name) {
			$name = '_default';
		}
		$this->SetHTMLHeader($this->pageHTMLheaders[$name], $side, $write);
	}

	function SetHTMLFooterByName($name, $side = 'O')
	{
		if (!$name) {
			$name = '_default';
		}
		$this->SetHTMLFooter($this->pageHTMLfooters[$name], $side);
	}

	function SetHeader($Harray = [], $side = '', $write = false)
	{
		$oddhtml = '';
		$evenhtml = '';

		if (is_string($Harray)) {

			if (strlen($Harray) === 0) {

				$oddhtml = '';
				$evenhtml = '';

			} elseif (strpos($Harray, '|') !== false) {

				$hdet = explode('|', $Harray);

				list($lw, $cw, $rw) = $this->_shareHeaderFooterWidth($hdet[0], $hdet[1], $hdet[2]);
				$oddhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: bottom; color: #000000; ';

				if ($this->defaultheaderfontsize) {
					$oddhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
				}

				if ($this->defaultheaderfontstyle) {

					if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
						$oddhtml .= ' font-weight: bold;';
					}

					if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
						$oddhtml .= ' font-style: italic;';
					}
				}

				if ($this->defaultheaderline) {
					$oddhtml .= ' border-bottom: 0.1mm solid #000000;';
				}

				$oddhtml .= '">';
				$oddhtml .= '<tr>';
				$oddhtml .= '<td width="' . $lw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: left; ">' . $hdet[0] . '</td>';
				$oddhtml .= '<td width="' . $cw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: center; ">' . $hdet[1] . '</td>';
				$oddhtml .= '<td width="' . $rw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: right; ">' . $hdet[2] . '</td>';
				$oddhtml .= '</tr></table>';

				$evenhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: bottom; color: #000000; ';

				if ($this->defaultheaderfontsize) {
					$evenhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
				}

				if ($this->defaultheaderfontstyle) {
					if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
						$evenhtml .= ' font-weight: bold;';
					}
					if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
						$evenhtml .= ' font-style: italic;';
					}
				}

				if ($this->defaultheaderline) {
					$evenhtml .= ' border-bottom: 0.1mm solid #000000;';
				}

				$evenhtml .= '">';
				$evenhtml .= '<tr>';
				$evenhtml .= '<td width="' . $rw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: left; ">' . $hdet[2] . '</td>';
				$evenhtml .= '<td width="' . $cw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: center; ">' . $hdet[1] . '</td>';
				$evenhtml .= '<td width="' . $lw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: right; ">' . $hdet[0] . '</td>';
				$evenhtml .= '</tr></table>';

			} else {

				$oddhtml = '<div style="margin: 0; color: #000000; ';

				if ($this->defaultheaderfontsize) {
					$oddhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
				}

				if ($this->defaultheaderfontstyle) {

					if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
						$oddhtml .= ' font-weight: bold;';
					}

					if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
						$oddhtml .= ' font-style: italic;';
					}
				}

				if ($this->defaultheaderline) {
					$oddhtml .= ' border-bottom: 0.1mm solid #000000;';
				}

				$oddhtml .= 'text-align: right; ">' . $Harray . '</div>';
				$evenhtml = '<div style="margin: 0; color: #000000; ';

				if ($this->defaultheaderfontsize) {
					$evenhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
				}

				if ($this->defaultheaderfontstyle) {

					if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
						$evenhtml .= ' font-weight: bold;';
					}

					if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
						$evenhtml .= ' font-style: italic;';
					}
				}

				if ($this->defaultheaderline) {
					$evenhtml .= ' border-bottom: 0.1mm solid #000000;';
				}

				$evenhtml .= 'text-align: left; ">' . $Harray . '</div>';
			}

		} elseif (is_array($Harray) && !empty($Harray)) {

			$odd = null;
			$even = null;

			if ($side === 'O') {
				$odd = $Harray;
			} elseif ($side === 'E') {
				$even = $Harray;
			} else {
				$odd = Arrays::get($Harray, 'odd', null);
				$even = Arrays::get($Harray, 'even', null);
			}

			$oddhtml = $this->_createHTMLheaderFooter($odd, 'H');
			$evenhtml = $this->_createHTMLheaderFooter($even, 'H');
		}

		if ($side === 'E') {
			$this->SetHTMLHeader($evenhtml, 'E', $write);
		} elseif ($side === 'O') {
			$this->SetHTMLHeader($oddhtml, 'O', $write);
		} else {
			$this->SetHTMLHeader($oddhtml, 'O', $write);
			$this->SetHTMLHeader($evenhtml, 'E', $write);
		}
	}

	function SetFooter($Farray = [], $side = '')
	{
		$oddhtml = '';
		$evenhtml = '';

		if (is_string($Farray)) {

			if (strlen($Farray) == 0) {

				$oddhtml = '';
				$evenhtml = '';

			} elseif (strpos($Farray, '|') !== false) {

				$hdet = explode('|', $Farray);
				$oddhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: top; color: #000000; ';

				if ($this->defaultfooterfontsize) {
					$oddhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
				}

				if ($this->defaultfooterfontstyle) {
					if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
						$oddhtml .= ' font-weight: bold;';
					}
					if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
						$oddhtml .= ' font-style: italic;';
					}
				}

				if ($this->defaultfooterline) {
					$oddhtml .= ' border-top: 0.1mm solid #000000;';
				}

				$oddhtml .= '">';
				$oddhtml .= '<tr>';
				$oddhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: left; ">' . $hdet[0] . '</td>';
				$oddhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: center; ">' . $hdet[1] . '</td>';
				$oddhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: right; ">' . $hdet[2] . '</td>';
				$oddhtml .= '</tr></table>';

				$evenhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: top; color: #000000; ';

				if ($this->defaultfooterfontsize) {
					$evenhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
				}

				if ($this->defaultfooterfontstyle) {

					if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
						$evenhtml .= ' font-weight: bold;';
					}

					if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
						$evenhtml .= ' font-style: italic;';
					}
				}

				if ($this->defaultfooterline) {
					$evenhtml .= ' border-top: 0.1mm solid #000000;';
				}

				$evenhtml .= '">';
				$evenhtml .= '<tr>';
				$evenhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: left; ">' . $hdet[2] . '</td>';
				$evenhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: center; ">' . $hdet[1] . '</td>';
				$evenhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: right; ">' . $hdet[0] . '</td>';
				$evenhtml .= '</tr></table>';

			} else {

				$oddhtml = '<div style="margin: 0; color: #000000; ';

				if ($this->defaultfooterfontsize) {
					$oddhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
				}

				if ($this->defaultfooterfontstyle) {

					if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
						$oddhtml .= ' font-weight: bold;';
					}

					if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
						$oddhtml .= ' font-style: italic;';
					}
				}

				if ($this->defaultfooterline) {
					$oddhtml .= ' border-top: 0.1mm solid #000000;';
				}

				$oddhtml .= 'text-align: right; ">' . $Farray . '</div>';

				$evenhtml = '<div style="margin: 0; color: #000000; ';

				if ($this->defaultfooterfontsize) {
					$evenhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
				}

				if ($this->defaultfooterfontstyle) {

					if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
						$evenhtml .= ' font-weight: bold;';
					}

					if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
						$evenhtml .= ' font-style: italic;';
					}
				}

				if ($this->defaultfooterline) {
					$evenhtml .= ' border-top: 0.1mm solid #000000;';
				}

				$evenhtml .= 'text-align: left; ">' . $Farray . '</div>';
			}

		} elseif (is_array($Farray)) {

			$odd = null;
			$even = null;

			if ($side === 'O') {
				$odd = $Farray;
			} elseif ($side == 'E') {
				$even = $Farray;
			} else {
				$odd = Arrays::get($Farray, 'odd', null);
				$even = Arrays::get($Farray, 'even', null);
			}

			$oddhtml = $this->_createHTMLheaderFooter($odd, 'F');
			$evenhtml = $this->_createHTMLheaderFooter($even, 'F');
		}

		if ($side === 'E') {
			$this->SetHTMLFooter($evenhtml, 'E');
		} elseif ($side === 'O') {
			$this->SetHTMLFooter($oddhtml, 'O');
		} else {
			$this->SetHTMLFooter($oddhtml, 'O');
			$this->SetHTMLFooter($evenhtml, 'E');
		}
	}

	/* -- WATERMARK -- */

	function SetWatermarkText($txt = '', $alpha = -1)
	{
		if ($alpha >= 0) {
			$this->watermarkTextAlpha = $alpha;
		}
		$this->watermarkText = $txt;
	}

	function SetWatermarkImage($src, $alpha = -1, $size = 'D', $pos = 'F')
	{
		if ($alpha >= 0) {
			$this->watermarkImageAlpha = $alpha;
		}
		$this->watermarkImage = $src;
		$this->watermark_size = $size;
		$this->watermark_pos = $pos;
	}

	/* -- END WATERMARK -- */

	// Page footer
	function Footer()
	{
		/* -- CSS-PAGE -- */
		// PAGED MEDIA - CROP / CROSS MARKS from @PAGE
		if ($this->show_marks == 'CROP' || $this->show_marks == 'CROPCROSS') {
			// Show TICK MARKS
			$this->SetLineWidth(0.1); // = 0.1 mm
			$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
			$l = $this->cropMarkLength;
			$m = $this->cropMarkMargin; // Distance of crop mark from margin
			$b = $this->nonPrintMargin; // Non-printable border at edge of paper sheet
			$ax1 = $b;
			$bx = $this->page_box['outer_width_LR'] - $m;
			$ax = max($ax1, $bx - $l);
			$cx1 = $this->w - $b;
			$dx = $this->w - $this->page_box['outer_width_LR'] + $m;
			$cx = min($cx1, $dx + $l);
			$ay1 = $b;
			$by = $this->page_box['outer_width_TB'] - $m;
			$ay = max($ay1, $by - $l);
			$cy1 = $this->h - $b;
			$dy = $this->h - $this->page_box['outer_width_TB'] + $m;
			$cy = min($cy1, $dy + $l);

			$this->Line($ax, $this->page_box['outer_width_TB'], $bx, $this->page_box['outer_width_TB']);
			$this->Line($cx, $this->page_box['outer_width_TB'], $dx, $this->page_box['outer_width_TB']);
			$this->Line($ax, $this->h - $this->page_box['outer_width_TB'], $bx, $this->h - $this->page_box['outer_width_TB']);
			$this->Line($cx, $this->h - $this->page_box['outer_width_TB'], $dx, $this->h - $this->page_box['outer_width_TB']);
			$this->Line($this->page_box['outer_width_LR'], $ay, $this->page_box['outer_width_LR'], $by);
			$this->Line($this->page_box['outer_width_LR'], $cy, $this->page_box['outer_width_LR'], $dy);
			$this->Line($this->w - $this->page_box['outer_width_LR'], $ay, $this->w - $this->page_box['outer_width_LR'], $by);
			$this->Line($this->w - $this->page_box['outer_width_LR'], $cy, $this->w - $this->page_box['outer_width_LR'], $dy);

			if ($this->printers_info) {
				$hd = date('Y-m-d H:i') . '  Page ' . $this->page . ' of {nb}';
				$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
				$this->SetFont('arial', '', 7.5, true, true);
				$this->x = $this->page_box['outer_width_LR'] + 1.5;
				$this->y = 1;
				$this->Cell(0, $this->FontSize, $hd, 0, 0, 'L', 0, '', 0, 0, 0, 'M');
				$this->SetFont($this->default_font, '', $this->original_default_font_size);
			}
		}
		if ($this->show_marks == 'CROSS' || $this->show_marks == 'CROPCROSS') {
			$this->SetLineWidth(0.1); // = 0.1 mm
			$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
			$l = 14 / 2; // longer length of the cross line (half)
			$w = 6 / 2; // shorter width of the cross line (half)
			$r = 1.2; // radius of circle
			$m = $this->crossMarkMargin; // Distance of cross mark from margin
			$x1 = $this->page_box['outer_width_LR'] - $m;
			$x2 = $this->w - $this->page_box['outer_width_LR'] + $m;
			$y1 = $this->page_box['outer_width_TB'] - $m;
			$y2 = $this->h - $this->page_box['outer_width_TB'] + $m;
			// Left
			$this->Circle($x1, $this->h / 2, $r, 'S');
			$this->Line($x1 - $w, $this->h / 2, $x1 + $w, $this->h / 2);
			$this->Line($x1, $this->h / 2 - $l, $x1, $this->h / 2 + $l);
			// Right
			$this->Circle($x2, $this->h / 2, $r, 'S');
			$this->Line($x2 - $w, $this->h / 2, $x2 + $w, $this->h / 2);
			$this->Line($x2, $this->h / 2 - $l, $x2, $this->h / 2 + $l);
			// Top
			$this->Circle($this->w / 2, $y1, $r, 'S');
			$this->Line($this->w / 2, $y1 - $w, $this->w / 2, $y1 + $w);
			$this->Line($this->w / 2 - $l, $y1, $this->w / 2 + $l, $y1);
			// Bottom
			$this->Circle($this->w / 2, $y2, $r, 'S');
			$this->Line($this->w / 2, $y2 - $w, $this->w / 2, $y2 + $w);
			$this->Line($this->w / 2 - $l, $y2, $this->w / 2 + $l, $y2);
		}

		/* -- END CSS-PAGE -- */

		// mPDF 6
		// If @page set non-HTML headers/footers named, they were not read until later in the HTML code - so now set them
		if ($this->page == 1) {
			if ($this->firstPageBoxHeader) {
				if (isset($this->pageHTMLheaders[$this->firstPageBoxHeader])) {
					$this->HTMLHeader = $this->pageHTMLheaders[$this->firstPageBoxHeader];
				}
				$this->Header();
			}
			if ($this->firstPageBoxFooter) {
				if (isset($this->pageHTMLfooters[$this->firstPageBoxFooter])) {
					$this->HTMLFooter = $this->pageHTMLfooters[$this->firstPageBoxFooter];
				}
			}
			$this->firstPageBoxHeader = '';
			$this->firstPageBoxFooter = '';
		}


		if (($this->mirrorMargins && ($this->page % 2 == 0) && $this->HTMLFooterE) || ($this->mirrorMargins && ($this->page % 2 == 1) && $this->HTMLFooter) || (!$this->mirrorMargins && $this->HTMLFooter)) {
			$this->writeHTMLFooters();
		}

		/* -- WATERMARK -- */
		if (($this->watermarkText) && ($this->showWatermarkText)) {
			$this->watermark($this->watermarkText, $this->watermarkAngle, 120, $this->watermarkTextAlpha); // Watermark text
		}
		if (($this->watermarkImage) && ($this->showWatermarkImage)) {
			$this->watermarkImg($this->watermarkImage, $this->watermarkImageAlpha); // Watermark image
		}
		/* -- END WATERMARK -- */
	}

	/* -- HTML-CSS -- */

	/**
	 * Write HTML code to the document
	 *
	 * Also used internally to parse HTML into buffers
	 *
	 * @param string $html
	 * @param int    $mode  Use HTMLParserMode constants. Controls what parts of the $html code is parsed.
	 * @param bool   $init  Clears and sets buffers to Top level block etc.
	 * @param bool   $close If false leaves buffers etc. in current state, so that it can continue a block etc.
	 */
	function WriteHTML($html, $mode = HTMLParserMode::DEFAULT_MODE, $init = true, $close = true)
	{
		/* Check $html is an integer, float, string, boolean or class with __toString(), otherwise throw exception */
		if (is_scalar($html) === false) {
			if (!is_object($html) || ! method_exists($html, '__toString')) {
				throw new \Mpdf\MpdfException('WriteHTML() requires $html be an integer, float, string, boolean or an object with the __toString() magic method.');
			}
		}

		// Check the mode is valid
		if (in_array($mode, HTMLParserMode::getAllModes(), true) === false) {
			throw new \Mpdf\MpdfException('WriteHTML() requires $mode to be one of the modes defined in HTMLParserMode');
		}

		/* Cast $html as a string */
		$html = (string) $html;

		// @log Parsing CSS & Headers

		if ($init) {
			$this->headerbuffer = '';
			$this->textbuffer = [];
			$this->fixedPosBlockSave = [];
		}
		if ($mode === HTMLParserMode::HEADER_CSS) {
			$html = '<style> ' . $html . ' </style>';
		} // stylesheet only

		if ($this->allow_charset_conversion) {
			if ($mode === HTMLParserMode::DEFAULT_MODE) {
				$this->ReadCharset($html);
			}
			if ($this->charset_in && $mode !== HTMLParserMode::HTML_HEADER_BUFFER) {
				$success = iconv($this->charset_in, 'UTF-8//TRANSLIT', $html);
				if ($success) {
					$html = $success;
				}
			}
		}

		$html = $this->purify_utf8($html, false);
		if ($init) {
			$this->blklvl = 0;
			$this->lastblocklevelchange = 0;
			$this->blk = [];
			$this->initialiseBlock($this->blk[0]);
			$this->blk[0]['width'] = & $this->pgwidth;
			$this->blk[0]['inner_width'] = & $this->pgwidth;
			$this->blk[0]['blockContext'] = $this->blockContext;
		}

		$zproperties = [];
		if ($mode === HTMLParserMode::DEFAULT_MODE || $mode === HTMLParserMode::HEADER_CSS) {
			$this->ReadMetaTags($html);

			if (preg_match('/<base[^>]*href=["\']([^"\'>]*)["\']/i', $html, $m)) {
				$this->SetBasePath($m[1]);
			}
			$html = $this->cssManager->ReadCSS($html);

			if ($this->autoLangToFont && !$this->usingCoreFont && preg_match('/<html [^>]*lang=[\'\"](.*?)[\'\"]/ism', $html, $m)) {
				$html_lang = $m[1];
			}

			if (preg_match('/<html [^>]*dir=[\'\"]\s*rtl\s*[\'\"]/ism', $html)) {
				$zproperties['DIRECTION'] = 'rtl';
			}

			// allow in-line CSS for body tag to be parsed // Get <body> tag inline CSS
			if (preg_match('/<body([^>]*)>(.*?)<\/body>/ism', $html, $m) || preg_match('/<body([^>]*)>(.*)$/ism', $html, $m)) {
				$html = $m[2];
				// Changed to allow style="background: url('bg.jpg')"
				if (preg_match('/style=[\"](.*?)[\"]/ism', $m[1], $mm) || preg_match('/style=[\'](.*?)[\']/ism', $m[1], $mm)) {
					$zproperties = $this->cssManager->readInlineCSS($mm[1]);
				}
				if (preg_match('/dir=[\'\"]\s*rtl\s*[\'\"]/ism', $m[1])) {
					$zproperties['DIRECTION'] = 'rtl';
				}
				if (isset($html_lang) && $html_lang) {
					$zproperties['LANG'] = $html_lang;
				}
				if ($this->autoLangToFont && !$this->onlyCoreFonts && preg_match('/lang=[\'\"](.*?)[\'\"]/ism', $m[1], $mm)) {
					$zproperties['LANG'] = $mm[1];
				}
			}
		}
		$properties = $this->cssManager->MergeCSS('BLOCK', 'BODY', '');
		if ($zproperties) {
			$properties = $this->cssManager->array_merge_recursive_unique($properties, $zproperties);
		}

		if (isset($properties['DIRECTION']) && $properties['DIRECTION']) {
			$this->cssManager->CSS['BODY']['DIRECTION'] = $properties['DIRECTION'];
		}
		if (!isset($this->cssManager->CSS['BODY']['DIRECTION'])) {
			$this->cssManager->CSS['BODY']['DIRECTION'] = $this->directionality;
		} else {
			$this->SetDirectionality($this->cssManager->CSS['BODY']['DIRECTION']);
		}

		$this->setCSS($properties, '', 'BODY');

		$this->blk[0]['InlineProperties'] = $this->saveInlineProperties();

		if ($mode === HTMLParserMode::HEADER_CSS) {
			return '';
		}
		if (!isset($this->cssManager->CSS['BODY'])) {
			$this->cssManager->CSS['BODY'] = [];
		}

		/* -- BACKGROUNDS -- */
		if (isset($properties['BACKGROUND-GRADIENT'])) {
			$this->bodyBackgroundGradient = $properties['BACKGROUND-GRADIENT'];
		}

		if (isset($properties['BACKGROUND-IMAGE']) && $properties['BACKGROUND-IMAGE']) {
			$ret = $this->SetBackground($properties, $this->pgwidth);
			if ($ret) {
				$this->bodyBackgroundImage = $ret;
			}
		}
		/* -- END BACKGROUNDS -- */

		/* -- CSS-PAGE -- */
		// If page-box is set
		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
			$this->page_box['current'] = '';
			$this->page_box['using'] = true;
			list($pborientation, $pbmgl, $pbmgr, $pbmgt, $pbmgb, $pbmgh, $pbmgf, $hname, $fname, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat) = $this->SetPagedMediaCSS('', false, 'O');
			$this->DefOrientation = $this->CurOrientation = $pborientation;
			$this->orig_lMargin = $this->DeflMargin = $pbmgl;
			$this->orig_rMargin = $this->DefrMargin = $pbmgr;
			$this->orig_tMargin = $this->tMargin = $pbmgt;
			$this->orig_bMargin = $this->bMargin = $pbmgb;
			$this->orig_hMargin = $this->margin_header = $pbmgh;
			$this->orig_fMargin = $this->margin_footer = $pbmgf;
			list($pborientation, $pbmgl, $pbmgr, $pbmgt, $pbmgb, $pbmgh, $pbmgf, $hname, $fname, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat) = $this->SetPagedMediaCSS('', true, 'O'); // first page
			$this->show_marks = $marks;
			if ($hname) {
				$this->firstPageBoxHeader = $hname;
			}
			if ($fname) {
				$this->firstPageBoxFooter = $fname;
			}
		}
		/* -- END CSS-PAGE -- */

		$parseonly = false;
		$this->bufferoutput = false;
		if ($mode == HTMLParserMode::HTML_PARSE_NO_WRITE) {
			$parseonly = true;
			// Close any open block tags
			$arr = [];
			$ai = 0;
			for ($b = $this->blklvl; $b > 0; $b--) {
				$this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
			}
			// Output any text left in buffer
			if (count($this->textbuffer)) {
				$this->printbuffer($this->textbuffer);
			}
			$this->textbuffer = [];
		} elseif ($mode === HTMLParserMode::HTML_HEADER_BUFFER) {
			// Close any open block tags
			$arr = [];
			$ai = 0;
			for ($b = $this->blklvl; $b > 0; $b--) {
				$this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
			}
			// Output any text left in buffer
			if (count($this->textbuffer)) {
				$this->printbuffer($this->textbuffer);
			}
			$this->bufferoutput = true;
			$this->textbuffer = [];
			$this->headerbuffer = '';
			$properties = $this->cssManager->MergeCSS('BLOCK', 'BODY', '');
			$this->setCSS($properties, '', 'BODY');
		}

		mb_internal_encoding('UTF-8');

		$html = $this->AdjustHTML($html, $this->tabSpaces); // Try to make HTML look more like XHTML

		if ($this->autoScriptToLang) {
			$html = $this->markScriptToLang($html);
		}

		preg_match_all('/<htmlpageheader([^>]*)>(.*?)<\/htmlpageheader>/si', $html, $h);
		for ($i = 0; $i < count($h[1]); $i++) {
			if (preg_match('/name=[\'|\"](.*?)[\'|\"]/', $h[1][$i], $n)) {
				$this->pageHTMLheaders[$n[1]]['html'] = $h[2][$i];
				$this->pageHTMLheaders[$n[1]]['h'] = $this->_getHtmlHeight($h[2][$i]);
			}
		}
		preg_match_all('/<htmlpagefooter([^>]*)>(.*?)<\/htmlpagefooter>/si', $html, $f);
		for ($i = 0; $i < count($f[1]); $i++) {
			if (preg_match('/name=[\'|\"](.*?)[\'|\"]/', $f[1][$i], $n)) {
				$this->pageHTMLfooters[$n[1]]['html'] = $f[2][$i];
				$this->pageHTMLfooters[$n[1]]['h'] = $this->_getHtmlHeight($f[2][$i]);
			}
		}

		$html = preg_replace('/<htmlpageheader.*?<\/htmlpageheader>/si', '', $html);
		$html = preg_replace('/<htmlpagefooter.*?<\/htmlpagefooter>/si', '', $html);

		if ($this->state == 0 && ($mode === HTMLParserMode::DEFAULT_MODE || $mode === HTMLParserMode::HTML_BODY)) {
			$this->AddPage($this->CurOrientation);
		}


		if (isset($hname) && preg_match('/^html_(.*)$/i', $hname, $n)) {
			$this->SetHTMLHeader($this->pageHTMLheaders[$n[1]], 'O', true);
		}
		if (isset($fname) && preg_match('/^html_(.*)$/i', $fname, $n)) {
			$this->SetHTMLFooter($this->pageHTMLfooters[$n[1]], 'O');
		}



		$html = str_replace('<?', '< ', $html); // Fix '<?XML' bug from HTML code generated by MS Word

		$this->checkSIP = false;
		$this->checkSMP = false;
		$this->checkCJK = false;
		if ($this->onlyCoreFonts) {
			$html = $this->SubstituteChars($html);
		} else {
			if (preg_match("/([" . $this->pregRTLchars . "])/u", $html)) {
				$this->biDirectional = true;
			} // *OTL*
			if (preg_match("/([\x{20000}-\x{2FFFF}])/u", $html)) {
				$this->checkSIP = true;
			}
			if (preg_match("/([\x{10000}-\x{1FFFF}])/u", $html)) {
				$this->checkSMP = true;
			}
			/* -- CJK-FONTS -- */
			if (preg_match("/([" . $this->pregCJKchars . "])/u", $html)) {
				$this->checkCJK = true;
			}
			/* -- END CJK-FONTS -- */
		}

		// Don't allow non-breaking spaces that are converted to substituted chars or will break anyway and mess up table width calc.
		$html = str_replace('<tta>160</tta>', chr(32), $html);
		$html = str_replace('</tta><tta>', '|', $html);
		$html = str_replace('</tts><tts>', '|', $html);
		$html = str_replace('</ttz><ttz>', '|', $html);

		// Add new supported tags in the DisableTags function
		$html = strip_tags($html, $this->enabledtags); // remove all unsupported tags, but the ones inside the 'enabledtags' string
		// Explode the string in order to parse the HTML code
		$a = preg_split('/<(.*?)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
		// ? more accurate regexp that allows e.g. <a name="Silly <name>">
		// if changing - also change in fn.SubstituteChars()
		// $a = preg_split ('/<((?:[^<>]+(?:"[^"]*"|\'[^\']*\')?)+)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);

		if ($this->mb_enc) {
			mb_internal_encoding($this->mb_enc);
		}
		$pbc = 0;
		$this->subPos = -1;
		$cnt = count($a);
		for ($i = 0; $i < $cnt; $i++) {
			$e = $a[$i];
			if ($i % 2 == 0) {
				// TEXT
				if ($this->blk[$this->blklvl]['hide']) {
					continue;
				}
				if ($this->inlineDisplayOff) {
					continue;
				}
				if ($this->inMeter) {
					continue;
				}

				if ($this->inFixedPosBlock) {
					$this->fixedPosBlock .= $e;
					continue;
				} // *CSS-POSITION*
				if (strlen($e) == 0) {
					continue;
				}

				if ($this->ignorefollowingspaces && !$this->ispre) {
					if (strlen(ltrim($e)) == 0) {
						continue;
					}
					if ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats' && substr($e, 0, 1) == ' ') {
						$this->ignorefollowingspaces = false;
						$e = ltrim($e);
					}
				}

				$this->OTLdata = null;  // mPDF 5.7.1

				$e = UtfString::strcode2utf($e);
				$e = $this->lesser_entity_decode($e);

				if ($this->usingCoreFont) {
					// If core font is selected in document which is not onlyCoreFonts - substitute with non-core font
					if ($this->useSubstitutions && !$this->onlyCoreFonts && $this->subPos < $i && !$this->specialcontent) {
						$cnt += $this->SubstituteCharsNonCore($a, $i, $e);
					}
					// CONVERT ENCODING
					$e = mb_convert_encoding($e, $this->mb_enc, 'UTF-8');
					if ($this->textvar & TextVars::FT_UPPERCASE) {
						$e = mb_strtoupper($e, $this->mb_enc);
					} // mPDF 5.7.1
					elseif ($this->textvar & TextVars::FT_LOWERCASE) {
						$e = mb_strtolower($e, $this->mb_enc);
					} // mPDF 5.7.1
					elseif ($this->textvar & TextVars::FT_CAPITALIZE) {
						$e = mb_convert_case($e, MB_CASE_TITLE, "UTF-8");
					} // mPDF 5.7.1
				} else {
					if ($this->checkSIP && $this->CurrentFont['sipext'] && $this->subPos < $i && (!$this->specialcontent || !$this->useActiveForms)) {
						$cnt += $this->SubstituteCharsSIP($a, $i, $e);
					}

					if ($this->useSubstitutions && !$this->onlyCoreFonts && $this->CurrentFont['type'] != 'Type0' && $this->subPos < $i && (!$this->specialcontent || !$this->useActiveForms)) {
						$cnt += $this->SubstituteCharsMB($a, $i, $e);
					}

					if ($this->textvar & TextVars::FT_UPPERCASE) {
						$e = mb_strtoupper($e, $this->mb_enc);
					} elseif ($this->textvar & TextVars::FT_LOWERCASE) {
						$e = mb_strtolower($e, $this->mb_enc);
					} elseif ($this->textvar & TextVars::FT_CAPITALIZE) {
						$e = mb_convert_case($e, MB_CASE_TITLE, "UTF-8");
					}

					/* -- OTL -- */
					// Use OTL OpenType Table Layout - GSUB & GPOS
					if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL'] && (!$this->specialcontent || !$this->useActiveForms)) {
						if (!$this->otl) {
							$this->otl = new Otl($this, $this->fontCache);
						}
						$e = $this->otl->applyOTL($e, $this->CurrentFont['useOTL']);
						$this->OTLdata = $this->otl->OTLdata;
						$this->otl->removeChar($e, $this->OTLdata, "\xef\xbb\xbf"); // Remove ZWNBSP (also Byte order mark FEFF)
					} /* -- END OTL -- */
					else {
						// removes U+200E/U+200F LTR and RTL mark and U+200C/U+200D Zero-width Joiner and Non-joiner
						$e = preg_replace("/[\xe2\x80\x8c\xe2\x80\x8d\xe2\x80\x8e\xe2\x80\x8f]/u", '', $e);
						$e = preg_replace("/[\xef\xbb\xbf]/u", '', $e); // Remove ZWNBSP (also Byte order mark FEFF)
					}
				}

				if (($this->tts) || ($this->ttz) || ($this->tta)) {
					$es = explode('|', $e);
					$e = '';
					foreach ($es as $val) {
						$e .= chr($val);
					}
				}

				//  FORM ELEMENTS
				if ($this->specialcontent) {
					/* -- FORMS -- */
					// SELECT tag (form element)
					if ($this->specialcontent == "type=select") {
						$e = ltrim($e);
						if (!empty($this->OTLdata)) {
							$this->otl->trimOTLdata($this->OTLdata, true, false);
						} // *OTL*
						$stringwidth = $this->GetStringWidth($e);
						if (!isset($this->selectoption['MAXWIDTH']) || $stringwidth > $this->selectoption['MAXWIDTH']) {
							$this->selectoption['MAXWIDTH'] = $stringwidth;
						}
						if (!isset($this->selectoption['SELECTED']) || $this->selectoption['SELECTED'] == '') {
							$this->selectoption['SELECTED'] = $e;
							if (!empty($this->OTLdata)) {
								$this->selectoption['SELECTED-OTLDATA'] = $this->OTLdata;
							} // *OTL*
						}
						// Active Forms
						if (isset($this->selectoption['ACTIVE']) && $this->selectoption['ACTIVE']) {
							$this->selectoption['ITEMS'][] = ['exportValue' => $this->selectoption['currentVAL'], 'content' => $e, 'selected' => $this->selectoption['currentSEL']];
						}
						$this->OTLdata = [];
					} // TEXTAREA
					else {
						$objattr = unserialize($this->specialcontent);
						$objattr['text'] = $e;
						$objattr['OTLdata'] = $this->OTLdata;
						$this->OTLdata = [];
						$te = "\xbb\xa4\xactype=textarea,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
						if ($this->tdbegin) {
							$this->_saveCellTextBuffer($te, $this->HREF);
						} else {
							$this->_saveTextBuffer($te, $this->HREF);
						}
					}
					/* -- END FORMS -- */
				} // TABLE
				elseif ($this->tableLevel) {
					/* -- TABLES -- */
					if ($this->tdbegin) {
						if (($this->ignorefollowingspaces) && !$this->ispre) {
							$e = ltrim($e);
							if (!empty($this->OTLdata)) {
								$this->otl->trimOTLdata($this->OTLdata, true, false);
							} // *OTL*
						}
						if ($e || $e === '0') {
							if ($this->blockjustfinished && $this->cell[$this->row][$this->col]['s'] > 0) {
								$this->_saveCellTextBuffer("\n");
								if (!isset($this->cell[$this->row][$this->col]['maxs'])) {
									$this->cell[$this->row][$this->col]['maxs'] = $this->cell[$this->row][$this->col]['s'];
								} elseif ($this->cell[$this->row][$this->col]['maxs'] < $this->cell[$this->row][$this->col]['s']) {
									$this->cell[$this->row][$this->col]['maxs'] = $this->cell[$this->row][$this->col]['s'];
								}
								$this->cell[$this->row][$this->col]['s'] = 0; // reset
							}
							$this->blockjustfinished = false;

							if (!isset($this->cell[$this->row][$this->col]['R']) || !$this->cell[$this->row][$this->col]['R']) {
								if (isset($this->cell[$this->row][$this->col]['s'])) {
									$this->cell[$this->row][$this->col]['s'] += $this->GetStringWidth($e, false, $this->OTLdata, $this->textvar);
								} else {
									$this->cell[$this->row][$this->col]['s'] = $this->GetStringWidth($e, false, $this->OTLdata, $this->textvar);
								}
								if (!empty($this->spanborddet)) {
									$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);
								}
							}

							$this->_saveCellTextBuffer($e, $this->HREF);

							if (substr($this->cell[$this->row][$this->col]['a'], 0, 1) == 'D') {

								$dp = $this->decimal_align[substr($this->cell[$this->row][$this->col]['a'], 0, 2)];
								$s = preg_split('/' . preg_quote($dp, '/') . '/', $e, 2);  // ? needs to be /u if not core
								$s0 = $this->GetStringWidth($s[0], false);

								if (isset($s[1]) && $s[1]) {
									$s1 = $this->GetStringWidth(($s[1] . $dp), false);
								} else {
									$s1 = 0;
								}

								if (!isset($this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs0'])) {
									if ($this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'] === false) {
										$this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'] = [];
									}
									$this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs0'] = $s0;
								} else {
									$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']);
								}

								if (!isset($this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs1'])) {
									$this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs1'] = $s1;
								} else {
									$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']);
								}
							}

							$this->nestedtablejustfinished = false;
							$this->linebreakjustfinished = false;
						}
					}
					/* -- END TABLES -- */
				} // ALL ELSE
				else {
					if ($this->ignorefollowingspaces && !$this->ispre) {
						$e = ltrim($e);
						if (!empty($this->OTLdata)) {
							$this->otl->trimOTLdata($this->OTLdata, true, false);
						} // *OTL*
					}
					if ($e || $e === '0') {
						$this->_saveTextBuffer($e, $this->HREF);
					}
				}
				if ($e || $e === '0') {
					$this->ignorefollowingspaces = false; // mPDF 6
				}
				if (substr($e, -1, 1) == ' ' && !$this->ispre && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
					$this->ignorefollowingspaces = true;
				}
			} else { // TAG **
				if (isset($e[0]) && $e[0] == '/') {
					$endtag = trim(strtoupper(substr($e, 1)));

					/* -- CSS-POSITION -- */
					// mPDF 6
					if ($this->inFixedPosBlock) {
						if (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags)) {
							$this->fixedPosBlockDepth--;
						}
						if ($this->fixedPosBlockDepth == 0) {
							$this->fixedPosBlockSave[] = [$this->fixedPosBlock, $this->fixedPosBlockBBox, $this->page];
							$this->fixedPosBlock = '';
							$this->inFixedPosBlock = false;
							continue;
						}
						$this->fixedPosBlock .= '<' . $e . '>';
						continue;
					}
					/* -- END CSS-POSITION -- */

					// mPDF 6
					// Correct for tags where HTML5 specifies optional end tags (see also OpenTag() )
					if ($this->allow_html_optional_endtags && !$parseonly) {
						if (isset($this->blk[$this->blklvl]['tag'])) {
							$closed = false;
							// li end tag may be omitted if there is no more content in the parent element
							if (!$closed && $this->blk[$this->blklvl]['tag'] == 'LI' && $endtag != 'LI' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
								$this->tag->CloseTag('LI', $a, $i);
								$closed = true;
							}
							// dd end tag may be omitted if there is no more content in the parent element
							if (!$closed && $this->blk[$this->blklvl]['tag'] == 'DD' && $endtag != 'DD' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
								$this->tag->CloseTag('DD', $a, $i);
								$closed = true;
							}
							// 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 [??????]
							if (!$closed && $this->blk[$this->blklvl]['tag'] == 'P' && $endtag != 'P' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
								$this->tag->CloseTag('P', $a, $i);
								$closed = true;
							}
							// option end tag may be omitted if there is no more content in the parent element
							if (!$closed && $this->blk[$this->blklvl]['tag'] == 'OPTION' && $endtag != 'OPTION' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
								$this->tag->CloseTag('OPTION', $a, $i);
								$closed = true;
							}
						}
						/* -- TABLES -- */
						// Check for Table tags where HTML specifies optional end tags,
						if ($endtag == 'TABLE') {
							if ($this->lastoptionaltag == 'THEAD' || $this->lastoptionaltag == 'TBODY' || $this->lastoptionaltag == 'TFOOT') {
								$this->tag->CloseTag($this->lastoptionaltag, $a, $i);
							}
							if ($this->lastoptionaltag == 'TR') {
								$this->tag->CloseTag('TR', $a, $i);
							}
							if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') {
								$this->tag->CloseTag($this->lastoptionaltag, $a, $i);
								$this->tag->CloseTag('TR', $a, $i);
							}
						}
						if ($endtag == 'THEAD' || $endtag == 'TBODY' || $endtag == 'TFOOT') {
							if ($this->lastoptionaltag == 'TR') {
								$this->tag->CloseTag('TR', $a, $i);
							}
							if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') {
								$this->tag->CloseTag($this->lastoptionaltag, $a, $i);
								$this->tag->CloseTag('TR', $a, $i);
							}
						}
						if ($endtag == 'TR') {
							if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') {
								$this->tag->CloseTag($this->lastoptionaltag, $a, $i);
							}
						}
						/* -- END TABLES -- */
					}


					// mPDF 6
					if ($this->blk[$this->blklvl]['hide']) {
						if (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags)) {
							unset($this->blk[$this->blklvl]);
							$this->blklvl--;
						}
						continue;
					}

					// mPDF 6
					$this->tag->CloseTag($endtag, $a, $i); // mPDF 6
				} else { // OPENING TAG
					if ($this->blk[$this->blklvl]['hide']) {
						if (strpos($e, ' ')) {
							$te = strtoupper(substr($e, 0, strpos($e, ' ')));
						} else {
							$te = strtoupper($e);
						}
						// mPDF 6
						if ($te == 'THEAD' || $te == 'TBODY' || $te == 'TFOOT' || $te == 'TR' || $te == 'TD' || $te == 'TH') {
							$this->lastoptionaltag = $te;
						}
						if (in_array($te, $this->outerblocktags) || in_array($te, $this->innerblocktags)) {
							$this->blklvl++;
							$this->blk[$this->blklvl]['hide'] = true;
							$this->blk[$this->blklvl]['tag'] = $te; // mPDF 6
						}
						continue;
					}

					/* -- CSS-POSITION -- */
					if ($this->inFixedPosBlock) {
						if (strpos($e, ' ')) {
							$te = strtoupper(substr($e, 0, strpos($e, ' ')));
						} else {
							$te = strtoupper($e);
						}
						$this->fixedPosBlock .= '<' . $e . '>';
						if (in_array($te, $this->outerblocktags) || in_array($te, $this->innerblocktags)) {
							$this->fixedPosBlockDepth++;
						}
						continue;
					}
					/* -- END CSS-POSITION -- */
					$regexp = '|=\'(.*?)\'|s'; // eliminate single quotes, if any
					$e = preg_replace($regexp, "=\"\$1\"", $e);
					// changes anykey=anyvalue to anykey="anyvalue" (only do this inside [some] tags)
					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)
						$regexp = '| (\\w+?)=([^\\s>"]+)|si';
						$e = preg_replace($regexp, " \$1=\"\$2\"", $e);
					}

					$e = preg_replace('/ (\\S+?)\s*=\s*"/i', " \\1=\"", $e);

					// Fix path values, if needed
					$orig_srcpath = '';
					if ((stristr($e, "href=") !== false) or ( stristr($e, "src=") !== false)) {
						$regexp = '/ (href|src)\s*=\s*"(.*?)"/i';
						preg_match($regexp, $e, $auxiliararray);
						if (isset($auxiliararray[2])) {
							$path = $auxiliararray[2];
						} else {
							$path = '';
						}
						if (trim($path) != '' && !(stristr($e, "src=") !== false && substr($path, 0, 4) == 'var:') && substr($path, 0, 1) != '@') {
							$path = htmlspecialchars_decode($path); // mPDF 5.7.4 URLs
							$orig_srcpath = $path;
							$this->GetFullPath($path);
							$regexp = '/ (href|src)="(.*?)"/i';
							$e = preg_replace($regexp, ' \\1="' . $path . '"', $e);
						}
					}//END of Fix path values
					// Extract attributes
					$contents = [];
					$contents1 = [];
					$contents2 = [];
					// Changed to allow style="background: url('bg.jpg')"
					// Changed to improve performance; maximum length of \S (attribute) = 16
					// Increase allowed attribute name to 32 - cutting off "toc-even-header-name" etc.
					preg_match_all('/\\S{1,32}=["][^"]*["]/', $e, $contents1);
					preg_match_all('/\\S{1,32}=[\'][^\']*[\']/i', $e, $contents2);

					$contents = array_merge($contents1, $contents2);
					preg_match('/\\S+/', $e, $a2);
					$tag = (isset($a2[0]) ? strtoupper($a2[0]) : '');
					$attr = [];
					if ($orig_srcpath) {
						$attr['ORIG_SRC'] = $orig_srcpath;
					}
					if (!empty($contents)) {
						foreach ($contents[0] as $v) {
							// Changed to allow style="background: url('bg.jpg')"
							if (preg_match('/^([^=]*)=["]?([^"]*)["]?$/', $v, $a3) || preg_match('/^([^=]*)=[\']?([^\']*)[\']?$/', $v, $a3)) {
								if (strtoupper($a3[1]) == 'ID' || strtoupper($a3[1]) == 'CLASS') { // 4.2.013 Omits STYLE
									$attr[strtoupper($a3[1])] = trim(strtoupper($a3[2]));
								} // includes header-style-right etc. used for <pageheader>
								elseif (preg_match('/^(HEADER|FOOTER)-STYLE/i', $a3[1])) {
									$attr[strtoupper($a3[1])] = trim(strtoupper($a3[2]));
								} else {
									$attr[strtoupper($a3[1])] = trim($a3[2]);
								}
							}
						}
					}
					$this->tag->OpenTag($tag, $attr, $a, $i); // mPDF 6
					/* -- CSS-POSITION -- */
					if ($this->inFixedPosBlock) {
						$this->fixedPosBlockBBox = [$tag, $attr, $this->x, $this->y];
						$this->fixedPosBlock = '';
						$this->fixedPosBlockDepth = 1;
					}
					/* -- END CSS-POSITION -- */
					if (preg_match('/\/$/', $e)) {
						$this->tag->CloseTag($tag, $a, $i);
					}
				}
			} // end TAG
		} // end of	foreach($a as $i=>$e)

		if ($close) {
			// Close any open block tags
			for ($b = $this->blklvl; $b > 0; $b--) {
				$this->tag->CloseTag($this->blk[$b]['tag'], $a, $i);
			}

			// Output any text left in buffer
			if (count($this->textbuffer) && !$parseonly) {
				$this->printbuffer($this->textbuffer);
			}
			if (!$parseonly) {
				$this->textbuffer = [];
			}

			/* -- CSS-FLOAT -- */
			// If ended with a float, need to move to end page
			$currpos = $this->page * 1000 + $this->y;
			if (isset($this->blk[$this->blklvl]['float_endpos']) && $this->blk[$this->blklvl]['float_endpos'] > $currpos) {
				$old_page = $this->page;
				$new_page = intval($this->blk[$this->blklvl]['float_endpos'] / 1000);
				if ($old_page != $new_page) {
					$s = $this->PrintPageBackgrounds();
					// Writes after the marker so not overwritten later by page background etc.
					$this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
					$this->pageBackgrounds = [];
					$this->page = $new_page;
					$this->ResetMargins();
					$this->Reset();
					$this->pageoutput[$this->page] = [];
				}
				$this->y = (round($this->blk[$this->blklvl]['float_endpos'] * 1000) % 1000000) / 1000; // mod changes operands to integers before processing
			}
			/* -- END CSS-FLOAT -- */

			/* -- CSS-IMAGE-FLOAT -- */
			$this->printfloatbuffer();
			/* -- END CSS-IMAGE-FLOAT -- */

			// Create Internal Links, if needed
			if (!empty($this->internallink)) {

				foreach ($this->internallink as $k => $v) {

					if (strpos($k, "#") !== false) {
						continue;
					}

					if (!is_array($v)) {
						continue;
					}

					$ypos = $v['Y'];
					$pagenum = $v['PAGE'];
					$sharp = "#";

					while (array_key_exists($sharp . $k, $this->internallink)) {
						$internallink = $this->internallink[$sharp . $k];
						$this->SetLink($internallink, $ypos, $pagenum);
						$sharp .= "#";
					}
				}
			}

			$this->bufferoutput = false;

			/* -- CSS-POSITION -- */
			if (count($this->fixedPosBlockSave)) {
				foreach ($this->fixedPosBlockSave as $fpbs) {
					$old_page = $this->page;
					$this->page = $fpbs[2];
					$this->WriteFixedPosHTML($fpbs[0], 0, 0, 100, 100, 'auto', $fpbs[1]);  // 0,0,10,10 are overwritten by bbox
					$this->page = $old_page;
				}
				$this->fixedPosBlockSave = [];
			}
			/* -- END CSS-POSITION -- */
		}
	}

	/* -- CSS-POSITION -- */

	function WriteFixedPosHTML($html, $x, $y, $w, $h, $overflow = 'visible', $bounding = [])
	{
		// $overflow can be 'hidden', 'visible' or 'auto' - 'auto' causes autofit to size
		// Annotations disabled - enabled in mPDF 5.0
		// Links do work
		// Will always go on current page (or start Page 1 if required)
		// Probably INCOMPATIBLE WITH keep with table, columns etc.
		// Called externally or interally via <div style="position: [fixed|absolute]">
		// When used internally, $x $y $w $h and $overflow are all overridden by $bounding

		$overflow = strtolower($overflow);
		if ($this->state == 0) {
			$this->AddPage($this->CurOrientation);
		}
		$save_y = $this->y;
		$save_x = $this->x;
		$this->fullImageHeight = $this->h;
		$save_cols = false;
		/* -- COLUMNS -- */
		if ($this->ColActive) {
			$save_cols = true;
			$save_nbcol = $this->NbCol; // other values of gap and vAlign will not change by setting Columns off
			$this->SetColumns(0);
		}
		/* -- END COLUMNS -- */
		$save_annots = $this->title2annots; // *ANNOTATIONS*
		$this->writingHTMLheader = true; // a FIX to stop pagebreaks etc.
		$this->writingHTMLfooter = true;
		$this->InFooter = true; // suppresses autopagebreaks
		$save_bgs = $this->pageBackgrounds;
		$checkinnerhtml = preg_replace('/\s/', '', $html);
		$rotate = 0;

		if ($w > $this->w) {
			$x = 0;
			$w = $this->w;
		}
		if ($h > $this->h) {
			$y = 0;
			$h = $this->h;
		}
		if ($x > $this->w) {
			$x = $this->w - $w;
		}
		if ($y > $this->h) {
			$y = $this->h - $h;
		}

		if (!empty($bounding)) {
			// $cont_ containing block = full physical page (position: absolute) or page inside margins (position: fixed)
			// $bbox_ Bounding box is the <div> which is positioned absolutely/fixed
			// top/left/right/bottom/width/height/background*/border*/padding*/margin* are taken from bounding
			// font*[family/size/style/weight]/line-height/text*[align/decoration/transform/indent]/color are transferred to $inner
			// as an enclosing <div> (after having checked ID/CLASS)
			// $x, $y, $w, $h are inside of $bbox_ = containing box for $inner_
			// $inner_ InnerHTML is the contents of that block to be output
			$tag = $bounding[0];
			$attr = $bounding[1];
			$orig_x0 = $bounding[2];
			$orig_y0 = $bounding[3];

			// As in WriteHTML() initialising
			$this->blklvl = 0;
			$this->lastblocklevelchange = 0;
			$this->blk = [];
			$this->initialiseBlock($this->blk[0]);

			$this->blk[0]['width'] = & $this->pgwidth;
			$this->blk[0]['inner_width'] = & $this->pgwidth;

			$this->blk[0]['blockContext'] = $this->blockContext;

			$properties = $this->cssManager->MergeCSS('BLOCK', 'BODY', '');
			$this->setCSS($properties, '', 'BODY');
			$this->blklvl = 1;
			$this->initialiseBlock($this->blk[1]);
			$this->blk[1]['tag'] = $tag;
			$this->blk[1]['attr'] = $attr;
			$this->Reset();
			$p = $this->cssManager->MergeCSS('BLOCK', $tag, $attr);
			if (isset($p['ROTATE']) && ($p['ROTATE'] == 90 || $p['ROTATE'] == -90 || $p['ROTATE'] == 180)) {
				$rotate = $p['ROTATE'];
			} // mPDF 6
			if (isset($p['OVERFLOW'])) {
				$overflow = strtolower($p['OVERFLOW']);
			}
			if (strtolower($p['POSITION']) == 'fixed') {
				$cont_w = $this->pgwidth; // $this->blk[0]['inner_width'];
				$cont_h = $this->h - $this->tMargin - $this->bMargin;
				$cont_x = $this->lMargin;
				$cont_y = $this->tMargin;
			} else {
				$cont_w = $this->w; // ABSOLUTE;
				$cont_h = $this->h;
				$cont_x = 0;
				$cont_y = 0;
			}

			// Pass on in-line properties to the innerhtml
			$css = '';
			if (isset($p['TEXT-ALIGN'])) {
				$css .= 'text-align: ' . strtolower($p['TEXT-ALIGN']) . '; ';
			}
			if (isset($p['TEXT-TRANSFORM'])) {
				$css .= 'text-transform: ' . strtolower($p['TEXT-TRANSFORM']) . '; ';
			}
			if (isset($p['TEXT-INDENT'])) {
				$css .= 'text-indent: ' . strtolower($p['TEXT-INDENT']) . '; ';
			}
			if (isset($p['TEXT-DECORATION'])) {
				$css .= 'text-decoration: ' . strtolower($p['TEXT-DECORATION']) . '; ';
			}
			if (isset($p['FONT-FAMILY'])) {
				$css .= 'font-family: ' . strtolower($p['FONT-FAMILY']) . '; ';
			}
			if (isset($p['FONT-STYLE'])) {
				$css .= 'font-style: ' . strtolower($p['FONT-STYLE']) . '; ';
			}
			if (isset($p['FONT-WEIGHT'])) {
				$css .= 'font-weight: ' . strtolower($p['FONT-WEIGHT']) . '; ';
			}
			if (isset($p['FONT-SIZE'])) {
				$css .= 'font-size: ' . strtolower($p['FONT-SIZE']) . '; ';
			}
			if (isset($p['LINE-HEIGHT'])) {
				$css .= 'line-height: ' . strtolower($p['LINE-HEIGHT']) . '; ';
			}
			if (isset($p['TEXT-SHADOW'])) {
				$css .= 'text-shadow: ' . strtolower($p['TEXT-SHADOW']) . '; ';
			}
			if (isset($p['LETTER-SPACING'])) {
				$css .= 'letter-spacing: ' . strtolower($p['LETTER-SPACING']) . '; ';
			}
			// mPDF 6
			if (isset($p['FONT-VARIANT-POSITION'])) {
				$css .= 'font-variant-position: ' . strtolower($p['FONT-VARIANT-POSITION']) . '; ';
			}
			if (isset($p['FONT-VARIANT-CAPS'])) {
				$css .= 'font-variant-caps: ' . strtolower($p['FONT-VARIANT-CAPS']) . '; ';
			}
			if (isset($p['FONT-VARIANT-LIGATURES'])) {
				$css .= 'font-variant-ligatures: ' . strtolower($p['FONT-VARIANT-LIGATURES']) . '; ';
			}
			if (isset($p['FONT-VARIANT-NUMERIC'])) {
				$css .= 'font-variant-numeric: ' . strtolower($p['FONT-VARIANT-NUMERIC']) . '; ';
			}
			if (isset($p['FONT-VARIANT-ALTERNATES'])) {
				$css .= 'font-variant-alternates: ' . strtolower($p['FONT-VARIANT-ALTERNATES']) . '; ';
			}
			if (isset($p['FONT-FEATURE-SETTINGS'])) {
				$css .= 'font-feature-settings: ' . strtolower($p['FONT-FEATURE-SETTINGS']) . '; ';
			}
			if (isset($p['FONT-LANGUAGE-OVERRIDE'])) {
				$css .= 'font-language-override: ' . strtolower($p['FONT-LANGUAGE-OVERRIDE']) . '; ';
			}
			if (isset($p['FONT-KERNING'])) {
				$css .= 'font-kerning: ' . strtolower($p['FONT-KERNING']) . '; ';
			}

			if (isset($p['COLOR'])) {
				$css .= 'color: ' . strtolower($p['COLOR']) . '; ';
			}
			if (isset($p['Z-INDEX'])) {
				$css .= 'z-index: ' . $p['Z-INDEX'] . '; ';
			}
			if ($css) {
				$html = '<div style="' . $css . '">' . $html . '</div>';
			}
			// Copy over (only) the properties to set for border and background
			$pb = [];
			$pb['MARGIN-TOP'] = (isset($p['MARGIN-TOP']) ? $p['MARGIN-TOP'] : '');
			$pb['MARGIN-RIGHT'] = (isset($p['MARGIN-RIGHT']) ? $p['MARGIN-RIGHT'] : '');
			$pb['MARGIN-BOTTOM'] = (isset($p['MARGIN-BOTTOM']) ? $p['MARGIN-BOTTOM'] : '');
			$pb['MARGIN-LEFT'] = (isset($p['MARGIN-LEFT']) ? $p['MARGIN-LEFT'] : '');
			$pb['PADDING-TOP'] = (isset($p['PADDING-TOP']) ? $p['PADDING-TOP'] : '');
			$pb['PADDING-RIGHT'] = (isset($p['PADDING-RIGHT']) ? $p['PADDING-RIGHT'] : '');
			$pb['PADDING-BOTTOM'] = (isset($p['PADDING-BOTTOM']) ? $p['PADDING-BOTTOM'] : '');
			$pb['PADDING-LEFT'] = (isset($p['PADDING-LEFT']) ? $p['PADDING-LEFT'] : '');
			$pb['BORDER-TOP'] = (isset($p['BORDER-TOP']) ? $p['BORDER-TOP'] : '');
			$pb['BORDER-RIGHT'] = (isset($p['BORDER-RIGHT']) ? $p['BORDER-RIGHT'] : '');
			$pb['BORDER-BOTTOM'] = (isset($p['BORDER-BOTTOM']) ? $p['BORDER-BOTTOM'] : '');
			$pb['BORDER-LEFT'] = (isset($p['BORDER-LEFT']) ? $p['BORDER-LEFT'] : '');
			if (isset($p['BORDER-TOP-LEFT-RADIUS-H'])) {
				$pb['BORDER-TOP-LEFT-RADIUS-H'] = $p['BORDER-TOP-LEFT-RADIUS-H'];
			}
			if (isset($p['BORDER-TOP-LEFT-RADIUS-V'])) {
				$pb['BORDER-TOP-LEFT-RADIUS-V'] = $p['BORDER-TOP-LEFT-RADIUS-V'];
			}
			if (isset($p['BORDER-TOP-RIGHT-RADIUS-H'])) {
				$pb['BORDER-TOP-RIGHT-RADIUS-H'] = $p['BORDER-TOP-RIGHT-RADIUS-H'];
			}
			if (isset($p['BORDER-TOP-RIGHT-RADIUS-V'])) {
				$pb['BORDER-TOP-RIGHT-RADIUS-V'] = $p['BORDER-TOP-RIGHT-RADIUS-V'];
			}
			if (isset($p['BORDER-BOTTOM-LEFT-RADIUS-H'])) {
				$pb['BORDER-BOTTOM-LEFT-RADIUS-H'] = $p['BORDER-BOTTOM-LEFT-RADIUS-H'];
			}
			if (isset($p['BORDER-BOTTOM-LEFT-RADIUS-V'])) {
				$pb['BORDER-BOTTOM-LEFT-RADIUS-V'] = $p['BORDER-BOTTOM-LEFT-RADIUS-V'];
			}
			if (isset($p['BORDER-BOTTOM-RIGHT-RADIUS-H'])) {
				$pb['BORDER-BOTTOM-RIGHT-RADIUS-H'] = $p['BORDER-BOTTOM-RIGHT-RADIUS-H'];
			}
			if (isset($p['BORDER-BOTTOM-RIGHT-RADIUS-V'])) {
				$pb['BORDER-BOTTOM-RIGHT-RADIUS-V'] = $p['BORDER-BOTTOM-RIGHT-RADIUS-V'];
			}
			if (isset($p['BACKGROUND-COLOR'])) {
				$pb['BACKGROUND-COLOR'] = $p['BACKGROUND-COLOR'];
			}
			if (isset($p['BOX-SHADOW'])) {
				$pb['BOX-SHADOW'] = $p['BOX-SHADOW'];
			}
			/* -- BACKGROUNDS -- */
			if (isset($p['BACKGROUND-IMAGE'])) {
				$pb['BACKGROUND-IMAGE'] = $p['BACKGROUND-IMAGE'];
			}
			if (isset($p['BACKGROUND-IMAGE-RESIZE'])) {
				$pb['BACKGROUND-IMAGE-RESIZE'] = $p['BACKGROUND-IMAGE-RESIZE'];
			}
			if (isset($p['BACKGROUND-IMAGE-OPACITY'])) {
				$pb['BACKGROUND-IMAGE-OPACITY'] = $p['BACKGROUND-IMAGE-OPACITY'];
			}
			if (isset($p['BACKGROUND-REPEAT'])) {
				$pb['BACKGROUND-REPEAT'] = $p['BACKGROUND-REPEAT'];
			}
			if (isset($p['BACKGROUND-POSITION'])) {
				$pb['BACKGROUND-POSITION'] = $p['BACKGROUND-POSITION'];
			}
			if (isset($p['BACKGROUND-GRADIENT'])) {
				$pb['BACKGROUND-GRADIENT'] = $p['BACKGROUND-GRADIENT'];
			}
			if (isset($p['BACKGROUND-SIZE'])) {
				$pb['BACKGROUND-SIZE'] = $p['BACKGROUND-SIZE'];
			}
			if (isset($p['BACKGROUND-ORIGIN'])) {
				$pb['BACKGROUND-ORIGIN'] = $p['BACKGROUND-ORIGIN'];
			}
			if (isset($p['BACKGROUND-CLIP'])) {
				$pb['BACKGROUND-CLIP'] = $p['BACKGROUND-CLIP'];
			}

			/* -- END BACKGROUNDS -- */

			$this->setCSS($pb, 'BLOCK', $tag);

			// ================================================================
			$bbox_br = $this->blk[1]['border_right']['w'];
			$bbox_bl = $this->blk[1]['border_left']['w'];
			$bbox_bt = $this->blk[1]['border_top']['w'];
			$bbox_bb = $this->blk[1]['border_bottom']['w'];
			$bbox_pr = $this->blk[1]['padding_right'];
			$bbox_pl = $this->blk[1]['padding_left'];
			$bbox_pt = $this->blk[1]['padding_top'];
			$bbox_pb = $this->blk[1]['padding_bottom'];
			$bbox_mr = $this->blk[1]['margin_right'];
			if (isset($p['MARGIN-RIGHT']) && strtolower($p['MARGIN-RIGHT']) == 'auto') {
				$bbox_mr = 'auto';
			}
			$bbox_ml = $this->blk[1]['margin_left'];
			if (isset($p['MARGIN-LEFT']) && strtolower($p['MARGIN-LEFT']) == 'auto') {
				$bbox_ml = 'auto';
			}
			$bbox_mt = $this->blk[1]['margin_top'];
			if (isset($p['MARGIN-TOP']) && strtolower($p['MARGIN-TOP']) == 'auto') {
				$bbox_mt = 'auto';
			}
			$bbox_mb = $this->blk[1]['margin_bottom'];
			if (isset($p['MARGIN-BOTTOM']) && strtolower($p['MARGIN-BOTTOM']) == 'auto') {
				$bbox_mb = 'auto';
			}
			if (isset($p['LEFT']) && strtolower($p['LEFT']) != 'auto') {
				$bbox_left = $this->sizeConverter->convert($p['LEFT'], $cont_w, $this->FontSize, false);
			} else {
				$bbox_left = 'auto';
			}
			if (isset($p['TOP']) && strtolower($p['TOP']) != 'auto') {
				$bbox_top = $this->sizeConverter->convert($p['TOP'], $cont_h, $this->FontSize, false);
			} else {
				$bbox_top = 'auto';
			}
			if (isset($p['RIGHT']) && strtolower($p['RIGHT']) != 'auto') {
				$bbox_right = $this->sizeConverter->convert($p['RIGHT'], $cont_w, $this->FontSize, false);
			} else {
				$bbox_right = 'auto';
			}
			if (isset($p['BOTTOM']) && strtolower($p['BOTTOM']) != 'auto') {
				$bbox_bottom = $this->sizeConverter->convert($p['BOTTOM'], $cont_h, $this->FontSize, false);
			} else {
				$bbox_bottom = 'auto';
			}
			if (isset($p['WIDTH']) && strtolower($p['WIDTH']) != 'auto') {
				$inner_w = $this->sizeConverter->convert($p['WIDTH'], $cont_w, $this->FontSize, false);
			} else {
				$inner_w = 'auto';
			}
			if (isset($p['HEIGHT']) && strtolower($p['HEIGHT']) != 'auto') {
				$inner_h = $this->sizeConverter->convert($p['HEIGHT'], $cont_h, $this->FontSize, false);
			} else {
				$inner_h = 'auto';
			}

			// If bottom or right pos are set and not left / top - save this to adjust rotated block later
			if ($rotate == 90 || $rotate == -90) { // mPDF 6
				if ($bbox_left === 'auto' && $bbox_right !== 'auto') {
					$rot_rpos = $bbox_right;
				} else {
					$rot_rpos = false;
				}
				if ($bbox_top === 'auto' && $bbox_bottom !== 'auto') {
					$rot_bpos = $bbox_bottom;
				} else {
					$rot_bpos = false;
				}
			}

			// ================================================================
			if ($checkinnerhtml == '' && $inner_h === 'auto') {
				$inner_h = 0.0001;
			}
			if ($checkinnerhtml == '' && $inner_w === 'auto') {
				$inner_w = 2 * $this->GetCharWidth('W', false);
			}
			// ================================================================
			// Algorithm from CSS2.1  See http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height
			// mPD 5.3.14
			// Special case (not CSS) if all not specified, centre vertically on page
			$bbox_top_orig = '';
			if ($bbox_top === 'auto' && $inner_h === 'auto' && $bbox_bottom === 'auto' && $bbox_mt === 'auto' && $bbox_mb === 'auto') {
				$bbox_top_orig = $bbox_top;
				if ($bbox_mt === 'auto') {
					$bbox_mt = 0;
				}
				if ($bbox_mb === 'auto') {
					$bbox_mb = 0;
				}
				$bbox_top = $orig_y0 - $bbox_mt - $cont_y;
				// solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
			} // mPD 5.3.14
			elseif ($bbox_top === 'auto' && $inner_h === 'auto' && $bbox_bottom === 'auto') {
				$bbox_top_orig = $bbox_top = $orig_y0 - $cont_y;
				if ($bbox_mt === 'auto') {
					$bbox_mt = 0;
				}
				if ($bbox_mb === 'auto') {
					$bbox_mb = 0;
				}
				// solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
			} elseif ($bbox_top !== 'auto' && $inner_h !== 'auto' && $bbox_bottom !== 'auto') {
				if ($bbox_mt === 'auto' && $bbox_mb === 'auto') {
					$x = $cont_h - $bbox_top - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_bottom;
					$bbox_mt = $bbox_mb = ($x / 2);
				} elseif ($bbox_mt === 'auto') {
					$bbox_mt = $cont_h - $bbox_top - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
				} elseif ($bbox_mb === 'auto') {
					$bbox_mb = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_bottom;
				} else {
					$bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt;
				}
			} else {
				if ($bbox_mt === 'auto') {
					$bbox_mt = 0;
				}
				if ($bbox_mb === 'auto') {
					$bbox_mb = 0;
				}
				if ($bbox_top === 'auto' && $inner_h === 'auto' && $bbox_bottom !== 'auto') {
					// solve for $bbox_top when content_h known - $inner_h=='auto' && $bbox_top =='auto'
				} elseif ($bbox_top === 'auto' && $bbox_bottom === 'auto' && $inner_h !== 'auto') {
					$bbox_top = $orig_y0 - $bbox_mt - $cont_y;
					$bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt;
				} elseif ($inner_h === 'auto' && $bbox_bottom === 'auto' && $bbox_top !== 'auto') {
					// solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
				} elseif ($bbox_top === 'auto' && $inner_h !== 'auto' && $bbox_bottom !== 'auto') {
					$bbox_top = $cont_h - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt - $bbox_bottom;
				} elseif ($inner_h === 'auto' && $bbox_top !== 'auto' && $bbox_bottom !== 'auto') {
					$inner_h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mt - $bbox_bottom;
				} elseif ($bbox_bottom === 'auto' && $bbox_top !== 'auto' && $inner_h !== 'auto') {
					$bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt;
				}
			}

			// THEN DO SAME FOR WIDTH
			// http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width
			if ($bbox_left === 'auto' && $inner_w === 'auto' && $bbox_right === 'auto') {
				if ($bbox_ml === 'auto') {
					$bbox_ml = 0;
				}
				if ($bbox_mr === 'auto') {
					$bbox_mr = 0;
				}
				// IF containing element RTL, should set $bbox_right
				$bbox_left = $orig_x0 - $bbox_ml - $cont_x;
				// solve for $bbox_right when content_w known - $inner_w=='auto' && $bbox_right=='auto'
			} elseif ($bbox_left !== 'auto' && $inner_w !== 'auto' && $bbox_right !== 'auto') {
				if ($bbox_ml === 'auto' && $bbox_mr === 'auto') {
					$x = $cont_w - $bbox_left - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_right;
					$bbox_ml = $bbox_mr = ($x / 2);
				} elseif ($bbox_ml === 'auto') {
					$bbox_ml = $cont_w - $bbox_left - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_mr - $bbox_right;
				} elseif ($bbox_mr === 'auto') {
					$bbox_mr = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_right;
				} else {
					$bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
				}
			} else {
				if ($bbox_ml === 'auto') {
					$bbox_ml = 0;
				}
				if ($bbox_mr === 'auto') {
					$bbox_mr = 0;
				}
				if ($bbox_left === 'auto' && $inner_w === 'auto' && $bbox_right !== 'auto') {
					// solve for $bbox_left when content_w known - $inner_w=='auto' && $bbox_left =='auto'
				} elseif ($bbox_left === 'auto' && $bbox_right === 'auto' && $inner_w !== 'auto') {
					// IF containing element RTL, should set $bbox_right
					$bbox_left = $orig_x0 - $bbox_ml - $cont_x;
					$bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
				} elseif ($inner_w === 'auto' && $bbox_right === 'auto' && $bbox_left !== 'auto') {
					// solve for $bbox_right when content_w known - $inner_w=='auto' && $bbox_right=='auto'
				} elseif ($bbox_left === 'auto' && $inner_w !== 'auto' && $bbox_right !== 'auto') {
					$bbox_left = $cont_w - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml - $bbox_right;
				} elseif ($inner_w === 'auto' && $bbox_left !== 'auto' && $bbox_right !== 'auto') {
					$inner_w = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $bbox_pr - $bbox_br - $bbox_ml - $bbox_right;
				} elseif ($bbox_right === 'auto' && $bbox_left !== 'auto' && $inner_w !== 'auto') {
					$bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
				}
			}

			// ================================================================
			// ================================================================
			/* -- BACKGROUNDS -- */
			if (isset($pb['BACKGROUND-IMAGE']) && $pb['BACKGROUND-IMAGE']) {
				$ret = $this->SetBackground($pb, $this->blk[1]['inner_width']);
				if ($ret) {
					$this->blk[1]['background-image'] = $ret;
				}
			}
			/* -- END BACKGROUNDS -- */

			$bbox_top_auto = $bbox_top === 'auto';
			$bbox_left_auto = $bbox_left === 'auto';
			$bbox_right_auto = $bbox_right === 'auto';
			$bbox_bottom_auto = $bbox_bottom === 'auto';

			$bbox_top = is_numeric($bbox_top) ? $bbox_top : 0;
			$bbox_left = is_numeric($bbox_left) ? $bbox_left : 0;
			$bbox_right = is_numeric($bbox_right) ? $bbox_right : 0;
			$bbox_bottom = is_numeric($bbox_bottom) ? $bbox_bottom : 0;

			$y = $cont_y + $bbox_top + $bbox_mt + $bbox_bt + $bbox_pt;
			$h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;

			$x = $cont_x + $bbox_left + $bbox_ml + $bbox_bl + $bbox_pl;
			$w = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $bbox_pr - $bbox_br - $bbox_mr - $bbox_right;

			// Set (temporary) values for x y w h to do first paint, if values are auto
			if ($inner_h === 'auto' && $bbox_top_auto) {
				$y = $cont_y + $bbox_mt + $bbox_bt + $bbox_pt;
				$h = $cont_h - ($bbox_bottom + $bbox_mt + $bbox_mb + $bbox_bt + $bbox_bb + $bbox_pt + $bbox_pb);
			} elseif ($inner_h === 'auto' && $bbox_bottom_auto) {
				$y = $cont_y + $bbox_top + $bbox_mt + $bbox_bt + $bbox_pt;
				$h = $cont_h - ($bbox_top + $bbox_mt + $bbox_mb + $bbox_bt + $bbox_bb + $bbox_pt + $bbox_pb);
			}
			if ($inner_w === 'auto' && $bbox_left_auto) {
				$x = $cont_x + $bbox_ml + $bbox_bl + $bbox_pl;
				$w = $cont_w - ($bbox_right + $bbox_ml + $bbox_mr + $bbox_bl + $bbox_br + $bbox_pl + $bbox_pr);
			} elseif ($inner_w === 'auto' && $bbox_right_auto) {
				$x = $cont_x + $bbox_left + $bbox_ml + $bbox_bl + $bbox_pl;
				$w = $cont_w - ($bbox_left + $bbox_ml + $bbox_mr + $bbox_bl + $bbox_br + $bbox_pl + $bbox_pr);
			}

			$bbox_y = $cont_y + $bbox_top + $bbox_mt;
			$bbox_x = $cont_x + $bbox_left + $bbox_ml;

			$saved_block1 = $this->blk[1];

			unset($p);
			unset($pb);

			// ================================================================
			if ($inner_w === 'auto') { // do a first write
				$this->lMargin = $x;
				$this->rMargin = $this->w - $w - $x;

				// SET POSITION & FONT VALUES
				$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
				$this->pageoutput[$this->page] = [];
				$this->x = $x;
				$this->y = $y;
				$this->HTMLheaderPageLinks = [];
				$this->HTMLheaderPageAnnots = [];
				$this->HTMLheaderPageForms = [];
				$this->pageBackgrounds = [];
				$this->maxPosR = 0;
				$this->maxPosL = $this->w; // For RTL
				$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
				$inner_w = $this->maxPosR - $this->lMargin;
				if ($bbox_right_auto) {
					$bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
				} elseif ($bbox_left_auto) {
					$bbox_left = $cont_w - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml - $bbox_right;
					$bbox_x = $cont_x + $bbox_left + $bbox_ml;
					$inner_x = $bbox_x + $bbox_bl + $bbox_pl;
					$x = $inner_x;
				}

				$w = $inner_w;
				$bbox_y = $cont_y + $bbox_top + $bbox_mt;
				$bbox_x = $cont_x + $bbox_left + $bbox_ml;
			}

			if ($inner_h === 'auto') { // do a first write

				$this->lMargin = $x;
				$this->rMargin = $this->w - $w - $x;

				// SET POSITION & FONT VALUES
				$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
				$this->pageoutput[$this->page] = [];
				$this->x = $x;
				$this->y = $y;
				$this->HTMLheaderPageLinks = [];
				$this->HTMLheaderPageAnnots = [];
				$this->HTMLheaderPageForms = [];
				$this->pageBackgrounds = [];
				$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
				$inner_h = $this->y - $y;

				if ($overflow != 'hidden' && $overflow != 'visible') { // constrained
					if (($this->y + $bbox_pb + $bbox_bb) > ($cont_y + $cont_h)) {
						$adj = ($this->y + $bbox_pb + $bbox_bb) - ($cont_y + $cont_h);
						$inner_h -= $adj;
					}
				}
				if ($bbox_bottom_auto && $bbox_top_orig === 'auto') {
					$bbox_bottom = $bbox_top = ($cont_h - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb) / 2;
					if ($overflow != 'hidden' && $overflow != 'visible') { // constrained
						if ($bbox_top < 0) {
							$bbox_top = 0;
							$inner_h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
						}
					}
					$bbox_y = $cont_y + $bbox_top + $bbox_mt;
					$inner_y = $bbox_y + $bbox_bt + $bbox_pt;
					$y = $inner_y;
				} elseif ($bbox_bottom_auto) {
					$bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb;
				} elseif ($bbox_top_auto) {
					$bbox_top = $cont_h - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
					if ($overflow != 'hidden' && $overflow != 'visible') { // constrained
						if ($bbox_top < 0) {
							$bbox_top = 0;
							$inner_h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
						}
					}
					$bbox_y = $cont_y + $bbox_top + $bbox_mt;
					$inner_y = $bbox_y + $bbox_bt + $bbox_pt;
					$y = $inner_y;
				}
				$h = $inner_h;
				$bbox_y = $cont_y + $bbox_top + $bbox_mt;
				$bbox_x = $cont_x + $bbox_left + $bbox_ml;
			}

			$inner_w = $w;
			$inner_h = $h;
		}

		$this->lMargin = $x;
		$this->rMargin = $this->w - $w - $x;

		// SET POSITION & FONT VALUES
		$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
		$this->pageoutput[$this->page] = [];

		$this->x = $x;
		$this->y = $y;

		$this->HTMLheaderPageLinks = [];
		$this->HTMLheaderPageAnnots = [];
		$this->HTMLheaderPageForms = [];

		$this->pageBackgrounds = [];

		$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);

		$actual_h = $this->y - $y;
		$use_w = $w;
		$use_h = $h;
		$ratio = $actual_h / $use_w;

		if ($overflow != 'hidden' && $overflow != 'visible') {
			$target = $h / $w;
			if ($target > 0) {
				if (($ratio / $target) > 1) {
					$nl = ceil($actual_h / $this->lineheight);
					$l = $use_w * $nl;
					$est_w = sqrt(($l * $this->lineheight) / $target) * 0.8;
					$use_w += ($est_w - $use_w) - ($w / 100);
				}
				$bpcstart = ($ratio / $target);
				$bpcctr = 1;

				while (($ratio / $target) > 1) {
					// @log 'Auto-sizing fixed-position block $bpcctr++

					$this->x = $x;
					$this->y = $y;

					if (($ratio / $target) > 1.5 || ($ratio / $target) < 0.6) {
						$use_w += ($w / $this->incrementFPR1);
					} elseif (($ratio / $target) > 1.2 || ($ratio / $target) < 0.85) {
						$use_w += ($w / $this->incrementFPR2);
					} elseif (($ratio / $target) > 1.1 || ($ratio / $target) < 0.91) {
						$use_w += ($w / $this->incrementFPR3);
					} else {
						$use_w += ($w / $this->incrementFPR4);
					}

					$use_h = $use_w * $target;
					$this->rMargin = $this->w - $use_w - $x;
					$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
					$this->HTMLheaderPageLinks = [];
					$this->HTMLheaderPageAnnots = [];
					$this->HTMLheaderPageForms = [];
					$this->pageBackgrounds = [];
					$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
					$actual_h = $this->y - $y;
					$ratio = $actual_h / $use_w;
				}
			}
		}

		$shrink_f = $w / $use_w;

		// ================================================================

		$this->pages[$this->page] .= '___BEFORE_BORDERS___';
		$block_s = $this->PrintPageBackgrounds(); // Save to print later inside clipping path
		$this->pageBackgrounds = [];

		// ================================================================

		if ($rotate == 90 || $rotate == -90) { // mPDF 6
			$prerotw = $bbox_bl + $bbox_pl + $inner_w + $bbox_pr + $bbox_br;
			$preroth = $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb;
			$rot_start = " q\n";
			if ($rotate == 90) {
				if ($rot_rpos !== false) {
					$adjw = $prerotw;
				} // width before rotation
				else {
					$adjw = $preroth;
				} // height before rotation
				if ($rot_bpos !== false) {
					$adjh = -$prerotw + $preroth;
				} else {
					$adjh = 0;
				}
			} else {
				if ($rot_rpos !== false) {
					$adjw = $prerotw - $preroth;
				} else {
					$adjw = 0;
				}
				if ($rot_bpos !== false) {
					$adjh = $preroth;
				} // height before rotation
				else {
					$adjh = $prerotw;
				} // width before rotation
			}
			$rot_start .= $this->transformTranslate($adjw, $adjh, true) . "\n";
			$rot_start .= $this->transformRotate($rotate, $bbox_x, $bbox_y, true) . "\n";
			$rot_end = " Q\n";
		} elseif ($rotate == 180) { // mPDF 6
			$rot_start = " q\n";
			$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";
			$rot_start .= $this->transformRotate(180, $bbox_x, $bbox_y, true) . "\n";
			$rot_end = " Q\n";
		} else {
			$rot_start = '';
			$rot_end = '';
		}

		// ================================================================
		if (!empty($bounding)) {
			// WHEN HEIGHT // BOTTOM EDGE IS KNOWN and $this->y is set to the bottom
			// Re-instate saved $this->blk[1]
			$this->blk[1] = $saved_block1;

			// These are only needed when painting border/background
			$this->blk[1]['width'] = $bbox_w = $cont_w - $bbox_left - $bbox_ml - $bbox_mr - $bbox_right;
			$this->blk[1]['x0'] = $bbox_x;
			$this->blk[1]['y0'] = $bbox_y;
			$this->blk[1]['startpage'] = $this->page;
			$this->blk[1]['y1'] = $bbox_y + $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb;
			$this->writer->write($rot_start);
			$this->PaintDivBB('', 0, 1); // Prints borders and sets backgrounds in $this->pageBackgrounds
			$this->writer->write($rot_end);
		}

		$s = $this->PrintPageBackgrounds();
		$s = $rot_start . $s . $rot_end;
		$this->pages[$this->page] = preg_replace('/___BEFORE_BORDERS___/', "\n" . $s . "\n", $this->pages[$this->page]);
		$this->pageBackgrounds = [];

		$this->writer->write($rot_start);

		// Clipping Output
		if ($overflow == 'hidden') {
			// Bounding rectangle to clip
			$clip_y1 = $this->y;
			if (!empty($bounding) && ($this->y + $bbox_pb + $bbox_bb) > ($bbox_y + $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb )) {
				$clip_y1 = ($bbox_y + $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb ) - ($bbox_pb + $bbox_bb);
			}
			// $op = 'W* n';	// Clipping
			$op = 'W n'; // Clipping alternative mode
			$this->writer->write("q");
			$ch = $clip_y1 - $y;
			$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));
			if (!empty($block_s)) {
				$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);
				$tmp .= "\n" . $block_s . "\nQ";
				$block_s = $tmp;
			}
		}


		if (!empty($block_s)) {
			if ($shrink_f != 1) { // i.e. autofit has resized the box
				$tmp = "q\n" . $this->transformScale(($shrink_f * 100), ($shrink_f * 100), $x, $y, true);
				$tmp .= "\n" . $block_s . "\nQ";
				$block_s = $tmp;
			}
			$this->writer->write($block_s);
		}



		if ($shrink_f != 1) { // i.e. autofit has resized the box
			$this->StartTransform();
			$this->transformScale(($shrink_f * 100), ($shrink_f * 100), $x, $y);
		}

		$this->writer->write($this->headerbuffer);

		if ($shrink_f != 1) { // i.e. autofit has resized the box
			$this->StopTransform();
		}

		if ($overflow == 'hidden') {
			// End clipping
			$this->writer->write("Q");
		}

		$this->writer->write($rot_end);


		// Page Links
		foreach ($this->HTMLheaderPageLinks as $lk) {
			if ($rotate) {
				$tmp = $lk[2]; // Switch h - w
				$lk[2] = $lk[3];
				$lk[3] = $tmp;

				$lx1 = (($lk[0] / Mpdf::SCALE));
				$ly1 = (($this->h - ($lk[1] / Mpdf::SCALE)));
				if ($rotate == 90) {
					$adjx = -($lx1 - $bbox_x) + ($preroth - ($ly1 - $bbox_y));
					$adjy = -($ly1 - $bbox_y) + ($lx1 - $bbox_x);
					$lk[2] = -$lk[2];
				} elseif ($rotate == -90) {
					$adjx = -($lx1 - $bbox_x) + ($ly1 - $bbox_y);
					$adjy = -($ly1 - $bbox_y) - ($lx1 - $bbox_x) + $prerotw;
					$lk[3] = -$lk[3];
				}
				if ($rot_rpos !== false) {
					$adjx += $prerotw - $preroth;
				}
				if ($rot_bpos !== false) {
					$adjy += $preroth - $prerotw;
				}
				$lx1 += $adjx;
				$ly1 += $adjy;

				$lk[0] = $lx1 * Mpdf::SCALE;
				$lk[1] = ($this->h - $ly1) * Mpdf::SCALE;
			}
			if ($shrink_f != 1) {  // i.e. autofit has resized the box
				$lx1 = (($lk[0] / Mpdf::SCALE) - $x);
				$lx2 = $x + ($lx1 * $shrink_f);
				$lk[0] = $lx2 * Mpdf::SCALE;
				$ly1 = (($this->h - ($lk[1] / Mpdf::SCALE)) - $y);
				$ly2 = $y + ($ly1 * $shrink_f);
				$lk[1] = ($this->h - $ly2) * Mpdf::SCALE;
				$lk[2] *= $shrink_f; // width
				$lk[3] *= $shrink_f; // height
			}
			$this->PageLinks[$this->page][] = $lk;
		}

		foreach ($this->HTMLheaderPageForms as $n => $f) {
			if ($shrink_f != 1) {  // i.e. autofit has resized the box
				$f['x'] = $x + (($f['x'] - $x) * $shrink_f);
				$f['y'] = $y + (($f['y'] - $y) * $shrink_f);
				$f['w'] *= $shrink_f;
				$f['h'] *= $shrink_f;
				$f['style']['fontsize'] *= $shrink_f;
			}
			$this->form->forms[$f['n']] = $f;
		}
		// Page Annotations
		foreach ($this->HTMLheaderPageAnnots as $lk) {
			if ($rotate) {
				if ($rotate == 90) {
					$adjx = -($lk['x'] - $bbox_x) + ($preroth - ($lk['y'] - $bbox_y));
					$adjy = -($lk['y'] - $bbox_y) + ($lk['x'] - $bbox_x);
				} elseif ($rotate == -90) {
					$adjx = -($lk['x'] - $bbox_x) + ($lk['y'] - $bbox_y);
					$adjy = -($lk['y'] - $bbox_y) - ($lk['x'] - $bbox_x) + $prerotw;
				}
				if ($rot_rpos !== false) {
					$adjx += $prerotw - $preroth;
				}
				if ($rot_bpos !== false) {
					$adjy += $preroth - $prerotw;
				}
				$lk['x'] += $adjx;
				$lk['y'] += $adjy;
			}
			if ($shrink_f != 1) {  // i.e. autofit has resized the box
				$lk['x'] = $x + (($lk['x'] - $x) * $shrink_f);
				$lk['y'] = $y + (($lk['y'] - $y) * $shrink_f);
			}
			$this->PageAnnots[$this->page][] = $lk;
		}

		// Restore
		$this->headerbuffer = '';
		$this->HTMLheaderPageLinks = [];
		$this->HTMLheaderPageAnnots = [];
		$this->HTMLheaderPageForms = [];
		$this->pageBackgrounds = $save_bgs;
		$this->writingHTMLheader = false;

		$this->writingHTMLfooter = false;
		$this->fullImageHeight = false;
		$this->ResetMargins();
		$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
		$this->SetXY($save_x, $save_y);
		$this->title2annots = $save_annots; // *ANNOTATIONS*
		$this->InFooter = false; // turns back on autopagebreaks
		$this->pageoutput[$this->page] = [];
		$this->pageoutput[$this->page]['Font'] = '';
		/* -- COLUMNS -- */
		if ($save_cols) {
			$this->SetColumns($save_nbcol, $this->colvAlign, $this->ColGap);
		}
		/* -- END COLUMNS -- */
	}

	/* -- END CSS-POSITION -- */

	function initialiseBlock(&$blk)
	{
		$blk['margin_top'] = 0;
		$blk['margin_left'] = 0;
		$blk['margin_bottom'] = 0;
		$blk['margin_right'] = 0;
		$blk['padding_top'] = 0;
		$blk['padding_left'] = 0;
		$blk['padding_bottom'] = 0;
		$blk['padding_right'] = 0;
		$blk['border_top']['w'] = 0;
		$blk['border_left']['w'] = 0;
		$blk['border_bottom']['w'] = 0;
		$blk['border_right']['w'] = 0;
		$blk['direction'] = 'ltr';
		$blk['hide'] = false;
		$blk['outer_left_margin'] = 0;
		$blk['outer_right_margin'] = 0;
		$blk['cascadeCSS'] = [];
		$blk['block-align'] = false;
		$blk['bgcolor'] = false;
		$blk['page_break_after_avoid'] = false;
		$blk['keep_block_together'] = false;
		$blk['float'] = false;
		$blk['line_height'] = '';
		$blk['margin_collapse'] = false;
	}

	function border_details($bd)
	{
		$prop = preg_split('/\s+/', trim($bd));

		if (isset($this->blk[$this->blklvl]['inner_width'])) {
			$refw = $this->blk[$this->blklvl]['inner_width'];
		} elseif (isset($this->blk[$this->blklvl - 1]['inner_width'])) {
			$refw = $this->blk[$this->blklvl - 1]['inner_width'];
		} else {
			$refw = $this->w;
		}
		if (count($prop) == 1) {
			$bsize = $this->sizeConverter->convert($prop[0], $refw, $this->FontSize, false);
			if ($bsize > 0) {
				return ['s' => 1, 'w' => $bsize, 'c' => $this->colorConverter->convert(0, $this->PDFAXwarnings), 'style' => 'solid'];
			} else {
				return ['w' => 0, 's' => 0];
			}
		} elseif (count($prop) == 2) {
			// 1px solid
			if (in_array($prop[1], $this->borderstyles) || $prop[1] == 'none' || $prop[1] == 'hidden') {
				$prop[2] = '';
			} // solid #000000
			elseif (in_array($prop[0], $this->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden') {
				$prop[0] = '';
				$prop[1] = $prop[0];
				$prop[2] = $prop[1];
			} // 1px #000000
			else {
				$prop[1] = '';
				$prop[2] = $prop[1];
			}
		} elseif (count($prop) == 3) {
			// Change #000000 1px solid to 1px solid #000000 (proper)
			if (substr($prop[0], 0, 1) == '#') {
				$tmp = $prop[0];
				$prop[0] = $prop[1];
				$prop[1] = $prop[2];
				$prop[2] = $tmp;
			} // Change solid #000000 1px to 1px solid #000000 (proper)
			elseif (substr($prop[0], 1, 1) == '#') {
				$tmp = $prop[1];
				$prop[0] = $prop[2];
				$prop[1] = $prop[0];
				$prop[2] = $tmp;
			} // Change solid 1px #000000 to 1px solid #000000 (proper)
			elseif (in_array($prop[0], $this->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden') {
				$tmp = $prop[0];
				$prop[0] = $prop[1];
				$prop[1] = $tmp;
			}
		} else {
			return ['w' => 0, 's' => 0];
		}
		// Size
		$bsize = $this->sizeConverter->convert($prop[0], $refw, $this->FontSize, false);
		// color
		$coul = $this->colorConverter->convert($prop[2], $this->PDFAXwarnings); // returns array
		// Style
		$prop[1] = strtolower($prop[1]);
		if (in_array($prop[1], $this->borderstyles) && $bsize > 0) {
			$on = 1;
		} elseif ($prop[1] == 'hidden') {
			$on = 1;
			$bsize = 0;
			$coul = '';
		} elseif ($prop[1] == 'none') {
			$on = 0;
			$bsize = 0;
			$coul = '';
		} else {
			$on = 0;
			$bsize = 0;
			$coul = '';
			$prop[1] = '';
		}
		return ['s' => $on, 'w' => $bsize, 'c' => $coul, 'style' => $prop[1], 'dom' => 0];
	}

	/* -- END HTML-CSS -- */


	/* -- BORDER-RADIUS -- */

	function _borderPadding($a, $b, &$px, &$py)
	{
		// $px and py are padding long axis (x) and short axis (y)
		$added = 0; // extra padding

		$x = $a - $px;
		$y = $b - $py;
		// Check if Falls within ellipse of border radius
		if (( (($x + $added) * ($x + $added)) / ($a * $a) + (($y + $added) * ($y + $added)) / ($b * $b) ) <= 1) {
			return false;
		}

		$t = atan2($y, $x);

		$newx = $b / sqrt((($b * $b) / ($a * $a)) + ( tan($t) * tan($t) ));
		$newy = $a / sqrt((($a * $a) / ($b * $b)) + ( (1 / tan($t)) * (1 / tan($t)) ));
		$px = max($px, $a - $newx + $added);
		$py = max($py, $b - $newy + $added);
	}

	/* -- END BORDER-RADIUS -- */
	/* -- HTML-CSS -- */
	/* -- CSS-PAGE -- */

	function SetPagedMediaCSS($name, $first, $oddEven)
	{
		if ($oddEven == 'E') {
			if ($this->directionality == 'rtl') {
				$side = 'R';
			} else {
				$side = 'L';
			}
		} else {
			if ($this->directionality == 'rtl') {
				$side = 'L';
			} else {
				$side = 'R';
			}
		}
		$name = strtoupper($name);
		$p = [];
		$p['SIZE'] = 'AUTO';

		// Uses mPDF original margins as default
		$p['MARGIN-RIGHT'] = strval($this->orig_rMargin) . 'mm';
		$p['MARGIN-LEFT'] = strval($this->orig_lMargin) . 'mm';
		$p['MARGIN-TOP'] = strval($this->orig_tMargin) . 'mm';
		$p['MARGIN-BOTTOM'] = strval($this->orig_bMargin) . 'mm';
		$p['MARGIN-HEADER'] = strval($this->orig_hMargin) . 'mm';
		$p['MARGIN-FOOTER'] = strval($this->orig_fMargin) . 'mm';

		// Basic page + selector
		if (isset($this->cssManager->CSS['@PAGE'])) {
			$zp = $this->cssManager->CSS['@PAGE'];
		} else {
			$zp = [];
		}
		if (is_array($zp) && !empty($zp)) {
			$p = array_merge($p, $zp);
		}

		if (isset($p['EVEN-HEADER-NAME']) && $oddEven == 'E') {
			$p['HEADER'] = $p['EVEN-HEADER-NAME'];
			unset($p['EVEN-HEADER-NAME']);
		}
		if (isset($p['ODD-HEADER-NAME']) && $oddEven != 'E') {
			$p['HEADER'] = $p['ODD-HEADER-NAME'];
			unset($p['ODD-HEADER-NAME']);
		}
		if (isset($p['EVEN-FOOTER-NAME']) && $oddEven == 'E') {
			$p['FOOTER'] = $p['EVEN-FOOTER-NAME'];
			unset($p['EVEN-FOOTER-NAME']);
		}
		if (isset($p['ODD-FOOTER-NAME']) && $oddEven != 'E') {
			$p['FOOTER'] = $p['ODD-FOOTER-NAME'];
			unset($p['ODD-FOOTER-NAME']);
		}

		// If right/Odd page
		if (isset($this->cssManager->CSS['@PAGE>>PSEUDO>>RIGHT']) && $side == 'R') {
			$zp = $this->cssManager->CSS['@PAGE>>PSEUDO>>RIGHT'];
		} else {
			$zp = [];
		}
		if (isset($zp['SIZE'])) {
			unset($zp['SIZE']);
		}
		if (isset($zp['SHEET-SIZE'])) {
			unset($zp['SHEET-SIZE']);
		}
		// Disallow margin-left or -right on :LEFT or :RIGHT
		if (isset($zp['MARGIN-LEFT'])) {
			unset($zp['MARGIN-LEFT']);
		}
		if (isset($zp['MARGIN-RIGHT'])) {
			unset($zp['MARGIN-RIGHT']);
		}
		if (is_array($zp) && !empty($zp)) {
			$p = array_merge($p, $zp);
		}

		// If left/Even page
		if (isset($this->cssManager->CSS['@PAGE>>PSEUDO>>LEFT']) && $side == 'L') {
			$zp = $this->cssManager->CSS['@PAGE>>PSEUDO>>LEFT'];
		} else {
			$zp = [];
		}
		if (isset($zp['SIZE'])) {
			unset($zp['SIZE']);
		}
		if (isset($zp['SHEET-SIZE'])) {
			unset($zp['SHEET-SIZE']);
		}
		// Disallow margin-left or -right on :LEFT or :RIGHT
		if (isset($zp['MARGIN-LEFT'])) {
			unset($zp['MARGIN-LEFT']);
		}
		if (isset($zp['MARGIN-RIGHT'])) {
			unset($zp['MARGIN-RIGHT']);
		}
		if (is_array($zp) && !empty($zp)) {
			$p = array_merge($p, $zp);
		}

		// If first page
		if (isset($this->cssManager->CSS['@PAGE>>PSEUDO>>FIRST']) && $first) {
			$zp = $this->cssManager->CSS['@PAGE>>PSEUDO>>FIRST'];
		} else {
			$zp = [];
		}
		if (isset($zp['SIZE'])) {
			unset($zp['SIZE']);
		}
		if (isset($zp['SHEET-SIZE'])) {
			unset($zp['SHEET-SIZE']);
		}
		// Disallow margin-left or -right on :FIRST	// mPDF 5.7.3
		if (isset($zp['MARGIN-LEFT'])) {
			unset($zp['MARGIN-LEFT']);
		}
		if (isset($zp['MARGIN-RIGHT'])) {
			unset($zp['MARGIN-RIGHT']);
		}
		if (is_array($zp) && !empty($zp)) {
			$p = array_merge($p, $zp);
		}

		// If named page
		if ($name) {
			if (isset($this->cssManager->CSS['@PAGE>>NAMED>>' . $name])) {
				$zp = $this->cssManager->CSS['@PAGE>>NAMED>>' . $name];
			} else {
				$zp = [];
			}
			if (is_array($zp) && !empty($zp)) {
				$p = array_merge($p, $zp);
			}

			if (isset($p['EVEN-HEADER-NAME']) && $oddEven == 'E') {
				$p['HEADER'] = $p['EVEN-HEADER-NAME'];
				unset($p['EVEN-HEADER-NAME']);
			}
			if (isset($p['ODD-HEADER-NAME']) && $oddEven != 'E') {
				$p['HEADER'] = $p['ODD-HEADER-NAME'];
				unset($p['ODD-HEADER-NAME']);
			}
			if (isset($p['EVEN-FOOTER-NAME']) && $oddEven == 'E') {
				$p['FOOTER'] = $p['EVEN-FOOTER-NAME'];
				unset($p['EVEN-FOOTER-NAME']);
			}
			if (isset($p['ODD-FOOTER-NAME']) && $oddEven != 'E') {
				$p['FOOTER'] = $p['ODD-FOOTER-NAME'];
				unset($p['ODD-FOOTER-NAME']);
			}

			// If named right/Odd page
			if (isset($this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>RIGHT']) && $side == 'R') {
				$zp = $this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>RIGHT'];
			} else {
				$zp = [];
			}
			if (isset($zp['SIZE'])) {
				unset($zp['SIZE']);
			}
			if (isset($zp['SHEET-SIZE'])) {
				unset($zp['SHEET-SIZE']);
			}
			// Disallow margin-left or -right on :LEFT or :RIGHT
			if (isset($zp['MARGIN-LEFT'])) {
				unset($zp['MARGIN-LEFT']);
			}
			if (isset($zp['MARGIN-RIGHT'])) {
				unset($zp['MARGIN-RIGHT']);
			}
			if (is_array($zp) && !empty($zp)) {
				$p = array_merge($p, $zp);
			}

			// If named left/Even page
			if (isset($this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>LEFT']) && $side == 'L') {
				$zp = $this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>LEFT'];
			} else {
				$zp = [];
			}
			if (isset($zp['SIZE'])) {
				unset($zp['SIZE']);
			}
			if (isset($zp['SHEET-SIZE'])) {
				unset($zp['SHEET-SIZE']);
			}
			// Disallow margin-left or -right on :LEFT or :RIGHT
			if (isset($zp['MARGIN-LEFT'])) {
				unset($zp['MARGIN-LEFT']);
			}
			if (isset($zp['MARGIN-RIGHT'])) {
				unset($zp['MARGIN-RIGHT']);
			}
			if (is_array($zp) && !empty($zp)) {
				$p = array_merge($p, $zp);
			}

			// If named first page
			if (isset($this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>FIRST']) && $first) {
				$zp = $this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>FIRST'];
			} else {
				$zp = [];
			}
			if (isset($zp['SIZE'])) {
				unset($zp['SIZE']);
			}
			if (isset($zp['SHEET-SIZE'])) {
				unset($zp['SHEET-SIZE']);
			}
			// Disallow margin-left or -right on :FIRST	// mPDF 5.7.3
			if (isset($zp['MARGIN-LEFT'])) {
				unset($zp['MARGIN-LEFT']);
			}
			if (isset($zp['MARGIN-RIGHT'])) {
				unset($zp['MARGIN-RIGHT']);
			}
			if (is_array($zp) && !empty($zp)) {
				$p = array_merge($p, $zp);
			}
		}

		$orientation = $mgl = $mgr = $mgt = $mgb = $mgh = $mgf = '';
		$header = $footer = '';
		$resetpagenum = $pagenumstyle = $suppress = '';
		$marks = '';
		$bg = [];

		$newformat = '';


		if (isset($p['SHEET-SIZE']) && is_array($p['SHEET-SIZE'])) {
			$newformat = $p['SHEET-SIZE'];
			if ($newformat[0] > $newformat[1]) { // landscape
				$newformat = array_reverse($newformat);
				$p['ORIENTATION'] = 'L';
			} else {
				$p['ORIENTATION'] = 'P';
			}
			$this->_setPageSize($newformat, $p['ORIENTATION']);
		}

		if (isset($p['SIZE']) && is_array($p['SIZE']) && !$newformat) {
			if ($p['SIZE']['W'] > $p['SIZE']['H']) {
				$p['ORIENTATION'] = 'L';
			} else {
				$p['ORIENTATION'] = 'P';
			}
		}
		if (is_array($p['SIZE'])) {
			if ($p['SIZE']['W'] > $this->fw) {
				$p['SIZE']['W'] = $this->fw;
			} // mPD 4.2 use fw not fPt
			if ($p['SIZE']['H'] > $this->fh) {
				$p['SIZE']['H'] = $this->fh;
			}
			if (($p['ORIENTATION'] == $this->DefOrientation && !$newformat) || ($newformat && $p['ORIENTATION'] == 'P')) {
				$outer_width_LR = ($this->fw - $p['SIZE']['W']) / 2;
				$outer_width_TB = ($this->fh - $p['SIZE']['H']) / 2;
			} else {
				$outer_width_LR = ($this->fh - $p['SIZE']['W']) / 2;
				$outer_width_TB = ($this->fw - $p['SIZE']['H']) / 2;
			}
			$pgw = $p['SIZE']['W'];
			$pgh = $p['SIZE']['H'];
		} else { // AUTO LANDSCAPE PORTRAIT
			$outer_width_LR = 0;
			$outer_width_TB = 0;
			if (!$newformat) {
				if (strtoupper($p['SIZE']) == 'AUTO') {
					$p['ORIENTATION'] = $this->DefOrientation;
				} elseif (strtoupper($p['SIZE']) == 'LANDSCAPE') {
					$p['ORIENTATION'] = 'L';
				} else {
					$p['ORIENTATION'] = 'P';
				}
			}
			if (($p['ORIENTATION'] == $this->DefOrientation && !$newformat) || ($newformat && $p['ORIENTATION'] == 'P')) {
				$pgw = $this->fw;
				$pgh = $this->fh;
			} else {
				$pgw = $this->fh;
				$pgh = $this->fw;
			}
		}

		if (isset($p['HEADER']) && $p['HEADER']) {
			$header = $p['HEADER'];
		}
		if (isset($p['FOOTER']) && $p['FOOTER']) {
			$footer = $p['FOOTER'];
		}
		if (isset($p['RESETPAGENUM']) && $p['RESETPAGENUM']) {
			$resetpagenum = $p['RESETPAGENUM'];
		}
		if (isset($p['PAGENUMSTYLE']) && $p['PAGENUMSTYLE']) {
			$pagenumstyle = $p['PAGENUMSTYLE'];
		}
		if (isset($p['SUPPRESS']) && $p['SUPPRESS']) {
			$suppress = $p['SUPPRESS'];
		}

		if (isset($p['MARKS'])) {
			if (preg_match('/cross/i', $p['MARKS']) && preg_match('/crop/i', $p['MARKS'])) {
				$marks = 'CROPCROSS';
			} elseif (strtoupper($p['MARKS']) == 'CROP') {
				$marks = 'CROP';
			} elseif (strtoupper($p['MARKS']) == 'CROSS') {
				$marks = 'CROSS';
			}
		}

		if (isset($p['BACKGROUND-COLOR']) && $p['BACKGROUND-COLOR']) {
			$bg['BACKGROUND-COLOR'] = $p['BACKGROUND-COLOR'];
		}
		/* -- BACKGROUNDS -- */
		if (isset($p['BACKGROUND-GRADIENT']) && $p['BACKGROUND-GRADIENT']) {
			$bg['BACKGROUND-GRADIENT'] = $p['BACKGROUND-GRADIENT'];
		}
		if (isset($p['BACKGROUND-IMAGE']) && $p['BACKGROUND-IMAGE']) {
			$bg['BACKGROUND-IMAGE'] = $p['BACKGROUND-IMAGE'];
		}
		if (isset($p['BACKGROUND-REPEAT']) && $p['BACKGROUND-REPEAT']) {
			$bg['BACKGROUND-REPEAT'] = $p['BACKGROUND-REPEAT'];
		}
		if (isset($p['BACKGROUND-POSITION']) && $p['BACKGROUND-POSITION']) {
			$bg['BACKGROUND-POSITION'] = $p['BACKGROUND-POSITION'];
		}
		if (isset($p['BACKGROUND-IMAGE-RESIZE']) && $p['BACKGROUND-IMAGE-RESIZE']) {
			$bg['BACKGROUND-IMAGE-RESIZE'] = $p['BACKGROUND-IMAGE-RESIZE'];
		}
		if (isset($p['BACKGROUND-IMAGE-OPACITY'])) {
			$bg['BACKGROUND-IMAGE-OPACITY'] = $p['BACKGROUND-IMAGE-OPACITY'];
		}
		/* -- END BACKGROUNDS -- */

		if (isset($p['MARGIN-LEFT'])) {
			$mgl = $this->sizeConverter->convert($p['MARGIN-LEFT'], $pgw) + $outer_width_LR;
		}
		if (isset($p['MARGIN-RIGHT'])) {
			$mgr = $this->sizeConverter->convert($p['MARGIN-RIGHT'], $pgw) + $outer_width_LR;
		}
		if (isset($p['MARGIN-BOTTOM'])) {
			$mgb = $this->sizeConverter->convert($p['MARGIN-BOTTOM'], $pgh) + $outer_width_TB;
		}
		if (isset($p['MARGIN-TOP'])) {
			$mgt = $this->sizeConverter->convert($p['MARGIN-TOP'], $pgh) + $outer_width_TB;
		}
		if (isset($p['MARGIN-HEADER'])) {
			$mgh = $this->sizeConverter->convert($p['MARGIN-HEADER'], $pgh) + $outer_width_TB;
		}
		if (isset($p['MARGIN-FOOTER'])) {
			$mgf = $this->sizeConverter->convert($p['MARGIN-FOOTER'], $pgh) + $outer_width_TB;
		}

		if (isset($p['ORIENTATION']) && $p['ORIENTATION']) {
			$orientation = $p['ORIENTATION'];
		}
		$this->page_box['outer_width_LR'] = $outer_width_LR; // Used in MARKS:crop etc.
		$this->page_box['outer_width_TB'] = $outer_width_TB;

		return [$orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $header, $footer, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat];
	}

	/* -- END CSS-PAGE -- */



	/* -- CSS-FLOAT -- */

	// Added mPDF 3.0 Float DIV - CLEAR
	function ClearFloats($clear, $blklvl = 0)
	{
		list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($blklvl, true);
		$end = $currpos = ($this->page * 1000 + $this->y);
		if ($clear == 'BOTH' && ($l_exists || $r_exists)) {
			$this->pageoutput[$this->page] = [];
			$end = max($l_max, $r_max, $currpos);
		} elseif ($clear == 'RIGHT' && $r_exists) {
			$this->pageoutput[$this->page] = [];
			$end = max($r_max, $currpos);
		} elseif ($clear == 'LEFT' && $l_exists) {
			$this->pageoutput[$this->page] = [];
			$end = max($l_max, $currpos);
		} else {
			return;
		}
		$old_page = $this->page;
		$new_page = intval($end / 1000);
		if ($old_page != $new_page) {
			$s = $this->PrintPageBackgrounds();
			// Writes after the marker so not overwritten later by page background etc.
			$this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
			$this->pageBackgrounds = [];
			$this->page = $new_page;
		}
		$this->ResetMargins();
		$this->pageoutput[$this->page] = [];

		$this->y = (round($end * 1000) % 1000000) / 1000; // mod changes operands to integers before processing
	}

	// Added mPDF 3.0 Float DIV
	function GetFloatDivInfo($blklvl = 0, $clear = false)
	{
		// If blklvl specified, only returns floats at that level - for ClearFloats
		$l_exists = false;
		$r_exists = false;
		$l_max = 0;
		$r_max = 0;
		$l_width = 0;
		$r_width = 0;
		if (count($this->floatDivs)) {
			$currpos = ($this->page * 1000 + $this->y);
			foreach ($this->floatDivs as $f) {
				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'])) {
					if ($f['side'] == 'L') {
						$l_exists = true;
						$l_max = max($l_max, $f['endpos']);
						$l_width = max($l_width, $f['w']);
					}
					if ($f['side'] == 'R') {
						$r_exists = true;
						$r_max = max($r_max, $f['endpos']);
						$r_width = max($r_width, $f['w']);
					}
				}
			}
		}
		return [$l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width];
	}

	/* -- END CSS-FLOAT -- */

	// LIST MARKERS	// mPDF 6  Lists
	function _setListMarker($listitemtype, $listitemimage, $listitemposition)
	{
		// if position:inside (and NOT table) - output now as a textbuffer; (so if next is block, will move to new line)
		// elseif position:outside (and NOT table) - output in front of first textbuffer output by setting listitem (cf. _saveTextBuffer)
		$e = '';
		$this->listitem = '';
		$spacer = ' ';
		// IMAGE
		if ($listitemimage && $listitemimage != 'none') {
			$listitemimage = trim(preg_replace('/url\(["\']*(.*?)["\']*\)/', '\\1', $listitemimage));

			// ? Restrict maximum height/width of list marker??
			$maxWidth = 100;
			$maxHeight = 100;

			$objattr = [];
			$objattr['margin_top'] = 0;
			$objattr['margin_bottom'] = 0;
			$objattr['margin_left'] = 0;
			$objattr['margin_right'] = 0;
			$objattr['padding_top'] = 0;
			$objattr['padding_bottom'] = 0;
			$objattr['padding_left'] = 0;
			$objattr['padding_right'] = 0;
			$objattr['width'] = 0;
			$objattr['height'] = 0;
			$objattr['border_top']['w'] = 0;
			$objattr['border_bottom']['w'] = 0;
			$objattr['border_left']['w'] = 0;
			$objattr['border_right']['w'] = 0;
			$objattr['visibility'] = 'visible';
			$srcpath = $listitemimage;
			$orig_srcpath = $listitemimage;

			$objattr['vertical-align'] = 'BS'; // vertical alignment of marker (baseline)
			$w = 0;
			$h = 0;

			// Image file
			$info = $this->imageProcessor->getImage($srcpath, true, true, $orig_srcpath);
			if (!$info) {
				return;
			}

			if ($info['w'] == 0 && $info['h'] == 0) {
				$info['h'] = $this->sizeConverter->convert('1em', $this->blk[$this->blklvl]['inner_width'], $this->FontSize, false);
			}

			$objattr['file'] = $srcpath;

			// Default width and height calculation if needed
			if ($w == 0 and $h == 0) {
				/* -- IMAGES-WMF -- */
				if ($info['type'] == 'wmf') {
					// WMF units are twips (1/20pt)
					// divide by 20 to get points
					// divide by k to get user units
					$w = abs($info['w']) / (20 * Mpdf::SCALE);
					$h = abs($info['h']) / (20 * Mpdf::SCALE);
				} else { 				/* -- END IMAGES-WMF -- */
					if ($info['type'] == 'svg') {
						// SVG units are pixels
						$w = abs($info['w']) / Mpdf::SCALE;
						$h = abs($info['h']) / Mpdf::SCALE;
					} else {
						// Put image at default image dpi
						$w = ($info['w'] / Mpdf::SCALE) * (72 / $this->img_dpi);
						$h = ($info['h'] / Mpdf::SCALE) * (72 / $this->img_dpi);
					}
				}
			}
			// IF WIDTH OR HEIGHT SPECIFIED
			if ($w == 0) {
				$w = abs($h * $info['w'] / $info['h']);
			}
			if ($h == 0) {
				$h = abs($w * $info['h'] / $info['w']);
			}

			if ($w > $maxWidth) {
				$w = $maxWidth;
				$h = abs($w * $info['h'] / $info['w']);
			}

			if ($h > $maxHeight) {
				$h = $maxHeight;
				$w = abs($h * $info['w'] / $info['h']);
			}

			$objattr['type'] = 'image';
			$objattr['itype'] = $info['type'];

			$objattr['orig_h'] = $info['h'];
			$objattr['orig_w'] = $info['w'];

			/* -- IMAGES-WMF -- */
			if ($info['type'] == 'wmf') {
				$objattr['wmf_x'] = $info['x'];
				$objattr['wmf_y'] = $info['y'];
			} else { 			/* -- END IMAGES-WMF -- */
				if ($info['type'] == 'svg') {
					$objattr['wmf_x'] = $info['x'];
					$objattr['wmf_y'] = $info['y'];
				}
			}

			$objattr['height'] = $h;
			$objattr['width'] = $w;
			$objattr['image_height'] = $h;
			$objattr['image_width'] = $w;

			$objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
			$objattr['listmarker'] = true;

			$objattr['listmarkerposition'] = $listitemposition;

			$e = "\xbb\xa4\xactype=image,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
			$this->_saveTextBuffer($e);

			if ($listitemposition == 'inside') {
				$e = $spacer;
				$this->_saveTextBuffer($e);
			}
		} elseif ($listitemtype == 'disc' || $listitemtype == 'circle' || $listitemtype == 'square') { // SYMBOL (needs new font)
			$objattr = [];
			$objattr['type'] = 'listmarker';
			$objattr['listmarkerposition'] = $listitemposition;
			$objattr['width'] = 0;
			$size = $this->sizeConverter->convert($this->list_symbol_size, $this->FontSize);
			$objattr['size'] = $size;
			$objattr['offset'] = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);

			if ($listitemposition == 'inside') {
				$objattr['width'] = $size + $objattr['offset'];
			}

			$objattr['height'] = $this->FontSize;
			$objattr['vertical-align'] = 'T';
			$objattr['text'] = '';
			$objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
			$objattr['bullet'] = $listitemtype;
			$objattr['colorarray'] = $this->colorarray;
			$objattr['fontfamily'] = $this->FontFamily;
			$objattr['fontsize'] = $this->FontSize;
			$objattr['fontsizept'] = $this->FontSizePt;
			$objattr['fontstyle'] = $this->FontStyle;

			$e = "\xbb\xa4\xactype=listmarker,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
			$this->listitem = $this->_saveTextBuffer($e, '', '', true); // true returns array

		} elseif (preg_match('/U\+([a-fA-F0-9]+)/i', $listitemtype, $m)) { // SYMBOL 2 (needs new font)

			if ($this->_charDefined($this->CurrentFont['cw'], hexdec($m[1]))) {
				$list_item_marker = UtfString::codeHex2utf($m[1]);
			} else {
				$list_item_marker = '-';
			}
			if (preg_match('/rgb\(.*?\)/', $listitemtype, $m)) {
				$list_item_color = $this->colorConverter->convert($m[0], $this->PDFAXwarnings);
			} else {
				$list_item_color = '';
			}

			// SAVE then SET COLR
			$save_colorarray = $this->colorarray;
			if ($list_item_color) {
				$this->colorarray = $list_item_color;
			}

			if ($listitemposition == 'inside') {
				$e = $list_item_marker . $spacer;
				$this->_saveTextBuffer($e);
			} else {
				$objattr = [];
				$objattr['type'] = 'listmarker';
				$objattr['width'] = 0;
				$objattr['height'] = $this->FontSize;
				$objattr['vertical-align'] = 'T';
				$objattr['text'] = $list_item_marker;
				$objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
				$objattr['colorarray'] = $this->colorarray;
				$objattr['fontfamily'] = $this->FontFamily;
				$objattr['fontsize'] = $this->FontSize;
				$objattr['fontsizept'] = $this->FontSizePt;
				$objattr['fontstyle'] = $this->FontStyle;
				$e = "\xbb\xa4\xactype=listmarker,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
				$this->listitem = $this->_saveTextBuffer($e, '', '', true); // true returns array
			}

			// RESET COLOR
			$this->colorarray = $save_colorarray;

		} else { // TEXT
			$counter = $this->listcounter[$this->listlvl];

			if ($listitemtype == 'none') {
				return;
			}

			$num = $this->_getStyledNumber($counter, $listitemtype, true);

			if ($listitemposition == 'inside') {
				$e = $num . $this->list_number_suffix . $spacer;
				$this->_saveTextBuffer($e);
			} else {
				if (isset($this->blk[$this->blklvl]['direction']) && $this->blk[$this->blklvl]['direction'] == 'rtl') {
					// REPLACE MIRRORED RTL $this->list_number_suffix  e.g. ) -> (  (NB could use Ucdn::$mirror_pairs)
					$m = strtr($this->list_number_suffix, ")]}", "([{") . $num;
				} else {
					$m = $num . $this->list_number_suffix;
				}

				$objattr = [];
				$objattr['type'] = 'listmarker';
				$objattr['width'] = 0;
				$objattr['height'] = $this->FontSize;
				$objattr['vertical-align'] = 'T';
				$objattr['text'] = $m;
				$objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
				$objattr['colorarray'] = $this->colorarray;
				$objattr['fontfamily'] = $this->FontFamily;
				$objattr['fontsize'] = $this->FontSize;
				$objattr['fontsizept'] = $this->FontSizePt;
				$objattr['fontstyle'] = $this->FontStyle;
				$e = "\xbb\xa4\xactype=listmarker,objattr=" . serialize($objattr) . "\xbb\xa4\xac";

				$this->listitem = $this->_saveTextBuffer($e, '', '', true); // true returns array
			}
		}
	}

	// mPDF Lists
	function _getListMarkerWidth(&$currblk, &$a, &$i)
	{
		$blt_width = 0;

		$markeroffset = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);

		// Get Maximum number in the list
		$maxnum = $this->listcounter[$this->listlvl];
		if ($currblk['list_style_type'] != 'disc' && $currblk['list_style_type'] != 'circle' && $currblk['list_style_type'] != 'square') {
			$lvl = 1;
			for ($j = $i + 2; $j < count($a); $j+=2) {
				$e = $a[$j];
				if (!$e) {
					continue;
				}
				if ($e[0] == '/') { // end tag
					$e = strtoupper(substr($e, 1));
					if ($e == 'OL' || $e == 'UL') {
						if ($lvl == 1) {
							break;
						}
						$lvl--;
					}
				} else { // opening tag
					if (strpos($e, ' ')) {
						$e = substr($e, 0, strpos($e, ' '));
					}
					$e = strtoupper($e);
					if ($e == 'LI') {
						if ($lvl == 1) {
							$maxnum++;
						}
					} elseif ($e == 'OL' || $e == 'UL') {
						$lvl++;
					}
				}
			}
		}

		$decToAlpha = new Conversion\DecToAlpha();
		$decToRoman = new Conversion\DecToRoman();
		$decToOther = new Conversion\DecToOther($this);

		switch ($currblk['list_style_type']) {
			case 'decimal':
			case '1':
				$blt_width = $this->GetStringWidth(str_repeat('5', strlen($maxnum)) . $this->list_number_suffix);
				break;
			case 'none':
				$blt_width = 0;
				break;
			case 'upper-alpha':
			case 'upper-latin':
			case 'A':
				$maxnumA = $decToAlpha->convert($maxnum, true);
				if ($maxnum < 13) {
					$blt_width = $this->GetStringWidth('D' . $this->list_number_suffix);
				} else {
					$blt_width = $this->GetStringWidth(str_repeat('W', strlen($maxnumA)) . $this->list_number_suffix);
				}
				break;
			case 'lower-alpha':
			case 'lower-latin':
			case 'a':
				$maxnuma = $decToAlpha->convert($maxnum, false);
				if ($maxnum < 13) {
					$blt_width = $this->GetStringWidth('b' . $this->list_number_suffix);
				} else {
					$blt_width = $this->GetStringWidth(str_repeat('m', strlen($maxnuma)) . $this->list_number_suffix);
				}
				break;
			case 'upper-roman':
			case 'I':
				if ($maxnum > 87) {
					$bbit = 87;
				} elseif ($maxnum > 86) {
					$bbit = 86;
				} elseif ($maxnum > 37) {
					$bbit = 38;
				} elseif ($maxnum > 36) {
					$bbit = 37;
				} elseif ($maxnum > 27) {
					$bbit = 28;
				} elseif ($maxnum > 26) {
					$bbit = 27;
				} elseif ($maxnum > 17) {
					$bbit = 18;
				} elseif ($maxnum > 16) {
					$bbit = 17;
				} elseif ($maxnum > 7) {
					$bbit = 8;
				} elseif ($maxnum > 6) {
					$bbit = 7;
				} elseif ($maxnum > 3) {
					$bbit = 4;
				} else {
					$bbit = $maxnum;
				}

				$maxlnum = $decToRoman->convert($bbit, true);
				$blt_width = $this->GetStringWidth($maxlnum . $this->list_number_suffix);

				break;
			case 'lower-roman':
			case 'i':
				if ($maxnum > 87) {
					$bbit = 87;
				} elseif ($maxnum > 86) {
					$bbit = 86;
				} elseif ($maxnum > 37) {
					$bbit = 38;
				} elseif ($maxnum > 36) {
					$bbit = 37;
				} elseif ($maxnum > 27) {
					$bbit = 28;
				} elseif ($maxnum > 26) {
					$bbit = 27;
				} elseif ($maxnum > 17) {
					$bbit = 18;
				} elseif ($maxnum > 16) {
					$bbit = 17;
				} elseif ($maxnum > 7) {
					$bbit = 8;
				} elseif ($maxnum > 6) {
					$bbit = 7;
				} elseif ($maxnum > 3) {
					$bbit = 4;
				} else {
					$bbit = $maxnum;
				}
				$maxlnum = $decToRoman->convert($bbit, false);
				$blt_width = $this->GetStringWidth($maxlnum . $this->list_number_suffix);
				break;

			case 'disc':
			case 'circle':
			case 'square':
				$size = $this->sizeConverter->convert($this->list_symbol_size, $this->FontSize);
				$offset = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);
				$blt_width = $size + $offset;
				break;

			case 'arabic-indic':
				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0660), strlen($maxnum)) . $this->list_number_suffix);
				break;
			case 'persian':
			case 'urdu':
				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x06F0), strlen($maxnum)) . $this->list_number_suffix);
				break;
			case 'bengali':
				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x09E6), strlen($maxnum)) . $this->list_number_suffix);
				break;
			case 'devanagari':
				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0966), strlen($maxnum)) . $this->list_number_suffix);
				break;
			case 'gujarati':
				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0AE6), strlen($maxnum)) . $this->list_number_suffix);
				break;
			case 'gurmukhi':
				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0A66), strlen($maxnum)) . $this->list_number_suffix);
				break;
			case 'kannada':
				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0CE6), strlen($maxnum)) . $this->list_number_suffix);
				break;
			case 'malayalam':
				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(6, 0x0D66), strlen($maxnum)) . $this->list_number_suffix);
				break;
			case 'oriya':
				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0B66), strlen($maxnum)) . $this->list_number_suffix);
				break;
			case 'telugu':
				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0C66), strlen($maxnum)) . $this->list_number_suffix);
				break;
			case 'tamil':
				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(9, 0x0BE6), strlen($maxnum)) . $this->list_number_suffix);
				break;
			case 'thai':
				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(5, 0x0E50), strlen($maxnum)) . $this->list_number_suffix);
				break;
			default:
				$blt_width = $this->GetStringWidth(str_repeat('5', strlen($maxnum)) . $this->list_number_suffix);
				break;
		}

		return ($blt_width + $markeroffset);
	}

	function _saveTextBuffer($t, $link = '', $intlink = '', $return = false)
	{
	// mPDF 6  Lists
		$arr = [];
		$arr[0] = $t;
		if (isset($link) && $link) {
			$arr[1] = $link;
		}
		$arr[2] = $this->currentfontstyle;
		if (isset($this->colorarray) && $this->colorarray) {
			$arr[3] = $this->colorarray;
		}
		$arr[4] = $this->currentfontfamily;
		$arr[5] = $this->currentLang; // mPDF 6
		if (isset($intlink) && $intlink) {
			$arr[7] = $intlink;
		}
		// mPDF 6
		// If Kerning set for OTL, and useOTL has positive value, but has not set for this particular script,
		// set for kerning via kern table
		// e.g. Latin script when useOTL set as 0x80
		if (isset($this->OTLtags['Plus']) && strpos($this->OTLtags['Plus'], 'kern') !== false && empty($this->OTLdata['GPOSinfo'])) {
			$this->textvar = ($this->textvar | TextVars::FC_KERNING);
		}
		$arr[8] = $this->textvar; // mPDF 5.7.1
		if (isset($this->textparam) && $this->textparam) {
			$arr[9] = $this->textparam;
		}
		if (isset($this->spanbgcolorarray) && $this->spanbgcolorarray) {
			$arr[10] = $this->spanbgcolorarray;
		}
		$arr[11] = $this->currentfontsize;
		if (isset($this->ReqFontStyle) && $this->ReqFontStyle) {
			$arr[12] = $this->ReqFontStyle;
		}
		if (isset($this->lSpacingCSS) && $this->lSpacingCSS) {
			$arr[14] = $this->lSpacingCSS;
		}
		if (isset($this->wSpacingCSS) && $this->wSpacingCSS) {
			$arr[15] = $this->wSpacingCSS;
		}
		if (isset($this->spanborddet) && $this->spanborddet) {
			$arr[16] = $this->spanborddet;
		}
		if (isset($this->textshadow) && $this->textshadow) {
			$arr[17] = $this->textshadow;
		}
		if (isset($this->OTLdata) && $this->OTLdata) {
			$arr[18] = $this->OTLdata;
			$this->OTLdata = [];
		} // mPDF 5.7.1
		else {
			$arr[18] = null;
		}
		// mPDF 6  Lists
		if ($return) {
			return ($arr);
		}
		if ($this->listitem) {
			$this->textbuffer[] = $this->listitem;
			$this->listitem = [];
		}
		$this->textbuffer[] = $arr;
	}

	function _saveCellTextBuffer($t, $link = '', $intlink = '')
	{
		$arr = [];
		$arr[0] = $t;
		if (isset($link) && $link) {
			$arr[1] = $link;
		}
		$arr[2] = $this->currentfontstyle;
		if (isset($this->colorarray) && $this->colorarray) {
			$arr[3] = $this->colorarray;
		}
		$arr[4] = $this->currentfontfamily;
		if (isset($intlink) && $intlink) {
			$arr[7] = $intlink;
		}
		// mPDF 6
		// If Kerning set for OTL, and useOTL has positive value, but has not set for this particular script,
		// set for kerning via kern table
		// e.g. Latin script when useOTL set as 0x80
		if (isset($this->OTLtags['Plus']) && strpos($this->OTLtags['Plus'], 'kern') !== false && empty($this->OTLdata['GPOSinfo'])) {
			$this->textvar = ($this->textvar | TextVars::FC_KERNING);
		}
		$arr[8] = $this->textvar; // mPDF 5.7.1
		if (isset($this->textparam) && $this->textparam) {
			$arr[9] = $this->textparam;
		}
		if (isset($this->spanbgcolorarray) && $this->spanbgcolorarray) {
			$arr[10] = $this->spanbgcolorarray;
		}
		$arr[11] = $this->currentfontsize;
		if (isset($this->ReqFontStyle) && $this->ReqFontStyle) {
			$arr[12] = $this->ReqFontStyle;
		}
		if (isset($this->lSpacingCSS) && $this->lSpacingCSS) {
			$arr[14] = $this->lSpacingCSS;
		}
		if (isset($this->wSpacingCSS) && $this->wSpacingCSS) {
			$arr[15] = $this->wSpacingCSS;
		}
		if (isset($this->spanborddet) && $this->spanborddet) {
			$arr[16] = $this->spanborddet;
		}
		if (isset($this->textshadow) && $this->textshadow) {
			$arr[17] = $this->textshadow;
		}
		if (isset($this->OTLdata) && $this->OTLdata) {
			$arr[18] = $this->OTLdata;
			$this->OTLdata = [];
		} // mPDF 5.7.1
		else {
			$arr[18] = null;
		}
		$this->cell[$this->row][$this->col]['textbuffer'][] = $arr;
	}

	function printbuffer($arrayaux, $blockstate = 0, $is_table = false, $table_draft = false, $cell_dir = '')
	{
		// $blockstate = 0;	// NO margins/padding
		// $blockstate = 1;	// Top margins/padding only
		// $blockstate = 2;	// Bottom margins/padding only
		// $blockstate = 3;	// Top & bottom margins/padding
		$this->spanbgcolorarray = '';
		$this->spanbgcolor = false;
		$this->spanborder = false;
		$this->spanborddet = [];
		$paint_ht_corr = 0;
		/* -- CSS-FLOAT -- */
		if (count($this->floatDivs)) {
			list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
			if (($this->blk[$this->blklvl]['inner_width'] - $l_width - $r_width) < (2 * $this->GetCharWidth('W', false))) {
				// Too narrow to fit - try to move down past L or R float
				if ($l_max < $r_max && ($this->blk[$this->blklvl]['inner_width'] - $r_width) > (2 * $this->GetCharWidth('W', false))) {
					$this->ClearFloats('LEFT', $this->blklvl);
				} elseif ($r_max < $l_max && ($this->blk[$this->blklvl]['inner_width'] - $l_width) > (2 * $this->GetCharWidth('W', false))) {
					$this->ClearFloats('RIGHT', $this->blklvl);
				} else {
					$this->ClearFloats('BOTH', $this->blklvl);
				}
			}
		}
		/* -- END CSS-FLOAT -- */
		$bak_y = $this->y;
		$bak_x = $this->x;
		$align = '';
		if (!$is_table) {
			if (isset($this->blk[$this->blklvl]['align']) && $this->blk[$this->blklvl]['align']) {
				$align = $this->blk[$this->blklvl]['align'];
			}
			// Block-align is set by e.g. <.. align="center"> Takes priority for this block but not inherited
			if (isset($this->blk[$this->blklvl]['block-align']) && $this->blk[$this->blklvl]['block-align']) {
				$align = $this->blk[$this->blklvl]['block-align'];
			}
			if (isset($this->blk[$this->blklvl]['direction'])) {
				$blockdir = $this->blk[$this->blklvl]['direction'];
			} else {
				$blockdir = "";
			}
			$this->divwidth = $this->blk[$this->blklvl]['width'];
		} else {
			$align = $this->cellTextAlign;
			$blockdir = $cell_dir;
		}
		$oldpage = $this->page;

		// ADDED for Out of Block now done as Flowing Block
		if ($this->divwidth == 0) {
			$this->divwidth = $this->pgwidth;
		}

		if (!$is_table) {
			$this->SetLineHeight($this->FontSizePt, $this->blk[$this->blklvl]['line_height']);
		}
		$this->divheight = $this->lineheight;
		$old_height = $this->divheight;

		// As a failsafe - if font has been set but not output to page
		if (!$table_draft) {
			$this->SetFont($this->default_font, '', $this->default_font_size, true, true); // force output to page
		}

		$this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, true, $blockdir, $table_draft);

		$array_size = count($arrayaux);

		// Added - Otherwise <div><div><p> did not output top margins/padding for 1st/2nd div
		if ($array_size == 0) {
			$this->finishFlowingBlock(true);
		} // true = END of flowing block
		// mPDF 6
		// ALL the chunks of textbuffer need to have at least basic OTLdata set
		// First make sure each element/chunk has the OTLdata for Bidi set.
		for ($i = 0; $i < $array_size; $i++) {
			if (empty($arrayaux[$i][18])) {
				if (substr($arrayaux[$i][0], 0, 3) == "\xbb\xa4\xac") { // object identifier has been identified!
					$unicode = [0xFFFC]; // Object replacement character
				} else {
					$unicode = $this->UTF8StringToArray($arrayaux[$i][0], false);
				}
				$is_strong = false;
				$this->getBasicOTLdata($arrayaux[$i][18], $unicode, $is_strong);
			}
			// Gets messed up if try and use core fonts inside a paragraph of text which needs to be BiDi re-ordered or OTLdata set
			if (($blockdir == 'rtl' || $this->biDirectional) && isset($arrayaux[$i][4]) && in_array($arrayaux[$i][4], ['ccourier', 'ctimes', 'chelvetica', 'csymbol', 'czapfdingbats'])) {
				throw new \Mpdf\MpdfException("You cannot use core fonts in a document which contains RTL text.");
			}
		}
		// mPDF 6
		// Process bidirectional text ready for bidi-re-ordering (which is done after line-breaks are established in WriteFlowingBlock etc.)
		if (($blockdir == 'rtl' || $this->biDirectional) && !$table_draft) {
			if (empty($this->otl)) {
				$this->otl = new Otl($this, $this->fontCache);
			}
			$this->otl->bidiPrepare($arrayaux, $blockdir);
			$array_size = count($arrayaux);
		}


		// Remove empty items // mPDF 6
		for ($i = $array_size - 1; $i > 0; $i--) {
			if (empty($arrayaux[$i][0]) && (isset($arrayaux[$i][16]) && $arrayaux[$i][16] !== '0') && empty($arrayaux[$i][7])) {
				unset($arrayaux[$i]);
			}
		}

		// Correct adjoining borders for inline elements
		if (isset($arrayaux[0][16])) {
			$lastspanborder = $arrayaux[0][16];
		} else {
			$lastspanborder = false;
		}
		for ($i = 1; $i < $array_size; $i++) {
			if (isset($arrayaux[$i][16]) && $arrayaux[$i][16] == $lastspanborder &&
				((!isset($arrayaux[$i][9]['bord-decoration']) && !isset($arrayaux[$i - 1][9]['bord-decoration'])) ||
				(isset($arrayaux[$i][9]['bord-decoration']) && isset($arrayaux[$i - 1][9]['bord-decoration']) && $arrayaux[$i][9]['bord-decoration'] == $arrayaux[$i - 1][9]['bord-decoration'])
				)
			) {
				if (isset($arrayaux[$i][16]['R'])) {
					$lastspanborder = $arrayaux[$i][16];
				} else {
					$lastspanborder = false;
				}
				$arrayaux[$i][16]['L']['s'] = 0;
				$arrayaux[$i][16]['L']['w'] = 0;
				$arrayaux[$i - 1][16]['R']['s'] = 0;
				$arrayaux[$i - 1][16]['R']['w'] = 0;
			} else {
				if (isset($arrayaux[$i][16]['R'])) {
					$lastspanborder = $arrayaux[$i][16];
				} else {
					$lastspanborder = false;
				}
			}
		}

		for ($i = 0; $i < $array_size; $i++) {
			// COLS
			$oldcolumn = $this->CurrCol;
			$vetor = isset($arrayaux[$i]) ? $arrayaux[$i] : null;
			if ($i == 0 && $vetor[0] != "\n" && ! $this->ispre) {
				$vetor[0] = ltrim($vetor[0]);
				if (!empty($vetor[18])) {
					$this->otl->trimOTLdata($vetor[18], true, false);
				} // *OTL*
			}

			// FIXED TO ALLOW IT TO SHOW '0'
			if (empty($vetor[0]) && !($vetor[0] === '0') && empty($vetor[7])) { // Ignore empty text and not carrying an internal link
				// Check if it is the last element. If so then finish printing the block
				if ($i == ($array_size - 1)) {
					$this->finishFlowingBlock(true);
				} // true = END of flowing block
				continue;
			}


			// Activating buffer properties
			if (isset($vetor[11]) && $vetor[11] != '') {   // Font Size
				if ($is_table && $this->shrin_k) {
					$this->SetFontSize($vetor[11] / $this->shrin_k, false);
				} else {
					$this->SetFontSize($vetor[11], false);
				}
			}

			if (isset($vetor[17]) && !empty($vetor[17])) { // TextShadow
				$this->textshadow = $vetor[17];
			}
			if (isset($vetor[16]) && !empty($vetor[16])) { // Border
				$this->spanborddet = $vetor[16];
				$this->spanborder = true;
			}

			if (isset($vetor[15])) {   // Word spacing
				$this->wSpacingCSS = $vetor[15];
				if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
					$this->minwSpacing = $this->sizeConverter->convert($this->wSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
				}
			}
			if (isset($vetor[14])) {   // Letter spacing
				$this->lSpacingCSS = $vetor[14];
				if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
					$this->fixedlSpacing = $this->sizeConverter->convert($this->lSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
				}
			}


			if (isset($vetor[10]) and ! empty($vetor[10])) { // Background color
				$this->spanbgcolorarray = $vetor[10];
				$this->spanbgcolor = true;
			}
			if (isset($vetor[9]) and ! empty($vetor[9])) { // Text parameters - Outline + hyphens
				$this->textparam = $vetor[9];
				$this->SetTextOutline($this->textparam);
				// mPDF 5.7.3  inline text-decoration parameters
				if ($is_table && $this->shrin_k) {
					if (isset($this->textparam['text-baseline'])) {
						$this->textparam['text-baseline'] /= $this->shrin_k;
					}
					if (isset($this->textparam['decoration-baseline'])) {
						$this->textparam['decoration-baseline'] /= $this->shrin_k;
					}
					if (isset($this->textparam['decoration-fontsize'])) {
						$this->textparam['decoration-fontsize'] /= $this->shrin_k;
					}
				}
			}
			if (isset($vetor[8])) {  // mPDF 5.7.1
				$this->textvar = $vetor[8];
			}
			if (isset($vetor[7]) and $vetor[7] != '') { // internal target: <a name="anyvalue">
				$ily = $this->y;
				if ($this->table_rotate) {
					$this->internallink[$vetor[7]] = ["Y" => $ily, "PAGE" => $this->page, "tbrot" => true];
				} elseif ($this->kwt) {
					$this->internallink[$vetor[7]] = ["Y" => $ily, "PAGE" => $this->page, "kwt" => true];
				} elseif ($this->ColActive) {
					$this->internallink[$vetor[7]] = ["Y" => $ily, "PAGE" => $this->page, "col" => $this->CurrCol];
				} elseif (!$this->keep_block_together) {
					$this->internallink[$vetor[7]] = ["Y" => $ily, "PAGE" => $this->page];
				}
				if (empty($vetor[0])) { // Ignore empty text
					// Check if it is the last element. If so then finish printing the block
					if ($i == ($array_size - 1)) {
						$this->finishFlowingBlock(true);
					} // true = END of flowing block
					continue;
				}
			}
			if (isset($vetor[5]) and $vetor[5] != '') {  // Language	// mPDF 6
				$this->currentLang = $vetor[5];
			}
			if (isset($vetor[4]) and $vetor[4] != '') {  // Font Family
				$font = $this->SetFont($vetor[4], $this->FontStyle, 0, false);
			}
			if (!empty($vetor[3])) { // Font Color
				$cor = $vetor[3];
				$this->SetTColor($cor);
			}
			if (isset($vetor[2]) and $vetor[2] != '') { // Bold,Italic styles
				$this->SetStyles($vetor[2]);
			}

			if (isset($vetor[12]) and $vetor[12] != '') { // Requested Bold,Italic
				$this->ReqFontStyle = $vetor[12];
			}
			if (isset($vetor[1]) and $vetor[1] != '') { // LINK
				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.)
					// Repeated reference to same anchor?
					while (array_key_exists($vetor[1], $this->internallink)) {
						$vetor[1] = "#" . $vetor[1];
					}
					$this->internallink[$vetor[1]] = $this->AddLink();
					$vetor[1] = $this->internallink[$vetor[1]];
				}
				$this->HREF = $vetor[1];     // HREF link style set here ******
			}

			// SPECIAL CONTENT - IMAGES & FORM OBJECTS
			// Print-out special content

			if (substr($vetor[0], 0, 3) == "\xbb\xa4\xac") { // identifier has been identified!
				$objattr = $this->_getObjAttr($vetor[0]);

				/* -- TABLES -- */
				if ($objattr['type'] == 'nestedtable') {
					if ($objattr['nestedcontent']) {
						$level = $objattr['level'];
						$table = &$this->table[$level][$objattr['table']];

						if ($table_draft) {
							$this->y += $this->table[($level + 1)][$objattr['nestedcontent']]['h']; // nested table height
							$this->finishFlowingBlock(false, 'nestedtable');
						} else {
							$cell = &$table['cells'][$objattr['row']][$objattr['col']];
							$this->finishFlowingBlock(false, 'nestedtable');
							$save_dw = $this->divwidth;
							$save_buffer = $this->cellBorderBuffer;
							$this->cellBorderBuffer = [];
							$ncx = $this->x;
							list($dummyx, $w) = $this->_tableGetWidth($table, $objattr['row'], $objattr['col']);
							$ntw = $this->table[($level + 1)][$objattr['nestedcontent']]['w']; // nested table width
							if (!$this->simpleTables) {
								if ($this->packTableData) {
									list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cell['borderbin']);
								} else {
									$br = $cell['border_details']['R']['w'];
									$bl = $cell['border_details']['L']['w'];
								}
								if ($table['borders_separate']) {
									$innerw = $w - $bl - $br - $cell['padding']['L'] - $cell['padding']['R'] - $table['border_spacing_H'];
								} else {
									$innerw = $w - $bl / 2 - $br / 2 - $cell['padding']['L'] - $cell['padding']['R'];
								}
							} elseif ($this->simpleTables) {
								if ($table['borders_separate']) {
									$innerw = $w - $table['simple']['border_details']['L']['w'] - $table['simple']['border_details']['R']['w'] - $cell['padding']['L'] - $cell['padding']['R'] - $table['border_spacing_H'];
								} else {
									$innerw = $w - $table['simple']['border_details']['L']['w'] / 2 - $table['simple']['border_details']['R']['w'] / 2 - $cell['padding']['L'] - $cell['padding']['R'];
								}
							}
							if ($cell['a'] == 'C' || $this->table[($level + 1)][$objattr['nestedcontent']]['a'] == 'C') {
								$ncx += ($innerw - $ntw) / 2;
							} elseif ($cell['a'] == 'R' || $this->table[($level + 1)][$objattr['nestedcontent']]['a'] == 'R') {
								$ncx += $innerw - $ntw;
							}
							$this->x = $ncx;

							$this->_tableWrite($this->table[($level + 1)][$objattr['nestedcontent']]);
							$this->cellBorderBuffer = $save_buffer;
							$this->x = $bak_x;
							$this->divwidth = $save_dw;
						}

						$this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, false, $blockdir, $table_draft);
					}
				} else {
					/* -- END TABLES -- */
					if ($is_table) { // *TABLES*
						$maxWidth = $this->divwidth;  // *TABLES*
					} // *TABLES*
					else { // *TABLES*
						$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']);
					} // *TABLES*

					/* -- CSS-IMAGE-FLOAT -- */
					// If float (already) exists at this level
					if (isset($this->floatmargins['R']) && $this->y <= $this->floatmargins['R']['y1'] && $this->y >= $this->floatmargins['R']['y0']) {
						$maxWidth -= $this->floatmargins['R']['w'];
					}
					if (isset($this->floatmargins['L']) && $this->y <= $this->floatmargins['L']['y1'] && $this->y >= $this->floatmargins['L']['y0']) {
						$maxWidth -= $this->floatmargins['L']['w'];
					}
					/* -- END CSS-IMAGE-FLOAT -- */

					list($skipln) = $this->inlineObject($objattr['type'], '', $this->y, $objattr, $this->lMargin, ($this->flowingBlockAttr['contentWidth'] / Mpdf::SCALE), $maxWidth, $this->flowingBlockAttr['height'], false, $is_table);
					//  1 -> New line needed because of width
					// -1 -> Will fit width on line but NEW PAGE REQUIRED because of height
					// -2 -> Will not fit on line therefore needs new line but thus NEW PAGE REQUIRED
					$iby = $this->y;
					$oldpage = $this->page;
					$oldcol = $this->CurrCol;
					if (($skipln == 1 || $skipln == -2) && !isset($objattr['float'])) {
						$this->finishFlowingBlock(false, $objattr['type']);
						$this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, false, $blockdir, $table_draft);
					}

					if (!$table_draft) {
						$thispage = $this->page;
						if ($this->CurrCol != $oldcol) {
							$changedcol = true;
						} else {
							$changedcol = false;
						}

						// the previous lines can already have triggered page break or column change
						if (!$changedcol && $skipln < 0 && $this->AcceptPageBreak() && $thispage == $oldpage) {
							$this->AddPage($this->CurOrientation);

							// Added to correct Images already set on line before page advanced
							// i.e. if second inline image on line is higher than first and forces new page
							if (count($this->objectbuffer)) {
								$yadj = $iby - $this->y;
								foreach ($this->objectbuffer as $ib => $val) {
									if ($this->objectbuffer[$ib]['OUTER-Y']) {
										$this->objectbuffer[$ib]['OUTER-Y'] -= $yadj;
									}
									if ($this->objectbuffer[$ib]['BORDER-Y']) {
										$this->objectbuffer[$ib]['BORDER-Y'] -= $yadj;
									}
									if ($this->objectbuffer[$ib]['INNER-Y']) {
										$this->objectbuffer[$ib]['INNER-Y'] -= $yadj;
									}
								}
							}
						}

						// Added to correct for OddEven Margins
						if ($this->page != $oldpage) {
							if (($this->page - $oldpage) % 2 == 1) {
								$bak_x += $this->MarginCorrection;
							}
							$oldpage = $this->page;
							$y = $this->tMargin - $paint_ht_corr;
							$this->oldy = $this->tMargin - $paint_ht_corr;
							$old_height = 0;
						}
						$this->x = $bak_x;
						/* -- COLUMNS -- */
						// COLS
						// OR COLUMN CHANGE
						if ($this->CurrCol != $oldcolumn) {
							if ($this->directionality == 'rtl') { // *OTL*
								$bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
							} // *OTL*
							else { // *OTL*
								$bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
							} // *OTL*
							$this->x = $bak_x;
							$oldcolumn = $this->CurrCol;
							$y = $this->y0 - $paint_ht_corr;
							$this->oldy = $this->y0 - $paint_ht_corr;
							$old_height = 0;
						}
						/* -- END COLUMNS -- */
					}

					/* -- CSS-IMAGE-FLOAT -- */
					if ($objattr['type'] == 'image' && isset($objattr['float'])) {
						$fy = $this->y;

						// DIV TOP MARGIN/BORDER/PADDING
						if ($this->flowingBlockAttr['newblock'] && ($this->flowingBlockAttr['blockstate'] == 1 || $this->flowingBlockAttr['blockstate'] == 3) && $this->flowingBlockAttr['lineCount'] == 0) {
							$fy += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
						}

						if ($objattr['float'] == 'R') {
							$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']);
						} elseif ($objattr['float'] == 'L') {
							$fx = $this->lMargin + ($this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_left']);
						}
						$w = $objattr['width'];
						$h = abs($objattr['height']);

						$widthLeft = $maxWidth - ($this->flowingBlockAttr['contentWidth'] / Mpdf::SCALE);
						$maxHeight = $this->h - ($this->tMargin + $this->margin_header + $this->bMargin + 10);
						// For Images
						$extraWidth = ($objattr['border_left']['w'] + $objattr['border_right']['w'] + $objattr['margin_left'] + $objattr['margin_right']);
						$extraHeight = ($objattr['border_top']['w'] + $objattr['border_bottom']['w'] + $objattr['margin_top'] + $objattr['margin_bottom']);

						if ($objattr['itype'] == 'wmf' || $objattr['itype'] == 'svg') {
							$file = $objattr['file'];
							$info = $this->formobjects[$file];
						} else {
							$file = $objattr['file'];
							$info = $this->images[$file];
						}
						$img_w = $w - $extraWidth;
						$img_h = $h - $extraHeight;
						if ($objattr['border_left']['w']) {
							$objattr['BORDER-WIDTH'] = $img_w + (($objattr['border_left']['w'] + $objattr['border_right']['w']) / 2);
							$objattr['BORDER-HEIGHT'] = $img_h + (($objattr['border_top']['w'] + $objattr['border_bottom']['w']) / 2);
							$objattr['BORDER-X'] = $fx + $objattr['margin_left'] + (($objattr['border_left']['w']) / 2);
							$objattr['BORDER-Y'] = $fy + $objattr['margin_top'] + (($objattr['border_top']['w']) / 2);
						}
						$objattr['INNER-WIDTH'] = $img_w;
						$objattr['INNER-HEIGHT'] = $img_h;
						$objattr['INNER-X'] = $fx + $objattr['margin_left'] + ($objattr['border_left']['w']);
						$objattr['INNER-Y'] = $fy + $objattr['margin_top'] + ($objattr['border_top']['w']);
						$objattr['ID'] = $info['i'];
						$objattr['OUTER-WIDTH'] = $w;
						$objattr['OUTER-HEIGHT'] = $h;
						$objattr['OUTER-X'] = $fx;
						$objattr['OUTER-Y'] = $fy;
						if ($objattr['float'] == 'R') {
							// If R float already exists at this level
							$this->floatmargins['R']['skipline'] = false;
							if (isset($this->floatmargins['R']['y1']) && $this->floatmargins['R']['y1'] > 0 && $fy < $this->floatmargins['R']['y1']) {
								$this->WriteFlowingBlock($vetor[0], $vetor[18]);  // mPDF 5.7.1
							} // If L float already exists at this level
							elseif (isset($this->floatmargins['L']['y1']) && $this->floatmargins['L']['y1'] > 0 && $fy < $this->floatmargins['L']['y1']) {
								// Final check distance between floats is not now too narrow to fit text
								$mw = 2 * $this->GetCharWidth('W', false);
								if (($this->blk[$this->blklvl]['inner_width'] - $w - $this->floatmargins['L']['w']) < $mw) {
									$this->WriteFlowingBlock($vetor[0], $vetor[18]);  // mPDF 5.7.1
								} else {
									$this->floatmargins['R']['x'] = $fx;
									$this->floatmargins['R']['w'] = $w;
									$this->floatmargins['R']['y0'] = $fy;
									$this->floatmargins['R']['y1'] = $fy + $h;
									if ($skipln == 1) {
										$this->floatmargins['R']['skipline'] = true;
										$this->floatmargins['R']['id'] = count($this->floatbuffer) + 0;
										$objattr['skipline'] = true;
									}
									$this->floatbuffer[] = $objattr;
								}
							} else {
								$this->floatmargins['R']['x'] = $fx;
								$this->floatmargins['R']['w'] = $w;
								$this->floatmargins['R']['y0'] = $fy;
								$this->floatmargins['R']['y1'] = $fy + $h;
								if ($skipln == 1) {
									$this->floatmargins['R']['skipline'] = true;
									$this->floatmargins['R']['id'] = count($this->floatbuffer) + 0;
									$objattr['skipline'] = true;
								}
								$this->floatbuffer[] = $objattr;
							}
						} elseif ($objattr['float'] == 'L') {
							// If L float already exists at this level
							$this->floatmargins['L']['skipline'] = false;
							if (isset($this->floatmargins['L']['y1']) && $this->floatmargins['L']['y1'] > 0 && $fy < $this->floatmargins['L']['y1']) {
								$this->floatmargins['L']['skipline'] = false;
								$this->WriteFlowingBlock($vetor[0], $vetor[18]);  // mPDF 5.7.1
							} // If R float already exists at this level
							elseif (isset($this->floatmargins['R']['y1']) && $this->floatmargins['R']['y1'] > 0 && $fy < $this->floatmargins['R']['y1']) {
								// Final check distance between floats is not now too narrow to fit text
								$mw = 2 * $this->GetCharWidth('W', false);
								if (($this->blk[$this->blklvl]['inner_width'] - $w - $this->floatmargins['R']['w']) < $mw) {
									$this->WriteFlowingBlock($vetor[0], $vetor[18]);  // mPDF 5.7.1
								} else {
									$this->floatmargins['L']['x'] = $fx + $w;
									$this->floatmargins['L']['w'] = $w;
									$this->floatmargins['L']['y0'] = $fy;
									$this->floatmargins['L']['y1'] = $fy + $h;
									if ($skipln == 1) {
										$this->floatmargins['L']['skipline'] = true;
										$this->floatmargins['L']['id'] = count($this->floatbuffer) + 0;
										$objattr['skipline'] = true;
									}
									$this->floatbuffer[] = $objattr;
								}
							} else {
								$this->floatmargins['L']['x'] = $fx + $w;
								$this->floatmargins['L']['w'] = $w;
								$this->floatmargins['L']['y0'] = $fy;
								$this->floatmargins['L']['y1'] = $fy + $h;
								if ($skipln == 1) {
									$this->floatmargins['L']['skipline'] = true;
									$this->floatmargins['L']['id'] = count($this->floatbuffer) + 0;
									$objattr['skipline'] = true;
								}
								$this->floatbuffer[] = $objattr;
							}
						}
					} else {
						/* -- END CSS-IMAGE-FLOAT -- */
						$this->WriteFlowingBlock($vetor[0], (isset($vetor[18]) ? $vetor[18] : null));  // mPDF 5.7.1
						/* -- CSS-IMAGE-FLOAT -- */
					}
					/* -- END CSS-IMAGE-FLOAT -- */
				} // *TABLES*
			} // END If special content
			else { // THE text
				if ($this->tableLevel) {
					$paint_ht_corr = 0;
				} // To move the y up when new column/page started if div border needed
				else {
					$paint_ht_corr = $this->blk[$this->blklvl]['border_top']['w'];
				}

				if ($vetor[0] == "\n") { // We are reading a <BR> now turned into newline ("\n")
					if ($this->flowingBlockAttr['content']) {
						$this->finishFlowingBlock(false, 'br');
					} elseif ($is_table) {
						$this->y+= $this->_computeLineheight($this->cellLineHeight);
					} elseif (!$is_table) {
						$this->DivLn($this->lineheight);
						if ($this->ColActive) {
							$this->breakpoints[$this->CurrCol][] = $this->y;
						} // *COLUMNS*
					}
					// Added to correct for OddEven Margins
					if ($this->page != $oldpage) {
						if (($this->page - $oldpage) % 2 == 1) {
							$bak_x += $this->MarginCorrection;
						}
						$oldpage = $this->page;
						$y = $this->tMargin - $paint_ht_corr;
						$this->oldy = $this->tMargin - $paint_ht_corr;
						$old_height = 0;
					}
					$this->x = $bak_x;
					/* -- COLUMNS -- */
					// COLS
					// OR COLUMN CHANGE
					if ($this->CurrCol != $oldcolumn) {
						if ($this->directionality == 'rtl') { // *OTL*
							$bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
						} // *OTL*
						else { // *OTL*
							$bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
						} // *OTL*
						$this->x = $bak_x;
						$oldcolumn = $this->CurrCol;
						$y = $this->y0 - $paint_ht_corr;
						$this->oldy = $this->y0 - $paint_ht_corr;
						$old_height = 0;
					}
					/* -- END COLUMNS -- */
					$this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, false, $blockdir, $table_draft);
				} else {
					$this->WriteFlowingBlock($vetor[0], $vetor[18]);  // mPDF 5.7.1
					// Added to correct for OddEven Margins
					if ($this->page != $oldpage) {
						if (($this->page - $oldpage) % 2 == 1) {
							$bak_x += $this->MarginCorrection;
							$this->x = $bak_x;
						}
						$oldpage = $this->page;
						$y = $this->tMargin - $paint_ht_corr;
						$this->oldy = $this->tMargin - $paint_ht_corr;
						$old_height = 0;
					}
					/* -- COLUMNS -- */
					// COLS
					// OR COLUMN CHANGE
					if ($this->CurrCol != $oldcolumn) {
						if ($this->directionality == 'rtl') { // *OTL*
							$bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
						} // *OTL*
						else { // *OTL*
							$bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
						} // *OTL*
						$this->x = $bak_x;
						$oldcolumn = $this->CurrCol;
						$y = $this->y0 - $paint_ht_corr;
						$this->oldy = $this->y0 - $paint_ht_corr;
						$old_height = 0;
					}
					/* -- END COLUMNS -- */
				}
			}

			// Check if it is the last element. If so then finish printing the block
			if ($i == ($array_size - 1)) {
				$this->finishFlowingBlock(true); // true = END of flowing block
				// Added to correct for OddEven Margins
				if ($this->page != $oldpage) {
					if (($this->page - $oldpage) % 2 == 1) {
						$bak_x += $this->MarginCorrection;
						$this->x = $bak_x;
					}
					$oldpage = $this->page;
					$y = $this->tMargin - $paint_ht_corr;
					$this->oldy = $this->tMargin - $paint_ht_corr;
					$old_height = 0;
				}

				/* -- COLUMNS -- */
				// COLS
				// OR COLUMN CHANGE
				if ($this->CurrCol != $oldcolumn) {
					if ($this->directionality == 'rtl') { // *OTL*
						$bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
					} // *OTL*
					else { // *OTL*
						$bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
					} // *OTL*
					$this->x = $bak_x;
					$oldcolumn = $this->CurrCol;
					$y = $this->y0 - $paint_ht_corr;
					$this->oldy = $this->y0 - $paint_ht_corr;
					$old_height = 0;
				}
				/* -- END COLUMNS -- */
			}

			// RESETTING VALUES
			$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
			$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
			$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
			$this->colorarray = '';
			$this->spanbgcolorarray = '';
			$this->spanbgcolor = false;
			$this->spanborder = false;
			$this->spanborddet = [];
			$this->HREF = '';
			$this->textparam = [];
			$this->SetTextOutline();

			$this->textvar = 0x00; // mPDF 5.7.1
			$this->OTLtags = [];
			$this->textshadow = '';

			$this->currentfontfamily = '';
			$this->currentfontsize = '';
			$this->currentfontstyle = '';
			$this->currentLang = $this->default_lang;  // mPDF 6
			$this->RestrictUnicodeFonts($this->default_available_fonts); // mPDF 6
			/* -- TABLES -- */
			if ($this->tableLevel) {
				$this->SetLineHeight('', $this->table[1][1]['cellLineHeight']); // *TABLES*
			} else { 			/* -- END TABLES -- */
				if (isset($this->blk[$this->blklvl]['line_height']) && $this->blk[$this->blklvl]['line_height']) {
					$this->SetLineHeight('', $this->blk[$this->blklvl]['line_height']); // sets default line height
				}
			}
			$this->ResetStyles();
			$this->lSpacingCSS = '';
			$this->wSpacingCSS = '';
			$this->fixedlSpacing = false;
			$this->minwSpacing = 0;
			$this->SetDash();
			$this->dash_on = false;
			$this->dotted_on = false;
		}//end of for(i=0;i<arraysize;i++)

		$this->Reset(); // mPDF 6
		// PAINT DIV BORDER	// DISABLED IN COLUMNS AS DOESN'T WORK WHEN BROKEN ACROSS COLS??
		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)) {
			$bottom_y = $this->y; // Does not include Bottom Margin
			if (isset($this->blk[$this->blklvl]['startpage']) && $this->blk[$this->blklvl]['startpage'] != $this->page && $blockstate != 1) {
				$this->PaintDivBB('pagetop', $blockstate);
			} elseif ($blockstate != 1) {
				$this->PaintDivBB('', $blockstate);
			}
			$this->y = $bottom_y;
			$this->x = $bak_x;
		}

		// Reset Font
		$this->SetFontSize($this->default_font_size, false);
		if ($table_draft) {
			$ch = $this->y - $bak_y;
			$this->y = $bak_y;
			$this->x = $bak_x;
			return $ch;
		}
	}

	function _setDashBorder($style, $div, $cp, $side)
	{
		if ($style == 'dashed' && (($side == 'L' || $side == 'R') || ($side == 'T' && $div != 'pagetop' && !$cp) || ($side == 'B' && $div != 'pagebottom') )) {
			$dashsize = 2; // final dash will be this + 1*linewidth
			$dashsizek = 1.5; // ratio of Dash/Blank
			$this->SetDash($dashsize, ($dashsize / $dashsizek) + ($this->LineWidth * 2));
		} elseif ($style == 'dotted' || ($side == 'T' && ($div == 'pagetop' || $cp)) || ($side == 'B' && $div == 'pagebottom')) {
			// Round join and cap
			$this->SetLineJoin(1);
			$this->SetLineCap(1);
			$this->SetDash(0.001, ($this->LineWidth * 3));
		}
	}

	function _setBorderLine($b, $k = 1)
	{
		$this->SetLineWidth($b['w'] / $k);
		$this->SetDColor($b['c']);
		if ($b['c'][0] == 5) { // RGBa
			$this->SetAlpha(ord($b['c'][4]) / 100, 'Normal', false, 'S'); // mPDF 5.7.2
		} elseif ($b['c'][0] == 6) { // CMYKa
			$this->SetAlpha(ord($b['c'][5]) / 100, 'Normal', false, 'S'); // mPDF 5.7.2
		}
	}

	function PaintDivBB($divider = '', $blockstate = 0, $blvl = 0)
	{
		// Borders & backgrounds are done elsewhere for columns - messes up the repositioning in printcolumnbuffer
		if ($this->ColActive) {
			return;
		} // *COLUMNS*
		if ($this->keep_block_together) {
			return;
		} // mPDF 6
		$save_y = $this->y;
		if (!$blvl) {
			$blvl = $this->blklvl;
		}
		$x0 = $x1 = $y0 = $y1 = 0;

		// Added mPDF 3.0 Float DIV
		if (isset($this->blk[$blvl]['bb_painted'][$this->page]) && $this->blk[$blvl]['bb_painted'][$this->page]) {
			return;
		} // *CSS-FLOAT*

		if (isset($this->blk[$blvl]['x0'])) {
			$x0 = $this->blk[$blvl]['x0'];
		} // left
		if (isset($this->blk[$blvl]['y1'])) {
			$y1 = $this->blk[$blvl]['y1'];
		} // bottom
		// Added mPDF 3.0 Float DIV - ensures backgrounds/borders are drawn to bottom of page
		if ($y1 == 0) {
			if ($divider == 'pagebottom') {
				$y1 = $this->h - $this->bMargin;
			} else {
				$y1 = $this->y;
			}
		}

		$continuingpage = (isset($this->blk[$blvl]['startpage']) && $this->blk[$blvl]['startpage'] != $this->page);

		if (isset($this->blk[$blvl]['y0'])) {
			$y0 = $this->blk[$blvl]['y0'];
		}
		$h = $y1 - $y0;
		$w = $this->blk[$blvl]['width'];
		$x1 = $x0 + $w;

		// Set border-widths as used here
		$border_top = $this->blk[$blvl]['border_top']['w'];
		$border_bottom = $this->blk[$blvl]['border_bottom']['w'];
		$border_left = $this->blk[$blvl]['border_left']['w'];
		$border_right = $this->blk[$blvl]['border_right']['w'];
		if (!$this->blk[$blvl]['border_top'] || $divider == 'pagetop' || $continuingpage) {
			$border_top = 0;
		}
		if (!$this->blk[$blvl]['border_bottom'] || $blockstate == 1 || $divider == 'pagebottom') {
			$border_bottom = 0;
		}

		$brTL_H = 0;
		$brTL_V = 0;
		$brTR_H = 0;
		$brTR_V = 0;
		$brBL_H = 0;
		$brBL_V = 0;
		$brBR_H = 0;
		$brBR_V = 0;

		$brset = false;
		/* -- BORDER-RADIUS -- */
		if (isset($this->blk[$blvl]['border_radius_TL_H'])) {
			$brTL_H = $this->blk[$blvl]['border_radius_TL_H'];
			$brset = true;
		}
		if (isset($this->blk[$blvl]['border_radius_TL_V'])) {
			$brTL_V = $this->blk[$blvl]['border_radius_TL_V'];
			$brset = true;
		}
		if (isset($this->blk[$blvl]['border_radius_TR_H'])) {
			$brTR_H = $this->blk[$blvl]['border_radius_TR_H'];
			$brset = true;
		}
		if (isset($this->blk[$blvl]['border_radius_TR_V'])) {
			$brTR_V = $this->blk[$blvl]['border_radius_TR_V'];
			$brset = true;
		}
		if (isset($this->blk[$blvl]['border_radius_BR_H'])) {
			$brBR_H = $this->blk[$blvl]['border_radius_BR_H'];
			$brset = true;
		}
		if (isset($this->blk[$blvl]['border_radius_BR_V'])) {
			$brBR_V = $this->blk[$blvl]['border_radius_BR_V'];
			$brset = true;
		}
		if (isset($this->blk[$blvl]['border_radius_BL_H'])) {
			$brBL_H = $this->blk[$blvl]['border_radius_BL_H'];
			$brset = true;
		}
		if (isset($this->blk[$blvl]['border_radius_BL_V'])) {
			$brBL_V = $this->blk[$blvl]['border_radius_BL_V'];
			$brset = true;
		}

		if (!$this->blk[$blvl]['border_top'] || $divider == 'pagetop' || $continuingpage) {
			$brTL_H = 0;
			$brTL_V = 0;
			$brTR_H = 0;
			$brTR_V = 0;
		}
		if (!$this->blk[$blvl]['border_bottom'] || $blockstate == 1 || $divider == 'pagebottom') {
			$brBL_H = 0;
			$brBL_V = 0;
			$brBR_H = 0;
			$brBR_V = 0;
		}

		// Disallow border-radius if it is smaller than the border width.
		if ($brTL_H < min($border_left, $border_top)) {
			$brTL_H = $brTL_V = 0;
		}
		if ($brTL_V < min($border_left, $border_top)) {
			$brTL_V = $brTL_H = 0;
		}
		if ($brTR_H < min($border_right, $border_top)) {
			$brTR_H = $brTR_V = 0;
		}
		if ($brTR_V < min($border_right, $border_top)) {
			$brTR_V = $brTR_H = 0;
		}
		if ($brBL_H < min($border_left, $border_bottom)) {
			$brBL_H = $brBL_V = 0;
		}
		if ($brBL_V < min($border_left, $border_bottom)) {
			$brBL_V = $brBL_H = 0;
		}
		if ($brBR_H < min($border_right, $border_bottom)) {
			$brBR_H = $brBR_V = 0;
		}
		if ($brBR_V < min($border_right, $border_bottom)) {
			$brBR_V = $brBR_H = 0;
		}

		// CHECK FOR radii that sum to > width or height of div ********
		$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));
		if ($f < 1) {
			$brTL_H *= $f;
			$brTL_V *= $f;
			$brTR_H *= $f;
			$brTR_V *= $f;
			$brBL_H *= $f;
			$brBL_V *= $f;
			$brBR_H *= $f;
			$brBR_V *= $f;
		}
		/* -- END BORDER-RADIUS -- */

		$tbcol = $this->colorConverter->convert(255, $this->PDFAXwarnings);
		for ($l = 0; $l <= $blvl; $l++) {
			if ($this->blk[$l]['bgcolor']) {
				$tbcol = $this->blk[$l]['bgcolorarray'];
			}
		}

		// BORDERS
		if (isset($this->blk[$blvl]['y0']) && $this->blk[$blvl]['y0']) {
			$y0 = $this->blk[$blvl]['y0'];
		}
		$h = $y1 - $y0;
		$w = $this->blk[$blvl]['width'];

		if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
			$tbd = $this->blk[$blvl]['border_top'];

			$legend = '';
			$legbreakL = 0;
			$legbreakR = 0;
			// BORDER LEGEND
			if (isset($this->blk[$blvl]['border_legend']) && $this->blk[$blvl]['border_legend']) {
				$legend = $this->blk[$blvl]['border_legend']; // Same structure array as textbuffer
				$txt = $legend[0] = ltrim($legend[0]);
				if (!empty($legend[18])) {
					$this->otl->trimOTLdata($legend[18], true, false);
				} // *OTL*
				// Set font, size, style, color
				$this->SetFont($legend[4], $legend[2], $legend[11]);
				if (isset($legend[3]) && $legend[3]) {
					$cor = $legend[3];
					$this->SetTColor($cor);
				}
				$stringWidth = $this->GetStringWidth($txt, true, $legend[18], $legend[8]);
				$save_x = $this->x;
				$save_y = $this->y;
				$save_currentfontfamily = $this->FontFamily;
				$save_currentfontsize = $this->FontSizePt;
				$save_currentfontstyle = $this->FontStyle;
				$this->y = $y0 - $this->FontSize / 2 + $this->blk[$blvl]['border_top']['w'] / 2;
				$this->x = $x0 + $this->blk[$blvl]['padding_left'] + $this->blk[$blvl]['border_left']['w'];

				// Set the distance from the border line to the text ? make configurable variable
				$gap = 0.2 * $this->FontSize;
				$legbreakL = $this->x - $gap;
				$legbreakR = $this->x + $stringWidth + $gap;
				$this->magic_reverse_dir($txt, $this->blk[$blvl]['direction'], $legend[18]);
				$fill = '';
				$this->Cell($stringWidth, $this->FontSize, $txt, '', 0, 'C', $fill, '', 0, 0, 0, 'M', $fill, false, $legend[18], $legend[8]);
				// Reset
				$this->x = $save_x;
				$this->y = $save_y;
				$this->SetFont($save_currentfontfamily, $save_currentfontstyle, $save_currentfontsize);
				$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
			}

			if (isset($tbd['s']) && $tbd['s']) {
				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
					$this->writer->write('q');
					$this->SetLineWidth(0);
					$this->writer->write(sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE));
					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $border_left) * Mpdf::SCALE, ($this->h - ($y0 + $border_top)) * Mpdf::SCALE));
					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * Mpdf::SCALE, ($this->h - ($y0 + $border_top)) * Mpdf::SCALE));
					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE));
					$this->writer->write(' h W n '); // Ends path no-op & Sets the clipping path
				}

				$this->_setBorderLine($tbd);
				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
					$legbreakL -= $border_top / 2; // because line cap different
					$legbreakR += $border_top / 2;
					$this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'T');
				} /* -- BORDER-RADIUS -- */ elseif (($brTL_V && $brTL_H) || ($brTR_V && $brTR_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
					$this->SetLineJoin(0);
					$this->SetLineCap(0);
				}
				$s = '';
				if ($brTR_H && $brTR_V) {
					$s .= ($this->_EllipseArc($x0 + $w - $brTR_H, $y0 + $brTR_V, $brTR_H - $border_top / 2, $brTR_V - $border_top / 2, 1, 2, true)) . "\n";
				} else { 				/* -- END BORDER-RADIUS -- */
					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
						$s .= (sprintf('%.3F %.3F m ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
					} else {
						$s .= (sprintf('%.3F %.3F m ', ($x0 + $w - ($border_top / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
					}
				}
				/* -- BORDER-RADIUS -- */
				if ($brTL_H && $brTL_V) {
					if ($legend) {
						if ($legbreakR < ($x0 + $w - $brTR_H)) {
							$s .= (sprintf('%.3F %.3F l ', $legbreakR * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
						}
						if ($legbreakL > ($x0 + $brTL_H )) {
							$s .= (sprintf('%.3F %.3F m ', $legbreakL * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
							$s .= (sprintf('%.3F %.3F l ', ($x0 + $brTL_H ) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE) . "\n");
						} else {
							$s .= (sprintf('%.3F %.3F m ', ($x0 + $brTL_H ) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
						}
					} else {
						$s .= (sprintf('%.3F %.3F l ', ($x0 + $brTL_H ) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
					}
					$s .= ($this->_EllipseArc($x0 + $brTL_H, $y0 + $brTL_V, $brTL_H - $border_top / 2, $brTL_V - $border_top / 2, 2, 1)) . "\n";
				} else {
					/* -- END BORDER-RADIUS -- */
					if ($legend) {
						if ($legbreakR < ($x0 + $w)) {
							$s .= (sprintf('%.3F %.3F l ', $legbreakR * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
						}
						if ($legbreakL > ($x0)) {
							$s .= (sprintf('%.3F %.3F m ', $legbreakL * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
							if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
								$s .= (sprintf('%.3F %.3F l ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
							} else {
								$s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_top / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
							}
						} elseif ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
							$s .= (sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
						} else {
							$s .= (sprintf('%.3F %.3F m ', ($x0 + $border_top / 2) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
						}
					} elseif ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
						$s .= (sprintf('%.3F %.3F l ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
					} else {
						$s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_top / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
					}
					/* -- BORDER-RADIUS -- */
				}
				/* -- END BORDER-RADIUS -- */
				$s .= 'S' . "\n";
				$this->writer->write($s);

				if ($tbd['style'] == 'double') {
					$this->SetLineWidth($tbd['w'] / 3);
					$this->SetDColor($tbcol);
					$this->writer->write($s);
				}
				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
					$this->writer->write('Q');
				}

				// Reset Corners and Dash off
				$this->SetLineWidth(0.1);
				$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
				$this->SetLineJoin(2);
				$this->SetLineCap(2);
				$this->SetDash();
			}
		}
		// Reinstate line above for dotted line divider when block border crosses a page
		// elseif ($divider == 'pagetop' || $continuingpage) {

		if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
			$tbd = $this->blk[$blvl]['border_bottom'];
			if (isset($tbd['s']) && $tbd['s']) {
				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
					$this->writer->write('q');
					$this->SetLineWidth(0);
					$this->writer->write(sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE));
					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $border_left) * Mpdf::SCALE, ($this->h - ($y0 + $h - $border_bottom)) * Mpdf::SCALE));
					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * Mpdf::SCALE, ($this->h - ($y0 + $h - $border_bottom)) * Mpdf::SCALE));
					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE));
					$this->writer->write(' h W n '); // Ends path no-op & Sets the clipping path
				}

				$this->_setBorderLine($tbd);
				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
					$this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'B');
				} /* -- BORDER-RADIUS -- */ elseif (($brBL_V && $brBL_H) || ($brBR_V && $brBR_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
					$this->SetLineJoin(0);
					$this->SetLineCap(0);
				}
				$s = '';
				if ($brBL_H && $brBL_V) {
					$s .= ($this->_EllipseArc($x0 + $brBL_H, $y0 + $h - $brBL_V, $brBL_H - $border_bottom / 2, $brBL_V - $border_bottom / 2, 3, 2, true)) . "\n";
				} else { 				/* -- END BORDER-RADIUS -- */
					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
						$s .= (sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
					} else {
						$s .= (sprintf('%.3F %.3F m ', ($x0 + ($border_bottom / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
					}
				}
				/* -- BORDER-RADIUS -- */
				if ($brBR_H && $brBR_V) {
					$s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_bottom / 2) - $brBR_H ) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
					$s .= ($this->_EllipseArc($x0 + $w - $brBR_H, $y0 + $h - $brBR_V, $brBR_H - $border_bottom / 2, $brBR_V - $border_bottom / 2, 4, 1)) . "\n";
				} else { 				/* -- END BORDER-RADIUS -- */
					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
						$s .= (sprintf('%.3F %.3F l ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
					} else {
						$s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_bottom / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
					}
				}
				$s .= 'S' . "\n";
				$this->writer->write($s);

				if ($tbd['style'] == 'double') {
					$this->SetLineWidth($tbd['w'] / 3);
					$this->SetDColor($tbcol);
					$this->writer->write($s);
				}
				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
					$this->writer->write('Q');
				}

				// Reset Corners and Dash off
				$this->SetLineWidth(0.1);
				$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
				$this->SetLineJoin(2);
				$this->SetLineCap(2);
				$this->SetDash();
			}
		}
		// Reinstate line below for dotted line divider when block border crosses a page
		// elseif ($blockstate == 1 || $divider == 'pagebottom') {

		if ($this->blk[$blvl]['border_left']) {
			$tbd = $this->blk[$blvl]['border_left'];
			if (isset($tbd['s']) && $tbd['s']) {
				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
					$this->writer->write('q');
					$this->SetLineWidth(0);
					$this->writer->write(sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE));
					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $border_left) * Mpdf::SCALE, ($this->h - ($y0 + $border_top)) * Mpdf::SCALE));
					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $border_left) * Mpdf::SCALE, ($this->h - ($y0 + $h - $border_bottom)) * Mpdf::SCALE));
					$this->writer->write(sprintf('%.3F %.3F l ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE));
					$this->writer->write(' h W n '); // Ends path no-op & Sets the clipping path
				}

				$this->_setBorderLine($tbd);
				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
					$this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'L');
				} /* -- BORDER-RADIUS -- */ elseif (($brTL_V && $brTL_H) || ($brBL_V && $brBL_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
					$this->SetLineJoin(0);
					$this->SetLineCap(0);
				}
				$s = '';
				if ($brTL_V && $brTL_H) {
					$s .= ($this->_EllipseArc($x0 + $brTL_H, $y0 + $brTL_V, $brTL_H - $border_left / 2, $brTL_V - $border_left / 2, 2, 2, true)) . "\n";
				} else { 				/* -- END BORDER-RADIUS -- */
					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
						$s .= (sprintf('%.3F %.3F m ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE)) . "\n";
					} else {
						$s .= (sprintf('%.3F %.3F m ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_left / 2))) * Mpdf::SCALE)) . "\n";
					}
				}
				/* -- BORDER-RADIUS -- */
				if ($brBL_V && $brBL_H) {
					$s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_left / 2) - $brBL_V) ) * Mpdf::SCALE)) . "\n";
					$s .= ($this->_EllipseArc($x0 + $brBL_H, $y0 + $h - $brBL_V, $brBL_H - $border_left / 2, $brBL_V - $border_left / 2, 3, 1)) . "\n";
				} else { 				/* -- END BORDER-RADIUS -- */
					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
						$s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h) ) * Mpdf::SCALE)) . "\n";
					} else {
						$s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_left / 2)) ) * Mpdf::SCALE)) . "\n";
					}
				}
				$s .= 'S' . "\n";
				$this->writer->write($s);

				if ($tbd['style'] == 'double') {
					$this->SetLineWidth($tbd['w'] / 3);
					$this->SetDColor($tbcol);
					$this->writer->write($s);
				}
				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
					$this->writer->write('Q');
				}

				// Reset Corners and Dash off
				$this->SetLineWidth(0.1);
				$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
				$this->SetLineJoin(2);
				$this->SetLineCap(2);
				$this->SetDash();
			}
		}
		if ($this->blk[$blvl]['border_right']) {
			$tbd = $this->blk[$blvl]['border_right'];
			if (isset($tbd['s']) && $tbd['s']) {
				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
					$this->writer->write('q');
					$this->SetLineWidth(0);
					$this->writer->write(sprintf('%.3F %.3F m ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE));
					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * Mpdf::SCALE, ($this->h - ($y0 + $border_top)) * Mpdf::SCALE));
					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * Mpdf::SCALE, ($this->h - ($y0 + $h - $border_bottom)) * Mpdf::SCALE));
					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE));
					$this->writer->write(' h W n '); // Ends path no-op & Sets the clipping path
				}

				$this->_setBorderLine($tbd);
				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
					$this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'R');
				} /* -- BORDER-RADIUS -- */ elseif (($brTR_V && $brTR_H) || ($brBR_V && $brBR_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
					$this->SetLineJoin(0);
					$this->SetLineCap(0);
				}
				$s = '';
				if ($brBR_V && $brBR_H) {
					$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";
				} else { 				/* -- END BORDER-RADIUS -- */
					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
						$s .= (sprintf('%.3F %.3F m ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE)) . "\n";
					} else {
						$s .= (sprintf('%.3F %.3F m ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_right / 2))) * Mpdf::SCALE)) . "\n";
					}
				}
				/* -- BORDER-RADIUS -- */
				if ($brTR_V && $brTR_H) {
					$s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_right / 2) + $brTR_V) ) * Mpdf::SCALE)) . "\n";
					$s .= ($this->_EllipseArc($x0 + $w - $brTR_H, $y0 + $brTR_V, $brTR_H - $border_right / 2, $brTR_V - $border_right / 2, 1, 1)) . "\n";
				} else { 				/* -- END BORDER-RADIUS -- */
					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
						$s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0) ) * Mpdf::SCALE)) . "\n";
					} else {
						$s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_right / 2)) ) * Mpdf::SCALE)) . "\n";
					}
				}
				$s .= 'S' . "\n";
				$this->writer->write($s);

				if ($tbd['style'] == 'double') {
					$this->SetLineWidth($tbd['w'] / 3);
					$this->SetDColor($tbcol);
					$this->writer->write($s);
				}
				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
					$this->writer->write('Q');
				}

				// Reset Corners and Dash off
				$this->SetLineWidth(0.1);
				$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
				$this->SetLineJoin(2);
				$this->SetLineCap(2);
				$this->SetDash();
			}
		}


		$this->SetDash();
		$this->y = $save_y;


		// BACKGROUNDS are disabled in columns/kbt/headers - messes up the repositioning in printcolumnbuffer
		if ($this->ColActive || $this->kwt || $this->keep_block_together) {
			return;
		}


		$bgx0 = $x0;
		$bgx1 = $x1;
		$bgy0 = $y0;
		$bgy1 = $y1;

		// Defined br values represent the radius of the outer curve - need to take border-width/2 from each radius for drawing the borders
		if (isset($this->blk[$blvl]['background_clip']) && $this->blk[$blvl]['background_clip'] == 'padding-box') {
			$brbgTL_H = max(0, $brTL_H - $this->blk[$blvl]['border_left']['w']);
			$brbgTL_V = max(0, $brTL_V - $this->blk[$blvl]['border_top']['w']);
			$brbgTR_H = max(0, $brTR_H - $this->blk[$blvl]['border_right']['w']);
			$brbgTR_V = max(0, $brTR_V - $this->blk[$blvl]['border_top']['w']);
			$brbgBL_H = max(0, $brBL_H - $this->blk[$blvl]['border_left']['w']);
			$brbgBL_V = max(0, $brBL_V - $this->blk[$blvl]['border_bottom']['w']);
			$brbgBR_H = max(0, $brBR_H - $this->blk[$blvl]['border_right']['w']);
			$brbgBR_V = max(0, $brBR_V - $this->blk[$blvl]['border_bottom']['w']);
			$bgx0 += $this->blk[$blvl]['border_left']['w'];
			$bgx1 -= $this->blk[$blvl]['border_right']['w'];
			if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
				$bgy0 += $this->blk[$blvl]['border_top']['w'];
			}
			if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
				$bgy1 -= $this->blk[$blvl]['border_bottom']['w'];
			}
		} elseif (isset($this->blk[$blvl]['background_clip']) && $this->blk[$blvl]['background_clip'] == 'content-box') {
			$brbgTL_H = max(0, $brTL_H - $this->blk[$blvl]['border_left']['w'] - $this->blk[$blvl]['padding_left']);
			$brbgTL_V = max(0, $brTL_V - $this->blk[$blvl]['border_top']['w'] - $this->blk[$blvl]['padding_top']);
			$brbgTR_H = max(0, $brTR_H - $this->blk[$blvl]['border_right']['w'] - $this->blk[$blvl]['padding_right']);
			$brbgTR_V = max(0, $brTR_V - $this->blk[$blvl]['border_top']['w'] - $this->blk[$blvl]['padding_top']);
			$brbgBL_H = max(0, $brBL_H - $this->blk[$blvl]['border_left']['w'] - $this->blk[$blvl]['padding_left']);
			$brbgBL_V = max(0, $brBL_V - $this->blk[$blvl]['border_bottom']['w'] - $this->blk[$blvl]['padding_bottom']);
			$brbgBR_H = max(0, $brBR_H - $this->blk[$blvl]['border_right']['w'] - $this->blk[$blvl]['padding_right']);
			$brbgBR_V = max(0, $brBR_V - $this->blk[$blvl]['border_bottom']['w'] - $this->blk[$blvl]['padding_bottom']);
			$bgx0 += $this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'];
			$bgx1 -= $this->blk[$blvl]['border_right']['w'] + $this->blk[$blvl]['padding_right'];
			if (($this->blk[$blvl]['border_top']['w'] || $this->blk[$blvl]['padding_top']) && $divider != 'pagetop' && !$continuingpage) {
				$bgy0 += $this->blk[$blvl]['border_top']['w'] + $this->blk[$blvl]['padding_top'];
			}
			if (($this->blk[$blvl]['border_bottom']['w'] || $this->blk[$blvl]['padding_bottom']) && $blockstate != 1 && $divider != 'pagebottom') {
				$bgy1 -= $this->blk[$blvl]['border_bottom']['w'] + $this->blk[$blvl]['padding_bottom'];
			}
		} else {
			$brbgTL_H = $brTL_H;
			$brbgTL_V = $brTL_V;
			$brbgTR_H = $brTR_H;
			$brbgTR_V = $brTR_V;
			$brbgBL_H = $brBL_H;
			$brbgBL_V = $brBL_V;
			$brbgBR_H = $brBR_H;
			$brbgBR_V = $brBR_V;
		}

		// Set clipping path
		$s = ' q 0 w '; // Line width=0
		$s .= sprintf('%.3F %.3F m ', ($bgx0 + $brbgTL_H ) * Mpdf::SCALE, ($this->h - $bgy0) * Mpdf::SCALE); // start point TL before the arc
		/* -- BORDER-RADIUS -- */
		if ($brbgTL_H || $brbgTL_V) {
			$s .= $this->_EllipseArc($bgx0 + $brbgTL_H, $bgy0 + $brbgTL_V, $brbgTL_H, $brbgTL_V, 2); // segment 2 TL
		}
		/* -- END BORDER-RADIUS -- */
		$s .= sprintf('%.3F %.3F l ', ($bgx0) * Mpdf::SCALE, ($this->h - ($bgy1 - $brbgBL_V )) * Mpdf::SCALE); // line to BL
		/* -- BORDER-RADIUS -- */
		if ($brbgBL_H || $brbgBL_V) {
			$s .= $this->_EllipseArc($bgx0 + $brbgBL_H, $bgy1 - $brbgBL_V, $brbgBL_H, $brbgBL_V, 3); // segment 3 BL
		}
		/* -- END BORDER-RADIUS -- */
		$s .= sprintf('%.3F %.3F l ', ($bgx1 - $brbgBR_H ) * Mpdf::SCALE, ($this->h - ($bgy1)) * Mpdf::SCALE); // line to BR
		/* -- BORDER-RADIUS -- */
		if ($brbgBR_H || $brbgBR_V) {
			$s .= $this->_EllipseArc($bgx1 - $brbgBR_H, $bgy1 - $brbgBR_V, $brbgBR_H, $brbgBR_V, 4); // segment 4 BR
		}
		/* -- END BORDER-RADIUS -- */
		$s .= sprintf('%.3F %.3F l ', ($bgx1) * Mpdf::SCALE, ($this->h - ($bgy0 + $brbgTR_V)) * Mpdf::SCALE); // line to TR
		/* -- BORDER-RADIUS -- */
		if ($brbgTR_H || $brbgTR_V) {
			$s .= $this->_EllipseArc($bgx1 - $brbgTR_H, $bgy0 + $brbgTR_V, $brbgTR_H, $brbgTR_V, 1); // segment 1 TR
		}
		/* -- END BORDER-RADIUS -- */
		$s .= sprintf('%.3F %.3F l ', ($bgx0 + $brbgTL_H ) * Mpdf::SCALE, ($this->h - $bgy0) * Mpdf::SCALE); // line to TL
		// Box Shadow
		$shadow = '';
		if (isset($this->blk[$blvl]['box_shadow']) && $this->blk[$blvl]['box_shadow'] && $h > 0) {
			foreach ($this->blk[$blvl]['box_shadow'] as $sh) {
				// Colors
				if ($sh['col'][0] == 1) {
					$colspace = 'Gray';
					if ($sh['col'][2] == 1) {
						$col1 = '1' . $sh['col'][1] . '1' . $sh['col'][3];
					} else {
						$col1 = '1' . $sh['col'][1] . '1' . chr(100);
					}
					$col2 = '1' . $sh['col'][1] . '1' . chr(0);
				} elseif ($sh['col'][0] == 4) { // CMYK
					$colspace = 'CMYK';
					$col1 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . chr(100);
					$col2 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . chr(0);
				} elseif ($sh['col'][0] == 5) { // RGBa
					$colspace = 'RGB';
					$col1 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4];
					$col2 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . chr(0);
				} elseif ($sh['col'][0] == 6) { // CMYKa
					$colspace = 'CMYK';
					$col1 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . $sh['col'][5];
					$col2 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . chr(0);
				} else {
					$colspace = 'RGB';
					$col1 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . chr(100);
					$col2 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . chr(0);
				}

				// Use clipping path as set above (and rectangle around page) to clip area outside box
				$shadow .= $s; // Use the clipping path with W*
				$shadow .= sprintf('0 %.3F m %.3F %.3F l ', $this->h * Mpdf::SCALE, $this->w * Mpdf::SCALE, $this->h * Mpdf::SCALE);
				$shadow .= sprintf('%.3F 0 l 0 0 l 0 %.3F l ', $this->w * Mpdf::SCALE, $this->h * Mpdf::SCALE);
				$shadow .= 'W n' . "\n";

				$sh['blur'] = abs($sh['blur']); // cannot have negative blur value
				// Ensure spread/blur do not make effective shadow width/height < 0
				// Could do more complex things but this just adjusts spread value
				if (-$sh['spread'] + $sh['blur'] / 2 > min($w / 2, $h / 2)) {
					$sh['spread'] = $sh['blur'] / 2 - min($w / 2, $h / 2) + 0.01;
				}
				// Shadow Offset
				if ($sh['x'] || $sh['y']) {
					$shadow .= sprintf(' q 1 0 0 1 %.4F %.4F cm', $sh['x'] * Mpdf::SCALE, -$sh['y'] * Mpdf::SCALE) . "\n";
				}

				// Set path for INNER shadow
				$shadow .= ' q 0 w ';
				$shadow .= $this->SetFColor($col1, true) . "\n";
				if ($col1[0] == 5 && ord($col1[4]) < 100) { // RGBa
					$shadow .= $this->SetAlpha(ord($col1[4]) / 100, 'Normal', true, 'F') . "\n";
				} elseif ($col1[0] == 6 && ord($col1[5]) < 100) { // CMYKa
					$shadow .= $this->SetAlpha(ord($col1[5]) / 100, 'Normal', true, 'F') . "\n";
				} elseif ($col1[0] == 1 && $col1[2] == 1 && ord($col1[3]) < 100) { // Gray
					$shadow .= $this->SetAlpha(ord($col1[3]) / 100, 'Normal', true, 'F') . "\n";
				}

				// Blur edges
				$mag = 0.551784; // Bezier Control magic number for 4-part spline for circle/ellipse
				$mag2 = 0.551784; // Bezier Control magic number to fill in edge of blurred rectangle
				$d1 = $sh['spread'] + $sh['blur'] / 2;
				$d2 = $sh['spread'] - $sh['blur'] / 2;
				$bl = $sh['blur'];
				$x00 = $x0 - $d1;
				$y00 = $y0 - $d1;
				$w00 = $w + $d1 * 2;
				$h00 = $h + $d1 * 2;

				// If any border-radius is greater width-negative spread(inner edge), ignore radii for shadow or screws up
				$flatten = false;
				if (max($brbgTR_H, $brbgTL_H, $brbgBR_H, $brbgBL_H) >= $w + $d2) {
					$flatten = true;
				}
				if (max($brbgTR_V, $brbgTL_V, $brbgBR_V, $brbgBL_V) >= $h + $d2) {
					$flatten = true;
				}


				// TOP RIGHT corner
				$p1x = $x00 + $w00 - $d1 - $brbgTR_H;
				$p1c2x = $p1x + ($d2 + $brbgTR_H) * $mag;
				$p1y = $y00 + $bl;
				$p2x = $x00 + $w00 - $d1 - $brbgTR_H;
				$p2c2x = $p2x + ($d1 + $brbgTR_H) * $mag;
				$p2y = $y00;
				$p2c1y = $p2y + $bl / 2;
				$p3x = $x00 + $w00;
				$p3c2x = $p3x - $bl / 2;
				$p3y = $y00 + $d1 + $brbgTR_V;
				$p3c1y = $p3y - ($d1 + $brbgTR_V) * $mag;
				$p4x = $x00 + $w00 - $bl;
				$p4y = $y00 + $d1 + $brbgTR_V;
				$p4c2y = $p4y - ($d2 + $brbgTR_V) * $mag;
				if (-$d2 > min($brbgTR_H, $brbgTR_V) || $flatten) {
					$p1x = $x00 + $w00 - $bl;
					$p1c2x = $p1x;
					$p2x = $x00 + $w00 - $bl;
					$p2c2x = $p2x + $bl * $mag2;
					$p3y = $y00 + $bl;
					$p3c1y = $p3y - $bl * $mag2;
					$p4y = $y00 + $bl;
					$p4c2y = $p4y;
				}

				$shadow .= sprintf('%.3F %.3F m ', ($p1x ) * Mpdf::SCALE, ($this->h - ($p1y )) * Mpdf::SCALE);
				$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);
				$patch_array[0]['f'] = 0;
				$patch_array[0]['points'] = [$p1x, $p1y, $p1x, $p1y,
					$p2x, $p2c1y, $p2x, $p2y, $p2c2x, $p2y,
					$p3x, $p3c1y, $p3x, $p3y, $p3c2x, $p3y,
					$p4x, $p4y, $p4x, $p4y, $p4x, $p4c2y,
					$p1c2x, $p1y];
				$patch_array[0]['colors'] = [$col1, $col2, $col2, $col1];


				// RIGHT
				$p1x = $x00 + $w00; // control point only matches p3 preceding
				$p1y = $y00 + $d1 + $brbgTR_V;
				$p2x = $x00 + $w00 - $bl; // control point only matches p4 preceding
				$p2y = $y00 + $d1 + $brbgTR_V;
				$p3x = $x00 + $w00 - $bl;
				$p3y = $y00 + $h00 - $d1 - $brbgBR_V;
				$p4x = $x00 + $w00;
				$p4c1x = $p4x - $bl / 2;
				$p4y = $y00 + $h00 - $d1 - $brbgBR_V;
				if (-$d2 > min($brbgTR_H, $brbgTR_V) || $flatten) {
					$p1y = $y00 + $bl;
					$p2y = $y00 + $bl;
				}
				if (-$d2 > min($brbgBR_H, $brbgBR_V) || $flatten) {
					$p3y = $y00 + $h00 - $bl;
					$p4y = $y00 + $h00 - $bl;
				}

				$shadow .= sprintf('%.3F %.3F l ', ($p3x ) * Mpdf::SCALE, ($this->h - ($p3y )) * Mpdf::SCALE);
				$patch_array[1]['f'] = 2;
				$patch_array[1]['points'] = [$p2x, $p2y,
					$p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
					$p4c1x, $p4y, $p4x, $p4y, $p4x, $p4y,
					$p1x, $p1y];
				$patch_array[1]['colors'] = [$col1, $col2];


				// BOTTOM RIGHT corner
				$p1x = $x00 + $w00 - $bl;  // control points only matches p3 preceding
				$p1y = $y00 + $h00 - $d1 - $brbgBR_V;
				$p1c2y = $p1y + ($d2 + $brbgBR_V) * $mag;
				$p2x = $x00 + $w00;     // control point only matches p4 preceding
				$p2y = $y00 + $h00 - $d1 - $brbgBR_V;
				$p2c2y = $p2y + ($d1 + $brbgBR_V) * $mag;
				$p3x = $x00 + $w00 - $d1 - $brbgBR_H;
				$p3c1x = $p3x + ($d1 + $brbgBR_H) * $mag;
				$p3y = $y00 + $h00;
				$p3c2y = $p3y - $bl / 2;
				$p4x = $x00 + $w00 - $d1 - $brbgBR_H;
				$p4c2x = $p4x + ($d2 + $brbgBR_H) * $mag;
				$p4y = $y00 + $h00 - $bl;

				if (-$d2 > min($brbgBR_H, $brbgBR_V) || $flatten) {
					$p1y = $y00 + $h00 - $bl;
					$p1c2y = $p1y;
					$p2y = $y00 + $h00 - $bl;
					$p2c2y = $p2y + $bl * $mag2;
					$p3x = $x00 + $w00 - $bl;
					$p3c1x = $p3x + $bl * $mag2;
					$p4x = $x00 + $w00 - $bl;
					$p4c2x = $p4x;
				}

				$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);
				$patch_array[2]['f'] = 2;
				$patch_array[2]['points'] = [$p2x, $p2c2y,
					$p3c1x, $p3y, $p3x, $p3y, $p3x, $p3c2y,
					$p4x, $p4y, $p4x, $p4y, $p4c2x, $p4y,
					$p1x, $p1c2y];
				$patch_array[2]['colors'] = [$col2, $col1];



				// BOTTOM
				$p1x = $x00 + $w00 - $d1 - $brbgBR_H; // control point only matches p3 preceding
				$p1y = $y00 + $h00;
				$p2x = $x00 + $w00 - $d1 - $brbgBR_H; // control point only matches p4 preceding
				$p2y = $y00 + $h00 - $bl;
				$p3x = $x00 + $d1 + $brbgBL_H;
				$p3y = $y00 + $h00 - $bl;
				$p4x = $x00 + $d1 + $brbgBL_H;
				$p4y = $y00 + $h00;
				$p4c1y = $p4y - $bl / 2;

				if (-$d2 > min($brbgBR_H, $brbgBR_V) || $flatten) {
					$p1x = $x00 + $w00 - $bl;
					$p2x = $x00 + $w00 - $bl;
				}
				if (-$d2 > min($brbgBL_H, $brbgBL_V) || $flatten) {
					$p3x = $x00 + $bl;
					$p4x = $x00 + $bl;
				}

				$shadow .= sprintf('%.3F %.3F l ', ($p3x ) * Mpdf::SCALE, ($this->h - ($p3y )) * Mpdf::SCALE);
				$patch_array[3]['f'] = 2;
				$patch_array[3]['points'] = [$p2x, $p2y,
					$p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
					$p4x, $p4c1y, $p4x, $p4y, $p4x, $p4y,
					$p1x, $p1y];
				$patch_array[3]['colors'] = [$col1, $col2];

				// BOTTOM LEFT corner
				$p1x = $x00 + $d1 + $brbgBL_H;
				$p1c2x = $p1x - ($d2 + $brbgBL_H) * $mag; // control points only matches p3 preceding
				$p1y = $y00 + $h00 - $bl;
				$p2x = $x00 + $d1 + $brbgBL_H;
				$p2c2x = $p2x - ($d1 + $brbgBL_H) * $mag; // control point only matches p4 preceding
				$p2y = $y00 + $h00;
				$p3x = $x00;
				$p3c2x = $p3x + $bl / 2;
				$p3y = $y00 + $h00 - $d1 - $brbgBL_V;
				$p3c1y = $p3y + ($d1 + $brbgBL_V) * $mag;
				$p4x = $x00 + $bl;
				$p4y = $y00 + $h00 - $d1 - $brbgBL_V;
				$p4c2y = $p4y + ($d2 + $brbgBL_V) * $mag;
				if (-$d2 > min($brbgBL_H, $brbgBL_V) || $flatten) {
					$p1x = $x00 + $bl;
					$p1c2x = $p1x;
					$p2x = $x00 + $bl;
					$p2c2x = $p2x - $bl * $mag2;
					$p3y = $y00 + $h00 - $bl;
					$p3c1y = $p3y + $bl * $mag2;
					$p4y = $y00 + $h00 - $bl;
					$p4c2y = $p4y;
				}

				$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);
				$patch_array[4]['f'] = 2;
				$patch_array[4]['points'] = [$p2c2x, $p2y,
					$p3x, $p3c1y, $p3x, $p3y, $p3c2x, $p3y,
					$p4x, $p4y, $p4x, $p4y, $p4x, $p4c2y,
					$p1c2x, $p1y];
				$patch_array[4]['colors'] = [$col2, $col1];


				// LEFT - joins on the right (C3-C4 of previous): f = 2
				$p1x = $x00; // control point only matches p3 preceding
				$p1y = $y00 + $h00 - $d1 - $brbgBL_V;
				$p2x = $x00 + $bl; // control point only matches p4 preceding
				$p2y = $y00 + $h00 - $d1 - $brbgBL_V;
				$p3x = $x00 + $bl;
				$p3y = $y00 + $d1 + $brbgTL_V;
				$p4x = $x00;
				$p4c1x = $p4x + $bl / 2;
				$p4y = $y00 + $d1 + $brbgTL_V;
				if (-$d2 > min($brbgBL_H, $brbgBL_V) || $flatten) {
					$p1y = $y00 + $h00 - $bl;
					$p2y = $y00 + $h00 - $bl;
				}
				if (-$d2 > min($brbgTL_H, $brbgTL_V) || $flatten) {
					$p3y = $y00 + $bl;
					$p4y = $y00 + $bl;
				}

				$shadow .= sprintf('%.3F %.3F l ', ($p3x ) * Mpdf::SCALE, ($this->h - ($p3y )) * Mpdf::SCALE);
				$patch_array[5]['f'] = 2;
				$patch_array[5]['points'] = [$p2x, $p2y,
					$p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
					$p4c1x, $p4y, $p4x, $p4y, $p4x, $p4y,
					$p1x, $p1y];
				$patch_array[5]['colors'] = [$col1, $col2];

				// TOP LEFT corner
				$p1x = $x00 + $bl;  // control points only matches p3 preceding
				$p1y = $y00 + $d1 + $brbgTL_V;
				$p1c2y = $p1y - ($d2 + $brbgTL_V) * $mag;
				$p2x = $x00;   // control point only matches p4 preceding
				$p2y = $y00 + $d1 + $brbgTL_V;
				$p2c2y = $p2y - ($d1 + $brbgTL_V) * $mag;
				$p3x = $x00 + $d1 + $brbgTL_H;
				$p3c1x = $p3x - ($d1 + $brbgTL_H) * $mag;
				$p3y = $y00;
				$p3c2y = $p3y + $bl / 2;
				$p4x = $x00 + $d1 + $brbgTL_H;
				$p4c2x = $p4x - ($d2 + $brbgTL_H) * $mag;
				$p4y = $y00 + $bl;

				if (-$d2 > min($brbgTL_H, $brbgTL_V) || $flatten) {
					$p1y = $y00 + $bl;
					$p1c2y = $p1y;
					$p2y = $y00 + $bl;
					$p2c2y = $p2y - $bl * $mag2;
					$p3x = $x00 + $bl;
					$p3c1x = $p3x - $bl * $mag2;
					$p4x = $x00 + $bl;
					$p4c2x = $p4x;
				}

				$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);
				$patch_array[6]['f'] = 2;
				$patch_array[6]['points'] = [$p2x, $p2c2y,
					$p3c1x, $p3y, $p3x, $p3y, $p3x, $p3c2y,
					$p4x, $p4y, $p4x, $p4y, $p4c2x, $p4y,
					$p1x, $p1c2y];
				$patch_array[6]['colors'] = [$col2, $col1];


				// TOP - joins on the right (C3-C4 of previous): f = 2
				$p1x = $x00 + $d1 + $brbgTL_H; // control point only matches p3 preceding
				$p1y = $y00;
				$p2x = $x00 + $d1 + $brbgTL_H; // control point only matches p4 preceding
				$p2y = $y00 + $bl;
				$p3x = $x00 + $w00 - $d1 - $brbgTR_H;
				$p3y = $y00 + $bl;
				$p4x = $x00 + $w00 - $d1 - $brbgTR_H;
				$p4y = $y00;
				$p4c1y = $p4y + $bl / 2;
				if (-$d2 > min($brbgTL_H, $brbgTL_V) || $flatten) {
					$p1x = $x00 + $bl;
					$p2x = $x00 + $bl;
				}
				if (-$d2 > min($brbgTR_H, $brbgTR_V) || $flatten) {
					$p3x = $x00 + $w00 - $bl;
					$p4x = $x00 + $w00 - $bl;
				}

				$shadow .= sprintf('%.3F %.3F l ', ($p3x ) * Mpdf::SCALE, ($this->h - ($p3y )) * Mpdf::SCALE);
				$patch_array[7]['f'] = 2;
				$patch_array[7]['points'] = [$p2x, $p2y,
					$p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
					$p4x, $p4c1y, $p4x, $p4y, $p4x, $p4y,
					$p1x, $p1y];
				$patch_array[7]['colors'] = [$col1, $col2];

				$shadow .= ' h f Q ' . "\n"; // Close path and Fill the inner solid shadow

				if ($bl) {
					$shadow .= $this->gradient->CoonsPatchMesh($x00, $y00, $w00, $h00, $patch_array, $x00, $x00 + $w00, $y00, $y00 + $h00, $colspace, true);
				}

				if ($sh['x'] || $sh['y']) {
					$shadow .= ' Q' . "\n";  // Shadow Offset
				}
				$shadow .= ' Q' . "\n"; // Ends path no-op & Sets the clipping path
			}
		}

		$s .= ' W n '; // Ends path no-op & Sets the clipping path

		if ($this->blk[$blvl]['bgcolor']) {
			$this->pageBackgrounds[$blvl][] = [
				'x' => $x0,
				'y' => $y0,
				'w' => $w,
				'h' => $h,
				'col' => $this->blk[$blvl]['bgcolorarray'],
				'clippath' => $s,
				'visibility' => $this->visibility,
				'shadow' => $shadow,
				'z-index' => $this->current_layer,
			];
		} elseif ($shadow) {
			$this->pageBackgrounds[$blvl][] = [
				'x' => 0,
				'y' => 0,
				'w' => 0,
				'h' => 0,
				'shadowonly' => true,
				'col' => '',
				'clippath' => '',
				'visibility' => $this->visibility,
				'shadow' => $shadow,
				'z-index' => $this->current_layer,
			];
		}

		/* -- BACKGROUNDS -- */
		if (isset($this->blk[$blvl]['gradient'])) {
			$g = $this->gradient->parseBackgroundGradient($this->blk[$blvl]['gradient']);
			if ($g) {
				$gx = $x0;
				$gy = $y0;
				$this->pageBackgrounds[$blvl][] = [
					'gradient' => true,
					'x' => $gx,
					'y' => $gy,
					'w' => $w,
					'h' => $h,
					'gradtype' => $g['type'],
					'stops' => $g['stops'],
					'colorspace' => $g['colorspace'],
					'coords' => $g['coords'],
					'extend' => $g['extend'],
					'clippath' => $s,
					'visibility' => $this->visibility,
					'z-index' => $this->current_layer
				];
			}
		}

		if (isset($this->blk[$blvl]['background-image'])) {
			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'])) {
				$g = $this->gradient->parseMozGradient($this->blk[$blvl]['background-image']['gradient']);
				if ($g) {
					$gx = $x0;
					$gy = $y0;
					// origin specifies the background-positioning-area (bpa)
					if ($this->blk[$blvl]['background-image']['origin'] == 'padding-box') {
						$gx += $this->blk[$blvl]['border_left']['w'];
						$w -= ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['border_right']['w']);
						if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
							$gy += $this->blk[$blvl]['border_top']['w'];
						}
						if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
							$gy1 = $y1 - $this->blk[$blvl]['border_bottom']['w'];
						} else {
							$gy1 = $y1;
						}
						$h = $gy1 - $gy;
					} elseif ($this->blk[$blvl]['background-image']['origin'] == 'content-box') {
						$gx += $this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'];
						$w -= ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'] + $this->blk[$blvl]['border_right']['w'] + $this->blk[$blvl]['padding_right']);
						if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
							$gy += $this->blk[$blvl]['border_top']['w'] + $this->blk[$blvl]['padding_top'];
						}
						if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
							$gy1 = $y1 - ($this->blk[$blvl]['border_bottom']['w'] + $this->blk[$blvl]['padding_bottom']);
						} else {
							$gy1 = $y1 - $this->blk[$blvl]['padding_bottom'];
						}
						$h = $gy1 - $gy;
					}

					if (isset($this->blk[$blvl]['background-image']['size']['w']) && $this->blk[$blvl]['background-image']['size']['w']) {
						$size = $this->blk[$blvl]['background-image']['size'];
						if ($size['w'] != 'contain' && $size['w'] != 'cover') {
							if (stristr($size['w'], '%')) {
								$size['w'] = (float) $size['w'];
								$size['w'] /= 100;
								$w *= $size['w'];
							} elseif ($size['w'] != 'auto') {
								$w = $size['w'];
							}
							if (stristr($size['h'], '%')) {
								$size['h'] = (float) $size['h'];
								$size['h'] /= 100;
								$h *= $size['h'];
							} elseif ($size['h'] != 'auto') {
								$h = $size['h'];
							}
						}
					}
					$this->pageBackgrounds[$blvl][] = [
						'gradient' => true,
						'x' => $gx,
						'y' => $gy,
						'w' => $w,
						'h' => $h,
						'gradtype' => $g['type'],
						'stops' => $g['stops'],
						'colorspace' => $g['colorspace'],
						'coords' => $g['coords'],
						'extend' => $g['extend'],
						'clippath' => $s,
						'visibility' => $this->visibility,
						'z-index' => $this->current_layer
					];
				}

			} else {

				$image_id = $this->blk[$blvl]['background-image']['image_id'];
				$orig_w = $this->blk[$blvl]['background-image']['orig_w'];
				$orig_h = $this->blk[$blvl]['background-image']['orig_h'];
				$x_pos = $this->blk[$blvl]['background-image']['x_pos'];
				$y_pos = $this->blk[$blvl]['background-image']['y_pos'];
				$x_repeat = $this->blk[$blvl]['background-image']['x_repeat'];
				$y_repeat = $this->blk[$blvl]['background-image']['y_repeat'];
				$resize = $this->blk[$blvl]['background-image']['resize'];
				$opacity = $this->blk[$blvl]['background-image']['opacity'];
				$itype = $this->blk[$blvl]['background-image']['itype'];
				$size = $this->blk[$blvl]['background-image']['size'];
				// origin specifies the background-positioning-area (bpa)

				$bpa = ['x' => $x0, 'y' => $y0, 'w' => $w, 'h' => $h];

				if ($this->blk[$blvl]['background-image']['origin'] == 'padding-box') {

					$bpa['x'] = $x0 + $this->blk[$blvl]['border_left']['w'];
					$bpa['w'] = $w - ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['border_right']['w']);
					if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
						$bpa['y'] = $y0 + $this->blk[$blvl]['border_top']['w'];
					} else {
						$bpa['y'] = $y0;
					}
					if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
						$bpay = $y1 - $this->blk[$blvl]['border_bottom']['w'];
					} else {
						$bpay = $y1;
					}
					$bpa['h'] = $bpay - $bpa['y'];

				} elseif ($this->blk[$blvl]['background-image']['origin'] == 'content-box') {

					$bpa['x'] = $x0 + $this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'];
					$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']);
					if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
						$bpa['y'] = $y0 + $this->blk[$blvl]['border_top']['w'] + $this->blk[$blvl]['padding_top'];
					} else {
						$bpa['y'] = $y0 + $this->blk[$blvl]['padding_top'];
					}
					if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
						$bpay = $y1 - ($this->blk[$blvl]['border_bottom']['w'] + $this->blk[$blvl]['padding_bottom']);
					} else {
						$bpay = $y1 - $this->blk[$blvl]['padding_bottom'];
					}
					$bpa['h'] = $bpay - $bpa['y'];

				}

				$this->pageBackgrounds[$blvl][] = [
					'x' => $x0,
					'y' => $y0,
					'w' => $w,
					'h' => $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,
					'visibility' => $this->visibility,
					'z-index' => $this->current_layer,
					'size' => $size,
					'bpa' => $bpa
				];
			}
		}
		/* -- END BACKGROUNDS -- */

		// Float DIV
		$this->blk[$blvl]['bb_painted'][$this->page] = true;
	}
	/* -- BORDER-RADIUS -- */

	function _EllipseArc($x0, $y0, $rx, $ry, $seg = 1, $part = false, $start = false)
	{
		// Anticlockwise segment 1-4 TR-TL-BL-BR (part=1 or 2)
		$s = '';

		if ($rx < 0) {
			$rx = 0;
		}

		if ($ry < 0) {
			$ry = 0;
		}

		$rx *= Mpdf::SCALE;
		$ry *= Mpdf::SCALE;

		$astart = 0;

		if ($seg == 1) { // Top Right
			$afinish = 90;
			$nSeg = 4;
		} elseif ($seg == 2) { // Top Left
			$afinish = 180;
			$nSeg = 8;
		} elseif ($seg == 3) { // Bottom Left
			$afinish = 270;
			$nSeg = 12;
		} else {   // Bottom Right
			$afinish = 360;
			$nSeg = 16;
		}

		$astart = deg2rad((float) $astart);
		$afinish = deg2rad((float) $afinish);

		$totalAngle = $afinish - $astart;
		$dt = $totalAngle / $nSeg; // segment angle
		$dtm = $dt / 3;
		$x0 *= Mpdf::SCALE;
		$y0 = ($this->h - $y0) * Mpdf::SCALE;
		$t1 = $astart;
		$a0 = $x0 + ($rx * cos($t1));
		$b0 = $y0 + ($ry * sin($t1));
		$c0 = -$rx * sin($t1);
		$d0 = $ry * cos($t1);
		$op = false;

		for ($i = 1; $i <= $nSeg; $i++) {
			// Draw this bit of the total curve
			$t1 = ($i * $dt) + $astart;
			$a1 = $x0 + ($rx * cos($t1));
			$b1 = $y0 + ($ry * sin($t1));
			$c1 = -$rx * sin($t1);
			$d1 = $ry * cos($t1);
			if ($i > ($nSeg - 4) && (!$part || ($part == 1 && $i <= $nSeg - 2) || ($part == 2 && $i > $nSeg - 2))) {
				if ($start && !$op) {
					$s .= sprintf('%.3F %.3F m ', $a0, $b0);
				}
				$s .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($a0 + ($c0 * $dtm)), ($b0 + ($d0 * $dtm)), ($a1 - ($c1 * $dtm)), ($b1 - ($d1 * $dtm)), $a1, $b1);
				$op = true;
			}
			$a0 = $a1;
			$b0 = $b1;
			$c0 = $c1;
			$d0 = $d1;
		}

		return $s;
	}

	/* -- END BORDER-RADIUS -- */

	function PaintDivLnBorder($state = 0, $blvl = 0, $h = 0)
	{
		// $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
		$this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y + $h;

		$save_y = $this->y;

		$w = $this->blk[$blvl]['width'];
		$x0 = $this->x;    // left
		$y0 = $this->y;    // top
		$x1 = $this->x + $w;   // bottom
		$y1 = $this->y + $h;   // bottom
		$continuingpage = (isset($this->blk[$blvl]['startpage']) && $this->blk[$blvl]['startpage'] != $this->page);

		if ($this->blk[$blvl]['border_top'] && ($state == 1 || $state == 3)) {
			$tbd = $this->blk[$blvl]['border_top'];
			if (isset($tbd['s']) && $tbd['s']) {
				$this->_setBorderLine($tbd);
				$this->y = $y0 + ($tbd['w'] / 2);
				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
					$this->_setDashBorder($tbd['style'], '', $continuingpage, 'T');
					$this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $this->y);
				} else {
					$this->SetLineJoin(0);
					$this->SetLineCap(0);
					$this->Line($x0, $this->y, $x0 + $w, $this->y);
				}
				$this->y += $tbd['w'];
				// Reset Corners and Dash off
				$this->SetLineJoin(2);
				$this->SetLineCap(2);
				$this->SetDash();
			}
		}
		if ($this->blk[$blvl]['border_left']) {
			$tbd = $this->blk[$blvl]['border_left'];
			if (isset($tbd['s']) && $tbd['s']) {
				$this->_setBorderLine($tbd);
				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
					$this->y = $y0 + ($tbd['w'] / 2);
					$this->_setDashBorder($tbd['style'], '', $continuingpage, 'L');
					$this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + ($tbd['w'] / 2), $y0 + $h - ($tbd['w'] / 2));
				} else {
					$this->y = $y0;
					$this->SetLineJoin(0);
					$this->SetLineCap(0);
					$this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + ($tbd['w'] / 2), $y0 + $h);
				}
				$this->y += $tbd['w'];
				// Reset Corners and Dash off
				$this->SetLineJoin(2);
				$this->SetLineCap(2);
				$this->SetDash();
			}
		}
		if ($this->blk[$blvl]['border_right']) {
			$tbd = $this->blk[$blvl]['border_right'];
			if (isset($tbd['s']) && $tbd['s']) {
				$this->_setBorderLine($tbd);
				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
					$this->y = $y0 + ($tbd['w'] / 2);
					$this->_setDashBorder($tbd['style'], '', $continuingpage, 'R');
					$this->Line($x0 + $w - ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $y0 + $h - ($tbd['w'] / 2));
				} else {
					$this->y = $y0;
					$this->SetLineJoin(0);
					$this->SetLineCap(0);
					$this->Line($x0 + $w - ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $y0 + $h);
				}
				$this->y += $tbd['w'];
				// Reset Corners and Dash off
				$this->SetLineJoin(2);
				$this->SetLineCap(2);
				$this->SetDash();
			}
		}
		if ($this->blk[$blvl]['border_bottom'] && $state > 1) {
			$tbd = $this->blk[$blvl]['border_bottom'];
			if (isset($tbd['s']) && $tbd['s']) {
				$this->_setBorderLine($tbd);
				$this->y = $y0 + $h - ($tbd['w'] / 2);
				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
					$this->_setDashBorder($tbd['style'], '', $continuingpage, 'B');
					$this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $this->y);
				} else {
					$this->SetLineJoin(0);
					$this->SetLineCap(0);
					$this->Line($x0, $this->y, $x0 + $w, $this->y);
				}
				$this->y += $tbd['w'];
				// Reset Corners and Dash off
				$this->SetLineJoin(2);
				$this->SetLineCap(2);
				$this->SetDash();
			}
		}
		$this->SetDash();
		$this->y = $save_y;
	}

	function PaintImgBorder($objattr, $is_table)
	{
		// Borders are disabled in columns - messes up the repositioning in printcolumnbuffer
		if ($this->ColActive) {
			return;
		} // *COLUMNS*
		if ($is_table) {
			$k = $this->shrin_k;
		} else {
			$k = 1;
		}
		$h = (isset($objattr['BORDER-HEIGHT']) ? $objattr['BORDER-HEIGHT'] : 0);
		$w = (isset($objattr['BORDER-WIDTH']) ? $objattr['BORDER-WIDTH'] : 0);
		$x0 = (isset($objattr['BORDER-X']) ? $objattr['BORDER-X'] : 0);
		$y0 = (isset($objattr['BORDER-Y']) ? $objattr['BORDER-Y'] : 0);

		// BORDERS
		if ($objattr['border_top']) {
			$tbd = $objattr['border_top'];
			if (!empty($tbd['s'])) {
				$this->_setBorderLine($tbd, $k);
				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
					$this->_setDashBorder($tbd['style'], '', '', 'T');
				}
				$this->Line($x0, $y0, $x0 + $w, $y0);
				// Reset Corners and Dash off
				$this->SetLineJoin(2);
				$this->SetLineCap(2);
				$this->SetDash();
			}
		}
		if ($objattr['border_left']) {
			$tbd = $objattr['border_left'];
			if (!empty($tbd['s'])) {
				$this->_setBorderLine($tbd, $k);
				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
					$this->_setDashBorder($tbd['style'], '', '', 'L');
				}
				$this->Line($x0, $y0, $x0, $y0 + $h);
				// Reset Corners and Dash off
				$this->SetLineJoin(2);
				$this->SetLineCap(2);
				$this->SetDash();
			}
		}
		if ($objattr['border_right']) {
			$tbd = $objattr['border_right'];
			if (!empty($tbd['s'])) {
				$this->_setBorderLine($tbd, $k);
				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
					$this->_setDashBorder($tbd['style'], '', '', 'R');
				}
				$this->Line($x0 + $w, $y0, $x0 + $w, $y0 + $h);
				// Reset Corners and Dash off
				$this->SetLineJoin(2);
				$this->SetLineCap(2);
				$this->SetDash();
			}
		}
		if ($objattr['border_bottom']) {
			$tbd = $objattr['border_bottom'];
			if (!empty($tbd['s'])) {
				$this->_setBorderLine($tbd, $k);
				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
					$this->_setDashBorder($tbd['style'], '', '', 'B');
				}
				$this->Line($x0, $y0 + $h, $x0 + $w, $y0 + $h);
				// Reset Corners and Dash off
				$this->SetLineJoin(2);
				$this->SetLineCap(2);
				$this->SetDash();
			}
		}
		$this->SetDash();
		$this->SetAlpha(1);
	}

	/* -- END HTML-CSS -- */

	function Reset()
	{
		$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
		$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
		$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
		$this->SetAlpha(1);
		$this->colorarray = '';

		$this->spanbgcolorarray = '';
		$this->spanbgcolor = false;
		$this->spanborder = false;
		$this->spanborddet = [];

		$this->ResetStyles();

		$this->HREF = '';
		$this->textparam = [];
		$this->SetTextOutline();

		$this->textvar = 0x00; // mPDF 5.7.1
		$this->OTLtags = [];
		$this->textshadow = '';

		$this->currentLang = $this->default_lang;  // mPDF 6
		$this->RestrictUnicodeFonts($this->default_available_fonts); // mPDF 6
		$this->SetFont($this->default_font, '', 0, false);
		$this->SetFontSize($this->default_font_size, false);

		$this->currentfontfamily = '';
		$this->currentfontsize = '';
		$this->currentfontstyle = '';

		if ($this->tableLevel && isset($this->table[1][1]['cellLineHeight'])) {
			$this->SetLineHeight('', $this->table[1][1]['cellLineHeight']);
		} else {
			if (isset($this->blk[$this->blklvl]['line_height']) && $this->blk[$this->blklvl]['line_height']) {
				$this->SetLineHeight('', $this->blk[$this->blklvl]['line_height']); // sets default line height
			}
		}

		$this->lSpacingCSS = '';
		$this->wSpacingCSS = '';
		$this->fixedlSpacing = false;
		$this->minwSpacing = 0;
		$this->SetDash(); // restore to no dash
		$this->dash_on = false;
		$this->dotted_on = false;
		$this->divwidth = 0;
		$this->divheight = 0;
		$this->cellTextAlign = '';
		$this->cellLineHeight = '';
		$this->cellLineStackingStrategy = '';
		$this->cellLineStackingShift = '';
		$this->oldy = -1;

		$bodystyle = [];

		if (isset($this->cssManager->CSS['BODY']['FONT-STYLE'])) {
			$bodystyle['FONT-STYLE'] = $this->cssManager->CSS['BODY']['FONT-STYLE'];
		}

		if (isset($this->cssManager->CSS['BODY']['FONT-WEIGHT'])) {
			$bodystyle['FONT-WEIGHT'] = $this->cssManager->CSS['BODY']['FONT-WEIGHT'];
		}

		if (isset($this->cssManager->CSS['BODY']['COLOR'])) {
			$bodystyle['COLOR'] = $this->cssManager->CSS['BODY']['COLOR'];
		}

		if (isset($bodystyle)) {
			$this->setCSS($bodystyle, 'BLOCK', 'BODY');
		}
	}

	/* -- HTML-CSS -- */

	function ReadMetaTags($html)
	{
		// changes anykey=anyvalue to anykey="anyvalue" (only do this when this happens inside tags)
		$regexp = '/ (\\w+?)=([^\\s>"]+)/si';
		$html = preg_replace($regexp, " \$1=\"\$2\"", $html);
		if (preg_match('/<title>(.*?)<\/title>/si', $html, $m)) {
			$this->SetTitle($m[1]);
		}
		preg_match_all('/<meta [^>]*?(name|content)="([^>]*?)" [^>]*?(name|content)="([^>]*?)".*?>/si', $html, $aux);
		$firstattr = $aux[1];
		$secondattr = $aux[3];
		for ($i = 0; $i < count($aux[0]); $i++) {
			$name = ( strtoupper($firstattr[$i]) == "NAME" ) ? strtoupper($aux[2][$i]) : strtoupper($aux[4][$i]);
			$content = ( strtoupper($firstattr[$i]) == "CONTENT" ) ? $aux[2][$i] : $aux[4][$i];
			switch ($name) {
				case "KEYWORDS":
					$this->SetKeywords($content);
					break;
				case "AUTHOR":
					$this->SetAuthor($content);
					break;
				case "DESCRIPTION":
					$this->SetSubject($content);
					break;
			}
		}
	}

	function ReadCharset($html)
	{
		// Charset conversion
		if ($this->allow_charset_conversion) {
			if (preg_match('/<head.*charset=([^\'\"\s]*).*<\/head>/si', $html, $m)) {
				if (strtoupper($m[1]) != 'UTF-8') {
					$this->charset_in = strtoupper($m[1]);
				}
			}
		}
	}

	function setCSS($arrayaux, $type = '', $tag = '')
	{
	// type= INLINE | BLOCK | TABLECELL // tag= BODY
		if (!is_array($arrayaux)) {
			return; // Removes PHP Warning
		}

		// mPDF 5.7.3  inline text-decoration parameters
		$preceeding_fontkey = $this->FontFamily . $this->FontStyle;
		$preceeding_fontsize = $this->FontSize;
		$spanbordset = false;
		$spanbgset = false;
		// mPDF 6
		$prevlevel = (($this->blklvl == 0) ? 0 : $this->blklvl - 1);

		// Set font size first so that e.g. MARGIN 0.83em works on font size for this element
		if (isset($arrayaux['FONT-SIZE'])) {
			$v = $arrayaux['FONT-SIZE'];
			$firstLetter = substr($v, 0, 1);
			if (is_numeric($firstLetter) || ($firstLetter === '.')) {
				if ($type == 'BLOCK' && $this->blklvl > 0 && isset($this->blk[$this->blklvl - 1]['InlineProperties']) && isset($this->blk[$this->blklvl - 1]['InlineProperties']['size'])) {
					$mmsize = $this->sizeConverter->convert($v, $this->blk[$this->blklvl - 1]['InlineProperties']['size']);
				} elseif ($type == 'TABLECELL') {
					$mmsize = $this->sizeConverter->convert($v, $this->default_font_size / Mpdf::SCALE);
				} else {
					$mmsize = $this->sizeConverter->convert($v, $this->FontSize);
				}
				$this->SetFontSize($mmsize * (Mpdf::SCALE), false); // Get size in points (pt)
			} else {
				$v = strtoupper($v);
				if (isset($this->fontsizes[$v])) {
					$this->SetFontSize($this->fontsizes[$v] * $this->default_font_size, false);
				}
			}
			if ($tag == 'BODY') {
				$this->SetDefaultFontSize($this->FontSizePt);
			}
		}

		// mPDF 6
		if (isset($arrayaux['LANG']) && $arrayaux['LANG']) {
			if ($this->autoLangToFont && !$this->usingCoreFont) {
				if ($arrayaux['LANG'] != $this->default_lang && $arrayaux['LANG'] != 'UTF-8') {
					list ($coreSuitable, $mpdf_pdf_unifont) = $this->languageToFont->getLanguageOptions($arrayaux['LANG'], $this->useAdobeCJK);
					if ($mpdf_pdf_unifont) {
						$arrayaux['FONT-FAMILY'] = $mpdf_pdf_unifont;
					}
					if ($tag == 'BODY') {
						$this->default_lang = $arrayaux['LANG'];
					}
				}
			}
			$this->currentLang = $arrayaux['LANG'];
		}

		// FOR INLINE and BLOCK OR 'BODY'
		if (isset($arrayaux['FONT-FAMILY'])) {
			$v = $arrayaux['FONT-FAMILY'];
			// If it is a font list, get all font types
			$aux_fontlist = explode(",", $v);
			$found = 0;
			foreach ($aux_fontlist as $f) {
				$fonttype = trim($f);
				$fonttype = preg_replace('/["\']*(.*?)["\']*/', '\\1', $fonttype);
				$fonttype = preg_replace('/ /', '', $fonttype);
				$v = strtolower(trim($fonttype));
				if (isset($this->fonttrans[$v]) && $this->fonttrans[$v]) {
					$v = $this->fonttrans[$v];
				}
				if ((!$this->onlyCoreFonts && in_array($v, $this->available_unifonts)) ||
					in_array($v, ['ccourier', 'ctimes', 'chelvetica']) ||
					($this->onlyCoreFonts && in_array($v, ['courier', 'times', 'helvetica', 'arial'])) ||
					in_array($v, ['sjis', 'uhc', 'big5', 'gb'])) {
					$fonttype = $v;
					$found = 1;
					break;
				}
			}
			if (!$found) {
				foreach ($aux_fontlist as $f) {
					$fonttype = trim($f);
					$fonttype = preg_replace('/["\']*(.*?)["\']*/', '\\1', $fonttype);
					$fonttype = preg_replace('/ /', '', $fonttype);
					$v = strtolower(trim($fonttype));
					if (isset($this->fonttrans[$v]) && $this->fonttrans[$v]) {
						$v = $this->fonttrans[$v];
					}
					if (in_array($v, $this->sans_fonts) || in_array($v, $this->serif_fonts) || in_array($v, $this->mono_fonts)) {
						$fonttype = $v;
						break;
					}
				}
			}

			if ($tag == 'BODY') {
				$this->SetDefaultFont($fonttype);
			}
			$this->SetFont($fonttype, $this->currentfontstyle, 0, false);
		} else {
			$this->SetFont($this->currentfontfamily, $this->currentfontstyle, 0, false);
		}

		foreach ($arrayaux as $k => $v) {
			if ($type != 'INLINE' && $tag != 'BODY' && $type != 'TABLECELL') {
				switch ($k) {
					// BORDERS
					case 'BORDER-TOP':
						$this->blk[$this->blklvl]['border_top'] = $this->border_details($v);
						if ($this->blk[$this->blklvl]['border_top']['s']) {
							$this->blk[$this->blklvl]['border'] = 1;
						}
						break;
					case 'BORDER-BOTTOM':
						$this->blk[$this->blklvl]['border_bottom'] = $this->border_details($v);
						if ($this->blk[$this->blklvl]['border_bottom']['s']) {
							$this->blk[$this->blklvl]['border'] = 1;
						}
						break;
					case 'BORDER-LEFT':
						$this->blk[$this->blklvl]['border_left'] = $this->border_details($v);
						if ($this->blk[$this->blklvl]['border_left']['s']) {
							$this->blk[$this->blklvl]['border'] = 1;
						}
						break;
					case 'BORDER-RIGHT':
						$this->blk[$this->blklvl]['border_right'] = $this->border_details($v);
						if ($this->blk[$this->blklvl]['border_right']['s']) {
							$this->blk[$this->blklvl]['border'] = 1;
						}
						break;

					// PADDING
					case 'PADDING-TOP':
						$this->blk[$this->blklvl]['padding_top'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;
					case 'PADDING-BOTTOM':
						$this->blk[$this->blklvl]['padding_bottom'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;
					case 'PADDING-LEFT':
						if (($tag == 'UL' || $tag == 'OL') && $v == 'auto') {
							$this->blk[$this->blklvl]['padding_left'] = 'auto';
							break;
						}
						$this->blk[$this->blklvl]['padding_left'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;
					case 'PADDING-RIGHT':
						if (($tag == 'UL' || $tag == 'OL') && $v == 'auto') {
							$this->blk[$this->blklvl]['padding_right'] = 'auto';
							break;
						}
						$this->blk[$this->blklvl]['padding_right'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;

					// MARGINS
					case 'MARGIN-TOP':
						$tmp = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						if (isset($this->blk[$this->blklvl]['lastbottommargin'])) {
							if ($tmp > $this->blk[$this->blklvl]['lastbottommargin']) {
								$tmp -= $this->blk[$this->blklvl]['lastbottommargin'];
							} else {
								$tmp = 0;
							}
						}
						$this->blk[$this->blklvl]['margin_top'] = $tmp;
						break;
					case 'MARGIN-BOTTOM':
						$this->blk[$this->blklvl]['margin_bottom'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;
					case 'MARGIN-LEFT':
						$this->blk[$this->blklvl]['margin_left'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;
					case 'MARGIN-RIGHT':
						$this->blk[$this->blklvl]['margin_right'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;

					/* -- BORDER-RADIUS -- */
					case 'BORDER-TOP-LEFT-RADIUS-H':
						$this->blk[$this->blklvl]['border_radius_TL_H'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;
					case 'BORDER-TOP-LEFT-RADIUS-V':
						$this->blk[$this->blklvl]['border_radius_TL_V'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;
					case 'BORDER-TOP-RIGHT-RADIUS-H':
						$this->blk[$this->blklvl]['border_radius_TR_H'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;
					case 'BORDER-TOP-RIGHT-RADIUS-V':
						$this->blk[$this->blklvl]['border_radius_TR_V'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;
					case 'BORDER-BOTTOM-LEFT-RADIUS-H':
						$this->blk[$this->blklvl]['border_radius_BL_H'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;
					case 'BORDER-BOTTOM-LEFT-RADIUS-V':
						$this->blk[$this->blklvl]['border_radius_BL_V'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;
					case 'BORDER-BOTTOM-RIGHT-RADIUS-H':
						$this->blk[$this->blklvl]['border_radius_BR_H'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;
					case 'BORDER-BOTTOM-RIGHT-RADIUS-V':
						$this->blk[$this->blklvl]['border_radius_BR_V'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						break;
					/* -- END BORDER-RADIUS -- */

					case 'BOX-SHADOW':
						$bs = $this->cssManager->setCSSboxshadow($v);
						if ($bs) {
							$this->blk[$this->blklvl]['box_shadow'] = $bs;
						}
						break;

					case 'BACKGROUND-CLIP':
						if (strtoupper($v) == 'PADDING-BOX') {
							$this->blk[$this->blklvl]['background_clip'] = 'padding-box';
						} elseif (strtoupper($v) == 'CONTENT-BOX') {
							$this->blk[$this->blklvl]['background_clip'] = 'content-box';
						}
						break;

					case 'PAGE-BREAK-AFTER':
						if (strtoupper($v) == 'AVOID') {
							$this->blk[$this->blklvl]['page_break_after_avoid'] = true;
						} elseif (strtoupper($v) == 'ALWAYS' || strtoupper($v) == 'LEFT' || strtoupper($v) == 'RIGHT') {
							$this->blk[$this->blklvl]['page_break_after'] = strtoupper($v);
						}
						break;

					// mPDF 6 pagebreaktype
					case 'BOX-DECORATION-BREAK':
						if (strtoupper($v) == 'CLONE') {
							$this->blk[$this->blklvl]['box_decoration_break'] = 'clone';
						} elseif (strtoupper($v) == 'SLICE') {
							$this->blk[$this->blklvl]['box_decoration_break'] = 'slice';
						}
						break;

					case 'WIDTH':
						if (strtoupper($v) != 'AUTO') {
							$this->blk[$this->blklvl]['css_set_width'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
						}
						break;

					// mPDF 6  Lists
					// LISTS
					case 'LIST-STYLE-TYPE':
						$this->blk[$this->blklvl]['list_style_type'] = strtolower($v);
						break;
					case 'LIST-STYLE-IMAGE':
						$this->blk[$this->blklvl]['list_style_image'] = strtolower($v);
						break;
					case 'LIST-STYLE-POSITION':
						$this->blk[$this->blklvl]['list_style_position'] = strtolower($v);
						break;
				}//end of switch($k)
			}


			if ($type != 'INLINE' && $type != 'TABLECELL') { // All block-level, including BODY tag
				switch ($k) {
					case 'TEXT-INDENT':
						// Computed value - to inherit
						$this->blk[$this->blklvl]['text_indent'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false) . 'mm';
						break;

					case 'MARGIN-COLLAPSE': // Custom tag to collapse margins at top and bottom of page
						if (strtoupper($v) == 'COLLAPSE') {
							$this->blk[$this->blklvl]['margin_collapse'] = true;
						}
						break;

					case 'LINE-HEIGHT':
						$this->blk[$this->blklvl]['line_height'] = $this->fixLineheight($v);
						if (!$this->blk[$this->blklvl]['line_height']) {
							$this->blk[$this->blklvl]['line_height'] = 'N';
						} // mPDF 6
						break;

					// mPDF 6
					case 'LINE-STACKING-STRATEGY':
						$this->blk[$this->blklvl]['line_stacking_strategy'] = strtolower($v);
						break;

					case 'LINE-STACKING-SHIFT':
						$this->blk[$this->blklvl]['line_stacking_shift'] = strtolower($v);
						break;

					case 'TEXT-ALIGN': // left right center justify
						switch (strtoupper($v)) {
							case 'LEFT':
								$this->blk[$this->blklvl]['align'] = "L";
								break;
							case 'CENTER':
								$this->blk[$this->blklvl]['align'] = "C";
								break;
							case 'RIGHT':
								$this->blk[$this->blklvl]['align'] = "R";
								break;
							case 'JUSTIFY':
								$this->blk[$this->blklvl]['align'] = "J";
								break;
						}
						break;

					/* -- BACKGROUNDS -- */
					case 'BACKGROUND-GRADIENT':
						if ($type == 'BLOCK') {
							$this->blk[$this->blklvl]['gradient'] = $v;
						}
						break;
					/* -- END BACKGROUNDS -- */

					case 'DIRECTION':
						if ($v) {
							$this->blk[$this->blklvl]['direction'] = strtolower($v);
						}
						break;
				}
			}

			// FOR INLINE ONLY
			if ($type == 'INLINE') {
				switch ($k) {
					case 'DISPLAY':
						if (strtoupper($v) == 'NONE') {
							$this->inlineDisplayOff = true;
						}
						break;
					case 'DIRECTION':
						break;
				}
			}
			// FOR INLINE ONLY
			if ($type == 'INLINE') {
				switch ($k) {
					// BORDERS
					case 'BORDER-TOP':
						$this->spanborddet['T'] = $this->border_details($v);
						$this->spanborder = true;
						$spanbordset = true;
						break;
					case 'BORDER-BOTTOM':
						$this->spanborddet['B'] = $this->border_details($v);
						$this->spanborder = true;
						$spanbordset = true;
						break;
					case 'BORDER-LEFT':
						$this->spanborddet['L'] = $this->border_details($v);
						$this->spanborder = true;
						$spanbordset = true;
						break;
					case 'BORDER-RIGHT':
						$this->spanborddet['R'] = $this->border_details($v);
						$this->spanborder = true;
						$spanbordset = true;
						break;
					case 'VISIBILITY': // block is set in OpenTag
						$v = strtolower($v);
						if ($v == 'visible' || $v == 'hidden' || $v == 'printonly' || $v == 'screenonly') {
							$this->textparam['visibility'] = $v;
						}
						break;
				}//end of switch($k)
			}

			if ($type != 'TABLECELL') {
				// FOR INLINE and BLOCK
				switch ($k) {
					case 'TEXT-ALIGN': // left right center justify
						if (strtoupper($v) == 'NOJUSTIFY' && $this->blk[$this->blklvl]['align'] == "J") {
							$this->blk[$this->blklvl]['align'] = "";
						}
						break;
					// bgcolor only - to stay consistent with original html2fpdf
					case 'BACKGROUND':
					case 'BACKGROUND-COLOR':
						$cor = $this->colorConverter->convert($v, $this->PDFAXwarnings);
						if ($cor) {
							if ($tag == 'BODY') {
								$this->bodyBackgroundColor = $cor;
							} elseif ($type == 'INLINE') {
								$this->spanbgcolorarray = $cor;
								$this->spanbgcolor = true;
								$spanbgset = true;
							} else {
								$this->blk[$this->blklvl]['bgcolorarray'] = $cor;
								$this->blk[$this->blklvl]['bgcolor'] = true;
							}
						} elseif ($type != 'INLINE') {
							if ($this->ColActive) {
								$this->blk[$this->blklvl]['bgcolorarray'] = $this->blk[$prevlevel]['bgcolorarray'];
								$this->blk[$this->blklvl]['bgcolor'] = $this->blk[$prevlevel]['bgcolor'];
							}
						}
						break;

					case 'VERTICAL-ALIGN': // super and sub only dealt with here e.g. <SUB> and <SUP>
						switch (strtoupper($v)) {
							case 'SUPER':
								$this->textvar = ($this->textvar | TextVars::FA_SUPERSCRIPT); // mPDF 5.7.1
								$this->textvar = ($this->textvar & ~TextVars::FA_SUBSCRIPT);
								// mPDF 5.7.3  inline text-decoration parameters
								if (isset($this->textparam['text-baseline'])) {
									$this->textparam['text-baseline'] += ($this->baselineSup) * $preceeding_fontsize;
								} else {
									$this->textparam['text-baseline'] = ($this->baselineSup) * $preceeding_fontsize;
								}
								break;
							case 'SUB':
								$this->textvar = ($this->textvar | TextVars::FA_SUBSCRIPT);
								$this->textvar = ($this->textvar & ~TextVars::FA_SUPERSCRIPT);
								// mPDF 5.7.3  inline text-decoration parameters
								if (isset($this->textparam['text-baseline'])) {
									$this->textparam['text-baseline'] += ($this->baselineSub) * $preceeding_fontsize;
								} else {
									$this->textparam['text-baseline'] = ($this->baselineSub) * $preceeding_fontsize;
								}
								break;
							case 'BASELINE':
								$this->textvar = ($this->textvar & ~TextVars::FA_SUBSCRIPT);
								$this->textvar = ($this->textvar & ~TextVars::FA_SUPERSCRIPT);
								// mPDF 5.7.3  inline text-decoration parameters
								if (isset($this->textparam['text-baseline'])) {
									unset($this->textparam['text-baseline']);
								}
								break;
							// mPDF 5.7.3  inline text-decoration parameters
							default:
								$lh = $this->_computeLineheight($this->blk[$this->blklvl]['line_height']);
								$sz = $this->sizeConverter->convert($v, $lh, $this->FontSize, false);
								$this->textvar = ($this->textvar & ~TextVars::FA_SUBSCRIPT);
								$this->textvar = ($this->textvar & ~TextVars::FA_SUPERSCRIPT);
								if ($sz) {
									if ($sz > 0) {
										$this->textvar = ($this->textvar | TextVars::FA_SUPERSCRIPT);
									} else {
										$this->textvar = ($this->textvar | TextVars::FA_SUBSCRIPT);
									}
									if (isset($this->textparam['text-baseline'])) {
										$this->textparam['text-baseline'] += $sz;
									} else {
										$this->textparam['text-baseline'] = $sz;
									}
								}
						}
						break;
				}//end of switch($k)
			}


			// FOR ALL
			switch ($k) {
				case 'LETTER-SPACING':
					$this->lSpacingCSS = $v;
					if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
						$this->fixedlSpacing = $this->sizeConverter->convert($this->lSpacingCSS, $this->FontSize);
					}
					break;

				case 'WORD-SPACING':
					$this->wSpacingCSS = $v;
					if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
						$this->minwSpacing = $this->sizeConverter->convert($this->wSpacingCSS, $this->FontSize);
					}
					break;

				case 'FONT-STYLE': // italic normal oblique
					switch (strtoupper($v)) {
						case 'ITALIC':
						case 'OBLIQUE':
							$this->SetStyle('I', true);
							break;
						case 'NORMAL':
							$this->SetStyle('I', false);
							break;
					}
					break;

				case 'FONT-WEIGHT': // normal bold // Does not support: bolder, lighter, 100..900(step value=100)
					switch (strtoupper($v)) {
						case 'BOLD':
							$this->SetStyle('B', true);
							break;
						case 'NORMAL':
							$this->SetStyle('B', false);
							break;
					}
					break;

				case 'FONT-KERNING':
					if (strtoupper($v) == 'NORMAL' || (strtoupper($v) == 'AUTO' && $this->useKerning)) {
						/* -- OTL -- */
						if ($this->CurrentFont['haskernGPOS']) {
							if (isset($this->OTLtags['Plus'])) {
								$this->OTLtags['Plus'] .= ' kern';
							} else {
								$this->OTLtags['Plus'] = ' kern';
							}
						} /* -- END OTL -- */ else {  // *OTL*
							$this->textvar = ($this->textvar | TextVars::FC_KERNING);
						} // *OTL*
					} elseif (strtoupper($v) == 'NONE' || (strtoupper($v) == 'AUTO' && !$this->useKerning)) {
						if (isset($this->OTLtags['Plus'])) {
							$this->OTLtags['Plus'] = str_replace('kern', '', $this->OTLtags['Plus']); // *OTL*
						}
						if (isset($this->OTLtags['FFPlus'])) {
							$this->OTLtags['FFPlus'] = preg_replace('/kern[\d]*/', '', $this->OTLtags['FFPlus']);
						}
						$this->textvar = ($this->textvar & ~TextVars::FC_KERNING);
					}
					break;

				/* -- OTL -- */
				case 'FONT-LANGUAGE-OVERRIDE':
					$v = strtoupper($v);
					if (strpos($v, 'NORMAL') !== false) {
						$this->fontLanguageOverride = '';
					} else {
						$this->fontLanguageOverride = trim($v);
					}
					break;


				case 'FONT-VARIANT-POSITION':
					if (isset($this->OTLtags['Plus'])) {
						$this->OTLtags['Plus'] = str_replace(['sups', 'subs'], '', $this->OTLtags['Plus']);
					}
					switch (strtoupper($v)) {
						case 'SUPER':
							$this->OTLtags['Plus'] .= ' sups';
							break;
						case 'SUB':
							$this->OTLtags['Plus'] .= ' subs';
							break;
						case 'NORMAL':
							break;
					}
					break;

				case 'FONT-VARIANT-CAPS':
					$v = strtoupper($v);
					if (!isset($this->OTLtags['Plus'])) {
						$this->OTLtags['Plus'] = '';
					}
					$this->OTLtags['Plus'] = str_replace(['c2sc', 'smcp', 'c2pc', 'pcap', 'unic', 'titl'], '', $this->OTLtags['Plus']);
					$this->textvar = ($this->textvar & ~TextVars::FC_SMALLCAPS);   // ?????????????? <small-caps>
					if (strpos($v, 'ALL-SMALL-CAPS') !== false) {
						$this->OTLtags['Plus'] .= ' c2sc smcp';
					} elseif (strpos($v, 'SMALL-CAPS') !== false) {
						if (isset($this->CurrentFont['hassmallcapsGSUB']) && $this->CurrentFont['hassmallcapsGSUB']) {
							$this->OTLtags['Plus'] .= ' smcp';
						} else {
							$this->textvar = ($this->textvar | TextVars::FC_SMALLCAPS);
						}
					} elseif (strpos($v, 'ALL-PETITE-CAPS') !== false) {
						$this->OTLtags['Plus'] .= ' c2pc pcap';
					} elseif (strpos($v, 'PETITE-CAPS') !== false) {
						$this->OTLtags['Plus'] .= ' pcap';
					} elseif (strpos($v, 'UNICASE') !== false) {
						$this->OTLtags['Plus'] .= ' unic';
					} elseif (strpos($v, 'TITLING-CAPS') !== false) {
						$this->OTLtags['Plus'] .= ' titl';
					}
					break;

				case 'FONT-VARIANT-LIGATURES':
					$v = strtoupper($v);
					if (!isset($this->OTLtags['Plus'])) {
						$this->OTLtags['Plus'] = '';
					}
					if (!isset($this->OTLtags['Minus'])) {
						$this->OTLtags['Minus'] = '';
					}
					if (strpos($v, 'NORMAL') !== false) {
						$this->OTLtags['Minus'] = str_replace(['liga', 'clig', 'calt'], '', $this->OTLtags['Minus']);
						$this->OTLtags['Plus'] = str_replace(['dlig', 'hlig'], '', $this->OTLtags['Plus']);
					} elseif (strpos($v, 'NONE') !== false) {
						$this->OTLtags['Minus'] .= ' liga clig calt';
						$this->OTLtags['Plus'] = str_replace(['dlig', 'hlig'], '', $this->OTLtags['Plus']);
					}
					if (strpos($v, 'NO-COMMON-LIGATURES') !== false) {
						$this->OTLtags['Minus'] .= ' liga clig';
					} elseif (strpos($v, 'COMMON-LIGATURES') !== false) {
						$this->OTLtags['Minus'] = str_replace(['liga', 'clig'], '', $this->OTLtags['Minus']);
					}
					if (strpos($v, 'NO-CONTEXTUAL') !== false) {
						$this->OTLtags['Minus'] .= ' calt';
					} elseif (strpos($v, 'CONTEXTUAL') !== false) {
						$this->OTLtags['Minus'] = str_replace('calt', '', $this->OTLtags['Minus']);
					}
					if (strpos($v, 'NO-DISCRETIONARY-LIGATURES') !== false) {
						$this->OTLtags['Plus'] = str_replace('dlig', '', $this->OTLtags['Plus']);
					} elseif (strpos($v, 'DISCRETIONARY-LIGATURES') !== false) {
						$this->OTLtags['Plus'] .= ' dlig';
					}
					if (strpos($v, 'NO-HISTORICAL-LIGATURES') !== false) {
						$this->OTLtags['Plus'] = str_replace('hlig', '', $this->OTLtags['Plus']);
					} elseif (strpos($v, 'HISTORICAL-LIGATURES') !== false) {
						$this->OTLtags['Plus'] .= ' hlig';
					}

					break;

				case 'FONT-VARIANT-NUMERIC':
					$v = strtoupper($v);
					if (!isset($this->OTLtags['Plus'])) {
						$this->OTLtags['Plus'] = '';
					}
					if (strpos($v, 'NORMAL') !== false) {
						$this->OTLtags['Plus'] = str_replace(['ordn', 'zero', 'lnum', 'onum', 'pnum', 'tnum', 'frac', 'afrc'], '', $this->OTLtags['Plus']);
					}
					if (strpos($v, 'ORDINAL') !== false) {
						$this->OTLtags['Plus'] .= ' ordn';
					}
					if (strpos($v, 'SLASHED-ZERO') !== false) {
						$this->OTLtags['Plus'] .= ' zero';
					}
					if (strpos($v, 'LINING-NUMS') !== false) {
						$this->OTLtags['Plus'] .= ' lnum';
						$this->OTLtags['Plus'] = str_replace('onum', '', $this->OTLtags['Plus']);
					} elseif (strpos($v, 'OLDSTYLE-NUMS') !== false) {
						$this->OTLtags['Plus'] .= ' onum';
						$this->OTLtags['Plus'] = str_replace('lnum', '', $this->OTLtags['Plus']);
					}
					if (strpos($v, 'PROPORTIONAL-NUMS') !== false) {
						$this->OTLtags['Plus'] .= ' pnum';
						$this->OTLtags['Plus'] = str_replace('tnum', '', $this->OTLtags['Plus']);
					} elseif (strpos($v, 'TABULAR-NUMS') !== false) {
						$this->OTLtags['Plus'] .= ' tnum';
						$this->OTLtags['Plus'] = str_replace('pnum', '', $this->OTLtags['Plus']);
					}
					if (strpos($v, 'DIAGONAL-FRACTIONS') !== false) {
						$this->OTLtags['Plus'] .= ' frac';
						$this->OTLtags['Plus'] = str_replace('afrc', '', $this->OTLtags['Plus']);
					} elseif (strpos($v, 'STACKED-FRACTIONS') !== false) {
						$this->OTLtags['Plus'] .= ' afrc';
						$this->OTLtags['Plus'] = str_replace('frac', '', $this->OTLtags['Plus']);
					}
					break;

				case 'FONT-VARIANT-ALTERNATES':  // Only supports historical-forms
					$v = strtoupper($v);
					if (!isset($this->OTLtags['Plus'])) {
						$this->OTLtags['Plus'] = '';
					}
					if (strpos($v, 'NORMAL') !== false) {
						$this->OTLtags['Plus'] = str_replace('hist', '', $this->OTLtags['Plus']);
					}
					if (strpos($v, 'HISTORICAL-FORMS') !== false) {
						$this->OTLtags['Plus'] .= ' hist';
					}
					break;


				case 'FONT-FEATURE-SETTINGS':
					$v = strtolower($v);
					if (strpos($v, 'normal') !== false) {
						$this->OTLtags['FFMinus'] = '';
						$this->OTLtags['FFPlus'] = '';
					} else {
						if (!isset($this->OTLtags['FFPlus'])) {
							$this->OTLtags['FFPlus'] = '';
						}
						if (!isset($this->OTLtags['FFMinus'])) {
							$this->OTLtags['FFMinus'] = '';
						}
						$tags = preg_split('/[,]/', $v);
						foreach ($tags as $t) {
							if (preg_match('/[\"\']([a-zA-Z0-9]{4})[\"\']\s*(on|off|\d*){0,1}/', $t, $m)) {
								if ($m[2] == 'off' || $m[2] === '0') {
									if (strpos($this->OTLtags['FFMinus'], $m[1]) === false) {
										$this->OTLtags['FFMinus'] .= ' ' . $m[1];
									}
									$this->OTLtags['FFPlus'] = preg_replace('/' . $m[1] . '[\d]*/', '', $this->OTLtags['FFPlus']);
								} else {
									if ($m[2] == 'on') {
										$m[2] = '1';
									}
									if (strpos($this->OTLtags['FFPlus'], $m[1]) === false) {
										$this->OTLtags['FFPlus'] .= ' ' . $m[1] . $m[2];
									}
									$this->OTLtags['FFMinus'] = str_replace($m[1], '', $this->OTLtags['FFMinus']);
								}
							}
						}
					}
					break;
				/* -- END OTL -- */


				case 'TEXT-TRANSFORM': // none uppercase lowercase // Does support: capitalize
					switch (strtoupper($v)) { // Not working 100%
						case 'CAPITALIZE':
							$this->textvar = ($this->textvar | TextVars::FT_CAPITALIZE); // mPDF 5.7.1
							$this->textvar = ($this->textvar & ~TextVars::FT_UPPERCASE); // mPDF 5.7.1
							$this->textvar = ($this->textvar & ~TextVars::FT_LOWERCASE); // mPDF 5.7.1
							break;
						case 'UPPERCASE':
							$this->textvar = ($this->textvar | TextVars::FT_UPPERCASE); // mPDF 5.7.1
							$this->textvar = ($this->textvar & ~TextVars::FT_LOWERCASE); // mPDF 5.7.1
							$this->textvar = ($this->textvar & ~TextVars::FT_CAPITALIZE); // mPDF 5.7.1
							break;
						case 'LOWERCASE':
							$this->textvar = ($this->textvar | TextVars::FT_LOWERCASE); // mPDF 5.7.1
							$this->textvar = ($this->textvar & ~TextVars::FT_UPPERCASE); // mPDF 5.7.1
							$this->textvar = ($this->textvar & ~TextVars::FT_CAPITALIZE); // mPDF 5.7.1
							break;
						case 'NONE':
							break;
							$this->textvar = ($this->textvar & ~TextVars::FT_UPPERCASE); // mPDF 5.7.1
							$this->textvar = ($this->textvar & ~TextVars::FT_LOWERCASE); // mPDF 5.7.1
							$this->textvar = ($this->textvar & ~TextVars::FT_CAPITALIZE); // mPDF 5.7.1
					}
					break;

				case 'TEXT-SHADOW':
					$ts = $this->cssManager->setCSStextshadow($v);
					if ($ts) {
						$this->textshadow = $ts;
					}
					break;

				case 'HYPHENS':
					if (strtoupper($v) == 'NONE') {
						$this->textparam['hyphens'] = 2;
					} elseif (strtoupper($v) == 'AUTO') {
						$this->textparam['hyphens'] = 1;
					} elseif (strtoupper($v) == 'MANUAL') {
						$this->textparam['hyphens'] = 0;
					}
					break;

				case 'TEXT-OUTLINE':
					if (strtoupper($v) == 'NONE') {
						$this->textparam['outline-s'] = false;
					}
					break;

				case 'TEXT-OUTLINE-WIDTH':
				case 'OUTLINE-WIDTH':
					switch (strtoupper($v)) {
						case 'THIN':
							$v = '0.03em';
							break;
						case 'MEDIUM':
							$v = '0.05em';
							break;
						case 'THICK':
							$v = '0.07em';
							break;
					}
					$w = $this->sizeConverter->convert($v, $this->FontSize, $this->FontSize);
					if ($w) {
						$this->textparam['outline-WIDTH'] = $w;
						$this->textparam['outline-s'] = true;
					} else {
						$this->textparam['outline-s'] = false;
					}
					break;

				case 'TEXT-OUTLINE-COLOR':
				case 'OUTLINE-COLOR':
					if (strtoupper($v) == 'INVERT') {
						if ($this->colorarray) {
							$cor = $this->colorarray;
							$this->textparam['outline-COLOR'] = $this->colorConverter->invert($cor);
						} else {
							$this->textparam['outline-COLOR'] = $this->colorConverter->convert(255, $this->PDFAXwarnings);
						}
					} else {
						$cor = $this->colorConverter->convert($v, $this->PDFAXwarnings);
						if ($cor) {
							$this->textparam['outline-COLOR'] = $cor;
						}
					}
					break;

				case 'COLOR': // font color
					$cor = $this->colorConverter->convert($v, $this->PDFAXwarnings);
					if ($cor) {
						$this->colorarray = $cor;
						$this->SetTColor($cor);
					}
					break;
			}//end of switch($k)
		}//end of foreach
		// mPDF 5.7.3  inline text-decoration parameters
		// Needs to be set at the end - after vertical-align = super/sub, so that textparam['text-baseline'] is set
		if (isset($arrayaux['TEXT-DECORATION'])) {
			$v = $arrayaux['TEXT-DECORATION']; // none underline line-through (strikeout) // Does not support: blink
			if (stristr($v, 'LINE-THROUGH')) {
				$this->textvar = ($this->textvar | TextVars::FD_LINETHROUGH);
				// mPDF 5.7.3  inline text-decoration parameters
				if (isset($this->textparam['text-baseline'])) {
					$this->textparam['s-decoration']['baseline'] = $this->textparam['text-baseline'];
				} else {
					$this->textparam['s-decoration']['baseline'] = 0;
				}
				$this->textparam['s-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
				$this->textparam['s-decoration']['fontsize'] = $this->FontSize;
				$this->textparam['s-decoration']['color'] = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
			}
			if (stristr($v, 'UNDERLINE')) {
				$this->textvar = ($this->textvar | TextVars::FD_UNDERLINE);
				// mPDF 5.7.3  inline text-decoration parameters
				if (isset($this->textparam['text-baseline'])) {
					$this->textparam['u-decoration']['baseline'] = $this->textparam['text-baseline'];
				} else {
					$this->textparam['u-decoration']['baseline'] = 0;
				}
				$this->textparam['u-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
				$this->textparam['u-decoration']['fontsize'] = $this->FontSize;
				$this->textparam['u-decoration']['color'] = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
			}
			if (stristr($v, 'OVERLINE')) {
				$this->textvar = ($this->textvar | TextVars::FD_OVERLINE);
				// mPDF 5.7.3  inline text-decoration parameters
				if (isset($this->textparam['text-baseline'])) {
					$this->textparam['o-decoration']['baseline'] = $this->textparam['text-baseline'];
				} else {
					$this->textparam['o-decoration']['baseline'] = 0;
				}
				$this->textparam['o-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
				$this->textparam['o-decoration']['fontsize'] = $this->FontSize;
				$this->textparam['o-decoration']['color'] = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
			}
			if (stristr($v, 'NONE')) {
				$this->textvar = ($this->textvar & ~TextVars::FD_UNDERLINE);
				$this->textvar = ($this->textvar & ~TextVars::FD_LINETHROUGH);
				$this->textvar = ($this->textvar & ~TextVars::FD_OVERLINE);
				// mPDF 5.7.3  inline text-decoration parameters
				if (isset($this->textparam['u-decoration'])) {
					unset($this->textparam['u-decoration']);
				}
				if (isset($this->textparam['s-decoration'])) {
					unset($this->textparam['s-decoration']);
				}
				if (isset($this->textparam['o-decoration'])) {
					unset($this->textparam['o-decoration']);
				}
			}
		}
		// mPDF 6
		if ($spanbordset) { // BORDER has been set on this INLINE element
			if (isset($this->textparam['text-baseline'])) {
				$this->textparam['bord-decoration']['baseline'] = $this->textparam['text-baseline'];
			} else {
				$this->textparam['bord-decoration']['baseline'] = 0;
			}
			$this->textparam['bord-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
			$this->textparam['bord-decoration']['fontsize'] = $this->FontSize;
		}
		if ($spanbgset) { // BACKGROUND[-COLOR] has been set on this INLINE element
			if (isset($this->textparam['text-baseline'])) {
				$this->textparam['bg-decoration']['baseline'] = $this->textparam['text-baseline'];
			} else {
				$this->textparam['bg-decoration']['baseline'] = 0;
			}
			$this->textparam['bg-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
			$this->textparam['bg-decoration']['fontsize'] = $this->FontSize;
		}
	}

	/* -- END HTML-CSS -- */

	function SetStyle($tag, $enable)
	{
		$this->$tag = $enable;
		$style = '';
		foreach (['B', 'I'] as $s) {
			if ($this->$s) {
				$style .= $s;
			}
		}
		$this->currentfontstyle = $style;
		$this->SetFont('', $style, 0, false);
	}

	// Set multiple styles at one time
	function SetStylesArray($arr)
	{
		$style = '';
		foreach (['B', 'I'] as $s) {
			if (isset($arr[$s])) {
				if ($arr[$s]) {
					$this->$s = true;
					$style .= $s;
				} else {
					$this->$s = false;
				}
			} elseif ($this->$s) {
				$style .= $s;
			}
		}
		$this->currentfontstyle = $style;
		$this->SetFont('', $style, 0, false);
	}

	// Set multiple styles at one $str e.g. "BI"
	function SetStyles($str)
	{
		$style = '';
		foreach (['B', 'I'] as $s) {
			if (strpos($str, $s) !== false) {
				$this->$s = true;
				$style .= $s;
			} else {
				$this->$s = false;
			}
		}
		$this->currentfontstyle = $style;
		$this->SetFont('', $style, 0, false);
	}

	function ResetStyles()
	{
		foreach (['B', 'I'] as $s) {
			$this->$s = false;
		}
		$this->currentfontstyle = '';
		$this->SetFont('', '', 0, false);
	}

	function DisableTags($str = '')
	{
		if ($str == '') { // enable all tags
			// Insert new supported tags in the long string below.
			$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>";
		} else {
			$str = explode(",", $str);
			foreach ($str as $v) {
				$this->enabledtags = str_replace(trim($v), '', $this->enabledtags);
			}
		}
	}

	/* -- TABLES -- */

	function TableCheckMinWidth($maxwidth, $forcewrap = 0, $textbuffer = [], $checkletter = false)
	{
	// mPDF 6
		$acclength = 0; // mPDF 6 (accumulated length across > 1 chunk)
		$acclongest = 0; // mPDF 6 (accumulated length max across > 1 chunk)
		$biggestword = 0;
		$toonarrow = false;
		if ((count($textbuffer) == 0) or ( (count($textbuffer) == 1) && ($textbuffer[0][0] == ''))) {
			return 0;
		}

		foreach ($textbuffer as $chunk) {
			$line = $chunk[0];
			$OTLdata = (isset($chunk[18]) ? $chunk[18] : null);

			// mPDF ITERATION
			if ($this->iterationCounter) {
				$line = preg_replace('/{iteration ([a-zA-Z0-9_]+)}/', '\\1', $line);
			}

			// IMAGES & FORM ELEMENTS
			if (substr($line, 0, 3) == "\xbb\xa4\xac") { // inline object - FORM element or IMAGE!
				$objattr = $this->_getObjAttr($line);
				if ($objattr['type'] != 'hr' && isset($objattr['width']) && ($objattr['width'] / $this->shrin_k) > ($maxwidth + 0.0001)) {
					if (($objattr['width'] / $this->shrin_k) > $biggestword) {
						$biggestword = ($objattr['width'] / $this->shrin_k);
					}
					$toonarrow = true;
				}
				continue;
			}

			if ($line == "\n") {
				$acclength = 0; // mPDF 6 (accumulated length across > 1 chunk)
				continue;
			}
			$line = trim($line);
			if (!empty($OTLdata)) {
				$this->otl->trimOTLdata($OTLdata, true, true);
			} // *OTL*
			// SET FONT SIZE/STYLE from $chunk[n]
			// FONTSIZE
			if (isset($chunk[11]) and $chunk[11] != '') {
				if ($this->shrin_k) {
					$this->SetFontSize($chunk[11] / $this->shrin_k, false);
				} else {
					$this->SetFontSize($chunk[11], false);
				}
			}
			// FONTFAMILY
			if (isset($chunk[4]) and $chunk[4] != '') {
				$font = $this->SetFont($chunk[4], $this->FontStyle, 0, false);
			}
			// B I
			if (isset($chunk[2]) and $chunk[2] != '') {
				$this->SetStyles($chunk[2]);
			}

			$lbw = $rbw = 0; // Border widths
			if (isset($chunk[16]) && !empty($chunk[16])) { // Border
				$this->spanborddet = $chunk[16];
				$lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
				$rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
			}
			if (isset($chunk[15])) {   // Word spacing
				$this->wSpacingCSS = $chunk[15];
				if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
					$this->minwSpacing = $this->sizeConverter->convert($this->wSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
				}
			}
			if (isset($chunk[14])) {   // Letter spacing
				$this->lSpacingCSS = $chunk[14];
				if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
					$this->fixedlSpacing = $this->sizeConverter->convert($this->lSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
				}
			}
			if (isset($chunk[8])) { // mPDF 5.7.1
				$this->textvar = $chunk[8];
			}

			// mPDF 6
			// If overflow==wrap ($checkletter) OR (No word breaks and contains CJK)
			if ($checkletter || (!preg_match('/(\xe2\x80\x8b| )/', trim($line)) && preg_match("/([" . $this->pregCJKchars . "])/u", $line) )) {
				if (preg_match("/([" . $this->pregCJKchars . "])/u", $line)) {
					$checkCJK = true;
				} else {
					$checkCJK = false;
				}

				$letters = preg_split('//u', $line);
				foreach ($letters as $k => $letter) {
					// mPDF 6
					if ($checkCJK) {
						if (preg_match("/[" . $this->CJKleading . "]/u", $letter) && $k > 0) {
							$letter = $letters[$k - 1] . $letter;
						}
						if (preg_match("/[" . $this->CJKfollowing . "]/u", $letter) && $k < (count($letters) - 1)) {
							$letter = $letter . $letters[$k + 1];
						}
					}

					$letterwidth = $this->GetStringWidth($letter, false, false, $chunk[8]); // Pass $textvar ($chunk[8]), but do OTLdata here
					// so don't have to split OTLdata for each word
					if ($k == 0) {
						$letterwidth += $lbw;
					}
					if ($k == (count($letters) - 1)) {
						$letterwidth += $rbw;
					}

					// Warn user that maxwidth is insufficient
					if ($letterwidth > $maxwidth + 0.0001) {
						if ($letterwidth > $biggestword) {
							$biggestword = $letterwidth;
						}
						$toonarrow = true;
					}
				}
			} else {
				// mPDF 6
				// Need to account for any XAdvance in GPOSinfo (OTLdata = $chunk[18])
				$wordXAdvance = [];
				if (isset($chunk[18]) && $chunk[18]) {
					preg_match_all('/(\xe2\x80\x8b| )/', $line, $spaces, PREG_OFFSET_CAPTURE); // U+200B Zero Width word boundary, or space
					$lastoffset = 0;
					$k = -1; // Added so that if no spaces found, "last word" later is calculated for the one and only word
					foreach ($spaces[0] as $k => $m) {
						$offset = $m[1];
						// ...TableCheckMinWidth...
						// At this point, BIDI not applied, Writing direction is not set, and XAdvanceL balances XAdvanceR
						for ($n = $lastoffset; $n < $offset; $n++) {
							if (isset($chunk[18]['GPOSinfo'][$n]['XAdvanceL'])) {
								if (isset($wordXAdvance[$k])) {
									$wordXAdvance[$k] += $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
								} else {
									$wordXAdvance[$k] = $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
								}
							}
						}
						$lastoffset = $offset + 1;
					}

					$k++;  // last word
					foreach ($chunk[18]['GPOSinfo'] as $n => $gpos) {
						if ($n >= $lastoffset && isset($chunk[18]['GPOSinfo'][$n]['XAdvanceL'])) {
							if (isset($wordXAdvance[$k])) {
								$wordXAdvance[$k] += $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
							} else {
								$wordXAdvance[$k] = $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
							}
						}
					}
				}

				$words = preg_split('/(\xe2\x80\x8b| )/', $line); // U+200B Zero Width word boundary, or space
				foreach ($words as $k => $word) {
					$word = trim($word);
					$wordwidth = $this->GetStringWidth($word, false, false, $chunk[8]); // Pass $textvar ($chunk[8]), but do OTLdata here
					// so don't have to split OTLdata for each word
					if (isset($wordXAdvance[$k])) {
						$wordwidth += ($wordXAdvance[$k] * 1000 / $this->CurrentFont['unitsPerEm']) * ($this->FontSize / 1000);
					}
					if ($k == 0) {
						$wordwidth += $lbw;
					}
					if ($k == (count($words) - 1)) {
						$wordwidth += $rbw;
					}

					// mPDF 6
					if (count($words) == 1 && substr($chunk[0], 0, 1) != ' ') {
						$acclength += $wordwidth;
					} elseif (count($words) > 1 && $k == 0 && substr($chunk[0], 0, 1) != ' ') {
						$acclength += $wordwidth;
					} else {
						$acclength = $wordwidth;
					}
					$acclongest = max($acclongest, $acclength);
					if (count($words) == 1 && substr($chunk[0], -1, 1) == ' ') {
						$acclength = 0;
					} elseif (count($words) > 1 && ($k != (count($words) - 1) || substr($chunk[0], -1, 1) == ' ')) {
						$acclength = 0;
					}

					// Warn user that maxwidth is insufficient
					if ($wordwidth > $maxwidth + 0.0001) {
						if ($wordwidth > $biggestword) {
							$biggestword = $wordwidth;
						}
						$toonarrow = true;
					}
				}
			}

			// mPDF 6  Accumulated length of biggest word - across multiple chunks
			if ($acclongest > $maxwidth + 0.0001) {
				if ($acclongest > $biggestword) {
					$biggestword = $acclongest;
				}
				$toonarrow = true;
			}

			// RESET FONT SIZE/STYLE
			// RESETTING VALUES
			// Now we must deactivate what we have used
			if (isset($chunk[2]) and $chunk[2] != '') {
				$this->ResetStyles();
			}
			if (isset($chunk[4]) and $chunk[4] != '') {
				$this->SetFont($this->default_font, $this->FontStyle, 0, false);
			}
			if (isset($chunk[11]) and $chunk[11] != '') {
				$this->SetFontSize($this->default_font_size, false);
			}
			$this->spanborddet = [];
			$this->textvar = 0x00; // mPDF 5.7.1
			$this->OTLtags = [];
			$this->lSpacingCSS = '';
			$this->wSpacingCSS = '';
			$this->fixedlSpacing = false;
			$this->minwSpacing = 0;
		}

		// Return -(wordsize) if word is bigger than maxwidth
		// ADDED
		if (($toonarrow) && ($this->table_error_report)) {
			throw new \Mpdf\MpdfException("Word is too long to fit in table - " . $this->table_error_report_param);
		}
		if ($toonarrow) {
			return -$biggestword;
		} else {
			return 1;
		}
	}

	function shrinkTable(&$table, $k)
	{
		$table['border_spacing_H'] /= $k;
		$table['border_spacing_V'] /= $k;

		$table['padding']['T'] /= $k;
		$table['padding']['R'] /= $k;
		$table['padding']['B'] /= $k;
		$table['padding']['L'] /= $k;

		$table['margin']['T'] /= $k;
		$table['margin']['R'] /= $k;
		$table['margin']['B'] /= $k;
		$table['margin']['L'] /= $k;

		$table['border_details']['T']['w'] /= $k;
		$table['border_details']['R']['w'] /= $k;
		$table['border_details']['B']['w'] /= $k;
		$table['border_details']['L']['w'] /= $k;

		if (isset($table['max_cell_border_width']['T'])) {
			$table['max_cell_border_width']['T'] /= $k;
		}
		if (isset($table['max_cell_border_width']['R'])) {
			$table['max_cell_border_width']['R'] /= $k;
		}
		if (isset($table['max_cell_border_width']['B'])) {
			$table['max_cell_border_width']['B'] /= $k;
		}
		if (isset($table['max_cell_border_width']['L'])) {
			$table['max_cell_border_width']['L'] /= $k;
		}

		if ($this->simpleTables) {
			$table['simple']['border_details']['T']['w'] /= $k;
			$table['simple']['border_details']['R']['w'] /= $k;
			$table['simple']['border_details']['B']['w'] /= $k;
			$table['simple']['border_details']['L']['w'] /= $k;
		}

		$table['miw'] /= $k;
		$table['maw'] /= $k;

		for ($j = 0; $j < $table['nc']; $j++) { // columns

			$table['wc'][$j]['miw'] = isset($table['wc'][$j]['miw']) ? $table['wc'][$j]['miw'] : 0;
			$table['wc'][$j]['maw'] = isset($table['wc'][$j]['maw']) ? $table['wc'][$j]['maw'] : 0;

			$table['wc'][$j]['miw'] /= $k;
			$table['wc'][$j]['maw'] /= $k;

			if (isset($table['decimal_align'][$j]['maxs0']) && $table['decimal_align'][$j]['maxs0']) {
				$table['decimal_align'][$j]['maxs0'] /= $k;
			}

			if (isset($table['decimal_align'][$j]['maxs1']) && $table['decimal_align'][$j]['maxs1']) {
				$table['decimal_align'][$j]['maxs1'] /= $k;
			}

			if (isset($table['wc'][$j]['absmiw']) && $table['wc'][$j]['absmiw']) {
				$table['wc'][$j]['absmiw'] /= $k;
			}

			for ($i = 0; $i < $table['nr']; $i++) { // rows

				$c = &$table['cells'][$i][$j];

				if (isset($c) && $c) {

					if (!$this->simpleTables) {

						if ($this->packTableData) {

							$cell = $this->_unpackCellBorder($c['borderbin']);

							$cell['border_details']['T']['w'] /= $k;
							$cell['border_details']['R']['w'] /= $k;
							$cell['border_details']['B']['w'] /= $k;
							$cell['border_details']['L']['w'] /= $k;
							$cell['border_details']['mbw']['TL'] /= $k;
							$cell['border_details']['mbw']['TR'] /= $k;
							$cell['border_details']['mbw']['BL'] /= $k;
							$cell['border_details']['mbw']['BR'] /= $k;
							$cell['border_details']['mbw']['LT'] /= $k;
							$cell['border_details']['mbw']['LB'] /= $k;
							$cell['border_details']['mbw']['RT'] /= $k;
							$cell['border_details']['mbw']['RB'] /= $k;

							$c['borderbin'] = $this->_packCellBorder($cell);

						} else {

							$c['border_details']['T']['w'] /= $k;
							$c['border_details']['R']['w'] /= $k;
							$c['border_details']['B']['w'] /= $k;
							$c['border_details']['L']['w'] /= $k;
							$c['border_details']['mbw']['TL'] /= $k;
							$c['border_details']['mbw']['TR'] /= $k;
							$c['border_details']['mbw']['BL'] /= $k;
							$c['border_details']['mbw']['BR'] /= $k;
							$c['border_details']['mbw']['LT'] /= $k;
							$c['border_details']['mbw']['LB'] /= $k;
							$c['border_details']['mbw']['RT'] /= $k;
							$c['border_details']['mbw']['RB'] /= $k;
						}
					}

					$c['padding']['T'] /= $k;
					$c['padding']['R'] /= $k;
					$c['padding']['B'] /= $k;
					$c['padding']['L'] /= $k;

					$c['maxs'] = isset($c['maxs']) ? $c['maxs'] /= $k : null;
					$c['w'] = isset($c['w']) ? $c['w'] /= $k : null;

					$c['s'] = isset($c['s']) ? $c['s'] /= $k : 0;
					$c['h'] = isset($c['h']) ? $c['h'] /= $k : null;

					$c['miw'] = isset($c['miw']) ? $c['miw'] /= $k : 0;
					$c['maw'] = isset($c['maw']) ? $c['maw'] /= $k : 0;

					$c['absmiw'] = isset($c['absmiw']) ? $c['absmiw'] /= $k : null;

					$c['nestedmaw'] = isset($c['nestedmaw']) ? $c['nestedmaw'] /= $k : null;
					$c['nestedmiw'] = isset($c['nestedmiw']) ? $c['nestedmiw'] /= $k : null;

					if (isset($c['textbuffer'])) {
						foreach ($c['textbuffer'] as $n => $tb) {
							if (!empty($tb[16])) {
								!isset($c['textbuffer'][$n][16]['T']) || $c['textbuffer'][$n][16]['T']['w'] /= $k;
								!isset($c['textbuffer'][$n][16]['B']) || $c['textbuffer'][$n][16]['B']['w'] /= $k;
								!isset($c['textbuffer'][$n][16]['L']) || $c['textbuffer'][$n][16]['L']['w'] /= $k;
								!isset($c['textbuffer'][$n][16]['R']) || $c['textbuffer'][$n][16]['R']['w'] /= $k;
							}
						}
					}

					unset($c);
				}

			} // rows
		} // columns
	}

	function read_short(&$fh)
	{
		$s = fread($fh, 2);
		$a = (ord($s[0]) << 8) + ord($s[1]);
		if ($a & (1 << 15)) {
			$a = ($a - (1 << 16));
		}
		return $a;
	}

	function _packCellBorder($cell)
	{
		if (!is_array($cell) || !isset($cell)) {
			return '';
		}

		if (!$this->packTableData) {
			return $cell;
		}
		// = 186 bytes
		$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));
		return $bindata;
	}

	function _getBorderWidths($bindata)
	{
		if (!$bindata) {
			return [0, 0, 0, 0];
		}
		if (!$this->packTableData) {
			return [$bindata['border_details']['T']['w'], $bindata['border_details']['R']['w'], $bindata['border_details']['B']['w'], $bindata['border_details']['L']['w']];
		}

		$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);
		$cell['border_details']['R']['w'] = $bd['rw'];
		$cell['border_details']['L']['w'] = $bd['lw'];
		$cell['border_details']['T']['w'] = $bd['tw'];
		$cell['border_details']['B']['w'] = $bd['bw'];
		return [$bd['tw'], $bd['rw'], $bd['bw'], $bd['lw']];
	}

	function _unpackCellBorder($bindata)
	{
		if (!$bindata) {
			return [];
		}
		if (!$this->packTableData) {
			return $bindata;
		}

		$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);

		$cell['border'] = $bd['bord'];
		$cell['border_details']['R']['s'] = $bd['rs'];
		$cell['border_details']['R']['w'] = $bd['rw'];
		$cell['border_details']['R']['c'] = str_pad($bd['rca'], 6, "\x00");
		$cell['border_details']['R']['style'] = trim($bd['rst']);
		$cell['border_details']['R']['dom'] = $bd['rd'];

		$cell['border_details']['L']['s'] = $bd['ls'];
		$cell['border_details']['L']['w'] = $bd['lw'];
		$cell['border_details']['L']['c'] = str_pad($bd['lca'], 6, "\x00");
		$cell['border_details']['L']['style'] = trim($bd['lst']);
		$cell['border_details']['L']['dom'] = $bd['ld'];

		$cell['border_details']['T']['s'] = $bd['ts'];
		$cell['border_details']['T']['w'] = $bd['tw'];
		$cell['border_details']['T']['c'] = str_pad($bd['tca'], 6, "\x00");
		$cell['border_details']['T']['style'] = trim($bd['tst']);
		$cell['border_details']['T']['dom'] = $bd['td'];

		$cell['border_details']['B']['s'] = $bd['bs'];
		$cell['border_details']['B']['w'] = $bd['bw'];
		$cell['border_details']['B']['c'] = str_pad($bd['bca'], 6, "\x00");
		$cell['border_details']['B']['style'] = trim($bd['bst']);
		$cell['border_details']['B']['dom'] = $bd['bd'];

		$cell['border_details']['mbw']['BL'] = $bd['mbl'];
		$cell['border_details']['mbw']['BR'] = $bd['mbr'];
		$cell['border_details']['mbw']['RT'] = $bd['mrt'];
		$cell['border_details']['mbw']['RB'] = $bd['mrb'];
		$cell['border_details']['mbw']['TL'] = $bd['mtl'];
		$cell['border_details']['mbw']['TR'] = $bd['mtr'];
		$cell['border_details']['mbw']['LT'] = $bd['mlt'];
		$cell['border_details']['mbw']['LB'] = $bd['mlb'];
		$cell['border_details']['cellposdom'] = $bd['cpd'];


		return($cell);
	}

	////////////////////////TABLE CODE (from PDFTable)/////////////////////////////////////
	////////////////////////TABLE CODE (from PDFTable)/////////////////////////////////////
	////////////////////////TABLE CODE (from PDFTable)/////////////////////////////////////
	// table		Array of (w, h, bc, nr, wc, hr, cells)
	// w			Width of table
	// h			Height of table
	// nc			Number column
	// nr			Number row
	// hr			List of height of each row
	// wc			List of width of each column
	// cells		List of cells of each rows, cells[i][j] is a cell in the table
	function _tableColumnWidth(&$table, $firstpass = false)
	{
		$cs = &$table['cells'];

		$nc = $table['nc'];
		$nr = $table['nr'];
		$listspan = [];

		if ($table['borders_separate']) {
			$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'];
		} else {
			$tblbw = $table['max_cell_border_width']['L'] / 2 + $table['max_cell_border_width']['R'] / 2 + $table['margin']['L'] + $table['margin']['R'];
		}

		// ADDED table['l'][colno]
		// = total length of text approx (using $c['s']) in that column - used to approximately distribute col widths in _tableWidth
		//
		for ($j = 0; $j < $nc; $j++) { // columns
			$wc = &$table['wc'][$j];
			for ($i = 0; $i < $nr; $i++) { // rows
				if (isset($cs[$i][$j]) && $cs[$i][$j]) {
					$c = &$cs[$i][$j];

					if ($this->simpleTables) {
						if ($table['borders_separate']) { // NB twice border width
							$extrcw = $table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w'] + $c['padding']['L'] + $c['padding']['R'] + $table['border_spacing_H'];
						} else {
							$extrcw = $table['simple']['border_details']['L']['w'] / 2 + $table['simple']['border_details']['R']['w'] / 2 + $c['padding']['L'] + $c['padding']['R'];
						}
					} else {
						if ($this->packTableData) {
							list($bt, $br, $bb, $bl) = $this->_getBorderWidths($c['borderbin']);
						} else {
							$br = $c['border_details']['R']['w'];
							$bl = $c['border_details']['L']['w'];
						}
						if ($table['borders_separate']) { // NB twice border width
							$extrcw = $bl + $br + $c['padding']['L'] + $c['padding']['R'] + $table['border_spacing_H'];
						} else {
							$extrcw = $bl / 2 + $br / 2 + $c['padding']['L'] + $c['padding']['R'];
						}
					}

					// $mw = $this->GetStringWidth('W') + $extrcw ;
					$mw = $extrcw; // mPDF 6
					if (substr($c['a'], 0, 1) == 'D') {
						$mw = $table['decimal_align'][$j]['maxs0'] + $table['decimal_align'][$j]['maxs1'] + $extrcw;
					}

					$c['absmiw'] = $mw;

					if (isset($c['R']) && $c['R']) {
						$c['maw'] = $c['miw'] = $this->FontSize + $extrcw;
						if (isset($c['w'])) { // If cell width is specified
							if ($c['miw'] < $c['w']) {
								$c['miw'] = $c['w'];
							}
						}
						if (!isset($c['colspan'])) {
							if ($wc['miw'] < $c['miw']) {
								$wc['miw'] = $c['miw'];
							}
							if ($wc['maw'] < $c['maw']) {
								$wc['maw'] = $c['maw'];
							}

							if ($firstpass) {
								if (isset($table['l'][$j])) {
									$table['l'][$j] += $c['miw'];
								} else {
									$table['l'][$j] = $c['miw'];
								}
							}
						}
						if ($c['miw'] > $wc['miw']) {
							$wc['miw'] = $c['miw'];
						}
						if ($wc['miw'] > $wc['maw']) {
							$wc['maw'] = $wc['miw'];
						}
						continue;
					}

					if ($firstpass) {
						if (isset($c['s'])) {
							$c['s'] += $extrcw;
						}
						if (isset($c['maxs'])) {
							$c['maxs'] += $extrcw;
						}
						if (isset($c['nestedmiw'])) {
							$c['nestedmiw'] += $extrcw;
						}
						if (isset($c['nestedmaw'])) {
							$c['nestedmaw'] += $extrcw;
						}
					}


					// If minimum width has already been set by a nested table or inline object (image/form), use it
					if (isset($c['nestedmiw']) && (!isset($this->table[1][1]['overflow']) || $this->table[1][1]['overflow'] != 'visible')) {
						$miw = $c['nestedmiw'];
					} else {
						$miw = $mw;
					}

					if (isset($c['maxs']) && $c['maxs'] != '') {
						$c['s'] = $c['maxs'];
					}

					// If maximum width has already been set by a nested table, use it
					if (isset($c['nestedmaw'])) {
						$c['maw'] = $c['nestedmaw'];
					} else {
						$c['maw'] = $c['s'];
					}

					if (isset($table['overflow']) && $table['overflow'] == 'visible' && $table['level'] == 1) {
						if (($c['maw'] + $tblbw) > $this->blk[$this->blklvl]['inner_width']) {
							$c['maw'] = $this->blk[$this->blklvl]['inner_width'] - $tblbw;
						}
					}

					if (isset($c['nowrap']) && $c['nowrap']) {
						$miw = $c['maw'];
					}

					if (isset($c['wpercent']) && $firstpass) {
						if (isset($c['colspan'])) { // Not perfect - but % set on colspan is shared equally on cols.
							for ($k = 0; $k < $c['colspan']; $k++) {
								$table['wc'][($j + $k)]['wpercent'] = $c['wpercent'] / $c['colspan'];
							}
						} else {
							if (isset($table['w']) && $table['w']) {
								$c['w'] = $c['wpercent'] / 100 * ($table['w'] - $tblbw );
							}
							$wc['wpercent'] = $c['wpercent'];
						}
					}

					if (isset($table['overflow']) && $table['overflow'] == 'visible' && $table['level'] == 1) {
						if (isset($c['w']) && ($c['w'] + $tblbw) > $this->blk[$this->blklvl]['inner_width']) {
							$c['w'] = $this->blk[$this->blklvl]['inner_width'] - $tblbw;
						}
					}


					if (isset($c['w'])) { // If cell width is specified
						if ($miw < $c['w']) {
							$c['miw'] = $c['w'];
						} // Cell min width = that specified
						if ($miw > $c['w']) {
							$c['miw'] = $c['w'] = $miw;
						} // If width specified is less than minimum allowed (W) increase it
						// mPDF 5.7.4  Do not set column width in colspan
						// cf. http://www.mpdf1.com/forum/discussion/2221/colspan-bug
						if (!isset($c['colspan'])) {
							if (!isset($wc['w'])) {
								$wc['w'] = 1;
							}  // If the Col width is not specified = set it to 1
						}
						// mPDF 5.7.3  cf. http://www.mpdf1.com/forum/discussion/1648/nested-table-bug-
						$c['maw'] = $c['w'];
					} else {
						$c['miw'] = $miw;
					} // If cell width not specified -> set Cell min width it to minimum allowed (W)

					if (isset($c['miw']) && $c['maw'] < $c['miw']) {
						$c['maw'] = $c['miw'];
					} // If Cell max width < Minwidth - increase it to =
					if (!isset($c['colspan'])) {
						if (isset($c['miw']) && $wc['miw'] < $c['miw']) {
							$wc['miw'] = $c['miw'];
						} // Update Col Minimum and maximum widths
						if ($wc['maw'] < $c['maw']) {
							$wc['maw'] = $c['maw'];
						}
						if ((isset($wc['absmiw']) && $wc['absmiw'] < $c['absmiw']) || !isset($wc['absmiw'])) {
							$wc['absmiw'] = $c['absmiw'];
						} // Update Col Minimum and maximum widths

						if (isset($table['l'][$j])) {
							$table['l'][$j] += $c['s'];
						} else {
							$table['l'][$j] = $c['s'];
						}
					} else {
						$listspan[] = [$i, $j];
					}

					// Check if minimum width of the whole column is big enough for largest word to fit
					// mPDF 6
					if (isset($c['textbuffer'])) {
						if (isset($table['overflow']) && $table['overflow'] == 'wrap') {
							$letter = true;
						} // check for maximum width of letters
						else {
							$letter = false;
						}
						$minwidth = $this->TableCheckMinWidth($wc['miw'] - $extrcw, 0, $c['textbuffer'], $letter);
					} else {
						$minwidth = 0;
					}
					if ($minwidth < 0) {
						// increase minimum width
						if (!isset($c['colspan'])) {
							$wc['miw'] = max((isset($wc['miw']) ? $wc['miw'] : 0), ((-$minwidth) + $extrcw));
						} else {
							$c['miw'] = max((isset($c['miw']) ? $c['miw'] : 0), ((-$minwidth) + $extrcw));
						}
					}
					if (!isset($c['colspan'])) {
						if ($wc['miw'] > $wc['maw']) {
							$wc['maw'] = $wc['miw'];
						} // update maximum width, if needed
					}
				}
				unset($c);
			}//rows
		}//columns
		// COLUMN SPANS
		$wc = &$table['wc'];
		foreach ($listspan as $span) {
			list($i, $j) = $span;
			$c = &$cs[$i][$j];
			$lc = $j + $c['colspan'];
			if ($lc > $nc) {
				$lc = $nc;
			}
			$wis = $wisa = 0;
			$was = $wasa = 0;
			$list = [];
			for ($k = $j; $k < $lc; $k++) {
				if (isset($table['l'][$k])) {
					if ($c['R']) {
						$table['l'][$k] += $c['miw'] / $c['colspan'];
					} else {
						$table['l'][$k] += $c['s'] / $c['colspan'];
					}
				} else {
					if ($c['R']) {
						$table['l'][$k] = $c['miw'] / $c['colspan'];
					} else {
						$table['l'][$k] = $c['s'] / $c['colspan'];
					}
				}
				$wis += $wc[$k]['miw'];   // $wis is the sum of the column miw in the colspan
				$was += $wc[$k]['maw'];   // $was is the sum of the column maw in the colspan
				if (!isset($c['w'])) {
					$list[] = $k;
					$wisa += $wc[$k]['miw']; // $wisa is the sum of the column miw in cells with no width specified in the colspan
					$wasa += $wc[$k]['maw']; // $wasa is the sum of the column maw in cells with no width specified in the colspan
				}
			}
			if ($c['miw'] > $wis) {
				if (!$wis) {
					for ($k = $j; $k < $lc; $k++) {
						$wc[$k]['miw'] = $c['miw'] / $c['colspan'];
					}
				} elseif (!count($list) && $wis != 0) {
					$wi = $c['miw'] - $wis;
					for ($k = $j; $k < $lc; $k++) {
						$wc[$k]['miw'] += ($wc[$k]['miw'] / $wis) * $wi;
					}
				} else {
					$wi = $c['miw'] - $wis;
					// mPDF 5.7.2   Extra min width distributed proportionately to all cells in colspan without a specified width
					// cf. http://www.mpdf1.com/forum/discussion/1607#Item_4
					foreach ($list as $k) {
						if (!isset($wc[$k]['w']) || !$wc[$k]['w']) {
							$wc[$k]['miw'] += ($wc[$k]['miw'] / $wisa) * $wi;
						}
					} // mPDF 5.7.2
				}
			}
			if ($c['maw'] > $was) {
				if (!$wis) {
					for ($k = $j; $k < $lc; $k++) {
						$wc[$k]['maw'] = $c['maw'] / $c['colspan'];
					}
				} elseif (!count($list) && $was != 0) {
					$wi = $c['maw'] - $was;
					for ($k = $j; $k < $lc; $k++) {
						$wc[$k]['maw'] += ($wc[$k]['maw'] / $was) * $wi;
					}
				} else {
					$wi = $c['maw'] - $was;
					// mPDF 5.7.4  Extra max width distributed evenly to all cells in colspan without a specified width
					// cf. http://www.mpdf1.com/forum/discussion/2221/colspan-bug
					foreach ($list as $k) {
						$wc[$k]['maw'] += $wi / count($list);
					}
				}
			}
			unset($c);
		}

		$checkminwidth = 0;
		$checkmaxwidth = 0;
		$totallength = 0;

		for ($i = 0; $i < $nc; $i++) {
			$checkminwidth += $table['wc'][$i]['miw'];
			$checkmaxwidth += $table['wc'][$i]['maw'];
			$totallength += isset($table['l']) ? $table['l'][$i] : 0;
		}

		if (!isset($table['w']) && $firstpass) {
			$sumpc = 0;
			$notset = 0;
			for ($i = 0; $i < $nc; $i++) {
				if (isset($table['wc'][$i]['wpercent']) && $table['wc'][$i]['wpercent']) {
					$sumpc += $table['wc'][$i]['wpercent'];
				} else {
					$notset++;
				}
			}

			// If sum of widths as %  >= 100% and not all columns are set
			// Set a nominal width of 1% for unset columns
			if ($sumpc >= 100 && $notset) {
				for ($i = 0; $i < $nc; $i++) {
					if ((!isset($table['wc'][$i]['wpercent']) || !$table['wc'][$i]['wpercent']) &&
						(!isset($table['wc'][$i]['w']) || !$table['wc'][$i]['w'])) {
						$table['wc'][$i]['wpercent'] = 1;
					}
				}
			}


			if ($sumpc) { // if any percents are set
				$sumnonpc = (100 - $sumpc);
				$sumpc = max($sumpc, 100);
				$miwleft = 0;
				$miwleftcount = 0;
				$miwsurplusnonpc = 0;
				$maxcalcmiw = 0;
				$mawleft = 0;
				$mawleftcount = 0;
				$mawsurplusnonpc = 0;
				$maxcalcmaw = 0;
				$mawnon = 0;
				$miwnon = 0;
				for ($i = 0; $i < $nc; $i++) {
					if (isset($table['wc'][$i]['wpercent'])) {
						$maxcalcmiw = max($maxcalcmiw, ($table['wc'][$i]['miw'] * $sumpc / $table['wc'][$i]['wpercent']));
						$maxcalcmaw = max($maxcalcmaw, ($table['wc'][$i]['maw'] * $sumpc / $table['wc'][$i]['wpercent']));
					} else {
						$miwleft += $table['wc'][$i]['miw'];
						$mawleft += $table['wc'][$i]['maw'];
						if (!isset($table['wc'][$i]['w'])) {
							$miwleftcount++;
							$mawleftcount++;
						}
					}
				}
				if ($miwleft && $sumnonpc > 0) {
					$miwnon = $miwleft * 100 / $sumnonpc;
				}
				if ($mawleft && $sumnonpc > 0) {
					$mawnon = $mawleft * 100 / $sumnonpc;
				}
				if (($miwnon > $checkminwidth || $maxcalcmiw > $checkminwidth) && $this->keep_table_proportions) {
					if ($miwnon > $maxcalcmiw) {
						$miwsurplusnonpc = round((($miwnon * $sumnonpc / 100) - $miwleft), 3);
						$checkminwidth = $miwnon;
					} else {
						$checkminwidth = $maxcalcmiw;
					}
					for ($i = 0; $i < $nc; $i++) {
						if (isset($table['wc'][$i]['wpercent'])) {
							$newmiw = $checkminwidth * $table['wc'][$i]['wpercent'] / 100;
							if ($table['wc'][$i]['miw'] < $newmiw) {
								$table['wc'][$i]['miw'] = $newmiw;
							}
							$table['wc'][$i]['w'] = 1;
						} elseif ($miwsurplusnonpc && !$table['wc'][$i]['w']) {
							$table['wc'][$i]['miw'] += $miwsurplusnonpc / $miwleftcount;
						}
					}
				}
				if (($mawnon > $checkmaxwidth || $maxcalcmaw > $checkmaxwidth)) {
					if ($mawnon > $maxcalcmaw) {
						$mawsurplusnonpc = round((($mawnon * $sumnonpc / 100) - $mawleft), 3);
						$checkmaxwidth = $mawnon;
					} else {
						$checkmaxwidth = $maxcalcmaw;
					}
					for ($i = 0; $i < $nc; $i++) {
						if (isset($table['wc'][$i]['wpercent'])) {
							$newmaw = $checkmaxwidth * $table['wc'][$i]['wpercent'] / 100;
							if ($table['wc'][$i]['maw'] < $newmaw) {
								$table['wc'][$i]['maw'] = $newmaw;
							}
							$table['wc'][$i]['w'] = 1;
						} elseif ($mawsurplusnonpc && !$table['wc'][$i]['w']) {
							$table['wc'][$i]['maw'] += $mawsurplusnonpc / $mawleftcount;
						}
						if ($table['wc'][$i]['maw'] < $table['wc'][$i]['miw']) {
							$table['wc'][$i]['maw'] = $table['wc'][$i]['miw'];
						}
					}
				}
				if ($checkminwidth > $checkmaxwidth) {
					$checkmaxwidth = $checkminwidth;
				}
			}
		}

		if (isset($table['wpercent']) && $table['wpercent']) {
			$checkminwidth *= (100 / $table['wpercent']);
			$checkmaxwidth *= (100 / $table['wpercent']);
		}


		$checkminwidth += $tblbw;
		$checkmaxwidth += $tblbw;

		// Table['miw'] set by percent in first pass may be larger than sum of column miw
		if ((isset($table['miw']) && $checkminwidth > $table['miw']) || !isset($table['miw'])) {
			$table['miw'] = $checkminwidth;
		}
		if ((isset($table['maw']) && $checkmaxwidth > $table['maw']) || !isset($table['maw'])) {
			$table['maw'] = $checkmaxwidth;
		}
		$table['tl'] = $totallength;

		// mPDF 6
		if ($this->table_rotate) {
			$mxw = $this->tbrot_maxw;
		} else {
			$mxw = $this->blk[$this->blklvl]['inner_width'];
		}

		if (!isset($table['overflow'])) {
			$table['overflow'] = null;
		}

		if ($table['overflow'] == 'visible') {
			return [0, 0];
		} elseif ($table['overflow'] == 'hidden' && !$this->table_rotate && !$this->ColActive && $checkminwidth > $mxw) {
			$table['w'] = $table['miw'];
			return [0, 0];
		}
		// elseif ($table['overflow']=='wrap') { return array(0,0); }	// mPDF 6

		if (isset($table['w']) && $table['w']) {

			if ($table['w'] >= $checkminwidth && $table['w'] <= $mxw) {
				$table['maw'] = $mxw = $table['w'];
			} elseif ($table['w'] >= $checkminwidth && $table['w'] > $mxw && $this->keep_table_proportions) {
				$checkminwidth = $table['w'];
			} elseif ($table['w'] < $checkminwidth && $checkminwidth < $mxw && $this->keep_table_proportions) {
				$table['maw'] = $table['w'] = $checkminwidth;
			} else {
				unset($table['w']);
			}
		}

		$ratio = $checkminwidth / $mxw;

		if ($checkminwidth > $mxw) {
			return [($ratio + 0.001), $checkminwidth]; // 0.001 to allow for rounded numbers when resizing
		}

		unset($cs);

		return [0, 0];
	}

	function _tableWidth(&$table)
	{
		$widthcols = &$table['wc'];
		$numcols = $table['nc'];
		$tablewidth = 0;

		if ($table['borders_separate']) {
			$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'];
		} else {
			$tblbw = $table['max_cell_border_width']['L'] / 2 + $table['max_cell_border_width']['R'] / 2 + $table['margin']['L'] + $table['margin']['R'];
		}

		if ($table['level'] > 1 && isset($table['w'])) {

			if (isset($table['wpercent']) && $table['wpercent']) {
				$table['w'] = $temppgwidth = (($table['w'] - $tblbw) * $table['wpercent'] / 100) + $tblbw;
			} else {
				$temppgwidth = $table['w'];
			}

		} elseif ($this->table_rotate) {

			$temppgwidth = $this->tbrot_maxw;

			// 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
			$enddiv = $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'];

			if ($enddiv / $temppgwidth < 0.05) {
				$temppgwidth -= $enddiv;
			}

		} else {

			if (isset($table['w']) && $table['w'] < $this->blk[$this->blklvl]['inner_width']) {
				$notfullwidth = 1;
				$temppgwidth = $table['w'];
			} elseif ($table['overflow'] == 'visible' && $table['level'] == 1) {
				$temppgwidth = null;
			} elseif ($table['overflow'] == 'hidden' && !$this->ColActive && isset($table['w']) && $table['w'] > $this->blk[$this->blklvl]['inner_width'] && $table['w'] == $table) {
				// $temppgwidth = $this->blk[$this->blklvl]['inner_width'];
				$temppgwidth = $table['w'];
			} else {
				$temppgwidth = $this->blk[$this->blklvl]['inner_width'];
			}

		}

		$totaltextlength = 0; // Added - to sum $table['l'][colno]
		$totalatextlength = 0; // Added - to sum $table['l'][colno] for those columns where width not set
		$percentages_set = 0;

		for ($i = 0; $i < $numcols; $i++) {
			if (isset($widthcols[$i]['wpercent'])) {
				$tablewidth += $widthcols[$i]['maw'];
				$percentages_set = 1;
			} elseif (isset($widthcols[$i]['w'])) {
				$tablewidth += $widthcols[$i]['miw'];
			} else {
				$tablewidth += $widthcols[$i]['maw'];
			}
			$totaltextlength += isset($table['l']) ? $table['l'][$i] : 0;
		}

		if (!$totaltextlength) {
			$totaltextlength = 1;
		}

		$tablewidth += $tblbw; // Outer half of table borders

		if ($tablewidth > $temppgwidth) {
			$table['w'] = $temppgwidth;
		} elseif ($tablewidth < $temppgwidth && !isset($table['w']) && $percentages_set) { // if any widths set as percentages and max width fits < page width
			$table['w'] = $table['maw'];
		}

		// if table width is set and is > allowed width
		if (isset($table['w']) && $table['w'] > $temppgwidth) {
			$table['w'] = $temppgwidth;
		}

		// IF the table width is now set - Need to distribute columns widths
		// mPDF 5.7.3
		// If the table width is already set to the maximum width (e.g. nested table), then use maximum column widths exactly
		if (isset($table['w']) && ($table['w'] == $tablewidth) && !$percentages_set) {

			// This sets the columns all to maximum width
			for ($i = 0; $i < $numcols; $i++) {
				$widthcols[$i] = $widthcols[$i]['maw'];
			}

		} elseif (isset($table['w'])) { // elseif the table width is set distribute width using algorithm

			$wis = $wisa = 0;
			$list = [];
			$notsetlist = [];

			for ($i = 0; $i < $numcols; $i++) {
				$wis += $widthcols[$i]['miw'];
				if (!isset($widthcols[$i]['w']) || ($widthcols[$i]['w'] && $table['w'] > $temppgwidth && !$this->keep_table_proportions && !$notfullwidth )) {
					$list[] = $i;
					$wisa += $widthcols[$i]['miw'];
					$totalatextlength += $table['l'][$i];
				}
			}

			if (!$totalatextlength) {
				$totalatextlength = 1;
			}

			// Allocate spare (more than col's minimum width) across the cols according to their approx total text length
			// Do it by setting minimum width here
			if ($table['w'] > $wis + $tblbw) {

				// First set any cell widths set as percentages
				if ($table['w'] < $temppgwidth || $this->keep_table_proportions) {
					for ($k = 0; $k < $numcols; $k++) {
						if (isset($widthcols[$k]['wpercent'])) {
							$curr = $widthcols[$k]['miw'];
							$widthcols[$k]['miw'] = ($table['w'] - $tblbw) * $widthcols[$k]['wpercent'] / 100;
							$wis += $widthcols[$k]['miw'] - $curr;
							$wisa += $widthcols[$k]['miw'] - $curr;
						}
					}
				}

				// Now allocate surplus up to maximum width of each column
				$surplus = 0;
				$ttl = 0; // number of surplus columns

				if (!count($list)) {

					$wi = ($table['w'] - ($wis + $tblbw)); // i.e. extra space to distribute

					for ($k = 0; $k < $numcols; $k++) {

						$spareratio = ($table['l'][$k] / $totaltextlength); //  gives ratio to divide up free space

						// Don't allocate more than Maximum required width - save rest in surplus
						if ($widthcols[$k]['miw'] + ($wi * $spareratio) >= $widthcols[$k]['maw']) { // mPDF 5.7.3
							$surplus += ($wi * $spareratio) - ($widthcols[$k]['maw'] - $widthcols[$k]['miw']);
							$widthcols[$k]['miw'] = $widthcols[$k]['maw'];
						} else {
							$notsetlist[] = $k;
							$ttl += $table['l'][$k];
							$widthcols[$k]['miw'] += ($wi * $spareratio);
						}
					}

				} else {

					$wi = ($table['w'] - ($wis + $tblbw)); // i.e. extra space to distribute

					foreach ($list as $k) {

						$spareratio = ($table['l'][$k] / $totalatextlength); //  gives ratio to divide up free space

						// Don't allocate more than Maximum required width - save rest in surplus
						if ($widthcols[$k]['miw'] + ($wi * $spareratio) >= $widthcols[$k]['maw']) { // mPDF 5.7.3
							$surplus += ($wi * $spareratio) - ($widthcols[$k]['maw'] - $widthcols[$k]['miw']);
							$widthcols[$k]['miw'] = $widthcols[$k]['maw'];
						} else {
							$notsetlist[] = $k;
							$ttl += $table['l'][$k];
							$widthcols[$k]['miw'] += ($wi * $spareratio);
						}
					}
				}

				// If surplus still left over apportion it across columns
				if ($surplus) {

					if (count($notsetlist) && count($notsetlist) < $numcols) { // if some are set only add to remaining - otherwise add to all of them
						foreach ($notsetlist as $i) {
							if ($ttl) {
								$widthcols[$i]['miw'] += $surplus * $table['l'][$i] / $ttl;
							}
						}
					} elseif (count($list) && count($list) < $numcols) { // If some widths are defined, and others have been added up to their maxmum
						foreach ($list as $i) {
							$widthcols[$i]['miw'] += $surplus / count($list);
						}
					} elseif ($numcols) { // If all columns
						$ttl = array_sum($table['l']);
						if ($ttl) {
							for ($i = 0; $i < $numcols; $i++) {
								$widthcols[$i]['miw'] += $surplus * $table['l'][$i] / $ttl;
							}
						}
					}
				}
			}

			// This sets the columns all to minimum width (which has been increased above if appropriate)
			for ($i = 0; $i < $numcols; $i++) {
				$widthcols[$i] = $widthcols[$i]['miw'];
			}

			// TABLE NOT WIDE ENOUGH EVEN FOR MINIMUM CONTENT WIDTH
			// If sum of column widths set are too wide for table
			$checktablewidth = 0;
			for ($i = 0; $i < $numcols; $i++) {
				$checktablewidth += $widthcols[$i];
			}

			if ($checktablewidth > ($temppgwidth + 0.001 - $tblbw)) {

				$usedup = 0;
				$numleft = 0;

				for ($i = 0; $i < $numcols; $i++) {
					if ((isset($widthcols[$i]) && $widthcols[$i] > (($temppgwidth - $tblbw) / $numcols)) && (!isset($widthcols[$i]['w']))) {
						$numleft++;
						unset($widthcols[$i]);
					} else {
						$usedup += $widthcols[$i];
					}
				}

				for ($i = 0; $i < $numcols; $i++) {
					if (!isset($widthcols[$i]) || !$widthcols[$i]) {
						$widthcols[$i] = ((($temppgwidth - $tblbw) - $usedup) / ($numleft));
					}
				}
			}

		} else { // table has no width defined

			$table['w'] = $tablewidth;

			for ($i = 0; $i < $numcols; $i++) {

				if (isset($widthcols[$i]['wpercent']) && $this->keep_table_proportions) {
					$colwidth = $widthcols[$i]['maw'];
				} elseif (isset($widthcols[$i]['w'])) {
					$colwidth = $widthcols[$i]['miw'];
				} else {
					$colwidth = $widthcols[$i]['maw'];
				}

				unset($widthcols[$i]);
				$widthcols[$i] = $colwidth;

			}
		}

		if ($table['overflow'] === 'visible' && $table['level'] == 1) {

			if ($tablewidth > $this->blk[$this->blklvl]['inner_width']) {

				for ($j = 0; $j < $numcols; $j++) { // columns

					for ($i = 0; $i < $table['nr']; $i++) { // rows

						if (isset($table['cells'][$i][$j]) && $table['cells'][$i][$j]) {

							$colspan = (isset($table['cells'][$i][$j]['colspan']) ? $table['cells'][$i][$j]['colspan'] : 1);

							if ($colspan > 1) {
								$w = 0;

								for ($c = $j; $c < ($j + $colspan); $c++) {
									$w += $widthcols[$c];
								}

								if ($w > $this->blk[$this->blklvl]['inner_width']) {
									$diff = $w - ($this->blk[$this->blklvl]['inner_width'] - $tblbw);
									for ($c = $j; $c < ($j + $colspan); $c++) {
										$widthcols[$c] -= $diff * ($widthcols[$c] / $w);
									}
									$table['w'] -= $diff;
									$table['csp'][$j] = $w - $diff;
								}
							}
						}
					}
				}
			}

			$pgNo = 0;
			$currWc = 0;

			for ($i = 0; $i < $numcols; $i++) { // columns

				if (isset($table['csp'][$i])) {
					$w = $table['csp'][$i];
					unset($table['csp'][$i]);
				} else {
					$w = $widthcols[$i];
				}

				if (($currWc + $w + $tblbw) > $this->blk[$this->blklvl]['inner_width']) {
					$pgNo++;
					$currWc = $widthcols[$i];
				} else {
					$currWc += $widthcols[$i];
				}

				$table['colPg'][$i] = $pgNo;
			}
		}
	}

	function _tableHeight(&$table)
	{
		$level = $table['level'];
		$levelid = $table['levelid'];
		$cells = &$table['cells'];
		$numcols = $table['nc'];
		$numrows = $table['nr'];
		$listspan = [];
		$checkmaxheight = 0;
		$headerrowheight = 0;
		$checkmaxheightplus = 0;
		$headerrowheightplus = 0;
		$firstrowheight = 0;

		$footerrowheight = 0;
		$footerrowheightplus = 0;
		if ($this->table_rotate) {
			$temppgheight = $this->tbrot_maxh;
			$remainingpage = $this->tbrot_maxh;
		} else {
			$temppgheight = ($this->h - $this->bMargin - $this->tMargin) - $this->kwt_height;
			$remainingpage = ($this->h - $this->bMargin - $this->y) - $this->kwt_height;

			// 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
			$enddiv = $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $table['margin']['B'];
			if ($remainingpage > $enddiv && $enddiv / $remainingpage < 0.05) {
				$remainingpage -= $enddiv;
			} elseif ($remainingpage == 0) {
				$remainingpage = 0.001;
			}
			if ($temppgheight > $enddiv && $enddiv / $temppgheight < 0.05) {
				$temppgheight -= $enddiv;
			} elseif ($temppgheight == 0) {
				$temppgheight = 0.001;
			}
		}
		if ($remainingpage < 0) {
			$remainingpage = 0.001;
		}
		if ($temppgheight < 0) {
			$temppgheight = 0.001;
		}

		for ($i = 0; $i < $numrows; $i++) { // rows
			$heightrow = &$table['hr'][$i];
			for ($j = 0; $j < $numcols; $j++) { // columns
				if (isset($cells[$i][$j]) && $cells[$i][$j]) {
					$c = &$cells[$i][$j];

					if ($this->simpleTables) {
						if ($table['borders_separate']) { // NB twice border width
							$extraWLR = ($table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w']) + ($c['padding']['L'] + $c['padding']['R']) + $table['border_spacing_H'];
							$extrh = ($table['simple']['border_details']['T']['w'] + $table['simple']['border_details']['B']['w']) + ($c['padding']['T'] + $c['padding']['B']) + $table['border_spacing_V'];
						} else {
							$extraWLR = ($table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w']) / 2 + ($c['padding']['L'] + $c['padding']['R']);
							$extrh = ($table['simple']['border_details']['T']['w'] + $table['simple']['border_details']['B']['w']) / 2 + ($c['padding']['T'] + $c['padding']['B']);
						}
					} else {
						if ($this->packTableData) {
							list($bt, $br, $bb, $bl) = $this->_getBorderWidths($c['borderbin']);
						} else {
							$bt = $c['border_details']['T']['w'];
							$bb = $c['border_details']['B']['w'];
							$br = $c['border_details']['R']['w'];
							$bl = $c['border_details']['L']['w'];
						}
						if ($table['borders_separate']) { // NB twice border width
							$extraWLR = $bl + $br + $c['padding']['L'] + $c['padding']['R'] + $table['border_spacing_H'];
							$extrh = $bt + $bb + $c['padding']['T'] + $c['padding']['B'] + $table['border_spacing_V'];
						} else {
							$extraWLR = $bl / 2 + $br / 2 + $c['padding']['L'] + $c['padding']['R'];
							$extrh = $bt / 2 + $bb / 2 + $c['padding']['T'] + $c['padding']['B'];
						}
					}

					if ($table['overflow'] == 'visible' && $level == 1) {
						list($x, $cw) = $this->_splitTableGetWidth($table, $i, $j);
					} else {
						list($x, $cw) = $this->_tableGetWidth($table, $i, $j);
					}


					// Get CELL HEIGHT
					// ++ extra parameter forces wrap to break word
					if ($c['R'] && isset($c['textbuffer'])) {
						$str = '';
						foreach ($c['textbuffer'] as $t) {
							$str .= $t[0] . ' ';
						}
						$str = rtrim($str);
						$s_fs = $this->FontSizePt;
						$s_f = $this->FontFamily;
						$s_st = $this->FontStyle;
						$this->SetFont($c['textbuffer'][0][4], $c['textbuffer'][0][2], $c['textbuffer'][0][11] / $this->shrin_k, true, true);
						$tempch = $this->GetStringWidth($str, true, $c['textbuffer'][0][18], $c['textbuffer'][0][8]);
						if ($c['R'] >= 45 && $c['R'] < 90) {
							$tempch = ((sin(deg2rad($c['R']))) * $tempch ) + ((sin(deg2rad($c['R']))) * (($c['textbuffer'][0][11] / Mpdf::SCALE) / $this->shrin_k));
						}
						$this->SetFont($s_f, $s_st, $s_fs, true, true);
						$ch = ($tempch ) + $extrh;
					} else {
						if (isset($c['textbuffer']) && !empty($c['textbuffer'])) {
							$this->cellLineHeight = $c['cellLineHeight'];
							$this->cellLineStackingStrategy = $c['cellLineStackingStrategy'];
							$this->cellLineStackingShift = $c['cellLineStackingShift'];
							$this->divwidth = $cw - $extraWLR;
							$tempch = $this->printbuffer($c['textbuffer'], '', true, true);
						} else {
							$tempch = 0;
						}

						// Added cellpadding top and bottom. (Lineheight already adjusted)
						$ch = $tempch + $extrh;
					}
					// If height is defined and it is bigger than calculated $ch then update values
					if (isset($c['h']) && $c['h'] > $ch) {
						$c['mih'] = $ch; // in order to keep valign working
						$ch = $c['h'];
					} else {
						$c['mih'] = $ch;
					}
					if (isset($c['rowspan'])) {
						$listspan[] = [$i, $j];
					} elseif ($heightrow < $ch) {
						$heightrow = $ch;
					}

					// this is the extra used in _tableWrite to determine whether to trigger a page change
					if ($table['borders_separate']) {
						if ($i == ($numrows - 1) || (isset($c['rowspan']) && ($i + $c['rowspan']) == ($numrows))) {
							$extra = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
						} else {
							$extra = $table['border_spacing_V'] / 2;
						}
					} else {
						if (!$this->simpleTables) {
							$extra = $bb / 2;
						} elseif ($this->simpleTables) {
							$extra = $table['simple']['border_details']['B']['w'] / 2;
						}
					}
					if (isset($table['is_thead'][$i]) && $table['is_thead'][$i]) {
						if ($j == 0) {
							$headerrowheight += $ch;
							$headerrowheightplus += $ch + $extra;
						}
					} elseif (isset($table['is_tfoot'][$i]) && $table['is_tfoot'][$i]) {
						if ($j == 0) {
							$footerrowheight += $ch;
							$footerrowheightplus += $ch + $extra;
						}
					} else {
						$checkmaxheight = max($checkmaxheight, $ch);
						$checkmaxheightplus = max($checkmaxheightplus, $ch + $extra);
					}
					if ($this->tableLevel == 1 && $i == (isset($table['headernrows']) ? $table['headernrows'] : 0)) {
						$firstrowheight = max($ch, $firstrowheight);
					}
					unset($c);
				}
			}//end of columns
		}//end of rows

		$heightrow = &$table['hr'];
		foreach ($listspan as $span) {
			list($i, $j) = $span;
			$c = &$cells[$i][$j];
			$lr = $i + $c['rowspan'];
			if ($lr > $numrows) {
				$lr = $numrows;
			}
			$hs = $hsa = 0;
			$list = [];
			for ($k = $i; $k < $lr; $k++) {
				$hs += $heightrow[$k];
				// mPDF 6
				$sh = false; // specified height
				for ($m = 0; $m < $numcols; $m++) { // columns
					$tc = &$cells[$k][$m];
					if (isset($tc['rowspan'])) {
						continue;
					}
					if (isset($tc['h'])) {
						$sh = true;
						break;
					}
				}
				if (!$sh) {
					$list[] = $k;
				}
			}

			if ($table['borders_separate']) {
				if ($i == ($numrows - 1) || ($i + $c['rowspan']) == ($numrows)) {
					$extra = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
				} else {
					$extra = $table['border_spacing_V'] / 2;
				}
			} else {
				if (!$this->simpleTables) {
					if ($this->packTableData) {
						list($bt, $br, $bb, $bl) = $this->_getBorderWidths($c['borderbin']);
					} else {
						$bb = $c['border_details']['B']['w'];
					}
					$extra = $bb / 2;
				} elseif ($this->simpleTables) {
					$extra = $table['simple']['border_details']['B']['w'] / 2;
				}
			}
			if (!empty($table['is_thead'][$i])) {
				$headerrowheight = max($headerrowheight, $hs);
				$headerrowheightplus = max($headerrowheightplus, $hs + $extra);
			} elseif (!empty($table['is_tfoot'][$i])) {
				$footerrowheight = max($footerrowheight, $hs);
				$footerrowheightplus = max($footerrowheightplus, $hs + $extra);
			} else {
				$checkmaxheight = max($checkmaxheight, $hs);
				$checkmaxheightplus = max($checkmaxheightplus, $hs + $extra);
			}
			if ($this->tableLevel == 1 && $i == (isset($table['headernrows']) ? $table['headernrows'] : 0)) {
				$firstrowheight = max($hs, $firstrowheight);
			}

			if ($c['mih'] > $hs) {
				if (!$hs) {
					for ($k = $i; $k < $lr; $k++) {
						$heightrow[$k] = $c['mih'] / $c['rowspan'];
					}
				} elseif (!count($list)) { // no rows in the rowspan have a height specified, so share amongst all rows equally
					$hi = $c['mih'] - $hs;
					for ($k = $i; $k < $lr; $k++) {
						$heightrow[$k] += ($heightrow[$k] / $hs) * $hi;
					}
				} else {
					$hi = $c['mih'] - $hs; // mPDF 6
					foreach ($list as $k) {
						$heightrow[$k] += $hi / (count($list)); // mPDF 6
					}
				}
			}
			unset($c);

			// If rowspans overlap so that one or more rows do not have a height set...
			// i.e. for one or more rows, the only cells (explicit) in that row have rowspan>1
			// so heightrow is still == 0
			if ($heightrow[$i] == 0) {
				// Get row extent to analyse above and below
				$top = $i;
				foreach ($listspan as $checkspan) {
					list($cki, $ckj) = $checkspan;
					$c = &$cells[$cki][$ckj];
					if (isset($c['rowspan']) && $c['rowspan'] > 1) {
						if (($cki + $c['rowspan'] - 1) >= $i) {
							$top = min($top, $cki);
						}
					}
				}
				$bottom = $i + $c['rowspan'] - 1;
				// Check for overconstrained conditions
				for ($k = $top; $k <= $bottom; $k++) {
					// if ['hr'] for any of the others is also 0, then abort (too complicated)
					if ($k != $i && $heightrow[$k] == 0) {
						break(1);
					}
					// check again that top and bottom are not crossed by rowspans - or abort (too complicated)
					if ($k == $top) {
						// ???? take account of colspan as well???
						for ($m = 0; $m < $numcols; $m++) { // columns
							if (!isset($cells[$k][$m]) || $cells[$k][$m] == 0) {
								break(2);
							}
						}
					} elseif ($k == $bottom) {
						// ???? take account of colspan as well???
						for ($m = 0; $m < $numcols; $m++) { // columns
							$c = &$cells[$k][$m];
							if (isset($c['rowspan']) && $c['rowspan'] > 1) {
								break(2);
							}
						}
					}
				}
				// By columns add up col height using ['h'] if set or ['mih'] if not
				// Intentionally do not substract border-spacing
				$colH = [];
				$extH = 0;
				$newhr = [];
				for ($m = 0; $m < $numcols; $m++) { // columns
					for ($k = $top; $k <= $bottom; $k++) {
						if (isset($cells[$k][$m]) && $cells[$k][$m] != 0) {
							$c = &$cells[$k][$m];
							if (isset($c['h']) && $c['h']) {
								$useh = $c['h'];
							} // ???? take account of colspan as well???
							else {
								$useh = $c['mih'];
							}
							if (isset($colH[$m])) {
								$colH[$m] += $useh;
							} else {
								$colH[$m] = $useh;
							}
							if (!isset($c['rowspan']) || $c['rowspan'] < 2) {
								$newhr[$k] = max((isset($newhr[$k]) ? $newhr[$k] : 0), $useh);
							}
						}
					}
					$extH = max($extH, $colH[$m]); // mPDF 6
				}
				$newhr[$i] = $extH - array_sum($newhr);
				for ($k = $top; $k <= $bottom; $k++) {
					$heightrow[$k] = $newhr[$k];
				}
			}


			unset($c);
		}

		$table['h'] = array_sum($heightrow);
		unset($heightrow);

		if ($table['borders_separate']) {
			$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'];
		} else {
			$table['h'] += $table['margin']['T'] + $table['margin']['B'] + $table['max_cell_border_width']['T'] / 2 + $table['max_cell_border_width']['B'] / 2;
		}

		$maxrowheight = $checkmaxheightplus + $headerrowheightplus + $footerrowheightplus;
		$maxfirstrowheight = $firstrowheight + $headerrowheightplus + $footerrowheightplus; // includes thead, 1st row and tfoot
		return [$table['h'], $maxrowheight, $temppgheight, $remainingpage, $maxfirstrowheight];
	}

	function _tableGetWidth(&$table, $i, $j)
	{
		$cell = &$table['cells'][$i][$j];
		if ($cell) {
			if (isset($cell['x0'])) {
				return [$cell['x0'], $cell['w0']];
			}
			$x = 0;
			$widthcols = &$table['wc'];
			for ($k = 0; $k < $j; $k++) {
				$x += $widthcols[$k];
			}
			$w = $widthcols[$j];
			if (isset($cell['colspan'])) {
				for ($k = $j + $cell['colspan'] - 1; $k > $j; $k--) {
					$w += $widthcols[$k];
				}
			}
			$cell['x0'] = $x;
			$cell['w0'] = $w;
			return [$x, $w];
		}
		return [0, 0];
	}

	function _splitTableGetWidth(&$table, $i, $j)
	{
		$cell = &$table['cells'][$i][$j];
		if ($cell) {
			if (isset($cell['x0'])) {
				return [$cell['x0'], $cell['w0']];
			}
			$x = 0;
			$widthcols = &$table['wc'];
			$pg = $table['colPg'][$j];
			for ($k = 0; $k < $j; $k++) {
				if ($table['colPg'][$k] == $pg) {
					$x += $widthcols[$k];
				}
			}
			$w = $widthcols[$j];
			if (isset($cell['colspan'])) {
				for ($k = $j + $cell['colspan'] - 1; $k > $j; $k--) {
					if ($table['colPg'][$k] == $pg) {
						$w += $widthcols[$k];
					}
				}
			}
			$cell['x0'] = $x;
			$cell['w0'] = $w;
			return [$x, $w];
		}
		return [0, 0];
	}

	function _tableGetHeight(&$table, $i, $j)
	{
		$cell = &$table['cells'][$i][$j];
		if ($cell) {
			if (isset($cell['y0'])) {
				return [$cell['y0'], $cell['h0']];
			}
			$y = 0;
			$heightrow = &$table['hr'];
			for ($k = 0; $k < $i; $k++) {
				$y += $heightrow[$k];
			}
			$h = $heightrow[$i];
			if (isset($cell['rowspan'])) {
				for ($k = $i + $cell['rowspan'] - 1; $k > $i; $k--) {
					if (array_key_exists($k, $heightrow)) {
						$h += $heightrow[$k];
					} else {
						$this->logger->debug('Possible non-wellformed HTML markup in a table', ['context' => LogContext::HTML_MARKUP]);
					}
				}
			}
			$cell['y0'] = $y;
			$cell['h0'] = $h;
			return [$y, $h];
		}
		return [0, 0];
	}

	function _tableGetMaxRowHeight($table, $row)
	{
		if ($row == $table['nc'] - 1) {
			return $table['hr'][$row];
		}
		$maxrowheight = $table['hr'][$row];
		for ($i = $row + 1; $i < $table['nr']; $i++) {
			$cellsset = 0;
			for ($j = 0; $j < $table['nc']; $j++) {
				if (isset($table['cells'][$i][$j])) {
					if (isset($table['cells'][$i][$j]['colspan'])) {
						$cellsset += $table['cells'][$i][$j]['colspan'];
					} else {
						$cellsset += 1;
					}
				}
			}
			if ($cellsset == $table['nc']) {
				return $maxrowheight;
			} else {
				$maxrowheight += $table['hr'][$i];
			}
		}
		return $maxrowheight;
	}

	// CHANGED TO ALLOW TABLE BORDER TO BE SPECIFIED CORRECTLY - added border_details
	function _tableRect($x, $y, $w, $h, $bord = -1, $details = [], $buffer = false, $bSeparate = false, $cort = 'cell', $tablecorner = '', $bsv = 0, $bsh = 0)
	{
		$cellBorderOverlay = [];

		if ($bord == -1) {
			$this->Rect($x, $y, $w, $h);
		} elseif ($this->simpleTables && ($cort == 'cell')) {
			$this->SetLineWidth($details['L']['w']);
			if ($details['L']['c']) {
				$this->SetDColor($details['L']['c']);
			} else {
				$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
			}
			$this->SetLineJoin(0);
			$this->Rect($x, $y, $w, $h);
		} elseif ($bord) {
			if (!$bSeparate && $buffer) {
				$priority = 'LRTB';
				for ($p = 0; $p < strlen($priority); $p++) {
					$side = $priority[$p];
					$details['p'] = $side;

					$dom = 0;
					if (isset($details[$side]['w'])) {
						$dom += ($details[$side]['w'] * 100000);
					}
					if (isset($details[$side]['style'])) {
						$dom += (array_search($details[$side]['style'], $this->borderstyles) * 100);
					}
					if (isset($details[$side]['dom'])) {
						$dom += ($details[$side]['dom'] * 10);
					}

					// Precedence to darker colours at joins
					$coldom = 0;
					if (isset($details[$side]['c']) && is_array($details[$side]['c'])) {
						if ($details[$side]['c'][0] == 3) {  // RGB
							$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);
						}
					} // 10 black - 0 white
					if ($coldom) {
						$dom += $coldom;
					}
					// Lastly precedence to RIGHT and BOTTOM cells at joins
					if (isset($details['cellposdom'])) {
						$dom += $details['cellposdom'];
					}

					$save = false;
					if ($side == 'T' && $this->issetBorder($bord, Border::TOP)) {
						$cbord = Border::TOP;
						$save = true;
					} elseif ($side == 'L' && $this->issetBorder($bord, Border::LEFT)) {
						$cbord = Border::LEFT;
						$save = true;
					} elseif ($side == 'R' && $this->issetBorder($bord, Border::RIGHT)) {
						$cbord = Border::RIGHT;
						$save = true;
					} elseif ($side == 'B' && $this->issetBorder($bord, Border::BOTTOM)) {
						$cbord = Border::BOTTOM;
						$save = true;
					}

					if ($save) {
						$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);
						if ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'groove' || $details[$side]['style'] == 'inset' || $details[$side]['style'] == 'outset' || $details[$side]['style'] == 'double') {
							$details[$side]['overlay'] = true;
							$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);
						}
					}
				}
				return;
			}

			if (isset($details['p']) && strlen($details['p']) > 1) {
				$priority = $details['p'];
			} else {
				$priority = 'LTRB';
			}
			$Tw = 0;
			$Rw = 0;
			$Bw = 0;
			$Lw = 0;
			if (isset($details['T']['w'])) {
				$Tw = $details['T']['w'];
			}
			if (isset($details['R']['w'])) {
				$Rw = $details['R']['w'];
			}
			if (isset($details['B']['w'])) {
				$Bw = $details['B']['w'];
			}
			if (isset($details['L']['w'])) {
				$Lw = $details['L']['w'];
			}

			$x2 = $x + $w;
			$y2 = $y + $h;
			$oldlinewidth = $this->LineWidth;

			for ($p = 0; $p < strlen($priority); $p++) {
				$side = $priority[$p];
				$xadj = 0;
				$xadj2 = 0;
				$yadj = 0;
				$yadj2 = 0;
				$print = false;
				if ($Tw && $side == 'T' && $this->issetBorder($bord, Border::TOP)) { // TOP
					$ly1 = $y;
					$ly2 = $y;
					$lx1 = $x;
					$lx2 = $x2;
					$this->SetLineWidth($Tw);
					if ($cort == 'cell' || strpos($tablecorner, 'L') !== false) {
						if ($Tw > $Lw) {
							$xadj = ($Tw - $Lw) / 2;
						}
						if ($Tw < $Lw) {
							$xadj = ($Tw + $Lw) / 2;
						}
					} else {
						$xadj = $Tw / 2 - $bsh / 2;
					}
					if ($cort == 'cell' || strpos($tablecorner, 'R') !== false) {
						if ($Tw > $Rw) {
							$xadj2 = ($Tw - $Rw) / 2;
						}
						if ($Tw < $Rw) {
							$xadj2 = ($Tw + $Rw) / 2;
						}
					} else {
						$xadj2 = $Tw / 2 - $bsh / 2;
					}
					if (!$bSeparate && !empty($details['mbw']) && !empty($details['mbw']['TL'])) {
						$xadj = ($Tw - $details['mbw']['TL']) / 2;
					}
					if (!$bSeparate && !empty($details['mbw']) && !empty($details['mbw']['TR'])) {
						$xadj2 = ($Tw - $details['mbw']['TR']) / 2;
					}
					$print = true;
				}
				if ($Lw && $side == 'L' && $this->issetBorder($bord, Border::LEFT)) { // LEFT
					$ly1 = $y;
					$ly2 = $y2;
					$lx1 = $x;
					$lx2 = $x;
					$this->SetLineWidth($Lw);
					if ($cort == 'cell' || strpos($tablecorner, 'T') !== false) {
						if ($Lw > $Tw) {
							$yadj = ($Lw - $Tw) / 2;
						}
						if ($Lw < $Tw) {
							$yadj = ($Lw + $Tw) / 2;
						}
					} else {
						$yadj = $Lw / 2 - $bsv / 2;
					}
					if ($cort == 'cell' || strpos($tablecorner, 'B') !== false) {
						if ($Lw > $Bw) {
							$yadj2 = ($Lw - $Bw) / 2;
						}
						if ($Lw < $Bw) {
							$yadj2 = ($Lw + $Bw) / 2;
						}
					} else {
						$yadj2 = $Lw / 2 - $bsv / 2;
					}
					if (!$bSeparate && $details['mbw']['LT']) {
						$yadj = ($Lw - $details['mbw']['LT']) / 2;
					}
					if (!$bSeparate && $details['mbw']['LB']) {
						$yadj2 = ($Lw - $details['mbw']['LB']) / 2;
					}
					$print = true;
				}
				if ($Rw && $side == 'R' && $this->issetBorder($bord, Border::RIGHT)) { // RIGHT
					$ly1 = $y;
					$ly2 = $y2;
					$lx1 = $x2;
					$lx2 = $x2;
					$this->SetLineWidth($Rw);
					if ($cort == 'cell' || strpos($tablecorner, 'T') !== false) {
						if ($Rw < $Tw) {
							$yadj = ($Rw + $Tw) / 2;
						}
						if ($Rw > $Tw) {
							$yadj = ($Rw - $Tw) / 2;
						}
					} else {
						$yadj = $Rw / 2 - $bsv / 2;
					}

					if ($cort == 'cell' || strpos($tablecorner, 'B') !== false) {
						if ($Rw > $Bw) {
							$yadj2 = ($Rw - $Bw) / 2;
						}
						if ($Rw < $Bw) {
							$yadj2 = ($Rw + $Bw) / 2;
						}
					} else {
						$yadj2 = $Rw / 2 - $bsv / 2;
					}

					if (!$bSeparate && !empty($details['mbw']) && !empty($details['mbw']['RT'])) {
						$yadj = ($Rw - $details['mbw']['RT']) / 2;
					}
					if (!$bSeparate && !empty($details['mbw']) && !empty($details['mbw']['RB'])) {
						$yadj2 = ($Rw - $details['mbw']['RB']) / 2;
					}
					$print = true;
				}
				if ($Bw && $side == 'B' && $this->issetBorder($bord, Border::BOTTOM)) { // BOTTOM
					$ly1 = $y2;
					$ly2 = $y2;
					$lx1 = $x;
					$lx2 = $x2;
					$this->SetLineWidth($Bw);
					if ($cort == 'cell' || strpos($tablecorner, 'L') !== false) {
						if ($Bw > $Lw) {
							$xadj = ($Bw - $Lw) / 2;
						}
						if ($Bw < $Lw) {
							$xadj = ($Bw + $Lw) / 2;
						}
					} else {
						$xadj = $Bw / 2 - $bsh / 2;
					}
					if ($cort == 'cell' || strpos($tablecorner, 'R') !== false) {
						if ($Bw > $Rw) {
							$xadj2 = ($Bw - $Rw) / 2;
						}
						if ($Bw < $Rw) {
							$xadj2 = ($Bw + $Rw) / 2;
						}
					} else {
						$xadj2 = $Bw / 2 - $bsh / 2;
					}
					if (!$bSeparate && isset($details['mbw']) && isset($details['mbw']['BL'])) {
						$xadj = ($Bw - $details['mbw']['BL']) / 2;
					}
					if (!$bSeparate && isset($details['mbw']) && isset($details['mbw']['BR'])) {
						$xadj2 = ($Bw - $details['mbw']['BR']) / 2;
					}
					$print = true;
				}

				// Now draw line
				if ($print) {
					/* -- TABLES-ADVANCED-BORDERS -- */
					if ($details[$side]['style'] == 'double') {
						if (!isset($details[$side]['overlay']) || !$details[$side]['overlay'] || $bSeparate) {
							if ($details[$side]['c']) {
								$this->SetDColor($details[$side]['c']);
							} else {
								$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
							}
							$this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
						}
						if ((isset($details[$side]['overlay']) && $details[$side]['overlay']) || $bSeparate) {
							if ($bSeparate && $cort == 'table') {
								if ($side == 'T') {
									$xadj -= $this->LineWidth / 2;
									$xadj2 -= $this->LineWidth;
									if ($this->issetBorder($bord, Border::LEFT)) {
										$xadj += $this->LineWidth / 2;
									}
									if ($this->issetBorder($bord, Border::RIGHT)) {
										$xadj2 += $this->LineWidth;
									}
								}
								if ($side == 'L') {
									$yadj -= $this->LineWidth / 2;
									$yadj2 -= $this->LineWidth;
									if ($this->issetBorder($bord, Border::TOP)) {
										$yadj += $this->LineWidth / 2;
									}
									if ($this->issetBorder($bord, Border::BOTTOM)) {
										$yadj2 += $this->LineWidth;
									}
								}
								if ($side == 'B') {
									$xadj -= $this->LineWidth / 2;
									$xadj2 -= $this->LineWidth;
									if ($this->issetBorder($bord, Border::LEFT)) {
										$xadj += $this->LineWidth / 2;
									}
									if ($this->issetBorder($bord, Border::RIGHT)) {
										$xadj2 += $this->LineWidth;
									}
								}
								if ($side == 'R') {
									$yadj -= $this->LineWidth / 2;
									$yadj2 -= $this->LineWidth;
									if ($this->issetBorder($bord, Border::TOP)) {
										$yadj += $this->LineWidth / 2;
									}
									if ($this->issetBorder($bord, Border::BOTTOM)) {
										$yadj2 += $this->LineWidth;
									}
								}
							}

							$this->SetLineWidth($this->LineWidth / 3);

							$tbcol = $this->colorConverter->convert(255, $this->PDFAXwarnings);
							for ($l = 0; $l <= $this->blklvl; $l++) {
								if ($this->blk[$l]['bgcolor']) {
									$tbcol = ($this->blk[$l]['bgcolorarray']);
								}
							}

							if ($bSeparate) {
								$cellBorderOverlay[] = [
									'x' => $lx1 + $xadj,
									'y' => $ly1 + $yadj,
									'x2' => $lx2 - $xadj2,
									'y2' => $ly2 - $yadj2,
									'col' => $tbcol,
									'lw' => $this->LineWidth,
								];
							} else {
								$this->SetDColor($tbcol);
								$this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
							}
						}
					} elseif (isset($details[$side]['style']) && ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'groove' || $details[$side]['style'] == 'inset' || $details[$side]['style'] == 'outset')) {
						if (!isset($details[$side]['overlay']) || !$details[$side]['overlay'] || $bSeparate) {
							if ($details[$side]['c']) {
								$this->SetDColor($details[$side]['c']);
							} else {
								$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
							}
							if ($details[$side]['style'] == 'outset' || $details[$side]['style'] == 'groove') {
								$nc = $this->colorConverter->darken($details[$side]['c']);
								$this->SetDColor($nc);
							} elseif ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'inset') {
								$nc = $this->colorConverter->lighten($details[$side]['c']);
								$this->SetDColor($nc);
							}
							$this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
						}
						if ((isset($details[$side]['overlay']) && $details[$side]['overlay']) || $bSeparate) {
							if ($details[$side]['c']) {
								$this->SetDColor($details[$side]['c']);
							} else {
								$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
							}
							$doubleadj = ($this->LineWidth) / 3;
							$this->SetLineWidth($this->LineWidth / 2);
							$xadj3 = $yadj3 = $wadj3 = $hadj3 = 0;

							if ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'inset') {
								$nc = $this->colorConverter->darken($details[$side]['c']);

								if ($bSeparate && $cort == 'table') {
									if ($side == 'T') {
										$yadj3 = $this->LineWidth / 2;
										$xadj3 = -$this->LineWidth / 2;
										$wadj3 = $this->LineWidth;
										if ($this->issetBorder($bord, Border::LEFT)) {
											$xadj3 += $this->LineWidth;
											$wadj3 -= $this->LineWidth;
										}
										if ($this->issetBorder($bord, Border::RIGHT)) {
											$wadj3 -= $this->LineWidth * 2;
										}
									}
									if ($side == 'L') {
										$xadj3 = $this->LineWidth / 2;
										$yadj3 = -$this->LineWidth / 2;
										$hadj3 = $this->LineWidth;
										if ($this->issetBorder($bord, Border::TOP)) {
											$yadj3 += $this->LineWidth;
											$hadj3 -= $this->LineWidth;
										}
										if ($this->issetBorder($bord, Border::BOTTOM)) {
											$hadj3 -= $this->LineWidth * 2;
										}
									}
									if ($side == 'B') {
										$yadj3 = $this->LineWidth / 2;
										$xadj3 = -$this->LineWidth / 2;
										$wadj3 = $this->LineWidth;
									}
									if ($side == 'R') {
										$xadj3 = $this->LineWidth / 2;
										$yadj3 = -$this->LineWidth / 2;
										$hadj3 = $this->LineWidth;
									}
								} elseif ($side == 'T') {
									$yadj3 = $this->LineWidth / 2;
									$xadj3 = $this->LineWidth / 2;
									$wadj3 = -$this->LineWidth * 2;
								} elseif ($side == 'L') {
									$xadj3 = $this->LineWidth / 2;
									$yadj3 = $this->LineWidth / 2;
									$hadj3 = -$this->LineWidth * 2;
								} elseif ($side == 'B' && $bSeparate) {
									$yadj3 = $this->LineWidth / 2;
									$wadj3 = $this->LineWidth / 2;
								} elseif ($side == 'R' && $bSeparate) {
									$xadj3 = $this->LineWidth / 2;
									$hadj3 = $this->LineWidth / 2;
								} elseif ($side == 'B') {
									$yadj3 = $this->LineWidth / 2;
									$xadj3 = $this->LineWidth / 2;
								} elseif ($side == 'R') {
									$xadj3 = $this->LineWidth / 2;
									$yadj3 = $this->LineWidth / 2;
								}
							} else {
								$nc = $this->colorConverter->lighten($details[$side]['c']);

								if ($bSeparate && $cort == 'table') {
									if ($side == 'T') {
										$yadj3 = $this->LineWidth / 2;
										$xadj3 = -$this->LineWidth / 2;
										$wadj3 = $this->LineWidth;
										if ($this->issetBorder($bord, Border::LEFT)) {
											$xadj3 += $this->LineWidth;
											$wadj3 -= $this->LineWidth;
										}
									}
									if ($side == 'L') {
										$xadj3 = $this->LineWidth / 2;
										$yadj3 = -$this->LineWidth / 2;
										$hadj3 = $this->LineWidth;
										if ($this->issetBorder($bord, Border::TOP)) {
											$yadj3 += $this->LineWidth;
											$hadj3 -= $this->LineWidth;
										}
									}
									if ($side == 'B') {
										$yadj3 = $this->LineWidth / 2;
										$xadj3 = -$this->LineWidth / 2;
										$wadj3 = $this->LineWidth;
										if ($this->issetBorder($bord, Border::LEFT)) {
											$xadj3 += $this->LineWidth;
											$wadj3 -= $this->LineWidth;
										}
									}
									if ($side == 'R') {
										$xadj3 = $this->LineWidth / 2;
										$yadj3 = -$this->LineWidth / 2;
										$hadj3 = $this->LineWidth;
										if ($this->issetBorder($bord, Border::TOP)) {
											$yadj3 += $this->LineWidth;
											$hadj3 -= $this->LineWidth;
										}
									}
								} elseif ($side == 'T') {
									$yadj3 = $this->LineWidth / 2;
									$xadj3 = $this->LineWidth / 2;
								} elseif ($side == 'L') {
									$xadj3 = $this->LineWidth / 2;
									$yadj3 = $this->LineWidth / 2;
								} elseif ($side == 'B' && $bSeparate) {
									$yadj3 = $this->LineWidth / 2;
									$xadj3 = $this->LineWidth / 2;
								} elseif ($side == 'R' && $bSeparate) {
									$xadj3 = $this->LineWidth / 2;
									$yadj3 = $this->LineWidth / 2;
								} elseif ($side == 'B') {
									$yadj3 = $this->LineWidth / 2;
									$xadj3 = -$this->LineWidth / 2;
									$wadj3 = $this->LineWidth;
								} elseif ($side == 'R') {
									$xadj3 = $this->LineWidth / 2;
									$yadj3 = -$this->LineWidth / 2;
									$hadj3 = $this->LineWidth;
								}
							}

							if ($bSeparate) {
								$cellBorderOverlay[] = [
									'x' => $lx1 + $xadj + $xadj3,
									'y' => $ly1 + $yadj + $yadj3,
									'x2' => $lx2 - $xadj2 + $xadj3 + $wadj3,
									'y2' => $ly2 - $yadj2 + $yadj3 + $hadj3,
									'col' => $nc,
									'lw' => $this->LineWidth,
								];
							} else {
								$this->SetDColor($nc);
								$this->Line($lx1 + $xadj + $xadj3, $ly1 + $yadj + $yadj3, $lx2 - $xadj2 + $xadj3 + $wadj3, $ly2 - $yadj2 + $yadj3 + $hadj3);
							}
						}
					} else {
						/* -- END TABLES-ADVANCED-BORDERS -- */
						if ($details[$side]['style'] == 'dashed') {
							$dashsize = 2; // final dash will be this + 1*linewidth
							$dashsizek = 1.5; // ratio of Dash/Blank
							$this->SetDash($dashsize, ($dashsize / $dashsizek) + ($this->LineWidth * 2));
						} elseif ($details[$side]['style'] == 'dotted') {
							$this->SetLineJoin(1);
							$this->SetLineCap(1);
							$this->SetDash(0.001, ($this->LineWidth * 2));
						}
						if ($details[$side]['c']) {
							$this->SetDColor($details[$side]['c']);
						} else {
							$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
						}
						$this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
						/* -- TABLES-ADVANCED-BORDERS -- */
					}
					/* -- END TABLES-ADVANCED-BORDERS -- */

					// Reset Corners
					$this->SetDash();
					// BUTT style line cap
					$this->SetLineCap(2);
				}
			}

			if ($bSeparate && count($cellBorderOverlay)) {
				foreach ($cellBorderOverlay as $cbo) {
					$this->SetLineWidth($cbo['lw']);
					$this->SetDColor($cbo['col']);
					$this->Line($cbo['x'], $cbo['y'], $cbo['x2'], $cbo['y2']);
				}
			}

			// $this->SetLineWidth($oldlinewidth);
			// $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
		}
	}

	/* -- TABLES -- */
	/* -- TABLES-ADVANCED-BORDERS -- */

	/* -- END TABLES-ADVANCED-BORDERS -- */

	function setBorder(&$var, $flag, $set = true)
	{
		$flag = intval($flag);
		if ($set) {
			$set = true;
		}
		$var = intval($var);
		$var = $set ? ($var | $flag) : ($var & ~$flag);
	}

	function issetBorder($var, $flag)
	{
		$flag = intval($flag);
		$var = intval($var);
		return (($var & $flag) == $flag);
	}

	function _table2cellBorder(&$tableb, &$cbdb, &$cellb, $bval)
	{
		if ($tableb && $tableb['w'] > $cbdb['w']) {
			$cbdb = $tableb;
			$this->setBorder($cellb, $bval);
		} elseif ($tableb && $tableb['w'] == $cbdb['w'] && array_search($tableb['style'], $this->borderstyles) > array_search($cbdb['style'], $this->borderstyles)) {
			$cbdb = $tableb;
			$this->setBorder($cellb, $bval);
		}
	}

	// FIX BORDERS ********************************************
	function _fixTableBorders(&$table)
	{
		if (!$table['borders_separate'] && $table['border_details']['L']['w']) {
			$table['max_cell_border_width']['L'] = $table['border_details']['L']['w'];
		}
		if (!$table['borders_separate'] && $table['border_details']['R']['w']) {
			$table['max_cell_border_width']['R'] = $table['border_details']['R']['w'];
		}
		if (!$table['borders_separate'] && $table['border_details']['T']['w']) {
			$table['max_cell_border_width']['T'] = $table['border_details']['T']['w'];
		}
		if (!$table['borders_separate'] && $table['border_details']['B']['w']) {
			$table['max_cell_border_width']['B'] = $table['border_details']['B']['w'];
		}
		if ($this->simpleTables) {
			return;
		}
		$cells = &$table['cells'];
		$numcols = $table['nc'];
		$numrows = $table['nr'];
		/* -- TABLES-ADVANCED-BORDERS -- */
		if (isset($table['topntail']) && $table['topntail']) {
			$tntborddet = $this->border_details($table['topntail']);
		}
		if (isset($table['thead-underline']) && $table['thead-underline']) {
			$thuborddet = $this->border_details($table['thead-underline']);
		}
		/* -- END TABLES-ADVANCED-BORDERS -- */

		for ($i = 0; $i < $numrows; $i++) { // Rows
			for ($j = 0; $j < $numcols; $j++) { // Columns
				if (isset($cells[$i][$j]) && $cells[$i][$j]) {
					$cell = &$cells[$i][$j];
					if ($this->packTableData) {
						$cbord = $this->_unpackCellBorder($cell['borderbin']);
					} else {
						$cbord = &$cells[$i][$j];
					}

					// mPDF 5.7.3
					if (!$cbord['border'] && $cbord['border'] !== 0 && isset($table['border']) && $table['border'] && $this->table_border_attr_set) {
						$cbord['border'] = $table['border'];
						$cbord['border_details'] = $table['border_details'];
					}

					if (isset($cell['colspan']) && $cell['colspan'] > 1) {
						$ccolsp = $cell['colspan'];
					} else {
						$ccolsp = 1;
					}
					if (isset($cell['rowspan']) && $cell['rowspan'] > 1) {
						$crowsp = $cell['rowspan'];
					} else {
						$crowsp = 1;
					}

					$cbord['border_details']['cellposdom'] = ((($i + 1) / $numrows) / 10000 ) + ((($j + 1) / $numcols) / 10 );
					// Inherit Cell border from Table border
					if ($this->table_border_css_set && !$table['borders_separate']) {
						if ($i == 0) {
							$this->_table2cellBorder($table['border_details']['T'], $cbord['border_details']['T'], $cbord['border'], Border::TOP);
						}
						if ($i == ($numrows - 1) || ($i + $crowsp) == ($numrows)) {
							$this->_table2cellBorder($table['border_details']['B'], $cbord['border_details']['B'], $cbord['border'], Border::BOTTOM);
						}
						if ($j == 0) {
							$this->_table2cellBorder($table['border_details']['L'], $cbord['border_details']['L'], $cbord['border'], Border::LEFT);
						}
						if ($j == ($numcols - 1) || ($j + $ccolsp) == ($numcols)) {
							$this->_table2cellBorder($table['border_details']['R'], $cbord['border_details']['R'], $cbord['border'], Border::RIGHT);
						}
					}

					/* -- TABLES-ADVANCED-BORDERS -- */
					$fixbottom = true;
					if (isset($table['topntail']) && $table['topntail']) {
						if ($i == 0) {
							$cbord['border_details']['T'] = $tntborddet;
							$this->setBorder($cbord['border'], Border::TOP);
						}
						if ($this->tableLevel == 1 && $table['headernrows'] > 0 && $i == $table['headernrows'] - 1) {
							$cbord['border_details']['B'] = $tntborddet;
							$this->setBorder($cbord['border'], Border::BOTTOM);
							$fixbottom = false;
						} elseif ($this->tableLevel == 1 && $table['headernrows'] > 0 && $i == $table['headernrows']) {
							if (!$table['borders_separate']) {
								$cbord['border_details']['T'] = $tntborddet;
								$this->setBorder($cbord['border'], Border::TOP);
							}
						}
						if ($this->tableLevel == 1 && $table['footernrows'] > 0 && $i == ($numrows - $table['footernrows'] - 1)) {
							if (!$table['borders_separate']) {
								$cbord['border_details']['B'] = $tntborddet;
								$this->setBorder($cbord['border'], Border::BOTTOM);
								$fixbottom = false;
							}
						} elseif ($this->tableLevel == 1 && $table['footernrows'] > 0 && $i == ($numrows - $table['footernrows'])) {
							$cbord['border_details']['T'] = $tntborddet;
							$this->setBorder($cbord['border'], Border::TOP);
						}
						if ($this->tabletheadjustfinished) { // $this->tabletheadjustfinished called from tableheader
							if (!$table['borders_separate']) {
								$cbord['border_details']['T'] = $tntborddet;
								$this->setBorder($cbord['border'], Border::TOP);
							}
						}
						if ($i == ($numrows - 1) || ($i + $crowsp) == ($numrows)) {
							$cbord['border_details']['B'] = $tntborddet;
							$this->setBorder($cbord['border'], Border::BOTTOM);
						}
					}
					if (isset($table['thead-underline']) && $table['thead-underline']) {
						if ($table['borders_separate']) {
							if ($i == 0) {
								$cbord['border_details']['B'] = $thuborddet;
								$this->setBorder($cbord['border'], Border::BOTTOM);
								$fixbottom = false;
							}
						} else {
							if ($this->tableLevel == 1 && $table['headernrows'] > 0 && $i == $table['headernrows'] - 1) {
								$cbord['border_details']['T'] = $thuborddet;
								$this->setBorder($cbord['border'], Border::TOP);
							} elseif ($this->tabletheadjustfinished) { // $this->tabletheadjustfinished called from tableheader
								$cbord['border_details']['T'] = $thuborddet;
								$this->setBorder($cbord['border'], Border::TOP);
							}
						}
					}

					// Collapse Border - Algorithm for conflicting borders
					// Hidden >> Width >> double>solid>dashed>dotted... >> style set on cell>table >> top/left>bottom/right
					// Do not turn off border which is overridden
					// Needed for page break for TOP/BOTTOM both to be defined in Collapsed borders
					// Means it is painted twice. (Left/Right can still disable overridden border)
					if (!$table['borders_separate']) {

						if (($i < ($numrows - 1) || ($i + $crowsp) < $numrows ) && $fixbottom) { // Bottom

							for ($cspi = 0; $cspi < $ccolsp; $cspi++) {

								// already defined Top for adjacent cell below
								if (isset($cells[($i + $crowsp)][$j + $cspi])) {
									if ($this->packTableData) {
										$adjc = $cells[($i + $crowsp)][$j + $cspi];
										$celladj = $this->_unpackCellBorder($adjc['borderbin']);
									} else {
										$celladj = & $cells[($i + $crowsp)][$j + $cspi];
									}
								} else {
									$celladj = false;
								}

								if (isset($celladj['border_details']['T']['s']) && $celladj['border_details']['T']['s'] == 1) {

									$csadj = $celladj['border_details']['T']['w'];
									$csthis = $cbord['border_details']['B']['w'];

									// Hidden
									if ($cbord['border_details']['B']['style'] == 'hidden') {

										$celladj['border_details']['T'] = $cbord['border_details']['B'];
										$this->setBorder($celladj['border'], Border::TOP, false);
										$this->setBorder($cbord['border'], Border::BOTTOM, false);

									} elseif ($celladj['border_details']['T']['style'] == 'hidden') {

										$cbord['border_details']['B'] = $celladj['border_details']['T'];
										$this->setBorder($cbord['border'], Border::BOTTOM, false);
										$this->setBorder($celladj['border'], Border::TOP, false);

									} elseif ($csthis > $csadj) { // Width

										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
											$celladj['border_details']['T'] = $cbord['border_details']['B'];
											$this->setBorder($cbord['border'], Border::BOTTOM);
										}

									} elseif ($csadj > $csthis) {

										if ($ccolsp < 2) { // don't overwrite this cell if it spans
											$cbord['border_details']['B'] = $celladj['border_details']['T'];
											$this->setBorder($celladj['border'], Border::TOP);
										}

									} elseif (array_search($cbord['border_details']['B']['style'], $this->borderstyles) > array_search($celladj['border_details']['T']['style'], $this->borderstyles)) { // double>solid>dashed>dotted...

										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
											$celladj['border_details']['T'] = $cbord['border_details']['B'];
											$this->setBorder($cbord['border'], Border::BOTTOM);
										}

									} elseif (array_search($celladj['border_details']['T']['style'], $this->borderstyles) > array_search($cbord['border_details']['B']['style'], $this->borderstyles)) {

										if ($ccolsp < 2) { // don't overwrite this cell if it spans
											$cbord['border_details']['B'] = $celladj['border_details']['T'];
											$this->setBorder($celladj['border'], Border::TOP);
										}

									} elseif ($celladj['border_details']['T']['dom'] > $celladj['border_details']['B']['dom']) { // Style set on cell vs. table

										if ($ccolsp < 2) { // don't overwrite this cell if it spans
											$cbord['border_details']['B'] = $celladj['border_details']['T'];
											$this->setBorder($celladj['border'], Border::TOP);
										}

									} else { // Style set on cell vs. table  - OR - LEFT/TOP (cell) in preference to BOTTOM/RIGHT

										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
											$celladj['border_details']['T'] = $cbord['border_details']['B'];
											$this->setBorder($cbord['border'], Border::BOTTOM);
										}

									}

								} elseif ($celladj) {

									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
										$celladj['border_details']['T'] = $cbord['border_details']['B'];
									}

								}

								// mPDF 5.7.4
								if ($celladj && $this->packTableData) {
									$cells[$i + $crowsp][$j + $cspi]['borderbin'] = $this->_packCellBorder($celladj);
								}

								unset($celladj);
							}
						}

						if ($j < ($numcols - 1) || ($j + $ccolsp) < $numcols) { // Right-Left

							for ($cspi = 0; $cspi < $crowsp; $cspi++) {

								// already defined Left for adjacent cell to R
								if (isset($cells[($i + $cspi)][$j + $ccolsp])) {
									if ($this->packTableData) {
										$adjc = $cells[($i + $cspi)][$j + $ccolsp];
										$celladj = $this->_unpackCellBorder($adjc['borderbin']);
									} else {
										$celladj = & $cells[$i + $cspi][$j + $ccolsp];
									}
								} else {
									$celladj = false;
								}
								if ($celladj && $celladj['border_details']['L']['s'] == 1) {
									$csadj = $celladj['border_details']['L']['w'];
									$csthis = $cbord['border_details']['R']['w'];
									// Hidden
									if ($cbord['border_details']['R']['style'] == 'hidden') {
										$celladj['border_details']['L'] = $cbord['border_details']['R'];
										$this->setBorder($celladj['border'], Border::LEFT, false);
										$this->setBorder($cbord['border'], Border::RIGHT, false);
									} elseif ($celladj['border_details']['L']['style'] == 'hidden') {
										$cbord['border_details']['R'] = $celladj['border_details']['L'];
										$this->setBorder($cbord['border'], Border::RIGHT, false);
										$this->setBorder($celladj['border'], Border::LEFT, false);
									} // Width
									elseif ($csthis > $csadj) {
										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
											$celladj['border_details']['L'] = $cbord['border_details']['R'];
											$this->setBorder($cbord['border'], Border::RIGHT);
											$this->setBorder($celladj['border'], Border::LEFT, false);
										}
									} elseif ($csadj > $csthis) {
										if ($crowsp < 2) { // don't overwrite this cell if it spans
											$cbord['border_details']['R'] = $celladj['border_details']['L'];
											$this->setBorder($cbord['border'], Border::RIGHT, false);
											$this->setBorder($celladj['border'], Border::LEFT);
										}
									} // double>solid>dashed>dotted...
									elseif (array_search($cbord['border_details']['R']['style'], $this->borderstyles) > array_search($celladj['border_details']['L']['style'], $this->borderstyles)) {
										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
											$celladj['border_details']['L'] = $cbord['border_details']['R'];
											$this->setBorder($celladj['border'], Border::LEFT, false);
											$this->setBorder($cbord['border'], Border::RIGHT);
										}
									} elseif (array_search($celladj['border_details']['L']['style'], $this->borderstyles) > array_search($cbord['border_details']['R']['style'], $this->borderstyles)) {
										if ($crowsp < 2) { // don't overwrite this cell if it spans
											$cbord['border_details']['R'] = $celladj['border_details']['L'];
											$this->setBorder($cbord['border'], Border::RIGHT, false);
											$this->setBorder($celladj['border'], Border::LEFT);
										}
									} // Style set on cell vs. table
									elseif ($celladj['border_details']['L']['dom'] > $cbord['border_details']['R']['dom']) {
										if ($crowsp < 2) { // don't overwrite this cell if it spans
											$cbord['border_details']['R'] = $celladj['border_details']['L'];
											$this->setBorder($celladj['border'], Border::LEFT);
										}
									} // Style set on cell vs. table  - OR - LEFT/TOP (cell) in preference to BOTTOM/RIGHT
									else {
										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
											$celladj['border_details']['L'] = $cbord['border_details']['R'];
											$this->setBorder($cbord['border'], Border::RIGHT);
										}
									}
								} elseif ($celladj) {
									// if right-cell border is not set
									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
										$celladj['border_details']['L'] = $cbord['border_details']['R'];
									}
								}
								// mPDF 5.7.4
								if ($celladj && $this->packTableData) {
									$cells[$i + $cspi][$j + $ccolsp]['borderbin'] = $this->_packCellBorder($celladj);
								}
								unset($celladj);
							}
						}
					}


					// Set maximum cell border width meeting at LRTB edges of cell - used for extended cell border
					// ['border_details']['mbw']['LT'] = meeting border width - Left border - Top end
					if (!$table['borders_separate']) {

						$cbord['border_details']['mbw']['BL'] = max($cbord['border_details']['mbw']['BL'], $cbord['border_details']['L']['w']);
						$cbord['border_details']['mbw']['BR'] = max($cbord['border_details']['mbw']['BR'], $cbord['border_details']['R']['w']);
						$cbord['border_details']['mbw']['RT'] = max($cbord['border_details']['mbw']['RT'], $cbord['border_details']['T']['w']);
						$cbord['border_details']['mbw']['RB'] = max($cbord['border_details']['mbw']['RB'], $cbord['border_details']['B']['w']);
						$cbord['border_details']['mbw']['TL'] = max($cbord['border_details']['mbw']['TL'], $cbord['border_details']['L']['w']);
						$cbord['border_details']['mbw']['TR'] = max($cbord['border_details']['mbw']['TR'], $cbord['border_details']['R']['w']);
						$cbord['border_details']['mbw']['LT'] = max($cbord['border_details']['mbw']['LT'], $cbord['border_details']['T']['w']);
						$cbord['border_details']['mbw']['LB'] = max($cbord['border_details']['mbw']['LB'], $cbord['border_details']['B']['w']);

						if (($i + $crowsp) < $numrows && isset($cells[$i + $crowsp][$j])) { // Has Bottom adjoining cell

							if ($this->packTableData) {
								$adjc = $cells[$i + $crowsp][$j];
								$celladj = $this->_unpackCellBorder($adjc['borderbin']);
							} else {
								$celladj = & $cells[$i + $crowsp][$j];
							}

							$cbord['border_details']['mbw']['BL'] = max(
								$cbord['border_details']['mbw']['BL'],
								$celladj ? $celladj['border_details']['L']['w'] : 0,
								$celladj ? $celladj['border_details']['mbw']['TL']: 0
							);

							$cbord['border_details']['mbw']['BR'] = max(
								$cbord['border_details']['mbw']['BR'],
								$celladj ? $celladj['border_details']['R']['w'] : 0,
								$celladj ? $celladj['border_details']['mbw']['TR']: 0
							);

							$cbord['border_details']['mbw']['LB'] = max(
								$cbord['border_details']['mbw']['LB'],
								$celladj ? $celladj['border_details']['mbw']['LT'] : 0
							);

							$cbord['border_details']['mbw']['RB'] = max(
								$cbord['border_details']['mbw']['RB'],
								$celladj ? $celladj['border_details']['mbw']['RT'] : 0
							);

							unset($celladj);
						}

						if (($j + $ccolsp) < $numcols && isset($cells[$i][$j + $ccolsp])) { // Has Right adjoining cell

							if ($this->packTableData) {
								$adjc = $cells[$i][$j + $ccolsp];
								$celladj = $this->_unpackCellBorder($adjc['borderbin']);
							} else {
								$celladj = & $cells[$i][$j + $ccolsp];
							}

							$cbord['border_details']['mbw']['RT'] = max(
								$cbord['border_details']['mbw']['RT'],
								$celladj ? $celladj['border_details']['T']['w'] : 0,
								$celladj ? $celladj['border_details']['mbw']['LT'] : 0
							);

							$cbord['border_details']['mbw']['RB'] = max(
								$cbord['border_details']['mbw']['RB'],
								$celladj ? $celladj['border_details']['B']['w'] : 0,
								$celladj ? $celladj['border_details']['mbw']['LB'] : 0
							);

							$cbord['border_details']['mbw']['TR'] = max(
								$cbord['border_details']['mbw']['TR'],
								$celladj ? $celladj['border_details']['mbw']['TL'] : 0
							);

							$cbord['border_details']['mbw']['BR'] = max(
								$cbord['border_details']['mbw']['BR'],
								$celladj ? $celladj['border_details']['mbw']['BL'] : 0
							);

							unset($celladj);
						}

						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

							if ($this->packTableData) {
								$adjc = $cells[$i - 1][$j];
								$celladj = $this->_unpackCellBorder($adjc['borderbin']);
							} else {
								$celladj = & $cells[$i - 1][$j];
							}

							$cbord['border_details']['mbw']['TL'] = max(
								$cbord['border_details']['mbw']['TL'],
								$celladj ? $celladj['border_details']['L']['w'] : 0,
								$celladj ? $celladj['border_details']['mbw']['BL'] : 0
							);

							$cbord['border_details']['mbw']['TR'] = max(
								$cbord['border_details']['mbw']['TR'],
								$celladj ? $celladj['border_details']['R']['w'] : 0,
								$celladj ? $celladj['border_details']['mbw']['BR'] : 0
							);

							$cbord['border_details']['mbw']['LT'] = max(
								$cbord['border_details']['mbw']['LT'],
								$celladj ? $celladj['border_details']['mbw']['LB'] : 0
							);

							$cbord['border_details']['mbw']['RT'] = max(
								$cbord['border_details']['mbw']['RT'],
								$celladj ? $celladj['border_details']['mbw']['RB'] : 0
							);

							if ($celladj['border_details']['mbw']['BL']) {
								$celladj['border_details']['mbw']['BL'] = max($cbord['border_details']['mbw']['TL'], $celladj['border_details']['mbw']['BL']);
							}

							if ($celladj['border_details']['mbw']['BR']) {
								$celladj['border_details']['mbw']['BR'] = max($celladj['border_details']['mbw']['BR'], $cbord['border_details']['mbw']['TR']);
							}

							if ($this->packTableData) {
								$cells[$i - 1][$j]['borderbin'] = $this->_packCellBorder($celladj);
							}
							unset($celladj);
						}

						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

							if ($this->packTableData) {
								$adjc = $cells[$i][$j - 1];
								$celladj = $this->_unpackCellBorder($adjc['borderbin']);
							} else {
								$celladj = & $cells[$i][$j - 1];
							}

							$cbord['border_details']['mbw']['LT'] = max(
								$cbord['border_details']['mbw']['LT'],
								$celladj ? $celladj['border_details']['T']['w'] : 0,
								$celladj ? $celladj['border_details']['mbw']['RT'] : 0
							);

							$cbord['border_details']['mbw']['LB'] = max(
								$cbord['border_details']['mbw']['LB'],
								$celladj ? $celladj['border_details']['B']['w'] : 0,
								$celladj ? $celladj['border_details']['mbw']['RB'] : 0
							);

							$cbord['border_details']['mbw']['BL'] = max(
								$cbord['border_details']['mbw']['BL'],
								$celladj ? $celladj['border_details']['mbw']['BR'] : 0
							);

							$cbord['border_details']['mbw']['TL'] = max(
								$cbord['border_details']['mbw']['TL'],
								$celladj ? $celladj['border_details']['mbw']['TR'] : 0
							);

							if ($celladj['border_details']['mbw']['RT']) {
								$celladj['border_details']['mbw']['RT'] = max($celladj['border_details']['mbw']['RT'], $cbord['border_details']['mbw']['LT']);
							}

							if ($celladj['border_details']['mbw']['RB']) {
								$celladj['border_details']['mbw']['RB'] = max($celladj['border_details']['mbw']['RB'], $cbord['border_details']['mbw']['LB']);
							}

							if ($this->packTableData) {
								$cells[$i][$j - 1]['borderbin'] = $this->_packCellBorder($celladj);
							}

							unset($celladj);
						}


						// Update maximum cell border width at LRTB edges of table - used for overall table width
						if ($j == 0 && $cbord['border_details']['L']['w']) {
							$table['max_cell_border_width']['L'] = max($table['max_cell_border_width']['L'], $cbord['border_details']['L']['w']);
						}
						if (($j == ($numcols - 1) || ($j + $ccolsp) == $numcols ) && $cbord['border_details']['R']['w']) {
							$table['max_cell_border_width']['R'] = max($table['max_cell_border_width']['R'], $cbord['border_details']['R']['w']);
						}
						if ($i == 0 && $cbord['border_details']['T']['w']) {
							$table['max_cell_border_width']['T'] = max($table['max_cell_border_width']['T'], $cbord['border_details']['T']['w']);
						}
						if (($i == ($numrows - 1) || ($i + $crowsp) == $numrows ) && $cbord['border_details']['B']['w']) {
							$table['max_cell_border_width']['B'] = max($table['max_cell_border_width']['B'], $cbord['border_details']['B']['w']);
						}
					}
					/* -- END TABLES-ADVANCED-BORDERS -- */

					if ($this->packTableData) {
						$cell['borderbin'] = $this->_packCellBorder($cbord);
					}

					unset($cbord);

					unset($cell);
				}
			}
		}
		unset($cell);
	}

	// END FIX BORDERS ************************************************************************************

	function _reverseTableDir(&$table)
	{
		$cells = &$table['cells'];
		$numcols = $table['nc'];
		$numrows = $table['nr'];
		for ($i = 0; $i < $numrows; $i++) { // Rows
			$row = [];
			for ($j = ($numcols - 1); $j >= 0; $j--) { // Columns
				if (isset($cells[$i][$j]) && $cells[$i][$j]) {
					$cell = &$cells[$i][$j];
					$col = $numcols - $j - 1;
					if (isset($cell['colspan']) && $cell['colspan'] > 1) {
						$col -= ($cell['colspan'] - 1);
					}
					// Nested content
					if (isset($cell['textbuffer'])) {
						for ($n = 0; $n < count($cell['textbuffer']); $n++) {
							$t = $cell['textbuffer'][$n][0];
							if (substr($t, 0, 19) == "\xbb\xa4\xactype=nestedtable") {
								$objattr = $this->_getObjAttr($t);
								$objattr['col'] = $col;
								$cell['textbuffer'][$n][0] = "\xbb\xa4\xactype=nestedtable,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
								$this->table[($this->tableLevel + 1)][$objattr['nestedcontent']]['nestedpos'][1] = $col;
							}
						}
					}
					$row[$col] = $cells[$i][$j];
					unset($cell);
				}
			}
			for ($f = 0; $f < $numcols; $f++) {
				if (!isset($row[$f])) {
					$row[$f] = 0;
				}
			}
			$table['cells'][$i] = $row;
		}
	}

	function _tableWrite(&$table, $split = false, $startrow = 0, $startcol = 0, $splitpg = 0, $rety = 0)
	{
		$level = $table['level'];
		$levelid = $table['levelid'];

		$cells = &$table['cells'];
		$numcols = $table['nc'];
		$numrows = $table['nr'];
		$maxbwtop = 0;
		if ($this->ColActive && $level == 1) {
			$this->breakpoints[$this->CurrCol][] = $this->y;
		} // *COLUMNS*

		if (!$split || ($startrow == 0 && $splitpg == 0) || $startrow > 0) {
			// TABLE TOP MARGIN
			if ($table['margin']['T']) {
				if (!$this->table_rotate && $level == 1) {
					$this->DivLn($table['margin']['T'], $this->blklvl, true, 1);  // collapsible
				} else {
					$this->y += ($table['margin']['T']);
				}
			}
			// Advance down page by half width of top border
			if ($table['borders_separate']) {
				if ($startrow > 0 && (!isset($table['is_thead']) || count($table['is_thead']) == 0)) {
					$adv = $table['border_spacing_V'] / 2;
				} else {
					$adv = $table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2;
				}
			} else {
				$adv = $table['max_cell_border_width']['T'] / 2;
			}
			if (!$this->table_rotate && $level == 1) {
				$this->DivLn($adv);
			} else {
				$this->y += $adv;
			}
		}

		if ($level == 1) {
			$this->x = $this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['padding_left'] + $this->blk[$this->blklvl]['border_left']['w'];
			$x0 = $this->x;
			$y0 = $this->y;
			$right = $x0 + $this->blk[$this->blklvl]['inner_width'];
			$outerfilled = $this->y; // Keep track of how far down the outer DIV bgcolor is painted (NB rowspans)
			$this->outerfilled = $this->y;
			$this->colsums = [];
		} else {
			$x0 = $this->x;
			$y0 = $this->y;
			$right = $x0 + $table['w'];
		}

		if ($this->table_rotate) {
			$temppgwidth = $this->tbrot_maxw;
			$this->PageBreakTrigger = $pagetrigger = $y0 + ($this->blk[$this->blklvl]['inner_width']);
			if ($level == 1) {
				$this->tbrot_y0 = $this->y - $adv - $table['margin']['T'];
				$this->tbrot_x0 = $this->x;
				$this->tbrot_w = $table['w'];
				if ($table['borders_separate']) {
					$this->tbrot_h = $table['margin']['T'] + $table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2;
				} else {
					$this->tbrot_h = $table['margin']['T'] + $table['padding']['T'] + $table['max_cell_border_width']['T'];
				}
			}
		} else {
			$this->PageBreakTrigger = $pagetrigger = ($this->h - $this->bMargin);
			if ($level == 1) {
				$temppgwidth = $this->blk[$this->blklvl]['inner_width'];
				if (isset($table['a']) and ( $table['w'] < $this->blk[$this->blklvl]['inner_width'])) {
					if ($table['a'] == 'C') {
						$x0 += ((($right - $x0) - $table['w']) / 2);
					} elseif ($table['a'] == 'R') {
						$x0 = $right - $table['w'];
					}
				}
			} else {
				$temppgwidth = $table['w'];
			}
		}
		if (!isset($table['overflow'])) {
			$table['overflow'] = null;
		}
		if ($table['overflow'] == 'hidden' && $level == 1 && !$this->table_rotate && !$this->ColActive) {
			// Bounding rectangle to clip
			$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);
			$this->writer->write($this->tableClipPath);
		} else {
			$this->tableClipPath = '';
		}


		if ($table['borders_separate']) {
			$indent = $table['margin']['L'] + $table['border_details']['L']['w'] + $table['padding']['L'] + $table['border_spacing_H'] / 2;
		} else {
			$indent = $table['margin']['L'] + $table['max_cell_border_width']['L'] / 2;
		}
		$x0 += $indent;

		$returny = 0;
		$lastCol = 0;
		$tableheader = [];
		$tablefooter = [];
		$tableheaderrowheight = 0;
		$tablefooterrowheight = 0;
		$footery = 0;

		// mPD 3.0 Set the Page & Column where table starts
		if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
			$tablestartpage = 'EVEN';
		} elseif (($this->mirrorMargins) && (($this->page) % 2 == 1)) { // ODD
			$tablestartpage = 'ODD';
		} else {
			$tablestartpage = '';
		}
		if ($this->ColActive) {
			$tablestartcolumn = $this->CurrCol;
		} else {
			$tablestartcolumn = '';
		}

		$y = $h = 0;
		for ($i = 0; $i < $numrows; $i++) { // Rows
			if (isset($table['is_tfoot'][$i]) && $table['is_tfoot'][$i] && $level == 1) {
				$tablefooterrowheight += $table['hr'][$i];
				$tablefooter[$i][0]['trbackground-images'] = $table['trbackground-images'][$i];
				$tablefooter[$i][0]['trgradients'] = $table['trgradients'][$i];
				$tablefooter[$i][0]['trbgcolor'] = $table['bgcolor'][$i];
				for ($j = $startcol; $j < $numcols; $j++) { // Columns
					if (isset($cells[$i][$j]) && $cells[$i][$j]) {
						$cell = &$cells[$i][$j];
						if ($split) {
							if ($table['colPg'][$j] != $splitpg) {
								continue;
							}
							list($x, $w) = $this->_splitTableGetWidth($table, $i, $j);
							$js = $j - $startcol;
						} else {
							list($x, $w) = $this->_tableGetWidth($table, $i, $j);
							$js = $j;
						}

						list($y, $h) = $this->_tableGetHeight($table, $i, $j);
						$x += $x0;
						$y += $y0;
						// Get info of tfoot ==>> table footer
						$tablefooter[$i][$js]['x'] = $x;
						$tablefooter[$i][$js]['y'] = $y;
						$tablefooter[$i][$js]['h'] = $h;
						$tablefooter[$i][$js]['w'] = $w;
						if (isset($cell['textbuffer'])) {
							$tablefooter[$i][$js]['textbuffer'] = $cell['textbuffer'];
						} else {
							$tablefooter[$i][$js]['textbuffer'] = '';
						}
						$tablefooter[$i][$js]['a'] = $cell['a'];
						$tablefooter[$i][$js]['R'] = $cell['R'];
						$tablefooter[$i][$js]['va'] = $cell['va'];
						$tablefooter[$i][$js]['mih'] = $cell['mih'];
						if (isset($cell['gradient'])) {
							$tablefooter[$i][$js]['gradient'] = $cell['gradient']; // *BACKGROUNDS*
						}
						if (isset($cell['background-image'])) {
							$tablefooter[$i][$js]['background-image'] = $cell['background-image']; // *BACKGROUNDS*
						}

						// CELL FILL BGCOLOR
						if (!$this->simpleTables) {
							if ($this->packTableData) {
								$c = $this->_unpackCellBorder($cell['borderbin']);
								$tablefooter[$i][$js]['border'] = $c['border'];
								$tablefooter[$i][$js]['border_details'] = $c['border_details'];
							} else {
								$tablefooter[$i][$js]['border'] = $cell['border'];
								$tablefooter[$i][$js]['border_details'] = $cell['border_details'];
							}
						} elseif ($this->simpleTables) {
							$tablefooter[$i][$js]['border'] = $table['simple']['border'];
							$tablefooter[$i][$js]['border_details'] = $table['simple']['border_details'];
						}
						$tablefooter[$i][$js]['bgcolor'] = $cell['bgcolor'];
						$tablefooter[$i][$js]['padding'] = $cell['padding'];
						if (isset($cell['rowspan'])) {
							$tablefooter[$i][$js]['rowspan'] = $cell['rowspan'];
						}
						if (isset($cell['colspan'])) {
							$tablefooter[$i][$js]['colspan'] = $cell['colspan'];
						}
						if (isset($cell['direction'])) {
							$tablefooter[$i][$js]['direction'] = $cell['direction'];
						}
						if (isset($cell['cellLineHeight'])) {
							$tablefooter[$i][$js]['cellLineHeight'] = $cell['cellLineHeight'];
						}
						if (isset($cell['cellLineStackingStrategy'])) {
							$tablefooter[$i][$js]['cellLineStackingStrategy'] = $cell['cellLineStackingStrategy'];
						}
						if (isset($cell['cellLineStackingShift'])) {
							$tablefooter[$i][$js]['cellLineStackingShift'] = $cell['cellLineStackingShift'];
						}
					}
				}
			}
		}

		if ($level == 1) {
			$this->writer->write('___TABLE___BACKGROUNDS' . $this->uniqstr);
		}
		$tableheaderadj = 0;
		$tablefooteradj = 0;

		$tablestartpageno = $this->page;

		// Draw Table Contents and Borders
		for ($i = 0; $i < $numrows; $i++) { // Rows
			if ($split && $startrow > 0) {
				$thnr = (isset($table['is_thead']) ? count($table['is_thead']) : 0);
				if ($i >= $thnr && $i < $startrow) {
					continue;
				}
				if ($i == $startrow) {
					$returny = $rety - $tableheaderrowheight;
				}
			}

			// Get Maximum row/cell height in row - including rowspan>1 + 1 overlapping
			$maxrowheight = $this->_tableGetMaxRowHeight($table, $i);

			$skippage = false;
			$newpagestarted = false;
			for ($j = $startcol; $j < $numcols; $j++) { // Columns
				if ($split) {
					if ($table['colPg'][$j] > $splitpg) {
						break;
					}
					$lastCol = $j;
				}
				if (isset($cells[$i][$j]) && $cells[$i][$j]) {
					$cell = &$cells[$i][$j];
					if ($split) {
						$lastCol = $j + (isset($cell['colspan']) ? ($cell['colspan'] - 1) : 0);
						list($x, $w) = $this->_splitTableGetWidth($table, $i, $j);
					} else {
						list($x, $w) = $this->_tableGetWidth($table, $i, $j);
					}

					list($y, $h) = $this->_tableGetHeight($table, $i, $j);
					$x += $x0;
					$y += $y0;
					$y -= $returny;

					if ($table['borders_separate']) {
						if (!empty($tablefooter) || $i == ($numrows - 1) || (isset($cell['rowspan']) && ($i + $cell['rowspan']) == $numrows) || (!isset($cell['rowspan']) && ($i + 1) == $numrows)) {
							$extra = $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
							// $extra = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V']/2;
						} else {
							$extra = $table['border_spacing_V'] / 2;
						}
					} else {
						$extra = $table['max_cell_border_width']['B'] / 2;
					}

					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) {
						if (!$skippage) {
							$finalSpread = true;
							$firstSpread = true;
							if ($split) {
								for ($t = $startcol; $t < $numcols; $t++) {
									// Are there more columns to print on a next page?
									if ($table['colPg'][$t] > $splitpg) {
										$finalSpread = false;
										break;
									}
								}
								if ($startcol > 0) {
									$firstSpread = false;
								}
							}

							if (($this->keepColumns || !$this->ColActive) && !empty($tablefooter) && $i > 0) {
								$this->y = $y;
								$ya = $this->y;
								$this->TableHeaderFooter($tablefooter, $tablestartpage, $tablestartcolumn, 'F', $level, $firstSpread, $finalSpread);
								if ($this->table_rotate) {
									$this->tbrot_h += $this->y - $ya;
								}
								$tablefooteradj = $this->y - $ya;
							}
							$y -= $y0;
							$returny += $y;

							$oldcolumn = $this->CurrCol;
							if ($this->AcceptPageBreak()) {
								$newpagestarted = true;
								$this->y = $y + $y0;

								// Move down to account for border-spacing or
								// extra half border width in case page breaks in middle
								if ($i > 0 && !$this->table_rotate && $level == 1 && !$this->ColActive) {
									if ($table['borders_separate']) {
										$adv = $table['border_spacing_V'] / 2;
										// If table footer
										if (($this->keepColumns || !$this->ColActive) && !empty($tablefooter) && $i > 0) {
											$adv += ($table['padding']['B'] + $table['border_details']['B']['w']);
										}
									} else {
										$maxbwtop = 0;
										$maxbwbottom = 0;
										if (!$this->simpleTables) {
											if (!empty($tablefooter)) {
												$maxbwbottom = $table['max_cell_border_width']['B'];
											} else {
												$brow = $i - 1;
												for ($ctj = 0; $ctj < $numcols; $ctj++) {
													if (isset($cells[$brow][$ctj]) && $cells[$brow][$ctj]) {
														if ($this->packTableData) {
															list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cells[$brow][$ctj]['borderbin']);
														} else {
															$bb = $cells[$brow][$ctj]['border_details']['B']['w'];
														}
														$maxbwbottom = max($maxbwbottom, $bb);
													}
												}
											}
											if (!empty($tableheader)) {
												$maxbwtop = $table['max_cell_border_width']['T'];
											} else {
												$trow = $i - 1;
												for ($ctj = 0; $ctj < $numcols; $ctj++) {
													if (isset($cells[$trow][$ctj]) && $cells[$trow][$ctj]) {
														if ($this->packTableData) {
															list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cells[$trow][$ctj]['borderbin']);
														} else {
															$bt = $cells[$trow][$ctj]['border_details']['T']['w'];
														}
														$maxbwtop = max($maxbwtop, $bt);
													}
												}
											}
										} elseif ($this->simpleTables) {
											$maxbwtop = $table['simple']['border_details']['T']['w'];
											$maxbwbottom = $table['simple']['border_details']['B']['w'];
										}
										$adv = $maxbwbottom / 2;
									}
									$this->y += $adv;
								}

								// Rotated table split over pages - needs this->y for borders/backgrounds
								if ($i > 0 && $this->table_rotate && $level == 1) {
									// 		$this->y = $y0 + $this->tbrot_w;
								}

								if ($this->tableClipPath) {
									$this->writer->write("Q");
								}

								$bx = $x0;
								$by = $y0;

								if ($table['borders_separate']) {
									$bx -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['border_spacing_H'] / 2);
									if ($tablestartpageno != $this->page) { // IF already broken across a previous pagebreak
										$by += $table['max_cell_border_width']['T'] / 2;
										if (empty($tableheader)) {
											$by -= ($table['border_spacing_V'] / 2);
										}
									} else {
										$by -= ($table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2);
									}
								} elseif ($tablestartpageno != $this->page && !empty($tableheader)) {
									$by += $maxbwtop / 2;
								}

								$by -= $tableheaderadj;
								$bh = $this->y - $by + $tablefooteradj;
								if (!$table['borders_separate']) {
									$bh -= $adv;
								}
								if ($split) {
									$bw = 0;
									for ($t = $startcol; $t < $numcols; $t++) {
										if ($table['colPg'][$t] == $splitpg) {
											$bw += $table['wc'][$t];
										}
										if ($table['colPg'][$t] > $splitpg) {
											break;
										}
									}
									if ($table['borders_separate']) {
										if ($firstSpread) {
											$bw += $table['padding']['L'] + $table['border_details']['L']['w'] + $table['border_spacing_H'];
										} else {
											$bx += ($table['padding']['L'] + $table['border_details']['L']['w']);
											$bw += $table['border_spacing_H'];
										}
										if ($finalSpread) {
											$bw += $table['padding']['R'] + $table['border_details']['R']['w'] / 2 + $table['border_spacing_H'];
										}
									}
								} else {
									$bw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
								}

								if ($this->splitTableBorderWidth && ($this->keepColumns || !$this->ColActive) && empty($tablefooter) && $i > 0 && $table['border_details']['B']['w']) {
									$prevDrawColor = $this->DrawColor;
									$lw = $this->LineWidth;
									$this->SetLineWidth($this->splitTableBorderWidth);
									$this->SetDColor($table['border_details']['B']['c']);
									$this->SetLineJoin(0);
									$this->SetLineCap(0);
									$blx = $bx;
									$blw = $bw;
									if (!$table['borders_separate']) {
										$blx -= ($table['max_cell_border_width']['L'] / 2);
										$blw += ($table['max_cell_border_width']['L'] / 2 + $table['max_cell_border_width']['R'] / 2);
									}
									$this->Line($blx, $this->y + ($this->splitTableBorderWidth / 2), $blx + $blw, $this->y + ($this->splitTableBorderWidth / 2));
									$this->DrawColor = $prevDrawColor;
									$this->writer->write($this->DrawColor);
									$this->SetLineWidth($lw);
									$this->SetLineJoin(2);
									$this->SetLineCap(2);
								}

								if (!$this->ColActive && ($i > 0 || $j > 0)) {
									if (isset($table['bgcolor'][-1])) {
										$color = $this->colorConverter->convert($table['bgcolor'][-1], $this->PDFAXwarnings);
										if ($color) {
											if (!$table['borders_separate']) {
												$bh -= $table['max_cell_border_width']['B'] / 2;
											}
											$this->tableBackgrounds[$level * 9][] = ['gradient' => false, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'col' => $color];
										}
									}

									/* -- BACKGROUNDS -- */
									if (isset($table['gradient'])) {
										$g = $this->gradient->parseBackgroundGradient($table['gradient']);
										if ($g) {
											$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' => ''];
										}
									}

									if (isset($table['background-image'])) {
										if ($table['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $table['background-image']['gradient'])) {
											$g = $this->gradient->parseMozGradient($table['background-image']['gradient']);
											if ($g) {
												$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' => ''];
											}
										} else {
											$image_id = $table['background-image']['image_id'];
											$orig_w = $table['background-image']['orig_w'];
											$orig_h = $table['background-image']['orig_h'];
											$x_pos = $table['background-image']['x_pos'];
											$y_pos = $table['background-image']['y_pos'];
											$x_repeat = $table['background-image']['x_repeat'];
											$y_repeat = $table['background-image']['y_repeat'];
											$resize = $table['background-image']['resize'];
											$opacity = $table['background-image']['opacity'];
											$itype = $table['background-image']['itype'];
											$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];
										}
									}
									/* -- END BACKGROUNDS -- */
								}

								// $this->AcceptPageBreak() has moved tablebuffer to $this->pages content
								if ($this->tableBackgrounds) {
									$s = $this->PrintTableBackgrounds();
									if ($this->bufferoutput) {
										$this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->headerbuffer);
										$this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->headerbuffer);
									} else {
										$this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
										$this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->pages[$this->page]);
									}
									$this->tableBackgrounds = [];
								}

								if ($split) {
									if ($i == 0 && $j == 0) {
										$y0 = -1;
									} elseif ($finalSpread) {
										$splitpg = 0;
										$startcol = 0;
										$startrow = $i;
									} else {
										$splitpg++;
										$startcol = $t;
										$returny -= $y;
									}
									return [false, $startrow, $startcol, $splitpg, $returny, $y0];
								}

								$this->AddPage($this->CurOrientation);

								$this->writer->write('___TABLE___BACKGROUNDS' . $this->uniqstr);


								if ($this->tableClipPath) {
									$this->writer->write($this->tableClipPath);
								}

								// Added to correct for OddEven Margins
								$x = $x + $this->MarginCorrection;
								$x0 = $x0 + $this->MarginCorrection;

								if ($this->splitTableBorderWidth && ($this->keepColumns || !$this->ColActive) && empty($tableheader) && $i > 0 && $table['border_details']['T']['w']) {
									$prevDrawColor = $this->DrawColor;
									$lw = $this->LineWidth;
									$this->SetLineWidth($this->splitTableBorderWidth);
									$this->SetDColor($table['border_details']['T']['c']);
									$this->SetLineJoin(0);
									$this->SetLineCap(0);
									$blx += $this->MarginCorrection;
									$this->Line($blx, $this->y - ($this->splitTableBorderWidth / 2), $blx + $blw, $this->y - ($this->splitTableBorderWidth / 2));
									$this->DrawColor = $prevDrawColor;
									$this->writer->write($this->DrawColor);
									$this->SetLineWidth($lw);
									$this->SetLineJoin(2);
									$this->SetLineCap(2);
								}

								// Move down to account for half of top border-spacing or
								// extra half border width in case page was broken in middle
								if ($i > 0 && !$this->table_rotate && $level == 1 && $table['headernrows'] == 0) {
									if ($table['borders_separate']) {
										$adv = $table['border_spacing_V'] / 2;
									} else {
										$maxbwtop = 0;
										for ($ctj = 0; $ctj < $numcols; $ctj++) {
											if (isset($cells[$i][$ctj]) && $cells[$i][$ctj]) {
												if (!$this->simpleTables) {
													if ($this->packTableData) {
														list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cells[$i][$ctj]['borderbin']);
													} else {
														$bt = $cells[$i][$ctj]['border_details']['T']['w'];
													}
													$maxbwtop = max($maxbwtop, $bt);
												} elseif ($this->simpleTables) {
													$maxbwtop = max($maxbwtop, $table['simple']['border_details']['T']['w']);
												}
											}
										}
										$adv = $maxbwtop / 2;
									}
									$this->y += $adv;
								}


								if ($this->table_rotate) {
									$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'];
									if ($table['borders_separate']) {
										$this->tbrot_h = $table['margin']['T'] + $table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2;
									} else {
										$this->tbrot_h = $table['margin']['T'] + $table['max_cell_border_width']['T'];
									}
									$this->tbrot_y0 = $this->y;
									$pagetrigger = $y0 - $tableheaderadj + ($this->blk[$this->blklvl]['inner_width']);
								} else {
									$pagetrigger = $this->PageBreakTrigger;
								}

								if ($this->kwt_saved && $level == 1) {
									$this->kwt_moved = true;
								}


								if (!empty($tableheader)) {
									$ya = $this->y;
									$this->TableHeaderFooter($tableheader, $tablestartpage, $tablestartcolumn, 'H', $level);
									if ($this->table_rotate) {
										$this->tbrot_h = $this->y - $ya;
									}
									$tableheaderadj = $this->y - $ya;
								} elseif ($i == 0 && !$this->table_rotate && $level == 1 && !$this->ColActive) {
									// Advance down page
									if ($table['borders_separate']) {
										$adv = $table['border_spacing_V'] / 2 + $table['border_details']['T']['w'] + $table['padding']['T'];
									} else {
										$adv = $table['max_cell_border_width']['T'] / 2;
									}
									if ($adv) {
										if ($this->table_rotate) {
											$this->y += ($adv);
										} else {
											$this->DivLn($adv, $this->blklvl, true);
										}
									}
								}

								$outerfilled = 0;
								$y = $y0 = $this->y;
							}

							/* -- COLUMNS -- */
							// COLS
							// COLUMN CHANGE
							if ($this->CurrCol != $oldcolumn) {
								// Added to correct for Columns
								$x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
								$x0 += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
								if ($this->CurrCol == 0) {  // just added a page - possibly with tableheader
									$y0 = $this->y;  // this->y0 is global used by Columns - $y0 is internal to tablewrite
								} else {
									$y0 = $this->y0;  // this->y0 is global used by Columns - $y0 is internal to tablewrite
								}
								$y = $y0;
								$outerfilled = 0;
								if ($this->CurrCol != 0 && ($this->keepColumns && $this->ColActive) && !empty($tableheader) && $i > 0) {
									$this->x = $x;
									$this->y = $y;
									$this->TableHeaderFooter($tableheader, $tablestartpage, $tablestartcolumn, 'H', $level);
									$y0 = $y = $this->y;
								}
							}
							/* -- END COLUMNS -- */
						}
						$skippage = true;
					}

					$this->x = $x;
					$this->y = $y;

					if ($this->kwt_saved && $level == 1) {
						$this->printkwtbuffer();
						$x0 = $x = $this->x;
						$y0 = $y = $this->y;
						$this->kwt_moved = false;
						$this->kwt_saved = false;
					}


					// Set the Page & Column where table actually starts
					if ($i == 0 && $j == 0 && $level == 1) {
						if (($this->mirrorMargins) && (($this->page) % 2 == 0)) {    // EVEN
							$tablestartpage = 'EVEN';
						} elseif (($this->mirrorMargins) && (($this->page) % 2 == 1)) {    // ODD
							$tablestartpage = 'ODD';
						} else {
							$tablestartpage = '';
						}
						$tablestartpageno = $this->page;
						if ($this->ColActive) {
							$tablestartcolumn = $this->CurrCol;
						} // *COLUMNS*
					}

					// ALIGN
					$align = $cell['a'];

					/* -- COLUMNS -- */
					// If outside columns, this is done in PaintDivBB
					if ($this->ColActive) {
						// OUTER FILL BGCOLOR of DIVS
						if ($this->blklvl > 0 && ($j == 0) && !$this->table_rotate && $level == 1) {
							$firstblockfill = $this->GetFirstBlockFill();
							if ($firstblockfill && $this->blklvl >= $firstblockfill) {
								$divh = $maxrowheight;
								// Last row
								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)))) {
									if ($table['borders_separate']) {
										$adv = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
									} else {
										$adv = $table['margin']['B'] + $table['max_cell_border_width']['B'] / 2;
									}
									$divh += $adv;  // last row: fill bottom half of bottom border (y advanced at end)
								}

								if (($this->y + $divh) > $outerfilled) { // if not already painted by previous rowspan
									$bak_x = $this->x;
									$bak_y = $this->y;
									if ($outerfilled > $this->y) {
										$divh = ($this->y + $divh) - $outerfilled;
										$this->y = $outerfilled;
									}

									$this->DivLn($divh, -3, false);
									$outerfilled = $this->y + $divh;
									// Reset current block fill
									$bcor = $this->blk[$this->blklvl]['bgcolorarray'];
									if ($bcor) {
										$this->SetFColor($bcor);
									}
									$this->x = $bak_x;
									$this->y = $bak_y;
								}
							}
						}
					}

					// TABLE BACKGROUND FILL BGCOLOR - for cellSpacing
					if ($this->ColActive) {
						if ($table['borders_separate']) {
							$fill = isset($table['bgcolor'][-1]) ? $table['bgcolor'][-1] : 0;
							if ($fill) {
								$color = $this->colorConverter->convert($fill, $this->PDFAXwarnings);
								if ($color) {
									$xadj = ($table['border_spacing_H'] / 2);
									$yadj = ($table['border_spacing_V'] / 2);
									$wadj = $table['border_spacing_H'];
									$hadj = $table['border_spacing_V'];
									if ($i == 0) {  // Top
										$yadj += $table['padding']['T'] + $table['border_details']['T']['w'];
										$hadj += $table['padding']['T'] + $table['border_details']['T']['w'];
									}
									if ($j == 0) {  // Left
										$xadj += $table['padding']['L'] + $table['border_details']['L']['w'];
										$wadj += $table['padding']['L'] + $table['border_details']['L']['w'];
									}
									if ($i == ($numrows - 1) || (isset($cell['rowspan']) && ($i + $cell['rowspan']) == $numrows) || (!isset($cell['rowspan']) && ($i + 1) == $numrows)) { // Bottom
										$hadj += $table['padding']['B'] + $table['border_details']['B']['w'];
									}
									if ($j == ($numcols - 1) || (isset($cell['colspan']) && ($j + $cell['colspan']) == $numcols) || (!isset($cell['colspan']) && ($j + 1) == $numcols)) { // Right
										$wadj += $table['padding']['R'] + $table['border_details']['R']['w'];
									}
									$this->SetFColor($color);
									$this->Rect($x - $xadj, $y - $yadj, $w + $wadj, $h + $hadj, 'F');
								}
							}
						}
					}
					/* -- END COLUMNS -- */

					if ($table['empty_cells'] != 'hide' || !empty($cell['textbuffer']) || (isset($cell['nestedcontent']) && $cell['nestedcontent']) || !$table['borders_separate']) {
						$paintcell = true;
					} else {
						$paintcell = false;
					}

					// Set Borders
					$bord = 0;
					$bord_det = [];

					if (!$this->simpleTables) {
						if ($this->packTableData) {
							$c = $this->_unpackCellBorder($cell['borderbin']);
							$bord = $c['border'];
							$bord_det = $c['border_details'];
						} else {
							$bord = $cell['border'];
							$bord_det = $cell['border_details'];
						}
					} elseif ($this->simpleTables) {
						$bord = $table['simple']['border'];
						$bord_det = $table['simple']['border_details'];
					}

					// TABLE ROW OR CELL FILL BGCOLOR
					$fill = 0;
					if (isset($cell['bgcolor']) && $cell['bgcolor'] && $cell['bgcolor'] != 'transparent') {
						$fill = $cell['bgcolor'];
						$leveladj = 6;
					} elseif (isset($table['bgcolor'][$i]) && $table['bgcolor'][$i] && $table['bgcolor'][$i] != 'transparent') { // Row color
						$fill = $table['bgcolor'][$i];
						$leveladj = 3;
					}
					if ($fill && $paintcell) {
						$color = $this->colorConverter->convert($fill, $this->PDFAXwarnings);
						if ($color) {
							if ($table['borders_separate']) {
								if ($this->ColActive) {
									$this->SetFColor($color);
									$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');
								} else {
									$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];
								}
							} else {
								if ($this->ColActive) {
									$this->SetFColor($color);
									$this->Rect($x, $y, $w, $h, 'F');
								} else {
									$this->tableBackgrounds[$level * 9 + $leveladj][] = ['gradient' => false, 'x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'col' => $color];
								}
							}
						}
					}

					/* -- BACKGROUNDS -- */
					if (isset($cell['gradient']) && $cell['gradient'] && $paintcell) {
						$g = $this->gradient->parseBackgroundGradient($cell['gradient']);
						if ($g) {
							if ($table['borders_separate']) {
								$px = $x + ($table['border_spacing_H'] / 2);
								$py = $y + ($table['border_spacing_V'] / 2);
								$pw = $w - $table['border_spacing_H'];
								$ph = $h - $table['border_spacing_V'];
							} else {
								$px = $x;
								$py = $y;
								$pw = $w;
								$ph = $h;
							}
							if ($this->ColActive) {
								$this->gradient->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
							} else {
								$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' => ''];
							}
						}
					}

					if (isset($cell['background-image']) && $paintcell) {
						if (isset($cell['background-image']['gradient']) && $cell['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $cell['background-image']['gradient'])) {
							$g = $this->gradient->parseMozGradient($cell['background-image']['gradient']);
							if ($g) {
								if ($table['borders_separate']) {
									$px = $x + ($table['border_spacing_H'] / 2);
									$py = $y + ($table['border_spacing_V'] / 2);
									$pw = $w - $table['border_spacing_H'];
									$ph = $h - $table['border_spacing_V'];
								} else {
									$px = $x;
									$py = $y;
									$pw = $w;
									$ph = $h;
								}
								if ($this->ColActive) {
									$this->gradient->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
								} else {
									$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' => ''];
								}
							}
						} elseif (isset($cell['background-image']['image_id']) && $cell['background-image']['image_id']) { // Background pattern
							$n = count($this->patterns) + 1;
							if ($table['borders_separate']) {
								$px = $x + ($table['border_spacing_H'] / 2);
								$py = $y + ($table['border_spacing_V'] / 2);
								$pw = $w - $table['border_spacing_H'];
								$ph = $h - $table['border_spacing_V'];
							} else {
								$px = $x;
								$py = $y;
								$pw = $w;
								$ph = $h;
							}
							if ($this->ColActive) {
								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']);
								$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];
								if ($cell['background-image']['opacity'] > 0 && $cell['background-image']['opacity'] < 1) {
									$opac = $this->SetAlpha($cell['background-image']['opacity'], 'Normal', true);
								} else {
									$opac = '';
								}
								$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));
							} else {
								$image_id = $cell['background-image']['image_id'];
								$orig_w = $cell['background-image']['orig_w'];
								$orig_h = $cell['background-image']['orig_h'];
								$x_pos = $cell['background-image']['x_pos'];
								$y_pos = $cell['background-image']['y_pos'];
								$x_repeat = $cell['background-image']['x_repeat'];
								$y_repeat = $cell['background-image']['y_repeat'];
								$resize = $cell['background-image']['resize'];
								$opacity = $cell['background-image']['opacity'];
								$itype = $cell['background-image']['itype'];
								$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];
							}
						}
					}
					/* -- END BACKGROUNDS -- */

					if (isset($cell['colspan']) && $cell['colspan'] > 1) {
						$ccolsp = $cell['colspan'];
					} else {
						$ccolsp = 1;
					}
					if (isset($cell['rowspan']) && $cell['rowspan'] > 1) {
						$crowsp = $cell['rowspan'];
					} else {
						$crowsp = 1;
					}


					// but still need to do this for repeated headers...
					if (!$table['borders_separate'] && $this->tabletheadjustfinished && !$this->simpleTables) {
						if (isset($table['topntail']) && $table['topntail']) {
							$bord_det['T'] = $this->border_details($table['topntail']);
							$bord_det['T']['w'] /= $this->shrin_k;
							$this->setBorder($bord, Border::TOP);
						}
						if (isset($table['thead-underline']) && $table['thead-underline']) {
							$bord_det['T'] = $this->border_details($table['thead-underline']);
							$bord_det['T']['w'] /= $this->shrin_k;
							$this->setBorder($bord, Border::TOP);
						}
					}


					// Get info of first row ==>> table header
					// Use > 1 row if THEAD
					if (isset($table['is_thead'][$i]) && $table['is_thead'][$i] && $level == 1) {
						if ($j == 0) {
							$tableheaderrowheight += $table['hr'][$i];
						}
						$tableheader[$i][0]['trbackground-images'] = (isset($table['trbackground-images'][$i]) ? $table['trbackground-images'][$i] : null);
						$tableheader[$i][0]['trgradients'] = (isset($table['trgradients'][$i]) ? $table['trgradients'][$i] : null);
						$tableheader[$i][0]['trbgcolor'] = (isset($table['bgcolor'][$i]) ? $table['bgcolor'][$i] : null);
						$tableheader[$i][$j]['x'] = $x;
						$tableheader[$i][$j]['y'] = $y;
						$tableheader[$i][$j]['h'] = $h;
						$tableheader[$i][$j]['w'] = $w;
						if (isset($cell['textbuffer'])) {
							$tableheader[$i][$j]['textbuffer'] = $cell['textbuffer'];
						} else {
							$tableheader[$i][$j]['textbuffer'] = '';
						}
						$tableheader[$i][$j]['a'] = $cell['a'];
						$tableheader[$i][$j]['R'] = $cell['R'];

						$tableheader[$i][$j]['va'] = $cell['va'];
						$tableheader[$i][$j]['mih'] = $cell['mih'];
						$tableheader[$i][$j]['gradient'] = (isset($cell['gradient']) ? $cell['gradient'] : null); // *BACKGROUNDS*
						$tableheader[$i][$j]['background-image'] = (isset($cell['background-image']) ? $cell['background-image'] : null); // *BACKGROUNDS*
						$tableheader[$i][$j]['rowspan'] = (isset($cell['rowspan']) ? $cell['rowspan'] : null);
						$tableheader[$i][$j]['colspan'] = (isset($cell['colspan']) ? $cell['colspan'] : null);
						$tableheader[$i][$j]['bgcolor'] = $cell['bgcolor'];

						if (!$this->simpleTables) {
							$tableheader[$i][$j]['border'] = $bord;
							$tableheader[$i][$j]['border_details'] = $bord_det;
						} elseif ($this->simpleTables) {
							$tableheader[$i][$j]['border'] = $table['simple']['border'];
							$tableheader[$i][$j]['border_details'] = $table['simple']['border_details'];
						}
						$tableheader[$i][$j]['padding'] = $cell['padding'];
						if (isset($cell['direction'])) {
							$tableheader[$i][$j]['direction'] = $cell['direction'];
						}
						if (isset($cell['cellLineHeight'])) {
							$tableheader[$i][$j]['cellLineHeight'] = $cell['cellLineHeight'];
						}
						if (isset($cell['cellLineStackingStrategy'])) {
							$tableheader[$i][$j]['cellLineStackingStrategy'] = $cell['cellLineStackingStrategy'];
						}
						if (isset($cell['cellLineStackingShift'])) {
							$tableheader[$i][$j]['cellLineStackingShift'] = $cell['cellLineStackingShift'];
						}
					}

					// CELL BORDER
					if ($bord) {
						if ($table['borders_separate'] && $paintcell) {
							$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']);
						} elseif (!$table['borders_separate']) {
							$this->_tableRect($x, $y, $w, $h, $bord, $bord_det, true, $table['borders_separate']);  // true causes buffer
						}
					}

					// VERTICAL ALIGN
					if ($cell['R'] && intval($cell['R']) > 0 && intval($cell['R']) < 90 && isset($cell['va']) && $cell['va'] != 'B') {
						$cell['va'] = 'B';
					}
					if (!isset($cell['va']) || $cell['va'] == 'M') {
						$this->y += ($h - $cell['mih']) / 2;
					} elseif (isset($cell['va']) && $cell['va'] == 'B') {
						$this->y += $h - $cell['mih'];
					}

					// NESTED CONTENT
					// TEXT (and nested tables)

					$this->divwidth = $w;
					if (!empty($cell['textbuffer'])) {
						$this->cellTextAlign = $align;
						$this->cellLineHeight = $cell['cellLineHeight'];
						$this->cellLineStackingStrategy = $cell['cellLineStackingStrategy'];
						$this->cellLineStackingShift = $cell['cellLineStackingShift'];
						if ($level == 1) {
							if (isset($table['is_tfoot'][$i]) && $table['is_tfoot'][$i]) {
								if (preg_match('/{colsum([0-9]*)[_]*}/', $cell['textbuffer'][0][0], $m)) {
									$rep = sprintf("%01." . intval($m[1]) . "f", $this->colsums[$j]);
									$cell['textbuffer'][0][0] = preg_replace('/{colsum[0-9_]*}/', $rep, $cell['textbuffer'][0][0]);
								}
							} elseif (!isset($table['is_thead'][$i])) {
								if (isset($this->colsums[$j])) {
									$this->colsums[$j] += $this->toFloat($cell['textbuffer'][0][0]);
								} else {
									$this->colsums[$j] = $this->toFloat($cell['textbuffer'][0][0]);
								}
							}
						}
						$opy = $this->y;
						// mPDF ITERATION
						if ($this->iterationCounter) {
							foreach ($cell['textbuffer'] as $k => $t) {
								if (preg_match('/{iteration ([a-zA-Z0-9_]+)}/', $t[0], $m)) {
									$vname = '__' . $m[1] . '_';
									if (!isset($this->$vname)) {
										$this->$vname = 1;
									} else {
										$this->$vname++;
									}
									$cell['textbuffer'][$k][0] = preg_replace('/{iteration ' . $m[1] . '}/', $this->$vname, $cell['textbuffer'][$k][0]);
								}
							}
						}


						if ($cell['R']) {
							$cellPtSize = $cell['textbuffer'][0][11] / $this->shrin_k;
							if (!$cellPtSize) {
								$cellPtSize = $this->default_font_size;
							}
							$cellFontHeight = ($cellPtSize / Mpdf::SCALE);
							$opx = $this->x;
							$angle = intval($cell['R']);
							// Only allow 45 to 89 degrees (when bottom-aligned) or exactly 90 or -90
							if ($angle > 90) {
								$angle = 90;
							} elseif ($angle > 0 && $angle < 45) {
								$angle = 45;
							} elseif ($angle < 0) {
								$angle = -90;
							}
							$offset = ((sin(deg2rad($angle))) * 0.37 * $cellFontHeight);
							if (isset($cell['a']) && $cell['a'] == 'R') {
								$this->x += ($w) + ($offset) - ($cellFontHeight / 3) - ($cell['padding']['R'] + ($table['border_spacing_H'] / 2));
							} elseif (!isset($cell['a']) || $cell['a'] == 'C') {
								$this->x += ($w / 2) + ($offset);
							} else {
								$this->x += ($offset) + ($cellFontHeight / 3) + ($cell['padding']['L'] + ($table['border_spacing_H'] / 2));
							}
							$str = '';
							foreach ($cell['textbuffer'] as $t) {
								$str .= $t[0] . ' ';
							}
							$str = rtrim($str);
							if (!isset($cell['va']) || $cell['va'] == 'M') {
								$this->y -= ($h - $cell['mih']) / 2; // Undo what was added earlier VERTICAL ALIGN
								if ($angle > 0) {
									$this->y += (($h - $cell['mih']) / 2) + $cell['padding']['T'] + ($cell['mih'] - ($cell['padding']['T'] + $cell['padding']['B']));
								} elseif ($angle < 0) {
									$this->y += (($h - $cell['mih']) / 2) + ($cell['padding']['T'] + ($table['border_spacing_V'] / 2));
								}
							} elseif (isset($cell['va']) && $cell['va'] == 'B') {
								$this->y -= $h - $cell['mih']; // Undo what was added earlier VERTICAL ALIGN
								if ($angle > 0) {
									$this->y += $h - ($cell['padding']['B'] + ($table['border_spacing_V'] / 2));
								} elseif ($angle < 0) {
									$this->y += $h - $cell['mih'] + ($cell['padding']['T'] + ($table['border_spacing_V'] / 2));
								}
							} elseif (isset($cell['va']) && $cell['va'] == 'T') {
								if ($angle > 0) {
									$this->y += $cell['mih'] - ($cell['padding']['B'] + ($table['border_spacing_V'] / 2));
								} elseif ($angle < 0) {
									$this->y += ($cell['padding']['T'] + ($table['border_spacing_V'] / 2));
								}
							}
							$this->Rotate($angle, $this->x, $this->y);
							$s_fs = $this->FontSizePt;
							$s_f = $this->FontFamily;
							$s_st = $this->FontStyle;
							if (!empty($cell['textbuffer'][0][3])) { // Font Color
								$cor = $cell['textbuffer'][0][3];
								$this->SetTColor($cor);
							}
							$this->SetFont($cell['textbuffer'][0][4], $cell['textbuffer'][0][2], $cellPtSize, true, true);

							$this->magic_reverse_dir($str, $this->directionality, $cell['textbuffer'][0][18]);
							$this->Text($this->x, $this->y, $str, $cell['textbuffer'][0][18], $cell['textbuffer'][0][8]); // textvar
							$this->Rotate(0);
							$this->SetFont($s_f, $s_st, $s_fs, true, true);
							$this->SetTColor(0);
							$this->x = $opx;
						} else {
							if (!$this->simpleTables) {
								if ($bord_det) {
									$btlw = $bord_det['L']['w'];
									$btrw = $bord_det['R']['w'];
									$bttw = $bord_det['T']['w'];
								} else {
									$btlw = 0;
									$btrw = 0;
									$bttw = 0;
								}
								if ($table['borders_separate']) {
									$xadj = $btlw + $cell['padding']['L'] + ($table['border_spacing_H'] / 2);
									$wadj = $btlw + $btrw + $cell['padding']['L'] + $cell['padding']['R'] + $table['border_spacing_H'];
									$yadj = $bttw + $cell['padding']['T'] + ($table['border_spacing_H'] / 2);
								} else {
									$xadj = $btlw / 2 + $cell['padding']['L'];
									$wadj = ($btlw + $btrw) / 2 + $cell['padding']['L'] + $cell['padding']['R'];
									$yadj = $bttw / 2 + $cell['padding']['T'];
								}
							} elseif ($this->simpleTables) {
								if ($table['borders_separate']) { // NB twice border width
									$xadj = $table['simple']['border_details']['L']['w'] + $cell['padding']['L'] + ($table['border_spacing_H'] / 2);
									$wadj = $table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w'] + $cell['padding']['L'] + $cell['padding']['R'] + $table['border_spacing_H'];
									$yadj = $table['simple']['border_details']['T']['w'] + $cell['padding']['T'] + ($table['border_spacing_H'] / 2);
								} else {
									$xadj = $table['simple']['border_details']['L']['w'] / 2 + $cell['padding']['L'];
									$wadj = ($table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w']) / 2 + $cell['padding']['L'] + $cell['padding']['R'];
									$yadj = $table['simple']['border_details']['T']['w'] / 2 + $cell['padding']['T'];
								}
							}
							$this->decimal_offset = 0;
							if (substr($cell['a'], 0, 1) == 'D') {
								if (isset($cell['colspan']) && $cell['colspan'] > 1) {
									$this->cellTextAlign = $c['a'] = substr($cell['a'], 2, 1);
								} else {
									$smax = $table['decimal_align'][$j]['maxs0'];
									$d_content = $table['decimal_align'][$j]['maxs0'] + $table['decimal_align'][$j]['maxs1'];
									$this->decimal_offset = $smax;
									$extra = ($w - $d_content - $wadj);
									if ($extra > 0) {
										if (substr($cell['a'], 2, 1) == 'R') {
											$this->decimal_offset += $extra;
										} elseif (substr($cell['a'], 2, 1) == 'C') {
											$this->decimal_offset += ($extra) / 2;
										}
									}
								}
							}
							$this->divwidth = $w - $wadj;
							if ($this->divwidth == 0) {
								$this->divwidth = 0.0001;
							}
							$this->x += $xadj;
							$this->y += $yadj;
							$this->printbuffer($cell['textbuffer'], '', true, false, $cell['direction']);
						}
						$this->y = $opy;
					}

					/* -- BACKGROUNDS -- */
					if (!$this->ColActive) {
						if (isset($table['trgradients'][$i]) && ($j == 0 || $table['borders_separate'])) {
							$g = $this->gradient->parseBackgroundGradient($table['trgradients'][$i]);
							if ($g) {
								$gx = $x0;
								$gy = $y;
								$gh = $h;
								$gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
								if ($table['borders_separate']) {
									$gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
									$clx = $x + ($table['border_spacing_H'] / 2);
									$cly = $y + ($table['border_spacing_V'] / 2);
									$clw = $w - $table['border_spacing_H'];
									$clh = $h - $table['border_spacing_V'];
									// Set clipping path
									$s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
									$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];
								} else {
									$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' => ''];
								}
							}
						}
						if (isset($table['trbackground-images'][$i]) && ($j == 0 || $table['borders_separate'])) {
							if (isset($table['trbackground-images'][$i]['gradient']) && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $table['trbackground-images'][$i]['gradient'])) {
								$g = $this->gradient->parseMozGradient($table['trbackground-images'][$i]['gradient']);
								if ($g) {
									$gx = $x0;
									$gy = $y;
									$gh = $h;
									$gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
									if ($table['borders_separate']) {
										$gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
										$clx = $x + ($table['border_spacing_H'] / 2);
										$cly = $y + ($table['border_spacing_V'] / 2);
										$clw = $w - $table['border_spacing_H'];
										$clh = $h - $table['border_spacing_V'];
										// Set clipping path
										$s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
										$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];
									} else {
										$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' => ''];
									}
								}
							} else {
								$image_id = $table['trbackground-images'][$i]['image_id'];
								$orig_w = $table['trbackground-images'][$i]['orig_w'];
								$orig_h = $table['trbackground-images'][$i]['orig_h'];
								$x_pos = $table['trbackground-images'][$i]['x_pos'];
								$y_pos = $table['trbackground-images'][$i]['y_pos'];
								$x_repeat = $table['trbackground-images'][$i]['x_repeat'];
								$y_repeat = $table['trbackground-images'][$i]['y_repeat'];
								$resize = $table['trbackground-images'][$i]['resize'];
								$opacity = $table['trbackground-images'][$i]['opacity'];
								$itype = $table['trbackground-images'][$i]['itype'];
								$clippath = '';
								$gx = $x0;
								$gy = $y;
								$gh = $h;
								$gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
								if ($table['borders_separate']) {
									$gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
									$clx = $x + ($table['border_spacing_H'] / 2);
									$cly = $y + ($table['border_spacing_V'] / 2);
									$clw = $w - $table['border_spacing_H'];
									$clh = $h - $table['border_spacing_V'];
									// Set clipping path
									$s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
									$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];
								} else {
									$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];
								}
							}
						}
					}

					/* -- END BACKGROUNDS -- */

					// TABLE BORDER - if separate
					if (($table['borders_separate'] || ($this->simpleTables && !$table['simple']['border'])) && $table['border']) {
						$halfspaceL = $table['padding']['L'] + ($table['border_spacing_H'] / 2);
						$halfspaceR = $table['padding']['R'] + ($table['border_spacing_H'] / 2);
						$halfspaceT = $table['padding']['T'] + ($table['border_spacing_V'] / 2);
						$halfspaceB = $table['padding']['B'] + ($table['border_spacing_V'] / 2);
						$tbx = $x;
						$tby = $y;
						$tbw = $w;
						$tbh = $h;
						$tab_bord = 0;

						$corner = '';
						if ($i == 0) {  // Top
							$tby -= $halfspaceT + ($table['border_details']['T']['w'] / 2);
							$tbh += $halfspaceT + ($table['border_details']['T']['w'] / 2);
							$this->setBorder($tab_bord, Border::TOP);
							$corner .= 'T';
						}
						if ($i == ($numrows - 1) || (isset($cell['rowspan']) && ($i + $cell['rowspan']) == $numrows)) { // Bottom
							$tbh += $halfspaceB + ($table['border_details']['B']['w'] / 2);
							$this->setBorder($tab_bord, Border::BOTTOM);
							$corner .= 'B';
						}
						if ($j == 0) {  // Left
							$tbx -= $halfspaceL + ($table['border_details']['L']['w'] / 2);
							$tbw += $halfspaceL + ($table['border_details']['L']['w'] / 2);
							$this->setBorder($tab_bord, Border::LEFT);
							$corner .= 'L';
						}
						if ($j == ($numcols - 1) || (isset($cell['colspan']) && ($j + $cell['colspan']) == $numcols)) { // Right
							$tbw += $halfspaceR + ($table['border_details']['R']['w'] / 2);
							$this->setBorder($tab_bord, Border::RIGHT);
							$corner .= 'R';
						}
						$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']);
					}

					unset($cell);
					// Reset values
					$this->Reset();
				}//end of (if isset(cells)...)
			}// end of columns

			$newpagestarted = false;
			$this->tabletheadjustfinished = false;

			/* -- COLUMNS -- */
			if ($this->ColActive) {
				if (!$this->table_keep_together && $i < $numrows - 1 && $level == 1) {
					$this->breakpoints[$this->CurrCol][] = $y + $h;
				} // mPDF 6
				if (count($this->cellBorderBuffer)) {
					$this->printcellbuffer();
				}
			}
			/* -- END COLUMNS -- */

			if ($i == $numrows - 1) {
				$this->y = $y + $h;
			} // last row jump (update this->y position)
			if ($this->table_rotate && $level == 1) {
				$this->tbrot_h += $h;
			}
		} // end of rows

		if (count($this->cellBorderBuffer)) {
			$this->printcellbuffer();
		}


		if ($this->tableClipPath) {
			$this->writer->write("Q");
		}
		$this->tableClipPath = '';

		// Advance down page by half width of bottom border
		if ($table['borders_separate']) {
			$this->y += $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
		} else {
			$this->y += $table['max_cell_border_width']['B'] / 2;
		}

		if ($table['borders_separate'] && $level == 1) {
			$this->tbrot_h += $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
		} elseif ($level == 1) {
			$this->tbrot_h += $table['margin']['B'] + $table['max_cell_border_width']['B'] / 2;
		}

		$bx = $x0;
		$by = $y0;
		if ($table['borders_separate']) {
			$bx -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['border_spacing_H'] / 2);
			if ($tablestartpageno != $this->page) { // IF broken across page
				$by += $table['max_cell_border_width']['T'] / 2;
				if (empty($tableheader)) {
					$by -= ($table['border_spacing_V'] / 2);
				}
			} elseif ($split && $startrow > 0 && empty($tableheader)) {
				$by -= ($table['border_spacing_V'] / 2);
			} else {
				$by -= ($table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2);
			}
		} elseif ($tablestartpageno != $this->page && !empty($tableheader)) {
			$by += $maxbwtop / 2;
		}
		$by -= $tableheaderadj;
		$bh = $this->y - $by;
		if (!$table['borders_separate']) {
			$bh -= $table['max_cell_border_width']['B'] / 2;
		}

		if ($split) {
			$bw = 0;
			$finalSpread = true;
			for ($t = $startcol; $t < $numcols; $t++) {
				if ($table['colPg'][$t] == $splitpg) {
					$bw += $table['wc'][$t];
				}
				if ($table['colPg'][$t] > $splitpg) {
					$finalSpread = false;
					break;
				}
			}
			if ($startcol == 0) {
				$firstSpread = true;
			} else {
				$firstSpread = false;
			}
			if ($table['borders_separate']) {
				$bw += $table['border_spacing_H'];
				if ($firstSpread) {
					$bw += $table['padding']['L'] + $table['border_details']['L']['w'];
				} else {
					$bx += ($table['padding']['L'] + $table['border_details']['L']['w']);
				}
				if ($finalSpread) {
					$bw += $table['padding']['R'] + $table['border_details']['R']['w'];
				}
			}
		} else {
			$bw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
		}

		if (!$this->ColActive) {
			if (isset($table['bgcolor'][-1])) {
				$color = $this->colorConverter->convert($table['bgcolor'][-1], $this->PDFAXwarnings);
				if ($color) {
					$this->tableBackgrounds[$level * 9][] = ['gradient' => false, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'col' => $color];
				}
			}

			/* -- BACKGROUNDS -- */
			if (isset($table['gradient'])) {
				$g = $this->gradient->parseBackgroundGradient($table['gradient']);
				if ($g) {
					$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' => ''];
				}
			}

			if (isset($table['background-image'])) {
				if (isset($table['background-image']['gradient']) && $table['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $table['background-image']['gradient'])) {
					$g = $this->gradient->parseMozGradient($table['background-image']['gradient']);
					if ($g) {
						$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' => ''];
					}
				} else {
					$image_id = $table['background-image']['image_id'];
					$orig_w = $table['background-image']['orig_w'];
					$orig_h = $table['background-image']['orig_h'];
					$x_pos = $table['background-image']['x_pos'];
					$y_pos = $table['background-image']['y_pos'];
					$x_repeat = $table['background-image']['x_repeat'];
					$y_repeat = $table['background-image']['y_repeat'];
					$resize = $table['background-image']['resize'];
					$opacity = $table['background-image']['opacity'];
					$itype = $table['background-image']['itype'];
					$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];
				}
			}
			/* -- END BACKGROUNDS -- */
		}

		if ($this->tableBackgrounds && $level == 1) {
			$s = $this->PrintTableBackgrounds();
			if ($this->table_rotate && !$this->processingHeader && !$this->processingFooter) {
				$this->tablebuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->tablebuffer);
				if ($level == 1) {
					$this->tablebuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->tablebuffer);
				}
			} elseif ($this->bufferoutput) {
				$this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->headerbuffer);
				if ($level == 1) {
					$this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->headerbuffer);
				}
			} else {
				$this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
				if ($level == 1) {
					$this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->pages[$this->page]);
				}
			}
			$this->tableBackgrounds = [];
		}


		// TABLE BOTTOM MARGIN
		if ($table['margin']['B']) {
			if (!$this->table_rotate && $level == 1) {
				$this->DivLn($table['margin']['B'], $this->blklvl, true);  // collapsible
			} else {
				$this->y += ($table['margin']['B']);
			}
		}

		if ($this->ColActive && $level == 1) {
			$this->breakpoints[$this->CurrCol][] = $this->y;
		} // *COLUMNS*

		if ($split) {
			// Are there more columns to print on a next page?
			if ($lastCol < $numcols - 1) {
				$splitpg++;
				$startcol = $lastCol + 1;
				return [false, $startrow, $startcol, $splitpg, $returny, $y0];
			} else {
				return [true, 0, 0, 0, false, false];
			}
		}
	}

	// END OF FUNCTION _tableWrite()
	/////////////////////////END OF TABLE CODE//////////////////////////////////
	/* -- END TABLES -- */

	function _putextgstates()
	{
		for ($i = 1; $i <= count($this->extgstates); $i++) {
			$this->writer->object();
			$this->extgstates[$i]['n'] = $this->n;
			$this->writer->write('<</Type /ExtGState');
			foreach ($this->extgstates[$i]['parms'] as $k => $v) {
				$this->writer->write('/' . $k . ' ' . $v);
			}
			$this->writer->write('>>');
			$this->writer->write('endobj');
		}
	}

	function SetProtection($permissions = [], $user_pass = '', $owner_pass = null, $length = 40)
	{
		$this->encrypted = $this->protection->setProtection($permissions, $user_pass, $owner_pass, $length);
	}

	// =========================================
	// FROM class PDF_Bookmark
	function Bookmark($txt, $level = 0, $y = 0)
	{
		$txt = $this->purify_utf8_text($txt);
		if ($this->text_input_as_HTML) {
			$txt = $this->all_entities_to_utf8($txt);
		}
		if ($y == -1) {
			if (!$this->ColActive) {
				$y = $this->y;
			} else {
				$y = $this->y0;
			} // If columns are on - mark top of columns
		}

		// else y is used as set, or =0 i.e. top of page
		// DIRECTIONALITY RTL
		$bmo = ['t' => $txt, 'l' => $level, 'y' => $y, 'p' => $this->page];

		if ($this->keep_block_together) {
			// do nothing
		} elseif ($this->table_rotate) {
			$this->tbrot_BMoutlines[] = $bmo;
		} elseif ($this->kwt) {
			$this->kwt_BMoutlines[] = $bmo;
		} elseif ($this->ColActive) {
			$this->col_BMoutlines[] = $bmo;
		} else {
			$this->BMoutlines[] = $bmo;
		}
	}

	/**
	 * Initiate, and Mark a place for the Table of Contents to be inserted
	 */
	function TOC(
		$tocfont = '',
		$tocfontsize = 0,
		$tocindent = 0,
		$resetpagenum = '',
		$pagenumstyle = '',
		$suppress = '',
		$toc_orientation = '',
		$TOCusePaging = true,
		$TOCuseLinking = false,
		$toc_id = 0,
		$tocoutdent = ''
	) {

		$this->tableOfContents->TOC(
			$tocfont,
			$tocfontsize,
			$tocindent,
			$resetpagenum,
			$pagenumstyle,
			$suppress,
			$toc_orientation,
			$TOCusePaging,
			$TOCuseLinking,
			$toc_id,
			$tocoutdent
		);
	}

	function TOCpagebreakByArray($a)
	{
		if (!is_array($a)) {
			$a = [];
		}
		$tocoutdent = (isset($a['tocoutdent']) ? $a['tocoutdent'] : (isset($a['outdent']) ? $a['outdent'] : ''));
		$TOCusePaging = (isset($a['TOCusePaging']) ? $a['TOCusePaging'] : (isset($a['paging']) ? $a['paging'] : true));
		$TOCuseLinking = (isset($a['TOCuseLinking']) ? $a['TOCuseLinking'] : (isset($a['links']) ? $a['links'] : ''));
		$toc_orientation = (isset($a['toc_orientation']) ? $a['toc_orientation'] : (isset($a['toc-orientation']) ? $a['toc-orientation'] : ''));
		$toc_mgl = (isset($a['toc_mgl']) ? $a['toc_mgl'] : (isset($a['toc-margin-left']) ? $a['toc-margin-left'] : ''));
		$toc_mgr = (isset($a['toc_mgr']) ? $a['toc_mgr'] : (isset($a['toc-margin-right']) ? $a['toc-margin-right'] : ''));
		$toc_mgt = (isset($a['toc_mgt']) ? $a['toc_mgt'] : (isset($a['toc-margin-top']) ? $a['toc-margin-top'] : ''));
		$toc_mgb = (isset($a['toc_mgb']) ? $a['toc_mgb'] : (isset($a['toc-margin-bottom']) ? $a['toc-margin-bottom'] : ''));
		$toc_mgh = (isset($a['toc_mgh']) ? $a['toc_mgh'] : (isset($a['toc-margin-header']) ? $a['toc-margin-header'] : ''));
		$toc_mgf = (isset($a['toc_mgf']) ? $a['toc_mgf'] : (isset($a['toc-margin-footer']) ? $a['toc-margin-footer'] : ''));
		$toc_ohname = (isset($a['toc_ohname']) ? $a['toc_ohname'] : (isset($a['toc-odd-header-name']) ? $a['toc-odd-header-name'] : ''));
		$toc_ehname = (isset($a['toc_ehname']) ? $a['toc_ehname'] : (isset($a['toc-even-header-name']) ? $a['toc-even-header-name'] : ''));
		$toc_ofname = (isset($a['toc_ofname']) ? $a['toc_ofname'] : (isset($a['toc-odd-footer-name']) ? $a['toc-odd-footer-name'] : ''));
		$toc_efname = (isset($a['toc_efname']) ? $a['toc_efname'] : (isset($a['toc-even-footer-name']) ? $a['toc-even-footer-name'] : ''));
		$toc_ohvalue = (isset($a['toc_ohvalue']) ? $a['toc_ohvalue'] : (isset($a['toc-odd-header-value']) ? $a['toc-odd-header-value'] : 0));
		$toc_ehvalue = (isset($a['toc_ehvalue']) ? $a['toc_ehvalue'] : (isset($a['toc-even-header-value']) ? $a['toc-even-header-value'] : 0));
		$toc_ofvalue = (isset($a['toc_ofvalue']) ? $a['toc_ofvalue'] : (isset($a['toc-odd-footer-value']) ? $a['toc-odd-footer-value'] : 0));
		$toc_efvalue = (isset($a['toc_efvalue']) ? $a['toc_efvalue'] : (isset($a['toc-even-footer-value']) ? $a['toc-even-footer-value'] : 0));
		$toc_preHTML = (isset($a['toc_preHTML']) ? $a['toc_preHTML'] : (isset($a['toc-preHTML']) ? $a['toc-preHTML'] : ''));
		$toc_postHTML = (isset($a['toc_postHTML']) ? $a['toc_postHTML'] : (isset($a['toc-postHTML']) ? $a['toc-postHTML'] : ''));
		$toc_bookmarkText = (isset($a['toc_bookmarkText']) ? $a['toc_bookmarkText'] : (isset($a['toc-bookmarkText']) ? $a['toc-bookmarkText'] : ''));
		$resetpagenum = (isset($a['resetpagenum']) ? $a['resetpagenum'] : '');
		$pagenumstyle = (isset($a['pagenumstyle']) ? $a['pagenumstyle'] : '');
		$suppress = (isset($a['suppress']) ? $a['suppress'] : '');
		$orientation = (isset($a['orientation']) ? $a['orientation'] : '');
		$mgl = (isset($a['mgl']) ? $a['mgl'] : (isset($a['margin-left']) ? $a['margin-left'] : ''));
		$mgr = (isset($a['mgr']) ? $a['mgr'] : (isset($a['margin-right']) ? $a['margin-right'] : ''));
		$mgt = (isset($a['mgt']) ? $a['mgt'] : (isset($a['margin-top']) ? $a['margin-top'] : ''));
		$mgb = (isset($a['mgb']) ? $a['mgb'] : (isset($a['margin-bottom']) ? $a['margin-bottom'] : ''));
		$mgh = (isset($a['mgh']) ? $a['mgh'] : (isset($a['margin-header']) ? $a['margin-header'] : ''));
		$mgf = (isset($a['mgf']) ? $a['mgf'] : (isset($a['margin-footer']) ? $a['margin-footer'] : ''));
		$ohname = (isset($a['ohname']) ? $a['ohname'] : (isset($a['odd-header-name']) ? $a['odd-header-name'] : ''));
		$ehname = (isset($a['ehname']) ? $a['ehname'] : (isset($a['even-header-name']) ? $a['even-header-name'] : ''));
		$ofname = (isset($a['ofname']) ? $a['ofname'] : (isset($a['odd-footer-name']) ? $a['odd-footer-name'] : ''));
		$efname = (isset($a['efname']) ? $a['efname'] : (isset($a['even-footer-name']) ? $a['even-footer-name'] : ''));
		$ohvalue = (isset($a['ohvalue']) ? $a['ohvalue'] : (isset($a['odd-header-value']) ? $a['odd-header-value'] : 0));
		$ehvalue = (isset($a['ehvalue']) ? $a['ehvalue'] : (isset($a['even-header-value']) ? $a['even-header-value'] : 0));
		$ofvalue = (isset($a['ofvalue']) ? $a['ofvalue'] : (isset($a['odd-footer-value']) ? $a['odd-footer-value'] : 0));
		$efvalue = (isset($a['efvalue']) ? $a['efvalue'] : (isset($a['even-footer-value']) ? $a['even-footer-value'] : 0));
		$toc_id = (isset($a['toc_id']) ? $a['toc_id'] : (isset($a['name']) ? $a['name'] : 0));
		$pagesel = (isset($a['pagesel']) ? $a['pagesel'] : (isset($a['pageselector']) ? $a['pageselector'] : ''));
		$toc_pagesel = (isset($a['toc_pagesel']) ? $a['toc_pagesel'] : (isset($a['toc-pageselector']) ? $a['toc-pageselector'] : ''));
		$sheetsize = (isset($a['sheetsize']) ? $a['sheetsize'] : (isset($a['sheet-size']) ? $a['sheet-size'] : ''));
		$toc_sheetsize = (isset($a['toc_sheetsize']) ? $a['toc_sheetsize'] : (isset($a['toc-sheet-size']) ? $a['toc-sheet-size'] : ''));

		$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);
	}

	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 = '')
	{
		// Start a new page
		if ($this->state == 0) {
			$this->AddPage();
		}
		if ($this->y == $this->tMargin && (!$this->mirrorMargins || ($this->mirrorMargins && $this->page % 2 == 1))) {
			// Don't add a page
			if ($this->page == 1 && count($this->PageNumSubstitutions) == 0) {
				if (!$suppress) {
					$suppress = 'off';
				}
				// $this->PageNumSubstitutions[] = array('from'=>1, 'reset'=> $resetpagenum, 'type'=>$pagenumstyle, 'suppress'=> $suppress);
			}
			$this->PageNumSubstitutions[] = ['from' => $this->page, 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress];
		} else {
			$this->AddPage($orientation, 'NEXT-ODD', $resetpagenum, $pagenumstyle, $suppress, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $sheetsize);
		}
		$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);
	}

	function TOC_Entry($txt, $level = 0, $toc_id = 0)
	{
		if ($this->ColActive) {
			$ily = $this->y0;
		} else {
			$ily = $this->y;
		} // use top of columns

		$linkn = $this->AddLink();
		$uid = '__mpdfinternallink_' . $linkn;
		if ($this->table_rotate) {
			$this->internallink[$uid] = ["Y" => $ily, "PAGE" => $this->page, "tbrot" => true];
		} elseif ($this->kwt) {
			$this->internallink[$uid] = ["Y" => $ily, "PAGE" => $this->page, "kwt" => true];
		} elseif ($this->ColActive) {
			$this->internallink[$uid] = ["Y" => $ily, "PAGE" => $this->page, "col" => $this->CurrCol];
		} elseif (!$this->keep_block_together) {
			$this->internallink[$uid] = ["Y" => $ily, "PAGE" => $this->page];
		}
		$this->internallink['#' . $uid] = $linkn;
		$this->SetLink($linkn, $ily, $this->page);

		if (strtoupper($toc_id) == 'ALL') {
			$toc_id = '_mpdf_all';
		} elseif (!$toc_id) {
			$toc_id = 0;
		} else {
			$toc_id = strtolower($toc_id);
		}
		$btoc = ['t' => $txt, 'l' => $level, 'p' => $this->page, 'link' => $linkn, 'toc_id' => $toc_id];
		if ($this->keep_block_together) {
			// do nothing
		} /* -- TABLES -- */ elseif ($this->table_rotate) {
			$this->tbrot_toc[] = $btoc;
		} elseif ($this->kwt) {
			$this->kwt_toc[] = $btoc;
		} /* -- END TABLES -- */ elseif ($this->ColActive) {  // *COLUMNS*
			$this->col_toc[] = $btoc; // *COLUMNS*
		} // *COLUMNS*
		else {
			$this->tableOfContents->_toc[] = $btoc;
		}
	}

	/* -- END TOC -- */

	// ======================================================
	function MovePages($target_page, $start_page, $end_page = -1)
	{
		// move a page/pages EARLIER in the document
		if ($end_page < 1) {
			$end_page = $start_page;
		}
		$n_toc = $end_page - $start_page + 1;

		// Set/Update PageNumSubstitutions changes before moving anything
		if (count($this->PageNumSubstitutions)) {
			$tp_present = false;
			$sp_present = false;
			$ep_present = false;
			foreach ($this->PageNumSubstitutions as $k => $v) {
				if ($this->PageNumSubstitutions[$k]['from'] == $target_page) {
					$tp_present = true;
					if ($this->PageNumSubstitutions[$k]['suppress'] != 'on' && $this->PageNumSubstitutions[$k]['suppress'] != 1) {
						$this->PageNumSubstitutions[$k]['suppress'] = 'off';
					}
				}
				if ($this->PageNumSubstitutions[$k]['from'] == $start_page) {
					$sp_present = true;
					if ($this->PageNumSubstitutions[$k]['suppress'] != 'on' && $this->PageNumSubstitutions[$k]['suppress'] != 1) {
						$this->PageNumSubstitutions[$k]['suppress'] = 'off';
					}
				}
				if ($this->PageNumSubstitutions[$k]['from'] == ($end_page + 1)) {
					$ep_present = true;
					if ($this->PageNumSubstitutions[$k]['suppress'] != 'on' && $this->PageNumSubstitutions[$k]['suppress'] != 1) {
						$this->PageNumSubstitutions[$k]['suppress'] = 'off';
					}
				}
			}

			if (!$tp_present) {
				list($tp_type, $tp_suppress, $tp_reset) = $this->docPageSettings($target_page);
			}
			if (!$sp_present) {
				list($sp_type, $sp_suppress, $sp_reset) = $this->docPageSettings($start_page);
			}
			if (!$ep_present) {
				list($ep_type, $ep_suppress, $ep_reset) = $this->docPageSettings($start_page - 1);
			}
		}

		$last = [];
		// store pages
		for ($i = $start_page; $i <= $end_page; $i++) {
			$last[] = $this->pages[$i];
		}
		// move pages
		for ($i = $start_page - 1; $i >= ($target_page); $i--) {
			$this->pages[$i + $n_toc] = $this->pages[$i];
		}
		// Put toc pages at insert point
		for ($i = 0; $i < $n_toc; $i++) {
			$this->pages[$target_page + $i] = $last[$i];
		}

		/* -- BOOKMARKS -- */
		// Update Bookmarks
		foreach ($this->BMoutlines as $i => $o) {
			if ($o['p'] >= $target_page) {
				$this->BMoutlines[$i]['p'] += $n_toc;
			}
		}
		/* -- END BOOKMARKS -- */

		// Update Page Links
		if (count($this->PageLinks)) {
			$newarr = [];
			foreach ($this->PageLinks as $i => $o) {
				foreach ($this->PageLinks[$i] as $key => $pl) {
					if (strpos($pl[4], '@') === 0) {
						$p = substr($pl[4], 1);
						if ($p >= $start_page && $p <= $end_page) {
							$this->PageLinks[$i][$key][4] = '@' . ($p + ($target_page - $start_page));
						} elseif ($p >= $target_page && $p < $start_page) {
							$this->PageLinks[$i][$key][4] = '@' . ($p + $n_toc);
						}
					}
				}
				if ($i >= $start_page && $i <= $end_page) {
					$newarr[($i + ($target_page - $start_page))] = $this->PageLinks[$i];
				} elseif ($i >= $target_page && $i < $start_page) {
					$newarr[($i + $n_toc)] = $this->PageLinks[$i];
				} else {
					$newarr[$i] = $this->PageLinks[$i];
				}
			}
			$this->PageLinks = $newarr;
		}

		// OrientationChanges
		if (count($this->OrientationChanges)) {
			$newarr = [];
			foreach ($this->OrientationChanges as $p => $v) {
				if ($p >= $start_page && $p <= $end_page) {
					$newarr[($p + ($target_page - $start_page))] = $this->OrientationChanges[$p];
				} elseif ($p >= $target_page && $p < $start_page) {
					$newarr[$p + $n_toc] = $this->OrientationChanges[$p];
				} else {
					$newarr[$p] = $this->OrientationChanges[$p];
				}
			}
			ksort($newarr);
			$this->OrientationChanges = $newarr;
		}

		// Page Dimensions
		if (count($this->pageDim)) {
			$newarr = [];
			foreach ($this->pageDim as $p => $v) {
				if ($p >= $start_page && $p <= $end_page) {
					$newarr[($p + ($target_page - $start_page))] = $this->pageDim[$p];
				} elseif ($p >= $target_page && $p < $start_page) {
					$newarr[$p + $n_toc] = $this->pageDim[$p];
				} else {
					$newarr[$p] = $this->pageDim[$p];
				}
			}
			ksort($newarr);
			$this->pageDim = $newarr;
		}

		// HTML Headers & Footers
		if (count($this->saveHTMLHeader)) {
			$newarr = [];
			foreach ($this->saveHTMLHeader as $p => $v) {
				if ($p >= $start_page && $p <= $end_page) {
					$newarr[($p + ($target_page - $start_page))] = $this->saveHTMLHeader[$p];
				} elseif ($p >= $target_page && $p < $start_page) {
					$newarr[$p + $n_toc] = $this->saveHTMLHeader[$p];
				} else {
					$newarr[$p] = $this->saveHTMLHeader[$p];
				}
			}
			ksort($newarr);
			$this->saveHTMLHeader = $newarr;
		}
		if (count($this->saveHTMLFooter)) {
			$newarr = [];
			foreach ($this->saveHTMLFooter as $p => $v) {
				if ($p >= $start_page && $p <= $end_page) {
					$newarr[($p + ($target_page - $start_page))] = $this->saveHTMLFooter[$p];
				} elseif ($p >= $target_page && $p < $start_page) {
					$newarr[$p + $n_toc] = $this->saveHTMLFooter[$p];
				} else {
					$newarr[$p] = $this->saveHTMLFooter[$p];
				}
			}
			ksort($newarr);
			$this->saveHTMLFooter = $newarr;
		}

		// Update Internal Links
		if (count($this->internallink)) {
			foreach ($this->internallink as $key => $o) {
				if (is_array($o) && $o['PAGE'] >= $start_page && $o['PAGE'] <= $end_page) {
					$this->internallink[$key]['PAGE'] += ($target_page - $start_page);
				} elseif (is_array($o) && $o['PAGE'] >= $target_page && $o['PAGE'] < $start_page) {
					$this->internallink[$key]['PAGE'] += $n_toc;
				}
			}
		}

		// Update Links
		if (count($this->links)) {
			foreach ($this->links as $key => $o) {
				if ($o[0] >= $start_page && $o[0] <= $end_page) {
					$this->links[$key][0] += ($target_page - $start_page);
				}
				if ($o[0] >= $target_page && $o[0] < $start_page) {
					$this->links[$key][0] += $n_toc;
				}
			}
		}

		// Update Form fields
		if (count($this->form->forms)) {
			foreach ($this->form->forms as $key => $f) {
				if ($f['page'] >= $start_page && $f['page'] <= $end_page) {
					$this->form->forms[$key]['page'] += ($target_page - $start_page);
				}
				if ($f['page'] >= $target_page && $f['page'] < $start_page) {
					$this->form->forms[$key]['page'] += $n_toc;
				}
			}
		}

		/* -- ANNOTATIONS -- */
		// Update Annotations
		if (count($this->PageAnnots)) {
			$newarr = [];
			foreach ($this->PageAnnots as $p => $anno) {
				if ($p >= $start_page && $p <= $end_page) {
					$np = $p + ($target_page - $start_page);
					foreach ($anno as $o) {
						$newarr[$np][] = $o;
					}
				} elseif ($p >= $target_page && $p < $start_page) {
					$np = $p + $n_toc;
					foreach ($anno as $o) {
						$newarr[$np][] = $o;
					}
				} else {
					$newarr[$p] = $this->PageAnnots[$p];
				}
			}
			$this->PageAnnots = $newarr;
			unset($newarr);
		}
		/* -- END ANNOTATIONS -- */

		// Update TOC pages
		if (count($this->tableOfContents->_toc)) {
			foreach ($this->tableOfContents->_toc as $key => $t) {
				if ($t['p'] >= $start_page && $t['p'] <= $end_page) {
					$this->tableOfContents->_toc[$key]['p'] += ($target_page - $start_page);
				}
				if ($t['p'] >= $target_page && $t['p'] < $start_page) {
					$this->tableOfContents->_toc[$key]['p'] += $n_toc;
				}
			}
		}

		// Update PageNumSubstitutions
		if (count($this->PageNumSubstitutions)) {
			$newarr = [];
			foreach ($this->PageNumSubstitutions as $k => $v) {
				if ($this->PageNumSubstitutions[$k]['from'] >= $start_page && $this->PageNumSubstitutions[$k]['from'] <= $end_page) {
					$this->PageNumSubstitutions[$k]['from'] += ($target_page - $start_page);
					$newarr[$this->PageNumSubstitutions[$k]['from']] = $this->PageNumSubstitutions[$k];
				} elseif ($this->PageNumSubstitutions[$k]['from'] >= $target_page && $this->PageNumSubstitutions[$k]['from'] < $start_page) {
					$this->PageNumSubstitutions[$k]['from'] += $n_toc;
					$newarr[$this->PageNumSubstitutions[$k]['from']] = $this->PageNumSubstitutions[$k];
				} else {
					$newarr[$this->PageNumSubstitutions[$k]['from']] = $this->PageNumSubstitutions[$k];
				}
			}

			if (!$sp_present) {
				$newarr[$target_page] = ['from' => $target_page, 'suppress' => $sp_suppress, 'reset' => $sp_reset, 'type' => $sp_type];
			}
			if (!$tp_present) {
				$newarr[($target_page + $n_toc)] = ['from' => ($target_page + $n_toc), 'suppress' => $tp_suppress, 'reset' => $tp_reset, 'type' => $tp_type];
			}
			if (!$ep_present && $end_page > count($this->pages)) {
				$newarr[($end_page + 1)] = ['from' => ($end_page + 1), 'suppress' => $ep_suppress, 'reset' => $ep_reset, 'type' => $ep_type];
			}
			ksort($newarr);
			$this->PageNumSubstitutions = [];
			foreach ($newarr as $v) {
				$this->PageNumSubstitutions[] = $v;
			}
		}
	}

	function DeletePages($start_page, $end_page = -1)
	{
		// move a page/pages EARLIER in the document
		if ($end_page < 1) {
			$end_page = $start_page;
		}
		$n_tod = $end_page - $start_page + 1;
		$last_page = count($this->pages);
		$n_atend = $last_page - $end_page + 1;

		// move pages
		for ($i = 0; $i < $n_atend; $i++) {
			$this->pages[$start_page + $i] = $this->pages[$end_page + 1 + $i];
		}
		// delete pages
		for ($i = 0; $i < $n_tod; $i++) {
			unset($this->pages[$last_page - $i]);
		}


		/* -- BOOKMARKS -- */
		// Update Bookmarks
		foreach ($this->BMoutlines as $i => $o) {
			if ($o['p'] >= $end_page) {
				$this->BMoutlines[$i]['p'] -= $n_tod;
			} elseif ($p < $start_page) {
				unset($this->BMoutlines[$i]);
			}
		}
		/* -- END BOOKMARKS -- */

		// Update Page Links
		if (count($this->PageLinks)) {
			$newarr = [];
			foreach ($this->PageLinks as $i => $o) {
				foreach ($this->PageLinks[$i] as $key => $pl) {
					if (strpos($pl[4], '@') === 0) {
						$p = substr($pl[4], 1);
						if ($p > $end_page) {
							$this->PageLinks[$i][$key][4] = '@' . ($p - $n_tod);
						} elseif ($p < $start_page) {
							unset($this->PageLinks[$i][$key]);
						}
					}
				}
				if ($i > $end_page) {
					$newarr[($i - $n_tod)] = $this->PageLinks[$i];
				} elseif ($p < $start_page) {
					$newarr[$i] = $this->PageLinks[$i];
				}
			}
			$this->PageLinks = $newarr;
		}

		// OrientationChanges
		if (count($this->OrientationChanges)) {
			$newarr = [];
			foreach ($this->OrientationChanges as $p => $v) {
				if ($p > $end_page) {
					$newarr[($p - $t_tod)] = $this->OrientationChanges[$p];
				} elseif ($p < $start_page) {
					$newarr[$p] = $this->OrientationChanges[$p];
				}
			}
			ksort($newarr);
			$this->OrientationChanges = $newarr;
		}

		// Page Dimensions
		if (count($this->pageDim)) {
			$newarr = [];
			foreach ($this->pageDim as $p => $v) {
				if ($p > $end_page) {
					$newarr[($p - $n_tod)] = $this->pageDim[$p];
				} elseif ($p < $start_page) {
					$newarr[$p] = $this->pageDim[$p];
				}
			}
			ksort($newarr);
			$this->pageDim = $newarr;
		}

		// HTML Headers & Footers
		if (count($this->saveHTMLHeader)) {
			foreach ($this->saveHTMLHeader as $p => $v) {
				if ($p > $end_page) {
					$newarr[($p - $n_tod)] = $this->saveHTMLHeader[$p];
				} // mPDF 5.7.3
				elseif ($p < $start_page) {
					$newarr[$p] = $this->saveHTMLHeader[$p];
				}
			}
			ksort($newarr);
			$this->saveHTMLHeader = $newarr;
		}
		if (count($this->saveHTMLFooter)) {
			$newarr = [];
			foreach ($this->saveHTMLFooter as $p => $v) {
				if ($p > $end_page) {
					$newarr[($p - $n_tod)] = $this->saveHTMLFooter[$p];
				} elseif ($p < $start_page) {
					$newarr[$p] = $this->saveHTMLFooter[$p];
				}
			}
			ksort($newarr);
			$this->saveHTMLFooter = $newarr;
		}

		// Update Internal Links
		foreach ($this->internallink as $key => $o) {
			if ($o['PAGE'] > $end_page) {
				$this->internallink[$key]['PAGE'] -= $n_tod;
			} elseif ($o['PAGE'] < $start_page) {
				unset($this->internallink[$key]);
			}
		}

		// Update Links
		foreach ($this->links as $key => $o) {
			if ($o[0] > $end_page) {
				$this->links[$key][0] -= $n_tod;
			} elseif ($o[0] < $start_page) {
				unset($this->links[$key]);
			}
		}

		// Update Form fields
		foreach ($this->form->forms as $key => $f) {
			if ($f['page'] > $end_page) {
				$this->form->forms[$key]['page'] -= $n_tod;
			} elseif ($f['page'] < $start_page) {
				unset($this->form->forms[$key]);
			}
		}

		/* -- ANNOTATIONS -- */
		// Update Annotations
		if (count($this->PageAnnots)) {
			$newarr = [];
			foreach ($this->PageAnnots as $p => $anno) {
				if ($p > $end_page) {
					foreach ($anno as $o) {
						$newarr[($p - $n_tod)][] = $o;
					}
				} elseif ($p < $start_page) {
					$newarr[$p] = $this->PageAnnots[$p];
				}
			}
			ksort($newarr);
			$this->PageAnnots = $newarr;
		}
		/* -- END ANNOTATIONS -- */

		// Update PageNumSubstitutions
		foreach ($this->PageNumSubstitutions as $k => $v) {
			if ($this->PageNumSubstitutions[$k]['from'] > $end_page) {
				$this->PageNumSubstitutions[$k]['from'] -= $n_tod;
			} elseif ($this->PageNumSubstitutions[$k]['from'] < $start_page) {
				unset($this->PageNumSubstitutions[$k]);
			}
		}

		unset($newarr);
		$this->page = count($this->pages);
	}

	// ======================================================
		/* -- INDEX -- */
	// FROM class PDF_Ref == INDEX

	function IndexEntry($txt, $xref = '')
	{
		if ($xref) {
			$this->IndexEntrySee($txt, $xref);
			return;
		}

		// Search the reference (AND Ref/PageNo) in the array
		$Present = false;
		if ($this->keep_block_together) {
			// do nothing
		} /* -- TABLES -- */ elseif ($this->kwt) {
			$size = count($this->kwt_Reference);
			for ($i = 0; $i < $size; $i++) {
				if (isset($this->kwt_Reference[$i]['t']) && $this->kwt_Reference[$i]['t'] == $txt) {
					$Present = true;
					if ($this->page != $this->kwt_Reference[$i]['op']) {
						$this->kwt_Reference[$i]['op'] = $this->page;
					}
				}
			}
			if (!$Present) { // If not found, add it
				$this->kwt_Reference[] = ['t' => $txt, 'op' => $this->page];
			}
		} /* -- END TABLES -- */ else {
			$size = count($this->Reference);
			for ($i = 0; $i < $size; $i++) {
				if (isset($this->Reference[$i]['t']) && $this->Reference[$i]['t'] == $txt) {
					$Present = true;
					if (!in_array($this->page, $this->Reference[$i]['p'])) {
						$this->Reference[$i]['p'][] = $this->page;
					}
				}
			}
			if (!$Present) { // If not found, add it
				$this->Reference[] = ['t' => $txt, 'p' => [$this->page]];
			}
		}
	}

	// Added function to add a reference "Elephants. See Chickens"
	function IndexEntrySee($txta, $txtb)
	{
		if ($this->directionality == 'rtl') { // *OTL*
			// ONLY DO THIS IF NOT IN TAGS
			if ($txta == strip_tags($txta)) {
				$txta = str_replace(':', ' - ', $txta); // *OTL*
			}
			if ($txtb == strip_tags($txtb)) {
				$txtb = str_replace(':', ' - ', $txtb); // *OTL*
			}
		} // *OTL*
		else { // *OTL*
			if ($txta == strip_tags($txta)) {
				$txta = str_replace(':', ', ', $txta);
			}
			if ($txtb == strip_tags($txtb)) {
				$txtb = str_replace(':', ', ', $txtb);
			}
		} // *OTL*
		$this->Reference[] = ['t' => $txta . ' - see ' . $txtb, 'p' => []];
	}

	private function filesInDir($directory)
	{
		$files = [];
		foreach ((new \DirectoryIterator($directory)) as $v) {
			if ($v->isDir() || $v->isDot()) {
				continue;
			}

			$files[] = $v->getPathname();
		}

		return $files;
	}

	function InsertIndex($usedivletters = 1, $useLinking = false, $indexCollationLocale = '', $indexCollationGroup = '')
	{
		$size = count($this->Reference);
		if ($size == 0) {
			return false;
		}

		// $spacer used after named entry
		// $sep  separates number [groups], $joiner joins numbers in range
		//  e.g. "elephant 73, 97-99"  =  elephant[$spacer]73[$sep]97[$joiner]99
		// $subEntrySeparator separates main and subentry (if $this->indexUseSubentries == false;) e.g.
		// Mammal:elephant => Mammal[$subEntrySeparator]elephant
		// $subEntryInset specifies what precedes a subentry (if $this->indexUseSubentries == true;) e.g.
		// Mammal:elephant => [$subEntryInset]elephant
		$spacer = "\xc2\xa0 ";
		if ($this->directionality == 'rtl') {
			$sep = '&#x060c; ';
			$joiner = '-';
			$subEntrySeparator = '&#x060c; ';
			$subEntryInset = ' - ';
		} else {
			$sep = ', ';
			$joiner = '-';
			$subEntrySeparator = ', ';
			$subEntryInset = ' - ';
		}

		for ($i = 0; $i < $size; $i++) {
			$txt = $this->Reference[$i]['t'];
			$txt = strip_tags($txt); // mPDF 6
			$txt = $this->purify_utf8($txt);
			$this->Reference[$i]['uf'] = $txt; // Unformatted e.g. pure utf-8 encoded characters, no mark-up/tags
			// Used for ordering and collation
		}

		if ($usedivletters) {
			if ($indexCollationGroup && \in_array(strtolower($indexCollationGroup), array_map(function ($v) {
					return strtolower(basename($v, '.php'));
			}, $this->filesInDir(__DIR__ . '/../data/collations/')))) {
				$collation = require __DIR__ . '/../data/collations/' . $indexCollationGroup . '.php';
			} else {
				$collation = [];
			}
			for ($i = 0; $i < $size; $i++) {
				if ($this->Reference[$i]['uf']) {
					$l = mb_substr($this->Reference[$i]['uf'], 0, 1, 'UTF-8');
					if (isset($indexCollationGroup) && $indexCollationGroup) {
						$uni = $this->UTF8StringToArray($l);
						$ucode = $uni[0];
						if (isset($collation[$ucode])) {
							$this->Reference[$i]['d'] = UtfString::code2utf($collation[$ucode]);
						} else {
							$this->Reference[$i]['d'] = mb_strtolower($l, 'UTF-8');
						}
					} else {
						$this->Reference[$i]['d'] = mb_strtolower($l, 'UTF-8');
					}
				}
			}
		}

		// Alphabetic sort of the references
		$originalLocale = setlocale(LC_COLLATE, 0);
		if ($indexCollationLocale) {
			setlocale(LC_COLLATE, $indexCollationLocale);
		}

		usort($this->Reference, function ($a, $b) {
			return strcoll(strtolower($a['uf']), strtolower($b['uf']));
		});

		if ($indexCollationLocale) {
			setlocale(LC_COLLATE, $originalLocale);
		}

		$html = '<div class="mpdf_index_main">';

		$lett = '';
		$last_lett = '';
		$mainentry = '';
		for ($i = 0; $i < $size; $i++) {
			if ($this->Reference[$i]['t']) {
				if ($usedivletters) {
					$lett = $this->Reference[$i]['d'];
					if ($lett != $last_lett) {
						$html .= '<div class="mpdf_index_letter">' . $lett . '</div>';
					}
				}
				$txt = $this->Reference[$i]['t'];

				// Sub-entries e.g. Mammals:elephant
				// But allow for tags e.g. <b>Mammal</b>:elephants
				$a = preg_split('/(<.*?>)/', $txt, -1, PREG_SPLIT_DELIM_CAPTURE);
				$txt = '';
				$marker = false;
				foreach ($a as $k => $e) {
					if ($k % 2 == 0 && !$marker) {
						if (strpos($e, ':') !== false) { // == SubEntry
							if ($this->indexUseSubentries) {
								// If the Main entry does not have any page numbers associated with it
								// create and insert an entry
								list($txtmain, $sub) = preg_split('/[:]/', $e, 2);
								if (strip_tags($txt . $txtmain) != $mainentry) {
									$html .= '<div class="mpdf_index_entry">' . $txt . $txtmain . '</div>';
									$mainentry = strip_tags($txt . $txtmain);
								}

								$txt = $subEntryInset;
								$e = $sub; // Only replace first one
							} else {
								$e = preg_replace('/[:]/', $subEntrySeparator, $e, 1); // Only replace first one
							}
							$marker = true; // Don't replace any more once the subentry marker has been found
						}
					}
					$txt .= $e;
				}

				if (!$marker) {
					$mainentry = strip_tags($txt);
				}

				$html .= '<div class="mpdf_index_entry">';
				$html .= $txt;
				$ppp = $this->Reference[$i]['p']; // = array of page numbers to point to
				if (count($ppp)) {
					sort($ppp);
					$newarr = [];
					$range_start = $ppp[0];
					$range_end = 0;

					$html .= $spacer;

					for ($zi = 1; $zi < count($ppp); $zi++) {
						if ($ppp[$zi] == ($ppp[($zi - 1)] + 1)) {
							$range_end = $ppp[$zi];
						} else {
							if ($range_end) {
								if ($range_end == $range_start + 1) {
									if ($useLinking) {
										$html .= '<a class="mpdf_index_link" href="@' . $range_start . '">';
									}
									$html .= $this->docPageNum($range_start);
									if ($useLinking) {
										$html .= '</a>';
									}
									$html .= $sep;

									if ($useLinking) {
										$html .= '<a class="mpdf_index_link" href="@' . $ppp[$zi - 1] . '">';
									}
									$html .= $this->docPageNum($ppp[$zi - 1]);
									if ($useLinking) {
										$html .= '</a>';
									}
									$html .= $sep;
								}
							} else {
								if ($useLinking) {
									$html .= '<a class="mpdf_index_link" href="@' . $ppp[$zi - 1] . '">';
								}
								$html .= $this->docPageNum($ppp[$zi - 1]);
								if ($useLinking) {
									$html .= '</a>';
								}
								$html .= $sep;
							}
							$range_start = $ppp[$zi];
							$range_end = 0;
						}
					}

					if ($range_end) {
						if ($useLinking) {
							$html .= '<a class="mpdf_index_link" href="@' . $range_start . '">';
						}
						$html .= $this->docPageNum($range_start);
						if ($range_end == $range_start + 1) {
							if ($useLinking) {
								$html .= '</a>';
							}
							$html .= $sep;
							if ($useLinking) {
								$html .= '<a class="mpdf_index_link" href="@' . $range_end . '">';
							}
							$html .= $this->docPageNum($range_end);
							if ($useLinking) {
								$html .= '</a>';
							}
						} else {
							$html .= $joiner;
							$html .= $this->docPageNum($range_end);
							if ($useLinking) {
								$html .= '</a>';
							}
						}
					} else {
						if ($useLinking) {
							$html .= '<a class="mpdf_index_link" href="@' . $ppp[(count($ppp) - 1)] . '">';
						}
						$html .= $this->docPageNum($ppp[(count($ppp) - 1)]);
						if ($useLinking) {
							$html .= '</a>';
						}
					}
				}
			}
			$html .= '</div>';
			$last_lett = $lett;
		}
		$html .= '</div>';
		$save_fpb = $this->fixedPosBlockSave;
		$this->WriteHTML($html);
		$this->fixedPosBlockSave = $save_fpb;

		$this->breakpoints[$this->CurrCol][] = $this->y;  // *COLUMNS*
	}

	/* -- END INDEX -- */

	function AcceptPageBreak()
	{
		if (count($this->cellBorderBuffer)) {
			$this->printcellbuffer();
		} // *TABLES*
		/* -- COLUMNS -- */
		if ($this->ColActive == 1) {
			if ($this->CurrCol < $this->NbCol - 1) {
				// Go to the next column
				$this->CurrCol++;
				$this->SetCol($this->CurrCol);
				$this->y = $this->y0;
				$this->ChangeColumn = 1; // Number (and direction) of columns changed +1, +2, -2 etc.
				// DIRECTIONALITY RTL
				if ($this->directionality == 'rtl') {
					$this->ChangeColumn = -($this->ChangeColumn);
				} // *OTL*
				// Stay on the page
				return false;
			} else {
				// Go back to the first column - NEW PAGE
				if (count($this->columnbuffer)) {
					$this->printcolumnbuffer();
				}
				$this->SetCol(0);
				$this->y0 = $this->tMargin;
				$this->ChangeColumn = -($this->NbCol - 1);
				// DIRECTIONALITY RTL
				if ($this->directionality == 'rtl') {
					$this->ChangeColumn = -($this->ChangeColumn);
				} // *OTL*
				// Page break
				return true;
			}
		} /* -- END COLUMNS -- */
		/* -- TABLES -- */ elseif ($this->table_rotate) {
			if ($this->tablebuffer) {
				$this->printtablebuffer();
			}
			return true;
		} /* -- END TABLES -- */ else { // *COLUMNS*
			$this->ChangeColumn = 0;
			return $this->autoPageBreak;
		} // *COLUMNS*
		return $this->autoPageBreak;
	}

	// ----------- COLUMNS ---------------------
	/* -- COLUMNS -- */

	function SetColumns($NbCol, $vAlign = '', $gap = 5)
	{
		// NbCol = number of columns
		// Anything less than 2 turns columns off
		if ($NbCol < 2) { // SET COLUMNS OFF
			if ($this->ColActive) {
				$this->ColActive = 0;
				if (count($this->columnbuffer)) {
					$this->printcolumnbuffer();
				}
				$this->NbCol = 1;
				$this->ResetMargins();
				$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
				$this->divwidth = 0;
				$this->Ln();
			}
			$this->ColActive = 0;
			$this->columnbuffer = [];
			$this->ColDetails = [];
			$this->columnLinks = [];
			$this->columnAnnots = [];
			$this->columnForms = [];
			$this->col_BMoutlines = [];
			$this->col_toc = [];
			$this->breakpoints = [];
		} else { // SET COLUMNS ON
			if ($this->ColActive) {
				$this->ColActive = 0;
				if (count($this->columnbuffer)) {
					$this->printcolumnbuffer();
				}
				$this->ResetMargins();
			}
			if (isset($this->y) && $this->y > $this->tMargin) {
				$this->Ln();
			}
			$this->NbCol = $NbCol;
			$this->ColGap = $gap;
			$this->divwidth = 0;
			$this->ColActive = 1;
			$this->ColumnAdjust = true; // enables column height adjustment for the page
			$this->columnbuffer = [];
			$this->ColDetails = [];
			$this->columnLinks = [];
			$this->columnAnnots = [];
			$this->columnForms = [];
			$this->col_BMoutlines = [];
			$this->col_toc = [];
			$this->breakpoints = [];
			if ((strtoupper($vAlign) == 'J') || (strtoupper($vAlign) == 'JUSTIFY')) {
				$vAlign = 'J';
			} else {
				$vAlign = '';
			}
			$this->colvAlign = $vAlign;
			// Save the ordinate
			$absL = $this->DeflMargin - ($gap / 2);
			$absR = $this->DefrMargin - ($gap / 2);
			$PageWidth = $this->w - $absL - $absR; // virtual pagewidth for calculation only
			$ColWidth = (($PageWidth - ($gap * ($NbCol))) / $NbCol);
			$this->ColWidth = $ColWidth;
			/* -- OTL -- */

			if ($this->directionality == 'rtl') {
				for ($i = 0; $i < $this->NbCol; $i++) {
					$this->ColL[$i] = $absL + ($gap / 2) + (($NbCol - ($i + 1)) * ($PageWidth / $NbCol));
					$this->ColR[$i] = $this->ColL[$i] + $ColWidth; // NB This is not R margin -> R pos
				}
			} else {
				/* -- END OTL -- */
				for ($i = 0; $i < $this->NbCol; $i++) {
					$this->ColL[$i] = $absL + ($gap / 2) + ($i * ($PageWidth / $NbCol) );
					$this->ColR[$i] = $this->ColL[$i] + $ColWidth; // NB This is not R margin -> R pos
				}
			} // *OTL*
			$this->pgwidth = $ColWidth;
			$this->SetCol(0);
			$this->y0 = $this->y;
		}
		$this->x = $this->lMargin;
	}

	function SetCol($CurrCol)
	{
		// Used internally to set column by number: 0 is 1st column
		// Set position on a column
		$this->CurrCol = $CurrCol;
		$x = $this->ColL[$CurrCol];
		$xR = $this->ColR[$CurrCol]; // NB This is not R margin -> R pos
		if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
			$x += $this->MarginCorrection;
			$xR += $this->MarginCorrection;
		}
		$this->SetMargins($x, ($this->w - $xR), $this->tMargin);
	}

	function AddColumn()
	{
		$this->NewColumn();
		$this->ColumnAdjust = false; // disables all column height adjustment for the page.
	}

	function NewColumn()
	{
		if ($this->ColActive == 1) {
			if ($this->CurrCol < $this->NbCol - 1) {
				// Go to the next column
				$this->CurrCol++;
				$this->SetCol($this->CurrCol);
				$this->y = $this->y0;
				$this->ChangeColumn = 1;
				// DIRECTIONALITY RTL
				if ($this->directionality == 'rtl') {
					$this->ChangeColumn = -($this->ChangeColumn);
				} // *OTL*
				// Stay on the page
			} else {
				// Go back to the first column
				// Page break
				if (count($this->columnbuffer)) {
					$this->printcolumnbuffer();
				}
				$this->AddPage($this->CurOrientation);
				$this->SetCol(0);
				$this->y0 = $this->tMargin;
				$this->ChangeColumn = -($this->NbCol - 1);
				// DIRECTIONALITY RTL
				if ($this->directionality == 'rtl') {
					$this->ChangeColumn = -($this->ChangeColumn);
				} // *OTL*
			}
			$this->x = $this->lMargin;
		} else {
			$this->AddPage($this->CurOrientation);
		}
	}

	function printcolumnbuffer()
	{
		// Columns ended (but page not ended) -> try to match all columns - unless disabled by using a custom column-break
		if (!$this->ColActive && $this->ColumnAdjust && !$this->keepColumns) {
			// Calculate adjustment to add to each column to calculate rel_y value
			$this->ColDetails[0]['add_y'] = 0;
			$last_col = 0;
			// Recursively add previous column's height
			for ($i = 1; $i < $this->NbCol; $i++) {
				if (isset($this->ColDetails[$i]['bottom_margin']) && $this->ColDetails[$i]['bottom_margin']) { // If any entries in the column
					$this->ColDetails[$i]['add_y'] = ($this->ColDetails[$i - 1]['bottom_margin'] - $this->y0) + $this->ColDetails[$i - 1]['add_y'];
					$last_col = $i;  // Last column actually printed
				}
			}

			// Calculate value for each position sensitive entry as though for one column
			foreach ($this->columnbuffer as $key => $s) {
				$t = $s['s'];
				if ($t == 'ACROFORM') {
					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
					$this->columnbuffer[$key]['s'] = '';
				} elseif (preg_match('/BT \d+\.\d\d+ (\d+\.\d\d+) Td/', $t)) {
					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
				} elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ [\-]{0,1}\d+\.\d\d+ re/', $t)) {
					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
				} elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) m/', $t)) {
					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
				} elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) l/', $t)) {
					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
				} 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)) {
					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
				} elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ c/', $t)) {
					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
				}
			}
			foreach ($this->internallink as $key => $f) {
				if (is_array($f) && isset($f['col'])) {
					$this->internallink[$key]['rel_y'] = $f['Y'] + $this->ColDetails[$f['col']]['add_y'] - $this->y0;
				}
			}

			$breaks = [];
			foreach ($this->breakpoints as $c => $bpa) {
				foreach ($bpa as $rely) {
					$breaks[] = $rely + $this->ColDetails[$c]['add_y'] - $this->y0;
				}
			}


			if (isset($this->ColDetails[$last_col]['bottom_margin'])) {
				$lcbm = $this->ColDetails[$last_col]['bottom_margin'];
			} else {
				$lcbm = 0;
			}
			$sum_h = $this->ColDetails[$last_col]['add_y'] + $lcbm - $this->y0;
			// $sum_h = max($this->ColDetails[$last_col]['add_y'] + $this->ColDetails[$last_col]['bottom_margin'] - $this->y0, end($breaks));
			$target_h = ($sum_h / $this->NbCol);

			$cbr = [];
			for ($i = 1; $i < $this->NbCol; $i++) {
				$th = ($sum_h * $i / $this->NbCol);
				foreach ($breaks as $bk => $val) {
					if ($val > $th) {
						if (!$bk || ($val - $th) < ($th - $breaks[$bk - 1])) {
							$cbr[$i - 1] = $val;
						} else {
							$cbr[$i - 1] = $breaks[$bk - 1];
						}
						break;
					}
				}
			}
			$cbr[($this->NbCol - 1)] = $sum_h;

			// mPDF 6
			// Avoid outputing with 1st column empty
			if (isset($cbr[0]) && $cbr[0] == 0) {
				for ($i = 0; $i < $this->NbCol - 1; $i++) {
					$cbr[$i] = $cbr[$i + 1];
				}
			}

			// Now update the columns - divide into columns of approximately equal value
			$last_new_col = 0;
			$yadj = 0; // mm
			$xadj = 0;
			$last_col_bottom = 0;
			$lowest_bottom_y = 0;
			$block_bottom = 0;
			$newcolumn = 0;
			foreach ($this->columnbuffer as $key => $s) {
				if (isset($s['rel_y'])) { // only process position sensitive data
					if ($s['rel_y'] >= $cbr[$newcolumn]) {
						$newcolumn++;
					} else {
						$newcolumn = $last_new_col;
					}


					$block_bottom = max($block_bottom, ($s['rel_y'] + $s['h']));

					if ($this->directionality == 'rtl') { // *OTL*
						$xadj = -(($newcolumn - $s['col']) * ($this->ColWidth + $this->ColGap)); // *OTL*
					} // *OTL*
					else { // *OTL*
						$xadj = ($newcolumn - $s['col']) * ($this->ColWidth + $this->ColGap);
					} // *OTL*

					if ($last_new_col != $newcolumn) { // Added new column
						$last_col_bottom = $this->columnbuffer[$key]['rel_y'];
						$block_bottom = 0;
					}
					$yadj = ($s['rel_y'] - $s['y']) - ($last_col_bottom) + $this->y0;
					// callback function
					$t = $s['s'];

					// mPDF 5.7+
					$t = $this->columnAdjustPregReplace('Td', $xadj, $yadj, '/BT (\d+\.\d\d+) (\d+\.\d\d+) Td/', $t);
					$t = $this->columnAdjustPregReplace('re', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) ([\-]{0,1}\d+\.\d\d+) re/', $t);
					$t = $this->columnAdjustPregReplace('l', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) l/', $t);
					$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);
					$t = $this->columnAdjustPregReplace('draw', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) m/', $t);
					$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);

					$this->columnbuffer[$key]['s'] = $t;
					$this->columnbuffer[$key]['newcol'] = $newcolumn;
					$this->columnbuffer[$key]['newy'] = $s['y'] + $yadj;
					$last_new_col = $newcolumn;
					$clb = $s['y'] + $yadj + $s['h']; // bottom_margin of current
					if ((isset($this->ColDetails[$newcolumn]['max_bottom']) && $clb > $this->ColDetails[$newcolumn]['max_bottom']) || (!isset($this->ColDetails[$newcolumn]['max_bottom']) && $clb)) {
						$this->ColDetails[$newcolumn]['max_bottom'] = $clb;
					}
					if ($clb > $lowest_bottom_y) {
						$lowest_bottom_y = $clb;
					}
					// Adjust LINKS
					if (isset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])])) {
						$ref = $this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])];
						$this->PageLinks[$this->page][$ref][0] += ($xadj * Mpdf::SCALE);
						$this->PageLinks[$this->page][$ref][1] -= ($yadj * Mpdf::SCALE);
						unset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])]);
					}
					// Adjust FORM FIELDS
					if (isset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])])) {
						$ref = $this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])];
						$this->form->forms[$ref]['x'] += ($xadj);
						$this->form->forms[$ref]['y'] += ($yadj);
						unset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])]);
					}
					/* -- ANNOTATIONS -- */
					if (isset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])])) {
						$ref = $this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])];
						if ($this->PageAnnots[$this->page][$ref]['x'] < 0) {
							$this->PageAnnots[$this->page][$ref]['x'] -= ($xadj);
						} else {
							$this->PageAnnots[$this->page][$ref]['x'] += ($xadj);
						}
						$this->PageAnnots[$this->page][$ref]['y'] += ($yadj); // unlike PageLinks, Page annots has y values from top in mm
						unset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])]);
					}
					/* -- END ANNOTATIONS -- */
				}
			}

			/* -- BOOKMARKS -- */
			// Adjust Bookmarks
			foreach ($this->col_BMoutlines as $v) {
				$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $this->y0, 'p' => $v['p']];
			}
			/* -- END BOOKMARKS -- */

			/* -- TOC -- */

			// Adjust ToC
			foreach ($this->col_toc as $v) {
				$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
				$this->links[$v['link']][1] = $this->y0;
			}
			/* -- END TOC -- */

			// Adjust column length to be equal
			if ($this->colvAlign == 'J') {
				foreach ($this->columnbuffer as $key => $s) {
					if (isset($s['rel_y'])) { // only process position sensitive data
						// Set ratio to expand y values or heights
						if (isset($this->ColDetails[$s['newcol']]['max_bottom']) && $this->ColDetails[$s['newcol']]['max_bottom'] && $this->ColDetails[$s['newcol']]['max_bottom'] != $this->y0) {
							$ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['newcol']]['max_bottom'] - ($this->y0));
						} else {
							$ratio = 1;
						}
						if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
							$yadj = ($s['newy'] - $this->y0) * ($ratio - 1);

							// Adjust LINKS
							if (isset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])])) {
								$ref = $this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])];
								$this->PageLinks[$this->page][$ref][1] -= ($yadj * Mpdf::SCALE); // y value
								$this->PageLinks[$this->page][$ref][3] *= $ratio; // height
								unset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])]);
							}
							// Adjust FORM FIELDS
							if (isset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])])) {
								$ref = $this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])];
								$this->form->forms[$ref]['x'] += ($xadj);
								$this->form->forms[$ref]['y'] += ($yadj);
								unset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])]);
							}
							/* -- ANNOTATIONS -- */
							if (isset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])])) {
								$ref = $this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])];
								$this->PageAnnots[$this->page][$ref]['y'] += ($yadj);
								unset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])]);
							}
							/* -- END ANNOTATIONS -- */
						}
					}
				}
				foreach ($this->internallink as $key => $f) {
					if (is_array($f) && isset($f['col'])) {
						$last_col_bottom = 0;
						for ($nbc = 0; $nbc < $this->NbCol; $nbc++) {
							if ($f['rel_y'] >= $cbr[$nbc]) {
								$last_col_bottom = $cbr[$nbc];
							}
						}
						$yadj = ($f['rel_y'] - $f['Y']) - $last_col_bottom + $this->y0;
						$f['Y'] += $yadj;
						unset($f['col']);
						unset($f['rel_y']);
						$this->internallink[$key] = $f;
					}
				}

				$last_col = -1;
				$trans_on = false;
				foreach ($this->columnbuffer as $key => $s) {
					if (isset($s['rel_y'])) { // only process position sensitive data
						// Set ratio to expand y values or heights
						if (isset($this->ColDetails[$s['newcol']]['max_bottom']) && $this->ColDetails[$s['newcol']]['max_bottom'] && $this->ColDetails[$s['newcol']]['max_bottom'] != $this->y0) {
							$ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['newcol']]['max_bottom'] - ($this->y0));
						} else {
							$ratio = 1;
						}
						if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
							// Start Transformation
							$this->pages[$this->page] .= $this->StartTransform(true) . "\n";
							$this->pages[$this->page] .= $this->transformScale(100, $ratio * 100, $x = '', $this->y0, true) . "\n";
							$trans_on = true;
						}
					}
					// Now output the adjusted values
					$this->pages[$this->page] .= $s['s'] . "\n";
					if (isset($s['rel_y']) && ($ratio > 1) && ($ratio <= $this->max_colH_correction)) { // only process position sensitive data
						// Stop Transformation
						$this->pages[$this->page] .= $this->StopTransform(true) . "\n";
						$trans_on = false;
					}
				}
				if ($trans_on) {
					$this->pages[$this->page] .= $this->StopTransform(true) . "\n";
				}
			} else { // if NOT $this->colvAlign == 'J'
				// Now output the adjusted values
				foreach ($this->columnbuffer as $s) {
					$this->pages[$this->page] .= $s['s'] . "\n";
				}
			}
			if ($lowest_bottom_y > 0) {
				$this->y = $lowest_bottom_y;
			}
		} // Columns not ended but new page -> align columns (can leave the columns alone - just tidy up the height)
		elseif ($this->colvAlign == 'J' && $this->ColumnAdjust && !$this->keepColumns) {
			// calculate the lowest bottom margin
			$lowest_bottom_y = 0;
			foreach ($this->columnbuffer as $key => $s) {
				// Only process output data
				$t = $s['s'];
				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)) ||
					(preg_match('/\d+\.\d\d+ (\d+\.\d\d+) l/', $t)) ||
					(preg_match('/q \d+\.\d\d+ 0 0 \d+\.\d\d+ \d+\.\d\d+ (\d+\.\d\d+) cm \/(I|FO)\d+ Do Q/', $t)) ||
					(preg_match('/\d+\.\d\d+ (\d+\.\d\d+) m/', $t)) ||
					(preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ c/', $t))) {
					$clb = $s['y'] + $s['h'];
					if ((isset($this->ColDetails[$s['col']]['max_bottom']) && $clb > $this->ColDetails[$s['col']]['max_bottom']) || !isset($this->ColDetails[$s['col']]['max_bottom'])) {
						$this->ColDetails[$s['col']]['max_bottom'] = $clb;
					}
					if ($clb > $lowest_bottom_y) {
						$lowest_bottom_y = $clb;
					}
					$this->columnbuffer[$key]['rel_y'] = $s['y']; // Marks position sensitive data to process later
					if ($t == 'ACROFORM') {
						$this->columnbuffer[$key]['s'] = '';
					}
				}
			}
			// Adjust column length equal
			foreach ($this->columnbuffer as $key => $s) {
				// Set ratio to expand y values or heights
				if (isset($this->ColDetails[$s['col']]['max_bottom']) && $this->ColDetails[$s['col']]['max_bottom']) {
					$ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['col']]['max_bottom'] - ($this->y0));
				} else {
					$ratio = 1;
				}
				if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
					$yadj = ($s['y'] - $this->y0) * ($ratio - 1);

					// Adjust LINKS
					if (isset($s['rel_y'])) { // only process position sensitive data
						// otherwise triggers for all entries in column buffer (.e.g. formatting) and makes below adjustments more than once
						if (isset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])])) {
							$ref = $this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])];
							$this->PageLinks[$this->page][$ref][1] -= ($yadj * Mpdf::SCALE); // y value
							$this->PageLinks[$this->page][$ref][3] *= $ratio; // height
							unset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])]);
						}
						// Adjust FORM FIELDS
						if (isset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])])) {
							$ref = $this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])];
							$this->form->forms[$ref]['x'] += ($xadj);
							$this->form->forms[$ref]['y'] += ($yadj);
							unset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])]);
						}
						/* -- ANNOTATIONS -- */
						if (isset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])])) {
							$ref = $this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])];
							$this->PageAnnots[$this->page][$ref]['y'] += ($yadj);
							unset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])]);
						}
						/* -- END ANNOTATIONS -- */
					}
				}
			}

			/* -- BOOKMARKS -- */

			// Adjust Bookmarks
			foreach ($this->col_BMoutlines as $v) {
				$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $this->y0, 'p' => $v['p']];
			}
			/* -- END BOOKMARKS -- */

			/* -- TOC -- */

			// Adjust ToC
			foreach ($this->col_toc as $v) {
				$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
				$this->links[$v['link']][1] = $this->y0;
			}
			/* -- END TOC -- */

			$trans_on = false;
			foreach ($this->columnbuffer as $key => $s) {

				if (isset($s['rel_y'])) { // only process position sensitive data

					// Set ratio to expand y values or heights
					if (isset($this->ColDetails[$s['col']]['max_bottom']) && $this->ColDetails[$s['col']]['max_bottom']) {
						$ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['col']]['max_bottom'] - ($this->y0));
					} else {
						$ratio = 1;
					}

					if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
						// Start Transformation
						$this->pages[$this->page] .= $this->StartTransform(true) . "\n";
						$this->pages[$this->page] .= $this->transformScale(100, $ratio * 100, $x = '', $this->y0, true) . "\n";
						$trans_on = true;
					}
				}

				// Now output the adjusted values
				$this->pages[$this->page] .= $s['s'] . "\n";
				if (isset($s['rel_y']) && ($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
					// Stop Transformation
					$this->pages[$this->page] .= $this->StopTransform(true) . "\n";
					$trans_on = false;
				}
			}

			if ($trans_on) {
				$this->pages[$this->page] .= $this->StopTransform(true) . "\n";
			}

			if ($lowest_bottom_y > 0) {
				$this->y = $lowest_bottom_y;
			}

		} else { // Just reproduce the page as it was

			// If page has not ended but height adjustment was disabled by custom column-break - adjust y
			$lowest_bottom_y = 0;

			if (!$this->ColActive && (!$this->ColumnAdjust || $this->keepColumns)) {

				// calculate the lowest bottom margin
				foreach ($this->columnbuffer as $key => $s) {

					// Only process output data
					$t = $s['s'];
					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))
							|| (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) l/', $t))
							|| (preg_match('/q \d+\.\d\d+ 0 0 \d+\.\d\d+ \d+\.\d\d+ (\d+\.\d\d+) cm \/(I|FO)\d+ Do Q/', $t))
							|| (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) m/', $t))
							|| (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ c/', $t))) {

						$clb = $s['y'] + $s['h'];

						if (isset($this->ColDetails[$s['col']]['max_bottom']) && $clb > $this->ColDetails[$s['col']]['max_bottom'] || (!isset($this->ColDetails[$s['col']]['max_bottom']) && $clb)) {
							$this->ColDetails[$s['col']]['max_bottom'] = $clb;
						}

						if ($clb > $lowest_bottom_y) {
							$lowest_bottom_y = $clb;
						}
					}
				}
			}

			foreach ($this->columnbuffer as $key => $s) {
				if ($s['s'] != 'ACROFORM') {
					$this->pages[$this->page] .= $s['s'] . "\n";
				}
			}

			if ($lowest_bottom_y > 0) {
				$this->y = $lowest_bottom_y;
			}

			/* -- BOOKMARKS -- */
			// Output Bookmarks
			foreach ($this->col_BMoutlines as $v) {
				$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $v['p']];
			}
			/* -- END BOOKMARKS -- */

			/* -- TOC -- */
			// Output ToC
			foreach ($this->col_toc as $v) {
				$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
			}
			/* -- END TOC -- */
		}

		foreach ($this->internallink as $key => $f) {

			if (isset($this->internallink[$key]['col'])) {
				unset($this->internallink[$key]['col']);
			}

			if (isset($this->internallink[$key]['rel_y'])) {
				unset($this->internallink[$key]['rel_y']);
			}
		}

		$this->columnbuffer = [];
		$this->ColDetails = [];
		$this->columnLinks = [];
		$this->columnAnnots = [];
		$this->columnForms = [];

		$this->col_BMoutlines = [];
		$this->col_toc = [];
		$this->breakpoints = [];
	}

	// mPDF 5.7+
	function columnAdjustPregReplace($type, $xadj, $yadj, $pattern, $subject)
	{
		preg_match($pattern, $subject, $matches);

		if (!count($matches)) {
			return $subject;
		}

		if (!isset($matches[3])) {
			$matches[3] = 0;
		}

		if (!isset($matches[4])) {
			$matches[4] = 0;
		}

		if (!isset($matches[5])) {
			$matches[5] = 0;
		}

		if (!isset($matches[6])) {
			$matches[6] = 0;
		}

		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);
	}
	/* -- END COLUMNS -- */

	// ==================================================================
	/* -- TABLES -- */
	function printcellbuffer()
	{
		if (count($this->cellBorderBuffer)) {

			sort($this->cellBorderBuffer);

			foreach ($this->cellBorderBuffer as $cbb) {

				$cba = unpack("A16dom/nbord/A1side/ns/dbw/a6ca/A10style/dx/dy/dw/dh/dmbl/dmbr/dmrt/dmrb/dmtl/dmtr/dmlt/dmlb/dcpd/dover/", $cbb);
				$side = $cba['side'];
				$color = str_pad($cba['ca'], 6, "\x00");

				$details = [];

				$details[$side]['dom'] = (float) $cba['dom'];
				$details[$side]['s'] = $cba['s'];
				$details[$side]['w'] = $cba['bw'];
				$details[$side]['c'] = $color;
				$details[$side]['style'] = trim($cba['style']);

				$details['mbw']['BL'] = $cba['mbl'];
				$details['mbw']['BR'] = $cba['mbr'];
				$details['mbw']['RT'] = $cba['mrt'];
				$details['mbw']['RB'] = $cba['mrb'];
				$details['mbw']['TL'] = $cba['mtl'];
				$details['mbw']['TR'] = $cba['mtr'];
				$details['mbw']['LT'] = $cba['mlt'];
				$details['mbw']['LB'] = $cba['mlb'];

				$details['cellposdom'] = $cba['cpd'];

				$details['p'] = $side;

				if ($cba['over'] == 1) {
					$details[$side]['overlay'] = true;
				} else {
					$details[$side]['overlay'] = false;
				}

				$this->_tableRect($cba['x'], $cba['y'], $cba['w'], $cba['h'], $cba['bord'], $details, false, false);
			}

			$this->cellBorderBuffer = [];
		}
	}

	// ==================================================================
	function printtablebuffer()
	{

		if (!$this->table_rotate) {

			$this->pages[$this->page] .= $this->tablebuffer;

			foreach ($this->tbrot_Links as $p => $l) {
				foreach ($l as $v) {
					$this->PageLinks[$p][] = $v;
				}
			}
			$this->tbrot_Links = [];

			/* -- ANNOTATIONS -- */
			foreach ($this->tbrot_Annots as $p => $l) {
				foreach ($l as $v) {
					$this->PageAnnots[$p][] = $v;
				}
			}
			$this->tbrot_Annots = [];
			/* -- END ANNOTATIONS -- */

			/* -- BOOKMARKS -- */
			// Output Bookmarks
			foreach ($this->tbrot_BMoutlines as $v) {
				$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $v['p']];
			}
			$this->tbrot_BMoutlines = [];
			/* -- END BOOKMARKS -- */

			/* -- TOC -- */
			// Output ToC
			foreach ($this->tbrot_toc as $v) {
				$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
			}
			$this->tbrot_toc = [];
			/* -- END TOC -- */

			return;
		}

		// elseif rotated
		$lm = $this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_left'];
		$pw = $this->blk[$this->blklvl]['inner_width'];

		// Start Transformation
		$this->pages[$this->page] .= $this->StartTransform(true) . "\n";

		if ($this->table_rotate > 1) { // clockwise

			if ($this->tbrot_align == 'L') {
				$xadj = $this->tbrot_h; // align L (as is)
			} elseif ($this->tbrot_align == 'R') {
				$xadj = $lm - $this->tbrot_x0 + ($pw); // align R
			} else {
				$xadj = $lm - $this->tbrot_x0 + (($pw + $this->tbrot_h) / 2); // align C
			}

			$yadj = 0;

		} else { // anti-clockwise

			if ($this->tbrot_align == 'L') {
				$xadj = 0; // align L (as is)
			} elseif ($this->tbrot_align == 'R') {
				$xadj = $lm - $this->tbrot_x0 + ($pw - $this->tbrot_h); // align R
			} else {
				$xadj = $lm - $this->tbrot_x0 + (($pw - $this->tbrot_h) / 2); // align C
			}

			$yadj = $this->tbrot_w;
		}


		$this->pages[$this->page] .= $this->transformTranslate($xadj, $yadj, true) . "\n";
		$this->pages[$this->page] .= $this->transformRotate($this->table_rotate, $this->tbrot_x0, $this->tbrot_y0, true) . "\n";

		// Now output the adjusted values
		$this->pages[$this->page] .= $this->tablebuffer;

		foreach ($this->tbrot_Links as $p => $l) {

			foreach ($l as $v) {

				$w = $v[2] / Mpdf::SCALE;
				$h = $v[3] / Mpdf::SCALE;
				$ax = ($v[0] / Mpdf::SCALE) - $this->tbrot_x0;
				$ay = (($this->hPt - $v[1]) / Mpdf::SCALE) - $this->tbrot_y0;

				if ($this->table_rotate > 1) { // clockwise
					$bx = $this->tbrot_x0 + $xadj - $ay - $h;
					$by = $this->tbrot_y0 + $yadj + $ax;
				} else {
					$bx = $this->tbrot_x0 + $xadj + $ay;
					$by = $this->tbrot_y0 + $yadj - $ax - $w;
				}

				$v[0] = $bx * Mpdf::SCALE;
				$v[1] = ($this->h - $by) * Mpdf::SCALE;
				$v[2] = $h * Mpdf::SCALE; // swap width and height
				$v[3] = $w * Mpdf::SCALE;

				$this->PageLinks[$p][] = $v;
			}
		}

		$this->tbrot_Links = [];
		foreach ($this->internallink as $key => $f) {
			if (is_array($f) && isset($f['tbrot'])) {
				$f['Y'] = $this->tbrot_y0;
				$f['PAGE'] = $this->page;
				unset($f['tbrot']);
				$this->internallink[$key] = $f;
			}
		}

		/* -- ANNOTATIONS -- */
		foreach ($this->tbrot_Annots as $p => $l) {
			foreach ($l as $v) {
				$ax = abs($v['x']) - $this->tbrot_x0; // abs because -ve values are internally set and held for reference if annotMargin set
				$ay = $v['y'] - $this->tbrot_y0;

				if ($this->table_rotate > 1) { // clockwise
					$bx = $this->tbrot_x0 + $xadj - $ay;
					$by = $this->tbrot_y0 + $yadj + $ax;
				} else {
					$bx = $this->tbrot_x0 + $xadj + $ay;
					$by = $this->tbrot_y0 + $yadj - $ax;
				}

				if ($v['x'] < 0) {
					$v['x'] = -$bx;
				} else {
					$v['x'] = $bx;
				}

				$v['y'] = ($by);
				$this->PageAnnots[$p][] = $v;
			}
		}

		$this->tbrot_Annots = [];
		/* -- END ANNOTATIONS -- */

		/* -- BOOKMARKS -- */
		// Adjust Bookmarks
		foreach ($this->tbrot_BMoutlines as $v) {
			$v['y'] = $this->tbrot_y0;
			$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $this->page];
		}
		/* -- END BOOKMARKS -- */

		/* -- TOC -- */
		// Adjust ToC - uses document page number
		foreach ($this->tbrot_toc as $v) {
			$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $this->page, 'link' => $v['link'], 'toc_id' => $v['toc_id']];
			$this->links[$v['link']][1] = $this->tbrot_y0;
		}
		/* -- END TOC -- */

		$this->tbrot_BMoutlines = [];
		$this->tbrot_toc = [];

		// Stop Transformation
		$this->pages[$this->page] .= $this->StopTransform(true) . "\n";

		$this->y = $this->tbrot_y0 + $this->tbrot_w;
		$this->x = $this->lMargin;

		$this->tablebuffer = '';
	}

	/**
	 * Keep-with-table This buffers contents of h1-6 to keep on page with table
	 */
	function printkwtbuffer()
	{
		if (!$this->kwt_moved) {

			foreach ($this->kwt_buffer as $s) {
				$this->pages[$this->page] .= $s['s'] . "\n";
			}

			foreach ($this->kwt_Links as $p => $l) {
				foreach ($l as $v) {
					$this->PageLinks[$p][] = $v;
				}
			}

			$this->kwt_Links = [];

			/* -- ANNOTATIONS -- */
			foreach ($this->kwt_Annots as $p => $l) {
				foreach ($l as $v) {
					$this->PageAnnots[$p][] = $v;
				}
			}
			$this->kwt_Annots = [];
			/* -- END ANNOTATIONS -- */

			/* -- INDEX -- */
			// Output Reference (index)
			foreach ($this->kwt_Reference as $v) {

				$Present = 0;

				for ($i = 0; $i < count($this->Reference); $i++) {
					if ($this->Reference[$i]['t'] == $v['t']) {
						$Present = 1;
						if (!in_array($v['op'], $this->Reference[$i]['p'])) {
							$this->Reference[$i]['p'][] = $v['op'];
						}
					}
				}

				if ($Present == 0) {
					$this->Reference[] = ['t' => $v['t'], 'p' => [$v['op']]];
				}
			}
			$this->kwt_Reference = [];
			/* -- END INDEX -- */

			/* -- BOOKMARKS -- */
			// Output Bookmarks
			foreach ($this->kwt_BMoutlines as $v) {
				$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $v['p']];
			}
			$this->kwt_BMoutlines = [];
			/* -- END BOOKMARKS -- */

			/* -- TOC -- */
			// Output ToC
			foreach ($this->kwt_toc as $v) {
				$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
			}
			$this->kwt_toc = [];
			/* -- END TOC -- */

			$this->pageoutput[$this->page] = []; // mPDF 6

			return;
		}

		// Start Transformation
		$this->pages[$this->page] .= $this->StartTransform(true) . "\n";
		$xadj = $this->lMargin - $this->kwt_x0;
		// $yadj = $this->y - $this->kwt_y0 ;
		$yadj = $this->tMargin - $this->kwt_y0;

		$this->pages[$this->page] .= $this->transformTranslate($xadj, $yadj, true) . "\n";

		// Now output the adjusted values
		foreach ($this->kwt_buffer as $s) {
			$this->pages[$this->page] .= $s['s'] . "\n";
		}

		// Adjust hyperLinks
		foreach ($this->kwt_Links as $p => $l) {
			foreach ($l as $v) {
				$bx = $this->kwt_x0 + $xadj;
				$by = $this->kwt_y0 + $yadj;
				$v[0] = $bx * Mpdf::SCALE;
				$v[1] = ($this->h - $by) * Mpdf::SCALE;
				$this->PageLinks[$p][] = $v;
			}
		}

		foreach ($this->internallink as $key => $f) {
			if (is_array($f) && isset($f['kwt'])) {
				$f['Y'] += $yadj;
				$f['PAGE'] = $this->page;
				unset($f['kwt']);
				$this->internallink[$key] = $f;
			}
		}

		/* -- ANNOTATIONS -- */
		foreach ($this->kwt_Annots as $p => $l) {
			foreach ($l as $v) {
				$bx = $this->kwt_x0 + $xadj;
				$by = $this->kwt_y0 + $yadj;
				if ($v['x'] < 0) {
					$v['x'] = -$bx;
				} else {
					$v['x'] = $bx;
				}
				$v['y'] = $by;
				$this->PageAnnots[$p][] = $v;
			}
		}
		/* -- END ANNOTATIONS -- */

		/* -- BOOKMARKS -- */

		// Adjust Bookmarks
		foreach ($this->kwt_BMoutlines as $v) {
			if ($v['y'] != 0) {
				$v['y'] += $yadj;
			}
			$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $this->page];
		}
		/* -- END BOOKMARKS -- */

		/* -- INDEX -- */
		// Adjust Reference (index)
		foreach ($this->kwt_Reference as $v) {

			$Present = 0;

			// Search the reference (AND Ref/PageNo) in the array
			for ($i = 0; $i < count($this->Reference); $i++) {
				if ($this->Reference[$i]['t'] == $v['t']) {
					$Present = 1;
					if (!in_array($this->page, $this->Reference[$i]['p'])) {
						$this->Reference[$i]['p'][] = $this->page;
					}
				}
			}

			if ($Present == 0) {
				$this->Reference[] = ['t' => $v['t'], 'p' => [$this->page]];
			}
		}
		/* -- END INDEX -- */

		/* -- TOC -- */

		// Adjust ToC
		foreach ($this->kwt_toc as $v) {
			$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $this->page, 'link' => $v['link'], 'toc_id' => $v['toc_id']];
			$this->links[$v['link']][0] = $this->page;
			$this->links[$v['link']][1] += $yadj;
		}
		/* -- END TOC -- */


		$this->kwt_Links = [];
		$this->kwt_Annots = [];

		$this->kwt_Reference = [];
		$this->kwt_BMoutlines = [];
		$this->kwt_toc = [];

		// Stop Transformation
		$this->pages[$this->page] .= $this->StopTransform(true) . "\n";

		$this->kwt_buffer = [];

		$this->y += $this->kwt_height;
		$this->pageoutput[$this->page] = []; // mPDF 6
	}
	/* -- END TABLES -- */

	function printfloatbuffer()
	{
		if (count($this->floatbuffer)) {
			$this->objectbuffer = $this->floatbuffer;
			$this->printobjectbuffer(false);
			$this->objectbuffer = [];
			$this->floatbuffer = [];
			$this->floatmargins = [];
		}
	}

	function Circle($x, $y, $r, $style = 'S')
	{
		$this->Ellipse($x, $y, $r, $r, $style);
	}

	function Ellipse($x, $y, $rx, $ry, $style = 'S')
	{
		if ($style === 'F') {
			$op = 'f';
		} elseif ($style === 'FD' or $style === 'DF') {
			$op = 'B';
		} else {
			$op = 'S';
		}

		$lx = 4 / 3 * (M_SQRT2 - 1) * $rx;
		$ly = 4 / 3 * (M_SQRT2 - 1) * $ry;

		$h = $this->h;

		$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));
		$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));
		$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));
		$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));
	}

	/* -- DIRECTW -- */
	function AutosizeText($text, $w, $font, $style, $szfont = 72)
	{

		$text = ' ' . $text . ' ';

		$this->SetFont($font, $style, $szfont, false);

		$text = $this->purify_utf8_text($text);
		if ($this->text_input_as_HTML) {
			$text = $this->all_entities_to_utf8($text);
		}
		if ($this->usingCoreFont) {
			$text = mb_convert_encoding($text, $this->mb_enc, 'UTF-8');
		}

		// DIRECTIONALITY
		if (preg_match("/([" . $this->pregRTLchars . "])/u", $text)) {
			$this->biDirectional = true;
		}

		$textvar = 0;
		$save_OTLtags = $this->OTLtags;
		$this->OTLtags = [];

		if ($this->useKerning) {
			if ($this->CurrentFont['haskernGPOS']) {
				$this->OTLtags['Plus'] .= ' kern';
			} else {
				$textvar = ($textvar | TextVars::FC_KERNING);
			}
		}

		/* -- OTL -- */
		// Use OTL OpenType Table Layout - GSUB & GPOS
		if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
			$text = $this->otl->applyOTL($text, $this->CurrentFont['useOTL']);
			$OTLdata = $this->otl->OTLdata;
		}
		/* -- END OTL -- */

		$this->OTLtags = $save_OTLtags;

		$this->magic_reverse_dir($text, $this->directionality, $OTLdata);

		$width = $this->sizeConverter->convert($w);
		$loop = 0;

		while ($loop == 0) {

			$this->SetFont($font, $style, $szfont, false);
			$sz = $this->GetStringWidth($text, true, $OTLdata, $textvar);

			if ($sz > $w) {
				$szfont --;
			} else {
				$loop ++;
			}
		}

		$this->SetFont($font, $style, $szfont, true, true);
		$this->Cell($w, 0, $text, 0, 0, "C", 0, '', 0, 0, 0, 'M', 0, false, $OTLdata, $textvar);
	}
	/* -- END DIRECTW -- */

	// ====================================================
	// ====================================================

	function magic_reverse_dir(&$chunk, $dir, &$chunkOTLdata)
	{
		/* -- OTL -- */
		if ($this->usingCoreFont) {
			return 0;
		}

		if ($chunk == '') {
			return 0;
		}

		if ($this->biDirectional || $dir == 'rtl') {

			// check if string contains RTL text
			// including any added from OTL tables (in PUA)
			$pregRTLchars = $this->pregRTLchars;

			if (isset($this->CurrentFont['rtlPUAstr']) && $this->CurrentFont['rtlPUAstr']) {
				$pregRTLchars .= $this->CurrentFont['rtlPUAstr'];
			}

			if (!preg_match("/[" . $pregRTLchars . "]/u", $chunk) && $dir != 'rtl') {
				return 0;
			}   // Chunk doesn't contain RTL characters

			$unicode = $this->UTF8StringToArray($chunk, false);

			$isStrong = false;
			if (empty($chunkOTLdata)) {
				$this->getBasicOTLdata($chunkOTLdata, $unicode, $isStrong);
			}

			$useGPOS = isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0x80);

			// NB Returned $chunk may be a shorter string (with adjusted $cOTLdata) by removal of LRE, RLE etc embedding codes.
			list($chunk, $rtl_content) = $this->otl->bidiSort($unicode, $chunk, $dir, $chunkOTLdata, $useGPOS);

			return $rtl_content;
		}

		/* -- END OTL -- */
		return 0;
	}

	/* -- OTL -- */

	function getBasicOTLdata(&$chunkOTLdata, $unicode, &$is_strong)
	{
		if (empty($this->otl)) {
			$this->otl = new Otl($this, $this->fontCache);
		}

		$chunkOTLdata['group'] = '';
		$chunkOTLdata['GPOSinfo'] = [];
		$chunkOTLdata['char_data'] = [];

		foreach ($unicode as $char) {

			$ucd_record = Ucdn::get_ucd_record($char);
			$chunkOTLdata['char_data'][] = ['bidi_class' => $ucd_record[2], 'uni' => $char];

			if ($ucd_record[2] == 0 || $ucd_record[2] == 3 || $ucd_record[2] == 4) {
				$is_strong = true;
			} // contains strong character

			if ($ucd_record[0] == Ucdn::UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
				$chunkOTLdata['group'] .= 'M';
			} elseif ($char == 32 || $char == 12288) {
				$chunkOTLdata['group'] .= 'S';
			} else {
				$chunkOTLdata['group'] .= 'C';
			}
		}
	}

	function _setBidiCodes($mode = 'start', $bdf = '')
	{
		$s = '';

		if ($mode == 'end') {

			// PDF comes before PDI to close isolate-override (e.g. "LRILROPDFPDI")
			if (strpos($bdf, 'PDF') !== false) {
				$s .= UtfString::code2utf(0x202C);
			} // POP DIRECTIONAL FORMATTING

			if (strpos($bdf, 'PDI') !== false) {
				$s .= UtfString::code2utf(0x2069);
			} // POP DIRECTIONAL ISOLATE

		} elseif ($mode == 'start') {

			// LRI comes before LRO to open isolate-override (e.g. "LRILROPDFPDI")
			if (strpos($bdf, 'LRI') !== false) {  // U+2066 LRI
				$s .= UtfString::code2utf(0x2066);
			} elseif (strpos($bdf, 'RLI') !== false) { // U+2067 RLI
				$s .= UtfString::code2utf(0x2067);
			} elseif (strpos($bdf, 'FSI') !== false) { // U+2068 FSI
				$s .= UtfString::code2utf(0x2068);
			}

			if (strpos($bdf, 'LRO') !== false) { // U+202D LRO
				$s .= UtfString::code2utf(0x202D);
			} elseif (strpos($bdf, 'RLO') !== false) { // U+202E RLO
				$s .= UtfString::code2utf(0x202E);
			} elseif (strpos($bdf, 'LRE') !== false) { // U+202A LRE
				$s .= UtfString::code2utf(0x202A);
			} elseif (strpos($bdf, 'RLE') !== false) { // U+202B RLE
				$s .= UtfString::code2utf(0x202B);
			}
		}

		return $s;
	}
	/* -- END OTL -- */

	function SetSubstitutions()
	{
		$subsarray = [];
		require __DIR__ . '/../data/subs_win-1252.php';
		$this->substitute = [];
		foreach ($subsarray as $key => $val) {
			$this->substitute[UtfString::code2utf($key)] = $val;
		}
	}

	function SubstituteChars($html)
	{
		// only substitute characters between tags
		if (count($this->substitute)) {
			$a = preg_split('/(<.*?>)/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
			$html = '';
			foreach ($a as $i => $e) {
				if ($i % 2 == 0) {
					$e = strtr($e, $this->substitute);
				}
				$html .= $e;
			}
		}

		return $html;
	}

	function SubstituteCharsSIP(&$writehtml_a, &$writehtml_i, &$writehtml_e)
	{
		if (preg_match("/^(.*?)([\x{20000}-\x{2FFFF}]+)(.*)/u", $writehtml_e, $m)) {
			if (isset($this->CurrentFont['sipext']) && $this->CurrentFont['sipext']) {
				$font = $this->CurrentFont['sipext'];
				if (!in_array($font, $this->available_unifonts)) {
					return 0;
				}
				$writehtml_a[$writehtml_i] = $writehtml_e = $m[1];
				array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
				$this->subPos = $writehtml_i;
				return 4;
			}
		}

		return 0;
	}

	/**
	 * If core font is selected in document which is not onlyCoreFonts - substitute with non-core font
	 */
	function SubstituteCharsNonCore(&$writehtml_a, &$writehtml_i, &$writehtml_e)
	{
		// Ignore if in Textarea
		if ($writehtml_i > 0 && strtolower(substr($writehtml_a[$writehtml_i - 1], 0, 8)) == 'textarea') {
			return 0;
		}

		if (mb_convert_encoding(mb_convert_encoding($writehtml_e, $this->mb_enc, "UTF-8"), "UTF-8", $this->mb_enc) == $writehtml_e) {
			return 0;
		}

		$cw = &$this->CurrentFont['cw'];
		$unicode = $this->UTF8StringToArray($writehtml_e, false);
		$start = -1;
		$end = 0;
		$flag = 0;
		$ftype = '';
		$u = [];

		if (!$this->subArrMB) {

			require __DIR__ . '/../data/subs_core.php';

			$this->subArrMB['a'] = $aarr;
			$this->subArrMB['s'] = $sarr;
			$this->subArrMB['z'] = $zarr;
		}

		foreach ($unicode as $c => $char) {

			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)) {
				if ($flag == 0) {
					$start = $c;
				}
				$flag = 1;
				$u[] = $char;
			} elseif ($flag > 0) {
				$end = $c - 1;
				break;
			}
		}

		if ($flag > 0 && !$end) {
			$end = count($unicode) - 1;
		}

		if ($start == -1) {
			return 0;
		}

		// Try in backup subs font
		if (!is_array($this->backupSubsFont)) {
			$this->backupSubsFont = ["$this->backupSubsFont"];
		}

		foreach ($this->backupSubsFont as $bsfctr => $bsf) {

			if ($this->fonttrans[$bsf] == 'chelvetica' || $this->fonttrans[$bsf] == 'ctimes' || $this->fonttrans[$bsf] == 'ccourier') {
				continue;
			}

			$font = $bsf;
			unset($cw);
			$cw = '';

			if (isset($this->fonts[$font])) {
				$cw = &$this->fonts[$font]['cw'];
			} elseif ($this->fontCache->has($font . '.cw.dat')) {
				$cw = $this->fontCache->load($font . '.cw.dat');
			} else {
				$prevFontFamily = $this->FontFamily;
				$prevFontStyle = $this->currentfontstyle;
				$prevFontSizePt = $this->FontSizePt;
				$this->SetFont($bsf, '', '', false);
				$this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
			}

			if (!$cw) {
				continue;
			}

			$l = 0;
			foreach ($u as $char) {
				if ($char == 173 || $this->_charDefined($cw, $char) || ($char > 1536 && $char < 1791) || ($char > 2304 && $char < 3455 )) {
					$l++;
				} else {
					if ($l == 0 && $bsfctr == (count($this->backupSubsFont) - 1)) { // Not found even in last backup font
						$cont = mb_substr($writehtml_e, $start + 1);
						$writehtml_e = mb_substr($writehtml_e, 0, $start + 1, 'UTF-8');
						array_splice($writehtml_a, $writehtml_i + 1, 0, ['', $cont]);
						$this->subPos = $writehtml_i + 1;

						return 2;
					} else {
						break;
					}
				}
			}

			if ($l > 0) {
				$patt = mb_substr($writehtml_e, $start, $l, 'UTF-8');
				if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
					$writehtml_e = $m[1];
					array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
					$this->subPos = $writehtml_i + 3;

					return 4;
				}
			}
		}

		unset($cw);

		return 0;
	}

	function SubstituteCharsMB(&$writehtml_a, &$writehtml_i, &$writehtml_e)
	{
		// Ignore if in Textarea
		if ($writehtml_i > 0 && strtolower(substr($writehtml_a[$writehtml_i - 1], 0, 8)) == 'textarea') {
			return 0;
		}

		$cw = &$this->CurrentFont['cw'];
		$unicode = $this->UTF8StringToArray($writehtml_e, false);
		$start = -1;
		$end = 0;
		$flag = 0;
		$ftype = '';
		$u = [];

		foreach ($unicode as $c => $char) {

			if (($flag == 0 || $flag == 2) && (!$this->_charDefined($cw, $char) || ($flag == 2 && $char == 32)) && $this->checkSIP && $char > 131071) {  // Unicode Plane 2 (SIP)

				if (in_array($this->FontFamily, $this->available_CJK_fonts)) {
					return 0;
				}

				if ($flag == 0) {
					$start = $c;
				}

				$flag = 2;
				$u[] = $char;

				// elseif (($flag == 0 || $flag==1) && $char != 173 && !$this->_charDefined($cw,$char) && ($char<1423 ||  ($char>3583 && $char < 11263))) {

			} elseif (($flag == 0 || $flag == 1) && $char != 173 && (!$this->_charDefined($cw, $char) || ($flag == 1 && $char == 32)) && ($char < 1536 || ($char > 1791 && $char < 2304) || $char > 3455)) {

				if ($flag == 0) {
					$start = $c;
				}

				$flag = 1;
				$u[] = $char;

			} elseif ($flag > 0) {

				$end = $c - 1;
				break;

			}
		}

		if ($flag > 0 && !$end) {
			$end = count($unicode) - 1;
		}

		if ($start == -1) {
			return 0;
		}

		if ($flag == 2) { // SIP

			// Check if current CJK font has a ext-B related font
			if (isset($this->CurrentFont['sipext']) && $this->CurrentFont['sipext']) {
				$font = $this->CurrentFont['sipext'];
				unset($cw);
				$cw = '';

				if (isset($this->fonts[$font])) {
					$cw = &$this->fonts[$font]['cw'];
				} elseif ($this->fontCache->has($font . '.cw.dat')) {
					$cw = $this->fontCache->load($font . '.cw.dat');
				} else {
					$prevFontFamily = $this->FontFamily;
					$prevFontStyle = $this->currentfontstyle;
					$prevFontSizePt = $this->FontSizePt;
					$this->SetFont($font, '', '', false);
					$this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
				}

				if (!$cw) {
					return 0;
				}

				$l = 0;
				foreach ($u as $char) {
					if ($this->_charDefined($cw, $char) || $char > 131071) {
						$l++;
					} else {
						break;
					}
				}

				if ($l > 0) {
					$patt = mb_substr($writehtml_e, $start, $l);
					if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
						$writehtml_e = $m[1];
						array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
						$this->subPos = $writehtml_i + 3;
						return 4;
					}
				}
			}

			// Check Backup SIP font (defined in Config\FontVariables)
			if (isset($this->backupSIPFont) && $this->backupSIPFont) {

				if ($this->currentfontfamily != $this->backupSIPFont) {
					$font = $this->backupSIPFont;
				} else {
					unset($cw);
					return 0;
				}

				unset($cw);
				$cw = '';

				if (isset($this->fonts[$font])) {
					$cw = &$this->fonts[$font]['cw'];
				} elseif ($this->fontCache->has($font . '.cw.dat')) {
					$cw = $this->fontCache->load($font . '.cw.dat');
				} else {
					$prevFontFamily = $this->FontFamily;
					$prevFontStyle = $this->currentfontstyle;
					$prevFontSizePt = $this->FontSizePt;
					$this->SetFont($this->backupSIPFont, '', '', false);
					$this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
				}

				if (!$cw) {
					return 0;
				}

				$l = 0;
				foreach ($u as $char) {
					if ($this->_charDefined($cw, $char) || $char > 131071) {
						$l++;
					} else {
						break;
					}
				}

				if ($l > 0) {
					$patt = mb_substr($writehtml_e, $start, $l);
					if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
						$writehtml_e = $m[1];
						array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
						$this->subPos = $writehtml_i + 3;
						return 4;
					}
				}
			}

			return 0;
		}

		// FIRST TRY CORE FONTS (when appropriate)
		if (!$this->PDFA && !$this->PDFX && !$this->biDirectional) {  // mPDF 6
			$repl = [];
			if (!$this->subArrMB) {
				require __DIR__ . '/../data/subs_core.php';
				$this->subArrMB['a'] = $aarr;
				$this->subArrMB['s'] = $sarr;
				$this->subArrMB['z'] = $zarr;
			}
			if (isset($this->subArrMB['a'][$u[0]])) {
				$font = 'tta';
				$ftype = 'C';
				foreach ($u as $char) {
					if (isset($this->subArrMB['a'][$char])) {
						$repl[] = $this->subArrMB['a'][$char];
					} else {
						break;
					}
				}
			} elseif (isset($this->subArrMB['z'][$u[0]])) {
				$font = 'ttz';
				$ftype = 'C';
				foreach ($u as $char) {
					if (isset($this->subArrMB['z'][$char])) {
						$repl[] = $this->subArrMB['z'][$char];
					} else {
						break;
					}
				}
			} elseif (isset($this->subArrMB['s'][$u[0]])) {
				$font = 'tts';
				$ftype = 'C';
				foreach ($u as $char) {
					if (isset($this->subArrMB['s'][$char])) {
						$repl[] = $this->subArrMB['s'][$char];
					} else {
						break;
					}
				}
			}
			if ($ftype == 'C') {
				$patt = mb_substr($writehtml_e, $start, count($repl));
				if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
					$writehtml_e = $m[1];
					array_splice($writehtml_a, $writehtml_i + 1, 0, [$font, implode('|', $repl), '/' . $font, $m[3]]); // e.g. <tts>
					$this->subPos = $writehtml_i + 3;
					return 4;
				}
				return 0;
			}
		}

		// LASTLY TRY IN BACKUP SUBS FONT
		if (!is_array($this->backupSubsFont)) {
			$this->backupSubsFont = ["$this->backupSubsFont"];
		}

		foreach ($this->backupSubsFont as $bsfctr => $bsf) {
			if ($this->currentfontfamily != $bsf) {
				$font = $bsf;
			} else {
				continue;
			}

			unset($cw);
			$cw = '';

			if (isset($this->fonts[$font])) {
				$cw = &$this->fonts[$font]['cw'];
			} elseif ($this->fontCache->has($font . '.cw.dat')) {
				$cw = $this->fontCache->load($font . '.cw.dat');
			} else {
				$prevFontFamily = $this->FontFamily;
				$prevFontStyle = $this->currentfontstyle;
				$prevFontSizePt = $this->FontSizePt;
				$this->SetFont($bsf, '', '', false);
				$this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
				if ($this->fontCache->has($font . '.cw.dat')) {
					$cw = $this->fontCache->load($font . '.cw.dat');
				}
			}

			if (!$cw) {
				continue;
			}

			$l = 0;
			foreach ($u as $char) {
				if ($char == 173 || $this->_charDefined($cw, $char) || ($char > 1536 && $char < 1791) || ($char > 2304 && $char < 3455 )) {  // Arabic and Indic
					$l++;
				} else {
					if ($l == 0 && $bsfctr == (count($this->backupSubsFont) - 1)) { // Not found even in last backup font
						$cont = mb_substr($writehtml_e, $start + 1);
						$writehtml_e = mb_substr($writehtml_e, 0, $start + 1);
						array_splice($writehtml_a, $writehtml_i + 1, 0, ['', $cont]);
						$this->subPos = $writehtml_i + 1;
						return 2;
					} else {
						break;
					}
				}
			}

			if ($l > 0) {
				$patt = mb_substr($writehtml_e, $start, $l);
				if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
					$writehtml_e = $m[1];
					array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
					$this->subPos = $writehtml_i + 3;
					return 4;
				}
			}
		}

		unset($cw);

		return 0;
	}

	function setHiEntitySubstitutions()
	{
		$entarr = include __DIR__ . '/../data/entity_substitutions.php';

		foreach ($entarr as $key => $val) {
			$this->entsearch[] = '&' . $key . ';';
			$this->entsubstitute[] = UtfString::code2utf($val);
		}
	}

	function SubstituteHiEntities($html)
	{
		// converts html_entities > ASCII 127 to unicode
		// Leaves in particular &lt; to distinguish from tag marker
		if (count($this->entsearch)) {
			$html = str_replace($this->entsearch, $this->entsubstitute, $html);
		}

		return $html;
	}

	/**
	 * Edited v1.2 Pass by reference; option to continue if invalid UTF-8 chars
	 */
	function is_utf8(&$string)
	{
		if ($string === mb_convert_encoding(mb_convert_encoding($string, "UTF-32", "UTF-8"), "UTF-8", "UTF-32")) {
			return true;
		}

		if ($this->ignore_invalid_utf8) {
			$string = mb_convert_encoding(mb_convert_encoding($string, "UTF-32", "UTF-8"), "UTF-8", "UTF-32");
			return true;
		}

		return false;
	}

	/**
	 * For HTML
	 *
	 * Checks string is valid UTF-8 encoded
	 * converts html_entities > ASCII 127 to UTF-8
	 * Only exception - leaves low ASCII entities e.g. &lt; &amp; etc.
	 * Leaves in particular &lt; to distinguish from tag marker
	 */
	function purify_utf8($html, $lo = true)
	{
		if (!$this->is_utf8($html)) {

			while (mb_convert_encoding(mb_convert_encoding($html, "UTF-32", "UTF-8"), "UTF-8", "UTF-32") !== $html) {

				$a = @iconv('UTF-8', 'UTF-8', $html);
				$error = error_get_last();
				if ($error && $error['message'] === 'iconv(): Detected an illegal character in input string') {
					throw new \Mpdf\MpdfException('Invalid input characters. Did you set $mpdf->in_charset properly?');
				}

				$pos = $start = strlen($a);
				$err = '';
				while (ord(substr($html, $pos, 1)) > 128) {
					$err .= '[[#' . ord(substr($html, $pos, 1)) . ']]';
					$pos++;
				}

				$this->logger->error($err, ['context' => LogContext::UTF8]);
				$html = substr($html, $pos);
			}

			throw new \Mpdf\MpdfException("HTML contains invalid UTF-8 character(s). See log for further details");
		}

		$html = preg_replace("/\r/", "", $html);

		// converts html_entities > ASCII 127 to UTF-8
		// Leaves in particular &lt; to distinguish from tag marker
		$html = $this->SubstituteHiEntities($html);

		// converts all &#nnn; or &#xHHH; to UTF-8 multibyte
		// If $lo==true then includes ASCII < 128
		$html = UtfString::strcode2utf($html, $lo);

		return $html;
	}

	/**
	 * For TEXT
	 */
	function purify_utf8_text($txt)
	{
		// Make sure UTF-8 string of characters
		if (!$this->is_utf8($txt)) {
			throw new \Mpdf\MpdfException("Text contains invalid UTF-8 character(s)");
		}

		$txt = preg_replace("/\r/", "", $txt);

		return ($txt);
	}

	function all_entities_to_utf8($txt)
	{
		// converts txt_entities > ASCII 127 to UTF-8
		// Leaves in particular &lt; to distinguish from tag marker
		$txt = $this->SubstituteHiEntities($txt);

		// converts all &#nnn; or &#xHHH; to UTF-8 multibyte
		$txt = UtfString::strcode2utf($txt);

		$txt = $this->lesser_entity_decode($txt);
		return ($txt);
	}

	/* -- BARCODES -- */
	/**
	 * UPC/EAN barcode
	 *
	 * EAN13, EAN8, UPCA, UPCE, ISBN, ISSN
	 * Accepts 12 or 13 digits with or without - hyphens
	 */
	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)
	{
		if (empty($code)) {
			return;
		}

		$codestr = $code;
		$code = preg_replace('/\-/', '', $code);

		$this->barcode = new Barcode();
		if ($btype == 'ISSN' || $btype == 'ISBN') {
			$arrcode = $this->barcode->getBarcodeArray($code, 'EAN13');
		} else {
			$arrcode = $this->barcode->getBarcodeArray($code, $btype);
		}

		if ($arrcode === false) {
			throw new \Mpdf\MpdfException('Error in barcode string: ' . $codestr);
		}

		if ((($btype === 'EAN13' || $btype === 'ISBN' || $btype === 'ISSN') && strlen($code) === 12)
				|| ($btype == 'UPCA' && strlen($code) === 11)
				|| ($btype == 'UPCE' && strlen($code) === 11)
				|| ($btype == 'EAN8' && strlen($code) === 7)) {

			$code .= $arrcode['checkdigit'];

			if (stristr($codestr, '-')) {
				$codestr .= '-' . $arrcode['checkdigit'];
			} else {
				$codestr .= $arrcode['checkdigit'];
			}
		}

		if ($btype === 'ISBN') {
			$codestr = 'ISBN ' . $codestr;
		}

		if ($btype === 'ISSN') {
			$codestr = 'ISSN ' . $codestr;
		}

		if (empty($x)) {
			$x = $this->x;
		}

		if (empty($y)) {
			$y = $this->y;
		}

		// set foreground color
		$prevDrawColor = $this->DrawColor;
		$prevTextColor = $this->TextColor;
		$prevFillColor = $this->FillColor;

		$lw = $this->LineWidth;
		$this->SetLineWidth(0.01);

		$size /= $k; // in case resized in a table

		$xres = $arrcode['nom-X'] * $size;
		$llm = $arrcode['lightmL'] * $arrcode['nom-X'] * $size; // Left Light margin
		$rlm = $arrcode['lightmR'] * $arrcode['nom-X'] * $size; // Right Light margin

		$bcw = ($arrcode["maxw"] * $xres); // Barcode width = Should always be 31.35mm * $size

		$fbw = $bcw + $llm + $rlm; // Full barcode width incl. light margins
		$ow = $fbw + $paddingL + $paddingR; // Full overall width incl. user-defined padding

		$fbwi = $fbw - 2; // Full barcode width incl. light margins - 2mm - for isbn string
		// cf. http://www.gs1uk.org/downloads/bar_code/Bar coding getting it right.pdf
		$num_height = 3 * $size;     // Height of numerals
		$fbh = $arrcode['nom-H'] * $size * $height;  // Full barcode height incl. numerals
		$bch = $fbh - (1.5 * $size);     // Barcode height of bars	 (3mm for numerals)

		if (($btype == 'EAN13' && $showtext) || $btype == 'ISSN' || $btype == 'ISBN') { // Add height for ISBN string + margin from top of bars
			$tisbnm = 1.5 * $size; // Top margin between isbn (if shown) & bars
			$codestr_fontsize = 2.1 * $size;
			$paddingT += $codestr_fontsize + $tisbnm;
		}

		$oh = $fbh + $paddingT + $paddingB;  // Full overall height incl. user-defined padding

		// PRINT border background color
		$xpos = $x;
		$ypos = $y;

		if ($col) {
			$this->SetDColor($col);
			$this->SetTColor($col);
		} else {
			$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
			$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
		}

		if ($bgcol) {
			$this->SetFColor($bgcol);
		} else {
			$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
		}

		if (!$bgcol && !$col) { // fn. called directly - not via HTML

			if ($border) {
				$fillb = 'DF';
			} else {
				$fillb = 'F';
			}

			$this->Rect($xpos, $ypos, $ow, $oh, $fillb);
		}


		// PRINT BARS
		$xpos = $x + $paddingL + $llm;
		$ypos = $y + $paddingT;

		if ($col) {
			$this->SetFColor($col);
		} else {
			$this->SetFColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
		}

		if ($arrcode !== false) {
			foreach ($arrcode["bcode"] as $v) {
				$bw = ($v["w"] * $xres);
				if ($v["t"]) {
					// draw a vertical bar
					$this->Rect($xpos, $ypos, $bw, $bch, 'F');
				}
				$xpos += $bw;
			}
		}

		// print text
		$prevFontFamily = $this->FontFamily;
		$prevFontStyle = $this->FontStyle;
		$prevFontSizePt = $this->FontSizePt;

		// ISBN string
		if (($btype === 'EAN13' && $showtext) || $btype === 'ISBN' || $btype === 'ISSN') {

			if ($this->onlyCoreFonts) {
				$this->SetFont('chelvetica');
			} else {
				$this->SetFont('sans');
			}

			if ($bgcol) {
				$this->SetFColor($bgcol);
			} else {
				$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
			}

			$this->x = $x + $paddingL + 1; // 1mm left margin (cf. $fbwi above)

			// max width is $fbwi
			$loop = 0;
			while ($loop == 0) {
				$this->SetFontSize($codestr_fontsize * 1.4 * Mpdf::SCALE, false); // don't write
				$sz = $this->GetStringWidth($codestr);

				if ($sz > $fbwi) {
					$codestr_fontsize -= 0.1;
				} else {
					$loop ++;
				}
			}

			$this->SetFont('', '', $codestr_fontsize * 1.4 * Mpdf::SCALE, true, true); // * 1.4 because font height is only 7/10 of given mm
			// WORD SPACING
			if ($fbwi > $sz) {
				$xtra = $fbwi - $sz;
				$charspacing = $xtra / (strlen($codestr) - 1);
				if ($charspacing) {
					$this->writer->write(sprintf('BT %.3F Tc ET', $charspacing * Mpdf::SCALE));
				}
			}

			$this->y = $y + $paddingT - ($codestr_fontsize ) - $tisbnm;
			$this->Cell($fbw, $codestr_fontsize, $codestr);

			if ($charspacing) {
				$this->writer->write('BT 0 Tc ET');
			}
		}


		// Bottom NUMERALS
		// mPDF 5.7.4
		if ($this->onlyCoreFonts) {
			$this->SetFont('ccourier');
			$fh = 1.3;
		} else {
			$this->SetFont('ocrb');
			$fh = 1.06;
		}

		$charRO = '';

		if ($btype === 'EAN13' || $btype === 'ISBN' || $btype === 'ISSN') {

			$outerfontsize = 3; // Inner fontsize = 3
			$outerp = $xres * 4;
			$innerp = $xres * 2.5;
			$textw = ($bcw * 0.5) - $outerp - $innerp;
			$chars = 6; // number of numerals in each half
			$charLO = substr($code, 0, 1); // Left Outer
			$charLI = substr($code, 1, 6); // Left Inner
			$charRI = substr($code, 7, 6); // Right Inner

			if (!$supplement) {
				$charRO = '>'; // Right Outer
			}

		} elseif ($btype === 'UPCA') {

			$outerfontsize = 2.3; // Inner fontsize = 3
			$outerp = $xres * 10;
			$innerp = $xres * 2.5;
			$textw = ($bcw * 0.5) - $outerp - $innerp;
			$chars = 5;
			$charLO = substr($code, 0, 1); // Left Outer
			$charLI = substr($code, 1, 5); // Left Inner
			$charRI = substr($code, 6, 5); // Right Inner
			$charRO = substr($code, 11, 1); // Right Outer

		} elseif ($btype === 'UPCE') {

			$outerfontsize = 2.3; // Inner fontsize = 3
			$outerp = $xres * 4;
			$innerp = 0;
			$textw = ($bcw * 0.5) - $outerp - $innerp;
			$chars = 3;
			$upce_code = $arrcode['code'];
			$charLO = substr($code, 0, 1); // Left Outer
			$charLI = substr($upce_code, 0, 3); // Left Inner
			$charRI = substr($upce_code, 3, 3); // Right Inner
			$charRO = substr($code, 11, 1); // Right Outer

		} elseif ($btype === 'EAN8') {

			$outerfontsize = 3; // Inner fontsize = 3
			$outerp = $xres * 4;
			$innerp = $xres * 2.5;
			$textw = ($bcw * 0.5) - $outerp - $innerp;
			$chars = 4;
			$charLO = '<'; // Left Outer
			$charLI = substr($code, 0, 4); // Left Inner
			$charRI = substr($code, 4, 4); // Right Inner

			if (!$supplement) {
				$charRO = '>'; // Right Outer
			}
		}

		$this->SetFontSize(($outerfontsize / 3) * 3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)

		if (!$this->usingCoreFont) { // character width at 3mm
			$cw = $this->_getCharWidth($this->CurrentFont['cw'], 32) * 3 * $fh * $size / 1000;
		} else {
			$cw = 600 * 3 * $fh * $size / 1000;
		}

		// Outer left character
		$y_text = $y + $paddingT + $bch - ($num_height / 2);
		$y_text_outer = $y + $paddingT + $bch - ($num_height * ($outerfontsize / 3) / 2);

		$this->x = $x + $paddingL - ($cw * ($outerfontsize / 3) * 0.1); // 0.1 is correction as char does not fill full width;
		$this->y = $y_text_outer;
		$this->Cell($cw, $num_height, $charLO);

		// WORD SPACING for inner chars
		$xtra = $textw - ($cw * $chars);
		$charspacing = $xtra / ($chars - 1);
		if ($charspacing) {
			$this->writer->write(sprintf('BT %.3F Tc ET', $charspacing * Mpdf::SCALE));
		}

		if ($bgcol) {
			$this->SetFColor($bgcol);
		} else {
			$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
		}

		$this->SetFontSize(3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)

		// Inner left half characters
		$this->x = $x + $paddingL + $llm + $outerp;
		$this->y = $y_text;
		$this->Cell($textw, $num_height, $charLI, 0, 0, '', 1);

		// Inner right half characters
		$this->x = $x + $paddingL + $llm + ($bcw * 0.5) + $innerp;
		$this->y = $y_text;
		$this->Cell($textw, $num_height, $charRI, 0, 0, '', 1);

		if ($charspacing) {
			$this->writer->write('BT 0 Tc ET');
		}

		// Outer Right character
		$this->SetFontSize(($outerfontsize / 3) * 3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)

		$this->x = $x + $paddingL + $llm + $bcw + $rlm - ($cw * ($outerfontsize / 3) * 0.9); // 0.9 is correction as char does not fill full width
		$this->y = $y_text_outer;
		$this->Cell($cw * ($outerfontsize / 3), $num_height, $charRO, 0, 0, 'R');

		if ($supplement) { // EAN-2 or -5 Supplement
			// PRINT BARS
			$supparrcode = $this->barcode->getBarcodeArray($supplement_code, 'EAN' . $supplement);

			if ($supparrcode === false) {
				throw new \Mpdf\MpdfException('Error in barcode string (supplement): ' . $codestr . ' ' . $supplement_code);
			}

			if (strlen($supplement_code) != $supplement) {
				throw new \Mpdf\MpdfException('Barcode supplement incorrect: ' . $supplement_code);
			}

			$llm = $fbw - (($arrcode['lightmR'] - $supparrcode['sepM']) * $arrcode['nom-X'] * $size); // Left Light margin
			$rlm = $arrcode['lightmR'] * $arrcode['nom-X'] * $size; // Right Light margin

			$bcw = ($supparrcode["maxw"] * $xres); // Barcode width = Should always be 31.35mm * $size

			$fbw = $bcw + $llm + $rlm; // Full barcode width incl. light margins
			$ow = $fbw + $paddingL + $paddingR; // Full overall width incl. user-defined padding
			$bch = $fbh - (1.5 * $size) - ($num_height + 0.5);  // Barcode height of bars	 (3mm for numerals)

			$xpos = $x + $paddingL + $llm;
			$ypos = $y + $paddingT + $num_height + 0.5;

			if ($col) {
				$this->SetFColor($col);
			} else {
				$this->SetFColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
			}

			if ($supparrcode !== false) {
				foreach ($supparrcode["bcode"] as $v) {
					$bw = ($v["w"] * $xres);
					if ($v["t"]) {
						// draw a vertical bar
						$this->Rect($xpos, $ypos, $bw, $bch, 'F');
					}
					$xpos += $bw;
				}
			}

			// Characters
			if ($bgcol) {
				$this->SetFColor($bgcol);
			} else {
				$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
			}

			$this->SetFontSize(3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)
			$this->x = $x + $paddingL + $llm;
			$this->y = $y + $paddingT;
			$this->Cell($bcw, $num_height, $supplement_code, 0, 0, 'C');

			// Outer Right character (light margin)
			$this->SetFontSize(($outerfontsize / 3) * 3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)
			$this->x = $x + $paddingL + $llm + $bcw + $rlm - ($cw * 0.9); // 0.9 is correction as char does not fill full width
			$this->y = $y + $paddingT;
			$this->Cell($cw * ($outerfontsize / 3), $num_height, '>', 0, 0, 'R');
		}

		// Restore **************
		$this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt);
		$this->DrawColor = $prevDrawColor;
		$this->TextColor = $prevTextColor;
		$this->FillColor = $prevFillColor;
		$this->SetLineWidth($lw);
		$this->SetY($y);
	}

	/**
	 * POSTAL and OTHER barcodes
	 */
	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)
	{
		if (empty($code)) {
			return;
		}

		$this->barcode = new Barcode();
		$arrcode = $this->barcode->getBarcodeArray($code, $btype, $print_ratio, $quiet_zone_left, $quiet_zone_right);

		if (empty($x)) {
			$x = $this->x;
		}

		if (empty($y)) {
			$y = $this->y;
		}

		$prevDrawColor = $this->DrawColor;
		$prevTextColor = $this->TextColor;
		$prevFillColor = $this->FillColor;
		$lw = $this->LineWidth;
		$this->SetLineWidth(0.01);
		$size /= $k; // in case resized in a table
		$xres = $arrcode['nom-X'] * $size;

		if ($btype === 'IMB' || $btype === 'RM4SCC' || $btype === 'KIX' || $btype === 'POSTNET' || $btype === 'PLANET') {
			$llm = $arrcode['quietL'] / $k; // Left Quiet margin
			$rlm = $arrcode['quietR'] / $k; // Right Quiet margin
			$tlm = $blm = $arrcode['quietTB'] / $k;
			$height = 1;  // Overrides
		} 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'])) {
			$llm = $arrcode['lightmL'] * $xres; // Left Quiet margin
			$rlm = $arrcode['lightmR'] * $xres; // Right Quiet margin
			$tlm = $blm = $arrcode['lightTB'] * $xres * $height;
		}

		$bcw = ($arrcode["maxw"] * $xres);
		$fbw = $bcw + $llm + $rlm;  // Full barcode width incl. light margins

		$bch = ($arrcode["nom-H"] * $size * $height);
		$fbh = $bch + $tlm + $blm;  // Full barcode height

		// PRINT border background color
		$xpos = $x;
		$ypos = $y;

		if ($col) {
			$this->SetDColor($col);
			$this->SetTColor($col);
		} else {
			$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
			$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
		}

		if ($bgcol) {
			$this->SetFColor($bgcol);
		} else {
			$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
		}

		// PRINT BARS
		if ($col) {
			$this->SetFColor($col);
		} else {
			$this->SetFColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
		}
		$xpos = $x + $llm;

		if ($arrcode !== false) {
			foreach ($arrcode["bcode"] as $v) {
				$bw = ($v["w"] * $xres);
				if ($v["t"]) {
					$ypos = $y + $tlm + ($bch * $v['p'] / $arrcode['maxh']);
					$this->Rect($xpos, $ypos, $bw, ($v['h'] * $bch / $arrcode['maxh']), 'F');
				}
				$xpos += $bw;
			}
		}

		// PRINT BEARER BARS
		if ($btype == 'I25B' || $btype == 'I25B+') {
			$this->Rect($x, $y, $fbw, ($arrcode['lightTB'] * $xres * $height), 'F');
			$this->Rect($x, $y + $tlm + $bch, $fbw, ($arrcode['lightTB'] * $xres * $height), 'F');
		}

		// Restore **************
		$this->DrawColor = $prevDrawColor;
		$this->TextColor = $prevTextColor;
		$this->FillColor = $prevFillColor;
		$this->SetLineWidth($lw);
		$this->SetY($y);
	}
	/* -- END BARCODES -- */

	function StartTransform($returnstring = false)
	{
		if ($returnstring) {
			return('q');
		} else {
			$this->writer->write('q');
		}
	}

	function StopTransform($returnstring = false)
	{
		if ($returnstring) {
			return('Q');
		} else {
			$this->writer->write('Q');
		}
	}

	function transformScale($s_x, $s_y, $x = '', $y = '', $returnstring = false)
	{
		if ($x === '') {
			$x = $this->x;
		}

		if ($y === '') {
			$y = $this->y;
		}

		if (($s_x == 0) or ( $s_y == 0)) {
			throw new \Mpdf\MpdfException('Please do not use values equal to zero for scaling');
		}

		$y = ($this->h - $y) * Mpdf::SCALE;
		$x *= Mpdf::SCALE;

		// calculate elements of transformation matrix
		$s_x /= 100;
		$s_y /= 100;
		$tm = [];
		$tm[0] = $s_x;
		$tm[1] = 0;
		$tm[2] = 0;
		$tm[3] = $s_y;
		$tm[4] = $x * (1 - $s_x);
		$tm[5] = $y * (1 - $s_y);

		// scale the coordinate system
		if ($returnstring) {
			return($this->_transform($tm, true));
		} else {
			$this->_transform($tm);
		}
	}

	function transformTranslate($t_x, $t_y, $returnstring = false)
	{
		// calculate elements of transformation matrix
		$tm = [];
		$tm[0] = 1;
		$tm[1] = 0;
		$tm[2] = 0;
		$tm[3] = 1;
		$tm[4] = $t_x * Mpdf::SCALE;
		$tm[5] = -$t_y * Mpdf::SCALE;

		// translate the coordinate system
		if ($returnstring) {
			return($this->_transform($tm, true));
		} else {
			$this->_transform($tm);
		}
	}

	function transformRotate($angle, $x = '', $y = '', $returnstring = false)
	{
		if ($x === '') {
			$x = $this->x;
		}

		if ($y === '') {
			$y = $this->y;
		}

		$angle = -$angle;
		$y = ($this->h - $y) * Mpdf::SCALE;
		$x *= Mpdf::SCALE;

		// calculate elements of transformation matrix
		$tm = [];
		$tm[0] = cos(deg2rad($angle));
		$tm[1] = sin(deg2rad($angle));
		$tm[2] = -$tm[1];
		$tm[3] = $tm[0];
		$tm[4] = $x + $tm[1] * $y - $tm[0] * $x;
		$tm[5] = $y - $tm[0] * $y - $tm[1] * $x;

		// rotate the coordinate system around ($x,$y)
		if ($returnstring) {
			return $this->_transform($tm, true);
		} else {
			$this->_transform($tm);
		}
	}

	/**
	 * mPDF 5.7.3 TRANSFORMS
	 */
	function transformSkew($angle_x, $angle_y, $x = '', $y = '', $returnstring = false)
	{
		if ($x === '') {
			$x = $this->x;
		}

		if ($y === '') {
			$y = $this->y;
		}

		$angle_x = -$angle_x;
		$angle_y = -$angle_y;

		$x *= Mpdf::SCALE;
		$y = ($this->h - $y) * Mpdf::SCALE;

		// calculate elements of transformation matrix
		$tm = [];
		$tm[0] = 1;
		$tm[1] = tan(deg2rad($angle_y));
		$tm[2] = tan(deg2rad($angle_x));
		$tm[3] = 1;
		$tm[4] = -$tm[2] * $y;
		$tm[5] = -$tm[1] * $x;

		// skew the coordinate system
		if ($returnstring) {
			return $this->_transform($tm, true);
		} else {
			$this->_transform($tm);
		}
	}

	function _transform($tm, $returnstring = false)
	{
		if ($returnstring) {
			return(sprintf('%.4F %.4F %.4F %.4F %.4F %.4F cm', $tm[0], $tm[1], $tm[2], $tm[3], $tm[4], $tm[5]));
		} else {
			$this->writer->write(sprintf('%.4F %.4F %.4F %.4F %.4F %.4F cm', $tm[0], $tm[1], $tm[2], $tm[3], $tm[4], $tm[5]));
		}
	}

	// AUTOFONT =========================
	function markScriptToLang($html)
	{
		if ($this->onlyCoreFonts) {
			return $html;
		}

		$n = '';
		$a = preg_split('/<(.*?)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
		foreach ($a as $i => $e) {
			if ($i % 2 == 0) {

				// ignore if in Textarea
				if ($i > 0 && strtolower(substr($a[$i - 1], 1, 8)) == 'textarea') {
					$a[$i] = $e;
					continue;
				}

				$e = UtfString::strcode2utf($e);
				$e = $this->lesser_entity_decode($e);

				$earr = $this->UTF8StringToArray($e, false);

				$scriptblock = 0;
				$scriptblocks = [];
				$scriptblocks[0] = 0;
				$chardata = [];
				$subchunk = 0;
				$charctr = 0;

				foreach ($earr as $char) {

					$ucd_record = Ucdn::get_ucd_record($char);
					$sbl = $ucd_record[6];

					if ($sbl && $sbl != 40 && $sbl != 102) {
						if ($scriptblock == 0) {
							$scriptblock = $sbl;
							$scriptblocks[$subchunk] = $scriptblock;
						} elseif ($scriptblock > 0 && $scriptblock != $sbl) {
							// NEW (non-common) Script encountered in this chunk.
							// Start a new subchunk
							$subchunk++;
							$scriptblock = $sbl;
							$charctr = 0;
							$scriptblocks[$subchunk] = $scriptblock;
						}
					}

					$chardata[$subchunk][$charctr]['script'] = $sbl;
					$chardata[$subchunk][$charctr]['uni'] = $char;
					$charctr++;
				}

				// If scriptblock[x] = common & non-baseScript
				// and scriptblock[x+1] = baseScript
				// Move common script from end of x to start of x+1
				for ($sch = 0; $sch < $subchunk; $sch++) {
					if ($scriptblocks[$sch] > 0 && $scriptblocks[$sch] != $this->baseScript && $scriptblocks[$sch + 1] == $this->baseScript) {
						$end = count($chardata[$sch]) - 1;
						while ($chardata[$sch][$end]['script'] == 0 && $end > 1) { // common script
							$tmp = array_pop($chardata[$sch]);
							array_unshift($chardata[$sch + 1], $tmp);
							$end--;
						}
					}
				}

				$o = '';
				for ($sch = 0; $sch <= $subchunk; $sch++) {

					if (isset($chardata[$sch])) {
						$s = '';
						for ($j = 0; $j < count($chardata[$sch]); $j++) {
							$s .= UtfString::code2utf($chardata[$sch][$j]['uni']);
						}

						// ZZZ99 Undo lesser_entity_decode as above - but only for <>&
						$s = str_replace("&", "&amp;", $s);
						$s = str_replace("<", "&lt;", $s);
						$s = str_replace(">", "&gt;", $s);

						// Check Vietnamese if Latin script - even if Basescript
						if ($scriptblocks[$sch] == Ucdn::SCRIPT_LATIN && $this->autoVietnamese && preg_match("/([" . $this->scriptToLanguage->getLanguageDelimiters('viet') . "])/u", $s)) {
							$o .= '<span lang="vi" class="lang_vi">' . $s . '</span>';
						} elseif ($scriptblocks[$sch] == Ucdn::SCRIPT_ARABIC && $this->autoArabic) { // Check Arabic for different languages if Arabic script - even if Basescript
							if (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('sindhi') . "]/u", $s)) {
								$o .= '<span lang="sd" class="lang_sd">' . $s . '</span>';
							} elseif (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('urdu') . "]/u", $s)) {
								$o .= '<span lang="ur" class="lang_ur">' . $s . '</span>';
							} elseif (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('pashto') . "]/u", $s)) {
								$o .= '<span lang="ps" class="lang_ps">' . $s . '</span>';
							} elseif (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('persian') . "]/u", $s)) {
								$o .= '<span lang="fa" class="lang_fa">' . $s . '</span>';
							} elseif ($this->baseScript != Ucdn::SCRIPT_ARABIC && $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch])) {
								$o .= '<span lang="' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '" class="lang_' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '">' . $s . '</span>';
							} else {
								// Just output chars
								$o .= $s;
							}
						} elseif ($scriptblocks[$sch] > 0 && $scriptblocks[$sch] != $this->baseScript && $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch])) { // Identify Script block if not Basescript, and mark up as language
							// Encase in <span>
							$o .= '<span lang="' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '" class="lang_' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '">';
							$o .= $s;
							$o .= '</span>';
						} else {
							// Just output chars
							$o .= $s;
						}
					}
				}

				$a[$i] = $o;
			} else {
				$a[$i] = '<' . $e . '>';
			}
		}

		$n = implode('', $a);

		return $n;
	}

	/* -- COLUMNS -- */
	/**
	 * Callback function from function printcolumnbuffer in mpdf
	 */
	function columnAdjustAdd($type, $k, $xadj, $yadj, $a, $b, $c = 0, $d = 0, $e = 0, $f = 0)
	{
		if ($type === 'Td') {  // xpos,ypos

			$a += ($xadj * $k);
			$b -= ($yadj * $k);

			return 'BT ' . sprintf('%.3F %.3F', $a, $b) . ' Td';

		} elseif ($type === 're') {  // xpos,ypos,width,height

			$a += ($xadj * $k);
			$b -= ($yadj * $k);

			return sprintf('%.3F %.3F %.3F %.3F', $a, $b, $c, $d) . ' re';

		} elseif ($type === 'l') {  // xpos,ypos,x2pos,y2pos

			$a += ($xadj * $k);
			$b -= ($yadj * $k);

			return sprintf('%.3F %.3F l', $a, $b);

		} elseif ($type === 'img') {  // width,height,xpos,ypos

			$c += ($xadj * $k);
			$d -= ($yadj * $k);

			return sprintf('q %.3F 0 0 %.3F %.3F %.3F', $a, $b, $c, $d) . ' cm /' . $e;

		} elseif ($type === 'draw') {  // xpos,ypos

			$a += ($xadj * $k);
			$b -= ($yadj * $k);

			return sprintf('%.3F %.3F m', $a, $b);

		} elseif ($type === 'bezier') {  // xpos,ypos,x2pos,y2pos,x3pos,y3pos

			$a += ($xadj * $k);
			$b -= ($yadj * $k);
			$c += ($xadj * $k);
			$d -= ($yadj * $k);
			$e += ($xadj * $k);
			$f -= ($yadj * $k);

			return sprintf('%.3F %.3F %.3F %.3F %.3F %.3F', $a, $b, $c, $d, $e, $f) . ' c';
		}
	}

	/* -- END COLUMNS -- */

	// mPDF 5.7.3 TRANSFORMS
	function ConvertAngle($s, $makepositive = true)
	{
		if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i', $s, $m)) {

			$angle = $m[1] + 0;

			if (strtolower($m[2]) == 'deg') {
				$angle = $angle;
			} elseif (strtolower($m[2]) == 'grad') {
				$angle *= (360 / 400);
			} elseif (strtolower($m[2]) == 'rad') {
				$angle = rad2deg($angle);
			}

			while ($angle >= 360) {
				$angle -= 360;
			}

			while ($angle <= -360) {
				$angle += 360;
			}

			if ($makepositive) { // always returns an angle between 0 and 360deg
				if ($angle < 0) {
					$angle += 360;
				}
			}

		} else {
			$angle = $s + 0;
		}

		return $angle;
	}

	function lesser_entity_decode($html)
	{
		// supports the most used entity codes (only does ascii safe characters)
		$html = str_replace("&lt;", "<", $html);
		$html = str_replace("&gt;", ">", $html);

		$html = str_replace("&apos;", "'", $html);
		$html = str_replace("&quot;", '"', $html);
		$html = str_replace("&amp;", "&", $html);

		return $html;
	}

	function AdjustHTML($html, $tabSpaces = 8)
	{
		$limit = ini_get('pcre.backtrack_limit');

		if (0 >= (int) $limit) {
			throw new \Mpdf\MpdfException(sprintf(
				'mPDF will not process HTML with disabled pcre.backtrack_limit to prevent unexpected behaviours, please set a positive backtrack limit.',
				$limit
			));
		}

		if (strlen($html) > (int) $limit) {
			throw new \Mpdf\MpdfException(sprintf(
				'The HTML code size is larger than pcre.backtrack_limit %d. You should use WriteHTML() with smaller string lengths.',
				$limit
			));
		}

		preg_match_all("/(<annotation.*?>)/si", $html, $m);
		if (count($m[1])) {
			for ($i = 0; $i < count($m[1]); $i++) {
				$sub = preg_replace("/\n/si", "\xbb\xa4\xac", $m[1][$i]);
				$html = preg_replace('/' . preg_quote($m[1][$i], '/') . '/si', $sub, $html);
			}
		}

		preg_match_all("/(<svg.*?<\/svg>)/si", $html, $svgi);
		if (count($svgi[0])) {
			for ($i = 0; $i < count($svgi[0]); $i++) {
				$file = $this->cache->write('/_tempSVG' . uniqid(random_int(1, 100000), true) . '_' . $i . '.svg', $svgi[0][$i]);
				$html = str_replace($svgi[0][$i], '<img src="' . $file . '" />', $html);
			}
		}

		// Remove javascript code from HTML (should not appear in the PDF file)
		$html = preg_replace('/<script.*?<\/script>/is', '', $html);

		// Remove special comments
		$html = preg_replace('/<!--mpdf/i', '', $html);
		$html = preg_replace('/mpdf-->/i', '', $html);

		// Remove comments from HTML (should not appear in the PDF file)
		$html = preg_replace('/<!--.*?-->/s', '', $html);

		$html = preg_replace('/\f/', '', $html); // replace formfeed by nothing
		$html = preg_replace('/\r/', '', $html); // replace carriage return by nothing

		// Well formed XHTML end tags
		$html = preg_replace('/<(br|hr)>/i', "<\\1 />", $html); // mPDF 6
		$html = preg_replace('/<(br|hr)\/>/i', "<\\1 />", $html);

		// Get rid of empty <thead></thead> etc
		$html = preg_replace('/<tr>\s*<\/tr>/i', '', $html);
		$html = preg_replace('/<thead>\s*<\/thead>/i', '', $html);
		$html = preg_replace('/<tfoot>\s*<\/tfoot>/i', '', $html);
		$html = preg_replace('/<table[^>]*>\s*<\/table>/i', '', $html);

		// Remove spaces at end of table cells
		$html = preg_replace("/[ \n\r]+<\/t(d|h)/", '</t\\1', $html);

		$html = preg_replace("/[ ]*<dottab\s*[\/]*>[ ]*/", '<dottab />', $html);

		// Concatenates any Substitute characters from symbols/dingbats
		$html = str_replace('</tts><tts>', '|', $html);
		$html = str_replace('</ttz><ttz>', '|', $html);
		$html = str_replace('</tta><tta>', '|', $html);

		$html = preg_replace('/<br \/>\s*/is', "<br />", $html);

		$html = preg_replace('/<wbr[ \/]*>\s*/is', "&#173;", $html);

		// Preserve '\n's in content between the tags <pre> and </pre>
		if (preg_match('/<pre/', $html)) {

			$html_a = preg_split('/(\<\/?pre[^\>]*\>)/', $html, -1, 2);
			$h = [];
			$c = 0;

			foreach ($html_a as $s) {
				if ($c > 1 && preg_match('/^<\/pre/i', $s)) {
					$c--;
					$s = preg_replace('/<\/pre/i', '</innerpre', $s);
				} elseif ($c > 0 && preg_match('/^<pre/i', $s)) {
					$c++;
					$s = preg_replace('/<pre/i', '<innerpre', $s);
				} elseif (preg_match('/^<pre/i', $s)) {
					$c++;
				} elseif (preg_match('/^<\/pre/i', $s)) {
					$c--;
				}
				array_push($h, $s);
			}

			$html = implode('', $h);
		}

		$thereispre = preg_match_all('#<pre(.*?)>(.*?)</pre>#si', $html, $temp);

		// Preserve '\n's in content between the tags <textarea> and </textarea>
		$thereistextarea = preg_match_all('#<textarea(.*?)>(.*?)</textarea>#si', $html, $temp2);
		$html = preg_replace('/[\n]/', ' ', $html); // replace linefeed by spaces
		$html = preg_replace('/[\t]/', ' ', $html); // replace tabs by spaces

		// Converts < to &lt; when not a tag
		$html = preg_replace('/<([^!\/a-zA-Z_:])/i', '&lt;\\1', $html); // mPDF 5.7.3
		$html = preg_replace("/[ ]+/", ' ', $html);

		$html = preg_replace('/\/li>\s+<\/(u|o)l/i', '/li></\\1l', $html);
		$html = preg_replace('/\/(u|o)l>\s+<\/li/i', '/\\1l></li', $html);
		$html = preg_replace('/\/li>\s+<\/(u|o)l/i', '/li></\\1l', $html);
		$html = preg_replace('/\/li>\s+<li/i', '/li><li', $html);
		$html = preg_replace('/<(u|o)l([^>]*)>[ ]+/i', '<\\1l\\2>', $html);
		$html = preg_replace('/[ ]+<(u|o)l/i', '<\\1l', $html);

		// Make self closing tabs valid XHTML
		// Tags which are self-closing: 1) Replaceable and 2) Non-replaced items
		$selftabs = 'input|hr|img|br|barcode|dottab';
		$selftabs2 = 'indexentry|indexinsert|bookmark|watermarktext|watermarkimage|column_break|columnbreak|newcolumn|newpage|page_break|pagebreak|formfeed|columns|toc|tocpagebreak|setpageheader|setpagefooter|sethtmlpageheader|sethtmlpagefooter|annotation';

		// Fix self-closing tags which don't close themselves
		$html = preg_replace('/(<(' . $selftabs . '|' . $selftabs2 . ')[^>\/]*)>/i', '\\1 />', $html);

		// Fix self-closing tags that don't include a space between the tag name and the closing slash
		$html = preg_replace('/(<(' . $selftabs . '|' . $selftabs2 . '))\/>/i', '\\1 />', $html);

		$iterator = 0;
		while ($thereispre) { // Recover <pre attributes>content</pre>
			$temp[2][$iterator] = preg_replace('/<([^!\/a-zA-Z_:])/', '&lt;\\1', $temp[2][$iterator]); // mPDF 5.7.2	// mPDF 5.7.3

			$temp[2][$iterator] = preg_replace_callback("/^([^\n\t]*?)\t/m", [$this, 'tabs2spaces_callback'], $temp[2][$iterator]); // mPDF 5.7+
			$temp[2][$iterator] = preg_replace('/\t/', str_repeat(" ", $tabSpaces), $temp[2][$iterator]);

			$temp[2][$iterator] = preg_replace('/\n/', "<br />", $temp[2][$iterator]);
			$temp[2][$iterator] = str_replace('\\', "\\\\", $temp[2][$iterator]);
			// $html = preg_replace('#<pre(.*?)>(.*?)</pre>#si','<erp'.$temp[1][$iterator].'>'.$temp[2][$iterator].'</erp>',$html,1);
			$html = preg_replace('#<pre(.*?)>(.*?)</pre>#si', '<erp' . $temp[1][$iterator] . '>' . str_replace('$', '\$', $temp[2][$iterator]) . '</erp>', $html, 1); // mPDF 5.7+
			$thereispre--;
			$iterator++;
		}

		$iterator = 0;
		while ($thereistextarea) { // Recover <textarea attributes>content</textarea>
			$temp2[2][$iterator] = preg_replace('/\t/', str_repeat(" ", $tabSpaces), $temp2[2][$iterator]);
			$temp2[2][$iterator] = str_replace('\\', "\\\\", $temp2[2][$iterator]);
			$html = preg_replace('#<textarea(.*?)>(.*?)</textarea>#si', '<aeratxet' . $temp2[1][$iterator] . '>' . trim($temp2[2][$iterator]) . '</aeratxet>', $html, 1);
			$thereistextarea--;
			$iterator++;
		}

		// Restore original tag names
		$html = str_replace("<erp", "<pre", $html);
		$html = str_replace("</erp>", "</pre>", $html);
		$html = str_replace("<aeratxet", "<textarea", $html);
		$html = str_replace("</aeratxet>", "</textarea>", $html);
		$html = str_replace("</innerpre", "</pre", $html);
		$html = str_replace("<innerpre", "<pre", $html);

		$html = preg_replace('/<textarea([^>]*)><\/textarea>/si', '<textarea\\1> </textarea>', $html);
		$html = preg_replace('/(<table[^>]*>)\s*(<caption)(.*?<\/caption>)(.*?<\/table>)/si', '\\2 position="top"\\3\\1\\4\\2 position="bottom"\\3', $html); // *TABLES*

		if ($this->use_kwt) {
			$returnHtml = preg_replace('/<(h[1-6])([^>]*(?<!\/))(>[^>]*<\/\\1>\s*<table)/si', '<\\1\\2 keep-with-table="1"\\3', $html);
			/* If no errors then save the return value */
			if (preg_last_error() === PREG_NO_ERROR) {
				$html = $returnHtml;
			}
		}

		$html = preg_replace("/\xbb\xa4\xac/", "\n", $html);

		// Fixes <p>&#8377</p> which browser copes with even though it is wrong!
		$html = preg_replace("/(&#[x]{0,1}[0-9a-f]{1,5})</i", "\\1;<", $html);

		return $html;
	}

	// mPDF 5.7+
	function tabs2spaces_callback($matches)
	{
		return (stripslashes($matches[1]) . str_repeat(' ', $this->tabSpaces - (mb_strlen(stripslashes($matches[1])) % $this->tabSpaces)));
	}

	// mPDF 5.7+
	function date_callback($matches)
	{
		return date($matches[1]);
	}

	// ========== OVERWRITE SEARCH STRING IN A PDF FILE ================
	function OverWrite($file_in, $search, $replacement, $dest = Destination::DOWNLOAD, $file_out = "mpdf")
	{
		$pdf = file_get_contents($file_in);

		if (!is_array($search)) {
			$x = $search;
			$search = [$x];
		}
		if (!is_array($replacement)) {
			$x = $replacement;
			$replacement = [$x]; // mPDF 5.7.4
		}

		if (!$this->onlyCoreFonts && !$this->usingCoreFont) {
			foreach ($search as $k => $val) {
				$search[$k] = $this->writer->utf8ToUtf16BigEndian($search[$k], false);
				$search[$k] = $this->writer->escape($search[$k]);
				$replacement[$k] = $this->writer->utf8ToUtf16BigEndian($replacement[$k], false);
				$replacement[$k] = $this->writer->escape($replacement[$k]);
			}
		} else {
			foreach ($replacement as $k => $val) {
				$replacement[$k] = mb_convert_encoding($replacement[$k], $this->mb_enc, 'utf-8');
				$replacement[$k] = $this->writer->escape($replacement[$k]);
			}
		}

		// Get xref into array
		$xref = [];
		preg_match("/xref\n0 (\d+)\n(.*?)\ntrailer/s", $pdf, $m);
		$xref_objid = $m[1];
		preg_match_all('/(\d{10}) (\d{5}) (f|n)/', $m[2], $x);
		for ($i = 0; $i < count($x[0]); $i++) {
			$xref[] = [(int) $x[1][$i], $x[2][$i], $x[3][$i]];
		}

		$changes = [];
		preg_match("/<<\s*\/Type\s*\/Pages\s*\/Kids\s*\[(.*?)\]\s*\/Count/s", $pdf, $m);
		preg_match_all("/(\d+) 0 R /s", $m[1], $o);
		$objlist = $o[1];

		foreach ($objlist as $obj) {
			if ($this->compress) {
				preg_match("/" . ($obj + 1) . " 0 obj\n<<\s*\/Filter\s*\/FlateDecode\s*\/Length (\d+)>>\nstream\n(.*?)\nendstream\n/s", $pdf, $m);
			} else {
				preg_match("/" . ($obj + 1) . " 0 obj\n<<\s*\/Length (\d+)>>\nstream\n(.*?)\nendstream\n/s", $pdf, $m);
			}

			$s = $m[2];
			if (!$s) {
				continue;
			}

			$oldlen = $m[1];

			if ($this->encrypted) {
				$s = $this->protection->rc4($this->protection->objectKey($obj + 1), $s);
			}

			if ($this->compress) {
				$s = gzuncompress($s);
			}

			foreach ($search as $k => $val) {
				$s = str_replace($search[$k], $replacement[$k], $s);
			}

			if ($this->compress) {
				$s = gzcompress($s);
			}

			if ($this->encrypted) {
				$s = $this->protection->rc4($this->protection->objectKey($obj + 1), $s);
			}

			$newlen = strlen($s);

			$changes[($xref[$obj + 1][0])] = ($newlen - $oldlen) + (strlen($newlen) - strlen($oldlen));

			if ($this->compress) {
				$newstr = ($obj + 1) . " 0 obj\n<</Filter /FlateDecode /Length " . $newlen . ">>\nstream\n" . $s . "\nendstream\n";
			} else {
				$newstr = ($obj + 1) . " 0 obj\n<</Length " . $newlen . ">>\nstream\n" . $s . "\nendstream\n";
			}

			$pdf = str_replace($m[0], $newstr, $pdf);
		}

		// Update xref in PDF
		krsort($changes);
		$newxref = "xref\n0 " . $xref_objid . "\n";
		foreach ($xref as $v) {
			foreach ($changes as $ck => $cv) {
				if ($v[0] > $ck) {
					$v[0] += $cv;
				}
			}
			$newxref .= sprintf('%010d', $v[0]) . ' ' . $v[1] . ' ' . $v[2] . " \n";
		}
		$newxref .= "trailer";
		$pdf = preg_replace("/xref\n0 \d+\n.*?\ntrailer/s", $newxref, $pdf);

		// Update startxref in PDF
		preg_match("/startxref\n(\d+)\n%%EOF/s", $pdf, $m);
		$startxref = $m[1];
		$startxref += array_sum($changes);
		$pdf = preg_replace("/startxref\n(\d+)\n%%EOF/s", "startxref\n" . $startxref . "\n%%EOF", $pdf);

		// OUTPUT
		switch ($dest) {
			case Destination::INLINE:
				if (isset($_SERVER['SERVER_NAME'])) {
					// We send to a browser
					header('Content-Type: application/pdf');
					header('Content-Length: ' . strlen($pdf));
					header('Content-disposition: inline; filename=' . $file_out);
				}

				echo $pdf;

				break;

			case Destination::FILE:
				if (!$file_out) {
					$file_out = 'mpdf.pdf';
				}

				$f = fopen($file_out, 'wb');

				if (!$f) {
					throw new \Mpdf\MpdfException('Unable to create output file: ' . $file_out);
				}

				fwrite($f, $pdf, strlen($pdf));

				fclose($f);

				break;

			case Destination::STRING_RETURN:
				return $pdf;

			case Destination::DOWNLOAD: // Download file
			default:
				if (isset($_SERVER['HTTP_USER_AGENT']) and strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
					header('Content-Type: application/force-download');
				} else {
					header('Content-Type: application/octet-stream');
				}

				header('Content-Length: ' . strlen($pdf));
				header('Content-disposition: attachment; filename=' . $file_out);

				echo $pdf;

				break;
		}
	}


	function Thumbnail($file, $npr = 3, $spacing = 10)
	{
		// $npr = number per row
		$w = (($this->pgwidth + $spacing) / $npr) - $spacing;
		$oldlinewidth = $this->LineWidth;
		$this->SetLineWidth(0.02);
		$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
		$h = 0;
		$maxh = 0;
		$x = $_x = $this->lMargin;
		$_y = $this->tMargin;

		if ($this->y == 0) {
			$y = $_y;
		} else {
			$y = $this->y;
		}

		$pagecount = $this->setSourceFile($file);

		for ($n = 1; $n <= $pagecount; $n++) {
			$tplidx = $this->importPage($n);
			$size = $this->useTemplate($tplidx, $x, $y, $w);
			$this->Rect($x, $y, $size['width'], $size['height']);
			$h = max($h, $size['height']);
			$maxh = max($h, $maxh);

			if ($n % $npr == 0) {
				if (($y + $h + $spacing + $maxh) > $this->PageBreakTrigger && $n != $pagecount) {
					$this->AddPage();
					$x = $_x;
					$y = $_y;
				} else {
					$y += $h + $spacing;
					$x = $_x;
					$h = 0;
				}
			} else {
				$x += $w + $spacing;
			}
		}
		$this->SetLineWidth($oldlinewidth);
	}

	function SetPageTemplate($tplidx = '')
	{
		if (!isset($this->importedPages[$tplidx])) {
			$this->pageTemplate = '';
			return false;
		}
		$this->pageTemplate = $tplidx;
	}

	function SetDocTemplate($file = '', $continue = 0, $continue2pages = 0)
	{
		$this->docTemplate = $file;
		$this->docTemplateContinue = $continue;
		$this->docTemplateContinue2pages = $continue2pages;

		if ($this->docTemplateContinue2pages) { // Enable continue when continue2pages is set
			$this->docTemplateContinue = $this->docTemplateContinue2pages;
		}
	}

	/* -- END IMPORTS -- */

	// JAVASCRIPT
	function _set_object_javascript($string)
	{
		$this->writer->object();
		$this->writer->write('<<');
		$this->writer->write('/S /JavaScript ');
		$this->writer->write('/JS ' . $this->writer->string($string));
		$this->writer->write('>>');
		$this->writer->write('endobj');
	}

	function SetJS($script)
	{
		$this->js = $script;
	}

	/**
	 * This function takes the last comma or dot (if any) to make a clean float, ignoring thousand separator, currency or any other letter
	 *
	 * @param string $num
	 * @see http://php.net/manual/de/function.floatval.php#114486
	 * @return float
	 */
	public function toFloat($num)
	{
		$dotPos = strrpos($num, '.');
		$commaPos = strrpos($num, ',');
		$sep = (($dotPos > $commaPos) && $dotPos) ? $dotPos : ((($commaPos > $dotPos) && $commaPos) ? $commaPos : false);

		if (!$sep) {
			return floatval(preg_replace('/[^0-9]/', '', $num));
		}

		return floatval(
			preg_replace('/[^0-9]/', '', substr($num, 0, $sep)) . '.' .
			preg_replace('/[^0-9]/', '', substr($num, $sep+1, strlen($num)))
		);
	}

	public function getFontDescriptor()
	{
		return $this->fontDescriptor;
	}

	/**
	 * Temporarily return the method to preserve example 44 yearbook
	 */
	public function _out($s)
	{
		$this->writer->write($s);
	}

	/**
	 * @param string $html
	 * @param string $PAGENO
	 * @param string $NbPgGp
	 * @param string $NbPg
	 * @return string
	 */
	protected function aliasReplace($html, $PAGENO, $NbPgGp, $NbPg)
	{
		// Replaces for header and footer
		$html = str_replace('{PAGENO}', $PAGENO, $html);
		$html = str_replace($this->aliasNbPgGp, $NbPgGp, $html); // {nbpg}
		$html = str_replace($this->aliasNbPg, $NbPg, $html); // {nb}

		// Replaces for the body
		$html = str_replace(mb_convert_encoding('{PAGENO}', 'UTF-16BE', 'UTF-8'), mb_convert_encoding($PAGENO, 'UTF-16BE', 'UTF-8'), $html);
		$html = str_replace(mb_convert_encoding($this->aliasNbPgGp, 'UTF-16BE', 'UTF-8'), mb_convert_encoding($NbPgGp, 'UTF-16BE', 'UTF-8'), $html); // {nbpg}
		$html = str_replace(mb_convert_encoding($this->aliasNbPg, 'UTF-16BE', 'UTF-8'), mb_convert_encoding($NbPg, 'UTF-16BE', 'UTF-8'), $html); // {nb}

		// Date replace
		$html = preg_replace_callback('/\{DATE\s+(.*?)\}/', [$this, 'date_callback'], $html); // mPDF 5.7

		return $html;
	}

}
صوت الليل لا ينام… حتى في عصر Gamini – tahkoom.com
تفاعل

صوت الليل لا ينام… حتى في عصر Gamini

كتبت : فرح سمير                                                                                                                                                              بين دفء الصوت وبرود التقنية… أسامة منير يتحدث

“حين يُستنسخ الصوت.. هل تُستنسخ الروح؟”

“أسامة منير: الروح لا تسجل ب mp3 ولا ذكاء يعوّض دفء الصوت الإنساني

عندما يُذكر اسم الإذاعة في العالم العربى ، يتردد في الأذهان فورًا صوت الإعلامي القدير أسامة منير، صاحب المدرسة الخاصة في فن التقديم الإذاعي، والبصمة الإنسانية الواضحة في برامجه، وعلى رأسها البرنامج الأشهر “أنا والنجوم وهواك”. بصوته العذب وحضوره الإنساني، أصبح “ الغائب الحاضر ” في ذاكرة مستمعين تربّوا على نبرة صدقه ودفء كلماته.

وفي الوقت الذي تواصل فيه التكنولوجيا اقتحام ميادين الإعلام، أعلنت شركة Google في مايو 2025 عن ميزة “البودكاست الذكي” ضمن تطبيق Gemini، والتي تتيح للمستخدمين تحويل مستنداتهم إلى حلقات صوتية تفاعلية، تديرها شخصيتان ذكيتان تعملان بالذكاء الاصطناعي.

في هذا السياق، نتحاور اليوم مع الإعلامي أسامة منير حول هذه النقلة النوعية، ونبحث معه في سؤال جوهري: هل ما زال الصوت البشري الدافئ قادرًا على الصمود أمام زحف الذكاء الاصطناعي؟ كيف يمكن للإعلامي أن يتكيّف مع هذه الأدوات الجديدة، دون أن يفقد إنسانيته، أو يفرّط في جوهر الرسالة الإعلامية؟

في رأيك، هل البودكاست بصوت الذكاء الاصطناعي يمكن أن ينافس صوت وتجربة المذيع البشري في المستقبل؟

أعتقد أن البودكاست “لحم ودم”، لا يصح أن يكون بصوت الذكاء الاصطناعي أبدًا. لأنك إن قمتِ بتحضير الأسئلة وطرحتها بصوت الذكاء الاصطناعي، ثم جاءت الإجابات أيضًا من الذكاءالاصطناعي، فكأنك فقط تبحثين عن وسيلة لقراءة نص مكتوب. لكن الحوار الحقيقي يكون حيًا، عبارة عن تلاقٍ بين فكر وفكر، وعقل وعقل. يكون فيه أخذ وردّ، ولا يمكن أن يُدار بأي شكل من الأشكال عن طريق الذكاء الاصطناعي، لأنه ببساطة سيفقد “الروح”،وسيفقد “الطعم”، وحتى “ذكاء الحوار” نفسه.

لديك تاريخ طويل في البرامج الإذاعية المؤثرة.. هل تعتقد أن الذكاء الاصطناعي يمكن أن ينقل نفس المشاعر والدفء الذي يقدمه المذيع الحقيقي؟

أعتقد أن البرامج الإذاعية لا يمكن أن تُدار على الإطلاق بتقنيات الذكاء الاصطناعي، فهذا شيء بعيد تمامًا. لأن المذيع الذي يجلس أمام الميكروفون — والذي نسميه “الحديدة” —تنقل “الحديدة” هذه ليس فقط صوته، وإنما أيضًا إحساسه وأفكاره، ومشاعره من فرح أو غضب أو حماس هناك دفء وخصوصية في العلاقة الحوارية بين المذيع والمستمع، ولا أعتقد أن هذا يمكن أن نحصل عليه بأي حال من الأحوال من الذكاء الاصطناعي.

هل سبق أن جربت أي أدوات ذكاء اصطناعي في إعداد أو إنتاج محتوى صوتي أو بودكاست؟ وإن لم تفعل، هل تفكر باستخدامها مستقبلا ً ؟

نعم، بالفعل جربت، كنت أستطلع كيف يمكن إنتاج محتوى بالذكاء الاصطناعي، أو كيف يمكن أن يساعدني في إعداد أفكار إذاعية أو وضع محاور.وجدت أنه ببساطة يجمع كل ما هو موجود على الإنترنت، لكنه لا يبتكر. يعرض المتاح فقط، ولا يضيف عليه.

ونعم، قد نستخدمه أحيانًا في أعمال “الفويس أوفر”، لكن في البرامج الإذاعية، لا.. لم أستخدمه من قبل ولا أرى أنه يمكن أن يُستخدم.

فيه بودكاستات حاليًا تُنتَج بالكامل باستخدام الذكاء الاصطناعي.. من كتابة النص إلى صوت المذيع، وحتى تحرير الحلقات. هل ترى في ذلك فرصة لتطور الإعلام أم خطرًا على المهنة؟

كون أن هناك الآن بودكاست يُنتَج بالكامل بالذكاء الاصطناعي، لا أعتقد أنه يُعتبر بودكاست حقيقي. لأنه سيفتقد للروح. ما الفائدة أن أطلب من الذكاء الاصطناعي كتابة سكريبت، ثم يقرأه بصوت مذيع اصطناعي، ويضيف له موسيقى، وأرفعه على المنصة؟ لم أفعل شيئًا.

لو قلت له مثلا ً : “اعمل لي محاضرة أو بودكاست عن التعايش السلمي”، سيضع لي نقاطًا وشرحًا. ثم أطلب منه قراءتها، فيقرأها جميعًا بإضافة موسيقى خلفية، فأقوم بنشرها على الإنترنت. هل فعلت شيئًا؟ لا. هذا يمكن لأي شخص أن يقرؤه على الإنترنت. البودكاست في جوهره إنساني. الإنسان هو من يناقش، وله فكر وتصور ورؤية، وهذا لن تجده أبدًا عند الذكاء الاصطناعي. الذكاء الاصطناعي يجمع لك بيانات واقعية من الإنترنت، لكنه لا يخلق. سأضرب لكِ مثلا ً : هناك أجهزة حديثة الآن تنتج موسيقى كاملة من توزيع وتركيب إيقاعات وآلات. لكن هناك آلات موسيقية، لا يمكن أن تُعزف إلا “لايف” لأن عزفها الحقيقي يحمل طعمًا خاصًا.مثل الكمان، والتشيلو، والأكورديون. لا يمكن أن تُعزف من “كيبورد”، لأن الصوت يختلف تمامًا.

هل سبق أن تم استخدام نبرة صوتك المميزة في تقنيات الذكاء الاصطناعي؟ وإن حدث، فكيف كان شعورك عندما استمعت إليه؟

نعم، سمعت صوتي بالذكاء الاصطناعي. فى مرة أحد الموزعين الموسيقيين أرسل لي مقطعًا ساخرًا استخدم فيه صوتي في“فويس أوفر”، وقال لي ممازحًا: “أنا ممكن أستغل صوتك!” ضحكت، لم أزعل، لكن لاحظت أنه ربما أخذ نبرة صوتي، “التون” والموجة الصوتية كانت صحيحة، لكن مخارج الحروف كانت مختلفة، والأسلوب كان مختلفًا. لأن من قرأ هو المتحدث الحقيقي، لكنه فقط غيّر صوته ليصبح صوتي. أي أن الذكاء الاصطناعي أخرج صوتي، لكن بأسلوبه هو. فلم يكن “الفويس أوفر” حتى بأسلوبي أنا. فما بالك لو استُخدم هذا في الرد على الناس في حوارات وأسئلة؟ هناك شيئًا “بلاستيكيًا”، شيئًا غير حقيقي. ستشعرين أن مع أنه لم يكن سكريبتًا مكتوبًا، بل مجرد تعديل صوت. فلم يوصل لا المعنى، ولا الإحساس، ولا حتى التحفيز.وهنا نقطة مهمة أود أن أذكرها: “الفويس أوفر” في الإعلان، هو البائع، هو من يقدّم المنتج للمستهلك، هو من يقنعه به بأسلوب معين. والإقناع هذا موهبة من عند الله سبحانه وتعالى، والصوت المقبول كذلك نعمة من الله.لا يمكن لشيء صُنع بأيادٍ بشرية أن يضاهي ما خلقه الله.

ما رأيك في تأثير الذكاء الاصطناعي على فرص الشباب في دخول مجال البودكاست؟ هل يمكن أن يسهل الطريق، أم يقلل من قيمة التجربة والخبرة؟الذكاء الاصطناعي؟

أعتقد أنه سيؤثر على دخول الشباب لمجال الإعلام والبودكاست. وهناك خطورة أخرى أود أن أذكرها، لا أعلم إن كنتِ ستسألين عنها أم لا،لكن أي شخص يمكنه الآن إنشاء بودكاست أو حوار باستخدام الذكاء الاصطناعي، ويمكن أن يستخدم أصوات شخصيات عالمية، أو أصوات لمسؤولين، وقد يؤدي ذلك إلى كارثة سياسية. تخيلوا أحدهم يستخدم صوت مسؤول ويضعه في إجابات معينة بطريقة مزيفة، هذا قد يسبب أزمة سياسية خطيرة، حتى على المستوى المحلي.

اذا طلبت من حضرتك نصيحة لطلاب الإعلام الذين يرغبون في دخول مجال البودكاست، خاصة في ظل وجود الذكاء الاصطناعي، ماذا تقول لهم؟

أقول للشباب الذين يريدون دخول مجال البودكاست والعمل في الإعلام: الميديا تحتاج إلى الإنسان الذي يمتلك “ذكاء اجتماعي”، ويجيد فن الحوار، ويعرف كيف يأخذ ويعطي. لأن الكلام يجب أن يكون تبادليًا، لا مجرد “أنا أتكلم وأتكلم” دون أن أترك مجالا ً للرد. ويجب أن يكون لديه ثقافة، ليس بالضرورة تخصصًا، لكن يعرف بعض الأمور الطبية، بعض الأمور التاريخية، الاجتماعية، الفنية،حتى عندما يتحدث، يكون لديه خلفية، ويكون مدركًا لما يتحدث عنه، لا يبدو كمن يكتشف الكلام لأول مرة أما عن استغلال الذكاء الاصطناعي في البودكاست، فيمكن استخدامه في تأليف موسيقى تتر أو خلفيات صوتية. لكن بودكاست كامل بأفكاره وبنائه بالذكاء الاصطناعي؟ لا أعتقد أنه سيكون مبدعًا أبدًا. يجب أن يجتهد الإنسان قليلا ً ليخرج بشيء مميز. المذيع الذي يريد أن يتعلم الإذاعة، عليه أن يتعلمها. الإذاعة بسيطة وسهلة، لكنها تتطلب شيئين: الحرفية والموهبة. يجب تعلم الحرفة: طريقة الكلام، النقاش، تقسيم المحاور، احترام الرأي الآخر.. إلخ. لكن الموهبة هي التي تطغى على الحرفة، وهي من عند الله. الله يعطيها لإنسان معين، لا تُمنح لأي أحد.

هل ترى أن مستقبل الإعلام الصوتي سيبقى قائمًا على العنصر البشري، أم أن الذكاء الاصطناعي قد يستحوذ عليه؟

الإعلام الصوتي سيظل كما هو، إعلامًا صوتيًا. ما الفائدة من أن أستمع إلى الراديو وتكون كل برامجه مصنوعة بالذكاء الاصطناعي؟ الذكاء الاصطناعي قد يكون مناسبًا في تطبيقات قراءة الكتب، لكنها ستكون مملة، بدون روح، بدون إحساس. الإحساس الذي يصل إلى الإنسان لا يمكن أن ينقله الذكاء الاصطناعي. فأنا شخصيًا جربت كثيرًا، مثلا ً كنا نسجل مواد وثائقية “دوكيومنتريز”، وحاولت بعد تسجيلها أن أستخدم صوتي مع الذكاء الاصطناعي، لكن النتيجة كانت سيئة جدًا جدًا.

بين أصالة الصوت الإذاعي وذكاء الآلة، يبقى الإنسان هو العنصر الحاسم في صناعة المحتوى. الإعلامي القدير أسامة منير ذكّرنا أن التكنولوجيا أداة، وليست بديلا ً ، وأن الرسالة الصادقة لا تولد من الخوارزميات، بل من الإحساس بالناسوفي النهاية، قد تتغير الأدوات وتتطور الوسائل، لكن جوهر الإعلام الحقيقي يظل مرتبطًا بالصدق، والإحساس، والرسالة التي تمس ّ وجدان المتلقي. وبين الذكاء الاصطناعي وذكاء المشاعر، يبقى الخيار أمام الإعلامي: هل يكون مكمّلا ً للتكنولوجيا… أم تابعًا لها

اظهر المزيد

مقالات ذات صلة

زر الذهاب إلى الأعلى