PluginProbe
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin / 2.4.4
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin v2.4.4
trunk 1.5 1.6 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 All 71 releases
pdf-print / mpdf / mpdf.php

mpdf.php in PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin 2.4.4, at mpdf/mpdf.php

31,556 lines 1.1 MB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // ******************************************************************************
4 // Software: mPDF, Unicode-HTML Free PDF generator *
5 // Version: 6.1 based on *
6 // FPDF by Olivier PLATHEY *
7 // HTML2FPDF by Renato Coelho *
8 // Date: 2016-03-25 *
9 // Author: Ian Back <ianb@bpm1.com> *
10 // License: GPL *
11 // *
12 // Changes: See changelog.txt *
13 // ******************************************************************************
14
15 define('mPDF_VERSION', '6.1');
16
17 //Scale factor
18 define('_MPDFK', (72 / 25.4));
19
20 // Specify which font metrics to use:
21 // 'winTypo' uses sTypoAscender etc from the OS/2 table and is the one usually recommended - BUT
22 // 'win' use WinAscent etc from OS/2 and inpractice seems to be used more commonly in Windows environment
23 // 'mac' uses Ascender etc from hhea table, and is used on Mac/OSX environment
24 if (!defined('_FONT_DESCRIPTOR')) {
25 define("_FONT_DESCRIPTOR", 'win'); // Values: '' [BLANK] or 'win', 'mac', 'winTypo'
26 }
27
28 /* -- HTML-CSS -- */
29 define('_BORDER_ALL', 15);
30 define('_BORDER_TOP', 8);
31 define('_BORDER_RIGHT', 4);
32 define('_BORDER_BOTTOM', 2);
33 define('_BORDER_LEFT', 1);
34 /* -- END HTML-CSS -- */
35
36 // mPDF 6.0
37 // Used for $textvars - user settings via CSS
38 define('FD_UNDERLINE', 1); // font-decoration
39 define('FD_LINETHROUGH', 2);
40 define('FD_OVERLINE', 4);
41 define('FA_SUPERSCRIPT', 8); // font-(vertical)-align
42 define('FA_SUBSCRIPT', 16);
43 define('FT_UPPERCASE', 32); // font-transform
44 define('FT_LOWERCASE', 64);
45 define('FT_CAPITALIZE', 128);
46 define('FC_KERNING', 256); // font-(other)-controls
47 define('FC_SMALLCAPS', 512);
48
49
50 if (!defined('_MPDF_PATH')) {
51 define('_MPDF_PATH', dirname(preg_replace('/\\\\/', '/', __FILE__)) . '/');
52 }
53
54 if (!defined('_MPDF_URI')) {
55 define('_MPDF_URI', _MPDF_PATH);
56 }
57
58 require_once _MPDF_PATH . 'includes/functions.php';
59 require_once _MPDF_PATH . 'config_lang2fonts.php';
60
61 require_once _MPDF_PATH . 'classes/ucdn.php'; // mPDF 6.0
62
63 /* -- OTL -- */
64 require_once _MPDF_PATH . 'classes/indic.php'; // mPDF 6.0
65 require_once _MPDF_PATH . 'classes/myanmar.php'; // mPDF 6.0
66 require_once _MPDF_PATH . 'classes/sea.php'; // mPDF 6.0
67 /* -- END OTL -- */
68
69 require_once _MPDF_PATH . 'Tag.php';
70 require_once _MPDF_PATH . 'MpdfException.php';
71
72 if (!defined('_JPGRAPH_PATH')) {
73 define("_JPGRAPH_PATH", _MPDF_PATH . 'jpgraph/');
74 }
75
76 if (!defined('_MPDF_TEMP_PATH')) {
77 define("_MPDF_TEMP_PATH", _MPDF_PATH . 'tmp/');
78 }
79
80 if (!defined('_MPDF_TTFONTPATH')) {
81 define('_MPDF_TTFONTPATH', _MPDF_PATH . 'ttfonts/');
82 }
83
84 if (!defined('_MPDF_TTFONTDATAPATH')) {
85 define('_MPDF_TTFONTDATAPATH', _MPDF_PATH . 'ttfontdata/');
86 }
87
88 $errorlevel = error_reporting();
89 $errorlevel = error_reporting($errorlevel & ~E_NOTICE);
90
91 //error_reporting(E_ALL);
92
93 if (function_exists("date_default_timezone_set")) {
94 if (ini_get("date.timezone") == "") {
95 date_default_timezone_set("Europe/London");
96 }
97 }
98
99 if (!function_exists('mb_strlen')) {
100 throw new MpdfException('mPDF requires mb_string functions. Ensure that mb_string extension is loaded.');
101 }
102
103 if (!defined('PHP_VERSION_ID')) {
104 $version = explode('.', PHP_VERSION);
105 define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2]));
106 }
107
108 class mPDF
109 {
110
111 ///////////////////////////////
112 // EXTERNAL (PUBLIC) VARIABLES
113 // Define these in config.php
114 ///////////////////////////////
115 var $useFixedNormalLineHeight; // mPDF 6
116 var $useFixedTextBaseline; // mPDF 6
117 var $adjustFontDescLineheight; // mPDF 6
118 var $interpolateImages; // mPDF 6
119 var $defaultPagebreakType; // mPDF 6 pagebreaktype
120 var $indexUseSubentries; // mPDF 6
121
122 var $autoScriptToLang; // mPDF 6
123 var $baseScript; // mPDF 6
124 var $autoVietnamese; // mPDF 6
125 var $autoArabic; // mPDF 6
126
127 var $CJKforceend;
128 var $h2bookmarks;
129 var $h2toc;
130 var $decimal_align;
131 var $margBuffer;
132 var $splitTableBorderWidth;
133
134 var $bookmarkStyles;
135 var $useActiveForms;
136
137 var $repackageTTF;
138 var $allowCJKorphans;
139 var $allowCJKoverflow;
140
141 var $useKerning;
142 var $restrictColorSpace;
143 var $bleedMargin;
144 var $crossMarkMargin;
145 var $cropMarkMargin;
146 var $cropMarkLength;
147 var $nonPrintMargin;
148
149 var $PDFX;
150 var $PDFXauto;
151
152 var $PDFA;
153 var $PDFAauto;
154 var $ICCProfile;
155
156 var $printers_info;
157 var $iterationCounter;
158 var $smCapsScale;
159 var $smCapsStretch;
160
161 var $backupSubsFont;
162 var $backupSIPFont;
163 var $debugfonts;
164 var $useAdobeCJK;
165 var $percentSubset;
166 var $maxTTFFilesize;
167 var $BMPonly;
168
169 var $tableMinSizePriority;
170
171 var $dpi;
172 var $watermarkImgAlphaBlend;
173 var $watermarkImgBehind;
174 var $justifyB4br;
175 var $packTableData;
176 var $pgsIns;
177 var $simpleTables;
178 var $enableImports;
179
180 var $debug;
181
182 var $showStats;
183 var $setAutoTopMargin;
184 var $setAutoBottomMargin;
185 var $autoMarginPadding;
186 var $collapseBlockMargins;
187 var $falseBoldWeight;
188 var $normalLineheight;
189 var $progressBar;
190 var $incrementFPR1;
191 var $incrementFPR2;
192 var $incrementFPR3;
193 var $incrementFPR4;
194
195 var $SHYlang;
196 var $SHYleftmin;
197 var $SHYrightmin;
198 var $SHYcharmin;
199 var $SHYcharmax;
200 var $SHYlanguages;
201
202 // PageNumber Conditional Text
203 var $pagenumPrefix;
204 var $pagenumSuffix;
205
206 var $nbpgPrefix;
207 var $nbpgSuffix;
208 var $showImageErrors;
209 var $allow_output_buffering;
210 var $autoPadding;
211 var $useGraphs;
212 var $tabSpaces;
213 var $autoLangToFont;
214 var $watermarkTextAlpha;
215 var $watermarkImageAlpha;
216 var $watermark_size;
217 var $watermark_pos;
218 var $annotSize;
219 var $annotMargin;
220 var $annotOpacity;
221 var $title2annots;
222 var $keepColumns;
223 var $keep_table_proportions;
224 var $ignore_table_widths;
225 var $ignore_table_percents;
226 var $list_number_suffix;
227
228 var $list_auto_mode; // mPDF 6
229 var $list_indent_first_level; // mPDF 6
230 var $list_indent_default; // mPDF 6
231 var $list_marker_offset; // mPDF 6
232
233 var $useSubstitutions;
234 var $CSSselectMedia;
235
236 var $forcePortraitHeaders;
237 var $forcePortraitMargins;
238 var $displayDefaultOrientation;
239 var $ignore_invalid_utf8;
240 var $allowedCSStags;
241 var $onlyCoreFonts;
242 var $allow_charset_conversion;
243
244 var $jSWord;
245 var $jSmaxChar;
246 var $jSmaxCharLast;
247 var $jSmaxWordLast;
248
249 var $max_colH_correction;
250
251 var $table_error_report;
252 var $table_error_report_param;
253 var $biDirectional;
254 var $text_input_as_HTML;
255 var $anchor2Bookmark;
256 var $shrink_tables_to_fit;
257
258 var $allow_html_optional_endtags;
259
260 var $img_dpi;
261
262 var $defaultheaderfontsize;
263 var $defaultheaderfontstyle;
264 var $defaultheaderline;
265 var $defaultfooterfontsize;
266 var $defaultfooterfontstyle;
267 var $defaultfooterline;
268 var $header_line_spacing;
269 var $footer_line_spacing;
270
271 var $pregCJKchars;
272 var $pregRTLchars;
273 var $pregCURSchars; // mPDF 6
274
275 var $mirrorMargins;
276 var $watermarkText;
277 var $watermarkImage;
278 var $showWatermarkText;
279 var $showWatermarkImage;
280
281 var $fontsizes;
282
283 var $defaultPageNumStyle; // mPDF 6
284
285 //////////////////////
286 // CLASS OBJECTS
287 //////////////////////
288 var $otl; // mPDF 5.7.1
289 var $cssmgr;
290 var $grad;
291 var $bmp;
292 var $wmf;
293 var $tocontents;
294 var $mpdfform;
295 var $directw;
296
297 //////////////////////
298 // INTERNAL VARIABLES
299 //////////////////////
300 var $script2lang;
301 var $viet;
302 var $pashto;
303 var $urdu;
304 var $persian;
305 var $sindhi;
306 var $extrapagebreak; // mPDF 6 pagebreaktype
307
308 var $uniqstr; // mPDF 5.7.2
309 var $hasOC;
310
311 var $textvar; // mPDF 5.7.1
312 var $fontLanguageOverride; // mPDF 5.7.1
313 var $OTLtags; // mPDF 5.7.1
314 var $OTLdata; // mPDF 5.7.1
315
316 var $writingToC;
317 var $layers;
318 var $current_layer;
319 var $open_layer_pane;
320 var $decimal_offset;
321 var $inMeter;
322
323 var $CJKleading;
324 var $CJKfollowing;
325 var $CJKoverflow;
326
327 var $textshadow;
328
329 var $colsums;
330 var $spanborder;
331 var $spanborddet;
332
333 var $visibility;
334
335 var $useRC128encryption;
336 var $uniqid;
337
338 var $kerning;
339 var $fixedlSpacing;
340 var $minwSpacing;
341 var $lSpacingCSS;
342 var $wSpacingCSS;
343
344 var $spotColorIDs;
345 var $SVGcolors;
346 var $spotColors;
347 var $defTextColor;
348 var $defDrawColor;
349 var $defFillColor;
350
351 var $tableBackgrounds;
352 var $inlineDisplayOff;
353 var $kt_y00;
354 var $kt_p00;
355 var $upperCase;
356 var $checkSIP;
357 var $checkSMP;
358 var $checkCJK;
359
360 var $watermarkImgAlpha;
361 var $PDFAXwarnings;
362 var $MetadataRoot;
363 var $OutputIntentRoot;
364 var $InfoRoot;
365 var $current_filename;
366 var $parsers;
367 var $current_parser;
368 var $_obj_stack;
369 var $_don_obj_stack;
370 var $_current_obj_id;
371 var $tpls;
372 var $tpl;
373 var $tplprefix;
374 var $_res;
375
376 var $pdf_version;
377 var $noImageFile;
378 var $lastblockbottommargin;
379 var $baselineC;
380
381 // mPDF 5.7.3 inline text-decoration parameters
382 var $baselineSup;
383 var $baselineSub;
384 var $baselineS;
385 var $subPos;
386 var $subArrMB;
387 var $ReqFontStyle;
388 var $tableClipPath;
389
390 var $fullImageHeight;
391
392 var $inFixedPosBlock; // Internal flag for position:fixed block
393 var $fixedPosBlock; // Buffer string for position:fixed block
394 var $fixedPosBlockDepth;
395 var $fixedPosBlockBBox;
396 var $fixedPosBlockSave;
397 var $maxPosL;
398 var $maxPosR;
399 var $loaded;
400
401 var $extraFontSubsets;
402
403 var $docTemplateStart; // Internal flag for page (page no. -1) that docTemplate starts on
404
405 var $time0;
406
407 // Classes
408 var $indic;
409 var $barcode;
410
411 var $SHYpatterns;
412 var $loadedSHYpatterns;
413 var $loadedSHYdictionary;
414 var $SHYdictionary;
415 var $SHYdictionaryWords;
416
417 var $spanbgcolorarray;
418 var $default_font;
419 var $headerbuffer;
420 var $lastblocklevelchange;
421 var $nestedtablejustfinished;
422 var $linebreakjustfinished;
423 var $cell_border_dominance_L;
424 var $cell_border_dominance_R;
425 var $cell_border_dominance_T;
426 var $cell_border_dominance_B;
427 var $table_keep_together;
428 var $plainCell_properties;
429 var $shrin_k1;
430 var $outerfilled;
431
432 var $blockContext;
433 var $floatDivs;
434
435 var $patterns;
436 var $pageBackgrounds;
437
438 var $bodyBackgroundGradient;
439 var $bodyBackgroundImage;
440 var $bodyBackgroundColor;
441
442 var $writingHTMLheader; // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
443 var $writingHTMLfooter;
444
445 var $angle;
446
447 var $gradients;
448
449 var $kwt_Reference;
450 var $kwt_BMoutlines;
451 var $kwt_toc;
452
453 var $tbrot_BMoutlines;
454 var $tbrot_toc;
455
456 var $col_BMoutlines;
457 var $col_toc;
458
459 var $currentGraphId;
460 var $graphs;
461
462 var $floatbuffer;
463 var $floatmargins;
464
465 var $bullet;
466 var $bulletarray;
467
468 var $currentLang;
469 var $default_lang;
470
471 var $default_available_fonts;
472
473 var $pageTemplate;
474 var $docTemplate;
475 var $docTemplateContinue;
476
477 var $arabGlyphs;
478 var $arabHex;
479 var $persianGlyphs;
480 var $persianHex;
481 var $arabVowels;
482 var $arabPrevLink;
483 var $arabNextLink;
484
485 var $formobjects; // array of Form Objects for WMF
486 var $InlineProperties;
487 var $InlineAnnots;
488 var $InlineBDF; // mPDF 6 Bidirectional formatting
489 var $InlineBDFctr; // mPDF 6
490
491 var $ktAnnots;
492 var $tbrot_Annots;
493 var $kwt_Annots;
494 var $columnAnnots;
495 var $columnForms;
496
497 var $PageAnnots;
498
499 var $pageDim; // Keep track of page wxh for orientation changes - set in _beginpage, used in _putannots
500
501 var $breakpoints;
502
503 var $tableLevel;
504 var $tbctr;
505 var $innermostTableLevel;
506 var $saveTableCounter;
507 var $cellBorderBuffer;
508
509 var $saveHTMLFooter_height;
510 var $saveHTMLFooterE_height;
511
512 var $firstPageBoxHeader;
513 var $firstPageBoxHeaderEven;
514 var $firstPageBoxFooter;
515 var $firstPageBoxFooterEven;
516
517 var $page_box;
518
519 var $show_marks; // crop or cross marks
520 var $basepathIsLocal;
521
522 var $use_kwt;
523 var $kwt;
524 var $kwt_height;
525 var $kwt_y0;
526 var $kwt_x0;
527 var $kwt_buffer;
528 var $kwt_Links;
529 var $kwt_moved;
530 var $kwt_saved;
531
532 var $PageNumSubstitutions;
533
534 var $table_borders_separate;
535 var $base_table_properties;
536 var $borderstyles;
537
538 var $blockjustfinished;
539
540 var $orig_bMargin;
541 var $orig_tMargin;
542 var $orig_lMargin;
543 var $orig_rMargin;
544 var $orig_hMargin;
545 var $orig_fMargin;
546
547 var $pageHTMLheaders;
548 var $pageHTMLfooters;
549
550 var $saveHTMLHeader;
551 var $saveHTMLFooter;
552
553 var $HTMLheaderPageLinks;
554 var $HTMLheaderPageAnnots;
555 var $HTMLheaderPageForms;
556
557 // See config_fonts.php for these next 5 values
558 var $available_unifonts;
559 var $sans_fonts;
560 var $serif_fonts;
561 var $mono_fonts;
562 var $defaultSubsFont;
563
564 // List of ALL available CJK fonts (incl. styles) (Adobe add-ons) hw removed
565 var $available_CJK_fonts;
566
567 var $HTMLHeader;
568 var $HTMLFooter;
569 var $HTMLHeaderE;
570 var $HTMLFooterE;
571 var $bufferoutput;
572
573 // CJK fonts
574 var $Big5_widths;
575 var $GB_widths;
576 var $SJIS_widths;
577 var $UHC_widths;
578
579 // SetProtection
580 var $encrypted; // whether document is protected
581 var $Uvalue; // U entry in pdf document
582 var $Ovalue; // O entry in pdf document
583 var $Pvalue; // P entry in pdf document
584
585 var $enc_obj_id; //encryption object id
586 var $last_rc4_key; //last RC4 key encrypted (cached for optimisation)
587 var $last_rc4_key_c; //last RC4 computed key
588
589 var $encryption_key;
590
591 var $padding; //used for encryption
592
593 // Bookmark
594 var $BMoutlines;
595 var $OutlineRoot;
596
597 // INDEX
598 var $ColActive;
599 var $Reference;
600 var $CurrCol;
601 var $NbCol;
602 var $y0; //Top ordinate of columns
603
604 var $ColL;
605 var $ColWidth;
606 var $ColGap;
607
608 // COLUMNS
609 var $ColR;
610 var $ChangeColumn;
611 var $columnbuffer;
612 var $ColDetails;
613 var $columnLinks;
614 var $colvAlign;
615
616 // Substitutions
617 var $substitute; // Array of substitution strings e.g. <ttz>112</ttz>
618 var $entsearch; // Array of HTML entities (>ASCII 127) to substitute
619 var $entsubstitute; // Array of substitution decimal unicode for the Hi entities
620
621 // Default values if no style sheet offered (cf. http://www.w3.org/TR/CSS21/sample.html)
622 var $defaultCSS;
623 var $lastoptionaltag; // Save current block item which HTML specifies optionsl endtag
624 var $pageoutput;
625 var $charset_in;
626 var $blk;
627 var $blklvl;
628 var $ColumnAdjust;
629
630 var $ws; // Word spacing
631
632 var $HREF;
633 var $pgwidth;
634 var $fontlist;
635 var $oldx;
636 var $oldy;
637 var $B;
638 var $I;
639
640 var $tdbegin;
641 var $table;
642 var $cell;
643 var $col;
644 var $row;
645
646 var $divbegin;
647 var $divwidth;
648 var $divheight;
649 var $spanbgcolor;
650
651 // mPDF 6 Used for table cell (block-type) properties
652 var $cellTextAlign;
653 var $cellLineHeight;
654 var $cellLineStackingStrategy;
655 var $cellLineStackingShift;
656
657 // mPDF 6 Lists
658 var $listcounter;
659 var $listlvl;
660 var $listtype;
661 var $listitem;
662
663 var $pjustfinished;
664 var $ignorefollowingspaces;
665 var $SMALL;
666 var $BIG;
667 var $dash_on;
668 var $dotted_on;
669
670 var $textbuffer;
671 var $currentfontstyle;
672 var $currentfontfamily;
673 var $currentfontsize;
674 var $colorarray;
675 var $bgcolorarray;
676 var $internallink;
677 var $enabledtags;
678
679 var $lineheight;
680 var $basepath;
681 var $textparam;
682
683 var $specialcontent;
684 var $selectoption;
685 var $objectbuffer;
686
687 // Table Rotation
688 var $table_rotate;
689 var $tbrot_maxw;
690 var $tbrot_maxh;
691 var $tablebuffer;
692 var $tbrot_align;
693 var $tbrot_Links;
694
695 var $keep_block_together; // Keep a Block from page-break-inside: avoid
696
697 var $tbrot_y0;
698 var $tbrot_x0;
699 var $tbrot_w;
700 var $tbrot_h;
701
702 var $mb_enc;
703 var $directionality;
704
705 var $extgstates; // Used for alpha channel - Transparency (Watermark)
706 var $mgl;
707 var $mgt;
708 var $mgr;
709 var $mgb;
710
711 var $tts;
712 var $ttz;
713 var $tta;
714
715 // Best to alter the below variables using default stylesheet above
716 var $page_break_after_avoid;
717 var $margin_bottom_collapse;
718 var $default_font_size; // in pts
719 var $original_default_font_size; // used to save default sizes when using table default
720 var $original_default_font;
721 var $watermark_font;
722 var $defaultAlign;
723
724 // TABLE
725 var $defaultTableAlign;
726 var $tablethead;
727 var $thead_font_weight;
728 var $thead_font_style;
729 var $thead_font_smCaps;
730 var $thead_valign_default;
731 var $thead_textalign_default;
732 var $tabletfoot;
733 var $tfoot_font_weight;
734 var $tfoot_font_style;
735 var $tfoot_font_smCaps;
736 var $tfoot_valign_default;
737 var $tfoot_textalign_default;
738
739 var $trow_text_rotate;
740
741 var $cellPaddingL;
742 var $cellPaddingR;
743 var $cellPaddingT;
744 var $cellPaddingB;
745 var $table_border_attr_set;
746 var $table_border_css_set;
747
748 var $shrin_k; // factor with which to shrink tables - used internally - do not change
749 var $shrink_this_table_to_fit; // 0 or false to disable; value (if set) gives maximum factor to reduce fontsize
750 var $MarginCorrection; // corrects for OddEven Margins
751 var $margin_footer;
752 var $margin_header;
753
754 var $tabletheadjustfinished;
755 var $usingCoreFont;
756 var $charspacing;
757
758 //Private properties FROM FPDF
759 var $DisplayPreferences;
760 var $flowingBlockAttr;
761 var $page; //current page number
762 var $n; //current object number
763 var $offsets; //array of object offsets
764 var $buffer; //buffer holding in-memory PDF
765 var $pages; //array containing pages
766 var $state; //current document state
767 var $compress; //compression flag
768 var $DefOrientation; //default orientation
769 var $CurOrientation; //current orientation
770 var $OrientationChanges; //array indicating orientation changes
771 var $k; //scale factor (number of points in user unit)
772 var $fwPt;
773 var $fhPt; //dimensions of page format in points
774 var $fw;
775 var $fh; //dimensions of page format in user unit
776 var $wPt;
777 var $hPt; //current dimensions of page in points
778 var $w;
779 var $h; //current dimensions of page in user unit
780 var $lMargin; //left margin
781 var $tMargin; //top margin
782 var $rMargin; //right margin
783 var $bMargin; //page break margin
784 var $cMarginL; //cell margin Left
785 var $cMarginR; //cell margin Right
786 var $cMarginT; //cell margin Left
787 var $cMarginB; //cell margin Right
788 var $DeflMargin; //Default left margin
789 var $DefrMargin; //Default right margin
790 var $x;
791 var $y; //current position in user unit for cell positioning
792 var $lasth; //height of last cell printed
793 var $LineWidth; //line width in user unit
794 var $CoreFonts; //array of standard font names
795 var $fonts; //array of used fonts
796 var $FontFiles; //array of font files
797 var $images; //array of used images
798 var $PageLinks; //array of links in pages
799 var $links; //array of internal links
800 var $FontFamily; //current font family
801 var $FontStyle; //current font style
802 var $CurrentFont; //current font info
803 var $FontSizePt; //current font size in points
804 var $FontSize; //current font size in user unit
805 var $DrawColor; //commands for drawing color
806 var $FillColor; //commands for filling color
807 var $TextColor; //commands for text color
808 var $ColorFlag; //indicates whether fill and text colors are different
809 var $autoPageBreak; //automatic page breaking
810 var $PageBreakTrigger; //threshold used to trigger page breaks
811 var $InFooter; //flag set when processing footer
812
813 var $InHTMLFooter;
814 var $processingFooter; //flag set when processing footer - added for columns
815 var $processingHeader; //flag set when processing header - added for columns
816 var $ZoomMode; //zoom display mode
817 var $LayoutMode; //layout display mode
818 var $title; //title
819 var $subject; //subject
820 var $author; //author
821 var $keywords; //keywords
822 var $creator; //creator
823
824 var $aliasNbPg; //alias for total number of pages
825 var $aliasNbPgGp; //alias for total number of pages in page group
826
827 //var $aliasNbPgHex; // mPDF 6 deleted
828 //var $aliasNbPgGpHex; // mPDF 6 deleted
829
830 var $ispre;
831 var $outerblocktags;
832 var $innerblocktags;
833
834 // **********************************
835 // **********************************
836 // **********************************
837 // **********************************
838 // **********************************
839 // **********************************
840 // **********************************
841 // **********************************
842 // **********************************
843
844 private $tag;
845
846 public function __construct($mode = '', $format = 'A4', $default_font_size = 0, $default_font = '', $mgl = 15, $mgr = 15, $mgt = 16, $mgb = 16, $mgh = 9, $mgf = 9, $orientation = 'P')
847 {
848 /* -- BACKGROUNDS -- */
849 if (!class_exists('grad', false)) {
850 include(_MPDF_PATH . 'classes/grad.php');
851 }
852 if (empty($this->grad)) {
853 $this->grad = new grad($this);
854 }
855 /* -- END BACKGROUNDS -- */
856 /* -- FORMS -- */
857 if (!class_exists('mpdfform', false)) {
858 include(_MPDF_PATH . 'classes/mpdfform.php');
859 }
860 if (empty($this->mpdfform)) {
861 $this->mpdfform = new mpdfform($this);
862 }
863 /* -- END FORMS -- */
864
865 $this->time0 = microtime(true);
866 //Some checks
867 $this->_dochecks();
868
869 $this->writingToC = false;
870 $this->layers = array();
871 $this->current_layer = 0;
872 $this->open_layer_pane = false;
873
874 $this->visibility = 'visible';
875
876 //Initialization of properties
877 $this->spotColors = array();
878 $this->spotColorIDs = array();
879 $this->tableBackgrounds = array();
880 $this->uniqstr = '20110230'; // mPDF 5.7.2
881 $this->kt_y00 = '';
882 $this->kt_p00 = '';
883 $this->iterationCounter = false;
884 $this->BMPonly = array();
885 $this->page = 0;
886 $this->n = 2;
887 $this->buffer = '';
888 $this->objectbuffer = array();
889 $this->pages = array();
890 $this->OrientationChanges = array();
891 $this->state = 0;
892 $this->fonts = array();
893 $this->FontFiles = array();
894 $this->images = array();
895 $this->links = array();
896 $this->InFooter = false;
897 $this->processingFooter = false;
898 $this->processingHeader = false;
899 $this->lasth = 0;
900 $this->FontFamily = '';
901 $this->FontStyle = '';
902 $this->FontSizePt = 9;
903 $this->U = false;
904 // Small Caps
905 $this->upperCase = array();
906 $this->smCapsScale = 1;
907 $this->smCapsStretch = 100;
908 $this->margBuffer = 0;
909 $this->inMeter = false;
910 $this->decimal_offset = 0;
911
912 $this->defTextColor = $this->TextColor = $this->SetTColor($this->ConvertColor(0), true);
913 $this->defDrawColor = $this->DrawColor = $this->SetDColor($this->ConvertColor(0), true);
914 $this->defFillColor = $this->FillColor = $this->SetFColor($this->ConvertColor(255), true);
915
916 //SVG color names array
917 //http://www.w3schools.com/css/css_colornames.asp
918 $this->SVGcolors = array('antiquewhite' => '#FAEBD7', 'aqua' => '#00FFFF', 'aquamarine' => '#7FFFD4', 'beige' => '#F5F5DC', 'black' => '#000000',
919 'blue' => '#0000FF', 'brown' => '#A52A2A', 'cadetblue' => '#5F9EA0', 'chocolate' => '#D2691E', 'cornflowerblue' => '#6495ED', 'crimson' => '#DC143C',
920 'darkblue' => '#00008B', 'darkgoldenrod' => '#B8860B', 'darkgreen' => '#006400', 'darkmagenta' => '#8B008B', 'darkorange' => '#FF8C00',
921 'darkred' => '#8B0000', 'darkseagreen' => '#8FBC8F', 'darkslategray' => '#2F4F4F', 'darkviolet' => '#9400D3', 'deepskyblue' => '#00BFFF',
922 'dodgerblue' => '#1E90FF', 'firebrick' => '#B22222', 'forestgreen' => '#228B22', 'fuchsia' => '#FF00FF', 'gainsboro' => '#DCDCDC', 'gold' => '#FFD700',
923 'gray' => '#808080', 'green' => '#008000', 'greenyellow' => '#ADFF2F', 'hotpink' => '#FF69B4', 'indigo' => '#4B0082', 'khaki' => '#F0E68C',
924 'lavenderblush' => '#FFF0F5', 'lemonchiffon' => '#FFFACD', 'lightcoral' => '#F08080', 'lightgoldenrodyellow' => '#FAFAD2', 'lightgreen' => '#90EE90',
925 'lightsalmon' => '#FFA07A', 'lightskyblue' => '#87CEFA', 'lightslategray' => '#778899', 'lightyellow' => '#FFFFE0', 'lime' => '#00FF00', 'limegreen' => '#32CD32',
926 'magenta' => '#FF00FF', 'maroon' => '#800000', 'mediumaquamarine' => '#66CDAA', 'mediumorchid' => '#BA55D3', 'mediumseagreen' => '#3CB371',
927 'mediumspringgreen' => '#00FA9A', 'mediumvioletred' => '#C71585', 'midnightblue' => '#191970', 'mintcream' => '#F5FFFA', 'moccasin' => '#FFE4B5', 'navy' => '#000080',
928 'olive' => '#808000', 'orange' => '#FFA500', 'orchid' => '#DA70D6', 'palegreen' => '#98FB98',
929 'palevioletred' => '#D87093', 'peachpuff' => '#FFDAB9', 'pink' => '#FFC0CB', 'powderblue' => '#B0E0E6', 'purple' => '#800080',
930 'red' => '#FF0000', 'royalblue' => '#4169E1', 'salmon' => '#FA8072', 'seagreen' => '#2E8B57', 'sienna' => '#A0522D', 'silver' => '#C0C0C0', 'skyblue' => '#87CEEB',
931 'slategray' => '#708090', 'springgreen' => '#00FF7F', 'steelblue' => '#4682B4', 'tan' => '#D2B48C', 'teal' => '#008080', 'thistle' => '#D8BFD8', 'turquoise' => '#40E0D0',
932 'violetred' => '#D02090', 'white' => '#FFFFFF', 'yellow' => '#FFFF00',
933 'aliceblue' => '#f0f8ff', 'azure' => '#f0ffff', 'bisque' => '#ffe4c4', 'blanchedalmond' => '#ffebcd', 'blueviolet' => '#8a2be2', 'burlywood' => '#deb887',
934 'chartreuse' => '#7fff00', 'coral' => '#ff7f50', 'cornsilk' => '#fff8dc', 'cyan' => '#00ffff', 'darkcyan' => '#008b8b', 'darkgray' => '#a9a9a9',
935 'darkgrey' => '#a9a9a9', 'darkkhaki' => '#bdb76b', 'darkolivegreen' => '#556b2f', 'darkorchid' => '#9932cc', 'darksalmon' => '#e9967a',
936 'darkslateblue' => '#483d8b', 'darkslategrey' => '#2f4f4f', 'darkturquoise' => '#00ced1', 'deeppink' => '#ff1493', 'dimgray' => '#696969',
937 'dimgrey' => '#696969', 'floralwhite' => '#fffaf0', 'ghostwhite' => '#f8f8ff', 'goldenrod' => '#daa520', 'grey' => '#808080', 'honeydew' => '#f0fff0',
938 'indianred' => '#cd5c5c', 'ivory' => '#fffff0', 'lavender' => '#e6e6fa', 'lawngreen' => '#7cfc00', 'lightblue' => '#add8e6', 'lightcyan' => '#e0ffff',
939 'lightgray' => '#d3d3d3', 'lightgrey' => '#d3d3d3', 'lightpink' => '#ffb6c1', 'lightseagreen' => '#20b2aa', 'lightslategrey' => '#778899',
940 'lightsteelblue' => '#b0c4de', 'linen' => '#faf0e6', 'mediumblue' => '#0000cd', 'mediumpurple' => '#9370db', 'mediumslateblue' => '#7b68ee',
941 'mediumturquoise' => '#48d1cc', 'mistyrose' => '#ffe4e1', 'navajowhite' => '#ffdead', 'oldlace' => '#fdf5e6', 'olivedrab' => '#6b8e23', 'orangered' => '#ff4500',
942 'palegoldenrod' => '#eee8aa', 'paleturquoise' => '#afeeee', 'papayawhip' => '#ffefd5', 'peru' => '#cd853f', 'plum' => '#dda0dd', 'rosybrown' => '#bc8f8f',
943 'saddlebrown' => '#8b4513', 'sandybrown' => '#f4a460', 'seashell' => '#fff5ee', 'slateblue' => '#6a5acd', 'slategrey' => '#708090', 'snow' => '#fffafa',
944 'tomato' => '#ff6347', 'violet' => '#ee82ee', 'wheat' => '#f5deb3', 'whitesmoke' => '#f5f5f5', 'yellowgreen' => '#9acd32');
945
946 // Uppercase alternatives (for Small Caps)
947 if (empty($this->upperCase)) {
948 @include(_MPDF_PATH . 'includes/upperCase.php');
949 }
950 $this->extrapagebreak = true; // mPDF 6 pagebreaktype
951
952 $this->ColorFlag = false;
953 $this->extgstates = array();
954
955 $this->mb_enc = 'windows-1252';
956 $this->directionality = 'ltr';
957 $this->defaultAlign = 'L';
958 $this->defaultTableAlign = 'L';
959
960 $this->fixedPosBlockSave = array();
961 $this->extraFontSubsets = 0;
962
963 $this->SHYpatterns = array();
964 $this->loadedSHYdictionary = false;
965 $this->SHYdictionary = array();
966 $this->SHYdictionaryWords = array();
967 $this->blockContext = 1;
968 $this->floatDivs = array();
969 $this->DisplayPreferences = '';
970
971 $this->patterns = array(); // Tiling patterns used for backgrounds
972 $this->pageBackgrounds = array();
973 $this->writingHTMLheader = false; // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
974 $this->writingHTMLfooter = false; // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
975 $this->gradients = array();
976
977 $this->kwt_Reference = array();
978 $this->kwt_BMoutlines = array();
979 $this->kwt_toc = array();
980
981 $this->tbrot_BMoutlines = array();
982 $this->tbrot_toc = array();
983
984 $this->col_BMoutlines = array();
985 $this->col_toc = array();
986 $this->graphs = array();
987
988 $this->pgsIns = array();
989 $this->PDFAXwarnings = array();
990 $this->inlineDisplayOff = false;
991 $this->lSpacingCSS = '';
992 $this->wSpacingCSS = '';
993 $this->fixedlSpacing = false;
994 $this->minwSpacing = 0;
995
996
997 $this->baselineC = 0.35; // Baseline for text
998 // mPDF 5.7.3 inline text-decoration parameters
999 $this->baselineSup = 0.5; // Sets default change in baseline for <sup> text as factor of preceeding fontsize
1000 // 0.35 has been recommended; 0.5 matches applications like MS Word
1001 $this->baselineSub = -0.2; // Sets default change in baseline for <sub> text as factor of preceeding fontsize
1002 $this->baselineS = 0.3; // Sets default height for <strike> text as factor of fontsize
1003 $this->baselineO = 1.1; // Sets default height for overline text as factor of fontsize
1004
1005 $this->noImageFile = str_replace("\\", "/", dirname(__FILE__)) . '/includes/no_image.jpg';
1006 $this->subPos = 0;
1007 $this->normalLineheight = 1.3; // This should be overridden in config.php - but it is so important a default value is put here
1008 // These are intended as configuration variables, and should be set in config.php - which will override these values;
1009 // set here as failsafe as will cause an error if not defined
1010 $this->incrementFPR1 = 10;
1011 $this->incrementFPR2 = 10;
1012 $this->incrementFPR3 = 10;
1013 $this->incrementFPR4 = 10;
1014
1015 $this->fullImageHeight = false;
1016 $this->floatbuffer = array();
1017 $this->floatmargins = array();
1018 $this->formobjects = array(); // array of Form Objects for WMF
1019 $this->InlineProperties = array();
1020 $this->InlineAnnots = array();
1021 $this->InlineBDF = array(); // mPDF 6
1022 $this->InlineBDFctr = 0; // mPDF 6
1023 $this->tbrot_Annots = array();
1024 $this->kwt_Annots = array();
1025 $this->columnAnnots = array();
1026 $this->pageDim = array();
1027 $this->breakpoints = array(); // used in columnbuffer
1028 $this->tableLevel = 0;
1029 $this->tbctr = array(); // counter for nested tables at each level
1030 $this->page_box = array();
1031 $this->show_marks = ''; // crop or cross marks
1032 $this->kwt = false;
1033 $this->kwt_height = 0;
1034 $this->kwt_y0 = 0;
1035 $this->kwt_x0 = 0;
1036 $this->kwt_buffer = array();
1037 $this->kwt_Links = array();
1038 $this->kwt_moved = false;
1039 $this->kwt_saved = false;
1040 $this->PageNumSubstitutions = array();
1041 $this->base_table_properties = array();
1042 $this->borderstyles = array('inset', 'groove', 'outset', 'ridge', 'dotted', 'dashed', 'solid', 'double');
1043 $this->tbrot_align = 'C';
1044
1045 $this->pageHTMLheaders = array();
1046 $this->pageHTMLfooters = array();
1047 $this->HTMLheaderPageLinks = array();
1048 $this->HTMLheaderPageAnnots = array();
1049
1050 $this->HTMLheaderPageForms = array();
1051 $this->columnForms = array();
1052 $this->tbrotForms = array();
1053 $this->useRC128encryption = false;
1054 $this->uniqid = '';
1055
1056 $this->pageoutput = array();
1057
1058 $this->bufferoutput = false;
1059 $this->encrypted = false; //whether document is protected
1060 $this->BMoutlines = array();
1061 $this->ColActive = 0; //Flag indicating that columns are on (the index is being processed)
1062 $this->Reference = array(); //Array containing the references
1063 $this->CurrCol = 0; //Current column number
1064 $this->ColL = array(0); // Array of Left pos of columns - absolute - needs Margin correction for Odd-Even
1065 $this->ColR = array(0); // Array of Right pos of columns - absolute pos - needs Margin correction for Odd-Even
1066 $this->ChangeColumn = 0;
1067 $this->columnbuffer = array();
1068 $this->ColDetails = array(); // Keeps track of some column details
1069 $this->columnLinks = array(); // Cross references PageLinks
1070 $this->substitute = array(); // Array of substitution strings e.g. <ttz>112</ttz>
1071 $this->entsearch = array(); // Array of HTML entities (>ASCII 127) to substitute
1072 $this->entsubstitute = array(); // Array of substitution decimal unicode for the Hi entities
1073 $this->lastoptionaltag = '';
1074 $this->charset_in = '';
1075 $this->blk = array();
1076 $this->blklvl = 0;
1077 $this->tts = false;
1078 $this->ttz = false;
1079 $this->tta = false;
1080 $this->ispre = false;
1081
1082 $this->checkSIP = false;
1083 $this->checkSMP = false;
1084 $this->checkCJK = false;
1085
1086 $this->page_break_after_avoid = false;
1087 $this->margin_bottom_collapse = false;
1088 $this->tablethead = 0;
1089 $this->tabletfoot = 0;
1090 $this->table_border_attr_set = 0;
1091 $this->table_border_css_set = 0;
1092 $this->shrin_k = 1.0;
1093 $this->shrink_this_table_to_fit = 0;
1094 $this->MarginCorrection = 0;
1095
1096 $this->tabletheadjustfinished = false;
1097 $this->usingCoreFont = false;
1098 $this->charspacing = 0;
1099
1100 $this->autoPageBreak = true;
1101
1102 require(_MPDF_PATH . 'config.php'); // config data
1103
1104 $this->_setPageSize($format, $orientation);
1105 $this->DefOrientation = $orientation;
1106
1107 $this->margin_header = $mgh;
1108 $this->margin_footer = $mgf;
1109
1110 $bmargin = $mgb;
1111
1112 $this->DeflMargin = $mgl;
1113 $this->DefrMargin = $mgr;
1114
1115 $this->orig_tMargin = $mgt;
1116 $this->orig_bMargin = $bmargin;
1117 $this->orig_lMargin = $this->DeflMargin;
1118 $this->orig_rMargin = $this->DefrMargin;
1119 $this->orig_hMargin = $this->margin_header;
1120 $this->orig_fMargin = $this->margin_footer;
1121
1122 if ($this->setAutoTopMargin == 'pad') {
1123 $mgt += $this->margin_header;
1124 }
1125 if ($this->setAutoBottomMargin == 'pad') {
1126 $mgb += $this->margin_footer;
1127 }
1128 $this->SetMargins($this->DeflMargin, $this->DefrMargin, $mgt); // sets l r t margin
1129 //Automatic page break
1130 $this->SetAutoPageBreak($this->autoPageBreak, $bmargin); // sets $this->bMargin & PageBreakTrigger
1131
1132 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
1133
1134 //Interior cell margin (1 mm) ? not used
1135 $this->cMarginL = 1;
1136 $this->cMarginR = 1;
1137 //Line width (0.2 mm)
1138 $this->LineWidth = .567 / _MPDFK;
1139
1140 //To make the function Footer() work - replaces {nb} with page number
1141 $this->AliasNbPages();
1142 $this->AliasNbPageGroups();
1143
1144 //$this->aliasNbPgHex = '{nbHEXmarker}'; // mPDF 6 deleted
1145 //$this->aliasNbPgGpHex = '{nbpgHEXmarker}'; // mPDF 6 deleted
1146 //Enable all tags as default
1147 $this->DisableTags();
1148 //Full width display mode
1149 $this->SetDisplayMode(100); // fullwidth? 'fullpage'
1150 //Compression
1151 $this->SetCompression(true);
1152 //Set default display preferences
1153 $this->SetDisplayPreferences('');
1154
1155 // Font data
1156 require(_MPDF_PATH . 'config_fonts.php');
1157
1158 // check for a custom config file that can add/overwrite the default config
1159 if (defined('_MPDF_SYSTEM_TTFONTS_CONFIG') && file_exists(_MPDF_SYSTEM_TTFONTS_CONFIG)) {
1160 require(_MPDF_SYSTEM_TTFONTS_CONFIG);
1161 }
1162
1163 // Available fonts
1164 $this->available_unifonts = array();
1165 foreach ($this->fontdata AS $f => $fs) {
1166 if (isset($fs['R']) && $fs['R']) {
1167 $this->available_unifonts[] = $f;
1168 }
1169 if (isset($fs['B']) && $fs['B']) {
1170 $this->available_unifonts[] = $f . 'B';
1171 }
1172 if (isset($fs['I']) && $fs['I']) {
1173 $this->available_unifonts[] = $f . 'I';
1174 }
1175 if (isset($fs['BI']) && $fs['BI']) {
1176 $this->available_unifonts[] = $f . 'BI';
1177 }
1178 }
1179
1180 $this->default_available_fonts = $this->available_unifonts;
1181
1182 $optcore = false;
1183 $onlyCoreFonts = false;
1184 if (preg_match('/([\-+])aCJK/i', $mode, $m)) {
1185 $mode = preg_replace('/([\-+])aCJK/i', '', $mode); // mPDF 6
1186 if ($m[1] == '+') {
1187 $this->useAdobeCJK = true;
1188 } else {
1189 $this->useAdobeCJK = false;
1190 }
1191 }
1192
1193 if (strlen($mode) == 1) {
1194 if ($mode == 's') {
1195 $this->percentSubset = 100;
1196 $mode = '';
1197 } elseif ($mode == 'c') {
1198 $onlyCoreFonts = true;
1199 $mode = '';
1200 }
1201 } elseif (substr($mode, -2) == '-s') {
1202 $this->percentSubset = 100;
1203 $mode = substr($mode, 0, strlen($mode) - 2);
1204 } elseif (substr($mode, -2) == '-c') {
1205 $onlyCoreFonts = true;
1206 $mode = substr($mode, 0, strlen($mode) - 2);
1207 } elseif (substr($mode, -2) == '-x') {
1208 $optcore = true;
1209 $mode = substr($mode, 0, strlen($mode) - 2);
1210 }
1211
1212 // Autodetect if mode is a language_country string (en-GB or en_GB or en)
1213 if ($mode && $mode != 'UTF-8') { // mPDF 6
1214 list ($coreSuitable, $mpdf_pdf_unifont) = GetLangOpts($mode, $this->useAdobeCJK, $this->fontdata);
1215 if ($coreSuitable && $optcore) {
1216 $onlyCoreFonts = true;
1217 }
1218 if ($mpdf_pdf_unifont) { // mPDF 6
1219 $default_font = $mpdf_pdf_unifont;
1220 }
1221 $this->currentLang = $mode;
1222 $this->default_lang = $mode;
1223 }
1224
1225 $this->onlyCoreFonts = $onlyCoreFonts;
1226
1227 if ($this->onlyCoreFonts) {
1228 $this->setMBencoding('windows-1252'); // sets $this->mb_enc
1229 } else {
1230 $this->setMBencoding('UTF-8'); // sets $this->mb_enc
1231 }
1232 @mb_regex_encoding('UTF-8'); // required only for mb_ereg... and mb_split functions
1233 // Adobe CJK fonts
1234 $this->available_CJK_fonts = array('gb', 'big5', 'sjis', 'uhc', 'gbB', 'big5B', 'sjisB', 'uhcB', 'gbI', 'big5I', 'sjisI', 'uhcI',
1235 'gbBI', 'big5BI', 'sjisBI', 'uhcBI');
1236
1237
1238 //Standard fonts
1239 $this->CoreFonts = array('ccourier' => 'Courier', 'ccourierB' => 'Courier-Bold', 'ccourierI' => 'Courier-Oblique', 'ccourierBI' => 'Courier-BoldOblique',
1240 'chelvetica' => 'Helvetica', 'chelveticaB' => 'Helvetica-Bold', 'chelveticaI' => 'Helvetica-Oblique', 'chelveticaBI' => 'Helvetica-BoldOblique',
1241 'ctimes' => 'Times-Roman', 'ctimesB' => 'Times-Bold', 'ctimesI' => 'Times-Italic', 'ctimesBI' => 'Times-BoldItalic',
1242 'csymbol' => 'Symbol', 'czapfdingbats' => 'ZapfDingbats');
1243 $this->fontlist = array("ctimes", "ccourier", "chelvetica", "csymbol", "czapfdingbats");
1244
1245 // Substitutions
1246 $this->setHiEntitySubstitutions();
1247
1248 if ($this->onlyCoreFonts) {
1249 $this->useSubstitutions = true;
1250 $this->SetSubstitutions();
1251 } else {
1252 $this->useSubstitutions = false;
1253 }
1254
1255 /* -- HTML-CSS -- */
1256
1257 if (!class_exists('cssmgr', false)) {
1258 include(_MPDF_PATH . 'classes/cssmgr.php');
1259 }
1260 $this->cssmgr = new cssmgr($this);
1261 // mPDF 6
1262 if (file_exists(_MPDF_PATH . 'mpdf.css')) {
1263 $css = file_get_contents(_MPDF_PATH . 'mpdf.css');
1264 $this->cssmgr->ReadCSS('<style> ' . $css . ' </style>');
1265 }
1266 /* -- END HTML-CSS -- */
1267
1268 if ($default_font == '') {
1269 if ($this->onlyCoreFonts) {
1270 if (in_array(strtolower($this->defaultCSS['BODY']['FONT-FAMILY']), $this->mono_fonts)) {
1271 $default_font = 'ccourier';
1272 } elseif (in_array(strtolower($this->defaultCSS['BODY']['FONT-FAMILY']), $this->sans_fonts)) {
1273 $default_font = 'chelvetica';
1274 } else {
1275 $default_font = 'ctimes';
1276 }
1277 } else {
1278 $default_font = $this->defaultCSS['BODY']['FONT-FAMILY'];
1279 }
1280 }
1281 if (!$default_font_size) {
1282 $mmsize = $this->ConvertSize($this->defaultCSS['BODY']['FONT-SIZE']);
1283 $default_font_size = $mmsize * (_MPDFK);
1284 }
1285
1286 if ($default_font) {
1287 $this->SetDefaultFont($default_font);
1288 }
1289 if ($default_font_size) {
1290 $this->SetDefaultFontSize($default_font_size);
1291 }
1292
1293 $this->SetLineHeight(); // lineheight is in mm
1294
1295 $this->SetFColor($this->ConvertColor(255));
1296 $this->HREF = '';
1297 $this->oldy = -1;
1298 $this->B = 0;
1299 $this->I = 0;
1300
1301 // mPDF 6 Lists
1302 $this->listlvl = 0;
1303 $this->listtype = array();
1304 $this->listitem = array();
1305 $this->listcounter = array();
1306
1307 $this->tdbegin = false;
1308 $this->table = array();
1309 $this->cell = array();
1310 $this->col = -1;
1311 $this->row = -1;
1312 $this->cellBorderBuffer = array();
1313
1314 $this->divbegin = false;
1315 // mPDF 6
1316 $this->cellTextAlign = '';
1317 $this->cellLineHeight = '';
1318 $this->cellLineStackingStrategy = '';
1319 $this->cellLineStackingShift = '';
1320
1321 $this->divwidth = 0;
1322 $this->divheight = 0;
1323 $this->spanbgcolor = false;
1324 $this->spanborder = false;
1325 $this->spanborddet = array();
1326
1327 $this->blockjustfinished = false;
1328 $this->ignorefollowingspaces = true; //in order to eliminate exceeding left-side spaces
1329 $this->dash_on = false;
1330 $this->dotted_on = false;
1331 $this->textshadow = '';
1332
1333 $this->currentfontfamily = '';
1334 $this->currentfontsize = '';
1335 $this->currentfontstyle = '';
1336 $this->colorarray = ''; // mPDF 6
1337 $this->spanbgcolorarray = ''; // mPDF 6
1338 $this->textbuffer = array();
1339 $this->internallink = array();
1340 $this->basepath = "";
1341
1342 $this->SetBasePath('');
1343
1344 $this->textparam = array();
1345
1346 $this->specialcontent = '';
1347 $this->selectoption = array();
1348
1349 /* -- IMPORTS -- */
1350
1351 $this->tpls = array();
1352 $this->tpl = 0;
1353 $this->tplprefix = "/TPL";
1354 $this->res = array();
1355 if ($this->enableImports) {
1356 $this->SetImportUse();
1357 }
1358 /* -- END IMPORTS -- */
1359
1360 if ($this->progressBar) {
1361 $this->StartProgressBarOutput($this->progressBar);
1362 } // *PROGRESS-BAR*
1363
1364 $this->tag = new Tag($this);
1365 }
1366
1367 function _setPageSize($format, &$orientation)
1368 {
1369 //Page format
1370 if (is_string($format)) {
1371 if ($format == '') {
1372 $format = 'A4';
1373 }
1374 $pfo = 'P';
1375 if (preg_match('/([0-9a-zA-Z]*)-L/i', $format, $m)) { // e.g. A4-L = A4 landscape
1376 $format = $m[1];
1377 $pfo = 'L';
1378 }
1379 $format = $this->_getPageFormat($format);
1380 if (!$format) {
1381 throw new MpdfException('Unknown page format: ' . $format);
1382 } else {
1383 $orientation = $pfo;
1384 }
1385
1386 $this->fwPt = $format[0];
1387 $this->fhPt = $format[1];
1388 } else {
1389 if (!$format[0] || !$format[1]) {
1390 throw new MpdfException('Invalid page format: ' . $format[0] . ' ' . $format[1]);
1391 }
1392 $this->fwPt = $format[0] * _MPDFK;
1393 $this->fhPt = $format[1] * _MPDFK;
1394 }
1395 $this->fw = $this->fwPt / _MPDFK;
1396 $this->fh = $this->fhPt / _MPDFK;
1397 //Page orientation
1398 $orientation = strtolower($orientation);
1399 if ($orientation == 'p' or $orientation == 'portrait') {
1400 $orientation = 'P';
1401 $this->wPt = $this->fwPt;
1402 $this->hPt = $this->fhPt;
1403 } elseif ($orientation == 'l' or $orientation == 'landscape') {
1404 $orientation = 'L';
1405 $this->wPt = $this->fhPt;
1406 $this->hPt = $this->fwPt;
1407 } else
1408 throw new MpdfException('Incorrect orientation: ' . $orientation);
1409 $this->CurOrientation = $orientation;
1410
1411 $this->w = $this->wPt / _MPDFK;
1412 $this->h = $this->hPt / _MPDFK;
1413 }
1414
1415 function _getPageFormat($format)
1416 {
1417 switch (strtoupper($format)) {
1418 case '4A0': {
1419 $format = array(4767.87, 6740.79);
1420 break;
1421 }
1422 case '2A0': {
1423 $format = array(3370.39, 4767.87);
1424 break;
1425 }
1426 case 'A0': {
1427 $format = array(2383.94, 3370.39);
1428 break;
1429 }
1430 case 'A1': {
1431 $format = array(1683.78, 2383.94);
1432 break;
1433 }
1434 case 'A2': {
1435 $format = array(1190.55, 1683.78);
1436 break;
1437 }
1438 case 'A3': {
1439 $format = array(841.89, 1190.55);
1440 break;
1441 }
1442 case 'A4': {
1443 $format = array(595.28, 841.89);
1444 break;
1445 }
1446 case 'A5': {
1447 $format = array(419.53, 595.28);
1448 break;
1449 }
1450 case 'A6': {
1451 $format = array(297.64, 419.53);
1452 break;
1453 }
1454 case 'A7': {
1455 $format = array(209.76, 297.64);
1456 break;
1457 }
1458 case 'A8': {
1459 $format = array(147.40, 209.76);
1460 break;
1461 }
1462 case 'A9': {
1463 $format = array(104.88, 147.40);
1464 break;
1465 }
1466 case 'A10': {
1467 $format = array(73.70, 104.88);
1468 break;
1469 }
1470 case 'B0': {
1471 $format = array(2834.65, 4008.19);
1472 break;
1473 }
1474 case 'B1': {
1475 $format = array(2004.09, 2834.65);
1476 break;
1477 }
1478 case 'B2': {
1479 $format = array(1417.32, 2004.09);
1480 break;
1481 }
1482 case 'B3': {
1483 $format = array(1000.63, 1417.32);
1484 break;
1485 }
1486 case 'B4': {
1487 $format = array(708.66, 1000.63);
1488 break;
1489 }
1490 case 'B5': {
1491 $format = array(498.90, 708.66);
1492 break;
1493 }
1494 case 'B6': {
1495 $format = array(354.33, 498.90);
1496 break;
1497 }
1498 case 'B7': {
1499 $format = array(249.45, 354.33);
1500 break;
1501 }
1502 case 'B8': {
1503 $format = array(175.75, 249.45);
1504 break;
1505 }
1506 case 'B9': {
1507 $format = array(124.72, 175.75);
1508 break;
1509 }
1510 case 'B10': {
1511 $format = array(87.87, 124.72);
1512 break;
1513 }
1514 case 'C0': {
1515 $format = array(2599.37, 3676.54);
1516 break;
1517 }
1518 case 'C1': {
1519 $format = array(1836.85, 2599.37);
1520 break;
1521 }
1522 case 'C2': {
1523 $format = array(1298.27, 1836.85);
1524 break;
1525 }
1526 case 'C3': {
1527 $format = array(918.43, 1298.27);
1528 break;
1529 }
1530 case 'C4': {
1531 $format = array(649.13, 918.43);
1532 break;
1533 }
1534 case 'C5': {
1535 $format = array(459.21, 649.13);
1536 break;
1537 }
1538 case 'C6': {
1539 $format = array(323.15, 459.21);
1540 break;
1541 }
1542 case 'C7': {
1543 $format = array(229.61, 323.15);
1544 break;
1545 }
1546 case 'C8': {
1547 $format = array(161.57, 229.61);
1548 break;
1549 }
1550 case 'C9': {
1551 $format = array(113.39, 161.57);
1552 break;
1553 }
1554 case 'C10': {
1555 $format = array(79.37, 113.39);
1556 break;
1557 }
1558 case 'RA0': {
1559 $format = array(2437.80, 3458.27);
1560 break;
1561 }
1562 case 'RA1': {
1563 $format = array(1729.13, 2437.80);
1564 break;
1565 }
1566 case 'RA2': {
1567 $format = array(1218.90, 1729.13);
1568 break;
1569 }
1570 case 'RA3': {
1571 $format = array(864.57, 1218.90);
1572 break;
1573 }
1574 case 'RA4': {
1575 $format = array(609.45, 864.57);
1576 break;
1577 }
1578 case 'SRA0': {
1579 $format = array(2551.18, 3628.35);
1580 break;
1581 }
1582 case 'SRA1': {
1583 $format = array(1814.17, 2551.18);
1584 break;
1585 }
1586 case 'SRA2': {
1587 $format = array(1275.59, 1814.17);
1588 break;
1589 }
1590 case 'SRA3': {
1591 $format = array(907.09, 1275.59);
1592 break;
1593 }
1594 case 'SRA4': {
1595 $format = array(637.80, 907.09);
1596 break;
1597 }
1598 case 'LETTER': {
1599 $format = array(612.00, 792.00);
1600 break;
1601 }
1602 case 'LEGAL': {
1603 $format = array(612.00, 1008.00);
1604 break;
1605 }
1606 case 'LEDGER': {
1607 $format = array(1224.00, 792.00);
1608 break;
1609 }
1610 case 'TABLOID': {
1611 $format = array(792.00, 1224.00);
1612 break;
1613 }
1614 case 'EXECUTIVE': {
1615 $format = array(521.86, 756.00);
1616 break;
1617 }
1618 case 'FOLIO': {
1619 $format = array(612.00, 936.00);
1620 break;
1621 }
1622 case 'B': {
1623 $format = array(362.83, 561.26);
1624 break;
1625 } // 'B' format paperback size 128x198mm
1626 case 'A': {
1627 $format = array(314.65, 504.57);
1628 break;
1629 } // 'A' format paperback size 111x178mm
1630 case 'DEMY': {
1631 $format = array(382.68, 612.28);
1632 break;
1633 } // 'Demy' format paperback size 135x216mm
1634 case 'ROYAL': {
1635 $format = array(433.70, 663.30);
1636 break;
1637 } // 'Royal' format paperback size 153x234mm
1638 default: {
1639 $format = array(595.28, 841.89);
1640 break;
1641 }
1642 }
1643 return $format;
1644 }
1645
1646 /* -- PROGRESS-BAR -- */
1647
1648 function StartProgressBarOutput($mode = 1)
1649 {
1650 // must be relative path, or URI (not a file system path)
1651 if (!defined('_MPDF_URI')) {
1652 $this->progressBar = false;
1653 if ($this->debug) {
1654 throw new MpdfException("You need to define _MPDF_URI to use the progress bar!");
1655 } else
1656 return false;
1657 }
1658 $this->progressBar = $mode;
1659 if ($this->progbar_altHTML) {
1660 echo $this->progbar_altHTML;
1661 } else {
1662 echo '<html>
1663 <head>
1664 <title>mPDF File Progress</title>
1665 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1666 <link rel="stylesheet" type="text/css" href="' . _MPDF_URI . 'progbar.css" />
1667 </head>
1668 <body>
1669 <div class="main">
1670 <div class="heading">' . $this->progbar_heading . '</div>
1671 <div class="demo">
1672 ';
1673 if ($this->progressBar == 2) {
1674 echo ' <table width="100%"><tr><td style="width: 50%;">
1675 <span class="barheading">Writing HTML code</span> <br/>
1676
1677 <div class="progressBar">
1678 <div id="element1" class="innerBar">&nbsp;</div>
1679 </div>
1680 <span class="code" id="box1"></span>
1681 </td><td style="width: 50%;">
1682 <span class="barheading">Autosizing elements</span> <br/>
1683 <div class="progressBar">
1684 <div id="element4" class="innerBar">&nbsp;</div>
1685 </div>
1686 <span class="code" id="box4"></span>
1687 <br/><br/>
1688 <span class="barheading">Writing Tables</span> <br/>
1689 <div class="progressBar">
1690 <div id="element7" class="innerBar">&nbsp;</div>
1691 </div>
1692 <span class="code" id="box7"></span>
1693 </td></tr>
1694 <tr><td><br /><br /></td><td></td></tr>
1695 <tr><td style="width: 50%;">
1696 ';
1697 }
1698 echo ' <span class="barheading">Writing PDF file</span> <br/>
1699 <div class="progressBar">
1700 <div id="element2" class="innerBar">&nbsp;</div>
1701 </div>
1702 <span class="code" id="box2"></span>
1703 ';
1704 if ($this->progressBar == 2) {
1705 echo '
1706 </td><td style="width: 50%;">
1707 <span class="barheading">Memory usage</span> <br/>
1708 <div class="progressBar">
1709 <div id="element5" class="innerBar">&nbsp;</div>
1710 </div>
1711 <span id="box5">0</span> ' . ini_get("memory_limit") . '<br />
1712 <br/><br/>
1713 <span class="barheading">Memory usage (peak)</span> <br/>
1714 <div class="progressBar">
1715 <div id="element6" class="innerBar">&nbsp;</div>
1716 </div>
1717 <span id="box6">0</span> ' . ini_get("memory_limit") . '<br />
1718 </td></tr>
1719 </table>
1720 ';
1721 }
1722 echo ' <br/><br/>
1723 <span id="box3"></span>
1724
1725 </div>
1726 ';
1727 }
1728 ob_flush();
1729 flush();
1730 }
1731
1732 function UpdateProgressBar($el, $val, $txt = '')
1733 {
1734 // $val should be a string - 5 = actual value, +15 = increment
1735
1736 if ($this->progressBar < 2) {
1737 if ($el > 3) {
1738 return;
1739 } elseif ($el == 1) {
1740 $el = 2;
1741 }
1742 }
1743 echo '<script type="text/javascript">';
1744 if ($val) {
1745 echo ' document.getElementById(\'element' . $el . '\').style.width=\'' . $val . '%\'; ';
1746 }
1747 if ($txt) {
1748 echo ' document.getElementById(\'box' . $el . '\').innerHTML=\'' . $txt . '\'; ';
1749 }
1750 if ($this->progressBar == 2) {
1751 $m = round(memory_get_usage(true) / 1048576);
1752 $m2 = round(memory_get_peak_usage(true) / 1048576);
1753 $mem = $m * 100 / (ini_get("memory_limit") + 0);
1754 $mem2 = $m2 * 100 / (ini_get("memory_limit") + 0);
1755 echo ' document.getElementById(\'element5\').style.width=\'' . $mem . '%\'; ';
1756 echo ' document.getElementById(\'element6\').style.width=\'' . $mem2 . '%\'; ';
1757 echo ' document.getElementById(\'box5\').innerHTML=\'' . $m . 'MB / \'; ';
1758 echo ' document.getElementById(\'box6\').innerHTML=\'' . $m2 . 'MB / \'; ';
1759 }
1760 echo '</script>' . "\n";
1761 ob_flush();
1762 flush();
1763 }
1764
1765 /* -- END PROGRESS-BAR -- */
1766
1767 function RestrictUnicodeFonts($res)
1768 {
1769 // $res = array of (Unicode) fonts to restrict to: e.g. norasi|norasiB - language specific
1770 if (count($res)) { // Leave full list of available fonts if passed blank array
1771 $this->available_unifonts = $res;
1772 } else {
1773 $this->available_unifonts = $this->default_available_fonts;
1774 }
1775 if (count($this->available_unifonts) == 0) {
1776 $this->available_unifonts[] = $this->default_available_fonts[0];
1777 }
1778 $this->available_unifonts = array_values($this->available_unifonts);
1779 }
1780
1781 function setMBencoding($enc)
1782 {
1783 if ($this->mb_enc != $enc) {
1784 $this->mb_enc = $enc;
1785 mb_internal_encoding($this->mb_enc);
1786 }
1787 }
1788
1789 function SetMargins($left, $right, $top)
1790 {
1791 //Set left, top and right margins
1792 $this->lMargin = $left;
1793 $this->rMargin = $right;
1794 $this->tMargin = $top;
1795 }
1796
1797 function ResetMargins()
1798 {
1799 //ReSet left, top margins
1800 if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation == 'P' && $this->CurOrientation == 'L') {
1801 if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
1802 $this->tMargin = $this->orig_rMargin;
1803 $this->bMargin = $this->orig_lMargin;
1804 } else { // ODD // OR NOT MIRRORING MARGINS/FOOTERS
1805 $this->tMargin = $this->orig_lMargin;
1806 $this->bMargin = $this->orig_rMargin;
1807 }
1808 $this->lMargin = $this->DeflMargin;
1809 $this->rMargin = $this->DefrMargin;
1810 $this->MarginCorrection = 0;
1811 $this->PageBreakTrigger = $this->h - $this->bMargin;
1812 } elseif (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
1813 $this->lMargin = $this->DefrMargin;
1814 $this->rMargin = $this->DeflMargin;
1815 $this->MarginCorrection = $this->DefrMargin - $this->DeflMargin;
1816 } else { // ODD // OR NOT MIRRORING MARGINS/FOOTERS
1817 $this->lMargin = $this->DeflMargin;
1818 $this->rMargin = $this->DefrMargin;
1819 if ($this->mirrorMargins) {
1820 $this->MarginCorrection = $this->DeflMargin - $this->DefrMargin;
1821 }
1822 }
1823 $this->x = $this->lMargin;
1824 }
1825
1826 function SetLeftMargin($margin)
1827 {
1828 //Set left margin
1829 $this->lMargin = $margin;
1830 if ($this->page > 0 and $this->x < $margin)
1831 $this->x = $margin;
1832 }
1833
1834 function SetTopMargin($margin)
1835 {
1836 //Set top margin
1837 $this->tMargin = $margin;
1838 }
1839
1840 function SetRightMargin($margin)
1841 {
1842 //Set right margin
1843 $this->rMargin = $margin;
1844 }
1845
1846 function SetAutoPageBreak($auto, $margin = 0)
1847 {
1848 //Set auto page break mode and triggering margin
1849 $this->autoPageBreak = $auto;
1850 $this->bMargin = $margin;
1851 $this->PageBreakTrigger = $this->h - $margin;
1852 }
1853
1854 function SetDisplayMode($zoom, $layout = 'continuous')
1855 {
1856 //Set display mode in viewer
1857 if ($zoom == 'fullpage' or $zoom == 'fullwidth' or $zoom == 'real' or $zoom == 'default' or ! is_string($zoom))
1858 $this->ZoomMode = $zoom;
1859 else
1860 throw new MpdfException('Incorrect zoom display mode: ' . $zoom);
1861 if ($layout == 'single' or $layout == 'continuous' or $layout == 'two' or $layout == 'twoleft' or $layout == 'tworight' or $layout == 'default')
1862 $this->LayoutMode = $layout;
1863 else
1864 throw new MpdfException('Incorrect layout display mode: ' . $layout);
1865 }
1866
1867 function SetCompression($compress)
1868 {
1869 //Set page compression
1870 if (function_exists('gzcompress'))
1871 $this->compress = $compress;
1872 else
1873 $this->compress = false;
1874 }
1875
1876 function SetTitle($title)
1877 {
1878 //Title of document // Arrives as UTF-8
1879 $this->title = $title;
1880 }
1881
1882 function SetSubject($subject)
1883 {
1884 //Subject of document
1885 $this->subject = $subject;
1886 }
1887
1888 function SetAuthor($author)
1889 {
1890 //Author of document
1891 $this->author = $author;
1892 }
1893
1894 function SetKeywords($keywords)
1895 {
1896 //Keywords of document
1897 $this->keywords = $keywords;
1898 }
1899
1900 function SetCreator($creator)
1901 {
1902 //Creator of document
1903 $this->creator = $creator;
1904 }
1905
1906 function SetAnchor2Bookmark($x)
1907 {
1908 $this->anchor2Bookmark = $x;
1909 }
1910
1911 function AliasNbPages($alias = '{nb}')
1912 {
1913 //Define an alias for total number of pages
1914 $this->aliasNbPg = $alias;
1915 }
1916
1917 function AliasNbPageGroups($alias = '{nbpg}')
1918 {
1919 //Define an alias for total number of pages in a group
1920 $this->aliasNbPgGp = $alias;
1921 }
1922
1923 function SetAlpha($alpha, $bm = 'Normal', $return = false, $mode = 'B')
1924 {
1925 // alpha: real value from 0 (transparent) to 1 (opaque)
1926 // bm: blend mode, one of the following:
1927 // Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn,
1928 // HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity
1929 // set alpha for stroking (CA) and non-stroking (ca) operations
1930 // mode determines F (fill) S (stroke) B (both)
1931 if (($this->PDFA || $this->PDFX) && $alpha != 1) {
1932 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
1933 $this->PDFAXwarnings[] = "Image opacity must be 100% (Opacity changed to 100%)";
1934 }
1935 $alpha = 1;
1936 }
1937 $a = array('BM' => '/' . $bm);
1938 if ($mode == 'F' || $mode == 'B')
1939 $a['ca'] = $alpha; // mPDF 5.7.2
1940 if ($mode == 'S' || $mode == 'B')
1941 $a['CA'] = $alpha; // mPDF 5.7.2
1942 $gs = $this->AddExtGState($a);
1943 if ($return) {
1944 return sprintf('/GS%d gs', $gs);
1945 } else {
1946 $this->_out(sprintf('/GS%d gs', $gs));
1947 }
1948 }
1949
1950 function AddExtGState($parms)
1951 {
1952 $n = count($this->extgstates);
1953 // check if graphics state already exists
1954 for ($i = 1; $i <= $n; $i++) {
1955 if (count($this->extgstates[$i]['parms']) == count($parms)) {
1956 $same = true;
1957 foreach ($this->extgstates[$i]['parms'] AS $k => $v) {
1958 if (!isset($parms[$k]) || $parms[$k] != $v) {
1959 $same = false;
1960 break;
1961 }
1962 }
1963 if ($same) {
1964 return $i;
1965 }
1966 }
1967 }
1968 $n++;
1969 $this->extgstates[$n]['parms'] = $parms;
1970 return $n;
1971 }
1972
1973 function SetVisibility($v)
1974 {
1975 if (($this->PDFA || $this->PDFX) && $this->visibility != 'visible') {
1976 $this->PDFAXwarnings[] = "Cannot set visibility to anything other than full when using PDFA or PDFX";
1977 return '';
1978 } elseif (!$this->PDFA && !$this->PDFX)
1979 $this->pdf_version = '1.5';
1980 if ($this->visibility != 'visible') {
1981 $this->_out('EMC');
1982 $this->hasOC = intval($this->hasOC);
1983 }
1984 if ($v == 'printonly') {
1985 $this->_out('/OC /OC1 BDC');
1986 $this->hasOC = ($this->hasOC | 1);
1987 } elseif ($v == 'screenonly') {
1988 $this->_out('/OC /OC2 BDC');
1989 $this->hasOC = ($this->hasOC | 2);
1990 } elseif ($v == 'hidden') {
1991 $this->_out('/OC /OC3 BDC');
1992 $this->hasOC = ($this->hasOC | 4);
1993 } elseif ($v != 'visible')
1994 throw new MpdfException('Incorrect visibility: ' . $v);
1995 $this->visibility = $v;
1996 }
1997
1998 function Open()
1999 {
2000 //Begin document
2001 if ($this->state == 0) {
2002 // Was is function _begindoc()
2003 // Start document
2004 $this->state = 1;
2005 $this->_out('%PDF-' . $this->pdf_version);
2006 $this->_out('%' . chr(226) . chr(227) . chr(207) . chr(211)); // 4 chars > 128 to show binary file
2007 }
2008 }
2009
2010 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2011 // DEPRACATED but included for backwards compatability
2012 // Depracated - can use AddPage for all
2013 function AddPages($a = '', $b = '', $c = '', $d = '', $e = '', $f = '', $g = '', $h = '', $i = '', $j = '', $k = '', $l = '', $m = '', $n = '', $o = '', $p = 0, $q = 0, $r = 0, $s = 0, $t = '', $u = '')
2014 {
2015 throw new MpdfException('function AddPages is depracated as of mPDF 6. Please use AddPage or HTML code methods instead.');
2016 }
2017
2018 function startPageNums()
2019 {
2020 throw new MpdfException('function startPageNums is depracated as of mPDF 6.');
2021 }
2022
2023 function setUnvalidatedText($a = '', $b = -1)
2024 {
2025 throw new MpdfException('function setUnvalidatedText is depracated as of mPDF 6. Please use SetWatermarkText instead.');
2026 }
2027
2028 function SetAutoFont($a)
2029 {
2030 throw new MpdfException('function SetAutoFont is depracated as of mPDF 6. Please use autoScriptToLang instead. See config.php');
2031 }
2032
2033 function Reference($a)
2034 {
2035 throw new MpdfException('function Reference is depracated as of mPDF 6. Please use IndexEntry instead.');
2036 }
2037
2038 function ReferenceSee($a, $b)
2039 {
2040 throw new MpdfException('function ReferenceSee is depracated as of mPDF 6. Please use IndexEntrySee instead.');
2041 }
2042
2043 function CreateReference($a = 1, $b = '', $c = '', $d = 3, $e = 1, $f = '', $g = 5, $h = '', $i = '', $j = false)
2044 {
2045 throw new MpdfException('function CreateReference is depracated as of mPDF 6. Please use InsertIndex instead.');
2046 }
2047
2048 function CreateIndex($a = 1, $b = '', $c = '', $d = 3, $e = 1, $f = '', $g = 5, $h = '', $i = '', $j = false)
2049 {
2050 throw new MpdfException('function CreateIndex is depracated as of mPDF 6. Please use InsertIndex instead.');
2051 }
2052
2053 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2054
2055 function Close()
2056 {
2057 // Check old Aliases - now depracated mPDF 6
2058 if (isset($this->UnvalidatedText)) {
2059 throw new MpdfException('$mpdf->UnvalidatedText is depracated as of mPDF 6. Please use $mpdf->watermarkText instead.');
2060 }
2061 if (isset($this->TopicIsUnvalidated)) {
2062 throw new MpdfException('$mpdf->TopicIsUnvalidated is depracated as of mPDF 6. Please use $mpdf->showWatermarkText instead.');
2063 }
2064 if (isset($this->AliasNbPg)) {
2065 throw new MpdfException('$mpdf->AliasNbPg is depracated as of mPDF 6. Please use $mpdf->aliasNbPg instead.');
2066 }
2067 if (isset($this->AliasNbPgGp)) {
2068 throw new MpdfException('$mpdf->AliasNbPgGp is depracated as of mPDF 6. Please use $mpdf->aliasNbPgGp instead.');
2069 }
2070 if (isset($this->BiDirectional)) {
2071 throw new MpdfException('$mpdf->BiDirectional is depracated as of mPDF 6. Please use $mpdf->biDirectional instead.');
2072 }
2073 if (isset($this->Anchor2Bookmark)) {
2074 throw new MpdfException('$mpdf->Anchor2Bookmark is depracated as of mPDF 6. Please use $mpdf->anchor2Bookmark instead.');
2075 }
2076 if (isset($this->KeepColumns)) {
2077 throw new MpdfException('$mpdf->KeepColumns is depracated as of mPDF 6. Please use $mpdf->keepColumns instead.');
2078 }
2079 if (isset($this->useOddEven)) {
2080 throw new MpdfException('$mpdf->useOddEven is depracated as of mPDF 6. Please use $mpdf->mirrorMargins instead.');
2081 }
2082 if (isset($this->useSubstitutionsMB)) {
2083 throw new MpdfException('$mpdf->useSubstitutionsMB is depracated as of mPDF 6. Please use $mpdf->useSubstitutions instead.');
2084 }
2085 if (isset($this->useLang)) {
2086 throw new MpdfException('$mpdf->useLang is depracated as of mPDF 6. Please use $mpdf->autoLangToFont instead.');
2087 }
2088 if (isset($this->useAutoFont)) {
2089 throw new MpdfException('$mpdf->useAutoFont is depracated. Please use $mpdf->autoScriptToLang instead.');
2090 }
2091
2092 if ($this->progressBar) {
2093 $this->UpdateProgressBar(2, '2', 'Closing last page');
2094 } // *PROGRESS-BAR*
2095 //Terminate document
2096 if ($this->state == 3)
2097 return;
2098 if ($this->page == 0)
2099 $this->AddPage($this->CurOrientation);
2100 if (count($this->cellBorderBuffer)) {
2101 $this->printcellbuffer();
2102 } // *TABLES*
2103 if ($this->tablebuffer) {
2104 $this->printtablebuffer();
2105 } // *TABLES*
2106 /* -- COLUMNS -- */
2107
2108 if ($this->ColActive) {
2109 $this->SetColumns(0);
2110 $this->ColActive = 0;
2111 if (count($this->columnbuffer)) {
2112 $this->printcolumnbuffer();
2113 }
2114 }
2115 /* -- END COLUMNS -- */
2116
2117 // BODY Backgrounds
2118 $s = '';
2119
2120 $s .= $this->PrintBodyBackgrounds();
2121
2122 $s .= $this->PrintPageBackgrounds();
2123 $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', "\n" . $s . "\n" . '\\1', $this->pages[$this->page]);
2124 $this->pageBackgrounds = array();
2125
2126 if ($this->visibility != 'visible')
2127 $this->SetVisibility('visible');
2128 $this->EndLayer();
2129
2130 if (!$this->tocontents || !$this->tocontents->TOCmark) { //Page footer
2131 $this->InFooter = true;
2132 $this->Footer();
2133 $this->InFooter = false;
2134 }
2135 if ($this->tocontents && ($this->tocontents->TOCmark || count($this->tocontents->m_TOC))) {
2136 $this->tocontents->insertTOC();
2137 } // *TOC*
2138 //Close page
2139 $this->_endpage();
2140
2141 //Close document
2142 $this->_enddoc();
2143 }
2144
2145 /* -- BACKGROUNDS -- */
2146
2147 function _resizeBackgroundImage($imw, $imh, $cw, $ch, $resize, $repx, $repy, $pba = array(), $size = array())
2148 {
2149 // pba is background positioning area (from CSS background-origin) may not always be set [x,y,w,h]
2150 // size is from CSS3 background-size - takes precendence over old resize
2151 // $w - absolute length or % or auto or cover | contain
2152 // $h - absolute length or % or auto or cover | contain
2153 if (isset($pba['w']))
2154 $cw = $pba['w'];
2155 if (isset($pba['h']))
2156 $ch = $pba['h'];
2157
2158 $cw = $cw * _MPDFK;
2159 $ch = $ch * _MPDFK;
2160 if (empty($size) && !$resize) {
2161 return array($imw, $imh, $repx, $repy);
2162 }
2163
2164 if (isset($size['w']) && $size['w']) {
2165 if ($size['w'] == 'contain') {
2166 // 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.
2167 // Same as resize==3
2168 $h = $imh * $cw / $imw;
2169 $w = $cw;
2170 if ($h > $ch) {
2171 $w = $w * $ch / $h;
2172 $h = $ch;
2173 }
2174 } elseif ($size['w'] == 'cover') {
2175 // 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.
2176 $h = $imh * $cw / $imw;
2177 $w = $cw;
2178 if ($h < $ch) {
2179 $w = $w * $h / $ch;
2180 $h = $ch;
2181 }
2182 } else {
2183 if (stristr($size['w'], '%')) {
2184 $size['w'] += 0;
2185 $size['w'] /= 100;
2186 $size['w'] = ($cw * $size['w']);
2187 }
2188 if (stristr($size['h'], '%')) {
2189 $size['h'] += 0;
2190 $size['h'] /= 100;
2191 $size['h'] = ($ch * $size['h']);
2192 }
2193 if ($size['w'] == 'auto' && $size['h'] == 'auto') {
2194 $w = $imw;
2195 $h = $imh;
2196 } elseif ($size['w'] == 'auto' && $size['h'] != 'auto') {
2197 $w = $imw * $size['h'] / $imh;
2198 $h = $size['h'];
2199 } elseif ($size['w'] != 'auto' && $size['h'] == 'auto') {
2200 $h = $imh * $size['w'] / $imw;
2201 $w = $size['w'];
2202 } else {
2203 $w = $size['w'];
2204 $h = $size['h'];
2205 }
2206 }
2207 return array($w, $h, $repx, $repy);
2208 } elseif ($resize == 1 && $imw > $cw) {
2209 $h = $imh * $cw / $imw;
2210 return array($cw, $h, $repx, $repy);
2211 } elseif ($resize == 2 && $imh > $ch) {
2212 $w = $imw * $ch / $imh;
2213 return array($w, $ch, $repx, $repy);
2214 } elseif ($resize == 3) {
2215 $w = $imw;
2216 $h = $imh;
2217 if ($w > $cw) {
2218 $h = $h * $cw / $w;
2219 $w = $cw;
2220 }
2221 if ($h > $ch) {
2222 $w = $w * $ch / $h;
2223 $h = $ch;
2224 }
2225 return array($w, $h, $repx, $repy);
2226 } elseif ($resize == 4) {
2227 $h = $imh * $cw / $imw;
2228 return array($cw, $h, $repx, $repy);
2229 } elseif ($resize == 5) {
2230 $w = $imw * $ch / $imh;
2231 return array($w, $ch, $repx, $repy);
2232 } elseif ($resize == 6) {
2233 return array($cw, $ch, $repx, $repy);
2234 }
2235 return array($imw, $imh, $repx, $repy);
2236 }
2237
2238 function SetBackground(&$properties, &$maxwidth)
2239 {
2240 if (isset($properties['BACKGROUND-ORIGIN']) && ($properties['BACKGROUND-ORIGIN'] == 'border-box' || $properties['BACKGROUND-ORIGIN'] == 'content-box')) {
2241 $origin = $properties['BACKGROUND-ORIGIN'];
2242 } else {
2243 $origin = 'padding-box';
2244 }
2245 if (isset($properties['BACKGROUND-SIZE'])) {
2246 if (stristr($properties['BACKGROUND-SIZE'], 'contain')) {
2247 $bsw = $bsh = 'contain';
2248 } elseif (stristr($properties['BACKGROUND-SIZE'], 'cover')) {
2249 $bsw = $bsh = 'cover';
2250 } else {
2251 $bsw = $bsh = 'auto';
2252 $sz = preg_split('/\s+/', trim($properties['BACKGROUND-SIZE']));
2253 if (count($sz) == 2) {
2254 $bsw = $sz[0];
2255 $bsh = $sz[1];
2256 } else {
2257 $bsw = $sz[0];
2258 }
2259 if (!stristr($bsw, '%') && !stristr($bsw, 'auto')) {
2260 $bsw = $this->ConvertSize($bsw, $maxwidth, $this->FontSize);
2261 }
2262 if (!stristr($bsh, '%') && !stristr($bsh, 'auto')) {
2263 $bsh = $this->ConvertSize($bsh, $maxwidth, $this->FontSize);
2264 }
2265 }
2266 $size = array('w' => $bsw, 'h' => $bsh);
2267 } else {
2268 $size = false;
2269 } // mPDF 6
2270 if (preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $properties['BACKGROUND-IMAGE'])) {
2271 return array('gradient' => $properties['BACKGROUND-IMAGE'], 'origin' => $origin, 'size' => $size);
2272 } else {
2273 $file = $properties['BACKGROUND-IMAGE'];
2274 $sizesarray = $this->Image($file, 0, 0, 0, 0, '', '', false, false, false, false, true);
2275 if (isset($sizesarray['IMAGE_ID'])) {
2276 $image_id = $sizesarray['IMAGE_ID'];
2277 $orig_w = $sizesarray['WIDTH'] * _MPDFK; // in user units i.e. mm
2278 $orig_h = $sizesarray['HEIGHT'] * _MPDFK; // (using $this->img_dpi)
2279 if (isset($properties['BACKGROUND-IMAGE-RESOLUTION'])) {
2280 if (preg_match('/from-image/i', $properties['BACKGROUND-IMAGE-RESOLUTION']) && isset($sizesarray['set-dpi']) && $sizesarray['set-dpi'] > 0) {
2281 $orig_w *= $this->img_dpi / $sizesarray['set-dpi'];
2282 $orig_h *= $this->img_dpi / $sizesarray['set-dpi'];
2283 } elseif (preg_match('/(\d+)dpi/i', $properties['BACKGROUND-IMAGE-RESOLUTION'], $m)) {
2284 $dpi = $m[1];
2285 if ($dpi > 0) {
2286 $orig_w *= $this->img_dpi / $dpi;
2287 $orig_h *= $this->img_dpi / $dpi;
2288 }
2289 }
2290 }
2291 $x_repeat = true;
2292 $y_repeat = true;
2293 if (isset($properties['BACKGROUND-REPEAT'])) {
2294 if ($properties['BACKGROUND-REPEAT'] == 'no-repeat' || $properties['BACKGROUND-REPEAT'] == 'repeat-x') {
2295 $y_repeat = false;
2296 }
2297 if ($properties['BACKGROUND-REPEAT'] == 'no-repeat' || $properties['BACKGROUND-REPEAT'] == 'repeat-y') {
2298 $x_repeat = false;
2299 }
2300 }
2301 $x_pos = 0;
2302 $y_pos = 0;
2303 if (isset($properties['BACKGROUND-POSITION'])) {
2304 $ppos = preg_split('/\s+/', $properties['BACKGROUND-POSITION']);
2305 $x_pos = $ppos[0];
2306 $y_pos = $ppos[1];
2307 if (!stristr($x_pos, '%')) {
2308 $x_pos = $this->ConvertSize($x_pos, $maxwidth, $this->FontSize);
2309 }
2310 if (!stristr($y_pos, '%')) {
2311 $y_pos = $this->ConvertSize($y_pos, $maxwidth, $this->FontSize);
2312 }
2313 }
2314 if (isset($properties['BACKGROUND-IMAGE-RESIZE'])) {
2315 $resize = $properties['BACKGROUND-IMAGE-RESIZE'];
2316 } else {
2317 $resize = 0;
2318 }
2319 if (isset($properties['BACKGROUND-IMAGE-OPACITY'])) {
2320 $opacity = $properties['BACKGROUND-IMAGE-OPACITY'];
2321 } else {
2322 $opacity = 1;
2323 }
2324 return array('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);
2325 }
2326 }
2327 return false;
2328 }
2329
2330 /* -- END BACKGROUNDS -- */
2331
2332 function PrintBodyBackgrounds()
2333 {
2334 $s = '';
2335 $clx = 0;
2336 $cly = 0;
2337 $clw = $this->w;
2338 $clh = $this->h;
2339 // If using bleed and trim margins in paged media
2340 if ($this->pageDim[$this->page]['outer_width_LR'] || $this->pageDim[$this->page]['outer_width_TB']) {
2341 $clx = $this->pageDim[$this->page]['outer_width_LR'] - $this->pageDim[$this->page]['bleedMargin'];
2342 $cly = $this->pageDim[$this->page]['outer_width_TB'] - $this->pageDim[$this->page]['bleedMargin'];
2343 $clw = $this->w - 2 * $clx;
2344 $clh = $this->h - 2 * $cly;
2345 }
2346
2347 if ($this->bodyBackgroundColor) {
2348 $s .= 'q ' . $this->SetFColor($this->bodyBackgroundColor, true) . "\n";
2349 if ($this->bodyBackgroundColor[0] == 5) { // RGBa
2350 $s .= $this->SetAlpha(ord($this->bodyBackgroundColor[4]) / 100, 'Normal', true, 'F') . "\n";
2351 } elseif ($this->bodyBackgroundColor[0] == 6) { // CMYKa
2352 $s .= $this->SetAlpha(ord($this->bodyBackgroundColor[5]) / 100, 'Normal', true, 'F') . "\n";
2353 }
2354 $s .= sprintf('%.3F %.3F %.3F %.3F re f Q', ($clx * _MPDFK), ($cly * _MPDFK), $clw * _MPDFK, $clh * _MPDFK) . "\n";
2355 }
2356
2357 /* -- BACKGROUNDS -- */
2358 if ($this->bodyBackgroundGradient) {
2359 $g = $this->grad->parseBackgroundGradient($this->bodyBackgroundGradient);
2360 if ($g) {
2361 $s .= $this->grad->Gradient($clx, $cly, $clw, $clh, (isset($g['gradtype']) ? $g['gradtype'] : null), $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true);
2362 }
2363 }
2364 if ($this->bodyBackgroundImage) {
2365 if (isset($this->bodyBackgroundImage['gradient']) && $this->bodyBackgroundImage['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $this->bodyBackgroundImage['gradient'])) {
2366 $g = $this->grad->parseMozGradient($this->bodyBackgroundImage['gradient']);
2367 if ($g) {
2368 $s .= $this->grad->Gradient($clx, $cly, $clw, $clh, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true);
2369 }
2370 } elseif ($this->bodyBackgroundImage['image_id']) { // Background pattern
2371 $n = count($this->patterns) + 1;
2372 // If using resize, uses TrimBox (not including the bleed)
2373 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']);
2374
2375 $this->patterns[$n] = array('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']);
2376 if (($this->bodyBackgroundImage['opacity'] > 0 || $this->bodyBackgroundImage['opacity'] === '0') && $this->bodyBackgroundImage['opacity'] < 1) {
2377 $opac = $this->SetAlpha($this->bodyBackgroundImage['opacity'], 'Normal', true);
2378 } else {
2379 $opac = '';
2380 }
2381 $s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, ($clx * _MPDFK), ($cly * _MPDFK), $clw * _MPDFK, $clh * _MPDFK) . "\n";
2382 }
2383 }
2384 /* -- END BACKGROUNDS -- */
2385 return $s;
2386 }
2387
2388 function _setClippingPath($clx, $cly, $clw, $clh)
2389 {
2390 $s = ' q 0 w '; // Line width=0
2391 $s .= sprintf('%.3F %.3F m ', ($clx) * _MPDFK, ($this->h - ($cly)) * _MPDFK); // start point TL before the arc
2392 $s .= sprintf('%.3F %.3F l ', ($clx) * _MPDFK, ($this->h - ($cly + $clh)) * _MPDFK); // line to BL
2393 $s .= sprintf('%.3F %.3F l ', ($clx + $clw) * _MPDFK, ($this->h - ($cly + $clh)) * _MPDFK); // line to BR
2394 $s .= sprintf('%.3F %.3F l ', ($clx + $clw) * _MPDFK, ($this->h - ($cly)) * _MPDFK); // line to TR
2395 $s .= sprintf('%.3F %.3F l ', ($clx) * _MPDFK, ($this->h - ($cly)) * _MPDFK); // line to TL
2396 $s .= ' W n '; // Ends path no-op & Sets the clipping path
2397 return $s;
2398 }
2399
2400 function PrintPageBackgrounds($adjustmenty = 0)
2401 {
2402 $s = '';
2403
2404 ksort($this->pageBackgrounds);
2405 foreach ($this->pageBackgrounds AS $bl => $pbs) {
2406 foreach ($pbs AS $pb) {
2407 if ((!isset($pb['image_id']) && !isset($pb['gradient'])) || isset($pb['shadowonly'])) { // Background colour or boxshadow
2408 if ($pb['z-index'] > 0) {
2409 $this->current_layer = $pb['z-index'];
2410 $s .= "\n" . '/OCBZ-index /ZI' . $pb['z-index'] . ' BDC' . "\n";
2411 }
2412
2413 if ($pb['visibility'] != 'visible') {
2414 if ($pb['visibility'] == 'printonly')
2415 $s .= '/OC /OC1 BDC' . "\n";
2416 elseif ($pb['visibility'] == 'screenonly')
2417 $s .= '/OC /OC2 BDC' . "\n";
2418 elseif ($pb['visibility'] == 'hidden')
2419 $s .= '/OC /OC3 BDC' . "\n";
2420 }
2421 // Box shadow
2422 if (isset($pb['shadow']) && $pb['shadow']) {
2423 $s .= $pb['shadow'] . "\n";
2424 }
2425 if (isset($pb['clippath']) && $pb['clippath']) {
2426 $s .= $pb['clippath'] . "\n";
2427 }
2428 $s .= 'q ' . $this->SetFColor($pb['col'], true) . "\n";
2429 if ($pb['col'][0] == 5) { // RGBa
2430 $s .= $this->SetAlpha(ord($pb['col'][4]) / 100, 'Normal', true, 'F') . "\n";
2431 } elseif ($pb['col'][0] == 6) { // CMYKa
2432 $s .= $this->SetAlpha(ord($pb['col'][5]) / 100, 'Normal', true, 'F') . "\n";
2433 }
2434 $s .= sprintf('%.3F %.3F %.3F %.3F re f Q', $pb['x'] * _MPDFK, ($this->h - $pb['y']) * _MPDFK, $pb['w'] * _MPDFK, -$pb['h'] * _MPDFK) . "\n";
2435 if (isset($pb['clippath']) && $pb['clippath']) {
2436 $s .= 'Q' . "\n";
2437 }
2438 if ($pb['visibility'] != 'visible')
2439 $s .= 'EMC' . "\n";
2440
2441 if ($pb['z-index'] > 0) {
2442 $s .= "\n" . 'EMCBZ-index' . "\n";
2443 $this->current_layer = 0;
2444 }
2445 }
2446 }
2447 /* -- BACKGROUNDS -- */
2448 foreach ($pbs AS $pb) {
2449 if ((isset($pb['gradient']) && $pb['gradient']) || (isset($pb['image_id']) && $pb['image_id'])) {
2450 if ($pb['z-index'] > 0) {
2451 $this->current_layer = $pb['z-index'];
2452 $s .= "\n" . '/OCGZ-index /ZI' . $pb['z-index'] . ' BDC' . "\n";
2453 }
2454 if ($pb['visibility'] != 'visible') {
2455 if ($pb['visibility'] == 'printonly')
2456 $s .= '/OC /OC1 BDC' . "\n";
2457 elseif ($pb['visibility'] == 'screenonly')
2458 $s .= '/OC /OC2 BDC' . "\n";
2459 elseif ($pb['visibility'] == 'hidden')
2460 $s .= '/OC /OC3 BDC' . "\n";
2461 }
2462 }
2463 if (isset($pb['gradient']) && $pb['gradient']) {
2464 if (isset($pb['clippath']) && $pb['clippath']) {
2465 $s .= $pb['clippath'] . "\n";
2466 }
2467 $s .= $this->grad->Gradient($pb['x'], $pb['y'], $pb['w'], $pb['h'], $pb['gradtype'], $pb['stops'], $pb['colorspace'], $pb['coords'], $pb['extend'], true);
2468 if (isset($pb['clippath']) && $pb['clippath']) {
2469 $s .= 'Q' . "\n";
2470 }
2471 } elseif (isset($pb['image_id']) && $pb['image_id']) { // Background Image
2472 $pb['y'] -= $adjustmenty;
2473 $pb['h'] += $adjustmenty;
2474 $n = count($this->patterns) + 1;
2475 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']);
2476 $this->patterns[$n] = array('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']);
2477 $x = $pb['x'] * _MPDFK;
2478 $y = ($this->h - $pb['y']) * _MPDFK;
2479 $w = $pb['w'] * _MPDFK;
2480 $h = -$pb['h'] * _MPDFK;
2481 if (isset($pb['clippath']) && $pb['clippath']) {
2482 $s .= $pb['clippath'] . "\n";
2483 }
2484 if ($this->writingHTMLfooter || $this->writingHTMLheader) { // Write each (tiles) image rather than use as a pattern
2485 $iw = $pb['orig_w'] / _MPDFK;
2486 $ih = $pb['orig_h'] / _MPDFK;
2487
2488 $w = $pb['w'];
2489 $h = $pb['h'];
2490 $x0 = $pb['x'];
2491 $y0 = $pb['y'];
2492
2493 if (isset($pb['bpa']) && $pb['bpa']) {
2494 $w = $pb['bpa']['w'];
2495 $h = $pb['bpa']['h'];
2496 $x0 = $pb['bpa']['x'];
2497 $y0 = $pb['bpa']['y'];
2498 }
2499
2500 if (isset($pb['size']['w']) && $pb['size']['w']) {
2501 $size = $pb['size'];
2502
2503 if ($size['w'] == 'contain') {
2504 // 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.
2505 // Same as resize==3
2506 $ih = $ih * $pb['bpa']['w'] / $iw;
2507 $iw = $pb['bpa']['w'];
2508 if ($ih > $pb['bpa']['h']) {
2509 $iw = $iw * $pb['bpa']['h'] / $ih;
2510 $ih = $pb['bpa']['h'];
2511 }
2512 } elseif ($size['w'] == 'cover') {
2513 // 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.
2514 $ih = $ih * $pb['bpa']['w'] / $iw;
2515 $iw = $pb['bpa']['w'];
2516 if ($ih < $pb['bpa']['h']) {
2517 $iw = $iw * $ih / $pb['bpa']['h'];
2518 $ih = $pb['bpa']['h'];
2519 }
2520 } else {
2521 if (stristr($size['w'], '%')) {
2522 $size['w'] += 0;
2523 $size['w'] /= 100;
2524 $size['w'] = ($pb['bpa']['w'] * $size['w']);
2525 }
2526 if (stristr($size['h'], '%')) {
2527 $size['h'] += 0;
2528 $size['h'] /= 100;
2529 $size['h'] = ($pb['bpa']['h'] * $size['h']);
2530 }
2531 if ($size['w'] == 'auto' && $size['h'] == 'auto') {
2532 $iw = $iw;
2533 $ih = $ih;
2534 } elseif ($size['w'] == 'auto' && $size['h'] != 'auto') {
2535 $iw = $iw * $size['h'] / $ih;
2536 $ih = $size['h'];
2537 } elseif ($size['w'] != 'auto' && $size['h'] == 'auto') {
2538 $ih = $ih * $size['w'] / $iw;
2539 $iw = $size['w'];
2540 } else {
2541 $iw = $size['w'];
2542 $ih = $size['h'];
2543 }
2544 }
2545 }
2546
2547 // Number to repeat
2548 if ($pb['x_repeat']) {
2549 $nx = ceil($pb['w'] / $iw) + 1;
2550 } else {
2551 $nx = 1;
2552 }
2553 if ($pb['y_repeat']) {
2554 $ny = ceil($pb['h'] / $ih) + 1;
2555 } else {
2556 $ny = 1;
2557 }
2558
2559 $x_pos = $pb['x_pos'];
2560 if (stristr($x_pos, '%')) {
2561 $x_pos += 0;
2562 $x_pos /= 100;
2563 $x_pos = ($pb['bpa']['w'] * $x_pos) - ($iw * $x_pos);
2564 }
2565 $y_pos = $pb['y_pos'];
2566 if (stristr($y_pos, '%')) {
2567 $y_pos += 0;
2568 $y_pos /= 100;
2569 $y_pos = ($pb['bpa']['h'] * $y_pos) - ($ih * $y_pos);
2570 }
2571 if ($nx > 1) {
2572 while ($x_pos > ($pb['x'] - $pb['bpa']['x'])) {
2573 $x_pos -= $iw;
2574 }
2575 }
2576 if ($ny > 1) {
2577 while ($y_pos > ($pb['y'] - $pb['bpa']['y'])) {
2578 $y_pos -= $ih;
2579 }
2580 }
2581 for ($xi = 0; $xi < $nx; $xi++) {
2582 for ($yi = 0; $yi < $ny; $yi++) {
2583 $x = $x0 + $x_pos + ($iw * $xi);
2584 $y = $y0 + $y_pos + ($ih * $yi);
2585 if ($pb['opacity'] > 0 && $pb['opacity'] < 1) {
2586 $opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
2587 } else {
2588 $opac = '';
2589 }
2590 $s .= sprintf("q %s %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $opac, $iw * _MPDFK, $ih * _MPDFK, $x * _MPDFK, ($this->h - ($y + $ih)) * _MPDFK, $pb['image_id']) . "\n";
2591 }
2592 }
2593 } else {
2594 if (($pb['opacity'] > 0 || $pb['opacity'] === '0') && $pb['opacity'] < 1) {
2595 $opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
2596 } else {
2597 $opac = '';
2598 }
2599 $s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $x, $y, $w, $h) . "\n";
2600 }
2601 if (isset($pb['clippath']) && $pb['clippath']) {
2602 $s .= 'Q' . "\n";
2603 }
2604 }
2605 if ((isset($pb['gradient']) && $pb['gradient']) || (isset($pb['image_id']) && $pb['image_id'])) {
2606 if ($pb['visibility'] != 'visible')
2607 $s .= 'EMC' . "\n";
2608
2609 if ($pb['z-index'] > 0) {
2610 $s .= "\n" . 'EMCGZ-index' . "\n";
2611 $this->current_layer = 0;
2612 }
2613 }
2614 }
2615 /* -- END BACKGROUNDS -- */
2616 }
2617 return $s;
2618 }
2619
2620 function PrintTableBackgrounds($adjustmenty = 0)
2621 {
2622 $s = '';
2623 /* -- BACKGROUNDS -- */
2624 ksort($this->tableBackgrounds);
2625 foreach ($this->tableBackgrounds AS $bl => $pbs) {
2626 foreach ($pbs AS $pb) {
2627 if ((!isset($pb['gradient']) || !$pb['gradient']) && (!isset($pb['image_id']) || !$pb['image_id'])) {
2628 $s .= 'q ' . $this->SetFColor($pb['col'], true) . "\n";
2629 if ($pb['col'][0] == 5) { // RGBa
2630 $s .= $this->SetAlpha(ord($pb['col'][4]) / 100, 'Normal', true, 'F') . "\n";
2631 } elseif ($pb['col'][0] == 6) { // CMYKa
2632 $s .= $this->SetAlpha(ord($pb['col'][5]) / 100, 'Normal', true, 'F') . "\n";
2633 }
2634 $s .= sprintf('%.3F %.3F %.3F %.3F re %s Q', $pb['x'] * _MPDFK, ($this->h - $pb['y']) * _MPDFK, $pb['w'] * _MPDFK, -$pb['h'] * _MPDFK, 'f') . "\n";
2635 }
2636 if (isset($pb['gradient']) && $pb['gradient']) {
2637 if (isset($pb['clippath']) && $pb['clippath']) {
2638 $s .= $pb['clippath'] . "\n";
2639 }
2640 $s .= $this->grad->Gradient($pb['x'], $pb['y'], $pb['w'], $pb['h'], $pb['gradtype'], $pb['stops'], $pb['colorspace'], $pb['coords'], $pb['extend'], true);
2641 if (isset($pb['clippath']) && $pb['clippath']) {
2642 $s .= 'Q' . "\n";
2643 }
2644 }
2645 if (isset($pb['image_id']) && $pb['image_id']) { // Background pattern
2646 $pb['y'] -= $adjustmenty;
2647 $pb['h'] += $adjustmenty;
2648 $n = count($this->patterns) + 1;
2649 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']);
2650 $this->patterns[$n] = array('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']);
2651 $x = $pb['x'] * _MPDFK;
2652 $y = ($this->h - $pb['y']) * _MPDFK;
2653 $w = $pb['w'] * _MPDFK;
2654 $h = -$pb['h'] * _MPDFK;
2655
2656 // mPDF 5.7.3
2657 if (($this->writingHTMLfooter || $this->writingHTMLheader) && (!isset($pb['clippath']) || $pb['clippath'] == '')) {
2658 // Set clipping path
2659 $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);
2660 }
2661
2662 if (isset($pb['clippath']) && $pb['clippath']) {
2663 $s .= $pb['clippath'] . "\n";
2664 }
2665
2666 // mPDF 5.7.3
2667 if ($this->writingHTMLfooter || $this->writingHTMLheader) { // Write each (tiles) image rather than use as a pattern
2668 $iw = $pb['orig_w'] / _MPDFK;
2669 $ih = $pb['orig_h'] / _MPDFK;
2670
2671 $w = $pb['w'];
2672 $h = $pb['h'];
2673 $x0 = $pb['x'];
2674 $y0 = $pb['y'];
2675
2676 if (isset($pb['bpa']) && $pb['bpa']) {
2677 $w = $pb['bpa']['w'];
2678 $h = $pb['bpa']['h'];
2679 $x0 = $pb['bpa']['x'];
2680 $y0 = $pb['bpa']['y'];
2681 }
2682 // At present 'bpa' (background page area) is not set for tablebackgrounds - only pagebackgrounds
2683 // For now, just set it as:
2684 else {
2685 $pb['bpa'] = array('x' => $x0, 'y' => $y0, 'w' => $w, 'h' => $h);
2686 }
2687
2688 if (isset($pb['size']['w']) && $pb['size']['w']) {
2689 $size = $pb['size'];
2690
2691 if ($size['w'] == 'contain') {
2692 // 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.
2693 // Same as resize==3
2694 $ih = $ih * $pb['bpa']['w'] / $iw;
2695 $iw = $pb['bpa']['w'];
2696 if ($ih > $pb['bpa']['h']) {
2697 $iw = $iw * $pb['bpa']['h'] / $ih;
2698 $ih = $pb['bpa']['h'];
2699 }
2700 } elseif ($size['w'] == 'cover') {
2701 // 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.
2702 $ih = $ih * $pb['bpa']['w'] / $iw;
2703 $iw = $pb['bpa']['w'];
2704 if ($ih < $pb['bpa']['h']) {
2705 $iw = $iw * $ih / $pb['bpa']['h'];
2706 $ih = $pb['bpa']['h'];
2707 }
2708 } else {
2709 if (stristr($size['w'], '%')) {
2710 $size['w'] += 0;
2711 $size['w'] /= 100;
2712 $size['w'] = ($pb['bpa']['w'] * $size['w']);
2713 }
2714 if (stristr($size['h'], '%')) {
2715 $size['h'] += 0;
2716 $size['h'] /= 100;
2717 $size['h'] = ($pb['bpa']['h'] * $size['h']);
2718 }
2719 if ($size['w'] == 'auto' && $size['h'] == 'auto') {
2720 $iw = $iw;
2721 $ih = $ih;
2722 } elseif ($size['w'] == 'auto' && $size['h'] != 'auto') {
2723 $iw = $iw * $size['h'] / $ih;
2724 $ih = $size['h'];
2725 } elseif ($size['w'] != 'auto' && $size['h'] == 'auto') {
2726 $ih = $ih * $size['w'] / $iw;
2727 $iw = $size['w'];
2728 } else {
2729 $iw = $size['w'];
2730 $ih = $size['h'];
2731 }
2732 }
2733 }
2734
2735 // Number to repeat
2736 if (isset($pb['x_repeat']) && $pb['x_repeat']) {
2737 $nx = ceil($pb['w'] / $iw) + 1;
2738 } else {
2739 $nx = 1;
2740 }
2741 if (isset($pb['y_repeat']) && $pb['y_repeat']) {
2742 $ny = ceil($pb['h'] / $ih) + 1;
2743 } else {
2744 $ny = 1;
2745 }
2746
2747 $x_pos = $pb['x_pos'];
2748 if (stristr($x_pos, '%')) {
2749 $x_pos += 0;
2750 $x_pos /= 100;
2751 $x_pos = ($pb['bpa']['w'] * $x_pos) - ($iw * $x_pos);
2752 }
2753 $y_pos = $pb['y_pos'];
2754 if (stristr($y_pos, '%')) {
2755 $y_pos += 0;
2756 $y_pos /= 100;
2757 $y_pos = ($pb['bpa']['h'] * $y_pos) - ($ih * $y_pos);
2758 }
2759 if ($nx > 1) {
2760 while ($x_pos > ($pb['x'] - $pb['bpa']['x'])) {
2761 $x_pos -= $iw;
2762 }
2763 }
2764 if ($ny > 1) {
2765 while ($y_pos > ($pb['y'] - $pb['bpa']['y'])) {
2766 $y_pos -= $ih;
2767 }
2768 }
2769 for ($xi = 0; $xi < $nx; $xi++) {
2770 for ($yi = 0; $yi < $ny; $yi++) {
2771 $x = $x0 + $x_pos + ($iw * $xi);
2772 $y = $y0 + $y_pos + ($ih * $yi);
2773 if ($pb['opacity'] > 0 && $pb['opacity'] < 1) {
2774 $opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
2775 } else {
2776 $opac = '';
2777 }
2778 $s .= sprintf("q %s %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $opac, $iw * _MPDFK, $ih * _MPDFK, $x * _MPDFK, ($this->h - ($y + $ih)) * _MPDFK, $pb['image_id']) . "\n";
2779 }
2780 }
2781 } else {
2782 if (($pb['opacity'] > 0 || $pb['opacity'] === '0') && $pb['opacity'] < 1) {
2783 $opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
2784 } else {
2785 $opac = '';
2786 }
2787 $s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $x, $y, $w, $h) . "\n";
2788 }
2789
2790 if (isset($pb['clippath']) && $pb['clippath']) {
2791 $s .= 'Q' . "\n";
2792 }
2793 }
2794 }
2795 }
2796 /* -- END BACKGROUNDS -- */
2797 return $s;
2798 }
2799
2800 function BeginLayer($id)
2801 {
2802 if ($this->current_layer > 0)
2803 $this->EndLayer();
2804 if ($id < 1) {
2805 return false;
2806 }
2807 if (!isset($this->layers[$id])) {
2808 $this->layers[$id] = array('name' => 'Layer ' . ($id));
2809 if (($this->PDFA || $this->PDFX)) {
2810 $this->PDFAXwarnings[] = "Cannot use layers when using PDFA or PDFX";
2811 return '';
2812 } elseif (!$this->PDFA && !$this->PDFX) {
2813 $this->pdf_version = '1.5';
2814 }
2815 }
2816 $this->current_layer = $id;
2817 $this->_out('/OCZ-index /ZI' . $id . ' BDC');
2818
2819 $this->pageoutput[$this->page] = array();
2820 }
2821
2822 function EndLayer()
2823 {
2824 if ($this->current_layer > 0) {
2825 $this->_out('EMCZ-index');
2826 $this->current_layer = 0;
2827 }
2828 }
2829
2830 function AddPageByArray($a)
2831 {
2832 if (!is_array($a)) {
2833 $a = array();
2834 }
2835 $orientation = (isset($a['orientation']) ? $a['orientation'] : '');
2836 $condition = (isset($a['condition']) ? $a['condition'] : (isset($a['type']) ? $a['type'] : ''));
2837 $resetpagenum = (isset($a['resetpagenum']) ? $a['resetpagenum'] : '');
2838 $pagenumstyle = (isset($a['pagenumstyle']) ? $a['pagenumstyle'] : '');
2839 $suppress = (isset($a['suppress']) ? $a['suppress'] : '');
2840 $mgl = (isset($a['mgl']) ? $a['mgl'] : (isset($a['margin-left']) ? $a['margin-left'] : ''));
2841 $mgr = (isset($a['mgr']) ? $a['mgr'] : (isset($a['margin-right']) ? $a['margin-right'] : ''));
2842 $mgt = (isset($a['mgt']) ? $a['mgt'] : (isset($a['margin-top']) ? $a['margin-top'] : ''));
2843 $mgb = (isset($a['mgb']) ? $a['mgb'] : (isset($a['margin-bottom']) ? $a['margin-bottom'] : ''));
2844 $mgh = (isset($a['mgh']) ? $a['mgh'] : (isset($a['margin-header']) ? $a['margin-header'] : ''));
2845 $mgf = (isset($a['mgf']) ? $a['mgf'] : (isset($a['margin-footer']) ? $a['margin-footer'] : ''));
2846 $ohname = (isset($a['ohname']) ? $a['ohname'] : (isset($a['odd-header-name']) ? $a['odd-header-name'] : ''));
2847 $ehname = (isset($a['ehname']) ? $a['ehname'] : (isset($a['even-header-name']) ? $a['even-header-name'] : ''));
2848 $ofname = (isset($a['ofname']) ? $a['ofname'] : (isset($a['odd-footer-name']) ? $a['odd-footer-name'] : ''));
2849 $efname = (isset($a['efname']) ? $a['efname'] : (isset($a['even-footer-name']) ? $a['even-footer-name'] : ''));
2850 $ohvalue = (isset($a['ohvalue']) ? $a['ohvalue'] : (isset($a['odd-header-value']) ? $a['odd-header-value'] : 0));
2851 $ehvalue = (isset($a['ehvalue']) ? $a['ehvalue'] : (isset($a['even-header-value']) ? $a['even-header-value'] : 0));
2852 $ofvalue = (isset($a['ofvalue']) ? $a['ofvalue'] : (isset($a['odd-footer-value']) ? $a['odd-footer-value'] : 0));
2853 $efvalue = (isset($a['efvalue']) ? $a['efvalue'] : (isset($a['even-footer-value']) ? $a['even-footer-value'] : 0));
2854 $pagesel = (isset($a['pagesel']) ? $a['pagesel'] : (isset($a['pageselector']) ? $a['pageselector'] : ''));
2855 $newformat = (isset($a['newformat']) ? $a['newformat'] : (isset($a['sheet-size']) ? $a['sheet-size'] : ''));
2856
2857 $this->AddPage($orientation, $condition, $resetpagenum, $pagenumstyle, $suppress, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $newformat);
2858 }
2859
2860 // mPDF 6 pagebreaktype
2861 function _preForcedPagebreak($pagebreaktype)
2862 {
2863 if ($pagebreaktype == 'cloneall') {
2864 // Close any open block tags
2865 $arr = array();
2866 $ai = 0;
2867 for ($b = $this->blklvl; $b > 0; $b--) {
2868 $this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
2869 }
2870 if ($this->blklvl == 0 && !empty($this->textbuffer)) { //Output previously buffered content
2871 $this->printbuffer($this->textbuffer, 1);
2872 $this->textbuffer = array();
2873 }
2874 } elseif ($pagebreaktype == 'clonebycss') {
2875 // Close open block tags whilst box-decoration-break==clone
2876 $arr = array();
2877 $ai = 0;
2878 for ($b = $this->blklvl; $b > 0; $b--) {
2879 if (isset($this->blk[$b]['box_decoration_break']) && $this->blk[$b]['box_decoration_break'] == 'clone') {
2880 $this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
2881 } else {
2882 if ($b == $this->blklvl && !empty($this->textbuffer)) { //Output previously buffered content
2883 $this->printbuffer($this->textbuffer, 1);
2884 $this->textbuffer = array();
2885 }
2886 break;
2887 }
2888 }
2889 } elseif (!empty($this->textbuffer)) { //Output previously buffered content
2890 $this->printbuffer($this->textbuffer, 1);
2891 $this->textbuffer = array();
2892 }
2893 }
2894
2895 // mPDF 6 pagebreaktype
2896 function _postForcedPagebreak($pagebreaktype, $startpage, $save_blk, $save_blklvl)
2897 {
2898 if ($pagebreaktype == 'cloneall') {
2899 $this->blk = array();
2900 $this->blk[0] = $save_blk[0];
2901 // Re-open block tags
2902 $this->blklvl = 0;
2903 $arr = array();
2904 $i = 0;
2905 for ($b = 1; $b <= $save_blklvl; $b++) {
2906 $this->tag->OpenTag($save_blk[$b]['tag'], $save_blk[$b]['attr'], $arr, $i);
2907 }
2908 } elseif ($pagebreaktype == 'clonebycss') {
2909 $this->blk = array();
2910 $this->blk[0] = $save_blk[0];
2911 // Don't re-open tags for lowest level elements - so need to do some adjustments
2912 for ($b = 1; $b <= $this->blklvl; $b++) {
2913 $this->blk[$b] = $save_blk[$b];
2914 $this->blk[$b]['startpage'] = 0;
2915 $this->blk[$b]['y0'] = $this->y; // ?? $this->tMargin
2916 if (($this->page - $startpage) % 2) {
2917 if (isset($this->blk[$b]['x0'])) {
2918 $this->blk[$b]['x0'] += $this->MarginCorrection;
2919 } else {
2920 $this->blk[$b]['x0'] = $this->MarginCorrection;
2921 }
2922 }
2923 //for Float DIV
2924 $this->blk[$b]['marginCorrected'][$this->page] = true;
2925 }
2926
2927 // Re-open block tags for any that have box_decoration_break==clone
2928 $arr = array();
2929 $i = 0;
2930 for ($b = $this->blklvl + 1; $b <= $save_blklvl; $b++) {
2931 if ($b < $this->blklvl) {
2932 $this->lastblocklevelchange = -1;
2933 }
2934 $this->tag->OpenTag($save_blk[$b]['tag'], $save_blk[$b]['attr'], $arr, $i);
2935 }
2936 if ($this->blk[$this->blklvl]['box_decoration_break'] != 'clone') {
2937 $this->lastblocklevelchange = -1;
2938 }
2939 } else {
2940 $this->lastblocklevelchange = -1;
2941 }
2942 }
2943
2944 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 = '')
2945 {
2946
2947 /* -- CSS-FLOAT -- */
2948 // Float DIV
2949 // Cannot do with columns on, or if any change in page orientation/margins etc.
2950 // If next page already exists - i.e background /headers and footers already written
2951 if ($this->state > 0 && $this->page < count($this->pages)) {
2952 $bak_cml = $this->cMarginL;
2953 $bak_cmr = $this->cMarginR;
2954 $bak_dw = $this->divwidth;
2955 // Paint Div Border if necessary
2956 if ($this->blklvl > 0) {
2957 $save_tr = $this->table_rotate; // *TABLES*
2958 $this->table_rotate = 0; // *TABLES*
2959 if ($this->y == $this->blk[$this->blklvl]['y0']) {
2960 $this->blk[$this->blklvl]['startpage'] ++;
2961 }
2962 if (($this->y > $this->blk[$this->blklvl]['y0']) || $this->flowingBlockAttr['is_table']) {
2963 $toplvl = $this->blklvl;
2964 } else {
2965 $toplvl = $this->blklvl - 1;
2966 }
2967 $sy = $this->y;
2968 for ($bl = 1; $bl <= $toplvl; $bl++) {
2969 $this->PaintDivBB('pagebottom', 0, $bl);
2970 }
2971 $this->y = $sy;
2972 $this->table_rotate = $save_tr; // *TABLES*
2973 }
2974 $s = $this->PrintPageBackgrounds();
2975
2976 // Writes after the marker so not overwritten later by page background etc.
2977 $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
2978 $this->pageBackgrounds = array();
2979 $family = $this->FontFamily;
2980 $style = $this->FontStyle;
2981 $size = $this->FontSizePt;
2982 $lw = $this->LineWidth;
2983 $dc = $this->DrawColor;
2984 $fc = $this->FillColor;
2985 $tc = $this->TextColor;
2986 $cf = $this->ColorFlag;
2987
2988 $this->printfloatbuffer();
2989
2990 //Move to next page
2991 $this->page++;
2992 $this->ResetMargins();
2993 $this->SetAutoPageBreak($this->autoPageBreak, $this->bMargin);
2994 $this->x = $this->lMargin;
2995 $this->y = $this->tMargin;
2996 $this->FontFamily = '';
2997 $this->_out('2 J');
2998 $this->LineWidth = $lw;
2999 $this->_out(sprintf('%.3F w', $lw * _MPDFK));
3000 if ($family)
3001 $this->SetFont($family, $style, $size, true, true);
3002 $this->DrawColor = $dc;
3003 if ($dc != $this->defDrawColor)
3004 $this->_out($dc);
3005 $this->FillColor = $fc;
3006 if ($fc != $this->defFillColor)
3007 $this->_out($fc);
3008 $this->TextColor = $tc;
3009 $this->ColorFlag = $cf;
3010 for ($bl = 1; $bl <= $this->blklvl; $bl++) {
3011 $this->blk[$bl]['y0'] = $this->y;
3012 // Don't correct more than once for background DIV containing a Float
3013 if (!isset($this->blk[$bl]['marginCorrected'][$this->page])) {
3014 $this->blk[$bl]['x0'] += $this->MarginCorrection;
3015 }
3016 $this->blk[$bl]['marginCorrected'][$this->page] = true;
3017 }
3018 $this->cMarginL = $bak_cml;
3019 $this->cMarginR = $bak_cmr;
3020 $this->divwidth = $bak_dw;
3021 return '';
3022 }
3023 /* -- END CSS-FLOAT -- */
3024
3025 //Start a new page
3026 if ($this->state == 0)
3027 $this->Open();
3028
3029 $bak_cml = $this->cMarginL;
3030 $bak_cmr = $this->cMarginR;
3031 $bak_dw = $this->divwidth;
3032
3033
3034 $bak_lh = $this->lineheight;
3035
3036 $orientation = substr(strtoupper($orientation), 0, 1);
3037 $condition = strtoupper($condition);
3038
3039
3040 if ($condition == 'E') { // only adds new page if needed to create an Even page
3041 if (!$this->mirrorMargins || ($this->page) % 2 == 0) {
3042 return false;
3043 }
3044 } elseif ($condition == 'O') { // only adds new page if needed to create an Odd page
3045 if (!$this->mirrorMargins || ($this->page) % 2 == 1) {
3046 return false;
3047 }
3048 } elseif ($condition == 'NEXT-EVEN') { // always adds at least one new page to create an Even page
3049 if (!$this->mirrorMargins) {
3050 $condition = '';
3051 } else {
3052 if ($pagesel) {
3053 $pbch = $pagesel;
3054 $pagesel = '';
3055 } // *CSS-PAGE*
3056 else {
3057 $pbch = false;
3058 } // *CSS-PAGE*
3059 $this->AddPage($this->CurOrientation, 'O');
3060 $this->extrapagebreak = true; // mPDF 6 pagebreaktype
3061 if ($pbch) {
3062 $pagesel = $pbch;
3063 } // *CSS-PAGE*
3064 $condition = '';
3065 }
3066 } elseif ($condition == 'NEXT-ODD') { // always adds at least one new page to create an Odd page
3067 if (!$this->mirrorMargins) {
3068 $condition = '';
3069 } else {
3070 if ($pagesel) {
3071 $pbch = $pagesel;
3072 $pagesel = '';
3073 } // *CSS-PAGE*
3074 else {
3075 $pbch = false;
3076 } // *CSS-PAGE*
3077 $this->AddPage($this->CurOrientation, 'E');
3078 $this->extrapagebreak = true; // mPDF 6 pagebreaktype
3079 if ($pbch) {
3080 $pagesel = $pbch;
3081 } // *CSS-PAGE*
3082 $condition = '';
3083 }
3084 }
3085
3086
3087 if ($resetpagenum || $pagenumstyle || $suppress) {
3088 $this->PageNumSubstitutions[] = array('from' => ($this->page + 1), 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress);
3089 }
3090
3091
3092 $save_tr = $this->table_rotate; // *TABLES*
3093 $this->table_rotate = 0; // *TABLES*
3094 $save_kwt = $this->kwt;
3095 $this->kwt = 0;
3096 $save_layer = $this->current_layer;
3097 $save_vis = $this->visibility;
3098
3099 if ($this->visibility != 'visible')
3100 $this->SetVisibility('visible');
3101 $this->EndLayer();
3102
3103 // Paint Div Border if necessary
3104 //PAINTS BACKGROUND COLOUR OR BORDERS for DIV - DISABLED FOR COLUMNS (cf. AcceptPageBreak) AT PRESENT in ->PaintDivBB
3105 if (!$this->ColActive && $this->blklvl > 0) {
3106 if (isset($this->blk[$this->blklvl]['y0']) && $this->y == $this->blk[$this->blklvl]['y0'] && !$this->extrapagebreak) { // mPDF 6 pagebreaktype
3107 if (isset($this->blk[$this->blklvl]['startpage'])) {
3108 $this->blk[$this->blklvl]['startpage'] ++;
3109 } else {
3110 $this->blk[$this->blklvl]['startpage'] = 1;
3111 }
3112 }
3113 if ((isset($this->blk[$this->blklvl]['y0']) && $this->y > $this->blk[$this->blklvl]['y0']) || $this->flowingBlockAttr['is_table'] || $this->extrapagebreak) {
3114 $toplvl = $this->blklvl;
3115 } // mPDF 6 pagebreaktype
3116 else {
3117 $toplvl = $this->blklvl - 1;
3118 }
3119 $sy = $this->y;
3120 for ($bl = 1; $bl <= $toplvl; $bl++) {
3121
3122 if (isset($this->blk[$bl]['z-index']) && $this->blk[$bl]['z-index'] > 0) {
3123 $this->BeginLayer($this->blk[$bl]['z-index']);
3124 }
3125 if (isset($this->blk[$bl]['visibility']) && $this->blk[$bl]['visibility'] && $this->blk[$bl]['visibility'] != 'visible') {
3126 $this->SetVisibility($this->blk[$bl]['visibility']);
3127 }
3128 $this->PaintDivBB('pagebottom', 0, $bl);
3129 }
3130 $this->y = $sy;
3131 // RESET block y0 and x0 - see below
3132 }
3133 $this->extrapagebreak = false; // mPDF 6 pagebreaktype
3134
3135 if ($this->visibility != 'visible')
3136 $this->SetVisibility('visible');
3137 $this->EndLayer();
3138
3139 // BODY Backgrounds
3140 if ($this->page > 0) {
3141 $s = '';
3142 $s .= $this->PrintBodyBackgrounds();
3143
3144 $s .= $this->PrintPageBackgrounds();
3145 $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', "\n" . $s . "\n" . '\\1', $this->pages[$this->page]);
3146 $this->pageBackgrounds = array();
3147 }
3148
3149 $save_kt = $this->keep_block_together;
3150 $this->keep_block_together = 0;
3151
3152 $save_cols = false;
3153 /* -- COLUMNS -- */
3154 if ($this->ColActive) {
3155 $save_cols = true;
3156 $save_nbcol = $this->NbCol; // other values of gap and vAlign will not change by setting Columns off
3157 $this->SetColumns(0);
3158 }
3159 /* -- END COLUMNS -- */
3160
3161
3162 $family = $this->FontFamily;
3163 $style = $this->FontStyle;
3164 $size = $this->FontSizePt;
3165 $this->ColumnAdjust = true; // enables column height adjustment for the page
3166 $lw = $this->LineWidth;
3167 $dc = $this->DrawColor;
3168 $fc = $this->FillColor;
3169 $tc = $this->TextColor;
3170 $cf = $this->ColorFlag;
3171 if ($this->page > 0) {
3172 //Page footer
3173 $this->InFooter = true;
3174
3175 $this->Reset();
3176 $this->pageoutput[$this->page] = array();
3177
3178 $this->Footer();
3179 //Close page
3180 $this->_endpage();
3181 }
3182
3183
3184 //Start new page
3185 $this->_beginpage($orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $newformat);
3186 if ($this->docTemplate) {
3187 $pagecount = $this->SetSourceFile($this->docTemplate);
3188 if (($this->page - $this->docTemplateStart) > $pagecount) {
3189 if ($this->docTemplateContinue) {
3190 $tplIdx = $this->ImportPage($pagecount);
3191 $this->UseTemplate($tplIdx);
3192 }
3193 } else {
3194 $tplIdx = $this->ImportPage(($this->page - $this->docTemplateStart));
3195 $this->UseTemplate($tplIdx);
3196 }
3197 }
3198 if ($this->pageTemplate) {
3199 $this->UseTemplate($this->pageTemplate);
3200 }
3201
3202 // Tiling Patterns
3203 $this->_out('___PAGE___START' . $this->uniqstr);
3204 $this->_out('___BACKGROUND___PATTERNS' . $this->uniqstr);
3205 $this->_out('___HEADER___MARKER' . $this->uniqstr);
3206 $this->pageBackgrounds = array();
3207
3208 //Set line cap style to square
3209 $this->SetLineCap(2);
3210 //Set line width
3211 $this->LineWidth = $lw;
3212 $this->_out(sprintf('%.3F w', $lw * _MPDFK));
3213 //Set font
3214 if ($family)
3215 $this->SetFont($family, $style, $size, true, true); // forces write
3216
3217 //Set colors
3218 $this->DrawColor = $dc;
3219 if ($dc != $this->defDrawColor)
3220 $this->_out($dc);
3221 $this->FillColor = $fc;
3222 if ($fc != $this->defFillColor)
3223 $this->_out($fc);
3224 $this->TextColor = $tc;
3225 $this->ColorFlag = $cf;
3226
3227 //Page header
3228 $this->Header();
3229
3230 //Restore line width
3231 if ($this->LineWidth != $lw) {
3232 $this->LineWidth = $lw;
3233 $this->_out(sprintf('%.3F w', $lw * _MPDFK));
3234 }
3235 //Restore font
3236 if ($family)
3237 $this->SetFont($family, $style, $size, true, true); // forces write
3238
3239 //Restore colors
3240 if ($this->DrawColor != $dc) {
3241 $this->DrawColor = $dc;
3242 $this->_out($dc);
3243 }
3244 if ($this->FillColor != $fc) {
3245 $this->FillColor = $fc;
3246 $this->_out($fc);
3247 }
3248 $this->TextColor = $tc;
3249 $this->ColorFlag = $cf;
3250 $this->InFooter = false;
3251
3252 if ($save_layer > 0)
3253 $this->BeginLayer($save_layer);
3254
3255 if ($save_vis != 'visible')
3256 $this->SetVisibility($save_vis);
3257
3258 /* -- COLUMNS -- */
3259 if ($save_cols) {
3260 // Restore columns
3261 $this->SetColumns($save_nbcol, $this->colvAlign, $this->ColGap);
3262 }
3263 if ($this->ColActive) {
3264 $this->SetCol(0);
3265 }
3266 /* -- END COLUMNS -- */
3267
3268
3269 //RESET BLOCK BORDER TOP
3270 if (!$this->ColActive) {
3271 for ($bl = 1; $bl <= $this->blklvl; $bl++) {
3272 $this->blk[$bl]['y0'] = $this->y;
3273 if (isset($this->blk[$bl]['x0'])) {
3274 $this->blk[$bl]['x0'] += $this->MarginCorrection;
3275 } else {
3276 $this->blk[$bl]['x0'] = $this->MarginCorrection;
3277 }
3278 // Added mPDF 3.0 Float DIV
3279 $this->blk[$bl]['marginCorrected'][$this->page] = true;
3280 }
3281 }
3282
3283
3284 $this->table_rotate = $save_tr; // *TABLES*
3285 $this->kwt = $save_kwt;
3286
3287 $this->keep_block_together = $save_kt;
3288
3289 $this->cMarginL = $bak_cml;
3290 $this->cMarginR = $bak_cmr;
3291 $this->divwidth = $bak_dw;
3292
3293 $this->lineheight = $bak_lh;
3294 }
3295
3296 function PageNo()
3297 {
3298 //Get current page number
3299 return $this->page;
3300 }
3301
3302 function AddSpotColorsFromFile($file)
3303 {
3304 $colors = @file($file);
3305 if (!$colors) {
3306 throw new MpdfException("Cannot load spot colors file - " . $file);
3307 }
3308 foreach ($colors AS $sc) {
3309 list($name, $c, $m, $y, $k) = preg_split("/\t/", $sc);
3310 $c = intval($c);
3311 $m = intval($m);
3312 $y = intval($y);
3313 $k = intval($k);
3314 $this->AddSpotColor($name, $c, $m, $y, $k);
3315 }
3316 }
3317
3318 function AddSpotColor($name, $c, $m, $y, $k)
3319 {
3320 $name = strtoupper(trim($name));
3321 if (!isset($this->spotColors[$name])) {
3322 $i = count($this->spotColors) + 1;
3323 $this->spotColors[$name] = array('i' => $i, 'c' => $c, 'm' => $m, 'y' => $y, 'k' => $k);
3324 $this->spotColorIDs[$i] = $name;
3325 }
3326 }
3327
3328 function SetColor($col, $type = '')
3329 {
3330 $out = '';
3331 if (!$col) {
3332 return '';
3333 } // mPDF 6
3334 if ($col[0] == 3 || $col[0] == 5) { // RGB / RGBa
3335 $out = sprintf('%.3F %.3F %.3F rg', ord($col[1]) / 255, ord($col[2]) / 255, ord($col[3]) / 255);
3336 } elseif ($col[0] == 1) { // GRAYSCALE
3337 $out = sprintf('%.3F g', ord($col[1]) / 255);
3338 } elseif ($col[0] == 2) { // SPOT COLOR
3339 $out = sprintf('/CS%d cs %.3F scn', ord($col[1]), ord($col[2]) / 100);
3340 } elseif ($col[0] == 4 || $col[0] == 6) { // CMYK / CMYKa
3341 $out = sprintf('%.3F %.3F %.3F %.3F k', ord($col[1]) / 100, ord($col[2]) / 100, ord($col[3]) / 100, ord($col[4]) / 100);
3342 }
3343 if ($type == 'Draw') {
3344 $out = strtoupper($out);
3345 } // e.g. rg => RG
3346 elseif ($type == 'CodeOnly') {
3347 $out = preg_replace('/\s(rg|g|k)/', '', $out);
3348 }
3349 return $out;
3350 }
3351
3352 function SetDColor($col, $return = false)
3353 {
3354 $out = $this->SetColor($col, 'Draw');
3355 if ($return) {
3356 return $out;
3357 }
3358 if ($out == '') {
3359 return '';
3360 }
3361 $this->DrawColor = $out;
3362 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['DrawColor']) && $this->pageoutput[$this->page]['DrawColor'] != $this->DrawColor) || !isset($this->pageoutput[$this->page]['DrawColor']))) {
3363 $this->_out($this->DrawColor);
3364 }
3365 $this->pageoutput[$this->page]['DrawColor'] = $this->DrawColor;
3366 }
3367
3368 function SetFColor($col, $return = false)
3369 {
3370 $out = $this->SetColor($col, 'Fill');
3371 if ($return) {
3372 return $out;
3373 }
3374 if ($out == '') {
3375 return '';
3376 }
3377 $this->FillColor = $out;
3378 $this->ColorFlag = ($out != $this->TextColor);
3379 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['FillColor']) && $this->pageoutput[$this->page]['FillColor'] != $this->FillColor) || !isset($this->pageoutput[$this->page]['FillColor']))) {
3380 $this->_out($this->FillColor);
3381 }
3382 $this->pageoutput[$this->page]['FillColor'] = $this->FillColor;
3383 }
3384
3385 function SetTColor($col, $return = false)
3386 {
3387 $out = $this->SetColor($col, 'Text');
3388 if ($return) {
3389 return $out;
3390 }
3391 if ($out == '') {
3392 return '';
3393 }
3394 $this->TextColor = $out;
3395 $this->ColorFlag = ($this->FillColor != $out);
3396 }
3397
3398 function SetDrawColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
3399 {
3400 //Set color for all stroking operations
3401 $col = array();
3402 if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) {
3403 $col = $this->ConvertColor($r);
3404 } elseif ($col4 == -1) {
3405 $col = $this->ConvertColor('rgb(' . $r . ',' . $g . ',' . $b . ')');
3406 } else {
3407 $col = $this->ConvertColor('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')');
3408 }
3409 $out = $this->SetDColor($col, $return);
3410 return $out;
3411 }
3412
3413 function SetFillColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
3414 {
3415 //Set color for all filling operations
3416 $col = array();
3417 if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) {
3418 $col = $this->ConvertColor($r);
3419 } elseif ($col4 == -1) {
3420 $col = $this->ConvertColor('rgb(' . $r . ',' . $g . ',' . $b . ')');
3421 } else {
3422 $col = $this->ConvertColor('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')');
3423 }
3424 $out = $this->SetFColor($col, $return);
3425 return $out;
3426 }
3427
3428 function SetTextColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
3429 {
3430 //Set color for text
3431 $col = array();
3432 if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) {
3433 $col = $this->ConvertColor($r);
3434 } elseif ($col4 == -1) {
3435 $col = $this->ConvertColor('rgb(' . $r . ',' . $g . ',' . $b . ')');
3436 } else {
3437 $col = $this->ConvertColor('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')');
3438 }
3439 $out = $this->SetTColor($col, $return);
3440 return $out;
3441 }
3442
3443 function _getCharWidth(&$cw, $u, $isdef = true)
3444 {
3445 $w = 0;
3446 if ($u == 0) {
3447 $w = false;
3448 } elseif (isset($cw[$u * 2 + 1])) {
3449 $w = (ord($cw[$u * 2]) << 8) + ord($cw[$u * 2 + 1]);
3450 }
3451 if ($w == 65535) {
3452 return 0;
3453 } elseif ($w) {
3454 return $w;
3455 } elseif ($isdef) {
3456 return false;
3457 } else {
3458 return 0;
3459 }
3460 }
3461
3462 function _charDefined(&$cw, $u)
3463 {
3464 $w = 0;
3465 if ($u == 0) {
3466 return false;
3467 }
3468 if (isset($cw[$u * 2 + 1])) {
3469 $w = (ord($cw[$u * 2]) << 8) + ord($cw[$u * 2 + 1]);
3470 }
3471 if ($w) {
3472 return true;
3473 } else {
3474 return false;
3475 }
3476 }
3477
3478 function GetCharWidthCore($c)
3479 {
3480 //Get width of a single character in the current Core font
3481 $c = (string) $c;
3482 $w = 0;
3483 // Soft Hyphens chr(173)
3484 if ($c == chr(173) && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
3485 return 0;
3486 } elseif (($this->textvar & FC_SMALLCAPS) && isset($this->upperCase[ord($c)])) { // mPDF 5.7.1
3487 $charw = $this->CurrentFont['cw'][chr($this->upperCase[ord($c)])];
3488 if ($charw !== false) {
3489 $charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
3490 $w+=$charw;
3491 }
3492 } elseif (isset($this->CurrentFont['cw'][$c])) {
3493 $w += $this->CurrentFont['cw'][$c];
3494 } elseif (isset($this->CurrentFont['cw'][ord($c)])) {
3495 $w += $this->CurrentFont['cw'][ord($c)];
3496 }
3497 $w *= ($this->FontSize / 1000);
3498 if ($this->minwSpacing || $this->fixedlSpacing) {
3499 if ($c == ' ')
3500 $nb_spaces = 1;
3501 else
3502 $nb_spaces = 0;
3503 $w += $this->fixedlSpacing + ($nb_spaces * $this->minwSpacing);
3504 }
3505 return ($w);
3506 }
3507
3508 function GetCharWidthNonCore($c, $addSubset = true)
3509 {
3510 //Get width of a single character in the current Non-Core font
3511 $c = (string) $c;
3512 $w = 0;
3513 $unicode = $this->UTF8StringToArray($c, $addSubset);
3514 $char = $unicode[0];
3515 /* -- CJK-FONTS -- */
3516 if ($this->CurrentFont['type'] == 'Type0') { // CJK Adobe fonts
3517 if ($char == 173) {
3518 return 0;
3519 } // Soft Hyphens
3520 elseif (isset($this->CurrentFont['cw'][$char])) {
3521 $w+=$this->CurrentFont['cw'][$char];
3522 } elseif (isset($this->CurrentFont['MissingWidth'])) {
3523 $w += $this->CurrentFont['MissingWidth'];
3524 } else {
3525 $w += 500;
3526 }
3527 } else {
3528 /* -- END CJK-FONTS -- */
3529 if ($char == 173) {
3530 return 0;
3531 } // Soft Hyphens
3532 elseif (($this->textvar & FC_SMALLCAPS) && isset($this->upperCase[$char])) { // mPDF 5.7.1
3533 $charw = $this->_getCharWidth($this->CurrentFont['cw'], $this->upperCase[$char]);
3534 if ($charw !== false) {
3535 $charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
3536 $w+=$charw;
3537 } elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
3538 $w += $this->CurrentFont['desc']['MissingWidth'];
3539 } elseif (isset($this->CurrentFont['MissingWidth'])) {
3540 $w += $this->CurrentFont['MissingWidth'];
3541 } else {
3542 $w += 500;
3543 }
3544 } else {
3545 $charw = $this->_getCharWidth($this->CurrentFont['cw'], $char);
3546 if ($charw !== false) {
3547 $w+=$charw;
3548 } elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
3549 $w += $this->CurrentFont['desc']['MissingWidth'];
3550 } elseif (isset($this->CurrentFont['MissingWidth'])) {
3551 $w += $this->CurrentFont['MissingWidth'];
3552 } else {
3553 $w += 500;
3554 }
3555 }
3556 } // *CJK-FONTS*
3557 $w *= ($this->FontSize / 1000);
3558 if ($this->minwSpacing || $this->fixedlSpacing) {
3559 if ($c == ' ')
3560 $nb_spaces = 1;
3561 else
3562 $nb_spaces = 0;
3563 $w += $this->fixedlSpacing + ($nb_spaces * $this->minwSpacing);
3564 }
3565 return ($w);
3566 }
3567
3568 function GetCharWidth($c, $addSubset = true)
3569 {
3570 if (!$this->usingCoreFont) {
3571 return $this->GetCharWidthNonCore($c, $addSubset);
3572 } else {
3573 return $this->GetCharWidthCore($c);
3574 }
3575 }
3576
3577 function GetStringWidth($s, $addSubset = true, $OTLdata = false, $textvar = 0, $includeKashida = false)
3578 { // mPDF 5.7.1
3579 //Get width of a string in the current font
3580 $s = (string) $s;
3581 $cw = &$this->CurrentFont['cw'];
3582 $w = 0;
3583 $kerning = 0;
3584 $lastchar = 0;
3585 $nb_carac = 0;
3586 $nb_spaces = 0;
3587 $kashida = 0;
3588 // mPDF ITERATION
3589 if ($this->iterationCounter)
3590 $s = preg_replace('/{iteration ([a-zA-Z0-9_]+)}/', '\\1', $s);
3591 if (!$this->usingCoreFont) {
3592 $discards = substr_count($s, "\xc2\xad"); // mPDF 6 soft hyphens [U+00AD]
3593 $unicode = $this->UTF8StringToArray($s, $addSubset);
3594 if ($this->minwSpacing || $this->fixedlSpacing) {
3595 $nb_spaces = mb_substr_count($s, ' ', $this->mb_enc);
3596 $nb_carac = count($unicode) - $discards; // mPDF 6
3597 // mPDF 5.7.1
3598 // Use GPOS OTL
3599 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
3600 if (isset($OTLdata['group']) && $OTLdata['group']) {
3601 $nb_carac -= substr_count($OTLdata['group'], 'M');
3602 }
3603 }
3604 }
3605 /* -- CJK-FONTS -- */
3606 if ($this->CurrentFont['type'] == 'Type0') { // CJK Adobe fonts
3607 foreach ($unicode as $char) {
3608 if ($char == 0x00AD) {
3609 continue;
3610 } // mPDF 6 soft hyphens [U+00AD]
3611 if (isset($cw[$char])) {
3612 $w+=$cw[$char];
3613 } elseif (isset($this->CurrentFont['MissingWidth'])) {
3614 $w += $this->CurrentFont['MissingWidth'];
3615 } else {
3616 $w += 500;
3617 }
3618 }
3619 } else {
3620 /* -- END CJK-FONTS -- */
3621 foreach ($unicode as $i => $char) {
3622 if ($char == 0x00AD) {
3623 continue;
3624 } // mPDF 6 soft hyphens [U+00AD]
3625 if (($textvar & FC_SMALLCAPS) && isset($this->upperCase[$char])) {
3626 $charw = $this->_getCharWidth($cw, $this->upperCase[$char]);
3627 if ($charw !== false) {
3628 $charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
3629 $w+=$charw;
3630 } elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
3631 $w += $this->CurrentFont['desc']['MissingWidth'];
3632 } elseif (isset($this->CurrentFont['MissingWidth'])) {
3633 $w += $this->CurrentFont['MissingWidth'];
3634 } else {
3635 $w += 500;
3636 }
3637 } else {
3638 $charw = $this->_getCharWidth($cw, $char);
3639 if ($charw !== false) {
3640 $w+=$charw;
3641 } elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
3642 $w += $this->CurrentFont['desc']['MissingWidth'];
3643 } elseif (isset($this->CurrentFont['MissingWidth'])) {
3644 $w += $this->CurrentFont['MissingWidth'];
3645 } else {
3646 $w += 500;
3647 }
3648 // mPDF 5.7.1
3649 // Use GPOS OTL
3650 // ...GetStringWidth...
3651 if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && !empty($OTLdata)) {
3652 if (isset($OTLdata['GPOSinfo'][$i]['wDir']) && $OTLdata['GPOSinfo'][$i]['wDir'] == 'RTL') {
3653 if (isset($OTLdata['GPOSinfo'][$i]['XAdvanceR']) && $OTLdata['GPOSinfo'][$i]['XAdvanceR']) {
3654 $w += $OTLdata['GPOSinfo'][$i]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
3655 }
3656 } else {
3657 if (isset($OTLdata['GPOSinfo'][$i]['XAdvanceL']) && $OTLdata['GPOSinfo'][$i]['XAdvanceL']) {
3658 $w += $OTLdata['GPOSinfo'][$i]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
3659 }
3660 }
3661 // Kashida from GPOS
3662 // Kashida is set as an absolute length value (already set as a proportion based on useKashida %)
3663 if ($includeKashida && isset($OTLdata['GPOSinfo'][$i]['kashida_space']) && $OTLdata['GPOSinfo'][$i]['kashida_space']) {
3664 $kashida += $OTLdata['GPOSinfo'][$i]['kashida_space'];
3665 }
3666 }
3667 if (($textvar & FC_KERNING) && $lastchar) {
3668 if (isset($this->CurrentFont['kerninfo'][$lastchar][$char])) {
3669 $kerning += $this->CurrentFont['kerninfo'][$lastchar][$char];
3670 }
3671 }
3672 $lastchar = $char;
3673 }
3674 }
3675 } // *CJK-FONTS*
3676 } else {
3677 if ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
3678 $s = str_replace(chr(173), '', $s);
3679 }
3680 $nb_carac = $l = strlen($s);
3681 if ($this->minwSpacing || $this->fixedlSpacing) {
3682 $nb_spaces = substr_count($s, ' ');
3683 }
3684 for ($i = 0; $i < $l; $i++) {
3685 if (($textvar & FC_SMALLCAPS) && isset($this->upperCase[ord($s[$i])])) { // mPDF 5.7.1
3686 $charw = $cw[chr($this->upperCase[ord($s[$i])])];
3687 if ($charw !== false) {
3688 $charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
3689 $w+=$charw;
3690 }
3691 } elseif (isset($cw[$s[$i]])) {
3692 $w += $cw[$s[$i]];
3693 } elseif (isset($cw[ord($s[$i])])) {
3694 $w += $cw[ord($s[$i])];
3695 }
3696 if (($textvar & FC_KERNING) && $i > 0) { // mPDF 5.7.1
3697 if (isset($this->CurrentFont['kerninfo'][$s[($i - 1)]][$s[$i]])) {
3698 $kerning += $this->CurrentFont['kerninfo'][$s[($i - 1)]][$s[$i]];
3699 }
3700 }
3701 }
3702 }
3703 unset($cw);
3704 if ($textvar & FC_KERNING) {
3705 $w += $kerning;
3706 } // mPDF 5.7.1
3707 $w *= ($this->FontSize / 1000);
3708 $w += (($nb_carac + $nb_spaces) * $this->fixedlSpacing) + ($nb_spaces * $this->minwSpacing);
3709 $w += $kashida / _MPDFK;
3710
3711 return ($w);
3712 }
3713
3714 function SetLineWidth($width)
3715 {
3716 //Set line width
3717 $this->LineWidth = $width;
3718 $lwout = (sprintf('%.3F w', $width * _MPDFK));
3719 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineWidth']) && $this->pageoutput[$this->page]['LineWidth'] != $lwout) || !isset($this->pageoutput[$this->page]['LineWidth']))) {
3720 $this->_out($lwout);
3721 }
3722 $this->pageoutput[$this->page]['LineWidth'] = $lwout;
3723 }
3724
3725 function Line($x1, $y1, $x2, $y2)
3726 {
3727 //Draw a line
3728 $this->_out(sprintf('%.3F %.3F m %.3F %.3F l S', $x1 * _MPDFK, ($this->h - $y1) * _MPDFK, $x2 * _MPDFK, ($this->h - $y2) * _MPDFK));
3729 }
3730
3731 function Arrow($x1, $y1, $x2, $y2, $headsize = 3, $fill = 'B', $angle = 25)
3732 {
3733 //F == fill //S == stroke //B == stroke and fill
3734 // angle = splay of arrowhead - 1 - 89 degrees
3735 if ($fill == 'F')
3736 $fill = 'f';
3737 elseif ($fill == 'FD' or $fill == 'DF' or $fill == 'B')
3738 $fill = 'B';
3739 else
3740 $fill = 'S';
3741 $a = atan2(($y2 - $y1), ($x2 - $x1));
3742 $b = $a + deg2rad($angle);
3743 $c = $a - deg2rad($angle);
3744 $x3 = $x2 - ($headsize * cos($b));
3745 $y3 = $this->h - ($y2 - ($headsize * sin($b)));
3746 $x4 = $x2 - ($headsize * cos($c));
3747 $y4 = $this->h - ($y2 - ($headsize * sin($c)));
3748
3749 $x5 = $x3 - ($x3 - $x4) / 2; // mid point of base of arrowhead - to join arrow line to
3750 $y5 = $y3 - ($y3 - $y4) / 2;
3751
3752 $s = '';
3753 $s.=sprintf('%.3F %.3F m %.3F %.3F l S', $x1 * _MPDFK, ($this->h - $y1) * _MPDFK, $x5 * _MPDFK, $y5 * _MPDFK);
3754 $this->_out($s);
3755
3756 $s = '';
3757 $s.=sprintf('%.3F %.3F m %.3F %.3F l %.3F %.3F l %.3F %.3F l %.3F %.3F l ', $x5 * _MPDFK, $y5 * _MPDFK, $x3 * _MPDFK, $y3 * _MPDFK, $x2 * _MPDFK, ($this->h - $y2) * _MPDFK, $x4 * _MPDFK, $y4 * _MPDFK, $x5 * _MPDFK, $y5 * _MPDFK);
3758 $s.=$fill;
3759 $this->_out($s);
3760 }
3761
3762 function Rect($x, $y, $w, $h, $style = '')
3763 {
3764 //Draw a rectangle
3765 if ($style == 'F')
3766 $op = 'f';
3767 elseif ($style == 'FD' or $style == 'DF')
3768 $op = 'B';
3769 else
3770 $op = 'S';
3771 $this->_out(sprintf('%.3F %.3F %.3F %.3F re %s', $x * _MPDFK, ($this->h - $y) * _MPDFK, $w * _MPDFK, -$h * _MPDFK, $op));
3772 }
3773
3774 function AddFont($family, $style = '')
3775 {
3776 if (empty($family)) {
3777 return;
3778 }
3779 $family = strtolower($family);
3780 $style = strtoupper($style);
3781 $style = str_replace('U', '', $style);
3782 if ($style == 'IB')
3783 $style = 'BI';
3784 $fontkey = $family . $style;
3785 // check if the font has been already added
3786 if (isset($this->fonts[$fontkey])) {
3787 return;
3788 }
3789
3790 /* -- CJK-FONTS -- */
3791 if (in_array($family, $this->available_CJK_fonts)) {
3792 if (empty($this->Big5_widths)) {
3793 require(_MPDF_PATH . 'includes/CJKdata.php');
3794 }
3795 $this->AddCJKFont($family); // don't need to add style
3796 return;
3797 }
3798 /* -- END CJK-FONTS -- */
3799
3800 if ($this->usingCoreFont) {
3801 throw new MpdfException("mPDF Error - problem with Font management");
3802 }
3803
3804 $stylekey = $style;
3805 if (!$style) {
3806 $stylekey = 'R';
3807 }
3808
3809 if (!isset($this->fontdata[$family][$stylekey]) || !$this->fontdata[$family][$stylekey]) {
3810 throw new MpdfException('mPDF Error - Font is not supported - ' . $family . ' ' . $style);
3811 }
3812
3813 $name = '';
3814 $originalsize = 0;
3815 $sip = false;
3816 $smp = false;
3817 $useOTL = 0; // mPDF 5.7.1
3818 $fontmetrics = ''; // mPDF 6
3819 $haskerninfo = false;
3820 $haskernGPOS = false;
3821 $hassmallcapsGSUB = false;
3822 $BMPselected = false;
3823 $GSUBScriptLang = array();
3824 $GSUBFeatures = array();
3825 $GSUBLookups = array();
3826 $GPOSScriptLang = array();
3827 $GPOSFeatures = array();
3828 $GPOSLookups = array();
3829 if (file_exists(_MPDF_TTFONTDATAPATH . $fontkey . '.mtx.php')) {
3830 include(_MPDF_TTFONTDATAPATH . $fontkey . '.mtx.php');
3831 }
3832
3833 $ttffile = '';
3834 if (defined('_MPDF_SYSTEM_TTFONTS')) {
3835 $ttffile = _MPDF_SYSTEM_TTFONTS . $this->fontdata[$family][$stylekey];
3836 if (!file_exists($ttffile)) {
3837 $ttffile = '';
3838 }
3839 }
3840 if (!$ttffile) {
3841 $ttffile = _MPDF_TTFONTPATH . $this->fontdata[$family][$stylekey];
3842 if (!file_exists($ttffile)) {
3843 throw new MpdfException("mPDF Error - cannot find TTF TrueType font file - " . $ttffile);
3844 }
3845 }
3846 $ttfstat = stat($ttffile);
3847
3848 if (isset($this->fontdata[$family]['TTCfontID'][$stylekey])) {
3849 $TTCfontID = $this->fontdata[$family]['TTCfontID'][$stylekey];
3850 } else {
3851 $TTCfontID = 0;
3852 }
3853
3854 $BMPonly = false;
3855 if (in_array($family, $this->BMPonly)) {
3856 $BMPonly = true;
3857 }
3858 $regenerate = false;
3859 if ($BMPonly && !$BMPselected) {
3860 $regenerate = true;
3861 } elseif (!$BMPonly && $BMPselected) {
3862 $regenerate = true;
3863 }
3864 // mPDF 5.7.1
3865 if (isset($this->fontdata[$family]['useOTL']) && $this->fontdata[$family]['useOTL'] && $useOTL != $this->fontdata[$family]['useOTL']) {
3866 $regenerate = true;
3867 $useOTL = $this->fontdata[$family]['useOTL'];
3868 } elseif ((!isset($this->fontdata[$family]['useOTL']) || !$this->fontdata[$family]['useOTL']) && $useOTL) {
3869 $regenerate = true;
3870 $useOTL = 0;
3871 }
3872 if (_FONT_DESCRIPTOR != $fontmetrics) {
3873 $regenerate = true;
3874 } // mPDF 6
3875 if (!isset($name) || $originalsize != $ttfstat['size'] || $regenerate) {
3876 if (!class_exists('TTFontFile', false)) {
3877 include(_MPDF_PATH . 'classes/ttfontsuni.php');
3878 }
3879 $ttf = new TTFontFile();
3880 $ttf->getMetrics($ttffile, $fontkey, $TTCfontID, $this->debugfonts, $BMPonly, $useOTL); // mPDF 5.7.1
3881 $cw = $ttf->charWidths;
3882 $kerninfo = $ttf->kerninfo;
3883 if ($kerninfo)
3884 $haskerninfo = true;
3885 $haskernGPOS = $ttf->haskernGPOS;
3886 $hassmallcapsGSUB = $ttf->hassmallcapsGSUB;
3887 $name = preg_replace('/[ ()]/', '', $ttf->fullName);
3888 $sip = $ttf->sipset;
3889 $smp = $ttf->smpset;
3890 // mPDF 6
3891 $GSUBScriptLang = $ttf->GSUBScriptLang;
3892 $GSUBFeatures = $ttf->GSUBFeatures;
3893 $GSUBLookups = $ttf->GSUBLookups;
3894 $rtlPUAstr = $ttf->rtlPUAstr;
3895 $GPOSScriptLang = $ttf->GPOSScriptLang;
3896 $GPOSFeatures = $ttf->GPOSFeatures;
3897 $GPOSLookups = $ttf->GPOSLookups;
3898 $glyphIDtoUni = $ttf->glyphIDtoUni;
3899
3900
3901 $desc = array(
3902 'CapHeight' => round($ttf->capHeight),
3903 'XHeight' => round($ttf->xHeight),
3904 'FontBBox' => '[' . round($ttf->bbox[0]) . " " . round($ttf->bbox[1]) . " " . round($ttf->bbox[2]) . " " . round($ttf->bbox[3]) . ']', /* FontBBox from head table */
3905
3906 /* 'MaxWidth' => round($ttf->advanceWidthMax), // AdvanceWidthMax from hhea table NB ArialUnicode MS = 31990 ! */
3907 'Flags' => $ttf->flags,
3908 'Ascent' => round($ttf->ascent),
3909 'Descent' => round($ttf->descent),
3910 'Leading' => round($ttf->lineGap),
3911 'ItalicAngle' => $ttf->italicAngle,
3912 'StemV' => round($ttf->stemV),
3913 'MissingWidth' => round($ttf->defaultWidth)
3914 );
3915 $panose = '';
3916 if (count($ttf->panose)) {
3917 $panoseArray = array_merge(array($ttf->sFamilyClass, $ttf->sFamilySubClass), $ttf->panose);
3918 foreach ($panoseArray as $value)
3919 $panose .= ' ' . dechex($value);
3920 }
3921 $unitsPerEm = round($ttf->unitsPerEm);
3922 $up = round($ttf->underlinePosition);
3923 $ut = round($ttf->underlineThickness);
3924 $strp = round($ttf->strikeoutPosition); // mPDF 6
3925 $strs = round($ttf->strikeoutSize); // mPDF 6
3926 $originalsize = $ttfstat['size'] + 0;
3927 $type = 'TTF';
3928 //Generate metrics .php file
3929 $s = '<?php' . "\n";
3930 $s.='$name=\'' . $name . "';\n";
3931 $s.='$type=\'' . $type . "';\n";
3932 $s.='$desc=' . var_export($desc, true) . ";\n";
3933 $s.='$unitsPerEm=' . $unitsPerEm . ";\n";
3934 $s.='$up=' . $up . ";\n";
3935 $s.='$ut=' . $ut . ";\n";
3936 $s.='$strp=' . $strp . ";\n"; // mPDF 6
3937 $s.='$strs=' . $strs . ";\n"; // mPDF 6
3938 $s.='$ttffile=\'' . $ttffile . "';\n";
3939 $s.='$TTCfontID=\'' . $TTCfontID . "';\n";
3940 $s.='$originalsize=' . $originalsize . ";\n";
3941 if ($sip)
3942 $s.='$sip=true;' . "\n";
3943 else
3944 $s.='$sip=false;' . "\n";
3945 if ($smp)
3946 $s.='$smp=true;' . "\n";
3947 else
3948 $s.='$smp=false;' . "\n";
3949 if ($BMPonly)
3950 $s.='$BMPselected=true;' . "\n";
3951 else
3952 $s.='$BMPselected=false;' . "\n";
3953 $s.='$fontkey=\'' . $fontkey . "';\n";
3954 $s.='$panose=\'' . $panose . "';\n";
3955 if ($haskerninfo)
3956 $s.='$haskerninfo=true;' . "\n";
3957 else
3958 $s.='$haskerninfo=false;' . "\n";
3959 if ($haskernGPOS)
3960 $s.='$haskernGPOS=true;' . "\n";
3961 else
3962 $s.='$haskernGPOS=false;' . "\n";
3963 if ($hassmallcapsGSUB)
3964 $s.='$hassmallcapsGSUB=true;' . "\n";
3965 else
3966 $s.='$hassmallcapsGSUB=false;' . "\n";
3967 $s.='$fontmetrics=\'' . _FONT_DESCRIPTOR . "';\n"; // mPDF 6
3968
3969 $s.='// TypoAscender/TypoDescender/TypoLineGap = ' . round($ttf->typoAscender) . ', ' . round($ttf->typoDescender) . ', ' . round($ttf->typoLineGap) . "\n";
3970 $s.='// usWinAscent/usWinDescent = ' . round($ttf->usWinAscent) . ', ' . round(-$ttf->usWinDescent) . "\n";
3971 $s.='// hhea Ascent/Descent/LineGap = ' . round($ttf->hheaascent) . ', ' . round($ttf->hheadescent) . ', ' . round($ttf->hhealineGap) . "\n";
3972
3973 // mPDF 5.7.1
3974 if (isset($this->fontdata[$family]['useOTL'])) {
3975 $s.='$useOTL=' . $this->fontdata[$family]['useOTL'] . ';' . "\n";
3976 } else
3977 $s.='$useOTL=0x0000;' . "\n";
3978 if ($rtlPUAstr) {
3979 $s.='$rtlPUAstr=\'' . $rtlPUAstr . "';\n";
3980 } else
3981 $s.='$rtlPUAstr=\'\';' . "\n";
3982 if (count($GSUBScriptLang)) {
3983 $s.='$GSUBScriptLang=' . var_export($GSUBScriptLang, true) . ";\n";
3984 }
3985 if (count($GSUBFeatures)) {
3986 $s.='$GSUBFeatures=' . var_export($GSUBFeatures, true) . ";\n";
3987 }
3988 if (count($GSUBLookups)) {
3989 $s.='$GSUBLookups=' . var_export($GSUBLookups, true) . ";\n";
3990 }
3991 if (count($GPOSScriptLang)) {
3992 $s.='$GPOSScriptLang=' . var_export($GPOSScriptLang, true) . ";\n";
3993 }
3994 if (count($GPOSFeatures)) {
3995 $s.='$GPOSFeatures=' . var_export($GPOSFeatures, true) . ";\n";
3996 }
3997 if (count($GPOSLookups)) {
3998 $s.='$GPOSLookups=' . var_export($GPOSLookups, true) . ";\n";
3999 }
4000 if ($kerninfo) {
4001 $s.='$kerninfo=' . var_export($kerninfo, true) . ";\n";
4002 }
4003 $s.="?>";
4004 if (is_writable(dirname(_MPDF_TTFONTDATAPATH . 'x'))) {
4005 $fh = fopen(_MPDF_TTFONTDATAPATH . $fontkey . '.mtx.php', "w");
4006 fwrite($fh, $s, strlen($s));
4007 fclose($fh);
4008 $fh = fopen(_MPDF_TTFONTDATAPATH . $fontkey . '.cw.dat', "wb");
4009 fwrite($fh, $cw, strlen($cw));
4010 fclose($fh);
4011 // mPDF 5.7.1
4012 $fh = fopen(_MPDF_TTFONTDATAPATH . $fontkey . '.gid.dat', "wb");
4013 fwrite($fh, $glyphIDtoUni, strlen($glyphIDtoUni));
4014 fclose($fh);
4015 if (file_exists(_MPDF_TTFONTDATAPATH . $fontkey . '.cgm'))
4016 unlink(_MPDF_TTFONTDATAPATH . $fontkey . '.cgm');
4017 if (file_exists(_MPDF_TTFONTDATAPATH . $fontkey . '.z'))
4018 unlink(_MPDF_TTFONTDATAPATH . $fontkey . '.z');
4019 if (file_exists(_MPDF_TTFONTDATAPATH . $fontkey . '.cw127.php'))
4020 unlink(_MPDF_TTFONTDATAPATH . $fontkey . '.cw127.php');
4021 if (file_exists(_MPDF_TTFONTDATAPATH . $fontkey . '.cw'))
4022 unlink(_MPDF_TTFONTDATAPATH . $fontkey . '.cw');
4023 }
4024 elseif ($this->debugfonts) {
4025 throw new MpdfException('Cannot write to the font caching directory - ' . _MPDF_TTFONTDATAPATH);
4026 }
4027 unset($ttf);
4028 } else {
4029 $cw = '';
4030 $glyphIDtoUni = '';
4031 if (file_exists(_MPDF_TTFONTDATAPATH . $fontkey . '.cw.dat'))
4032 $cw = file_get_contents(_MPDF_TTFONTDATAPATH . $fontkey . '.cw.dat');
4033 if (file_exists(_MPDF_TTFONTDATAPATH . $fontkey . '.gid.dat'))
4034 $glyphIDtoUni = file_get_contents(_MPDF_TTFONTDATAPATH . $fontkey . '.gid.dat');
4035 }
4036
4037 /* -- OTL -- */
4038 // mPDF 5.7.1
4039 // Use OTL OpenType Table Layout - GSUB
4040 if (isset($this->fontdata[$family]['useOTL']) && ($this->fontdata[$family]['useOTL'])) {
4041 if (!class_exists('otl', false)) {
4042 include(_MPDF_PATH . 'classes/otl.php');
4043 }
4044 if (empty($this->otl)) {
4045 $this->otl = new otl($this);
4046 }
4047 }
4048 /* -- END OTL -- */
4049
4050 if (isset($this->fontdata[$family]['sip-ext']) && $this->fontdata[$family]['sip-ext']) {
4051 $sipext = $this->fontdata[$family]['sip-ext'];
4052 } else {
4053 $sipext = '';
4054 }
4055
4056 // Override with values from config_font.php
4057 if (isset($this->fontdata[$family]['Ascent']) && $this->fontdata[$family]['Ascent']) {
4058 $desc['Ascent'] = $this->fontdata[$family]['Ascent'];
4059 }
4060 if (isset($this->fontdata[$family]['Descent']) && $this->fontdata[$family]['Descent']) {
4061 $desc['Descent'] = $this->fontdata[$family]['Descent'];
4062 }
4063 if (isset($this->fontdata[$family]['Leading']) && $this->fontdata[$family]['Leading']) {
4064 $desc['Leading'] = $this->fontdata[$family]['Leading'];
4065 }
4066
4067
4068
4069 $i = count($this->fonts) + $this->extraFontSubsets + 1;
4070 if ($sip || $smp) {
4071 $this->fonts[$fontkey] = array('i' => $i, 'type' => $type, 'name' => $name, 'desc' => $desc, 'panose' => $panose, 'unitsPerEm' => $unitsPerEm, 'up' => $up, 'ut' => $ut, 'strs' => $strs, 'strp' => $strp, 'cw' => $cw, 'ttffile' => $ttffile, 'fontkey' => $fontkey, 'subsets' => array(0 => range(0, 127)), 'subsetfontids' => array($i), 'used' => false, 'sip' => $sip, 'sipext' => $sipext, 'smp' => $smp, 'TTCfontID' => $TTCfontID, 'useOTL' => (isset($this->fontdata[$family]['useOTL']) ? $this->fontdata[$family]['useOTL'] : false), 'useKashida' => (isset($this->fontdata[$family]['useKashida']) ? $this->fontdata[$family]['useKashida'] : false), 'GSUBScriptLang' => $GSUBScriptLang, 'GSUBFeatures' => $GSUBFeatures, 'GSUBLookups' => $GSUBLookups, 'GPOSScriptLang' => $GPOSScriptLang, 'GPOSFeatures' => $GPOSFeatures, 'GPOSLookups' => $GPOSLookups, 'rtlPUAstr' => $rtlPUAstr, 'glyphIDtoUni' => $glyphIDtoUni, 'haskerninfo' => $haskerninfo, 'haskernGPOS' => $haskernGPOS, 'hassmallcapsGSUB' => $hassmallcapsGSUB); // mPDF 5.7.1 // mPDF 6
4072 } else {
4073 $ss = array();
4074 for ($s = 32; $s < 128; $s++) {
4075 $ss[$s] = $s;
4076 }
4077 $this->fonts[$fontkey] = array('i' => $i, 'type' => $type, 'name' => $name, 'desc' => $desc, 'panose' => $panose, 'unitsPerEm' => $unitsPerEm, 'up' => $up, 'ut' => $ut, 'strs' => $strs, 'strp' => $strp, 'cw' => $cw, 'ttffile' => $ttffile, 'fontkey' => $fontkey, 'subset' => $ss, 'used' => false, 'sip' => $sip, 'sipext' => $sipext, 'smp' => $smp, 'TTCfontID' => $TTCfontID, 'useOTL' => (isset($this->fontdata[$family]['useOTL']) ? $this->fontdata[$family]['useOTL'] : false), 'useKashida' => (isset($this->fontdata[$family]['useKashida']) ? $this->fontdata[$family]['useKashida'] : false), 'GSUBScriptLang' => $GSUBScriptLang, 'GSUBFeatures' => $GSUBFeatures, 'GSUBLookups' => $GSUBLookups, 'GPOSScriptLang' => $GPOSScriptLang, 'GPOSFeatures' => $GPOSFeatures, 'GPOSLookups' => $GPOSLookups, 'rtlPUAstr' => $rtlPUAstr, 'glyphIDtoUni' => $glyphIDtoUni, 'haskerninfo' => $haskerninfo, 'haskernGPOS' => $haskernGPOS, 'hassmallcapsGSUB' => $hassmallcapsGSUB); // mPDF 5.7.1 // mPDF 6
4078 }
4079 if ($haskerninfo) {
4080 $this->fonts[$fontkey]['kerninfo'] = $kerninfo;
4081 }
4082 $this->FontFiles[$fontkey] = array('length1' => $originalsize, 'type' => "TTF", 'ttffile' => $ttffile, 'sip' => $sip, 'smp' => $smp);
4083 unset($cw);
4084 }
4085
4086 function SetFont($family, $style = '', $size = 0, $write = true, $forcewrite = false)
4087 {
4088 $family = strtolower($family);
4089 if (!$this->onlyCoreFonts) {
4090 if ($family == 'sans' || $family == 'sans-serif') {
4091 $family = $this->sans_fonts[0];
4092 }
4093 if ($family == 'serif') {
4094 $family = $this->serif_fonts[0];
4095 }
4096 if ($family == 'mono' || $family == 'monospace') {
4097 $family = $this->mono_fonts[0];
4098 }
4099 }
4100 if (isset($this->fonttrans[$family]) && $this->fonttrans[$family]) {
4101 $family = $this->fonttrans[$family];
4102 }
4103 if ($family == '') {
4104 if ($this->FontFamily) {
4105 $family = $this->FontFamily;
4106 } elseif ($this->default_font) {
4107 $family = $this->default_font;
4108 } else {
4109 throw new MpdfException("No font or default font set!");
4110 }
4111 }
4112 $this->ReqFontStyle = $style; // required or requested style - used later for artificial bold/italic
4113
4114 if (($family == 'csymbol') || ($family == 'czapfdingbats') || ($family == 'ctimes') || ($family == 'ccourier') || ($family == 'chelvetica')) {
4115 if ($this->PDFA || $this->PDFX) {
4116 if ($family == 'csymbol' || $family == 'czapfdingbats') {
4117 throw new MpdfException("Symbol and Zapfdingbats cannot be embedded in mPDF (required for PDFA1-b or PDFX/1-a).");
4118 }
4119 if ($family == 'ctimes' || $family == 'ccourier' || $family == 'chelvetica') {
4120 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
4121 $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.)";
4122 }
4123 if ($family == 'chelvetica') {
4124 $family = 'sans';
4125 }
4126 if ($family == 'ctimes') {
4127 $family = 'serif';
4128 }
4129 if ($family == 'ccourier') {
4130 $family = 'mono';
4131 }
4132 }
4133 $this->usingCoreFont = false;
4134 } else {
4135 $this->usingCoreFont = true;
4136 }
4137 if ($family == 'csymbol' || $family == 'czapfdingbats') {
4138 $style = '';
4139 }
4140 } else {
4141 $this->usingCoreFont = false;
4142 }
4143
4144 // mPDF 5.7.1
4145 if ($style) {
4146 $style = strtoupper($style);
4147 if ($style == 'IB')
4148 $style = 'BI';
4149 }
4150 if ($size == 0)
4151 $size = $this->FontSizePt;
4152
4153 $fontkey = $family . $style;
4154
4155 $stylekey = $style;
4156 if (!$stylekey) {
4157 $stylekey = "R";
4158 }
4159
4160 if (!$this->onlyCoreFonts && !$this->usingCoreFont) {
4161 if (!isset($this->fonts[$fontkey]) || count($this->default_available_fonts) != count($this->available_unifonts)) { // not already added
4162 /* -- CJK-FONTS -- */
4163 // CJK fonts
4164 if (in_array($fontkey, $this->available_CJK_fonts)) {
4165 if (!isset($this->fonts[$fontkey])) { // already added
4166 if (empty($this->Big5_widths)) {
4167 require(_MPDF_PATH . 'includes/CJKdata.php');
4168 }
4169 $this->AddCJKFont($family); // don't need to add style
4170 }
4171 }
4172 // Test to see if requested font/style is available - or substitute
4173 else
4174 /* -- END CJK-FONTS -- */
4175 if (!in_array($fontkey, $this->available_unifonts)) {
4176 // If font[nostyle] exists - set it
4177 if (in_array($family, $this->available_unifonts)) {
4178 $style = '';
4179 }
4180
4181 // elseif only one font available - set it (assumes if only one font available it will not have a style)
4182 elseif (count($this->available_unifonts) == 1) {
4183 $family = $this->available_unifonts[0];
4184 $style = '';
4185 } else {
4186 $found = 0;
4187 // else substitute font of similar type
4188 if (in_array($family, $this->sans_fonts)) {
4189 $i = array_intersect($this->sans_fonts, $this->available_unifonts);
4190 if (count($i)) {
4191 $i = array_values($i);
4192 // with requested style if possible
4193 if (!in_array(($i[0] . $style), $this->available_unifonts)) {
4194 $style = '';
4195 }
4196 $family = $i[0];
4197 $found = 1;
4198 }
4199 } elseif (in_array($family, $this->serif_fonts)) {
4200 $i = array_intersect($this->serif_fonts, $this->available_unifonts);
4201 if (count($i)) {
4202 $i = array_values($i);
4203 // with requested style if possible
4204 if (!in_array(($i[0] . $style), $this->available_unifonts)) {
4205 $style = '';
4206 }
4207 $family = $i[0];
4208 $found = 1;
4209 }
4210 } elseif (in_array($family, $this->mono_fonts)) {
4211 $i = array_intersect($this->mono_fonts, $this->available_unifonts);
4212 if (count($i)) {
4213 $i = array_values($i);
4214 // with requested style if possible
4215 if (!in_array(($i[0] . $style), $this->available_unifonts)) {
4216 $style = '';
4217 }
4218 $family = $i[0];
4219 $found = 1;
4220 }
4221 }
4222
4223 if (!$found) {
4224 // set first available font
4225 $fs = $this->available_unifonts[0];
4226 preg_match('/^([a-z_0-9\-]+)([BI]{0,2})$/', $fs, $fas); // Allow "-"
4227 // with requested style if possible
4228 $ws = $fas[1] . $style;
4229 if (in_array($ws, $this->available_unifonts)) {
4230 $family = $fas[1]; // leave $style as is
4231 } elseif (in_array($fas[1], $this->available_unifonts)) {
4232 // or without style
4233 $family = $fas[1];
4234 $style = '';
4235 } else {
4236 // or with the style specified
4237 $family = $fas[1];
4238 $style = $fas[2];
4239 }
4240 }
4241 }
4242 $fontkey = $family . $style;
4243 }
4244 }
4245 // try to add font (if not already added)
4246 $this->AddFont($family, $style);
4247
4248 //Test if font is already selected
4249 if ($this->FontFamily == $family && $this->FontFamily == $this->currentfontfamily && $this->FontStyle == $style && $this->FontStyle == $this->currentfontstyle && $this->FontSizePt == $size && $this->FontSizePt == $this->currentfontsize && !$forcewrite) {
4250 return $family;
4251 }
4252
4253 $fontkey = $family . $style;
4254
4255 //Select it
4256 $this->FontFamily = $family;
4257 $this->FontStyle = $style;
4258 $this->FontSizePt = $size;
4259 $this->FontSize = $size / _MPDFK;
4260 $this->CurrentFont = &$this->fonts[$fontkey];
4261 if ($write) {
4262 $fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
4263 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
4264 $this->_out($fontout);
4265 }
4266 $this->pageoutput[$this->page]['Font'] = $fontout;
4267 }
4268
4269
4270
4271 // Added - currentfont (lowercase) used in HTML2PDF
4272 $this->currentfontfamily = $family;
4273 $this->currentfontsize = $size;
4274 $this->currentfontstyle = $style;
4275 $this->setMBencoding('UTF-8');
4276 } else { // if using core fonts
4277 if ($this->PDFA || $this->PDFX) {
4278 throw new MpdfException('Core Adobe fonts cannot be embedded in mPDF (required for PDFA1-b or PDFX/1-a) - cannot use option to use core fonts.');
4279 }
4280 $this->setMBencoding('windows-1252');
4281
4282 //Test if font is already selected
4283 if (($this->FontFamily == $family) AND ( $this->FontStyle == $style) AND ( $this->FontSizePt == $size) && !$forcewrite) {
4284 return $family;
4285 }
4286
4287 if (!isset($this->CoreFonts[$fontkey])) {
4288 if (in_array($family, $this->serif_fonts)) {
4289 $family = 'ctimes';
4290 } elseif (in_array($family, $this->mono_fonts)) {
4291 $family = 'ccourier';
4292 } else {
4293 $family = 'chelvetica';
4294 }
4295 $this->usingCoreFont = true;
4296 $fontkey = $family . $style;
4297 }
4298
4299 if (!isset($this->fonts[$fontkey])) {
4300 // STANDARD CORE FONTS
4301 if (isset($this->CoreFonts[$fontkey])) {
4302 //Load metric file
4303 $file = $family;
4304 if ($family == 'ctimes' || $family == 'chelvetica' || $family == 'ccourier') {
4305 $file.=strtolower($style);
4306 }
4307 $file.='.php';
4308 include(_MPDF_PATH . 'font/' . $file);
4309 if (!isset($cw)) {
4310 throw new MpdfException('Could not include font metric file');
4311 }
4312 $i = count($this->fonts) + $this->extraFontSubsets + 1;
4313 $this->fonts[$fontkey] = array('i' => $i, 'type' => 'core', 'name' => $this->CoreFonts[$fontkey], 'desc' => $desc, 'up' => $up, 'ut' => $ut, 'cw' => $cw);
4314 if ($this->useKerning && isset($kerninfo)) {
4315 $this->fonts[$fontkey]['kerninfo'] = $kerninfo;
4316 }
4317 } else {
4318 throw new MpdfException('mPDF error - Font not defined');
4319 }
4320 }
4321 //Test if font is already selected
4322 if (($this->FontFamily == $family) AND ( $this->FontStyle == $style) AND ( $this->FontSizePt == $size) && !$forcewrite) {
4323 return $family;
4324 }
4325 //Select it
4326 $this->FontFamily = $family;
4327 $this->FontStyle = $style;
4328 $this->FontSizePt = $size;
4329 $this->FontSize = $size / _MPDFK;
4330 $this->CurrentFont = &$this->fonts[$fontkey];
4331 if ($write) {
4332 $fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
4333 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
4334 $this->_out($fontout);
4335 }
4336 $this->pageoutput[$this->page]['Font'] = $fontout;
4337 }
4338 // Added - currentfont (lowercase) used in HTML2PDF
4339 $this->currentfontfamily = $family;
4340 $this->currentfontsize = $size;
4341 $this->currentfontstyle = $style;
4342 }
4343
4344 return $family;
4345 }
4346
4347 function SetFontSize($size, $write = true)
4348 {
4349 //Set font size in points
4350 if ($this->FontSizePt == $size)
4351 return;
4352 $this->FontSizePt = $size;
4353 $this->FontSize = $size / _MPDFK;
4354 $this->currentfontsize = $size;
4355 if ($write) {
4356 $fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
4357 // Edited mPDF 3.0
4358 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
4359 $this->_out($fontout);
4360 }
4361 $this->pageoutput[$this->page]['Font'] = $fontout;
4362 }
4363 }
4364
4365 function AddLink()
4366 {
4367 //Create a new internal link
4368 $n = count($this->links) + 1;
4369 $this->links[$n] = array(0, 0);
4370 return $n;
4371 }
4372
4373 function SetLink($link, $y = 0, $page = -1)
4374 {
4375 //Set destination of internal link
4376 if ($y == -1)
4377 $y = $this->y;
4378 if ($page == -1)
4379 $page = $this->page;
4380 $this->links[$link] = array($page, $y);
4381 }
4382
4383 function Link($x, $y, $w, $h, $link)
4384 {
4385 $l = array($x * _MPDFK, $this->hPt - $y * _MPDFK, $w * _MPDFK, $h * _MPDFK, $link);
4386 if ($this->keep_block_together) { // don't write yet
4387 return;
4388 } elseif ($this->table_rotate) { // *TABLES*
4389 $this->tbrot_Links[$this->page][] = $l; // *TABLES*
4390 return; // *TABLES*
4391 } // *TABLES*
4392 elseif ($this->kwt) {
4393 $this->kwt_Links[$this->page][] = $l;
4394 return;
4395 }
4396
4397 if ($this->writingHTMLheader || $this->writingHTMLfooter) {
4398 $this->HTMLheaderPageLinks[] = $l;
4399 return;
4400 }
4401 //Put a link on the page
4402 $this->PageLinks[$this->page][] = $l;
4403 // Save cross-reference to Column buffer
4404 $ref = count($this->PageLinks[$this->page]) - 1; // *COLUMNS*
4405 $this->columnLinks[$this->CurrCol][INTVAL($this->x)][INTVAL($this->y)] = $ref; // *COLUMNS*
4406 }
4407
4408 function Text($x, $y, $txt, $OTLdata = array(), $textvar = 0, $aixextra = '', $coordsys = '', $return = false)
4409 {
4410 // Output (or return) a string
4411 // Called (internally) by Watermark() & _tableWrite() [rotated cells] & TableHeaderFooter() & WriteText()
4412 // Called also from classes/svg.php
4413 // Expects Font to be set
4414 // Expects input to be mb_encoded if necessary and RTL reversed & OTL processed
4415 // ARTIFICIAL BOLD AND ITALIC
4416 $s = 'q ';
4417 if ($this->falseBoldWeight && strpos($this->ReqFontStyle, "B") !== false && strpos($this->FontStyle, "B") === false) {
4418 $s .= '2 Tr 1 J 1 j ';
4419 $s .= sprintf('%.3F w ', ($this->FontSize / 130) * _MPDFK * $this->falseBoldWeight);
4420 $tc = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
4421 if ($this->FillColor != $tc) {
4422 $s .= $tc . ' ';
4423 } // stroke (outline) = same colour as text(fill)
4424 }
4425 if (strpos($this->ReqFontStyle, "I") !== false && strpos($this->FontStyle, "I") === false) {
4426 $aix = '1 0 0.261799 1 %.3F %.3F Tm';
4427 } else {
4428 $aix = '%.3F %.3F Td';
4429 }
4430
4431 $aix = $aixextra . $aix;
4432
4433 if ($this->ColorFlag)
4434 $s.=$this->TextColor . ' ';
4435
4436 $this->CurrentFont['used'] = true;
4437
4438 if ($this->usingCoreFont) {
4439 $txt2 = str_replace(chr(160), chr(32), $txt);
4440 } else {
4441 $txt2 = str_replace(chr(194) . chr(160), chr(32), $txt);
4442 }
4443
4444 $px = $x;
4445 $py = $y;
4446 if ($coordsys != 'SVG') {
4447 $px = $x * _MPDFK;
4448 $py = ($this->h - $y) * _MPDFK;
4449 }
4450
4451
4452 /* * ************** SIMILAR TO Cell() ************************ */
4453
4454 // IF corefonts AND NOT SmCaps AND NOT Kerning
4455 // Just output text
4456 if ($this->usingCoreFont && !($textvar & FC_SMALLCAPS) && !($textvar & FC_KERNING)) {
4457 $txt2 = $this->_escape($txt2);
4458 $s .=sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
4459 }
4460
4461
4462 // IF NOT corefonts [AND NO wordspacing] AND NOT SIP/SMP AND NOT SmCaps AND NOT Kerning AND NOT OTL
4463 // Just output text
4464 elseif (!$this->usingCoreFont && !($textvar & FC_SMALLCAPS) && !($textvar & FC_KERNING) && !(isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && !empty($OTLdata['GPOSinfo']))) {
4465 // IF SIP/SMP
4466 if ($this->CurrentFont['sip'] || $this->CurrentFont['smp']) {
4467 $txt2 = $this->UTF8toSubset($txt2);
4468 $s .=sprintf('BT ' . $aix . ' %s Tj ET', $px, $py, $txt2);
4469 }
4470 // NOT SIP/SMP
4471 else {
4472 $txt2 = $this->UTF8ToUTF16BE($txt2, false);
4473 $txt2 = $this->_escape($txt2);
4474 $s .=sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
4475 }
4476 }
4477
4478 // IF NOT corefonts [AND IS wordspacing] AND NOT SIP AND NOT SmCaps AND NOT Kerning AND NOT OTL
4479 // Not required here (cf. Cell() )
4480 // ELSE (IF SmCaps || Kerning || OTL) [corefonts or not corefonts; SIP or SMP or BMP]
4481 else {
4482 $s .= $this->applyGPOSpdf($txt2, $aix, $px, $py, $OTLdata, $textvar);
4483 }
4484 /* * ************** END ************************ */
4485
4486 $s .= ' ';
4487
4488 if (($textvar & FD_UNDERLINE) && $txt != '') { // mPDF 5.7.1
4489 $c = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
4490 if ($this->FillColor != $c) {
4491 $s.= ' ' . $c . ' ';
4492 }
4493 if (isset($this->CurrentFont['up']) && $this->CurrentFont['up']) {
4494 $up = $this->CurrentFont['up'];
4495 } else {
4496 $up = -100;
4497 }
4498 $adjusty = (-$up / 1000 * $this->FontSize);
4499 if (isset($this->CurrentFont['ut']) && $this->CurrentFont['ut']) {
4500 $ut = $this->CurrentFont['ut'] / 1000 * $this->FontSize;
4501 } else {
4502 $ut = 60 / 1000 * $this->FontSize;
4503 }
4504 $olw = $this->LineWidth;
4505 $s.=' ' . (sprintf(' %.3F w', $ut * _MPDFK));
4506 $s.=' ' . $this->_dounderline($x, $y + $adjusty, $txt, $OTLdata, $textvar);
4507 $s.=' ' . (sprintf(' %.3F w', $olw * _MPDFK));
4508 if ($this->FillColor != $c) {
4509 $s.= ' ' . $this->FillColor . ' ';
4510 }
4511 }
4512 // STRIKETHROUGH
4513 if (($textvar & FD_LINETHROUGH) && $txt != '') { // mPDF 5.7.1
4514 $c = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
4515 if ($this->FillColor != $c) {
4516 $s.= ' ' . $c . ' ';
4517 }
4518 //Superscript and Subscript Y coordinate adjustment (now for striked-through texts)
4519 if (isset($this->CurrentFont['desc']['CapHeight']) && $this->CurrentFont['desc']['CapHeight']) {
4520 $ch = $this->CurrentFont['desc']['CapHeight'];
4521 } else {
4522 $ch = 700;
4523 }
4524 $adjusty = (-$ch / 1000 * $this->FontSize) * 0.35;
4525 if (isset($this->CurrentFont['ut']) && $this->CurrentFont['ut']) {
4526 $ut = $this->CurrentFont['ut'] / 1000 * $this->FontSize;
4527 } else {
4528 $ut = 60 / 1000 * $this->FontSize;
4529 }
4530 $olw = $this->LineWidth;
4531 $s.=' ' . (sprintf(' %.3F w', $ut * _MPDFK));
4532 $s.=' ' . $this->_dounderline($x, $y + $adjusty, $txt, $OTLdata, $textvar);
4533 $s.=' ' . (sprintf(' %.3F w', $olw * _MPDFK));
4534 if ($this->FillColor != $c) {
4535 $s.= ' ' . $this->FillColor . ' ';
4536 }
4537 }
4538 $s .= 'Q';
4539
4540 if ($return) {
4541 return $s . " \n";
4542 }
4543 $this->_out($s);
4544 }
4545
4546 /* -- DIRECTW -- */
4547
4548 function WriteText($x, $y, $txt)
4549 {
4550 // Output a string using Text() but does encoding and text reversing of RTL
4551 $txt = $this->purify_utf8_text($txt);
4552 if ($this->text_input_as_HTML) {
4553 $txt = $this->all_entities_to_utf8($txt);
4554 }
4555 if ($this->usingCoreFont) {
4556 $txt = mb_convert_encoding($txt, $this->mb_enc, 'UTF-8');
4557 }
4558
4559 // DIRECTIONALITY
4560 if (preg_match("/([" . $this->pregRTLchars . "])/u", $txt)) {
4561 $this->biDirectional = true;
4562 } // *OTL*
4563
4564 $textvar = 0;
4565 $save_OTLtags = $this->OTLtags;
4566 $this->OTLtags = array();
4567 if ($this->useKerning) {
4568 if ($this->CurrentFont['haskernGPOS']) {
4569 $this->OTLtags['Plus'] .= ' kern';
4570 } else {
4571 $textvar = ($textvar | FC_KERNING);
4572 }
4573 }
4574
4575 /* -- OTL -- */
4576 // Use OTL OpenType Table Layout - GSUB & GPOS
4577 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
4578 $txt = $this->otl->applyOTL($txt, $this->CurrentFont['useOTL']);
4579 $OTLdata = $this->otl->OTLdata;
4580 }
4581 /* -- END OTL -- */
4582 $this->OTLtags = $save_OTLtags;
4583
4584 $this->magic_reverse_dir($txt, $this->directionality, $OTLdata);
4585
4586 $this->Text($x, $y, $txt, $OTLdata, $textvar);
4587 }
4588
4589 function WriteCell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = 0, $link = '', $currentx = 0)
4590 {
4591 //Output a cell using Cell() but does encoding and text reversing of RTL
4592 $txt = $this->purify_utf8_text($txt);
4593 if ($this->text_input_as_HTML) {
4594 $txt = $this->all_entities_to_utf8($txt);
4595 }
4596 if ($this->usingCoreFont) {
4597 $txt = mb_convert_encoding($txt, $this->mb_enc, 'UTF-8');
4598 }
4599 // DIRECTIONALITY
4600 if (preg_match("/([" . $this->pregRTLchars . "])/u", $txt)) {
4601 $this->biDirectional = true;
4602 } // *OTL*
4603
4604 $textvar = 0;
4605 $save_OTLtags = $this->OTLtags;
4606 $this->OTLtags = array();
4607 if ($this->useKerning) {
4608 if ($this->CurrentFont['haskernGPOS']) {
4609 $this->OTLtags['Plus'] .= ' kern';
4610 } else {
4611 $textvar = ($textvar | FC_KERNING);
4612 }
4613 }
4614
4615 /* -- OTL -- */
4616 // Use OTL OpenType Table Layout - GSUB & GPOS
4617 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
4618 $txt = $this->otl->applyOTL($txt, $this->CurrentFont['useOTL']);
4619 $OTLdata = $this->otl->OTLdata;
4620 }
4621 /* -- END OTL -- */
4622 $this->OTLtags = $save_OTLtags;
4623
4624 $this->magic_reverse_dir($txt, $this->directionality, $OTLdata);
4625
4626 $this->Cell($w, $h, $txt, $border, $ln, $align, $fill, $link, $currentx, 0, 0, 'M', 0, false, $OTLdata, $textvar);
4627 }
4628
4629 /* -- END DIRECTW -- */
4630
4631 function ResetSpacing()
4632 {
4633 if ($this->ws != 0) {
4634 $this->_out('BT 0 Tw ET');
4635 }
4636 $this->ws = 0;
4637 if ($this->charspacing != 0) {
4638 $this->_out('BT 0 Tc ET');
4639 }
4640 $this->charspacing = 0;
4641 }
4642
4643 function SetSpacing($cs, $ws)
4644 {
4645 if (intval($cs * 1000) == 0) {
4646 $cs = 0;
4647 }
4648 if ($cs) {
4649 $this->_out(sprintf('BT %.3F Tc ET', $cs));
4650 } elseif ($this->charspacing != 0) {
4651 $this->_out('BT 0 Tc ET');
4652 }
4653 $this->charspacing = $cs;
4654 if (intval($ws * 1000) == 0) {
4655 $ws = 0;
4656 }
4657 if ($ws) {
4658 $this->_out(sprintf('BT %.3F Tw ET', $ws));
4659 } elseif ($this->ws != 0) {
4660 $this->_out('BT 0 Tw ET');
4661 }
4662 $this->ws = $ws;
4663 }
4664
4665 // WORD SPACING
4666 function GetJspacing($nc, $ns, $w, $inclCursive, &$cOTLdata)
4667 {
4668 $kashida_present = false;
4669 $kashida_space = 0;
4670 if ($w > 0 && $inclCursive && isset($this->CurrentFont['useKashida']) && $this->CurrentFont['useKashida'] && !empty($cOTLdata)) {
4671 for ($c = 0; $c < count($cOTLdata); $c++) {
4672 for ($i = 0; $i < strlen($cOTLdata[$c]['group']); $i++) {
4673 if (isset($cOTLdata[$c]['GPOSinfo'][$i]['kashida']) && $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > 0) {
4674 $kashida_present = true;
4675 break 2;
4676 }
4677 }
4678 }
4679 }
4680
4681 if ($kashida_present) {
4682 $k_ctr = 0; // Number of kashida points
4683 $k_total = 0; // Total of kashida values (priority)
4684 // Reset word
4685 $max_kashida_in_word = 0;
4686 $last_kashida_in_word = -1;
4687
4688 for ($c = 0; $c < count($cOTLdata); $c++) {
4689 for ($i = 0; $i < strlen($cOTLdata[$c]['group']); $i++) {
4690
4691 if ($cOTLdata[$c]['group'][$i] == 'S') {
4692 // Save from last word
4693 if ($max_kashida_in_word) {
4694 $k_ctr++;
4695 $k_total = $max_kashida_in_word;
4696 }
4697 // Reset word
4698 $max_kashida_in_word = 0;
4699 $last_kashida_in_word = -1;
4700 }
4701
4702 if (isset($cOTLdata[$c]['GPOSinfo'][$i]['kashida']) && $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > 0) {
4703 if ($max_kashida_in_word) {
4704 if ($cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > $max_kashida_in_word) {
4705 $max_kashida_in_word = $cOTLdata[$c]['GPOSinfo'][$i]['kashida'];
4706 $cOTLdata[$c]['GPOSinfo'][$last_kashida_in_word]['kashida'] = 0;
4707 $last_kashida_in_word = $i;
4708 } else {
4709 $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] = 0;
4710 }
4711 } else {
4712 $max_kashida_in_word = $cOTLdata[$c]['GPOSinfo'][$i]['kashida'];
4713 $last_kashida_in_word = $i;
4714 }
4715 }
4716 }
4717 }
4718 // Save from last word
4719 if ($max_kashida_in_word) {
4720 $k_ctr++;
4721 $k_total = $max_kashida_in_word;
4722 }
4723
4724 // Number of kashida points = $k_ctr
4725 // $useKashida is a % value from CurrentFont/config_fonts.php
4726 // % ratio divided between word-spacing and kashida-spacing
4727 $kashida_space_ratio = intval($this->CurrentFont['useKashida']) / 100;
4728
4729
4730 $kashida_space = $w * $kashida_space_ratio;
4731
4732 $tatw = $this->_getCharWidth($this->CurrentFont['cw'], 0x0640);
4733 // Only use kashida if each allocated kashida width is > 0.01 x width of a tatweel
4734 // Otherwise fontstretch is too small and errors
4735 // If not just leave to adjust word-spacing
4736 if ($tatw && (($kashida_space / $k_ctr) / $tatw) > 0.01) {
4737 for ($c = 0; $c < count($cOTLdata); $c++) {
4738 for ($i = 0; $i < strlen($cOTLdata[$c]['group']); $i++) {
4739 if (isset($cOTLdata[$c]['GPOSinfo'][$i]['kashida']) && $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > 0) {
4740 // At this point kashida is a number representing priority (higher number - higher priority)
4741 // We are now going to set it as an actual length
4742 // This shares it equally amongst words:
4743 $cOTLdata[$c]['GPOSinfo'][$i]['kashida_space'] = (1 / $k_ctr) * $kashida_space;
4744 }
4745 }
4746 }
4747 $w -= $kashida_space;
4748 }
4749 }
4750
4751 $ws = 0;
4752 $charspacing = 0;
4753 $ww = $this->jSWord;
4754 $ncx = $nc - 1;
4755 if ($nc == 0) {
4756 return array(0, 0, 0);
4757 }
4758 // Only word spacing allowed / possible
4759 elseif ($this->fixedlSpacing !== false || $inclCursive) {
4760 if ($ns) {
4761 $ws = $w / $ns;
4762 }
4763 } elseif ($nc == 1) {
4764 $charspacing = $w;
4765 } elseif (!$ns) {
4766 $charspacing = $w / ($ncx );
4767 if (($this->jSmaxChar > 0) && ($charspacing > $this->jSmaxChar)) {
4768 $charspacing = $this->jSmaxChar;
4769 }
4770 } elseif ($ns == ($ncx )) {
4771 $charspacing = $w / $ns;
4772 } else {
4773 if ($this->usingCoreFont) {
4774 $cs = ($w * (1 - $this->jSWord)) / ($ncx );
4775 if (($this->jSmaxChar > 0) && ($cs > $this->jSmaxChar)) {
4776 $cs = $this->jSmaxChar;
4777 $ww = 1 - (($cs * ($ncx )) / $w);
4778 }
4779 $charspacing = $cs;
4780 $ws = ($w * ($ww) ) / $ns;
4781 } else {
4782 $cs = ($w * (1 - $this->jSWord)) / ($ncx - $ns);
4783 if (($this->jSmaxChar > 0) && ($cs > $this->jSmaxChar)) {
4784 $cs = $this->jSmaxChar;
4785 $ww = 1 - (($cs * ($ncx - $ns)) / $w);
4786 }
4787 $charspacing = $cs;
4788 $ws = (($w * ($ww) ) / $ns) - $charspacing;
4789 }
4790 }
4791 return array($charspacing, $ws, $kashida_space);
4792 }
4793
4794 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)
4795 { // mPDF 5.7.1
4796 //Output a cell
4797 // Expects input to be mb_encoded if necessary and RTL reversed
4798 // NON_BREAKING SPACE
4799 if ($this->usingCoreFont) {
4800 $txt = str_replace(chr(160), chr(32), $txt);
4801 } else {
4802 $txt = str_replace(chr(194) . chr(160), chr(32), $txt);
4803 }
4804
4805 $oldcolumn = $this->CurrCol;
4806 // Automatic page break
4807 // Allows PAGE-BREAK-AFTER = avoid to work
4808 if (isset($this->blk[$this->blklvl])) {
4809 $bottom = $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['margin_bottom'];
4810 } else {
4811 $bottom = 0;
4812 }
4813 if (!$this->tableLevel && (($this->y + $this->divheight > $this->PageBreakTrigger) || ($this->y + $h > $this->PageBreakTrigger) ||
4814 ($this->y + ($h * 2) + $bottom > $this->PageBreakTrigger && $this->blk[$this->blklvl]['page_break_after_avoid'])) and ! $this->InFooter and $this->AcceptPageBreak()) { // mPDF 5.7.2
4815 $x = $this->x; //Current X position
4816 // WORD SPACING
4817 $ws = $this->ws; //Word Spacing
4818 $charspacing = $this->charspacing; //Character Spacing
4819 $this->ResetSpacing();
4820
4821 $this->AddPage($this->CurOrientation);
4822 // Added to correct for OddEven Margins
4823 $x += $this->MarginCorrection;
4824 if ($currentx) {
4825 $currentx += $this->MarginCorrection;
4826 }
4827 $this->x = $x;
4828 // WORD SPACING
4829 $this->SetSpacing($charspacing, $ws);
4830 }
4831
4832 // Test: to put line through centre of cell: $this->Line($this->x,$this->y+($h/2),$this->x+50,$this->y+($h/2));
4833 // Test: to put border around cell as it is specified: $border='LRTB';
4834
4835
4836 /* -- COLUMNS -- */
4837 // COLS
4838 // COLUMN CHANGE
4839 if ($this->CurrCol != $oldcolumn) {
4840 if ($currentx) {
4841 $currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
4842 }
4843 $this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
4844 }
4845
4846 // COLUMNS Update/overwrite the lowest bottom of printing y value for a column
4847 if ($this->ColActive) {
4848 if ($h) {
4849 $this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y + $h;
4850 } else {
4851 $this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y + $this->divheight;
4852 }
4853 }
4854 /* -- END COLUMNS -- */
4855
4856
4857 if ($w == 0)
4858 $w = $this->w - $this->rMargin - $this->x;
4859 $s = '';
4860 if ($fill == 1 && $this->FillColor) {
4861 if ((isset($this->pageoutput[$this->page]['FillColor']) && $this->pageoutput[$this->page]['FillColor'] != $this->FillColor) || !isset($this->pageoutput[$this->page]['FillColor'])) {
4862 $s .= $this->FillColor . ' ';
4863 }
4864 $this->pageoutput[$this->page]['FillColor'] = $this->FillColor;
4865 }
4866
4867
4868 if ($lineBox && isset($lineBox['boxtop']) && $txt) { // i.e. always from WriteFlowingBlock/finishFlowingBlock (but not objects -
4869 // which only have $lineBox['top'] set)
4870 $boxtop = $this->y + $lineBox['boxtop'];
4871 $boxbottom = $this->y + $lineBox['boxbottom'];
4872 $glyphYorigin = $lineBox['glyphYorigin'];
4873 $baseline_shift = $lineBox['baseline-shift'];
4874 $bord_boxtop = $bg_boxtop = $boxtop = $boxtop - $baseline_shift;
4875 $bord_boxbottom = $bg_boxbottom = $boxbottom = $boxbottom - $baseline_shift;
4876 $bord_boxheight = $bg_boxheight = $boxheight = $boxbottom - $boxtop;
4877
4878 // If inline element BACKGROUND has bounding box set by parent element:
4879 if (isset($lineBox['background-boxtop'])) {
4880 $bg_boxtop = $this->y + $lineBox['background-boxtop'] - $lineBox['background-baseline-shift'];
4881 $bg_boxbottom = $this->y + $lineBox['background-boxbottom'] - $lineBox['background-baseline-shift'];
4882 $bg_boxheight = $bg_boxbottom - $bg_boxtop;
4883 }
4884 // If inline element BORDER has bounding box set by parent element:
4885 if (isset($lineBox['border-boxtop'])) {
4886 $bord_boxtop = $this->y + $lineBox['border-boxtop'] - $lineBox['border-baseline-shift'];
4887 $bord_boxbottom = $this->y + $lineBox['border-boxbottom'] - $lineBox['border-baseline-shift'];
4888 $bord_boxheight = $bord_boxbottom - $bord_boxtop;
4889 }
4890 } else {
4891 $boxtop = $this->y;
4892 $boxheight = $h;
4893 $boxbottom = $this->y + $h;
4894 $baseline_shift = 0;
4895 if ($txt != '') {
4896 // FONT SIZE - this determines the baseline caculation
4897 $bfs = $this->FontSize;
4898 //Calculate baseline Superscript and Subscript Y coordinate adjustment
4899 $bfx = $this->baselineC;
4900 $baseline = $bfx * $bfs;
4901
4902 if ($textvar & FA_SUPERSCRIPT) {
4903 $baseline_shift = $this->textparam['text-baseline'];
4904 } // mPDF 5.7.1 // mPDF 6
4905 elseif ($textvar & FA_SUBSCRIPT) {
4906 $baseline_shift = $this->textparam['text-baseline'];
4907 } // mPDF 5.7.1 // mPDF 6
4908 elseif ($this->bullet) {
4909 $baseline += ($bfx - 0.7) * $this->FontSize;
4910 }
4911
4912 // Vertical align (for Images)
4913 if ($valign == 'T') {
4914 $va = (0.5 * $bfs * $this->normalLineheight);
4915 } elseif ($valign == 'B') {
4916 $va = $h - (0.5 * $bfs * $this->normalLineheight);
4917 } else {
4918 $va = 0.5 * $h;
4919 } // Middle
4920 // ONLY SET THESE IF WANT TO CONFINE BORDER +/- FILL TO FIT FONTSIZE - NOT FULL CELL AS IS ORIGINAL FUNCTION
4921 // spanfill or spanborder are set in FlowingBlock functions
4922 if ($spanfill || !empty($this->spanborddet) || $link != '') {
4923 $exth = 0.2; // Add to fontsize to increase height of background / link / border
4924 $boxtop = $this->y + $baseline + $va - ($this->FontSize * (1 + $exth / 2) * (0.5 + $bfx));
4925 $boxheight = $this->FontSize * (1 + $exth);
4926 $boxbottom = $boxtop + $boxheight;
4927 }
4928 $glyphYorigin = $baseline + $va;
4929 }
4930 $boxtop -= $baseline_shift;
4931 $boxbottom -= $baseline_shift;
4932 $bord_boxtop = $bg_boxtop = $boxtop;
4933 $bord_boxbottom = $bg_boxbottom = $boxbottom;
4934 $bord_boxheight = $bg_boxheight = $boxheight = $boxbottom - $boxtop;
4935 }
4936
4937
4938 $bbw = $tbw = $lbw = $rbw = 0; // Border widths
4939 if (!empty($this->spanborddet)) {
4940 if (!isset($this->spanborddet['B'])) {
4941 $this->spanborddet['B'] = array('s' => 0, 'style' => '', 'w' => 0);
4942 }
4943 if (!isset($this->spanborddet['T'])) {
4944 $this->spanborddet['T'] = array('s' => 0, 'style' => '', 'w' => 0);
4945 }
4946 if (!isset($this->spanborddet['L'])) {
4947 $this->spanborddet['L'] = array('s' => 0, 'style' => '', 'w' => 0);
4948 }
4949 if (!isset($this->spanborddet['R'])) {
4950 $this->spanborddet['R'] = array('s' => 0, 'style' => '', 'w' => 0);
4951 }
4952 $bbw = $this->spanborddet['B']['w'];
4953 $tbw = $this->spanborddet['T']['w'];
4954 $lbw = $this->spanborddet['L']['w'];
4955 $rbw = $this->spanborddet['R']['w'];
4956 }
4957 if ($fill == 1 || $border == 1 || !empty($this->spanborddet)) {
4958 if (!empty($this->spanborddet)) {
4959 if ($fill == 1) {
4960 $s.=sprintf('%.3F %.3F %.3F %.3F re f ', ($this->x - $lbw) * _MPDFK, ($this->h - $bg_boxtop + $tbw) * _MPDFK, ($w + $lbw + $rbw) * _MPDFK, (-$bg_boxheight - $tbw - $bbw) * _MPDFK);
4961 }
4962 $s.= ' q ';
4963 $dashon = 3;
4964 $dashoff = 3.5;
4965 $dot = 2.5;
4966 if ($tbw) {
4967 $short = 0;
4968 if ($this->spanborddet['T']['style'] == 'dashed') {
4969 $s.=sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $tbw * $dashon * _MPDFK, $tbw * $dashoff * _MPDFK);
4970 } elseif ($this->spanborddet['T']['style'] == 'dotted') {
4971 $s.=sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $tbw * $dot * _MPDFK, -$tbw / 2 * _MPDFK);
4972 $short = $tbw / 2;
4973 } else {
4974 $s.=' 0 j 0 J [] 0 d ';
4975 }
4976 if ($this->spanborddet['T']['style'] != 'dotted') {
4977 $s .= 'q ';
4978 $s .= sprintf('%.3F %.3F m ', ($this->x - $lbw) * _MPDFK, ($this->h - $bord_boxtop + $tbw) * _MPDFK);
4979 $s .= sprintf('%.3F %.3F l ', ($this->x + $w + $rbw) * _MPDFK, ($this->h - $bord_boxtop + $tbw) * _MPDFK);
4980 $s .= sprintf('%.3F %.3F l ', ($this->x + $w) * _MPDFK, ($this->h - $bord_boxtop) * _MPDFK);
4981 $s .= sprintf('%.3F %.3F l ', ($this->x) * _MPDFK, ($this->h - $bord_boxtop) * _MPDFK);
4982 $s .= ' h W n '; // Ends path no-op & Sets the clipping path
4983 }
4984 $c = $this->SetDColor($this->spanborddet['T']['c'], true);
4985 if ($this->spanborddet['T']['style'] == 'double') {
4986 $s.=sprintf(' %s %.3F w ', $c, $tbw / 3 * _MPDFK);
4987 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * _MPDFK, ($this->h - $bord_boxtop + $tbw * 5 / 6) * _MPDFK, ($this->x + $w + $rbw) * _MPDFK, ($this->h - $bord_boxtop + $tbw * 5 / 6) * _MPDFK);
4988 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * _MPDFK, ($this->h - $bord_boxtop + $tbw / 6) * _MPDFK, ($this->x + $w + $rbw) * _MPDFK, ($this->h - $bord_boxtop + $tbw / 6) * _MPDFK);
4989 } elseif ($this->spanborddet['T']['style'] == 'dotted') {
4990 $s.=sprintf(' %s %.3F w ', $c, $tbw * _MPDFK);
4991 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * _MPDFK, ($this->h - $bord_boxtop + $tbw / 2) * _MPDFK, ($this->x + $w + $rbw - $short) * _MPDFK, ($this->h - $bord_boxtop + $tbw / 2) * _MPDFK);
4992 } else {
4993 $s.=sprintf(' %s %.3F w ', $c, $tbw * _MPDFK);
4994 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * _MPDFK, ($this->h - $bord_boxtop + $tbw / 2) * _MPDFK, ($this->x + $w + $rbw - $short) * _MPDFK, ($this->h - $bord_boxtop + $tbw / 2) * _MPDFK);
4995 }
4996 if ($this->spanborddet['T']['style'] != 'dotted') {
4997 $s .= ' Q ';
4998 }
4999 }
5000 if ($bbw) {
5001 $short = 0;
5002 if ($this->spanborddet['B']['style'] == 'dashed') {
5003 $s.=sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $bbw * $dashon * _MPDFK, $bbw * $dashoff * _MPDFK);
5004 } elseif ($this->spanborddet['B']['style'] == 'dotted') {
5005 $s.=sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $bbw * $dot * _MPDFK, -$bbw / 2 * _MPDFK);
5006 $short = $bbw / 2;
5007 } else {
5008 $s.=' 0 j 0 J [] 0 d ';
5009 }
5010 if ($this->spanborddet['B']['style'] != 'dotted') {
5011 $s .= 'q ';
5012 $s .= sprintf('%.3F %.3F m ', ($this->x - $lbw) * _MPDFK, ($this->h - $bord_boxbottom - $bbw) * _MPDFK);
5013 $s .= sprintf('%.3F %.3F l ', ($this->x + $w + $rbw) * _MPDFK, ($this->h - $bord_boxbottom - $bbw) * _MPDFK);
5014 $s .= sprintf('%.3F %.3F l ', ($this->x + $w) * _MPDFK, ($this->h - $bord_boxbottom) * _MPDFK);
5015 $s .= sprintf('%.3F %.3F l ', ($this->x) * _MPDFK, ($this->h - $bord_boxbottom) * _MPDFK);
5016 $s .= ' h W n '; // Ends path no-op & Sets the clipping path
5017 }
5018 $c = $this->SetDColor($this->spanborddet['B']['c'], true);
5019 if ($this->spanborddet['B']['style'] == 'double') {
5020 $s.=sprintf(' %s %.3F w ', $c, $bbw / 3 * _MPDFK);
5021 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * _MPDFK, ($this->h - $bord_boxbottom - $bbw / 6) * _MPDFK, ($this->x + $w + $rbw - $short) * _MPDFK, ($this->h - $bord_boxbottom - $bbw / 6) * _MPDFK);
5022 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * _MPDFK, ($this->h - $bord_boxbottom - $bbw * 5 / 6) * _MPDFK, ($this->x + $w + $rbw - $short) * _MPDFK, ($this->h - $bord_boxbottom - $bbw * 5 / 6) * _MPDFK);
5023 } elseif ($this->spanborddet['B']['style'] == 'dotted') {
5024 $s.=sprintf(' %s %.3F w ', $c, $bbw * _MPDFK);
5025 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * _MPDFK, ($this->h - $bord_boxbottom - $bbw / 2) * _MPDFK, ($this->x + $w + $rbw - $short) * _MPDFK, ($this->h - $bord_boxbottom - $bbw / 2) * _MPDFK);
5026 } else {
5027 $s.=sprintf(' %s %.3F w ', $c, $bbw * _MPDFK);
5028 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * _MPDFK, ($this->h - $bord_boxbottom - $bbw / 2) * _MPDFK, ($this->x + $w + $rbw - $short) * _MPDFK, ($this->h - $bord_boxbottom - $bbw / 2) * _MPDFK);
5029 }
5030 if ($this->spanborddet['B']['style'] != 'dotted') {
5031 $s .= ' Q ';
5032 }
5033 }
5034 if ($lbw) {
5035 $short = 0;
5036 if ($this->spanborddet['L']['style'] == 'dashed') {
5037 $s.=sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $lbw * $dashon * _MPDFK, $lbw * $dashoff * _MPDFK);
5038 } elseif ($this->spanborddet['L']['style'] == 'dotted') {
5039 $s.=sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $lbw * $dot * _MPDFK, -$lbw / 2 * _MPDFK);
5040 $short = $lbw / 2;
5041 } else {
5042 $s.=' 0 j 0 J [] 0 d ';
5043 }
5044 if ($this->spanborddet['L']['style'] != 'dotted') {
5045 $s .= 'q ';
5046 $s .= sprintf('%.3F %.3F m ', ($this->x - $lbw) * _MPDFK, ($this->h - $bord_boxbottom - $bbw) * _MPDFK);
5047 $s .= sprintf('%.3F %.3F l ', ($this->x) * _MPDFK, ($this->h - $bord_boxbottom) * _MPDFK);
5048 $s .= sprintf('%.3F %.3F l ', ($this->x) * _MPDFK, ($this->h - $bord_boxtop) * _MPDFK);
5049 $s .= sprintf('%.3F %.3F l ', ($this->x - $lbw) * _MPDFK, ($this->h - $bord_boxtop + $tbw) * _MPDFK);
5050 $s .= ' h W n '; // Ends path no-op & Sets the clipping path
5051 }
5052 $c = $this->SetDColor($this->spanborddet['L']['c'], true);
5053 if ($this->spanborddet['L']['style'] == 'double') {
5054 $s.=sprintf(' %s %.3F w ', $c, $lbw / 3 * _MPDFK);
5055 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw / 6) * _MPDFK, ($this->h - $bord_boxtop + $tbw) * _MPDFK, ($this->x - $lbw / 6) * _MPDFK, ($this->h - $bord_boxbottom - $bbw + $short) * _MPDFK);
5056 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw * 5 / 6) * _MPDFK, ($this->h - $bord_boxtop + $tbw) * _MPDFK, ($this->x - $lbw * 5 / 6) * _MPDFK, ($this->h - $bord_boxbottom - $bbw + $short) * _MPDFK);
5057 } elseif ($this->spanborddet['L']['style'] == 'dotted') {
5058 $s.=sprintf(' %s %.3F w ', $c, $lbw * _MPDFK);
5059 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw / 2) * _MPDFK, ($this->h - $bord_boxtop + $tbw) * _MPDFK, ($this->x - $lbw / 2) * _MPDFK, ($this->h - $bord_boxbottom - $bbw + $short) * _MPDFK);
5060 } else {
5061 $s.=sprintf(' %s %.3F w ', $c, $lbw * _MPDFK);
5062 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw / 2) * _MPDFK, ($this->h - $bord_boxtop + $tbw) * _MPDFK, ($this->x - $lbw / 2) * _MPDFK, ($this->h - $bord_boxbottom - $bbw + $short) * _MPDFK);
5063 }
5064 if ($this->spanborddet['L']['style'] != 'dotted') {
5065 $s .= ' Q ';
5066 }
5067 }
5068 if ($rbw) {
5069 $short = 0;
5070 if ($this->spanborddet['R']['style'] == 'dashed') {
5071 $s.=sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $rbw * $dashon * _MPDFK, $rbw * $dashoff * _MPDFK);
5072 } elseif ($this->spanborddet['R']['style'] == 'dotted') {
5073 $s.=sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $rbw * $dot * _MPDFK, -$rbw / 2 * _MPDFK);
5074 $short = $rbw / 2;
5075 } else {
5076 $s.=' 0 j 0 J [] 0 d ';
5077 }
5078 if ($this->spanborddet['R']['style'] != 'dotted') {
5079 $s .= 'q ';
5080 $s .= sprintf('%.3F %.3F m ', ($this->x + $w + $rbw) * _MPDFK, ($this->h - $bord_boxbottom - $bbw) * _MPDFK);
5081 $s .= sprintf('%.3F %.3F l ', ($this->x + $w) * _MPDFK, ($this->h - $bord_boxbottom) * _MPDFK);
5082 $s .= sprintf('%.3F %.3F l ', ($this->x + $w) * _MPDFK, ($this->h - $bord_boxtop) * _MPDFK);
5083 $s .= sprintf('%.3F %.3F l ', ($this->x + $w + $rbw) * _MPDFK, ($this->h - $bord_boxtop + $tbw) * _MPDFK);
5084 $s .= ' h W n '; // Ends path no-op & Sets the clipping path
5085 }
5086 $c = $this->SetDColor($this->spanborddet['R']['c'], true);
5087 if ($this->spanborddet['R']['style'] == 'double') {
5088 $s.=sprintf(' %s %.3F w ', $c, $rbw / 3 * _MPDFK);
5089 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x + $w + $rbw / 6) * _MPDFK, ($this->h - $bord_boxtop + $tbw) * _MPDFK, ($this->x + $w + $rbw / 6) * _MPDFK, ($this->h - $bord_boxbottom - $bbw + $short) * _MPDFK);
5090 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x + $w + $rbw * 5 / 6) * _MPDFK, ($this->h - $bord_boxtop + $tbw) * _MPDFK, ($this->x + $w + $rbw * 5 / 6) * _MPDFK, ($this->h - $bord_boxbottom - $bbw + $short) * _MPDFK);
5091 } elseif ($this->spanborddet['R']['style'] == 'dotted') {
5092 $s.=sprintf(' %s %.3F w ', $c, $rbw * _MPDFK);
5093 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x + $w + $rbw / 2) * _MPDFK, ($this->h - $bord_boxtop + $tbw) * _MPDFK, ($this->x + $w + $rbw / 2) * _MPDFK, ($this->h - $bord_boxbottom - $bbw + $short) * _MPDFK);
5094 } else {
5095 $s.=sprintf(' %s %.3F w ', $c, $rbw * _MPDFK);
5096 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x + $w + $rbw / 2) * _MPDFK, ($this->h - $bord_boxtop + $tbw) * _MPDFK, ($this->x + $w + $rbw / 2) * _MPDFK, ($this->h - $bord_boxbottom - $bbw + $short) * _MPDFK);
5097 }
5098 if ($this->spanborddet['R']['style'] != 'dotted') {
5099 $s .= ' Q ';
5100 }
5101 }
5102 $s.= ' Q ';
5103 } else { // If "border", does not come from WriteFlowingBlock or FinishFlowingBlock
5104 if ($fill == 1)
5105 $op = ($border == 1) ? 'B' : 'f';
5106 else
5107 $op = 'S';
5108 $s.=sprintf('%.3F %.3F %.3F %.3F re %s ', $this->x * _MPDFK, ($this->h - $bg_boxtop) * _MPDFK, $w * _MPDFK, -$bg_boxheight * _MPDFK, $op);
5109 }
5110 }
5111
5112 if (is_string($border)) { // If "border", does not come from WriteFlowingBlock or FinishFlowingBlock
5113 $x = $this->x;
5114 $y = $this->y;
5115 if (is_int(strpos($border, 'L')))
5116 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', $x * _MPDFK, ($this->h - $bord_boxtop) * _MPDFK, $x * _MPDFK, ($this->h - ($bord_boxbottom)) * _MPDFK);
5117 if (is_int(strpos($border, 'T')))
5118 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', $x * _MPDFK, ($this->h - $bord_boxtop) * _MPDFK, ($x + $w) * _MPDFK, ($this->h - $bord_boxtop) * _MPDFK);
5119 if (is_int(strpos($border, 'R')))
5120 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', ($x + $w) * _MPDFK, ($this->h - $bord_boxtop) * _MPDFK, ($x + $w) * _MPDFK, ($this->h - ($bord_boxbottom)) * _MPDFK);
5121 if (is_int(strpos($border, 'B')))
5122 $s.=sprintf('%.3F %.3F m %.3F %.3F l S ', $x * _MPDFK, ($this->h - ($bord_boxbottom)) * _MPDFK, ($x + $w) * _MPDFK, ($this->h - ($bord_boxbottom)) * _MPDFK);
5123 }
5124
5125 if ($txt != '') {
5126
5127
5128 if ($exactWidth)
5129 $stringWidth = $w;
5130 else
5131 $stringWidth = $this->GetStringWidth($txt, true, $OTLdata, $textvar) + ( $this->charspacing * mb_strlen($txt, $this->mb_enc) / _MPDFK ) + ( $this->ws * mb_substr_count($txt, ' ', $this->mb_enc) / _MPDFK );
5132
5133 // Set x OFFSET FOR PRINTING
5134 if ($align == 'R') {
5135 $dx = $w - $this->cMarginR - $stringWidth - $lcpaddingR;
5136 } elseif ($align == 'C') {
5137 $dx = (($w - $stringWidth ) / 2);
5138 } elseif ($align == 'L' or $align == 'J')
5139 $dx = $this->cMarginL + $lcpaddingL;
5140 else
5141 $dx = 0;
5142
5143 if ($this->ColorFlag)
5144 $s .='q ' . $this->TextColor . ' ';
5145
5146 // OUTLINE
5147 if (isset($this->textparam['outline-s']) && $this->textparam['outline-s'] && !($textvar & FC_SMALLCAPS)) { // mPDF 5.7.1
5148 $s .=' ' . sprintf('%.3F w', $this->LineWidth * _MPDFK) . ' ';
5149 $s .=" $this->DrawColor ";
5150 $s .=" 2 Tr ";
5151 } elseif ($this->falseBoldWeight && strpos($this->ReqFontStyle, "B") !== false && strpos($this->FontStyle, "B") === false && !($textvar & FC_SMALLCAPS)) { // can't use together with OUTLINE or Small Caps // mPDF 5.7.1 ??? why not with SmallCaps ???
5152 $s .= ' 2 Tr 1 J 1 j ';
5153 $s .= ' ' . sprintf('%.3F w', ($this->FontSize / 130) * _MPDFK * $this->falseBoldWeight) . ' ';
5154 $tc = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
5155 if ($this->FillColor != $tc) {
5156 $s .= ' ' . $tc . ' ';
5157 } // stroke (outline) = same colour as text(fill)
5158 } else {
5159 $s .=" 0 Tr ";
5160 }
5161
5162 if (strpos($this->ReqFontStyle, "I") !== false && strpos($this->FontStyle, "I") === false) { // Artificial italic
5163 $aix = '1 0 0.261799 1 %.3F %.3F Tm ';
5164 } else {
5165 $aix = '%.3F %.3F Td ';
5166 }
5167
5168 $px = ($this->x + $dx) * _MPDFK;
5169 $py = ($this->h - ($this->y + $glyphYorigin - $baseline_shift)) * _MPDFK;
5170
5171 // THE TEXT
5172 $txt2 = $txt;
5173 $sub = '';
5174 $this->CurrentFont['used'] = true;
5175
5176 /* * ************** SIMILAR TO Text() ************************ */
5177
5178 // IF corefonts AND NOT SmCaps AND NOT Kerning
5179 // Just output text; charspacing and wordspacing already set by charspacing (Tc) and ws (Tw)
5180 if ($this->usingCoreFont && !($textvar & FC_SMALLCAPS) && !($textvar & FC_KERNING)) {
5181 $txt2 = $this->_escape($txt2);
5182 $sub .=sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
5183 }
5184
5185
5186 // IF NOT corefonts AND NO wordspacing AND NOT SIP/SMP AND NOT SmCaps AND NOT Kerning AND NOT OTL
5187 // Just output text
5188 elseif (!$this->usingCoreFont && !$this->ws && !($textvar & FC_SMALLCAPS) && !($textvar & FC_KERNING) && !(isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && !empty($OTLdata['GPOSinfo']))) {
5189 // IF SIP/SMP
5190 if ((isset($this->CurrentFont['sip']) && $this->CurrentFont['sip']) || (isset($this->CurrentFont['smp']) && $this->CurrentFont['smp'])) {
5191 $txt2 = $this->UTF8toSubset($txt2);
5192 $sub .=sprintf('BT ' . $aix . ' %s Tj ET', $px, $py, $txt2);
5193 }
5194 // NOT SIP/SMP
5195 else {
5196 $txt2 = $this->UTF8ToUTF16BE($txt2, false);
5197 $txt2 = $this->_escape($txt2);
5198 $sub .=sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
5199 }
5200 }
5201
5202
5203 // IF NOT corefonts AND IS wordspacing AND NOT SIP AND NOT SmCaps AND NOT Kerning AND NOT OTL
5204 // Output text word by word with an adjustment to the intercharacter spacing for SPACEs to form word spacing
5205 // IF multibyte - Tw has no effect - need to do word spacing using an adjustment before each space
5206 elseif (!$this->usingCoreFont && $this->ws && !((isset($this->CurrentFont['sip']) && $this->CurrentFont['sip']) || (isset($this->CurrentFont['smp']) && $this->CurrentFont['smp'])) && !($textvar & FC_SMALLCAPS) && !($textvar & FC_KERNING) && !(isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && (!empty($OTLdata['GPOSinfo']) || (strpos($OTLdata['group'], 'M') !== false && $this->charspacing)) )) {
5207 $space = " ";
5208 $space = $this->UTF8ToUTF16BE($space, false);
5209 $space = $this->_escape($space);
5210 $sub .=sprintf('BT ' . $aix . ' %.3F Tc [', $px, $py, $this->charspacing);
5211 $t = explode(' ', $txt2);
5212 $numt = count($t);
5213 for ($i = 0; $i < $numt; $i++) {
5214 $tx = $t[$i];
5215 $tx = $this->UTF8ToUTF16BE($tx, false);
5216 $tx = $this->_escape($tx);
5217 $sub .=sprintf('(%s) ', $tx);
5218 if (($i + 1) < $numt) {
5219 $adj = -($this->ws) * 1000 / $this->FontSizePt;
5220 $sub .=sprintf('%d(%s) ', $adj, $space);
5221 }
5222 }
5223 $sub .='] TJ ';
5224 $sub .=' ET';
5225 }
5226
5227
5228 // ELSE (IF SmCaps || Kerning || OTL) [corefonts or not corefonts; SIP or SMP or BMP]
5229 else {
5230 $sub = $this->applyGPOSpdf($txt, $aix, $px, $py, $OTLdata, $textvar);
5231 }
5232
5233 /* * ************** END SIMILAR TO Text() ************************ */
5234
5235 if ($this->shrin_k > 1) {
5236 $shrin_k = $this->shrin_k;
5237 } else {
5238 $shrin_k = 1;
5239 }
5240 // UNDERLINE
5241 if ($textvar & FD_UNDERLINE) { // mPDF 5.7.1 // mPDF 6
5242 // mPDF 5.7.3 inline text-decoration parameters
5243 $c = $this->textparam['u-decoration']['color'];
5244 if ($this->FillColor != $c) {
5245 $sub .= ' ' . $c . ' ';
5246 }
5247 // mPDF 5.7.3 inline text-decoration parameters
5248 $decorationfontkey = $this->textparam['u-decoration']['fontkey'];
5249 $decorationfontsize = $this->textparam['u-decoration']['fontsize'] / $shrin_k;
5250 if (isset($this->fonts[$decorationfontkey]['ut']) && $this->fonts[$decorationfontkey]['ut']) {
5251 $ut = $this->fonts[$decorationfontkey]['ut'] / 1000 * $decorationfontsize;
5252 } else {
5253 $ut = 60 / 1000 * $decorationfontsize;
5254 }
5255 if (isset($this->fonts[$decorationfontkey]['up']) && $this->fonts[$decorationfontkey]['up']) {
5256 $up = $this->fonts[$decorationfontkey]['up'];
5257 } else {
5258 $up = -100;
5259 }
5260 $adjusty = (-$up / 1000 * $decorationfontsize) + $ut / 2;
5261 $ubaseline = $glyphYorigin - $this->textparam['u-decoration']['baseline'] / $shrin_k;
5262 $olw = $this->LineWidth;
5263 $sub .=' ' . (sprintf(' %.3F w 0 j 0 J ', $ut * _MPDFK));
5264 $sub .=' ' . $this->_dounderline($this->x + $dx, $this->y + $ubaseline + $adjusty, $txt, $OTLdata, $textvar);
5265 $sub .=' ' . (sprintf(' %.3F w 2 j 2 J ', $olw * _MPDFK));
5266 if ($this->FillColor != $c) {
5267 $sub .= ' ' . $this->FillColor . ' ';
5268 }
5269 }
5270
5271 // STRIKETHROUGH
5272 if ($textvar & FD_LINETHROUGH) { // mPDF 5.7.1 // mPDF 6
5273 // mPDF 5.7.3 inline text-decoration parameters
5274 $c = $this->textparam['s-decoration']['color'];
5275 if ($this->FillColor != $c) {
5276 $sub .= ' ' . $c . ' ';
5277 }
5278 // mPDF 5.7.3 inline text-decoration parameters
5279 $decorationfontkey = $this->textparam['s-decoration']['fontkey'];
5280 $decorationfontsize = $this->textparam['s-decoration']['fontsize'] / $shrin_k;
5281 // Use yStrikeoutSize from OS/2 if available
5282 if (isset($this->fonts[$decorationfontkey]['strs']) && $this->fonts[$decorationfontkey]['strs']) {
5283 $ut = $this->fonts[$decorationfontkey]['strs'] / 1000 * $decorationfontsize;
5284 }
5285 // else use underlineThickness from post if available
5286 elseif (isset($this->fonts[$decorationfontkey]['ut']) && $this->fonts[$decorationfontkey]['ut']) {
5287 $ut = $this->fonts[$decorationfontkey]['ut'] / 1000 * $decorationfontsize;
5288 } else {
5289 $ut = 50 / 1000 * $decorationfontsize;
5290 }
5291 // Use yStrikeoutPosition from OS/2 if available
5292 if (isset($this->fonts[$decorationfontkey]['strp']) && $this->fonts[$decorationfontkey]['strp']) {
5293 $up = $this->fonts[$decorationfontkey]['strp'];
5294 $adjusty = (-$up / 1000 * $decorationfontsize);
5295 }
5296 // else use a fraction ($this->baselineS) of CapHeight
5297 else {
5298 if (isset($this->fonts[$decorationfontkey]['desc']['CapHeight']) && $this->fonts[$decorationfontkey]['desc']['CapHeight']) {
5299 $ch = $this->fonts[$decorationfontkey]['desc']['CapHeight'];
5300 } else {
5301 $ch = 700;
5302 }
5303 $adjusty = (-$ch / 1000 * $decorationfontsize) * $this->baselineS;
5304 }
5305
5306 $sbaseline = $glyphYorigin - $this->textparam['s-decoration']['baseline'] / $shrin_k;
5307 $olw = $this->LineWidth;
5308 $sub .=' ' . (sprintf(' %.3F w 0 j 0 J ', $ut * _MPDFK));
5309 $sub .=' ' . $this->_dounderline($this->x + $dx, $this->y + $sbaseline + $adjusty, $txt, $OTLdata, $textvar);
5310 $sub .=' ' . (sprintf(' %.3F w 2 j 2 J ', $olw * _MPDFK));
5311 if ($this->FillColor != $c) {
5312 $sub .= ' ' . $this->FillColor . ' ';
5313 }
5314 }
5315
5316 // mPDF 5.7.3 inline text-decoration parameters
5317 // OVERLINE
5318 if ($textvar & FD_OVERLINE) { // mPDF 5.7.1 // mPDF 6
5319 // mPDF 5.7.3 inline text-decoration parameters
5320 $c = $this->textparam['o-decoration']['color'];
5321 if ($this->FillColor != $c) {
5322 $sub .= ' ' . $c . ' ';
5323 }
5324 // mPDF 5.7.3 inline text-decoration parameters
5325 $decorationfontkey = $this->textparam['o-decoration']['fontkey'] / $shrin_k;
5326 $decorationfontsize = $this->textparam['o-decoration']['fontsize'];
5327 if (isset($this->fonts[$decorationfontkey]['ut']) && $this->fonts[$decorationfontkey]['ut']) {
5328 $ut = $this->fonts[$decorationfontkey]['ut'] / 1000 * $decorationfontsize;
5329 } else {
5330 $ut = 60 / 1000 * $decorationfontsize;
5331 }
5332 if (isset($this->fonts[$decorationfontkey]['desc']['CapHeight']) && $this->fonts[$decorationfontkey]['desc']['CapHeight']) {
5333 $ch = $this->fonts[$decorationfontkey]['desc']['CapHeight'];
5334 } else {
5335 $ch = 700;
5336 }
5337 $adjusty = (-$ch / 1000 * $decorationfontsize) * $this->baselineO;
5338 $obaseline = $glyphYorigin - $this->textparam['o-decoration']['baseline'] / $shrin_k;
5339 $olw = $this->LineWidth;
5340 $sub .=' ' . (sprintf(' %.3F w 0 j 0 J ', $ut * _MPDFK));
5341 $sub .=' ' . $this->_dounderline($this->x + $dx, $this->y + $obaseline + $adjusty, $txt, $OTLdata, $textvar);
5342 $sub .=' ' . (sprintf(' %.3F w 2 j 2 J ', $olw * _MPDFK));
5343 if ($this->FillColor != $c) {
5344 $sub .= ' ' . $this->FillColor . ' ';
5345 }
5346 }
5347
5348 // TEXT SHADOW
5349 if ($this->textshadow) { // First to process is last in CSS comma separated shadows
5350 foreach ($this->textshadow AS $ts) {
5351 $s .= ' q ';
5352 $s .= $this->SetTColor($ts['col'], true) . "\n";
5353 if ($ts['col'][0] == 5 && ord($ts['col'][4]) < 100) { // RGBa
5354 $s .= $this->SetAlpha(ord($ts['col'][4]) / 100, 'Normal', true, 'F') . "\n";
5355 } elseif ($ts['col'][0] == 6 && ord($ts['col'][5]) < 100) { // CMYKa
5356 $s .= $this->SetAlpha(ord($ts['col'][5]) / 100, 'Normal', true, 'F') . "\n";
5357 } elseif ($ts['col'][0] == 1 && $ts['col'][2] == 1 && ord($ts['col'][3]) < 100) { // Gray
5358 $s .= $this->SetAlpha(ord($ts['col'][3]) / 100, 'Normal', true, 'F') . "\n";
5359 }
5360 $s .= sprintf(' 1 0 0 1 %.4F %.4F cm', $ts['x'] * _MPDFK, -$ts['y'] * _MPDFK) . "\n";
5361 $s .= $sub;
5362 $s .= ' Q ';
5363 }
5364 }
5365
5366 $s .= $sub;
5367
5368 // COLOR
5369 if ($this->ColorFlag)
5370 $s .=' Q';
5371
5372 // LINK
5373 if ($link != '') {
5374 $this->Link($this->x, $boxtop, $w, $boxheight, $link);
5375 }
5376 }
5377 if ($s)
5378 $this->_out($s);
5379
5380 // WORD SPACING
5381 if ($this->ws && !$this->usingCoreFont) {
5382 $this->_out(sprintf('BT %.3F Tc ET', $this->charspacing));
5383 }
5384 $this->lasth = $h;
5385 if (strpos($txt, "\n") !== false)
5386 $ln = 1; // cell recognizes \n from <BR> tag
5387 if ($ln > 0) {
5388 //Go to next line
5389 $this->y += $h;
5390 if ($ln == 1) {
5391 //Move to next line
5392 if ($currentx != 0) {
5393 $this->x = $currentx;
5394 } else {
5395 $this->x = $this->lMargin;
5396 }
5397 }
5398 } else
5399 $this->x+=$w;
5400 }
5401
5402 function applyGPOSpdf($txt, $aix, $x, $y, $OTLdata, $textvar = 0)
5403 {
5404 // Generate PDF string
5405 //==============================
5406 if ((isset($this->CurrentFont['sip']) && $this->CurrentFont['sip']) || (isset($this->CurrentFont['smp']) && $this->CurrentFont['smp'])) {
5407 $sipset = true;
5408 } else {
5409 $sipset = false;
5410 }
5411
5412 if ($textvar & FC_SMALLCAPS) {
5413 $smcaps = true;
5414 } // IF SmallCaps using transformation, NOT OTL
5415 else {
5416 $smcaps = false;
5417 }
5418
5419 if ($sipset) {
5420 $fontid = $last_fontid = $original_fontid = $this->CurrentFont['subsetfontids'][0];
5421 } else {
5422 $fontid = $last_fontid = $original_fontid = $this->CurrentFont['i'];
5423 }
5424 $SmallCapsON = false; // state: uppercase/not
5425 $lastSmallCapsON = false; // state: uppercase/not
5426 $last_fontsize = $fontsize = $this->FontSizePt;
5427 $last_fontstretch = $fontstretch = 100;
5428 $groupBreak = false;
5429
5430 $unicode = $this->UTF8StringToArray($txt);
5431
5432 $GPOSinfo = (isset($OTLdata['GPOSinfo']) ? $OTLdata['GPOSinfo'] : array());
5433 $charspacing = ($this->charspacing * 1000 / $this->FontSizePt);
5434 $wordspacing = ($this->ws * 1000 / $this->FontSizePt);
5435
5436 $XshiftBefore = 0;
5437 $XshiftAfter = 0;
5438 $lastYPlacement = 0;
5439
5440 if ($sipset) {
5441 // mPDF 6 DELETED ********
5442 // $txt= preg_replace('/'.preg_quote($this->aliasNbPg,'/').'/', chr(7), $txt); // ? Need to adjust OTL info
5443 // $txt= preg_replace('/'.preg_quote($this->aliasNbPgGp,'/').'/', chr(8), $txt); // ? Need to adjust OTL info
5444 $tj = '<';
5445 } else {
5446 $tj = '(';
5447 }
5448
5449 for ($i = 0; $i < count($unicode); $i++) {
5450 $c = $unicode[$i];
5451 $tx = '';
5452 $XshiftBefore = $XshiftAfter;
5453 $XshiftAfter = 0;
5454 $YPlacement = 0;
5455 $groupBreak = false;
5456 $kashida = 0;
5457 if (!empty($OTLdata)) {
5458 // YPlacement from GPOS
5459 if (isset($GPOSinfo[$i]['YPlacement']) && $GPOSinfo[$i]['YPlacement']) {
5460 $YPlacement = $GPOSinfo[$i]['YPlacement'] * $this->FontSizePt / $this->CurrentFont['unitsPerEm'];
5461 $groupBreak = true;
5462 }
5463 // XPlacement from GPOS
5464 if (isset($GPOSinfo[$i]['XPlacement']) && $GPOSinfo[$i]['XPlacement']) {
5465
5466 if (!isset($GPOSinfo[$i]['wDir']) || $GPOSinfo[$i]['wDir'] != 'RTL') {
5467 if (isset($GPOSinfo[$i]['BaseWidth'])) {
5468 $GPOSinfo[$i]['XPlacement'] -= $GPOSinfo[$i]['BaseWidth'];
5469 }
5470 }
5471
5472 // Convert to PDF Text space (thousandths of a unit );
5473 $XshiftBefore += $GPOSinfo[$i]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
5474 $XshiftAfter += -$GPOSinfo[$i]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
5475 }
5476
5477 // Kashida from GPOS
5478 // Kashida is set as an absolute length value, but to adjust text needs to be converted to
5479 // font-related size
5480 if (isset($GPOSinfo[$i]['kashida_space']) && $GPOSinfo[$i]['kashida_space']) {
5481 $kashida = $GPOSinfo[$i]['kashida_space'];
5482 }
5483
5484 if ($c == 32) { // word spacing
5485 $XshiftAfter += $wordspacing;
5486 }
5487
5488 if (substr($OTLdata['group'], ($i + 1), 1) != 'M') { // Don't add inter-character spacing before Marks
5489 $XshiftAfter += $charspacing;
5490 }
5491
5492 // ...applyGPOSpdf...
5493 // XAdvance from GPOS - Convert to PDF Text space (thousandths of a unit );
5494 if (((isset($GPOSinfo[$i]['wDir']) && $GPOSinfo[$i]['wDir'] != 'RTL') || !isset($GPOSinfo[$i]['wDir'])) && isset($GPOSinfo[$i]['XAdvanceL']) && $GPOSinfo[$i]['XAdvanceL']) {
5495 $XshiftAfter += $GPOSinfo[$i]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
5496 } elseif (isset($GPOSinfo[$i]['wDir']) && $GPOSinfo[$i]['wDir'] == 'RTL' && isset($GPOSinfo[$i]['XAdvanceR']) && $GPOSinfo[$i]['XAdvanceR']) {
5497 $XshiftAfter += $GPOSinfo[$i]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
5498 }
5499 }
5500 // Character & Word spacing - if NOT OTL
5501 else {
5502 $XshiftAfter += $charspacing;
5503 if ($c == 32) {
5504 $XshiftAfter += $wordspacing;
5505 }
5506 }
5507
5508 // IF Kerning done using pairs rather than OTL
5509 if ($textvar & FC_KERNING) {
5510 if ($i > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]])) {
5511 $XshiftBefore += $this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]];
5512 }
5513 }
5514
5515 if ($YPlacement != $lastYPlacement) {
5516 $groupBreak = true;
5517 }
5518
5519 if ($XshiftBefore) { // +ve value in PDF moves to the left
5520 // If Fontstretch is ongoing, need to adjust X adjustments because these will be stretched out.
5521 $XshiftBefore *= 100 / $last_fontstretch;
5522 if ($sipset) {
5523 $tj .= sprintf('>%d<', (-$XshiftBefore));
5524 } else {
5525 $tj .= sprintf(')%d(', (-$XshiftBefore));
5526 }
5527 }
5528
5529 // Small-Caps
5530 if ($smcaps) {
5531 if (isset($this->upperCase[$c])) {
5532 $c = $this->upperCase[$c];
5533 //$this->CurrentFont['subset'][$this->upperCase[$c]] = $this->upperCase[$c]; // add the CAP to subset
5534 $SmallCapsON = true;
5535 // For $sipset
5536 if (!$lastSmallCapsON) { // Turn ON SmallCaps
5537 $groupBreak = true;
5538 $fontstretch = $this->smCapsStretch;
5539 $fontsize = $this->FontSizePt * $this->smCapsScale;
5540 }
5541 } else {
5542 $SmallCapsON = false;
5543 if ($lastSmallCapsON) { // Turn OFF SmallCaps
5544 $groupBreak = true;
5545 $fontstretch = 100;
5546 $fontsize = $this->FontSizePt;
5547 }
5548 }
5549 }
5550
5551 // Prepare Text and Select Font ID
5552 if ($sipset) {
5553 // mPDF 6 DELETED ********
5554 //if ($c == 7 || $c == 8) {
5555 // if ($original_fontid != $last_fontid) {
5556 // $groupBreak = true;
5557 // $fontid = $original_fontid;
5558 // }
5559 // if ($c == 7) { $tj .= $this->aliasNbPgHex; }
5560 // else { $tj .= $this->aliasNbPgGpHex; }
5561 // continue;
5562 //}
5563 for ($j = 0; $j < 99; $j++) {
5564 $init = array_search($c, $this->CurrentFont['subsets'][$j]);
5565 if ($init !== false) {
5566 if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
5567 $groupBreak = true;
5568 $fontid = $this->CurrentFont['subsetfontids'][$j];
5569 }
5570 $tx = sprintf("%02s", strtoupper(dechex($init)));
5571 break;
5572 } elseif (count($this->CurrentFont['subsets'][$j]) < 255) {
5573 $n = count($this->CurrentFont['subsets'][$j]);
5574 $this->CurrentFont['subsets'][$j][$n] = $c;
5575 if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
5576 $groupBreak = true;
5577 $fontid = $this->CurrentFont['subsetfontids'][$j];
5578 }
5579 $tx = sprintf("%02s", strtoupper(dechex($n)));
5580 break;
5581 } elseif (!isset($this->CurrentFont['subsets'][($j + 1)])) {
5582 $this->CurrentFont['subsets'][($j + 1)] = array(0 => 0);
5583 $this->CurrentFont['subsetfontids'][($j + 1)] = count($this->fonts) + $this->extraFontSubsets + 1;
5584 $this->extraFontSubsets++;
5585 }
5586 }
5587 } else {
5588 $tx = code2utf($c);
5589 if ($this->usingCoreFont) {
5590 $tx = utf8_decode($tx);
5591 } else {
5592 $tx = $this->UTF8ToUTF16BE($tx, false);
5593 }
5594 $tx = $this->_escape($tx);
5595 }
5596
5597 // If any settings require a new Text Group
5598 if ($groupBreak || $fontstretch != $last_fontstretch) {
5599 if ($sipset) {
5600 $tj .= '>] TJ ';
5601 } else {
5602 $tj .= ')] TJ ';
5603 }
5604 if ($fontid != $last_fontid || $fontsize != $last_fontsize) {
5605 $tj .= sprintf(' /F%d %.3F Tf ', $fontid, $fontsize);
5606 }
5607 if ($fontstretch != $last_fontstretch) {
5608 $tj .= sprintf('%d Tz ', $fontstretch);
5609 }
5610 if ($YPlacement != $lastYPlacement) {
5611 $tj .= sprintf('%.3F Ts ', $YPlacement);
5612 }
5613 if ($sipset) {
5614 $tj .= '[<';
5615 } else {
5616 $tj .= '[(';
5617 }
5618 }
5619
5620 // Output the code for the txt character
5621 $tj .= $tx;
5622 $lastSmallCapsON = $SmallCapsON;
5623 $last_fontid = $fontid;
5624 $last_fontsize = $fontsize;
5625 $last_fontstretch = $fontstretch;
5626
5627 // Kashida
5628 if ($kashida) {
5629 $c = 0x0640; // add the Tatweel U+0640
5630 if (isset($this->CurrentFont['subset'])) {
5631 $this->CurrentFont['subset'][$c] = $c;
5632 }
5633 $kashida *= 1000 / $this->FontSizePt;
5634 $tatw = $this->_getCharWidth($this->CurrentFont['cw'], 0x0640);
5635
5636 // Get YPlacement from next Base character
5637 $nextbase = $i + 1;
5638 while ($OTLdata['group'][$nextbase] != 'C') {
5639 $nextbase++;
5640 }
5641 if (isset($GPOSinfo[$nextbase]) && isset($GPOSinfo[$nextbase]['YPlacement']) && $GPOSinfo[$nextbase]['YPlacement']) {
5642 $YPlacement = $GPOSinfo[$nextbase]['YPlacement'] * $this->FontSizePt / $this->CurrentFont['unitsPerEm'];
5643 }
5644
5645 // Prepare Text and Select Font ID
5646 if ($sipset) {
5647 for ($j = 0; $j < 99; $j++) {
5648 $init = array_search($c, $this->CurrentFont['subsets'][$j]);
5649 if ($init !== false) {
5650 if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
5651 $fontid = $this->CurrentFont['subsetfontids'][$j];
5652 }
5653 $tx = sprintf("%02s", strtoupper(dechex($init)));
5654 break;
5655 } elseif (count($this->CurrentFont['subsets'][$j]) < 255) {
5656 $n = count($this->CurrentFont['subsets'][$j]);
5657 $this->CurrentFont['subsets'][$j][$n] = $c;
5658 if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
5659 $fontid = $this->CurrentFont['subsetfontids'][$j];
5660 }
5661 $tx = sprintf("%02s", strtoupper(dechex($n)));
5662 break;
5663 } elseif (!isset($this->CurrentFont['subsets'][($j + 1)])) {
5664 $this->CurrentFont['subsets'][($j + 1)] = array(0 => 0);
5665 $this->CurrentFont['subsetfontids'][($j + 1)] = count($this->fonts) + $this->extraFontSubsets + 1;
5666 $this->extraFontSubsets++;
5667 }
5668 }
5669 } else {
5670 $tx = code2utf($c);
5671 $tx = $this->UTF8ToUTF16BE($tx, false);
5672 $tx = $this->_escape($tx);
5673 }
5674
5675 if ($kashida > $tatw) {
5676 // Insert multiple tatweel characters, repositioning the last one to give correct total length
5677 $fontstretch = 100;
5678 $nt = intval($kashida / $tatw);
5679 $nudgeback = (($nt + 1) * $tatw) - $kashida;
5680 $optx = str_repeat($tx, $nt);
5681 if ($sipset) {
5682 $optx .= sprintf('>%d<', ($nudgeback));
5683 } else {
5684 $optx .= sprintf(')%d(', ($nudgeback));
5685 }
5686 $optx .= $tx; // #last
5687 } else {
5688 // Insert single tatweel character and use fontstretch to get correct length
5689 $fontstretch = ($kashida / $tatw) * 100;
5690 $optx = $tx;
5691 }
5692
5693 if ($sipset) {
5694 $tj .= '>] TJ ';
5695 } else {
5696 $tj .= ')] TJ ';
5697 }
5698 if ($fontid != $last_fontid || $fontsize != $last_fontsize) {
5699 $tj .= sprintf(' /F%d %.3F Tf ', $fontid, $fontsize);
5700 }
5701 if ($fontstretch != $last_fontstretch) {
5702 $tj .= sprintf('%d Tz ', $fontstretch);
5703 }
5704 $tj .= sprintf('%.3F Ts ', $YPlacement);
5705 if ($sipset) {
5706 $tj .= '[<';
5707 } else {
5708 $tj .= '[(';
5709 }
5710
5711 // Output the code for the txt character(s)
5712 $tj .= $optx;
5713 $last_fontid = $fontid;
5714 $last_fontstretch = $fontstretch;
5715 $fontstretch = 100;
5716 }
5717
5718 $lastYPlacement = $YPlacement;
5719 }
5720
5721
5722 // Finish up
5723 if ($sipset) {
5724 $tj .= '>';
5725 if ($XshiftAfter) {
5726 $tj .= sprintf('%d', (-$XshiftAfter));
5727 }
5728 if ($last_fontid != $original_fontid) {
5729 $tj .= '] TJ ';
5730 $tj .= sprintf(' /F%d %.3F Tf ', $original_fontid, $fontsize);
5731 $tj .= '[';
5732 }
5733 $tj = preg_replace('/([^\\\])<>/', '\\1 ', $tj);
5734 } else {
5735 $tj .= ')';
5736 if ($XshiftAfter) {
5737 $tj .= sprintf('%d', (-$XshiftAfter));
5738 }
5739 if ($last_fontid != $original_fontid) {
5740 $tj .= '] TJ ';
5741 $tj .= sprintf(' /F%d %.3F Tf ', $original_fontid, $fontsize);
5742 $tj .= '[';
5743 }
5744 $tj = preg_replace('/([^\\\])\(\)/', '\\1 ', $tj);
5745 }
5746
5747
5748 $s = sprintf(' BT ' . $aix . ' 0 Tc 0 Tw [%s] TJ ET ', $x, $y, $tj);
5749
5750 //echo $s."\n\n"; // exit;
5751
5752 return $s;
5753 }
5754
5755 function _kern($txt, $mode, $aix, $x, $y)
5756 {
5757 if ($mode == 'MBTw') { // Multibyte requiring word spacing
5758 $space = ' ';
5759 //Convert string to UTF-16BE without BOM
5760 $space = $this->UTF8ToUTF16BE($space, false);
5761 $space = $this->_escape($space);
5762 $s = sprintf(' BT ' . $aix, $x * _MPDFK, ($this->h - $y) * _MPDFK);
5763 $t = explode(' ', $txt);
5764 for ($i = 0; $i < count($t); $i++) {
5765 $tx = $t[$i];
5766
5767 $tj = '(';
5768 $unicode = $this->UTF8StringToArray($tx);
5769 for ($ti = 0; $ti < count($unicode); $ti++) {
5770 if ($ti > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($ti - 1)]][$unicode[$ti]])) {
5771 $kern = -$this->CurrentFont['kerninfo'][$unicode[($ti - 1)]][$unicode[$ti]];
5772 $tj .= sprintf(')%d(', $kern);
5773 }
5774 $tc = code2utf($unicode[$ti]);
5775 $tc = $this->UTF8ToUTF16BE($tc, false);
5776 $tj .= $this->_escape($tc);
5777 }
5778 $tj .= ')';
5779 $s.=sprintf(' %.3F Tc [%s] TJ', $this->charspacing, $tj);
5780
5781
5782 if (($i + 1) < count($t)) {
5783 $s.=sprintf(' %.3F Tc (%s) Tj', $this->ws + $this->charspacing, $space);
5784 }
5785 }
5786 $s.=' ET ';
5787 } elseif (!$this->usingCoreFont) {
5788 $s = '';
5789 $tj = '(';
5790 $unicode = $this->UTF8StringToArray($txt);
5791 for ($i = 0; $i < count($unicode); $i++) {
5792 if ($i > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]])) {
5793 $kern = -$this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]];
5794 $tj .= sprintf(')%d(', $kern);
5795 }
5796 $tx = code2utf($unicode[$i]);
5797 $tx = $this->UTF8ToUTF16BE($tx, false);
5798 $tj .= $this->_escape($tx);
5799 }
5800 $tj .= ')';
5801 $s.=sprintf(' BT ' . $aix . ' [%s] TJ ET ', $x * _MPDFK, ($this->h - $y) * _MPDFK, $tj);
5802 } else { // CORE Font
5803 $s = '';
5804 $tj = '(';
5805 $l = strlen($txt);
5806 for ($i = 0; $i < $l; $i++) {
5807 if ($i > 0 && isset($this->CurrentFont['kerninfo'][$txt[($i - 1)]][$txt[$i]])) {
5808 $kern = -$this->CurrentFont['kerninfo'][$txt[($i - 1)]][$txt[$i]];
5809 $tj .= sprintf(')%d(', $kern);
5810 }
5811 $tj .= $this->_escape($txt[$i]);
5812 }
5813 $tj .= ')';
5814 $s.=sprintf(' BT ' . $aix . ' [%s] TJ ET ', $x * _MPDFK, ($this->h - $y) * _MPDFK, $tj);
5815 }
5816
5817 return $s;
5818 }
5819
5820 function MultiCell($w, $h, $txt, $border = 0, $align = '', $fill = 0, $link = '', $directionality = 'ltr', $encoded = false, $OTLdata = false, $maxrows = false)
5821 {
5822 // maxrows is called from mpdfform->TEXTAREA
5823 // Parameter (pre-)encoded - When called internally from form::textarea - mb_encoding already done and OTL - but not reverse RTL
5824 if (!$encoded) {
5825 $txt = $this->purify_utf8_text($txt);
5826 if ($this->text_input_as_HTML) {
5827 $txt = $this->all_entities_to_utf8($txt);
5828 }
5829 if ($this->usingCoreFont) {
5830 $txt = mb_convert_encoding($txt, $this->mb_enc, 'UTF-8');
5831 }
5832 if (preg_match("/([" . $this->pregRTLchars . "])/u", $txt)) {
5833 $this->biDirectional = true;
5834 } // *OTL*
5835 /* -- OTL -- */
5836 $OTLdata = array();
5837 // Use OTL OpenType Table Layout - GSUB & GPOS
5838 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
5839 $txt = $this->otl->applyOTL($txt, $this->CurrentFont['useOTL']);
5840 $OTLdata = $this->otl->OTLdata;
5841 }
5842 if ($directionality == 'rtl' || $this->biDirectional) {
5843 if (!isset($OTLdata)) {
5844 $unicode = $this->UTF8StringToArray($txt, false);
5845 $is_strong = false;
5846 $this->getBasicOTLdata($OTLdata, $unicode, $is_strong);
5847 }
5848 }
5849 /* -- END OTL -- */
5850 }
5851 if (!$align) {
5852 $align = $this->defaultAlign;
5853 }
5854
5855 //Output text with automatic or explicit line breaks
5856 $cw = &$this->CurrentFont['cw'];
5857 if ($w == 0)
5858 $w = $this->w - $this->rMargin - $this->x;
5859
5860 $wmax = ($w - ($this->cMarginL + $this->cMarginR));
5861 if ($this->usingCoreFont) {
5862 $s = str_replace("\r", '', $txt);
5863 $nb = strlen($s);
5864 while ($nb > 0 and $s[$nb - 1] == "\n")
5865 $nb--;
5866 } else {
5867 $s = str_replace("\r", '', $txt);
5868 $nb = mb_strlen($s, $this->mb_enc);
5869 while ($nb > 0 and mb_substr($s, $nb - 1, 1, $this->mb_enc) == "\n")
5870 $nb--;
5871 }
5872 $b = 0;
5873 if ($border) {
5874 if ($border == 1) {
5875 $border = 'LTRB';
5876 $b = 'LRT';
5877 $b2 = 'LR';
5878 } else {
5879 $b2 = '';
5880 if (is_int(strpos($border, 'L')))
5881 $b2.='L';
5882 if (is_int(strpos($border, 'R')))
5883 $b2.='R';
5884 $b = is_int(strpos($border, 'T')) ? $b2 . 'T' : $b2;
5885 }
5886 }
5887 $sep = -1;
5888 $i = 0;
5889 $j = 0;
5890 $l = 0;
5891 $ns = 0;
5892 $nl = 1;
5893
5894 $rows = 0;
5895 $start_y = $this->y;
5896
5897 if (!$this->usingCoreFont) {
5898 $inclCursive = false;
5899 if (preg_match("/([" . $this->pregCURSchars . "])/u", $s)) {
5900 $inclCursive = true;
5901 }
5902 while ($i < $nb) {
5903 //Get next character
5904 $c = mb_substr($s, $i, 1, $this->mb_enc);
5905 if ($c == "\n") {
5906 //Explicit line break
5907 // WORD SPACING
5908 $this->ResetSpacing();
5909 $tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc));
5910 $tmpOTLdata = false;
5911 /* -- OTL -- */
5912 if (isset($OTLdata)) {
5913 $tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j);
5914 $this->otl->trimOTLdata($tmpOTLdata, false, true);
5915 $this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
5916 }
5917 /* -- END OTL -- */
5918 $this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);
5919 if ($maxrows != false && isset($this->mpdfform) && ($this->y - $start_y) / $h > $maxrows) {
5920 return false;
5921 }
5922 $i++;
5923 $sep = -1;
5924 $j = $i;
5925 $l = 0;
5926 $ns = 0;
5927 $nl++;
5928 if ($border and $nl == 2)
5929 $b = $b2;
5930 continue;
5931 }
5932 if ($c == " ") {
5933 $sep = $i;
5934 $ls = $l;
5935 $ns++;
5936 }
5937
5938 $l += $this->GetCharWidthNonCore($c);
5939
5940 if ($l > $wmax) {
5941 //Automatic line break
5942 if ($sep == -1) { // Only one word
5943 if ($i == $j)
5944 $i++;
5945 // WORD SPACING
5946 $this->ResetSpacing();
5947 $tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc));
5948 $tmpOTLdata = false;
5949 /* -- OTL -- */
5950 if (isset($OTLdata)) {
5951 $tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j);
5952 $this->otl->trimOTLdata($tmpOTLdata, false, true);
5953 $this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
5954 }
5955 /* -- END OTL -- */
5956 $this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);
5957 } else {
5958 $tmp = rtrim(mb_substr($s, $j, $sep - $j, $this->mb_enc));
5959 $tmpOTLdata = false;
5960 /* -- OTL -- */
5961 if (isset($OTLdata)) {
5962 $tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $sep - $j);
5963 $this->otl->trimOTLdata($tmpOTLdata, false, true);
5964 }
5965 /* -- END OTL -- */
5966 if ($align == 'J') {
5967 //////////////////////////////////////////
5968 // JUSTIFY J using Unicode fonts (Word spacing doesn't work)
5969 // WORD SPACING UNICODE
5970 // Change NON_BREAKING SPACE to spaces so they are 'spaced' properly
5971 $tmp = str_replace(chr(194) . chr(160), chr(32), $tmp);
5972 $len_ligne = $this->GetStringWidth($tmp, false, $tmpOTLdata);
5973 $nb_carac = mb_strlen($tmp, $this->mb_enc);
5974 $nb_spaces = mb_substr_count($tmp, ' ', $this->mb_enc);
5975 // Take off number of Marks
5976 // Use GPOS OTL
5977 if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'])) {
5978 if (isset($tmpOTLdata['group']) && $tmpOTLdata['group']) {
5979 $nb_carac -= substr_count($tmpOTLdata['group'], 'M');
5980 }
5981 }
5982
5983 list($charspacing, $ws, $kashida) = $this->GetJspacing($nb_carac, $nb_spaces, ((($wmax) - $len_ligne) * _MPDFK), $inclCursive, $tmpOTLdata);
5984 $this->SetSpacing($charspacing, $ws);
5985 //////////////////////////////////////////
5986 }
5987 if (isset($OTLdata)) {
5988 $this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
5989 }
5990 $this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);
5991 $i = $sep + 1;
5992 }
5993 if ($maxrows != false && isset($this->mpdfform) && ($this->y - $start_y) / $h > $maxrows) {
5994 return false;
5995 }
5996 $sep = -1;
5997 $j = $i;
5998 $l = 0;
5999 $ns = 0;
6000 $nl++;
6001 if ($border and $nl == 2)
6002 $b = $b2;
6003 } else
6004 $i++;
6005 }
6006 //Last chunk
6007 // WORD SPACING
6008
6009 $this->ResetSpacing();
6010 }
6011
6012
6013 else {
6014
6015 while ($i < $nb) {
6016 //Get next character
6017 $c = $s[$i];
6018 if ($c == "\n") {
6019 //Explicit line break
6020 // WORD SPACING
6021 $this->ResetSpacing();
6022 $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link);
6023 if ($maxrows != false && isset($this->mpdfform) && ($this->y - $start_y) / $h > $maxrows) {
6024 return false;
6025 }
6026 $i++;
6027 $sep = -1;
6028 $j = $i;
6029 $l = 0;
6030 $ns = 0;
6031 $nl++;
6032 if ($border and $nl == 2)
6033 $b = $b2;
6034 continue;
6035 }
6036 if ($c == " ") {
6037 $sep = $i;
6038 $ls = $l;
6039 $ns++;
6040 }
6041
6042 $l += $this->GetCharWidthCore($c);
6043 if ($l > $wmax) {
6044 //Automatic line break
6045 if ($sep == -1) {
6046 if ($i == $j)
6047 $i++;
6048 // WORD SPACING
6049 $this->ResetSpacing();
6050 $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link);
6051 }
6052 else {
6053 if ($align == 'J') {
6054 $tmp = rtrim(substr($s, $j, $sep - $j));
6055 //////////////////////////////////////////
6056 // JUSTIFY J using Unicode fonts (Word spacing doesn't work)
6057 // WORD SPACING NON_UNICODE/CJK
6058 // Change NON_BREAKING SPACE to spaces so they are 'spaced' properly
6059 $tmp = str_replace(chr(160), chr(32), $tmp);
6060 $len_ligne = $this->GetStringWidth($tmp);
6061 $nb_carac = strlen($tmp);
6062 $nb_spaces = substr_count($tmp, ' ');
6063 $tmpOTLdata = array();
6064 list($charspacing, $ws, $kashida) = $this->GetJspacing($nb_carac, $nb_spaces, ((($wmax) - $len_ligne) * _MPDFK), false, $tmpOTLdata);
6065 $this->SetSpacing($charspacing, $ws);
6066 //////////////////////////////////////////
6067 }
6068 $this->Cell($w, $h, substr($s, $j, $sep - $j), $b, 2, $align, $fill, $link);
6069 $i = $sep + 1;
6070 }
6071 if ($maxrows != false && isset($this->mpdfform) && ($this->y - $start_y) / $h > $maxrows) {
6072 return false;
6073 }
6074 $sep = -1;
6075 $j = $i;
6076 $l = 0;
6077 $ns = 0;
6078 $nl++;
6079 if ($border and $nl == 2)
6080 $b = $b2;
6081 } else
6082 $i++;
6083 }
6084 //Last chunk
6085 // WORD SPACING
6086
6087 $this->ResetSpacing();
6088 }
6089 //Last chunk
6090 if ($border and is_int(strpos($border, 'B')))
6091 $b.='B';
6092 if (!$this->usingCoreFont) {
6093 $tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc));
6094 $tmpOTLdata = false;
6095 /* -- OTL -- */
6096 if (isset($OTLdata)) {
6097 $tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j);
6098 $this->otl->trimOTLdata($tmpOTLdata, false, true);
6099 $this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
6100 }
6101 /* -- END OTL -- */
6102 $this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);
6103 } else {
6104 $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link);
6105 }
6106 $this->x = $this->lMargin;
6107 }
6108
6109 /* -- DIRECTW -- */
6110
6111 function Write($h, $txt, $currentx = 0, $link = '', $directionality = 'ltr', $align = '')
6112 {
6113 if (!class_exists('directw', false)) {
6114 include(_MPDF_PATH . 'classes/directw.php');
6115 }
6116 if (empty($this->directw)) {
6117 $this->directw = new directw($this);
6118 }
6119 $this->directw->Write($h, $txt, $currentx, $link, $directionality, $align);
6120 }
6121
6122 /* -- END DIRECTW -- */
6123
6124
6125 /* -- HTML-CSS -- */
6126
6127 function saveInlineProperties()
6128 {
6129 $saved = array();
6130 $saved['family'] = $this->FontFamily;
6131 $saved['style'] = $this->FontStyle;
6132 $saved['sizePt'] = $this->FontSizePt;
6133 $saved['size'] = $this->FontSize;
6134 $saved['HREF'] = $this->HREF;
6135 $saved['textvar'] = $this->textvar; // mPDF 5.7.1
6136 $saved['OTLtags'] = $this->OTLtags; // mPDF 5.7.1
6137 $saved['textshadow'] = $this->textshadow;
6138 $saved['linewidth'] = $this->LineWidth;
6139 $saved['drawcolor'] = $this->DrawColor;
6140 $saved['textparam'] = $this->textparam;
6141 $saved['lSpacingCSS'] = $this->lSpacingCSS;
6142 $saved['wSpacingCSS'] = $this->wSpacingCSS;
6143 $saved['I'] = $this->I;
6144 $saved['B'] = $this->B;
6145 $saved['colorarray'] = $this->colorarray;
6146 $saved['bgcolorarray'] = $this->spanbgcolorarray;
6147 $saved['border'] = $this->spanborddet;
6148 $saved['color'] = $this->TextColor;
6149 $saved['bgcolor'] = $this->FillColor;
6150 $saved['lang'] = $this->currentLang;
6151 $saved['fontLanguageOverride'] = $this->fontLanguageOverride; // mPDF 5.7.1
6152 $saved['display_off'] = $this->inlineDisplayOff;
6153
6154 return $saved;
6155 }
6156
6157 function restoreInlineProperties(&$saved)
6158 {
6159 $FontFamily = $saved['family'];
6160 $this->FontStyle = $saved['style'];
6161 $this->FontSizePt = $saved['sizePt'];
6162 $this->FontSize = $saved['size'];
6163
6164 $this->currentLang = $saved['lang'];
6165 $this->fontLanguageOverride = $saved['fontLanguageOverride']; // mPDF 5.7.1
6166
6167 $this->ColorFlag = ($this->FillColor != $this->TextColor); //Restore ColorFlag as well
6168
6169 $this->HREF = $saved['HREF'];
6170 $this->textvar = $saved['textvar']; // mPDF 5.7.1
6171 $this->OTLtags = $saved['OTLtags']; // mPDF 5.7.1
6172 $this->textshadow = $saved['textshadow'];
6173 $this->LineWidth = $saved['linewidth'];
6174 $this->DrawColor = $saved['drawcolor'];
6175 $this->textparam = $saved['textparam'];
6176 $this->inlineDisplayOff = $saved['display_off'];
6177
6178 $this->lSpacingCSS = $saved['lSpacingCSS'];
6179 if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
6180 $this->fixedlSpacing = $this->ConvertSize($this->lSpacingCSS, $this->FontSize);
6181 } else {
6182 $this->fixedlSpacing = false;
6183 }
6184 $this->wSpacingCSS = $saved['wSpacingCSS'];
6185 if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
6186 $this->minwSpacing = $this->ConvertSize($this->wSpacingCSS, $this->FontSize);
6187 } else {
6188 $this->minwSpacing = 0;
6189 }
6190
6191 $this->SetFont($FontFamily, $saved['style'], $saved['sizePt'], false);
6192
6193 $this->currentfontstyle = $saved['style'];
6194 $this->currentfontsize = $saved['sizePt'];
6195 $this->SetStylesArray(array('B' => $saved['B'], 'I' => $saved['I'])); // mPDF 5.7.1
6196
6197 $this->TextColor = $saved['color'];
6198 $this->FillColor = $saved['bgcolor'];
6199 $this->colorarray = $saved['colorarray'];
6200 $cor = $saved['colorarray'];
6201 if ($cor)
6202 $this->SetTColor($cor);
6203 $this->spanbgcolorarray = $saved['bgcolorarray'];
6204 $cor = $saved['bgcolorarray'];
6205 if ($cor)
6206 $this->SetFColor($cor);
6207 $this->spanborddet = $saved['border'];
6208 }
6209
6210 // Used when ColActive for tables - updated to return first block with background fill OR borders
6211 function GetFirstBlockFill()
6212 {
6213 // Returns the first blocklevel that uses a bgcolor fill
6214 $startfill = 0;
6215 for ($i = 1; $i <= $this->blklvl; $i++) {
6216 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']) {
6217 $startfill = $i;
6218 break;
6219 }
6220 }
6221 return $startfill;
6222 }
6223
6224 //-------------------------FLOWING BLOCK------------------------------------//
6225 //The following functions were originally written by Damon Kohler //
6226 //--------------------------------------------------------------------------//
6227
6228 function saveFont()
6229 {
6230 $saved = array();
6231 $saved['family'] = $this->FontFamily;
6232 $saved['style'] = $this->FontStyle;
6233 $saved['sizePt'] = $this->FontSizePt;
6234 $saved['size'] = $this->FontSize;
6235 $saved['curr'] = &$this->CurrentFont;
6236 $saved['lang'] = $this->currentLang; // mPDF 6
6237 $saved['color'] = $this->TextColor;
6238 $saved['spanbgcolor'] = $this->spanbgcolor;
6239 $saved['spanbgcolorarray'] = $this->spanbgcolorarray;
6240 $saved['bord'] = $this->spanborder;
6241 $saved['border'] = $this->spanborddet;
6242 $saved['HREF'] = $this->HREF;
6243 $saved['textvar'] = $this->textvar; // mPDF 5.7.1
6244 $saved['textshadow'] = $this->textshadow;
6245 $saved['linewidth'] = $this->LineWidth;
6246 $saved['drawcolor'] = $this->DrawColor;
6247 $saved['textparam'] = $this->textparam;
6248 $saved['ReqFontStyle'] = $this->ReqFontStyle;
6249 $saved['fixedlSpacing'] = $this->fixedlSpacing;
6250 $saved['minwSpacing'] = $this->minwSpacing;
6251 return $saved;
6252 }
6253
6254 function restoreFont(&$saved, $write = true)
6255 {
6256 if (!isset($saved) || empty($saved))
6257 return;
6258
6259 $this->FontFamily = $saved['family'];
6260 $this->FontStyle = $saved['style'];
6261 $this->FontSizePt = $saved['sizePt'];
6262 $this->FontSize = $saved['size'];
6263 $this->CurrentFont = &$saved['curr'];
6264 $this->currentLang = $saved['lang']; // mPDF 6
6265 $this->TextColor = $saved['color'];
6266 $this->spanbgcolor = $saved['spanbgcolor'];
6267 $this->spanbgcolorarray = $saved['spanbgcolorarray'];
6268 $this->spanborder = $saved['bord'];
6269 $this->spanborddet = $saved['border'];
6270 $this->ColorFlag = ($this->FillColor != $this->TextColor); //Restore ColorFlag as well
6271 $this->HREF = $saved['HREF'];
6272 $this->fixedlSpacing = $saved['fixedlSpacing'];
6273 $this->minwSpacing = $saved['minwSpacing'];
6274 $this->textvar = $saved['textvar']; // mPDF 5.7.1
6275 $this->textshadow = $saved['textshadow'];
6276 $this->LineWidth = $saved['linewidth'];
6277 $this->DrawColor = $saved['drawcolor'];
6278 $this->textparam = $saved['textparam'];
6279 if ($write) {
6280 $this->SetFont($saved['family'], $saved['style'], $saved['sizePt'], true, true); // force output
6281 $fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
6282 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
6283 $this->_out($fontout);
6284 }
6285 $this->pageoutput[$this->page]['Font'] = $fontout;
6286 } else
6287 $this->SetFont($saved['family'], $saved['style'], $saved['sizePt'], false);
6288 $this->ReqFontStyle = $saved['ReqFontStyle'];
6289 }
6290
6291 function newFlowingBlock($w, $h, $a = '', $is_table = false, $blockstate = 0, $newblock = true, $blockdir = 'ltr', $table_draft = false)
6292 {
6293 if (!$a) {
6294 if ($blockdir == 'rtl') {
6295 $a = 'R';
6296 } else {
6297 $a = 'L';
6298 }
6299 }
6300 $this->flowingBlockAttr['width'] = ($w * _MPDFK);
6301 // line height in user units
6302 $this->flowingBlockAttr['is_table'] = $is_table;
6303 $this->flowingBlockAttr['table_draft'] = $table_draft;
6304 $this->flowingBlockAttr['height'] = $h;
6305 $this->flowingBlockAttr['lineCount'] = 0;
6306 $this->flowingBlockAttr['align'] = $a;
6307 $this->flowingBlockAttr['font'] = array();
6308 $this->flowingBlockAttr['content'] = array();
6309 $this->flowingBlockAttr['contentB'] = array();
6310 $this->flowingBlockAttr['contentWidth'] = 0;
6311 $this->flowingBlockAttr['blockstate'] = $blockstate;
6312
6313 $this->flowingBlockAttr['newblock'] = $newblock;
6314 $this->flowingBlockAttr['valign'] = 'M';
6315 $this->flowingBlockAttr['blockdir'] = $blockdir;
6316 $this->flowingBlockAttr['cOTLdata'] = array(); // mPDF 5.7.1
6317 $this->flowingBlockAttr['lastBidiText'] = ''; // mPDF 5.7.1
6318 if (!empty($this->otl)) {
6319 $this->otl->lastBidiStrongType = '';
6320 } // *OTL*
6321 }
6322
6323 function finishFlowingBlock($endofblock = false, $next = '')
6324 {
6325 $currentx = $this->x;
6326 //prints out the last chunk
6327 $is_table = $this->flowingBlockAttr['is_table'];
6328 $table_draft = $this->flowingBlockAttr['table_draft'];
6329 $maxWidth = & $this->flowingBlockAttr['width'];
6330 $stackHeight = & $this->flowingBlockAttr['height'];
6331 $align = & $this->flowingBlockAttr['align'];
6332 $content = & $this->flowingBlockAttr['content'];
6333 $contentB = & $this->flowingBlockAttr['contentB'];
6334 $font = & $this->flowingBlockAttr['font'];
6335 $contentWidth = & $this->flowingBlockAttr['contentWidth'];
6336 $lineCount = & $this->flowingBlockAttr['lineCount'];
6337 $valign = & $this->flowingBlockAttr['valign'];
6338 $blockstate = $this->flowingBlockAttr['blockstate'];
6339
6340 $cOTLdata = & $this->flowingBlockAttr['cOTLdata']; // mPDF 5.7.1
6341 $newblock = $this->flowingBlockAttr['newblock'];
6342 $blockdir = $this->flowingBlockAttr['blockdir'];
6343
6344 // *********** BLOCK BACKGROUND COLOR *****************//
6345 if ($this->blk[$this->blklvl]['bgcolor'] && !$is_table) {
6346 $fill = 0;
6347 } else {
6348 $this->SetFColor($this->ConvertColor(255));
6349 $fill = 0;
6350 }
6351
6352 $hanger = '';
6353 // Always right trim!
6354 // Right trim last content and adjust width if needed to justify (later)
6355 if (isset($content[count($content) - 1]) && preg_match('/[ ]+$/', $content[count($content) - 1], $m)) {
6356 $strip = strlen($m[0]);
6357 $content[count($content) - 1] = substr($content[count($content) - 1], 0, (strlen($content[count($content) - 1]) - $strip));
6358 /* -- OTL -- */
6359 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
6360 $this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], false, true);
6361 }
6362 /* -- END OTL -- */
6363 }
6364
6365 // the amount of space taken up so far in user units
6366 $usedWidth = 0;
6367
6368 // COLS
6369 $oldcolumn = $this->CurrCol;
6370
6371 if ($this->ColActive && !$is_table) {
6372 $this->breakpoints[$this->CurrCol][] = $this->y;
6373 } // *COLUMNS*
6374 // Print out each chunk
6375
6376 /* -- TABLES -- */
6377 if ($is_table) {
6378 $ipaddingL = 0;
6379 $ipaddingR = 0;
6380 $paddingL = 0;
6381 $paddingR = 0;
6382 } else {
6383 /* -- END TABLES -- */
6384 $ipaddingL = $this->blk[$this->blklvl]['padding_left'];
6385 $ipaddingR = $this->blk[$this->blklvl]['padding_right'];
6386 $paddingL = ($ipaddingL * _MPDFK);
6387 $paddingR = ($ipaddingR * _MPDFK);
6388 $this->cMarginL = $this->blk[$this->blklvl]['border_left']['w'];
6389 $this->cMarginR = $this->blk[$this->blklvl]['border_right']['w'];
6390
6391 // Added mPDF 3.0 Float DIV
6392 $fpaddingR = 0;
6393 $fpaddingL = 0;
6394 /* -- CSS-FLOAT -- */
6395 if (count($this->floatDivs)) {
6396 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
6397 if ($r_exists) {
6398 $fpaddingR = $r_width;
6399 }
6400 if ($l_exists) {
6401 $fpaddingL = $l_width;
6402 }
6403 }
6404 /* -- END CSS-FLOAT -- */
6405
6406 $usey = $this->y + 0.002;
6407 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
6408 $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
6409 }
6410 /* -- CSS-IMAGE-FLOAT -- */
6411 // If float exists at this level
6412 if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
6413 $fpaddingR += $this->floatmargins['R']['w'];
6414 }
6415 if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
6416 $fpaddingL += $this->floatmargins['L']['w'];
6417 }
6418 /* -- END CSS-IMAGE-FLOAT -- */
6419 } // *TABLES*
6420
6421
6422 $lineBox = array();
6423
6424 $this->_setInlineBlockHeights($lineBox, $stackHeight, $content, $font, $is_table);
6425
6426 if ($is_table && count($content) == 0) {
6427 $stackHeight = 0;
6428 }
6429
6430 if ($table_draft) {
6431 $this->y += $stackHeight;
6432 $this->objectbuffer = array();
6433 return 0;
6434 }
6435
6436 // While we're at it, check if contains cursive text
6437 // Change NBSP to SPACE.
6438 // Re-calculate contentWidth
6439 $contentWidth = 0;
6440
6441 foreach ($content as $k => $chunk) {
6442 $this->restoreFont($font[$k], false);
6443 if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
6444 // Soft Hyphens chr(173)
6445 if (!$this->usingCoreFont) {
6446 /* -- OTL -- */
6447 // mPDF 5.7.1
6448 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
6449 $this->otl->removeChar($chunk, $cOTLdata[$k], "\xc2\xad");
6450 $this->otl->replaceSpace($chunk, $cOTLdata[$k]);
6451 $content[$k] = $chunk;
6452 }
6453 /* -- END OTL -- */ else { // *OTL*
6454 $content[$k] = $chunk = str_replace("\xc2\xad", '', $chunk);
6455 $content[$k] = $chunk = str_replace(chr(194) . chr(160), chr(32), $chunk);
6456 } // *OTL*
6457 } elseif ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
6458 $content[$k] = $chunk = str_replace(chr(173), '', $chunk);
6459 $content[$k] = $chunk = str_replace(chr(160), chr(32), $chunk);
6460 }
6461 $contentWidth += $this->GetStringWidth($chunk, true, (isset($cOTLdata[$k]) ? $cOTLdata[$k] : false), $this->textvar) * _MPDFK;
6462 } elseif (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
6463 // LIST MARKERS // mPDF 6 Lists
6464 if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') {
6465 // do nothing
6466 } else {
6467 $contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * _MPDFK;
6468 }
6469 }
6470 }
6471
6472 if (isset($font[count($font) - 1])) {
6473 $lastfontreqstyle = (isset($font[count($font) - 1]['ReqFontStyle']) ? $font[count($font) - 1]['ReqFontStyle'] : '');
6474 $lastfontstyle = (isset($font[count($font) - 1]['style']) ? $font[count($font) - 1]['style'] : '');
6475 } else {
6476 $lastfontreqstyle = null;
6477 $lastfontstyle = null;
6478 }
6479 if ($blockdir == 'ltr' && strpos($lastfontreqstyle, "I") !== false && strpos($lastfontstyle, "I") === false) { // Artificial italic
6480 $lastitalic = $this->FontSize * 0.15 * _MPDFK;
6481 } else {
6482 $lastitalic = 0;
6483 }
6484
6485 // Get PAGEBREAK TO TEST for height including the bottom border/padding
6486 $check_h = max($this->divheight, $stackHeight);
6487
6488 // This fixes a proven bug...
6489 if ($endofblock && $newblock && $blockstate == 0 && !$content) {
6490 $check_h = 0;
6491 }
6492 // but ? needs to fix potentially more widespread...
6493 // if (!$content) { $check_h = 0; }
6494
6495 if ($this->blklvl > 0 && !$is_table) {
6496 if ($endofblock && $blockstate > 1) {
6497 if ($this->blk[$this->blklvl]['page_break_after_avoid']) {
6498 $check_h += $stackHeight;
6499 }
6500 $check_h += ($this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w']);
6501 }
6502 if (($newblock && ($blockstate == 1 || $blockstate == 3) && $lineCount == 0) || ($endofblock && $blockstate == 3 && $lineCount == 0)) {
6503 $check_h += ($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['border_top']['w']);
6504 }
6505 }
6506
6507 // Force PAGE break if column height cannot take check-height
6508 if ($this->ColActive && $check_h > ($this->PageBreakTrigger - $this->y0)) {
6509 $this->SetCol($this->NbCol - 1);
6510 }
6511
6512 // Avoid just border/background-color moved on to next page
6513 if ($endofblock && $blockstate > 1 && !$content) {
6514 $buff = $this->margBuffer;
6515 } else {
6516 $buff = 0;
6517 }
6518
6519
6520 // PAGEBREAK
6521 if (!$is_table && ($this->y + $check_h) > ($this->PageBreakTrigger + $buff) and ! $this->InFooter and $this->AcceptPageBreak()) {
6522 $bak_x = $this->x; //Current X position
6523 // WORD SPACING
6524 $ws = $this->ws; //Word Spacing
6525 $charspacing = $this->charspacing; //Character Spacing
6526 $this->ResetSpacing();
6527
6528 $this->AddPage($this->CurOrientation);
6529
6530 $this->x = $bak_x;
6531 // Added to correct for OddEven Margins
6532 $currentx += $this->MarginCorrection;
6533 $this->x += $this->MarginCorrection;
6534
6535 // WORD SPACING
6536 $this->SetSpacing($charspacing, $ws);
6537 }
6538
6539
6540 /* -- COLUMNS -- */
6541 // COLS
6542 // COLUMN CHANGE
6543 if ($this->CurrCol != $oldcolumn) {
6544 $currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
6545 $this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
6546 $oldcolumn = $this->CurrCol;
6547 }
6548
6549
6550 if ($this->ColActive && !$is_table) {
6551 $this->breakpoints[$this->CurrCol][] = $this->y;
6552 }
6553 /* -- END COLUMNS -- */
6554
6555 // TOP MARGIN
6556 if ($newblock && ($blockstate == 1 || $blockstate == 3) && ($this->blk[$this->blklvl]['margin_top']) && $lineCount == 0 && !$is_table) {
6557 $this->DivLn($this->blk[$this->blklvl]['margin_top'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']);
6558 if ($this->ColActive) {
6559 $this->breakpoints[$this->CurrCol][] = $this->y;
6560 } // *COLUMNS*
6561 }
6562
6563 if ($newblock && ($blockstate == 1 || $blockstate == 3) && $lineCount == 0 && !$is_table) {
6564 $this->blk[$this->blklvl]['y0'] = $this->y;
6565 $this->blk[$this->blklvl]['startpage'] = $this->page;
6566 if ($this->blk[$this->blklvl]['float']) {
6567 $this->blk[$this->blklvl]['float_start_y'] = $this->y;
6568 }
6569 if ($this->ColActive) {
6570 $this->breakpoints[$this->CurrCol][] = $this->y;
6571 } // *COLUMNS*
6572 }
6573
6574 // Paragraph INDENT
6575 $WidthCorrection = 0;
6576 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) {
6577 $ti = $this->ConvertSize($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false); // mPDF 5.7.4
6578 $WidthCorrection = ($ti * _MPDFK);
6579 }
6580
6581
6582 // PADDING and BORDER spacing/fill
6583 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && (($this->blk[$this->blklvl]['padding_top']) || ($this->blk[$this->blklvl]['border_top'])) && ($lineCount == 0) && (!$is_table)) {
6584 // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
6585 $this->DivLn($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'], -3, true, false, 1);
6586 if ($this->ColActive) {
6587 $this->breakpoints[$this->CurrCol][] = $this->y;
6588 } // *COLUMNS*
6589 $this->x = $currentx;
6590 }
6591
6592
6593 // Added mPDF 3.0 Float DIV
6594 $fpaddingR = 0;
6595 $fpaddingL = 0;
6596 /* -- CSS-FLOAT -- */
6597 if (count($this->floatDivs)) {
6598 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
6599 if ($r_exists) {
6600 $fpaddingR = $r_width;
6601 }
6602 if ($l_exists) {
6603 $fpaddingL = $l_width;
6604 }
6605 }
6606 /* -- END CSS-FLOAT -- */
6607
6608 $usey = $this->y + 0.002;
6609 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
6610 $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
6611 }
6612 /* -- CSS-IMAGE-FLOAT -- */
6613 // If float exists at this level
6614 if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
6615 $fpaddingR += $this->floatmargins['R']['w'];
6616 }
6617 if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
6618 $fpaddingL += $this->floatmargins['L']['w'];
6619 }
6620 /* -- END CSS-IMAGE-FLOAT -- */
6621
6622
6623 if ($content) {
6624
6625 // In FinishFlowing Block no lines are justified as it is always last line
6626 // but if CJKorphan has allowed content width to go over max width, use J charspacing to compress line
6627 // JUSTIFICATION J - NOT!
6628 $nb_carac = 0;
6629 $nb_spaces = 0;
6630 $jcharspacing = 0;
6631 $jkashida = 0;
6632 $jws = 0;
6633 $inclCursive = false;
6634 $dottab = false;
6635 foreach ($content as $k => $chunk) {
6636 if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
6637 $nb_carac += mb_strlen($chunk, $this->mb_enc);
6638 $nb_spaces += mb_substr_count($chunk, ' ', $this->mb_enc);
6639 // mPDF 6
6640 // Use GPOS OTL
6641 $this->restoreFont($font[$k], false);
6642 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
6643 if (isset($cOTLdata[$k]['group']) && $cOTLdata[$k]['group']) {
6644 $nb_marks = substr_count($cOTLdata[$k]['group'], 'M');
6645 $nb_carac -= $nb_marks;
6646 }
6647 if (preg_match("/([" . $this->pregCURSchars . "])/u", $chunk)) {
6648 $inclCursive = true;
6649 }
6650 }
6651 } else {
6652 $nb_carac ++; // mPDF 6 allow spacing for inline object
6653 if ($this->objectbuffer[$k]['type'] == 'dottab') {
6654 $dottab = $this->objectbuffer[$k]['outdent'];
6655 }
6656 }
6657 }
6658
6659 // DIRECTIONALITY RTL
6660 $chunkorder = range(0, count($content) - 1); // mPDF 6
6661 /* -- OTL -- */
6662 // mPDF 6
6663 if ($blockdir == 'rtl' || $this->biDirectional) {
6664 $this->otl->_bidiReorder($chunkorder, $content, $cOTLdata, $blockdir);
6665 // From this point on, $content and $cOTLdata may contain more elements (and re-ordered) compared to
6666 // $this->objectbuffer and $font ($chunkorder contains the mapping)
6667 }
6668 /* -- END OTL -- */
6669
6670 // Remove any XAdvance from OTL data at end of line
6671 // And correct for XPlacement on last character
6672 // BIDI is applied
6673 foreach ($chunkorder AS $aord => $k) {
6674 if (count($cOTLdata)) {
6675 $this->restoreFont($font[$k], false);
6676 // ...FinishFlowingBlock...
6677 if ($aord == count($chunkorder) - 1 && isset($cOTLdata[$aord]['group'])) { // Last chunk on line
6678 $nGPOS = strlen($cOTLdata[$aord]['group']) - 1; // Last character
6679 if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL']) || isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'])) {
6680 if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'])) {
6681 $w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
6682 } else {
6683 $w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
6684 }
6685 $w *= ($this->FontSize / 1000);
6686 $contentWidth -= $w * _MPDFK;
6687 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = 0;
6688 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = 0;
6689 }
6690
6691 // If last character has an XPlacement set, adjust width calculation, and add to XAdvance to account for it
6692 if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'])) {
6693 $w = -$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
6694 $w *= ($this->FontSize / 1000);
6695 $contentWidth -= $w * _MPDFK;
6696 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
6697 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
6698 }
6699 }
6700 }
6701 }
6702
6703 // 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)
6704 // If "orphans" in fact is just a final space - ignore this
6705 $lastchar = mb_substr($content[(count($chunkorder) - 1)], mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, 1, $this->mb_enc);
6706 if (preg_match("/[" . $this->CJKoverflow . "]/u", $lastchar)) {
6707 $CJKoverflow = true;
6708 } else {
6709 $CJKoverflow = false;
6710 }
6711 if ((((($contentWidth + $lastitalic) > $maxWidth) && ($content[(count($chunkorder) - 1)] != ' ') ) ||
6712 (!$endofblock && $align == 'J' && ($next == 'image' || $next == 'select' || $next == 'input' || $next == 'textarea' || ($next == 'br' && $this->justifyB4br)))) && !($CJKoverflow && $this->allowCJKoverflow)) {
6713 // WORD SPACING
6714 list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) )), $inclCursive, $cOTLdata);
6715 }
6716 /* -- CJK-FONTS -- */ elseif ($this->checkCJK && $align == 'J' && $CJKoverflow && $this->allowCJKoverflow && $this->CJKforceend) {
6717 // force-end overhang
6718 $hanger = mb_substr($content[(count($chunkorder) - 1)], mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, 1, $this->mb_enc);
6719 if (preg_match("/[" . $this->CJKoverflow . "]/u", $hanger)) {
6720 $content[(count($chunkorder) - 1)] = mb_substr($content[(count($chunkorder) - 1)], 0, mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, $this->mb_enc);
6721 $this->restoreFont($font[$chunkorder[count($chunkorder) - 1]], false);
6722 $contentWidth -= $this->GetStringWidth($hanger) * _MPDFK;
6723 $nb_carac -= 1;
6724 list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) )), $inclCursive, $cOTLdata);
6725 }
6726 }
6727 /* -- END CJK-FONTS -- */
6728
6729 // Check if will fit at word/char spacing of previous line - if so continue it
6730 // but only allow a maximum of $this->jSmaxWordLast and $this->jSmaxCharLast
6731 elseif ($contentWidth < ($maxWidth - $lastitalic - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK))) && !$this->fixedlSpacing) {
6732 if ($this->ws > $this->jSmaxWordLast) {
6733 $jws = $this->jSmaxWordLast;
6734 }
6735 if ($this->charspacing > $this->jSmaxCharLast) {
6736 $jcharspacing = $this->jSmaxCharLast;
6737 }
6738 $check = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) ) - ( $jcharspacing * $nb_carac) - ( $jws * $nb_spaces);
6739 if ($check <= 0) {
6740 $jcharspacing = 0;
6741 $jws = 0;
6742 }
6743 }
6744
6745 $empty = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) );
6746
6747
6748 $empty -= ($jcharspacing * ($nb_carac - 1)); // mPDF 6 nb_carac MINUS 1
6749 $empty -= ($jws * $nb_spaces);
6750 $empty -= ($jkashida);
6751
6752 $empty /= _MPDFK;
6753
6754 if (!$is_table) {
6755 $this->maxPosR = max($this->maxPosR, ($this->w - $this->rMargin - $this->blk[$this->blklvl]['outer_right_margin'] - $empty));
6756 $this->maxPosL = min($this->maxPosL, ($this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $empty));
6757 }
6758
6759 $arraysize = count($chunkorder);
6760
6761 $margins = ($this->cMarginL + $this->cMarginR) + ($ipaddingL + $ipaddingR + $fpaddingR + $fpaddingR );
6762
6763 if (!$is_table) {
6764 $this->DivLn($stackHeight, $this->blklvl, false);
6765 } // false -> don't advance y
6766
6767 $this->x = $currentx + $this->cMarginL + $ipaddingL + $fpaddingL;
6768 if ($dottab !== false && $blockdir == 'rtl') {
6769 $this->x -= $dottab;
6770 } elseif ($align == 'R') {
6771 $this->x += $empty;
6772 } elseif ($align == 'J' && $blockdir == 'rtl') {
6773 $this->x += $empty;
6774 } elseif ($align == 'C') {
6775 $this->x += ($empty / 2);
6776 }
6777
6778 // Paragraph INDENT
6779 $WidthCorrection = 0;
6780 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) {
6781 $ti = $this->ConvertSize($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false); // mPDF 5.7.4
6782 if ($blockdir != 'rtl') {
6783 $this->x += $ti;
6784 } // mPDF 6
6785 }
6786
6787 foreach ($chunkorder AS $aord => $k) { // mPDF 5.7
6788 $chunk = $content[$aord];
6789 if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
6790
6791 $xadj = $this->x - $this->objectbuffer[$k]['OUTER-X'];
6792 $this->objectbuffer[$k]['OUTER-X'] += $xadj;
6793 $this->objectbuffer[$k]['BORDER-X'] += $xadj;
6794 $this->objectbuffer[$k]['INNER-X'] += $xadj;
6795
6796 if ($this->objectbuffer[$k]['type'] == 'listmarker') {
6797 $this->objectbuffer[$k]['lineBox'] = $lineBox[-1]; // Block element details for glyph-origin
6798 }
6799 $yadj = $this->y - $this->objectbuffer[$k]['OUTER-Y'];
6800 if ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
6801 $this->objectbuffer[$k]['lineBox'] = $lineBox[$k]; // element details for glyph-origin
6802 }
6803 if ($this->objectbuffer[$k]['type'] != 'dottab') { // mPDF 6 DOTTAB
6804 $yadj += $lineBox[$k]['top'];
6805 }
6806 $this->objectbuffer[$k]['OUTER-Y'] += $yadj;
6807 $this->objectbuffer[$k]['BORDER-Y'] += $yadj;
6808 $this->objectbuffer[$k]['INNER-Y'] += $yadj;
6809 }
6810
6811 $this->restoreFont($font[$k]); // mPDF 5.7
6812
6813 if ($is_table && substr($align, 0, 1) == 'D' && $aord == 0) {
6814 $dp = $this->decimal_align[substr($align, 0, 2)];
6815 $s = preg_split('/' . preg_quote($dp, '/') . '/', $content[0], 2); // ? needs to be /u if not core
6816 $s0 = $this->GetStringWidth($s[0], false);
6817 $this->x += ($this->decimal_offset - $s0);
6818 }
6819
6820 $this->SetSpacing(($this->fixedlSpacing * _MPDFK) + $jcharspacing, ($this->fixedlSpacing + $this->minwSpacing) * _MPDFK + $jws);
6821 $this->fixedlSpacing = false;
6822 $this->minwSpacing = 0;
6823
6824 $save_vis = $this->visibility;
6825 if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->textparam['visibility'] != $this->visibility) {
6826 $this->SetVisibility($this->textparam['visibility']);
6827 }
6828
6829 // *********** SPAN BACKGROUND COLOR ***************** //
6830 if (isset($this->spanbgcolor) && $this->spanbgcolor) {
6831 $cor = $this->spanbgcolorarray;
6832 $this->SetFColor($cor);
6833 $save_fill = $fill;
6834 $spanfill = 1;
6835 $fill = 1;
6836 }
6837 if (!empty($this->spanborddet)) {
6838 if (strpos($contentB[$k], 'L') !== false && isset($this->spanborddet['L']))
6839 $this->x += $this->spanborddet['L']['w'];
6840 if (strpos($contentB[$k], 'L') === false)
6841 $this->spanborddet['L']['s'] = $this->spanborddet['L']['w'] = 0;
6842 if (strpos($contentB[$k], 'R') === false)
6843 $this->spanborddet['R']['s'] = $this->spanborddet['R']['w'] = 0;
6844 }
6845 // WORD SPACING
6846 // mPDF 5.7.1
6847 $stringWidth = $this->GetStringWidth($chunk, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar);
6848 $nch = mb_strlen($chunk, $this->mb_enc);
6849 // Use GPOS OTL
6850 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
6851 if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) {
6852 $nch -= substr_count($cOTLdata[$aord]['group'], 'M');
6853 }
6854 }
6855 $stringWidth += ( $this->charspacing * $nch / _MPDFK );
6856
6857 $stringWidth += ( $this->ws * mb_substr_count($chunk, ' ', $this->mb_enc) / _MPDFK );
6858
6859 if (isset($this->objectbuffer[$k])) {
6860 if ($this->objectbuffer[$k]['type'] == 'dottab') {
6861 $this->objectbuffer[$k]['OUTER-WIDTH'] +=$empty;
6862 $this->objectbuffer[$k]['OUTER-WIDTH'] +=$this->objectbuffer[$k]['outdent'];
6863 }
6864 // LIST MARKERS // mPDF 6 Lists
6865 if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') {
6866 // do nothing
6867 } else {
6868 $stringWidth = $this->objectbuffer[$k]['OUTER-WIDTH'];
6869 }
6870 }
6871
6872 if ($stringWidth == 0) {
6873 $stringWidth = 0.000001;
6874 }
6875 if ($aord == $arraysize - 1) { // mPDF 5.7
6876 // mPDF 5.7.1
6877 if ($this->checkCJK && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) {
6878 // force-end overhang
6879 $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
6880 $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
6881 } else {
6882 $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
6883 }
6884 } else
6885 $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
6886
6887
6888 if (!empty($this->spanborddet)) {
6889 if (strpos($contentB[$k], 'R') !== false && $aord != $arraysize - 1)
6890 $this->x += $this->spanborddet['R']['w'];
6891 }
6892 // *********** SPAN BACKGROUND COLOR OFF - RESET BLOCK BGCOLOR ***************** //
6893 if (isset($spanfill) && $spanfill) {
6894 $fill = $save_fill;
6895 $spanfill = 0;
6896 if ($fill) {
6897 $this->SetFColor($bcor);
6898 }
6899 }
6900 if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->visibility != $save_vis) {
6901 $this->SetVisibility($save_vis);
6902 }
6903 }
6904
6905 $this->printobjectbuffer($is_table, $blockdir);
6906 $this->objectbuffer = array();
6907 $this->ResetSpacing();
6908 } // END IF CONTENT
6909
6910 /* -- CSS-IMAGE-FLOAT -- */
6911 // Update values if set to skipline
6912 if ($this->floatmargins) {
6913 $this->_advanceFloatMargins();
6914 }
6915
6916
6917 if ($endofblock && $blockstate > 1) {
6918 // If float exists at this level
6919 if (isset($this->floatmargins['R']['y1'])) {
6920 $fry1 = $this->floatmargins['R']['y1'];
6921 } else {
6922 $fry1 = 0;
6923 }
6924 if (isset($this->floatmargins['L']['y1'])) {
6925 $fly1 = $this->floatmargins['L']['y1'];
6926 } else {
6927 $fly1 = 0;
6928 }
6929 if ($this->y < $fry1 || $this->y < $fly1) {
6930 $drop = max($fry1, $fly1) - $this->y;
6931 $this->DivLn($drop);
6932 $this->x = $currentx;
6933 }
6934 }
6935 /* -- END CSS-IMAGE-FLOAT -- */
6936
6937
6938 // PADDING and BORDER spacing/fill
6939 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)) {
6940 // If CSS height set, extend bottom - if on same page as block started, and CSS HEIGHT > actual height,
6941 // and does not force pagebreak
6942 $extra = 0;
6943 if (isset($this->blk[$this->blklvl]['css_set_height']) && $this->blk[$this->blklvl]['css_set_height'] && $this->blk[$this->blklvl]['startpage'] == $this->page) {
6944 // predicted height
6945 $h1 = ($this->y - $this->blk[$this->blklvl]['y0']) + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'];
6946 if ($h1 < ($this->blk[$this->blklvl]['css_set_height'] + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['padding_top'])) {
6947 $extra = ($this->blk[$this->blklvl]['css_set_height'] + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['padding_top']) - $h1;
6948 }
6949 if ($this->y + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $extra > $this->PageBreakTrigger) {
6950 $extra = $this->PageBreakTrigger - ($this->y + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w']);
6951 }
6952 }
6953
6954 // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
6955 $this->DivLn($this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $extra, -3, true, false, 2);
6956 $this->x = $currentx;
6957
6958 if ($this->ColActive) {
6959 $this->breakpoints[$this->CurrCol][] = $this->y;
6960 } // *COLUMNS*
6961 }
6962
6963 // SET Bottom y1 of block (used for painting borders)
6964 if (($endofblock) && ($blockstate > 1) && (!$is_table)) {
6965 $this->blk[$this->blklvl]['y1'] = $this->y;
6966 }
6967
6968 // BOTTOM MARGIN
6969 if (($endofblock) && ($blockstate > 1) && ($this->blk[$this->blklvl]['margin_bottom']) && (!$is_table)) {
6970 if ($this->y + $this->blk[$this->blklvl]['margin_bottom'] < $this->PageBreakTrigger and ! $this->InFooter) {
6971 $this->DivLn($this->blk[$this->blklvl]['margin_bottom'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']);
6972 if ($this->ColActive) {
6973 $this->breakpoints[$this->CurrCol][] = $this->y;
6974 } // *COLUMNS*
6975 }
6976 }
6977
6978 // Reset lineheight
6979 $stackHeight = $this->divheight;
6980 }
6981
6982 function printobjectbuffer($is_table = false, $blockdir = false)
6983 {
6984 if (!$blockdir) {
6985 $blockdir = $this->directionality;
6986 }
6987 if ($is_table && $this->shrin_k > 1) {
6988 $k = $this->shrin_k;
6989 } else {
6990 $k = 1;
6991 }
6992 $save_y = $this->y;
6993 $save_x = $this->x;
6994 $save_currentfontfamily = $this->FontFamily;
6995 $save_currentfontsize = $this->FontSizePt;
6996 $save_currentfontstyle = $this->FontStyle;
6997 if ($blockdir == 'rtl') {
6998 $rtlalign = 'R';
6999 } else {
7000 $rtlalign = 'L';
7001 }
7002 foreach ($this->objectbuffer AS $ib => $objattr) {
7003 if ($objattr['type'] == 'bookmark' || $objattr['type'] == 'indexentry' || $objattr['type'] == 'toc') {
7004 $x = $objattr['OUTER-X'];
7005 $y = $objattr['OUTER-Y'];
7006 $this->y = $y - $this->FontSize / 2;
7007 $this->x = $x;
7008 if ($objattr['type'] == 'bookmark') {
7009 $this->Bookmark($objattr['CONTENT'], $objattr['bklevel'], $y - $this->FontSize);
7010 } // *BOOKMARKS*
7011 if ($objattr['type'] == 'indexentry') {
7012 $this->IndexEntry($objattr['CONTENT']);
7013 } // *INDEX*
7014 if ($objattr['type'] == 'toc') {
7015 $this->TOC_Entry($objattr['CONTENT'], $objattr['toclevel'], (isset($objattr['toc_id']) ? $objattr['toc_id'] : ''));
7016 } // *TOC*
7017 }
7018 /* -- ANNOTATIONS -- */ elseif ($objattr['type'] == 'annot') {
7019 if ($objattr['POS-X']) {
7020 $x = $objattr['POS-X'];
7021 } elseif ($this->annotMargin <> 0) {
7022 $x = -$objattr['OUTER-X'];
7023 } else {
7024 $x = $objattr['OUTER-X'];
7025 }
7026 if ($objattr['POS-Y']) {
7027 $y = $objattr['POS-Y'];
7028 } else {
7029 $y = $objattr['OUTER-Y'] - $this->FontSize / 2;
7030 }
7031 // Create a dummy entry in the _out/columnBuffer with position sensitive data,
7032 // linking $y-1 in the Columnbuffer with entry in $this->columnAnnots
7033 // and when columns are split in length will not break annotation from current line
7034 $this->y = $y - 1;
7035 $this->x = $x - 1;
7036 $this->Line($x - 1, $y - 1, $x - 1, $y - 1);
7037 $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'] : ''));
7038 }
7039 /* -- END ANNOTATIONS -- */ else {
7040 $y = $objattr['OUTER-Y'];
7041 $x = $objattr['OUTER-X'];
7042 $w = $objattr['OUTER-WIDTH'];
7043 $h = $objattr['OUTER-HEIGHT'];
7044 if (isset($objattr['text'])) {
7045 $texto = $objattr['text'];
7046 }
7047 $this->y = $y;
7048 $this->x = $x;
7049 if (isset($objattr['fontfamily'])) {
7050 $this->SetFont($objattr['fontfamily'], '', $objattr['fontsize']);
7051 }
7052 }
7053
7054 // HR
7055 if ($objattr['type'] == 'hr') {
7056 $this->SetDColor($objattr['color']);
7057 switch ($objattr['align']) {
7058 case 'C':
7059 $empty = $objattr['OUTER-WIDTH'] - $objattr['INNER-WIDTH'];
7060 $empty /= 2;
7061 $x += $empty;
7062 break;
7063 case 'R':
7064 $empty = $objattr['OUTER-WIDTH'] - $objattr['INNER-WIDTH'];
7065 $x += $empty;
7066 break;
7067 }
7068 $oldlinewidth = $this->LineWidth;
7069 $this->SetLineWidth($objattr['linewidth'] / $k);
7070 $this->y += ($objattr['linewidth'] / 2) + $objattr['margin_top'] / $k;
7071 $this->Line($x, $this->y, $x + $objattr['INNER-WIDTH'], $this->y);
7072 $this->SetLineWidth($oldlinewidth);
7073 $this->SetDColor($this->ConvertColor(0));
7074 }
7075 // IMAGE
7076 if ($objattr['type'] == 'image') {
7077 // mPDF 5.7.3 TRANSFORMS
7078 if (isset($objattr['transform'])) {
7079 $this->_out("\n" . '% BTR'); // Begin Transform
7080 }
7081 if (isset($objattr['z-index']) && $objattr['z-index'] > 0 && $this->current_layer == 0) {
7082 $this->BeginLayer($objattr['z-index']);
7083 }
7084 if (isset($objattr['visibility']) && $objattr['visibility'] != 'visible' && $objattr['visibility']) {
7085 $this->SetVisibility($objattr['visibility']);
7086 }
7087 if (isset($objattr['opacity'])) {
7088 $this->SetAlpha($objattr['opacity']);
7089 }
7090
7091 $obiw = $objattr['INNER-WIDTH'];
7092 $obih = $objattr['INNER-HEIGHT'];
7093 $sx = $objattr['INNER-WIDTH'] * _MPDFK / $objattr['orig_w'];
7094 $sy = abs($objattr['INNER-HEIGHT']) * _MPDFK / abs($objattr['orig_h']);
7095 $sx = ($objattr['INNER-WIDTH'] * _MPDFK / $objattr['orig_w']);
7096 $sy = ($objattr['INNER-HEIGHT'] * _MPDFK / $objattr['orig_h']);
7097
7098 $rotate = 0;
7099 if (isset($objattr['ROTATE'])) {
7100 $rotate = $objattr['ROTATE'];
7101 }
7102 if ($rotate == 90) {
7103 // Clockwise
7104 $obiw = $objattr['INNER-HEIGHT'];
7105 $obih = $objattr['INNER-WIDTH'];
7106 $tr = $this->transformTranslate(0, -$objattr['INNER-WIDTH'], true);
7107 $tr .= ' ' . $this->transformRotate(90, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-WIDTH']), true);
7108 $sx = $obiw * _MPDFK / $objattr['orig_h'];
7109 $sy = $obih * _MPDFK / $objattr['orig_w'];
7110 } elseif ($rotate == -90 || $rotate == 270) {
7111 // AntiClockwise
7112 $obiw = $objattr['INNER-HEIGHT'];
7113 $obih = $objattr['INNER-WIDTH'];
7114 $tr = $this->transformTranslate($objattr['INNER-WIDTH'], ($objattr['INNER-HEIGHT'] - $objattr['INNER-WIDTH']), true);
7115 $tr .= ' ' . $this->transformRotate(-90, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-WIDTH']), true);
7116 $sx = $obiw * _MPDFK / $objattr['orig_h'];
7117 $sy = $obih * _MPDFK / $objattr['orig_w'];
7118 } elseif ($rotate == 180) {
7119 // Mirror
7120 $tr = $this->transformTranslate($objattr['INNER-WIDTH'], -$objattr['INNER-HEIGHT'], true);
7121 $tr .= ' ' . $this->transformRotate(180, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-HEIGHT']), true);
7122 } else {
7123 $tr = '';
7124 }
7125 $tr = trim($tr);
7126 if ($tr) {
7127 $tr .= ' ';
7128 }
7129 $gradmask = '';
7130
7131 // mPDF 5.7.3 TRANSFORMS
7132 $tr2 = '';
7133 if (isset($objattr['transform'])) {
7134 $maxsize_x = $w;
7135 $maxsize_y = $h;
7136 $cx = $x + $w / 2;
7137 $cy = $y + $h / 2;
7138 preg_match_all('/(translatex|translatey|translate|scalex|scaley|scale|rotate|skewX|skewY|skew)\((.*?)\)/is', $objattr['transform'], $m);
7139 if (count($m[0])) {
7140 for ($i = 0; $i < count($m[0]); $i++) {
7141 $c = strtolower($m[1][$i]);
7142 $v = trim($m[2][$i]);
7143 $vv = preg_split('/[ ,]+/', $v);
7144 if ($c == 'translate' && count($vv)) {
7145 $translate_x = $this->ConvertSize($vv[0], $maxsize_x, false, false);
7146 if (count($vv) == 2) {
7147 $translate_y = $this->ConvertSize($vv[1], $maxsize_y, false, false);
7148 } else {
7149 $translate_y = 0;
7150 }
7151 $tr2 .= $this->transformTranslate($translate_x, $translate_y, true) . ' ';
7152 } elseif ($c == 'translatex' && count($vv)) {
7153 $translate_x = $this->ConvertSize($vv[0], $maxsize_x, false, false);
7154 $tr2 .= $this->transformTranslate($translate_x, 0, true) . ' ';
7155 } elseif ($c == 'translatey' && count($vv)) {
7156 $translate_y = $this->ConvertSize($vv[1], $maxsize_y, false, false);
7157 $tr2 .= $this->transformTranslate(0, $translate_y, true) . ' ';
7158 } elseif ($c == 'scale' && count($vv)) {
7159 $scale_x = $vv[0] * 100;
7160 if (count($vv) == 2) {
7161 $scale_y = $vv[1] * 100;
7162 } else {
7163 $scale_y = $scale_x;
7164 }
7165 $tr2 .= $this->transformScale($scale_x, $scale_y, $cx, $cy, true) . ' ';
7166 } elseif ($c == 'scalex' && count($vv)) {
7167 $scale_x = $vv[0] * 100;
7168 $tr2 .= $this->transformScale($scale_x, 0, $cx, $cy, true) . ' ';
7169 } elseif ($c == 'scaley' && count($vv)) {
7170 $scale_y = $vv[1] * 100;
7171 $tr2 .= $this->transformScale(0, $scale_y, $cx, $cy, true) . ' ';
7172 } elseif ($c == 'skew' && count($vv)) {
7173 $angle_x = $this->ConvertAngle($vv[0], false);
7174 if (count($vv) == 2) {
7175 $angle_y = $this->ConvertAngle($vv[1], false);
7176 } else {
7177 $angle_y = 0;
7178 }
7179 $tr2 .= $this->transformSkew($angle_x, $angle_y, $cx, $cy, true) . ' ';
7180 } elseif ($c == 'skewx' && count($vv)) {
7181 $angle = $this->ConvertAngle($vv[0], false);
7182 $tr2 .= $this->transformSkew($angle, 0, $cx, $cy, true) . ' ';
7183 } elseif ($c == 'skewy' && count($vv)) {
7184 $angle = $this->ConvertAngle($vv[0], false);
7185 $tr2 .= $this->transformSkew(0, $angle, $cx, $cy, true) . ' ';
7186 } elseif ($c == 'rotate' && count($vv)) {
7187 $angle = $this->ConvertAngle($vv[0]);
7188 $tr2 .= $this->transformRotate($angle, $cx, $cy, true) . ' ';
7189 }
7190 }
7191 }
7192 }
7193
7194 // LIST MARKERS (Images) // mPDF 6 Lists
7195 if (isset($objattr['listmarker']) && $objattr['listmarker'] && $objattr['listmarkerposition'] == 'outside') {
7196 $mw = $objattr['OUTER-WIDTH'];
7197 // NB If change marker-offset, also need to alter in function _getListMarkerWidth
7198 $adjx = $this->ConvertSize($this->list_marker_offset, $this->FontSize);
7199 if ($objattr['dir'] == 'rtl') {
7200 $objattr['INNER-X'] += $adjx;
7201 } else {
7202 $objattr['INNER-X'] -= $adjx;
7203 $objattr['INNER-X'] -= $mw;
7204 }
7205 }
7206 // mPDF 5.7.3 TRANSFORMS / BACKGROUND COLOR
7207 // Transform also affects image background
7208 if ($tr2) {
7209 $this->_out('q ' . $tr2 . ' ');
7210 }
7211 if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
7212 $bgcol = $objattr['bgcolor'];
7213 $this->SetFColor($bgcol);
7214 $this->Rect($x, $y, $w, $h, 'F');
7215 $this->SetFColor($this->ConvertColor(255));
7216 }
7217 if ($tr2) {
7218 $this->_out('Q');
7219 }
7220
7221 /* -- BACKGROUNDS -- */
7222 if (isset($objattr['GRADIENT-MASK'])) {
7223 $g = $this->grad->parseMozGradient($objattr['GRADIENT-MASK']);
7224 if ($g) {
7225 $dummy = $this->grad->Gradient($objattr['INNER-X'], $objattr['INNER-Y'], $obiw, $obih, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true, true);
7226 $gradmask = '/TGS' . count($this->gradients) . ' gs ';
7227 }
7228 }
7229 /* -- END BACKGROUNDS -- */
7230 /* -- IMAGES-WMF -- */
7231 if (isset($objattr['itype']) && $objattr['itype'] == 'wmf') {
7232 $outstring = sprintf('q ' . $tr . $tr2 . '%.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, -$sy, $objattr['INNER-X'] * _MPDFK - $sx * $objattr['wmf_x'], (($this->h - $objattr['INNER-Y']) * _MPDFK) + $sy * $objattr['wmf_y'], $objattr['ID']); // mPDF 5.7.3 TRANSFORMS
7233 } else
7234 /* -- END IMAGES-WMF -- */
7235 if (isset($objattr['itype']) && $objattr['itype'] == 'svg') {
7236 $outstring = sprintf('q ' . $tr . $tr2 . '%.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, -$sy, $objattr['INNER-X'] * _MPDFK - $sx * $objattr['wmf_x'], (($this->h - $objattr['INNER-Y']) * _MPDFK) + $sy * $objattr['wmf_y'], $objattr['ID']); // mPDF 5.7.3 TRANSFORMS
7237 } else {
7238 $outstring = sprintf("q " . $tr . $tr2 . "%.3F 0 0 %.3F %.3F %.3F cm " . $gradmask . "/I%d Do Q", $obiw * _MPDFK, $obih * _MPDFK, $objattr['INNER-X'] * _MPDFK, ($this->h - ($objattr['INNER-Y'] + $obih )) * _MPDFK, $objattr['ID']); // mPDF 5.7.3 TRANSFORMS
7239 }
7240 $this->_out($outstring);
7241 // LINK
7242 if (isset($objattr['link']))
7243 $this->Link($objattr['INNER-X'], $objattr['INNER-Y'], $objattr['INNER-WIDTH'], $objattr['INNER-HEIGHT'], $objattr['link']);
7244 if (isset($objattr['opacity'])) {
7245 $this->SetAlpha(1);
7246 }
7247
7248 // mPDF 5.7.3 TRANSFORMS
7249 // Transform also affects image borders
7250 if ($tr2) {
7251 $this->_out('q ' . $tr2 . ' ');
7252 }
7253 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)) {
7254 $this->PaintImgBorder($objattr, $is_table);
7255 }
7256 if ($tr2) {
7257 $this->_out('Q');
7258 }
7259
7260 if (isset($objattr['visibility']) && $objattr['visibility'] != 'visible' && $objattr['visibility']) {
7261 $this->SetVisibility('visible');
7262 }
7263 if (isset($objattr['z-index']) && $objattr['z-index'] > 0 && $this->current_layer == 0) {
7264 $this->EndLayer();
7265 }
7266 // mPDF 5.7.3 TRANSFORMS
7267 if (isset($objattr['transform'])) {
7268 $this->_out("\n" . '% ETR'); // End Transform
7269 }
7270 }
7271
7272 /* -- BARCODES -- */
7273 // BARCODE
7274 if ($objattr['type'] == 'barcode') {
7275 $bgcol = $this->ConvertColor(255);
7276 if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
7277 $bgcol = $objattr['bgcolor'];
7278 }
7279 $col = $this->ConvertColor(0);
7280 if (isset($objattr['color']) && $objattr['color']) {
7281 $col = $objattr['color'];
7282 }
7283 $this->SetFColor($bgcol);
7284 $this->Rect($objattr['BORDER-X'], $objattr['BORDER-Y'], $objattr['BORDER-WIDTH'], $objattr['BORDER-HEIGHT'], 'F');
7285 $this->SetFColor($this->ConvertColor(255));
7286 if (isset($objattr['BORDER-WIDTH'])) {
7287 $this->PaintImgBorder($objattr, $is_table);
7288 }
7289 if ($objattr['btype'] == 'EAN13' || $objattr['btype'] == 'ISBN' || $objattr['btype'] == 'ISSN' || $objattr['btype'] == 'UPCA' || $objattr['btype'] == 'UPCE' || $objattr['btype'] == 'EAN8') {
7290 $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);
7291 }
7292 // QR-code
7293 elseif ($objattr['btype'] == 'QR') {
7294 if (!class_exists('QRcode', false)) {
7295 include(_MPDF_PATH . 'qrcode/qrcode.class.php');
7296 }
7297 $this->qrcode = new QRcode($objattr['code'], $objattr['errorlevel']);
7298 $this->qrcode->displayFPDF($this, $objattr['INNER-X'], $objattr['INNER-Y'], $objattr['bsize'] * 25, array(255, 255, 255), array(0, 0, 0));
7299 } else {
7300 $this->WriteBarcode2($objattr['code'], $objattr['INNER-X'], $objattr['INNER-Y'], $objattr['bsize'], $objattr['bheight'], $bgcol, $col, $objattr['btype'], $objattr['pr_ratio'], $k);
7301 }
7302 }
7303 /* -- END BARCODES -- */
7304
7305 // TEXT CIRCLE
7306 if ($objattr['type'] == 'textcircle') {
7307 $bgcol = '';
7308 if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
7309 $bgcol = $objattr['bgcolor'];
7310 }
7311 $col = $this->ConvertColor(0);
7312 if (isset($objattr['color']) && $objattr['color']) {
7313 $col = $objattr['color'];
7314 }
7315 $this->SetTColor($col);
7316 $this->SetFColor($bgcol);
7317 if ($bgcol)
7318 $this->Rect($objattr['BORDER-X'], $objattr['BORDER-Y'], $objattr['BORDER-WIDTH'], $objattr['BORDER-HEIGHT'], 'F');
7319 $this->SetFColor($this->ConvertColor(255));
7320 if (isset($objattr['BORDER-WIDTH'])) {
7321 $this->PaintImgBorder($objattr, $is_table);
7322 }
7323 if (!class_exists('directw', false)) {
7324 include(_MPDF_PATH . 'classes/directw.php');
7325 }
7326 if (empty($this->directw)) {
7327 $this->directw = new directw($this);
7328 }
7329 if (isset($objattr['top-text'])) {
7330 $this->directw->CircularText($objattr['INNER-X'] + $objattr['INNER-WIDTH'] / 2, $objattr['INNER-Y'] + $objattr['INNER-HEIGHT'] / 2, $objattr['r'] / $k, $objattr['top-text'], 'top', $objattr['fontfamily'], $objattr['fontsize'] / $k, $objattr['fontstyle'], $objattr['space-width'], $objattr['char-width'], (isset($objattr['divider']) ? $objattr['divider'] : ''));
7331 }
7332 if (isset($objattr['bottom-text'])) {
7333 $this->directw->CircularText($objattr['INNER-X'] + $objattr['INNER-WIDTH'] / 2, $objattr['INNER-Y'] + $objattr['INNER-HEIGHT'] / 2, $objattr['r'] / $k, $objattr['bottom-text'], 'bottom', $objattr['fontfamily'], $objattr['fontsize'] / $k, $objattr['fontstyle'], $objattr['space-width'], $objattr['char-width'], (isset($objattr['divider']) ? $objattr['divider'] : ''));
7334 }
7335 }
7336
7337 $this->ResetSpacing();
7338
7339 // LIST MARKERS (Text or bullets) // mPDF 6 Lists
7340 if ($objattr['type'] == 'listmarker') {
7341 if (isset($objattr['fontfamily'])) {
7342 $this->SetFont($objattr['fontfamily'], $objattr['fontstyle'], $objattr['fontsizept']);
7343 }
7344 $col = $this->ConvertColor(0);
7345 if (isset($objattr['colorarray']) && ($objattr['colorarray'])) {
7346 $col = $objattr['colorarray'];
7347 }
7348
7349 if (isset($objattr['bullet']) && $objattr['bullet']) { // Used for position "outside" only
7350 $type = $objattr['bullet'];
7351 $size = $objattr['size'];
7352
7353 if ($objattr['listmarkerposition'] == 'inside') {
7354 $adjx = $size / 2;
7355 if ($objattr['dir'] == 'rtl') {
7356 $adjx += $objattr['offset'];
7357 }
7358 $this->x += $adjx;
7359 } else {
7360 $adjx = $objattr['offset'];
7361 $adjx += $size / 2;
7362 if ($objattr['dir'] == 'rtl') {
7363 $this->x += $adjx;
7364 } else {
7365 $this->x -= $adjx;
7366 }
7367 }
7368
7369 $yadj = $objattr['lineBox']['glyphYorigin'];
7370 if (isset($this->CurrentFont['desc']['XHeight']) && $this->CurrentFont['desc']['XHeight']) {
7371 $xh = $this->CurrentFont['desc']['XHeight'];
7372 } else {
7373 $xh = 500;
7374 }
7375 $yadj -= ($this->FontSize * $xh / 1000) * 0.625; // Vertical height of bullet (centre) from baseline= XHeight * 0.625
7376 $this->y += $yadj;
7377
7378 $this->_printListBullet($this->x, $this->y, $size, $type, $col);
7379 } else {
7380 $this->SetTColor($col);
7381 $w = $this->GetStringWidth($texto);
7382 // NB If change marker-offset, also need to alter in function _getListMarkerWidth
7383 $adjx = $this->ConvertSize($this->list_marker_offset, $this->FontSize);
7384 if ($objattr['dir'] == 'rtl') {
7385 $align = 'L';
7386 $this->x += $adjx;
7387 } else {
7388 // Use these lines to set as marker-offset, right-aligned - default
7389 $align = 'R';
7390 $this->x -= $adjx;
7391 $this->x -= $w;
7392 }
7393 $this->Cell($w, $this->FontSize, $texto, 0, 0, $align, 0, '', 0, 0, 0, 'T', 0, false, false, 0, $objattr['lineBox']);
7394 $this->SetTColor($this->ConvertColor(0));
7395 }
7396 }
7397
7398 // DOT-TAB
7399 if ($objattr['type'] == 'dottab') {
7400 if (isset($objattr['fontfamily'])) {
7401 $this->SetFont($objattr['fontfamily'], '', $objattr['fontsize']);
7402 }
7403 $sp = $this->GetStringWidth(' ');
7404 $nb = floor(($w - 2 * $sp) / $this->GetStringWidth('.'));
7405 if ($nb > 0) {
7406 $dots = ' ' . str_repeat('.', $nb) . ' ';
7407 } else {
7408 $dots = ' ';
7409 }
7410 $col = $this->ConvertColor(0);
7411 if (isset($objattr['colorarray']) && ($objattr['colorarray'])) {
7412 $col = $objattr['colorarray'];
7413 }
7414 $this->SetTColor($col);
7415 $save_dh = $this->divheight;
7416 $save_sbd = $this->spanborddet;
7417 $save_textvar = $this->textvar; // mPDF 5.7.1
7418 $this->spanborddet = '';
7419 $this->divheight = 0;
7420 $this->textvar = 0x00; // mPDF 5.7.1
7421
7422 $this->Cell($w, $h, $dots, 0, 0, 'C', 0, '', 0, 0, 0, 'T', 0, false, false, 0, $objattr['lineBox']); // mPDF 6 DOTTAB
7423 $this->spanborddet = $save_sbd;
7424 $this->textvar = $save_textvar; // mPDF 5.7.1
7425 $this->divheight = $save_dh;
7426 $this->SetTColor($this->ConvertColor(0));
7427 }
7428
7429 /* -- FORMS -- */
7430 // TEXT/PASSWORD INPUT
7431 if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'TEXT' || $objattr['subtype'] == 'PASSWORD')) {
7432 $this->mpdfform->print_ob_text($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
7433 }
7434
7435 // TEXTAREA
7436 if ($objattr['type'] == 'textarea') {
7437 $this->mpdfform->print_ob_textarea($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
7438 }
7439
7440 // SELECT
7441 if ($objattr['type'] == 'select') {
7442 $this->mpdfform->print_ob_select($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
7443 }
7444
7445
7446 // INPUT/BUTTON as IMAGE
7447 if ($objattr['type'] == 'input' && $objattr['subtype'] == 'IMAGE') {
7448 $this->mpdfform->print_ob_imageinput($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
7449 }
7450
7451 // BUTTON
7452 if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'SUBMIT' || $objattr['subtype'] == 'RESET' || $objattr['subtype'] == 'BUTTON')) {
7453 $this->mpdfform->print_ob_button($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
7454 }
7455
7456 // CHECKBOX
7457 if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'CHECKBOX')) {
7458 $this->mpdfform->print_ob_checkbox($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $x, $y);
7459 }
7460 // RADIO
7461 if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'RADIO')) {
7462 $this->mpdfform->print_ob_radio($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $x, $y);
7463 }
7464 /* -- END FORMS -- */
7465 }
7466 $this->SetFont($save_currentfontfamily, $save_currentfontstyle, $save_currentfontsize);
7467 $this->y = $save_y;
7468 $this->x = $save_x;
7469 unset($content);
7470 }
7471
7472 function _printListBullet($x, $y, $size, $type, $color)
7473 {
7474 // x and y are the centre of the bullet; size is the width and/or height in mm
7475 $fcol = $this->SetTColor($color, true);
7476 $lcol = strtoupper($fcol); // change 0 0 0 rg to 0 0 0 RG
7477 $this->_out(sprintf('q %s %s', $lcol, $fcol));
7478 $this->_out('0 j 0 J [] 0 d');
7479 if ($type == 'square') {
7480 $size *= 0.85; // Smaller to appear the same size as circle/disc
7481 $this->_out(sprintf('%.3F %.3F %.3F %.3F re f', ($x - $size / 2) * _MPDFK, ($this->h - $y + $size / 2) * _MPDFK, ($size) * _MPDFK, (-$size) * _MPDFK));
7482 } elseif ($type == 'disc') {
7483 $this->Circle($x, $y, $size / 2, 'F'); // Fill
7484 } elseif ($type == 'circle') {
7485 $lw = $size / 12; // Line width
7486 $this->_out(sprintf('%.3F w ', $lw * _MPDFK));
7487 $this->Circle($x, $y, $size / 2 - $lw / 2, 'S'); // Stroke
7488 }
7489 $this->_out('Q');
7490 }
7491
7492 // mPDF 6
7493 // Get previous character and move pointers
7494 function _moveToPrevChar(&$contentctr, &$charctr, $content)
7495 {
7496 $lastchar = false;
7497 $charctr--;
7498 while ($charctr < 0) { // go back to previous $content[]
7499 $contentctr--;
7500 if ($contentctr < 0) {
7501 return false;
7502 }
7503 if ($this->usingCoreFont) {
7504 $charctr = strlen($content[$contentctr]) - 1;
7505 } else {
7506 $charctr = mb_strlen($content[$contentctr], $this->mb_enc) - 1;
7507 }
7508 }
7509 if ($this->usingCoreFont) {
7510 $lastchar = $content[$contentctr][$charctr];
7511 } else {
7512 $lastchar = mb_substr($content[$contentctr], $charctr, 1, $this->mb_enc);
7513 }
7514 return $lastchar;
7515 }
7516
7517 // Get previous character
7518 function _getPrevChar($contentctr, $charctr, $content)
7519 {
7520 $lastchar = false;
7521 $charctr--;
7522 while ($charctr < 0) { // go back to previous $content[]
7523 $contentctr--;
7524 if ($contentctr < 0) {
7525 return false;
7526 }
7527 if ($this->usingCoreFont) {
7528 $charctr = strlen($content[$contentctr]) - 1;
7529 } else {
7530 $charctr = mb_strlen($content[$contentctr], $this->mb_enc) - 1;
7531 }
7532 }
7533 if ($this->usingCoreFont) {
7534 $lastchar = $content[$contentctr][$charctr];
7535 } else {
7536 $lastchar = mb_substr($content[$contentctr], $charctr, 1, $this->mb_enc);
7537 }
7538 return $lastchar;
7539 }
7540
7541 function WriteFlowingBlock($s, $sOTLdata)
7542 { // mPDF 5.7.1
7543 $currentx = $this->x;
7544 $is_table = $this->flowingBlockAttr['is_table'];
7545 $table_draft = $this->flowingBlockAttr['table_draft'];
7546 // width of all the content so far in points
7547 $contentWidth = & $this->flowingBlockAttr['contentWidth'];
7548 // cell width in points
7549 $maxWidth = & $this->flowingBlockAttr['width'];
7550 $lineCount = & $this->flowingBlockAttr['lineCount'];
7551 // line height in user units
7552 $stackHeight = & $this->flowingBlockAttr['height'];
7553 $align = & $this->flowingBlockAttr['align'];
7554 $content = & $this->flowingBlockAttr['content'];
7555 $contentB = & $this->flowingBlockAttr['contentB'];
7556 $font = & $this->flowingBlockAttr['font'];
7557 $valign = & $this->flowingBlockAttr['valign'];
7558 $blockstate = $this->flowingBlockAttr['blockstate'];
7559 $cOTLdata = & $this->flowingBlockAttr['cOTLdata']; // mPDF 5.7.1
7560
7561 $newblock = $this->flowingBlockAttr['newblock'];
7562 $blockdir = $this->flowingBlockAttr['blockdir'];
7563
7564 // *********** BLOCK BACKGROUND COLOR ***************** //
7565 if ($this->blk[$this->blklvl]['bgcolor'] && !$is_table) {
7566 $fill = 0;
7567 } else {
7568 $this->SetFColor($this->ConvertColor(255));
7569 $fill = 0;
7570 }
7571 $font[] = $this->saveFont();
7572 $content[] = '';
7573 $contentB[] = '';
7574 $cOTLdata[] = $sOTLdata; // mPDF 5.7.1
7575 $currContent = & $content[count($content) - 1];
7576
7577 $CJKoverflow = false;
7578 $Oikomi = false; // mPDF 6
7579 $hanger = '';
7580
7581 // COLS
7582 $oldcolumn = $this->CurrCol;
7583 if ($this->ColActive && !$is_table) {
7584 $this->breakpoints[$this->CurrCol][] = $this->y;
7585 } // *COLUMNS*
7586
7587 /* -- TABLES -- */
7588 if ($is_table) {
7589 $ipaddingL = 0;
7590 $ipaddingR = 0;
7591 $paddingL = 0;
7592 $paddingR = 0;
7593 $cpaddingadjustL = 0;
7594 $cpaddingadjustR = 0;
7595 // Added mPDF 3.0
7596 $fpaddingR = 0;
7597 $fpaddingL = 0;
7598 } else {
7599 /* -- END TABLES -- */
7600 $ipaddingL = $this->blk[$this->blklvl]['padding_left'];
7601 $ipaddingR = $this->blk[$this->blklvl]['padding_right'];
7602 $paddingL = ($ipaddingL * _MPDFK);
7603 $paddingR = ($ipaddingR * _MPDFK);
7604 $this->cMarginL = $this->blk[$this->blklvl]['border_left']['w'];
7605 $cpaddingadjustL = -$this->cMarginL;
7606 $this->cMarginR = $this->blk[$this->blklvl]['border_right']['w'];
7607 $cpaddingadjustR = -$this->cMarginR;
7608 // Added mPDF 3.0 Float DIV
7609 $fpaddingR = 0;
7610 $fpaddingL = 0;
7611 /* -- CSS-FLOAT -- */
7612 if (count($this->floatDivs)) {
7613 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
7614 if ($r_exists) {
7615 $fpaddingR = $r_width;
7616 }
7617 if ($l_exists) {
7618 $fpaddingL = $l_width;
7619 }
7620 }
7621 /* -- END CSS-FLOAT -- */
7622
7623 $usey = $this->y + 0.002;
7624 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
7625 $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
7626 }
7627 /* -- CSS-IMAGE-FLOAT -- */
7628 // If float exists at this level
7629 if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
7630 $fpaddingR += $this->floatmargins['R']['w'];
7631 }
7632 if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
7633 $fpaddingL += $this->floatmargins['L']['w'];
7634 }
7635 /* -- END CSS-IMAGE-FLOAT -- */
7636 } // *TABLES*
7637 //OBJECTS - IMAGES & FORM Elements (NB has already skipped line/page if required - in printbuffer)
7638 if (substr($s, 0, 3) == "\xbb\xa4\xac") { //identifier has been identified!
7639 $objattr = $this->_getObjAttr($s);
7640 $h_corr = 0;
7641 if ($is_table) { // *TABLES*
7642 $maximumW = ($maxWidth / _MPDFK) - ($this->cellPaddingL + $this->cMarginL + $this->cellPaddingR + $this->cMarginR); // *TABLES*
7643 } // *TABLES*
7644 else { // *TABLES*
7645 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0) && (!$is_table)) {
7646 $h_corr = $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
7647 }
7648 $maximumW = ($maxWidth / _MPDFK) - ($this->blk[$this->blklvl]['padding_left'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_right'] + $this->blk[$this->blklvl]['border_right']['w'] + $fpaddingL + $fpaddingR );
7649 } // *TABLES*
7650 $objattr = $this->inlineObject($objattr['type'], $this->lMargin + $fpaddingL + ($contentWidth / _MPDFK), ($this->y + $h_corr), $objattr, $this->lMargin, ($contentWidth / _MPDFK), $maximumW, $stackHeight, true, $is_table);
7651
7652 // SET LINEHEIGHT for this line ================ RESET AT END
7653 $stackHeight = MAX($stackHeight, $objattr['OUTER-HEIGHT']);
7654 $this->objectbuffer[count($content) - 1] = $objattr;
7655 // if (isset($objattr['vertical-align'])) { $valign = $objattr['vertical-align']; }
7656 // else { $valign = ''; }
7657 // LIST MARKERS // mPDF 6 Lists
7658 if ($objattr['type'] == 'image' && isset($objattr['listmarker']) && $objattr['listmarker'] && $objattr['listmarkerposition'] == 'outside') {
7659 // do nothing
7660 } else {
7661 $contentWidth += ($objattr['OUTER-WIDTH'] * _MPDFK);
7662 }
7663 return;
7664 }
7665
7666 $lbw = $rbw = 0; // Border widths
7667 if (!empty($this->spanborddet)) {
7668 if (isset($this->spanborddet['L']))
7669 $lbw = $this->spanborddet['L']['w'];
7670 if (isset($this->spanborddet['R']))
7671 $rbw = $this->spanborddet['R']['w'];
7672 }
7673
7674 if ($this->usingCoreFont) {
7675 $clen = strlen($s);
7676 } else {
7677 $clen = mb_strlen($s, $this->mb_enc);
7678 }
7679
7680 // for every character in the string
7681 for ($i = 0; $i < $clen; $i++) {
7682
7683 // extract the current character
7684 // get the width of the character in points
7685 if ($this->usingCoreFont) {
7686 $c = $s[$i];
7687 // Soft Hyphens chr(173)
7688 $cw = ($this->GetCharWidthCore($c) * _MPDFK);
7689 if (($this->textvar & FC_KERNING) && $i > 0) { // mPDF 5.7.1
7690 if (isset($this->CurrentFont['kerninfo'][$s[($i - 1)]][$c])) {
7691 $cw += ($this->CurrentFont['kerninfo'][$s[($i - 1)]][$c] * $this->FontSizePt / 1000 );
7692 }
7693 }
7694 } else {
7695 $c = mb_substr($s, $i, 1, $this->mb_enc);
7696 $cw = ($this->GetCharWidthNonCore($c, false) * _MPDFK);
7697 // mPDF 5.7.1
7698 // Use OTL GPOS
7699 if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) {
7700 // ...WriteFlowingBlock...
7701 // Only add XAdvanceL (not sure at present whether RTL or LTR writing direction)
7702 // At this point, XAdvanceL and XAdvanceR will balance
7703 if (isset($sOTLdata['GPOSinfo'][$i]['XAdvanceL'])) {
7704 $cw += $sOTLdata['GPOSinfo'][$i]['XAdvanceL'] * (1000 / $this->CurrentFont['unitsPerEm']) * ($this->FontSize / 1000) * _MPDFK;
7705 }
7706 }
7707 if (($this->textvar & FC_KERNING) && $i > 0) { // mPDF 5.7.1
7708 $lastc = mb_substr($s, ($i - 1), 1, $this->mb_enc);
7709 $ulastc = $this->UTF8StringToArray($lastc, false);
7710 $uc = $this->UTF8StringToArray($c, false);
7711 if (isset($this->CurrentFont['kerninfo'][$ulastc[0]][$uc[0]])) {
7712 $cw += ($this->CurrentFont['kerninfo'][$ulastc[0]][$uc[0]] * $this->FontSizePt / 1000 );
7713 }
7714 }
7715 }
7716
7717 if ($i == 0) {
7718 $cw += $lbw * _MPDFK;
7719 $contentB[(count($contentB) - 1)] .= 'L';
7720 }
7721 if ($i == ($clen - 1)) {
7722 $cw += $rbw * _MPDFK;
7723 $contentB[(count($contentB) - 1)] .= 'R';
7724 }
7725 if ($c == ' ') {
7726 $currContent .= $c;
7727 $contentWidth += $cw;
7728 continue;
7729 }
7730
7731 // Paragraph INDENT
7732 $WidthCorrection = 0;
7733 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) {
7734 $ti = $this->ConvertSize($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false); // mPDF 5.7.4
7735 $WidthCorrection = ($ti * _MPDFK);
7736 }
7737 // OUTDENT
7738 foreach ($this->objectbuffer AS $k => $objattr) { // mPDF 6 DOTTAB
7739 if ($objattr['type'] == 'dottab') {
7740 $WidthCorrection -= ($objattr['outdent'] * _MPDFK);
7741 break;
7742 }
7743 }
7744
7745
7746 // Added mPDF 3.0 Float DIV
7747 $fpaddingR = 0;
7748 $fpaddingL = 0;
7749 /* -- CSS-FLOAT -- */
7750 if (count($this->floatDivs)) {
7751 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
7752 if ($r_exists) {
7753 $fpaddingR = $r_width;
7754 }
7755 if ($l_exists) {
7756 $fpaddingL = $l_width;
7757 }
7758 }
7759 /* -- END CSS-FLOAT -- */
7760
7761 $usey = $this->y + 0.002;
7762 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
7763 $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
7764 }
7765
7766 /* -- CSS-IMAGE-FLOAT -- */
7767 // If float exists at this level
7768 if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
7769 $fpaddingR += $this->floatmargins['R']['w'];
7770 }
7771 if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
7772 $fpaddingL += $this->floatmargins['L']['w'];
7773 }
7774 /* -- END CSS-IMAGE-FLOAT -- */
7775
7776
7777 // try adding another char
7778 if (( $contentWidth + $cw > $maxWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) ) + 0.001)) {// 0.001 is to correct for deviations converting mm=>pts
7779 // it won't fit, output what we already have
7780 $lineCount++;
7781
7782 // contains any content that didn't make it into this print
7783 $savedContent = '';
7784 $savedContentB = '';
7785 $savedOTLdata = array(); // mPDF 5.7.1
7786 $savedFont = array();
7787 $savedObj = array();
7788 $savedPreOTLdata = array(); // mPDF 5.7.1
7789 $savedPreContent = array();
7790 $savedPreContentB = array();
7791 $savedPreFont = array();
7792
7793 // mPDF 6
7794 // New line-breaking algorithm
7795 /////////////////////
7796 // LINE BREAKING
7797 /////////////////////
7798 $breakfound = false;
7799 $contentctr = count($content) - 1;
7800 if ($this->usingCoreFont) {
7801 $charctr = strlen($currContent);
7802 } else {
7803 $charctr = mb_strlen($currContent, $this->mb_enc);
7804 }
7805 $checkchar = $c;
7806 $prevchar = $this->_getPrevChar($contentctr, $charctr, $content);
7807
7808 /* -- CJK-FONTS -- */
7809 /////////////////////
7810 // 1) CJK Overflowing a) punctuation or b) Oikomi
7811 /////////////////////
7812 // Next character ($c) is suitable to add as overhanging or squeezed punctuation, or Oikomi
7813 if ($CJKoverflow || $Oikomi) { // If flag already set
7814 $CJKoverflow = false;
7815 $Oikomi = false;
7816 $breakfound = true;
7817 }
7818 if (!$this->usingCoreFont && !$breakfound && $this->checkCJK) {
7819 // Get next/following character (in this chunk)
7820 $followingchar = '';
7821 if ($i < ($clen - 1)) {
7822 if ($this->usingCoreFont) {
7823 $followingchar = $s[$i + 1];
7824 } else {
7825 $followingchar = mb_substr($s, $i + 1, 1, $this->mb_enc);
7826 }
7827 }
7828 /////////////////////
7829 // 1a) Overflow punctuation
7830 /////////////////////
7831 if (preg_match("/[" . $this->pregCJKchars . "]/u", $prevchar) && preg_match("/[" . $this->CJKoverflow . "]/u", $checkchar) && $this->allowCJKorphans) {
7832 // add character onto this line
7833 $currContent .= $c;
7834 $contentWidth += $cw;
7835 $CJKoverflow = true; // Set flag
7836 continue;
7837 }
7838 /////////////////////
7839 // 1b) Try squeezing another character(s) onto this line = Oikomi, if character cannot end line
7840 // or next character cannot start line (and not splitting CJK numerals)
7841 /////////////////////
7842 // NB otherwise it move lastchar(s) to next line to keep $c company = Oidashi, which is done below in standard way
7843 elseif (preg_match("/[" . $this->pregCJKchars . "]/u", $checkchar) && $this->allowCJKorphans &&
7844 (preg_match("/[" . $this->CJKleading . "]/u", $followingchar) || preg_match("/[" . $this->CJKfollowing . "]/u", $checkchar)) &&
7845 !preg_match("/[" . $this->CJKleading . "]/u", $checkchar) && !preg_match("/[" . $this->CJKfollowing . "]/u", $followingchar) &&
7846 !(preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $followingchar) && preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $checkchar))) {
7847 // add character onto this line
7848 $currContent .= $c;
7849 $contentWidth += $cw;
7850 $Oikomi = true; // Set flag
7851 continue;
7852 }
7853 }
7854 /* -- END CJK-FONTS -- */
7855 /* -- HYPHENATION -- */
7856 /////////////////////
7857 // AUTOMATIC HYPHENATION
7858 // 2) Automatic hyphen in current word (does not cross tags)
7859 /////////////////////
7860 if (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] == 1) {
7861 $currWord = '';
7862 // Look back and ahead to get current word
7863 for ($ac = $charctr - 1; $ac >= 0; $ac--) {
7864 if ($this->usingCoreFont) {
7865 $addc = substr($currContent, $ac, 1);
7866 } else {
7867 $addc = mb_substr($currContent, $ac, 1, $this->mb_enc);
7868 }
7869 if ($addc == ' ') {
7870 break;
7871 }
7872 $currWord = $addc . $currWord;
7873 }
7874 $start = $ac + 1;
7875 for ($ac = $i; $ac < ($clen - 1); $ac++) {
7876 if ($this->usingCoreFont) {
7877 $addc = substr($s, $ac, 1);
7878 } else {
7879 $addc = mb_substr($s, $ac, 1, $this->mb_enc);
7880 }
7881 if ($addc == ' ') {
7882 break;
7883 }
7884 $currWord .= $addc;
7885 }
7886 $ptr = $this->hyphenateWord($currWord, $charctr - $start);
7887 if ($ptr > -1) {
7888 $breakfound = array($contentctr, $start + $ptr, $contentctr, $start + $ptr, 'hyphen');
7889 }
7890 }
7891 /* -- END HYPHENATION -- */
7892
7893 // Search backwards to find first line-break opportunity
7894 while ($breakfound == false && $prevchar !== false) {
7895 $cutcontentctr = $contentctr;
7896 $cutcharctr = $charctr;
7897 $prevchar = $this->_moveToPrevChar($contentctr, $charctr, $content);
7898 /////////////////////
7899 // 3) Break at SPACE
7900 /////////////////////
7901 if ($prevchar == ' ') {
7902 $breakfound = array($contentctr, $charctr, $cutcontentctr, $cutcharctr, 'discard');
7903 }
7904 /////////////////////
7905 // 4) Break at U+200B in current word (Khmer, Lao & Thai Invisible word boundary, and Tibetan)
7906 /////////////////////
7907 elseif ($prevchar == "\xe2\x80\x8b") { // U+200B Zero-width Word Break
7908 $breakfound = array($contentctr, $charctr, $cutcontentctr, $cutcharctr, 'discard');
7909 }
7910 /////////////////////
7911 // 5) Break at Hard HYPHEN '-' or U+2010
7912 /////////////////////
7913 elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && ($prevchar == '-' || $prevchar == "\xe2\x80\x90")) {
7914 // Don't break a URL
7915 // Look back to get first part of current word
7916 $checkw = '';
7917 for ($ac = $charctr - 1; $ac >= 0; $ac--) {
7918 if ($this->usingCoreFont) {
7919 $addc = substr($currContent, $ac, 1);
7920 } else {
7921 $addc = mb_substr($currContent, $ac, 1, $this->mb_enc);
7922 }
7923 if ($addc == ' ') {
7924 break;
7925 }
7926 $checkw = $addc . $checkw;
7927 }
7928 // Don't break if HyphenMinus AND (a URL or before a numeral or before a >)
7929 if ((!preg_match('/(http:|ftp:|https:|www\.)/', $checkw) && $checkchar != '>' && !preg_match('/[0-9]/', $checkchar)) || $prevchar == "\xe2\x80\x90") {
7930 $breakfound = array($cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut');
7931 }
7932 }
7933 /////////////////////
7934 // 6) Break at Soft HYPHEN (replace with hard hyphen)
7935 /////////////////////
7936 elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && !$this->usingCoreFont && $prevchar == "\xc2\xad") {
7937 $breakfound = array($cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut');
7938 $content[$contentctr] = mb_substr($content[$contentctr], 0, $charctr, $this->mb_enc) . '-' . mb_substr($content[$contentctr], $charctr + 1, mb_strlen($content[$contentctr]), $this->mb_enc);
7939 if (!empty($cOTLdata[$contentctr])) {
7940 $cOTLdata[$contentctr]['char_data'][$charctr] = array('bidi_class' => 9, 'uni' => 45);
7941 $cOTLdata[$contentctr]['group'][$charctr] = 'C';
7942 }
7943 } elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats' && $prevchar == chr(173)) {
7944 $breakfound = array($cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut');
7945 $content[$contentctr] = substr($content[$contentctr], 0, $charctr) . '-' . substr($content[$contentctr], $charctr + 1);
7946 }
7947 /* -- CJK-FONTS -- */
7948 /////////////////////
7949 // 7) Break at CJK characters (unless forbidden characters to end or start line)
7950 // CJK Avoiding line break in the middle of numerals
7951 /////////////////////
7952 elseif (!$this->usingCoreFont && $this->checkCJK && preg_match("/[" . $this->pregCJKchars . "]/u", $checkchar) &&
7953 !preg_match("/[" . $this->CJKfollowing . "]/u", $checkchar) && !preg_match("/[" . $this->CJKleading . "]/u", $prevchar) &&
7954 !(preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $prevchar) && preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $checkchar))) {
7955 $breakfound = array($cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut');
7956 }
7957 /* -- END CJK-FONTS -- */
7958 /////////////////////
7959 // 8) Break at OBJECT (Break before all objects here - selected objects are moved forward to next line below e.g. dottab)
7960 /////////////////////
7961 if (isset($this->objectbuffer[$contentctr])) {
7962 $breakfound = array($cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut');
7963 }
7964
7965
7966 $checkchar = $prevchar;
7967 }
7968
7969 // If a line-break opportunity found:
7970 if (is_array($breakfound)) {
7971 $contentctr = $breakfound[0];
7972 $charctr = $breakfound[1];
7973 $cutcontentctr = $breakfound[2];
7974 $cutcharctr = $breakfound[3];
7975 $type = $breakfound[4];
7976 // Cache chunks which are already processed, but now need to be passed on to the new line
7977 for ($ix = count($content) - 1; $ix > $cutcontentctr; $ix--) {
7978 // save and crop off any subsequent chunks
7979 /* -- OTL -- */
7980 if (!empty($sOTLdata)) {
7981 $tmpOTL = array_pop($cOTLdata);
7982 $savedPreOTLdata[] = $tmpOTL;
7983 }
7984 /* -- END OTL -- */
7985 $savedPreContent[] = array_pop($content);
7986 $savedPreContentB[] = array_pop($contentB);
7987 $savedPreFont[] = array_pop($font);
7988 }
7989
7990 // Next cache the part which will start the next line
7991 if ($this->usingCoreFont) {
7992 $savedPreContent[] = substr($content[$cutcontentctr], $cutcharctr);
7993 } else {
7994 $savedPreContent[] = mb_substr($content[$cutcontentctr], $cutcharctr, mb_strlen($content[$cutcontentctr]), $this->mb_enc);
7995 }
7996 $savedPreContentB[] = preg_replace('/L/', '', $contentB[$cutcontentctr]);
7997 $savedPreFont[] = $font[$cutcontentctr];
7998 /* -- OTL -- */
7999 if (!empty($sOTLdata)) {
8000 $savedPreOTLdata[] = $this->otl->splitOTLdata($cOTLdata[$cutcontentctr], $cutcharctr, $cutcharctr);
8001 }
8002 /* -- END OTL -- */
8003
8004
8005 // Finally adjust the Current content which ends this line
8006 if ($cutcharctr == 0 && $type == 'discard') {
8007 array_pop($content);
8008 array_pop($contentB);
8009 array_pop($font);
8010 array_pop($cOTLdata);
8011 }
8012
8013 $currContent = & $content[count($content) - 1];
8014 if ($this->usingCoreFont) {
8015 $currContent = substr($currContent, 0, $charctr);
8016 } else {
8017 $currContent = mb_substr($currContent, 0, $charctr, $this->mb_enc);
8018 }
8019
8020 if (!empty($sOTLdata)) {
8021 $savedPreOTLdata[] = $this->otl->splitOTLdata($cOTLdata[(count($cOTLdata) - 1)], mb_strlen($currContent, $this->mb_enc));
8022 }
8023
8024 if (strpos($contentB[(count($contentB) - 1)], 'R') !== false) { // ???
8025 $contentB[count($content) - 1] = preg_replace('/R/', '', $contentB[count($content) - 1]); // ???
8026 }
8027
8028 if ($type == 'hyphen') {
8029 $currContent .= '-';
8030 if (!empty($cOTLdata[(count($cOTLdata) - 1)])) {
8031 $cOTLdata[(count($cOTLdata) - 1)]['char_data'][] = array('bidi_class' => 9, 'uni' => 45);
8032 $cOTLdata[(count($cOTLdata) - 1)]['group'] .= 'C';
8033 }
8034 }
8035
8036 $savedContent = '';
8037 $savedContentB = '';
8038 $savedFont = array();
8039 $savedOTLdata = array();
8040 }
8041 // If no line-break opportunity found - split at current position
8042 // or - Next character ($c) is suitable to add as overhanging or squeezed punctuation, or Oikomi, as set above by:
8043 // 1) CJK Overflowing a) punctuation or b) Oikomi
8044 // in which case $breakfound==1 and NOT array
8045
8046 if (!is_array($breakfound)) {
8047 $savedFont = $this->saveFont();
8048 if (!empty($sOTLdata)) {
8049 $savedOTLdata = $this->otl->splitOTLdata($cOTLdata[(count($cOTLdata) - 1)], mb_strlen($currContent, $this->mb_enc));
8050 }
8051 }
8052
8053 if ($content[count($content) - 1] == '' && !isset($this->objectbuffer[count($content) - 1])) {
8054 array_pop($content);
8055 array_pop($contentB);
8056 array_pop($font);
8057 array_pop($cOTLdata);
8058 $currContent = & $content[count($content) - 1];
8059 }
8060
8061 // Right Trim current content - including CJK space, and for OTLdata
8062 // incl. CJK - strip CJK space at end of line &#x3000; = \xe3\x80\x80 = CJK space
8063 $currContent = rtrim($currContent);
8064 if ($this->checkCJK) {
8065 $currContent = preg_replace("/\xe3\x80\x80$/", '', $currContent);
8066 } // *CJK-FONTS*
8067 /* -- OTL -- */
8068 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
8069 $this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], false, true); // NB also does U+3000
8070 }
8071 /* -- END OTL -- */
8072
8073
8074 // Selected OBJECTS are moved forward to next line, unless they come before a space or U+200B (type='discard')
8075 if (isset($this->objectbuffer[(count($content) - 1)]) && (!isset($type) || $type != 'discard')) {
8076 $objtype = $this->objectbuffer[(count($content) - 1)]['type'];
8077 if ($objtype == 'dottab' || $objtype == 'bookmark' || $objtype == 'indexentry' || $objtype == 'toc' || $objtype == 'annot') {
8078 $savedObj = array_pop($this->objectbuffer);
8079 }
8080 }
8081
8082
8083 // Decimal alignment (cancel if wraps to > 1 line)
8084 if ($is_table && substr($align, 0, 1) == 'D') {
8085 $align = substr($align, 2, 1);
8086 }
8087
8088 $lineBox = array();
8089
8090 $this->_setInlineBlockHeights($lineBox, $stackHeight, $content, $font, $is_table);
8091
8092 // update $contentWidth since it has changed with cropping
8093 $contentWidth = 0;
8094
8095 $inclCursive = false;
8096 foreach ($content as $k => $chunk) {
8097 if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
8098 // LIST MARKERS
8099 if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker']) {
8100 if ($this->objectbuffer[$k]['listmarkerposition'] != 'outside') {
8101 $contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * _MPDFK;
8102 }
8103 } else {
8104 $contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * _MPDFK;
8105 }
8106 } elseif (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
8107 $this->restoreFont($font[$k], false);
8108 if ($this->checkCJK && $k == count($content) - 1 && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $this->CJKforceend) {
8109 // force-end overhang
8110 $hanger = mb_substr($chunk, mb_strlen($chunk, $this->mb_enc) - 1, 1, $this->mb_enc);
8111 // Probably ought to do something with char_data and GPOS in cOTLdata...
8112 $content[$k] = $chunk = mb_substr($chunk, 0, mb_strlen($chunk, $this->mb_enc) - 1, $this->mb_enc);
8113 }
8114
8115 // Soft Hyphens chr(173) + Replace NBSP with SPACE + Set inclcursive if includes CURSIVE TEXT
8116 if (!$this->usingCoreFont) {
8117 /* -- OTL -- */
8118 if ((isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) || !empty($sOTLdata)) {
8119 $this->otl->removeChar($chunk, $cOTLdata[$k], "\xc2\xad");
8120 $this->otl->replaceSpace($chunk, $cOTLdata[$k]); // NBSP -> space
8121 if (preg_match("/([" . $this->pregCURSchars . "])/u", $chunk)) {
8122 $inclCursive = true;
8123 }
8124 $content[$k] = $chunk;
8125 }
8126 /* -- END OTL -- */ else { // *OTL*
8127 $content[$k] = $chunk = str_replace("\xc2\xad", '', $chunk);
8128 $content[$k] = $chunk = str_replace(chr(194) . chr(160), chr(32), $chunk);
8129 } // *OTL*
8130 } elseif ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
8131 $content[$k] = $chunk = str_replace(chr(173), '', $chunk);
8132 $content[$k] = $chunk = str_replace(chr(160), chr(32), $chunk);
8133 }
8134
8135 $contentWidth += $this->GetStringWidth($chunk, true, (isset($cOTLdata[$k]) ? $cOTLdata[$k] : false), $this->textvar) * _MPDFK; // mPDF 5.7.1
8136 if (!empty($this->spanborddet)) {
8137 if (isset($this->spanborddet['L']['w']) && strpos($contentB[$k], 'L') !== false)
8138 $contentWidth += $this->spanborddet['L']['w'] * _MPDFK;
8139 if (isset($this->spanborddet['R']['w']) && strpos($contentB[$k], 'R') !== false)
8140 $contentWidth += $this->spanborddet['R']['w'] * _MPDFK;
8141 }
8142 }
8143 }
8144
8145 $lastfontreqstyle = (isset($font[count($font) - 1]['ReqFontStyle']) ? $font[count($font) - 1]['ReqFontStyle'] : '');
8146 $lastfontstyle = (isset($font[count($font) - 1]['style']) ? $font[count($font) - 1]['style'] : '');
8147 if ($blockdir == 'ltr' && strpos($lastfontreqstyle, "I") !== false && strpos($lastfontstyle, "I") === false) { // Artificial italic
8148 $lastitalic = $this->FontSize * 0.15 * _MPDFK;
8149 } else {
8150 $lastitalic = 0;
8151 }
8152
8153
8154
8155
8156 // NOW FORMAT THE LINE TO OUTPUT
8157 if (!$table_draft) {
8158 // DIRECTIONALITY RTL
8159 $chunkorder = range(0, count($content) - 1); // mPDF 5.7
8160 /* -- OTL -- */
8161 // mPDF 6
8162 if ($blockdir == 'rtl' || $this->biDirectional) {
8163 $this->otl->_bidiReorder($chunkorder, $content, $cOTLdata, $blockdir);
8164 // From this point on, $content and $cOTLdata may contain more elements (and re-ordered) compared to
8165 // $this->objectbuffer and $font ($chunkorder contains the mapping)
8166 }
8167
8168 /* -- END OTL -- */
8169 // Remove any XAdvance from OTL data at end of line
8170 foreach ($chunkorder AS $aord => $k) {
8171 if (count($cOTLdata)) {
8172 $this->restoreFont($font[$k], false);
8173 // ...WriteFlowingBlock...
8174 if ($aord == count($chunkorder) - 1 && isset($cOTLdata[$aord]['group'])) { // Last chunk on line
8175 $nGPOS = strlen($cOTLdata[$aord]['group']) - 1; // Last character
8176 if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL']) || isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'])) {
8177 if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'])) {
8178 $w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
8179 } else {
8180 $w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
8181 }
8182 $w *= ($this->FontSize / 1000);
8183 $contentWidth -= $w * _MPDFK;
8184 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = 0;
8185 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = 0;
8186 }
8187
8188 // If last character has an XPlacement set, adjust width calculation, and add to XAdvance to account for it
8189 if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'])) {
8190 $w = -$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
8191 $w *= ($this->FontSize / 1000);
8192 $contentWidth -= $w * _MPDFK;
8193 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
8194 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
8195 }
8196 }
8197 }
8198 }
8199
8200 // JUSTIFICATION J
8201 $jcharspacing = 0;
8202 $jws = 0;
8203 $nb_carac = 0;
8204 $nb_spaces = 0;
8205 $jkashida = 0;
8206 // if it's justified, we need to find the char/word spacing (or if hanger $this->CJKforceend)
8207 if (($align == 'J' && !$CJKoverflow) || (($contentWidth + $lastitalic > $maxWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) ) + 0.001) && (!$CJKoverflow || ($CJKoverflow && !$this->allowCJKoverflow))) || $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) { // 0.001 is to correct for deviations converting mm=>pts
8208 // JUSTIFY J (Use character spacing)
8209 // WORD SPACING
8210 foreach ($chunkorder AS $aord => $k) { // mPDF 5.7
8211 $chunk = $content[$aord];
8212 if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
8213 $nb_carac += mb_strlen($chunk, $this->mb_enc);
8214 $nb_spaces += mb_substr_count($chunk, ' ', $this->mb_enc);
8215 // Use GPOS OTL
8216 if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) {
8217 if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) {
8218 $nb_carac -= substr_count($cOTLdata[$aord]['group'], 'M');
8219 }
8220 }
8221 } else {
8222 $nb_carac ++;
8223 } // mPDF 6 allow spacing for inline object
8224 }
8225 // GetJSpacing adds kashida spacing to GPOSinfo if appropriate for Font
8226 list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) )), $inclCursive, $cOTLdata);
8227 }
8228
8229 // WORD SPACING
8230 $empty = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) );
8231
8232 $empty -= ($jcharspacing * ($nb_carac - 1)); // mPDF 6 nb_carac MINUS 1
8233 $empty -= ($jws * $nb_spaces);
8234 $empty -= ($jkashida);
8235 $empty /= _MPDFK;
8236
8237 $b = ''; //do not use borders
8238 // Get PAGEBREAK TO TEST for height including the top border/padding
8239 $check_h = max($this->divheight, $stackHeight);
8240 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($this->blklvl > 0) && ($lineCount == 1) && (!$is_table)) {
8241 $check_h += ($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['border_top']['w']);
8242 }
8243
8244 if ($this->ColActive && $check_h > ($this->PageBreakTrigger - $this->y0)) {
8245 $this->SetCol($this->NbCol - 1);
8246 }
8247
8248 // PAGEBREAK
8249 // 'If' below used in order to fix "first-line of other page with justify on" bug
8250 if (!$is_table && ($this->y + $check_h) > $this->PageBreakTrigger and ! $this->InFooter and $this->AcceptPageBreak()) {
8251 $bak_x = $this->x; //Current X position
8252 // WORD SPACING
8253 $ws = $this->ws; //Word Spacing
8254 $charspacing = $this->charspacing; //Character Spacing
8255 $this->ResetSpacing();
8256
8257 $this->AddPage($this->CurOrientation);
8258
8259 $this->x = $bak_x;
8260 // Added to correct for OddEven Margins
8261 $currentx += $this->MarginCorrection;
8262 $this->x += $this->MarginCorrection;
8263
8264 // WORD SPACING
8265 $this->SetSpacing($charspacing, $ws);
8266 }
8267
8268 if ($this->kwt && !$is_table) { // mPDF 5.7+
8269 $this->printkwtbuffer();
8270 $this->kwt = false;
8271 }
8272
8273
8274 /* -- COLUMNS -- */
8275 // COLS
8276 // COLUMN CHANGE
8277 if ($this->CurrCol != $oldcolumn) {
8278 $currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
8279 $this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
8280 $oldcolumn = $this->CurrCol;
8281 }
8282
8283 if ($this->ColActive && !$is_table) {
8284 $this->breakpoints[$this->CurrCol][] = $this->y;
8285 } // *COLUMNS*
8286 /* -- END COLUMNS -- */
8287
8288 // TOP MARGIN
8289 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($this->blk[$this->blklvl]['margin_top']) && ($lineCount == 1) && (!$is_table)) {
8290 $this->DivLn($this->blk[$this->blklvl]['margin_top'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']);
8291 if ($this->ColActive) {
8292 $this->breakpoints[$this->CurrCol][] = $this->y;
8293 } // *COLUMNS*
8294 }
8295
8296
8297 // Update y0 for top of block (used to paint border)
8298 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 1) && (!$is_table)) {
8299 $this->blk[$this->blklvl]['y0'] = $this->y;
8300 $this->blk[$this->blklvl]['startpage'] = $this->page;
8301 if ($this->blk[$this->blklvl]['float']) {
8302 $this->blk[$this->blklvl]['float_start_y'] = $this->y;
8303 }
8304 }
8305
8306 // TOP PADDING and BORDER spacing/fill
8307 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && (($this->blk[$this->blklvl]['padding_top']) || ($this->blk[$this->blklvl]['border_top'])) && ($lineCount == 1) && (!$is_table)) {
8308 // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
8309 $this->DivLn($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'], -3, true, false, 1);
8310 if ($this->ColActive) {
8311 $this->breakpoints[$this->CurrCol][] = $this->y;
8312 } // *COLUMNS*
8313 }
8314
8315 $arraysize = count($chunkorder);
8316
8317 $margins = ($this->cMarginL + $this->cMarginR) + ($ipaddingL + $ipaddingR + $fpaddingR + $fpaddingR );
8318
8319 // PAINT BACKGROUND FOR THIS LINE
8320 if (!$is_table) {
8321 $this->DivLn($stackHeight, $this->blklvl, false);
8322 } // false -> don't advance y
8323
8324 $this->x = $currentx + $this->cMarginL + $ipaddingL + $fpaddingL;
8325 if ($align == 'R') {
8326 $this->x += $empty;
8327 } elseif ($align == 'C') {
8328 $this->x += ($empty / 2);
8329 }
8330
8331 // Paragraph INDENT
8332 if (isset($this->blk[$this->blklvl]['text_indent']) && ($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 1) && (!$is_table) && ($blockdir != 'rtl') && ($align != 'C')) {
8333 $ti = $this->ConvertSize($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false); // mPDF 5.7.4
8334 $this->x += $ti;
8335 }
8336
8337 // BIDI magic_reverse moved upwards from here
8338
8339 foreach ($chunkorder AS $aord => $k) { // mPDF 5.7
8340 $chunk = $content[$aord];
8341
8342 if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
8343 $xadj = $this->x - $this->objectbuffer[$k]['OUTER-X'];
8344 $this->objectbuffer[$k]['OUTER-X'] += $xadj;
8345 $this->objectbuffer[$k]['BORDER-X'] += $xadj;
8346 $this->objectbuffer[$k]['INNER-X'] += $xadj;
8347
8348 if ($this->objectbuffer[$k]['type'] == 'listmarker') {
8349 $this->objectbuffer[$k]['lineBox'] = $lineBox[-1]; // Block element details for glyph-origin
8350 }
8351 $yadj = $this->y - $this->objectbuffer[$k]['OUTER-Y'];
8352 if ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
8353 $this->objectbuffer[$k]['lineBox'] = $lineBox[$k]; // element details for glyph-origin
8354 }
8355 if ($this->objectbuffer[$k]['type'] != 'dottab') { // mPDF 6 DOTTAB
8356 $yadj += $lineBox[$k]['top'];
8357 }
8358 $this->objectbuffer[$k]['OUTER-Y'] += $yadj;
8359 $this->objectbuffer[$k]['BORDER-Y'] += $yadj;
8360 $this->objectbuffer[$k]['INNER-Y'] += $yadj;
8361 }
8362
8363 $this->restoreFont($font[$k]); // mPDF 5.7
8364
8365 $this->SetSpacing(($this->fixedlSpacing * _MPDFK) + $jcharspacing, ($this->fixedlSpacing + $this->minwSpacing) * _MPDFK + $jws);
8366 // Now unset these values so they don't influence GetStringwidth below or in fn. Cell
8367 $this->fixedlSpacing = false;
8368 $this->minwSpacing = 0;
8369
8370 $save_vis = $this->visibility;
8371 if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->textparam['visibility'] != $this->visibility) {
8372 $this->SetVisibility($this->textparam['visibility']);
8373 }
8374 // *********** SPAN BACKGROUND COLOR ***************** //
8375 if ($this->spanbgcolor) {
8376 $cor = $this->spanbgcolorarray;
8377 $this->SetFColor($cor);
8378 $save_fill = $fill;
8379 $spanfill = 1;
8380 $fill = 1;
8381 }
8382 if (!empty($this->spanborddet)) {
8383 if (strpos($contentB[$k], 'L') !== false)
8384 $this->x += (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
8385 if (strpos($contentB[$k], 'L') === false)
8386 $this->spanborddet['L']['s'] = $this->spanborddet['L']['w'] = 0;
8387 if (strpos($contentB[$k], 'R') === false)
8388 $this->spanborddet['R']['s'] = $this->spanborddet['R']['w'] = 0;
8389 }
8390
8391 // WORD SPACING
8392 // StringWidth this time includes any kashida spacing
8393 $stringWidth = $this->GetStringWidth($chunk, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, true);
8394
8395 $nch = mb_strlen($chunk, $this->mb_enc);
8396 // Use GPOS OTL
8397 if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) {
8398 if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) {
8399 $nch -= substr_count($cOTLdata[$aord]['group'], 'M');
8400 }
8401 }
8402 $stringWidth += ( $this->charspacing * $nch / _MPDFK );
8403
8404 $stringWidth += ( $this->ws * mb_substr_count($chunk, ' ', $this->mb_enc) / _MPDFK );
8405
8406 if (isset($this->objectbuffer[$k])) {
8407 // LIST MARKERS // mPDF 6 Lists
8408 if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') {
8409 $stringWidth = 0;
8410 } else {
8411 $stringWidth = $this->objectbuffer[$k]['OUTER-WIDTH'];
8412 }
8413 }
8414
8415 if ($stringWidth == 0) {
8416 $stringWidth = 0.000001;
8417 }
8418
8419 if ($aord == $arraysize - 1) {
8420 $stringWidth -= ( $this->charspacing / _MPDFK );
8421 if ($this->checkCJK && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) {
8422 // force-end overhang
8423 $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));
8424 $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));
8425 } else {
8426 $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)
8427 }
8428 } else
8429 $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
8430
8431 if (!empty($this->spanborddet)) {
8432 if (strpos($contentB[$k], 'R') !== false && $aord != $arraysize - 1)
8433 $this->x += $this->spanborddet['R']['w'];
8434 }
8435 // *********** SPAN BACKGROUND COLOR OFF - RESET BLOCK BGCOLOR ***************** //
8436 if (isset($spanfill) && $spanfill) {
8437 $fill = $save_fill;
8438 $spanfill = 0;
8439 if ($fill) {
8440 $this->SetFColor($bcor);
8441 }
8442 }
8443 if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->visibility != $save_vis) {
8444 $this->SetVisibility($save_vis);
8445 }
8446 }
8447 } elseif ($table_draft) {
8448 $this->y += $stackHeight;
8449 }
8450
8451 if (!$is_table) {
8452 $this->maxPosR = max($this->maxPosR, ($this->w - $this->rMargin - $this->blk[$this->blklvl]['outer_right_margin']));
8453 $this->maxPosL = min($this->maxPosL, ($this->lMargin + $this->blk[$this->blklvl]['outer_left_margin']));
8454 }
8455
8456 // move on to the next line, reset variables, tack on saved content and current char
8457
8458 if (!$table_draft)
8459 $this->printobjectbuffer($is_table, $blockdir);
8460 $this->objectbuffer = array();
8461
8462
8463 /* -- CSS-IMAGE-FLOAT -- */
8464 // Update values if set to skipline
8465 if ($this->floatmargins) {
8466 $this->_advanceFloatMargins();
8467 }
8468 /* -- END CSS-IMAGE-FLOAT -- */
8469
8470 // Reset lineheight
8471 $stackHeight = $this->divheight;
8472 $valign = 'M';
8473
8474 $font = array();
8475 $content = array();
8476 $contentB = array();
8477 $cOTLdata = array(); // mPDF 5.7.1
8478 $contentWidth = 0;
8479 if (!empty($savedObj)) {
8480 $this->objectbuffer[] = $savedObj;
8481 $font[] = $savedFont;
8482 $content[] = '';
8483 $contentB[] = '';
8484 $cOTLdata[] = array(); // mPDF 5.7.1
8485 $contentWidth += $savedObj['OUTER-WIDTH'] * _MPDFK;
8486 }
8487 if (count($savedPreContent) > 0) {
8488 for ($ix = count($savedPreContent) - 1; $ix >= 0; $ix--) {
8489 $font[] = $savedPreFont[$ix];
8490 $content[] = $savedPreContent[$ix];
8491 $contentB[] = $savedPreContentB[$ix];
8492 if (!empty($sOTLdata)) {
8493 $cOTLdata[] = $savedPreOTLdata[$ix];
8494 }
8495 $this->restoreFont($savedPreFont[$ix]);
8496 $lbw = $rbw = 0; // Border widths
8497 if (!empty($this->spanborddet)) {
8498 $lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
8499 $rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
8500 }
8501 if ($ix > 0) {
8502 $contentWidth += $this->GetStringWidth($savedPreContent[$ix], true, (isset($savedPreOTLdata[$ix]) ? $savedPreOTLdata[$ix] : false), $this->textvar) * _MPDFK; // mPDF 5.7.1
8503 if (strpos($savedPreContentB[$ix], 'L') !== false)
8504 $contentWidth += $lbw;
8505 if (strpos($savedPreContentB[$ix], 'R') !== false)
8506 $contentWidth += $rbw;
8507 }
8508 }
8509 $savedPreContent = array();
8510 $savedPreContentB = array();
8511 $savedPreOTLdata = array(); // mPDF 5.7.1
8512 $savedPreFont = array();
8513 $content[(count($content) - 1)] .= $c;
8514 }
8515 else {
8516 $font[] = $savedFont;
8517 $content[] = $savedContent . $c;
8518 $contentB[] = $savedContentB;
8519 $cOTLdata[] = $savedOTLdata; // mPDF 5.7.1
8520 }
8521
8522 $currContent = & $content[(count($content) - 1)];
8523 $this->restoreFont($font[(count($font) - 1)]); // mPDF 6.0
8524
8525 /* -- CJK-FONTS -- */
8526 // CJK - strip CJK space at start of line
8527 // &#x3000; = \xe3\x80\x80 = CJK space
8528 if ($this->checkCJK && $currContent == "\xe3\x80\x80") {
8529 $currContent = '';
8530 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
8531 $this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], true, false); // left trim U+3000
8532 }
8533 }
8534 /* -- END CJK-FONTS -- */
8535
8536 $lbw = $rbw = 0; // Border widths
8537 if (!empty($this->spanborddet)) {
8538 $lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
8539 $rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
8540 }
8541
8542 $contentWidth += $this->GetStringWidth($currContent, false, (isset($cOTLdata[(count($cOTLdata) - 1)]) ? $cOTLdata[(count($cOTLdata) - 1)] : false), $this->textvar) * _MPDFK; // mPDF 5.7.1
8543 if (strpos($savedContentB, 'L') !== false)
8544 $contentWidth += $lbw;
8545 $CJKoverflow = false;
8546 $hanger = '';
8547 }
8548 // another character will fit, so add it on
8549 else {
8550 $contentWidth += $cw;
8551 $currContent .= $c;
8552 }
8553 }
8554
8555 unset($content);
8556 unset($contentB);
8557 }
8558
8559 //----------------------END OF FLOWING BLOCK------------------------------------//
8560
8561
8562 /* -- CSS-IMAGE-FLOAT -- */
8563 // Update values if set to skipline
8564 function _advanceFloatMargins()
8565 {
8566 // Update floatmargins - L
8567 if (isset($this->floatmargins['L']) && $this->floatmargins['L']['skipline'] && $this->floatmargins['L']['y0'] != $this->y) {
8568 $yadj = $this->y - $this->floatmargins['L']['y0'];
8569 $this->floatmargins['L']['y0'] = $this->y;
8570 $this->floatmargins['L']['y1'] += $yadj;
8571
8572 // Update objattr in floatbuffer
8573 if ($this->floatbuffer[$this->floatmargins['L']['id']]['border_left']['w']) {
8574 $this->floatbuffer[$this->floatmargins['L']['id']]['BORDER-Y'] += $yadj;
8575 }
8576 $this->floatbuffer[$this->floatmargins['L']['id']]['INNER-Y'] += $yadj;
8577 $this->floatbuffer[$this->floatmargins['L']['id']]['OUTER-Y'] += $yadj;
8578
8579 // Unset values
8580 $this->floatbuffer[$this->floatmargins['L']['id']]['skipline'] = false;
8581 $this->floatmargins['L']['skipline'] = false;
8582 $this->floatmargins['L']['id'] = '';
8583 }
8584 // Update floatmargins - R
8585 if (isset($this->floatmargins['R']) && $this->floatmargins['R']['skipline'] && $this->floatmargins['R']['y0'] != $this->y) {
8586 $yadj = $this->y - $this->floatmargins['R']['y0'];
8587 $this->floatmargins['R']['y0'] = $this->y;
8588 $this->floatmargins['R']['y1'] += $yadj;
8589
8590 // Update objattr in floatbuffer
8591 if ($this->floatbuffer[$this->floatmargins['R']['id']]['border_left']['w']) {
8592 $this->floatbuffer[$this->floatmargins['R']['id']]['BORDER-Y'] += $yadj;
8593 }
8594 $this->floatbuffer[$this->floatmargins['R']['id']]['INNER-Y'] += $yadj;
8595 $this->floatbuffer[$this->floatmargins['R']['id']]['OUTER-Y'] += $yadj;
8596
8597 // Unset values
8598 $this->floatbuffer[$this->floatmargins['R']['id']]['skipline'] = false;
8599 $this->floatmargins['R']['skipline'] = false;
8600 $this->floatmargins['R']['id'] = '';
8601 }
8602 }
8603
8604 /* -- END CSS-IMAGE-FLOAT -- */
8605
8606
8607
8608 /* -- END HTML-CSS -- */
8609
8610 function _SetTextRendering($mode)
8611 {
8612 if (!(($mode == 0) || ($mode == 1) || ($mode == 2)))
8613 throw new MpdfException("Text rendering mode should be 0, 1 or 2 (value : $mode)");
8614 $tr = ($mode . ' Tr');
8615 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) {
8616 $this->_out($tr);
8617 }
8618 $this->pageoutput[$this->page]['TextRendering'] = $tr;
8619 }
8620
8621 function SetTextOutline($params = array())
8622 {
8623 if (isset($params['outline-s']) && $params['outline-s']) {
8624 $this->SetLineWidth($params['outline-WIDTH']);
8625 $this->SetDColor($params['outline-COLOR']);
8626 $tr = ('2 Tr');
8627 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) {
8628 $this->_out($tr);
8629 }
8630 $this->pageoutput[$this->page]['TextRendering'] = $tr;
8631 } else { //Now resets all values
8632 $this->SetLineWidth(0.2);
8633 $this->SetDColor($this->ConvertColor(0));
8634 $this->_SetTextRendering(0);
8635 $tr = ('0 Tr');
8636 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) {
8637 $this->_out($tr);
8638 }
8639 $this->pageoutput[$this->page]['TextRendering'] = $tr;
8640 }
8641 }
8642
8643 function Image($file, $x, $y, $w = 0, $h = 0, $type = '', $link = '', $paint = true, $constrain = true, $watermark = false, $shownoimg = true, $allowvector = true)
8644 {
8645 $orig_srcpath = $file;
8646 $this->GetFullPath($file);
8647
8648 $info = $this->_getImage($file, true, $allowvector, $orig_srcpath);
8649 if (!$info && $paint) {
8650 $info = $this->_getImage($this->noImageFile);
8651 if ($info) {
8652 $file = $this->noImageFile;
8653 $w = ($info['w'] * (25.4 / $this->dpi)); // 14 x 16px
8654 $h = ($info['h'] * (25.4 / $this->dpi)); // 14 x 16px
8655 }
8656 }
8657 if (!$info)
8658 return false;
8659 //Automatic width and height calculation if needed
8660 if ($w == 0 and $h == 0) {
8661 /* -- IMAGES-WMF -- */
8662 if ($info['type'] == 'wmf') {
8663 // WMF units are twips (1/20pt)
8664 // divide by 20 to get points
8665 // divide by k to get user units
8666 $w = abs($info['w']) / (20 * _MPDFK);
8667 $h = abs($info['h']) / (20 * _MPDFK);
8668 } else
8669 /* -- END IMAGES-WMF -- */
8670 if ($info['type'] == 'svg') {
8671 // returned SVG units are pts
8672 // divide by k to get user units (mm)
8673 $w = abs($info['w']) / _MPDFK;
8674 $h = abs($info['h']) / _MPDFK;
8675 } else {
8676 //Put image at default image dpi
8677 $w = ($info['w'] / _MPDFK) * (72 / $this->img_dpi);
8678 $h = ($info['h'] / _MPDFK) * (72 / $this->img_dpi);
8679 }
8680 }
8681 if ($w == 0)
8682 $w = abs($h * $info['w'] / $info['h']);
8683 if ($h == 0)
8684 $h = abs($w * $info['h'] / $info['w']);
8685
8686 /* -- WATERMARK -- */
8687 if ($watermark) {
8688 $maxw = $this->w;
8689 $maxh = $this->h;
8690 // Size = D PF or array
8691 if (is_array($this->watermark_size)) {
8692 $w = $this->watermark_size[0];
8693 $h = $this->watermark_size[1];
8694 } elseif (!is_string($this->watermark_size)) {
8695 $maxw -= $this->watermark_size * 2;
8696 $maxh -= $this->watermark_size * 2;
8697 $w = $maxw;
8698 $h = abs($w * $info['h'] / $info['w']);
8699 if ($h > $maxh) {
8700 $h = $maxh;
8701 $w = abs($h * $info['w'] / $info['h']);
8702 }
8703 } elseif ($this->watermark_size == 'F') {
8704 if ($this->ColActive) {
8705 $maxw = $this->w - ($this->DeflMargin + $this->DefrMargin);
8706 } else {
8707 $maxw = $this->pgwidth;
8708 }
8709 $maxh = $this->h - ($this->tMargin + $this->bMargin);
8710 $w = $maxw;
8711 $h = abs($w * $info['h'] / $info['w']);
8712 if ($h > $maxh) {
8713 $h = $maxh;
8714 $w = abs($h * $info['w'] / $info['h']);
8715 }
8716 } elseif ($this->watermark_size == 'P') { // Default P
8717 $w = $maxw;
8718 $h = abs($w * $info['h'] / $info['w']);
8719 if ($h > $maxh) {
8720 $h = $maxh;
8721 $w = abs($h * $info['w'] / $info['h']);
8722 }
8723 }
8724 // Automatically resize to maximum dimensions of page if too large
8725 if ($w > $maxw) {
8726 $w = $maxw;
8727 $h = abs($w * $info['h'] / $info['w']);
8728 }
8729 if ($h > $maxh) {
8730 $h = $maxh;
8731 $w = abs($h * $info['w'] / $info['h']);
8732 }
8733 // Position
8734 if (is_array($this->watermark_pos)) {
8735 $x = $this->watermark_pos[0];
8736 $y = $this->watermark_pos[1];
8737 } elseif ($this->watermark_pos == 'F') { // centred on printable area
8738 if ($this->ColActive) { // *COLUMNS*
8739 if (($this->mirrorMargins) && (($this->page) % 2 == 0)) {
8740 $xadj = $this->DeflMargin - $this->DefrMargin;
8741 } // *COLUMNS*
8742 else {
8743 $xadj = 0;
8744 } // *COLUMNS*
8745 $x = ($this->DeflMargin - $xadj + ($this->w - ($this->DeflMargin + $this->DefrMargin)) / 2) - ($w / 2); // *COLUMNS*
8746 } // *COLUMNS*
8747 else { // *COLUMNS*
8748 $x = ($this->lMargin + ($this->pgwidth) / 2) - ($w / 2);
8749 } // *COLUMNS*
8750 $y = ($this->tMargin + ($this->h - ($this->tMargin + $this->bMargin)) / 2) - ($h / 2);
8751 } else { // default P - centred on whole page
8752 $x = ($this->w / 2) - ($w / 2);
8753 $y = ($this->h / 2) - ($h / 2);
8754 }
8755 /* -- IMAGES-WMF -- */
8756 if ($info['type'] == 'wmf') {
8757 $sx = $w * _MPDFK / $info['w'];
8758 $sy = -$h * _MPDFK / $info['h'];
8759 $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * _MPDFK - $sx * $info['x'], (($this->h - $y) * _MPDFK) - $sy * $info['y'], $info['i']);
8760 } else
8761 /* -- END IMAGES-WMF -- */
8762 if ($info['type'] == 'svg') {
8763 $sx = $w * _MPDFK / $info['w'];
8764 $sy = -$h * _MPDFK / $info['h'];
8765 $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * _MPDFK - $sx * $info['x'], (($this->h - $y) * _MPDFK) - $sy * $info['y'], $info['i']);
8766 } else {
8767 $outstring = sprintf("q %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $w * _MPDFK, $h * _MPDFK, $x * _MPDFK, ($this->h - ($y + $h)) * _MPDFK, $info['i']);
8768 }
8769
8770 if ($this->watermarkImgBehind) {
8771 $outstring = $this->watermarkImgAlpha . "\n" . $outstring . "\n" . $this->SetAlpha(1, 'Normal', true) . "\n";
8772 $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', "\n" . $outstring . "\n" . '\\1', $this->pages[$this->page]);
8773 } else {
8774 $this->_out($outstring);
8775 }
8776
8777 return 0;
8778 } // end of IF watermark
8779 /* -- END WATERMARK -- */
8780
8781 if ($constrain) {
8782 // Automatically resize to maximum dimensions of page if too large
8783 if (isset($this->blk[$this->blklvl]['inner_width']) && $this->blk[$this->blklvl]['inner_width']) {
8784 $maxw = $this->blk[$this->blklvl]['inner_width'];
8785 } else {
8786 $maxw = $this->pgwidth;
8787 }
8788 if ($w > $maxw) {
8789 $w = $maxw;
8790 $h = abs($w * $info['h'] / $info['w']);
8791 }
8792 if ($h > $this->h - ($this->tMargin + $this->bMargin + 1)) { // see below - +10 to avoid drawing too close to border of page
8793 $h = $this->h - ($this->tMargin + $this->bMargin + 1);
8794 if ($this->fullImageHeight) {
8795 $h = $this->fullImageHeight;
8796 }
8797 $w = abs($h * $info['w'] / $info['h']);
8798 }
8799
8800
8801 //Avoid drawing out of the paper(exceeding width limits).
8802 //if ( ($x + $w) > $this->fw ) {
8803 if (($x + $w) > $this->w) {
8804 $x = $this->lMargin;
8805 $y += 5;
8806 }
8807
8808 $changedpage = false;
8809 $oldcolumn = $this->CurrCol;
8810 //Avoid drawing out of the page.
8811 if ($y + $h > $this->PageBreakTrigger and ! $this->InFooter and $this->AcceptPageBreak()) {
8812 $this->AddPage($this->CurOrientation);
8813 // Added to correct for OddEven Margins
8814 $x = $x + $this->MarginCorrection;
8815 $y = $this->tMargin; // mPDF 5.7.3
8816 $changedpage = true;
8817 }
8818 /* -- COLUMNS -- */
8819 // COLS
8820 // COLUMN CHANGE
8821 if ($this->CurrCol != $oldcolumn) {
8822 $y = $this->y0;
8823 $x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
8824 $this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
8825 }
8826 /* -- END COLUMNS -- */
8827 } // end of IF constrain
8828
8829 /* -- IMAGES-WMF -- */
8830 if ($info['type'] == 'wmf') {
8831 $sx = $w * _MPDFK / $info['w'];
8832 $sy = -$h * _MPDFK / $info['h'];
8833 $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * _MPDFK - $sx * $info['x'], (($this->h - $y) * _MPDFK) - $sy * $info['y'], $info['i']);
8834 } else
8835 /* -- END IMAGES-WMF -- */
8836 if ($info['type'] == 'svg') {
8837 $sx = $w * _MPDFK / $info['w'];
8838 $sy = -$h * _MPDFK / $info['h'];
8839 $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * _MPDFK - $sx * $info['x'], (($this->h - $y) * _MPDFK) - $sy * $info['y'], $info['i']);
8840 } else {
8841 $outstring = sprintf("q %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $w * _MPDFK, $h * _MPDFK, $x * _MPDFK, ($this->h - ($y + $h)) * _MPDFK, $info['i']);
8842 }
8843
8844 if ($paint) {
8845 $this->_out($outstring);
8846 if ($link)
8847 $this->Link($x, $y, $w, $h, $link);
8848
8849 // Avoid writing text on top of the image. // THIS WAS OUTSIDE THE if ($paint) bit!!!!!!!!!!!!!!!!
8850 $this->y = $y + $h;
8851 }
8852
8853 //Return width-height array
8854 $sizesarray['WIDTH'] = $w;
8855 $sizesarray['HEIGHT'] = $h;
8856 $sizesarray['X'] = $x; //Position before painting image
8857 $sizesarray['Y'] = $y; //Position before painting image
8858 $sizesarray['OUTPUT'] = $outstring;
8859
8860 $sizesarray['IMAGE_ID'] = $info['i'];
8861 $sizesarray['itype'] = $info['type'];
8862 $sizesarray['set-dpi'] = (isset($info['set-dpi']) ? $info['set-dpi'] : 0);
8863 return $sizesarray;
8864 }
8865
8866 //=============================================================
8867 //=============================================================
8868 //=============================================================
8869 //=============================================================
8870 //=============================================================
8871 /* -- HTML-CSS -- */
8872
8873 function _getObjAttr($t)
8874 {
8875 $c = explode("\xbb\xa4\xac", $t, 2);
8876 $c = explode(",", $c[1], 2);
8877 foreach ($c as $v) {
8878 $v = explode("=", $v, 2);
8879 $sp[$v[0]] = $v[1];
8880 }
8881 return (unserialize($sp['objattr']));
8882 }
8883
8884 function inlineObject($type, $x, $y, $objattr, $Lmargin, $widthUsed, $maxWidth, $lineHeight, $paint = false, $is_table = false)
8885 {
8886 if ($is_table) {
8887 $k = $this->shrin_k;
8888 } else {
8889 $k = 1;
8890 }
8891
8892 // NB $x is only used when paint=true
8893 // Lmargin not used
8894 $w = 0;
8895 if (isset($objattr['width'])) {
8896 $w = $objattr['width'] / $k;
8897 }
8898 $h = 0;
8899 if (isset($objattr['height'])) {
8900 $h = abs($objattr['height'] / $k);
8901 }
8902 $widthLeft = $maxWidth - $widthUsed;
8903 $maxHeight = $this->h - ($this->tMargin + $this->bMargin + 10);
8904 if ($this->fullImageHeight) {
8905 $maxHeight = $this->fullImageHeight;
8906 }
8907 // For Images
8908 if (isset($objattr['border_left'])) {
8909 $extraWidth = ($objattr['border_left']['w'] + $objattr['border_right']['w'] + $objattr['margin_left'] + $objattr['margin_right']) / $k;
8910 $extraHeight = ($objattr['border_top']['w'] + $objattr['border_bottom']['w'] + $objattr['margin_top'] + $objattr['margin_bottom']) / $k;
8911
8912 if ($type == 'image' || $type == 'barcode' || $type == 'textcircle') {
8913 $extraWidth += ($objattr['padding_left'] + $objattr['padding_right']) / $k;
8914 $extraHeight += ($objattr['padding_top'] + $objattr['padding_bottom']) / $k;
8915 }
8916 }
8917
8918 if (!isset($objattr['vertical-align'])) {
8919 if ($objattr['type'] == 'select') {
8920 $objattr['vertical-align'] = 'M';
8921 } else {
8922 $objattr['vertical-align'] = 'BS';
8923 }
8924 } // mPDF 6
8925
8926 if ($type == 'image' || (isset($objattr['subtype']) && $objattr['subtype'] == 'IMAGE')) {
8927 if (isset($objattr['itype']) && ($objattr['itype'] == 'wmf' || $objattr['itype'] == 'svg')) {
8928 $file = $objattr['file'];
8929 $info = $this->formobjects[$file];
8930 } elseif (isset($objattr['file'])) {
8931 $file = $objattr['file'];
8932 $info = $this->images[$file];
8933 }
8934 }
8935 if ($type == 'annot' || $type == 'bookmark' || $type == 'indexentry' || $type == 'toc') {
8936 $w = 0.00001;
8937 $h = 0.00001;
8938 }
8939
8940 // TEST whether need to skipline
8941 if (!$paint) {
8942 if ($type == 'hr') { // always force new line
8943 if (($y + $h + $lineHeight > $this->PageBreakTrigger) && !$this->InFooter && !$is_table) {
8944 return array(-2, $w, $h);
8945 } // New page + new line
8946 else {
8947 return array(1, $w, $h);
8948 } // new line
8949 } else {
8950 // LIST MARKERS // mPDF 6 Lists
8951 $displayheight = $h;
8952 $displaywidth = $w;
8953 if ($objattr['type'] == 'image' && isset($objattr['listmarker']) && $objattr['listmarker']) {
8954 $displayheight = 0;
8955 if ($objattr['listmarkerposition'] == 'outside') {
8956 $displaywidth = 0;
8957 }
8958 }
8959
8960 if ($widthUsed > 0 && $displaywidth > $widthLeft && (!$is_table || $type != 'image')) { // New line needed
8961 // mPDF 6 Lists
8962 if (($y + $displayheight + $lineHeight > $this->PageBreakTrigger) && !$this->InFooter) {
8963 return array(-2, $w, $h);
8964 } // New page + new line
8965 return array(1, $w, $h); // new line
8966 } elseif ($widthUsed > 0 && $displaywidth > $widthLeft && $is_table) { // New line needed in TABLE
8967 return array(1, $w, $h); // new line
8968 }
8969 // Will fit on line but NEW PAGE REQUIRED
8970 elseif (($y + $displayheight > $this->PageBreakTrigger) && !$this->InFooter && !$is_table) {
8971 return array(-1, $w, $h);
8972 } // mPDF 6 Lists
8973 else {
8974 return array(0, $w, $h);
8975 }
8976 }
8977 }
8978
8979 if ($type == 'annot' || $type == 'bookmark' || $type == 'indexentry' || $type == 'toc') {
8980 $w = 0.00001;
8981 $h = 0.00001;
8982 $objattr['BORDER-WIDTH'] = 0;
8983 $objattr['BORDER-HEIGHT'] = 0;
8984 $objattr['BORDER-X'] = $x;
8985 $objattr['BORDER-Y'] = $y;
8986 $objattr['INNER-WIDTH'] = 0;
8987 $objattr['INNER-HEIGHT'] = 0;
8988 $objattr['INNER-X'] = $x;
8989 $objattr['INNER-Y'] = $y;
8990 }
8991
8992 if ($type == 'image') {
8993 // Automatically resize to width remaining
8994 if ($w > ($widthLeft + 0.0001) && !$is_table) { // mPDF 5.7.4 0.0001 to allow for rounding errors when w==maxWidth
8995 $w = $widthLeft;
8996 $h = abs($w * $info['h'] / $info['w']);
8997 }
8998 $img_w = $w - $extraWidth;
8999 $img_h = $h - $extraHeight;
9000
9001 $objattr['BORDER-WIDTH'] = $img_w + $objattr['padding_left'] / $k + $objattr['padding_right'] / $k + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2);
9002 $objattr['BORDER-HEIGHT'] = $img_h + $objattr['padding_top'] / $k + $objattr['padding_bottom'] / $k + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2);
9003 $objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2);
9004 $objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2);
9005 $objattr['INNER-WIDTH'] = $img_w;
9006 $objattr['INNER-HEIGHT'] = $img_h;
9007 $objattr['INNER-X'] = $x + $objattr['padding_left'] / $k + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k);
9008 $objattr['INNER-Y'] = $y + $objattr['padding_top'] / $k + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k);
9009 $objattr['ID'] = $info['i'];
9010 }
9011
9012 if ($type == 'input' && $objattr['subtype'] == 'IMAGE') {
9013 $img_w = $w - $extraWidth;
9014 $img_h = $h - $extraHeight;
9015 $objattr['BORDER-WIDTH'] = $img_w + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2);
9016 $objattr['BORDER-HEIGHT'] = $img_h + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2);
9017 $objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2);
9018 $objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2);
9019 $objattr['INNER-WIDTH'] = $img_w;
9020 $objattr['INNER-HEIGHT'] = $img_h;
9021 $objattr['INNER-X'] = $x + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k);
9022 $objattr['INNER-Y'] = $y + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k);
9023 $objattr['ID'] = $info['i'];
9024 }
9025
9026 if ($type == 'barcode' || $type == 'textcircle') {
9027 $b_w = $w - $extraWidth;
9028 $b_h = $h - $extraHeight;
9029 $objattr['BORDER-WIDTH'] = $b_w + $objattr['padding_left'] / $k + $objattr['padding_right'] / $k + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2);
9030 $objattr['BORDER-HEIGHT'] = $b_h + $objattr['padding_top'] / $k + $objattr['padding_bottom'] / $k + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2);
9031 $objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2);
9032 $objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2);
9033 $objattr['INNER-X'] = $x + $objattr['padding_left'] / $k + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k);
9034 $objattr['INNER-Y'] = $y + $objattr['padding_top'] / $k + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k);
9035 $objattr['INNER-WIDTH'] = $b_w;
9036 $objattr['INNER-HEIGHT'] = $b_h;
9037 }
9038
9039
9040 if ($type == 'textarea') {
9041 // Automatically resize to width remaining
9042 if ($w > $widthLeft && !$is_table) {
9043 $w = $widthLeft;
9044 }
9045 // This used to resize height to maximum remaining on page ? why. Causes problems when in table and causing a new column
9046 // if (($y + $h > $this->PageBreakTrigger) && !$this->InFooter) {
9047 // $h=$this->h - $y - $this->bMargin;
9048 // }
9049 }
9050
9051 if ($type == 'hr') {
9052 if ($is_table) {
9053 $objattr['INNER-WIDTH'] = $maxWidth * $objattr['W-PERCENT'] / 100;
9054 $objattr['width'] = $objattr['INNER-WIDTH'];
9055 $w = $maxWidth;
9056 } else {
9057 if ($w > $maxWidth) {
9058 $w = $maxWidth;
9059 }
9060 $objattr['INNER-WIDTH'] = $w;
9061 $w = $maxWidth;
9062 }
9063 }
9064
9065
9066
9067 if (($type == 'select') || ($type == 'input' && ($objattr['subtype'] == 'TEXT' || $objattr['subtype'] == 'PASSWORD'))) {
9068 // Automatically resize to width remaining
9069 if ($w > $widthLeft && !$is_table) {
9070 $w = $widthLeft;
9071 }
9072 }
9073
9074 if ($type == 'textarea' || $type == 'select' || $type == 'input') {
9075 if (isset($objattr['fontsize']))
9076 $objattr['fontsize'] /= $k;
9077 if (isset($objattr['linewidth']))
9078 $objattr['linewidth'] /= $k;
9079 }
9080
9081 if (!isset($objattr['BORDER-Y'])) {
9082 $objattr['BORDER-Y'] = 0;
9083 }
9084 if (!isset($objattr['BORDER-X'])) {
9085 $objattr['BORDER-X'] = 0;
9086 }
9087 if (!isset($objattr['INNER-Y'])) {
9088 $objattr['INNER-Y'] = 0;
9089 }
9090 if (!isset($objattr['INNER-X'])) {
9091 $objattr['INNER-X'] = 0;
9092 }
9093
9094 //Return width-height array
9095 $objattr['OUTER-WIDTH'] = $w;
9096 $objattr['OUTER-HEIGHT'] = $h;
9097 $objattr['OUTER-X'] = $x;
9098 $objattr['OUTER-Y'] = $y;
9099 return $objattr;
9100 }
9101
9102 /* -- END HTML-CSS -- */
9103
9104 //=============================================================
9105 //=============================================================
9106 //=============================================================
9107 //=============================================================
9108 //=============================================================
9109
9110 function SetLineJoin($mode = 0)
9111 {
9112 $s = sprintf('%d j', $mode);
9113 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineJoin']) && $this->pageoutput[$this->page]['LineJoin'] != $s) || !isset($this->pageoutput[$this->page]['LineJoin']))) {
9114 $this->_out($s);
9115 }
9116 $this->pageoutput[$this->page]['LineJoin'] = $s;
9117 }
9118
9119 function SetLineCap($mode = 2)
9120 {
9121 $s = sprintf('%d J', $mode);
9122 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineCap']) && $this->pageoutput[$this->page]['LineCap'] != $s) || !isset($this->pageoutput[$this->page]['LineCap']))) {
9123 $this->_out($s);
9124 }
9125 $this->pageoutput[$this->page]['LineCap'] = $s;
9126 }
9127
9128 function SetDash($black = false, $white = false)
9129 {
9130 if ($black and $white)
9131 $s = sprintf('[%.3F %.3F] 0 d', $black * _MPDFK, $white * _MPDFK);
9132 else
9133 $s = '[] 0 d';
9134 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Dash']) && $this->pageoutput[$this->page]['Dash'] != $s) || !isset($this->pageoutput[$this->page]['Dash']))) {
9135 $this->_out($s);
9136 }
9137 $this->pageoutput[$this->page]['Dash'] = $s;
9138 }
9139
9140 function SetDisplayPreferences($preferences)
9141 {
9142 // String containing any or none of /HideMenubar/HideToolbar/HideWindowUI/DisplayDocTitle/CenterWindow/FitWindow
9143 $this->DisplayPreferences .= $preferences;
9144 }
9145
9146 function Ln($h = '', $collapsible = 0)
9147 {
9148 // Added collapsible to allow collapsible top-margin on new page
9149 //Line feed; default value is last cell height
9150 $this->x = $this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'];
9151 if ($collapsible && ($this->y == $this->tMargin) && (!$this->ColActive)) {
9152 $h = 0;
9153 }
9154 if (is_string($h))
9155 $this->y+=$this->lasth;
9156 else
9157 $this->y+=$h;
9158 }
9159
9160 /* -- HTML-CSS -- */
9161
9162 function DivLn($h, $level = -3, $move_y = true, $collapsible = false, $state = 0)
9163 {
9164 // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
9165 // Used in Columns and keep-with-table i.e. "kwt"
9166 // writes background block by block so it can be repositioned
9167 // and also used in writingFlowingBlock at top and bottom of blocks to move y (not to draw/paint anything)
9168 // adds lines (y) where DIV bgcolors are filled in
9169 // this->x is returned as it was
9170 // allows .00001 as nominal height used for bookmarks/annotations etc.
9171 if ($collapsible && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->tMargin)) && (!$this->ColActive)) {
9172 return;
9173 }
9174
9175 // mPDF 6 Columns
9176 // if ($collapsible && (sprintf("%0.4f", $this->y)==sprintf("%0.4f", $this->y0)) && ($this->ColActive) && $this->CurrCol == 0) { return; } // *COLUMNS*
9177 if ($collapsible && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->y0)) && ($this->ColActive)) {
9178 return;
9179 } // *COLUMNS*
9180 // Still use this method if columns or keep-with-table, as it allows repositioning later
9181 // otherwise, now uses PaintDivBB()
9182 if (!$this->ColActive && !$this->kwt) {
9183 if ($move_y && !$this->ColActive) {
9184 $this->y += $h;
9185 }
9186 return;
9187 }
9188
9189 if ($level == -3) {
9190 $level = $this->blklvl;
9191 }
9192 $firstblockfill = $this->GetFirstBlockFill();
9193 if ($firstblockfill && $this->blklvl > 0 && $this->blklvl >= $firstblockfill) {
9194 $last_x = 0;
9195 $last_w = 0;
9196 $last_fc = $this->FillColor;
9197 $bak_x = $this->x;
9198 $bak_h = $this->divheight;
9199 $this->divheight = 0; // Temporarily turn off divheight - as Cell() uses it to check for PageBreak
9200 for ($blvl = $firstblockfill; $blvl <= $level; $blvl++) {
9201 $this->x = $this->lMargin + $this->blk[$blvl]['outer_left_margin'];
9202 // mPDF 6
9203 if ($this->blk[$blvl]['bgcolor']) {
9204 $this->SetFColor($this->blk[$blvl]['bgcolorarray']);
9205 }
9206 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'])) {
9207 $x = $this->x;
9208 $this->Cell(($this->blk[$blvl]['width']), $h, '', '', 0, '', 1);
9209 $this->x = $x;
9210 if (!$this->keep_block_together && !$this->writingHTMLheader && !$this->writingHTMLfooter) {
9211 // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
9212 if ($blvl == $this->blklvl) {
9213 $this->PaintDivLnBorder($state, $blvl, $h);
9214 } else {
9215 $this->PaintDivLnBorder(0, $blvl, $h);
9216 }
9217 }
9218 }
9219 $last_x = $this->lMargin + $this->blk[$blvl]['outer_left_margin'];
9220 $last_w = $this->blk[$blvl]['width'];
9221 $last_fc = $this->FillColor;
9222 }
9223 // Reset current block fill
9224 if (isset($this->blk[$this->blklvl]['bgcolorarray'])) {
9225 $bcor = $this->blk[$this->blklvl]['bgcolorarray'];
9226 $this->SetFColor($bcor);
9227 }
9228 $this->x = $bak_x;
9229 $this->divheight = $bak_h;
9230 }
9231 if ($move_y) {
9232 $this->y += $h;
9233 }
9234 }
9235
9236 /* -- END HTML-CSS -- */
9237
9238 function SetX($x)
9239 {
9240 //Set x position
9241 if ($x >= 0)
9242 $this->x = $x;
9243 else
9244 $this->x = $this->w + $x;
9245 }
9246
9247 function SetY($y)
9248 {
9249 //Set y position and reset x
9250 $this->x = $this->lMargin;
9251 if ($y >= 0)
9252 $this->y = $y;
9253 else
9254 $this->y = $this->h + $y;
9255 }
9256
9257 function SetXY($x, $y)
9258 {
9259 //Set x and y positions
9260 $this->SetY($y);
9261 $this->SetX($x);
9262 }
9263
9264 function Output($name = '', $dest = '')
9265 {
9266 //Output PDF to some destination
9267 if ($this->showStats) {
9268 echo '<div>Generated in ' . sprintf('%.2F', (microtime(true) - $this->time0)) . ' seconds</div>';
9269 }
9270 //Finish document if necessary
9271 if ($this->progressBar) {
9272 $this->UpdateProgressBar(1, '100', 'Finished');
9273 } // *PROGRESS-BAR*
9274 if ($this->state < 3)
9275 $this->Close();
9276 if ($this->progressBar) {
9277 $this->UpdateProgressBar(2, '100', 'Finished');
9278 } // *PROGRESS-BAR*
9279 // fn. error_get_last is only in PHP>=5.2
9280 if ($this->debug && function_exists('error_get_last') && error_get_last()) {
9281 $e = error_get_last();
9282 if (($e['type'] < 2048 && $e['type'] != 8) || (intval($e['type']) & intval(ini_get("error_reporting")))) {
9283 echo "<p>Error message detected - PDF file generation aborted.</p>";
9284 echo $e['message'] . '<br />';
9285 echo 'File: ' . $e['file'] . '<br />';
9286 echo 'Line: ' . $e['line'] . '<br />';
9287 exit;
9288 }
9289 }
9290
9291
9292 if (($this->PDFA || $this->PDFX) && $this->encrypted) {
9293 throw new MpdfException("PDFA1-b or PDFX/1-a does not permit encryption of documents.");
9294 }
9295 if (count($this->PDFAXwarnings) && (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto))) {
9296 if ($this->PDFA) {
9297 echo '<div>WARNING - This file could not be generated as it stands as a PDFA1-b compliant file.</div>';
9298 echo '<div>These issues can be automatically fixed by mPDF using <i>$mpdf-&gt;PDFAauto=true;</i></div>';
9299 echo '<div>Action that mPDF will take to automatically force PDFA1-b compliance are shown in brackets.</div>';
9300 } else {
9301 echo '<div>WARNING - This file could not be generated as it stands as a PDFX/1-a compliant file.</div>';
9302 echo '<div>These issues can be automatically fixed by mPDF using <i>$mpdf-&gt;PDFXauto=true;</i></div>';
9303 echo '<div>Action that mPDF will take to automatically force PDFX/1-a compliance are shown in brackets.</div>';
9304 }
9305 echo '<div>Warning(s) generated:</div><ul>';
9306 $this->PDFAXwarnings = array_unique($this->PDFAXwarnings);
9307 foreach ($this->PDFAXwarnings AS $w) {
9308 echo '<li>' . $w . '</li>';
9309 }
9310 echo '</ul>';
9311 exit;
9312 }
9313
9314 if ($this->showStats) {
9315 echo '<div>Compiled in ' . sprintf('%.2F', (microtime(true) - $this->time0)) . ' seconds (total)</div>';
9316 echo '<div>Peak Memory usage ' . number_format((memory_get_peak_usage(true) / (1024 * 1024)), 2) . ' MB</div>';
9317 echo '<div>PDF file size ' . number_format((strlen($this->buffer) / 1024)) . ' kB</div>';
9318 echo '<div>Number of fonts ' . count($this->fonts) . '</div>';
9319 exit;
9320 }
9321
9322
9323 if (is_bool($dest))
9324 $dest = $dest ? 'D' : 'F';
9325 $dest = strtoupper($dest);
9326 if ($dest == '') {
9327 if ($name == '') {
9328 $name = 'mpdf.pdf';
9329 $dest = 'I';
9330 } else {
9331 $dest = 'F';
9332 }
9333 }
9334
9335 /* -- PROGRESS-BAR -- */
9336 if ($this->progressBar && ($dest == 'D' || $dest == 'I')) {
9337 if ($name == '') {
9338 $name = 'mpdf.pdf';
9339 }
9340 $tempfile = '_tempPDF' . uniqid(rand(1, 100000), true);
9341 //Save to local file
9342 $f = fopen(_MPDF_TEMP_PATH . $tempfile . '.pdf', 'wb');
9343 if (!$f)
9344 throw new MpdfException('Unable to create temporary output file: ' . $tempfile . '.pdf');
9345 fwrite($f, $this->buffer, strlen($this->buffer));
9346 fclose($f);
9347 $this->UpdateProgressBar(3, '', 'Finished');
9348
9349 echo '<script type="text/javascript">
9350
9351 var form = document.createElement("form");
9352 form.setAttribute("method", "post");
9353 form.setAttribute("action", "' . _MPDF_URI . 'includes/out.php");
9354
9355 var hiddenField = document.createElement("input");
9356 hiddenField.setAttribute("type", "hidden");
9357 hiddenField.setAttribute("name", "filename");
9358 hiddenField.setAttribute("value", "' . $tempfile . '");
9359 form.appendChild(hiddenField);
9360
9361 var hiddenField = document.createElement("input");
9362 hiddenField.setAttribute("type", "hidden");
9363 hiddenField.setAttribute("name", "dest");
9364 hiddenField.setAttribute("value", "' . $dest . '");
9365 form.appendChild(hiddenField);
9366
9367 var hiddenField = document.createElement("input");
9368 hiddenField.setAttribute("type", "hidden");
9369 hiddenField.setAttribute("name", "opname");
9370 hiddenField.setAttribute("value", "' . $name . '");
9371 form.appendChild(hiddenField);
9372
9373 var hiddenField = document.createElement("input");
9374 hiddenField.setAttribute("type", "hidden");
9375 hiddenField.setAttribute("name", "path");
9376 hiddenField.setAttribute("value", "' . urlencode(_MPDF_TEMP_PATH) . '");
9377 form.appendChild(hiddenField);
9378
9379 document.body.appendChild(form);
9380 form.submit();
9381
9382 </script>
9383 </div>
9384 </body>
9385 </html>';
9386 exit;
9387 }
9388 else {
9389 if ($this->progressBar) {
9390 $this->UpdateProgressBar(3, '', 'Finished');
9391 }
9392 /* -- END PROGRESS-BAR -- */
9393
9394 switch ($dest) {
9395 case 'I':
9396 if ($this->debug && !$this->allow_output_buffering && ob_get_contents()) {
9397 echo "<p>Output has already been sent from the script - PDF file generation aborted.</p>";
9398 exit;
9399 }
9400 //Send to standard output
9401 if (PHP_SAPI != 'cli') {
9402 //We send to a browser
9403 header('Content-Type: application/pdf');
9404 if (headers_sent())
9405 throw new MpdfException('Some data has already been output to browser, can\'t send PDF file');
9406 if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) OR empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
9407 // don't use length if server using compression
9408 header('Content-Length: ' . strlen($this->buffer));
9409 }
9410 header('Content-disposition: inline; filename="' . $name . '"');
9411 header('Cache-Control: public, must-revalidate, max-age=0');
9412 header('Pragma: public');
9413 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
9414 header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
9415 }
9416 echo $this->buffer;
9417 break;
9418 case 'D':
9419 //Download file
9420 header('Content-Description: File Transfer');
9421 if (headers_sent())
9422 throw new MpdfException('Some data has already been output to browser, can\'t send PDF file');
9423 header('Content-Transfer-Encoding: binary');
9424 header('Cache-Control: public, must-revalidate, max-age=0');
9425 header('Pragma: public');
9426 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
9427 header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
9428 header('Content-Type: application/force-download');
9429 header('Content-Type: application/octet-stream', false);
9430 header('Content-Type: application/download', false);
9431 header('Content-Type: application/pdf', false);
9432 if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) OR empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
9433 // don't use length if server using compression
9434 header('Content-Length: ' . strlen($this->buffer));
9435 }
9436 header('Content-disposition: attachment; filename="' . $name . '"');
9437 echo $this->buffer;
9438 break;
9439 case 'F':
9440 //Save to local file
9441 $f = fopen($name, 'wb');
9442 if (!$f)
9443 throw new MpdfException('Unable to create output file: ' . $name);
9444 fwrite($f, $this->buffer, strlen($this->buffer));
9445 fclose($f);
9446 break;
9447 case 'S':
9448 //Return as a string
9449 return $this->buffer;
9450 default:
9451 throw new MpdfException('Incorrect output destination: ' . $dest);
9452 }
9453 } // *PROGRESS-BAR*
9454 //======================================================================================================
9455 // DELETE OLD TMP FILES - Housekeeping
9456 // Delete any files in tmp/ directory that are >1 hrs old
9457 $interval = 3600;
9458 if ($handle = @opendir(preg_replace('/\/$/', '', _MPDF_TEMP_PATH))) { // mPDF 5.7.3
9459 while (false !== ($file = readdir($handle))) {
9460 if (($file != "..") && ($file != ".") && !is_dir(_MPDF_TEMP_PATH . $file) && ((filemtime(_MPDF_TEMP_PATH . $file) + $interval) < time()) && (substr($file, 0, 1) !== '.') && ($file != 'dummy.txt')) { // mPDF 5.7.3
9461 unlink(_MPDF_TEMP_PATH . $file);
9462 }
9463 }
9464 closedir($handle);
9465 }
9466 //==============================================================================================================
9467
9468 return '';
9469 }
9470
9471 // *****************************************************************************
9472 // *
9473 // Protected methods *
9474 // *
9475 // *****************************************************************************
9476 function _dochecks()
9477 {
9478 //Check for locale-related bug
9479 if (1.1 == 1)
9480 throw new MpdfException('Don\'t alter the locale before including mPDF');
9481 //Check for decimal separator
9482 if (sprintf('%.1f', 1.0) != '1.0')
9483 setlocale(LC_NUMERIC, 'C');
9484 $mqr = ini_get("magic_quotes_runtime");
9485 if ($mqr) {
9486 throw new MpdfException('mPDF requires magic_quotes_runtime to be turned off e.g. by using ini_set("magic_quotes_runtime", 0);');
9487 }
9488 }
9489
9490 function _puthtmlheaders()
9491 {
9492 $this->state = 2;
9493 $nb = $this->page;
9494 for ($n = 1; $n <= $nb; $n++) {
9495 if ($this->mirrorMargins && $n % 2 == 0) {
9496 $OE = 'E';
9497 } // EVEN
9498 else {
9499 $OE = 'O';
9500 }
9501 $this->page = $n;
9502 $pn = $this->docPageNum($n);
9503 if ($pn)
9504 $pnstr = $this->pagenumPrefix . $pn . $this->pagenumSuffix;
9505 else {
9506 $pnstr = '';
9507 }
9508 $pnt = $this->docPageNumTotal($n);
9509 if ($pnt)
9510 $pntstr = $this->nbpgPrefix . $pnt . $this->nbpgSuffix;
9511 else {
9512 $pntstr = '';
9513 }
9514 if (isset($this->saveHTMLHeader[$n][$OE])) {
9515 $html = $this->saveHTMLHeader[$n][$OE]['html'];
9516 $this->lMargin = $this->saveHTMLHeader[$n][$OE]['ml'];
9517 $this->rMargin = $this->saveHTMLHeader[$n][$OE]['mr'];
9518 $this->tMargin = $this->saveHTMLHeader[$n][$OE]['mh'];
9519 $this->bMargin = $this->saveHTMLHeader[$n][$OE]['mf'];
9520 $this->margin_header = $this->saveHTMLHeader[$n][$OE]['mh'];
9521 $this->margin_footer = $this->saveHTMLHeader[$n][$OE]['mf'];
9522 $this->w = $this->saveHTMLHeader[$n][$OE]['pw'];
9523 $this->h = $this->saveHTMLHeader[$n][$OE]['ph'];
9524 $rotate = (isset($this->saveHTMLHeader[$n][$OE]['rotate']) ? $this->saveHTMLHeader[$n][$OE]['rotate'] : null);
9525 $this->Reset();
9526 $this->pageoutput[$n] = array();
9527 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
9528 $this->x = $this->lMargin;
9529 $this->y = $this->margin_header;
9530 $html = str_replace('{PAGENO}', $pnstr, $html);
9531 $html = str_replace($this->aliasNbPgGp, $pntstr, $html); // {nbpg}
9532 $html = str_replace($this->aliasNbPg, $nb, $html); // {nb}
9533 $html = preg_replace_callback('/\{DATE\s+(.*?)\}/', array($this, 'date_callback'), $html); // mPDF 5.7
9534
9535 $this->HTMLheaderPageLinks = array();
9536 $this->HTMLheaderPageAnnots = array();
9537 $this->HTMLheaderPageForms = array();
9538 $this->pageBackgrounds = array();
9539
9540 $this->writingHTMLheader = true;
9541 $this->WriteHTML($html, 4); // parameter 4 saves output to $this->headerbuffer
9542 $this->writingHTMLheader = false;
9543 $this->Reset();
9544 $this->pageoutput[$n] = array();
9545
9546 $s = $this->PrintPageBackgrounds();
9547 $this->headerbuffer = $s . $this->headerbuffer;
9548 $os = '';
9549 if ($rotate) {
9550 $os .= sprintf('q 0 -1 1 0 0 %.3F cm ', ($this->w * _MPDFK));
9551 // To rotate the other way i.e. Header to left of page:
9552 //$os .= sprintf('q 0 1 -1 0 %.3F %.3F cm ',($this->h*_MPDFK), (($this->rMargin - $this->lMargin )*_MPDFK));
9553 }
9554 $os .= $this->headerbuffer;
9555 if ($rotate) {
9556 $os .= ' Q' . "\n";
9557 }
9558
9559 // Writes over the page background but behind any other output on page
9560 $os = preg_replace('/\\\\/', '\\\\\\\\', $os);
9561 $this->pages[$n] = preg_replace('/(___HEADER___MARKER' . $this->uniqstr . ')/', "\n" . $os . "\n" . '\\1', $this->pages[$n]);
9562
9563 $lks = $this->HTMLheaderPageLinks;
9564 foreach ($lks AS $lk) {
9565 if ($rotate) {
9566 $lw = $lk[2];
9567 $lh = $lk[3];
9568 $lk[2] = $lh;
9569 $lk[3] = $lw; // swap width and height
9570 $ax = $lk[0] / _MPDFK;
9571 $ay = $lk[1] / _MPDFK;
9572 $bx = $ay - ($lh / _MPDFK);
9573 $by = $this->w - $ax;
9574 $lk[0] = $bx * _MPDFK;
9575 $lk[1] = ($this->h - $by) * _MPDFK - $lw;
9576 }
9577 $this->PageLinks[$n][] = $lk;
9578 }
9579 /* -- FORMS -- */
9580 foreach ($this->HTMLheaderPageForms AS $f) {
9581 $this->mpdfform->forms[$f['n']] = $f;
9582 }
9583 /* -- END FORMS -- */
9584 }
9585 if (isset($this->saveHTMLFooter[$n][$OE])) {
9586 $html = $this->saveHTMLFooter[$this->page][$OE]['html'];
9587 $this->lMargin = $this->saveHTMLFooter[$n][$OE]['ml'];
9588 $this->rMargin = $this->saveHTMLFooter[$n][$OE]['mr'];
9589 $this->tMargin = $this->saveHTMLFooter[$n][$OE]['mh'];
9590 $this->bMargin = $this->saveHTMLFooter[$n][$OE]['mf'];
9591 $this->margin_header = $this->saveHTMLFooter[$n][$OE]['mh'];
9592 $this->margin_footer = $this->saveHTMLFooter[$n][$OE]['mf'];
9593 $this->w = $this->saveHTMLFooter[$n][$OE]['pw'];
9594 $this->h = $this->saveHTMLFooter[$n][$OE]['ph'];
9595 $rotate = (isset($this->saveHTMLFooter[$n][$OE]['rotate']) ? $this->saveHTMLFooter[$n][$OE]['rotate'] : null);
9596 $this->Reset();
9597 $this->pageoutput[$n] = array();
9598 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
9599 $this->x = $this->lMargin;
9600 $top_y = $this->y = $this->h - $this->margin_footer;
9601
9602 // if bottom-margin==0, corrects to avoid division by zero
9603 if ($this->y == $this->h) {
9604 $top_y = $this->y = ($this->h - 0.1);
9605 }
9606 $html = str_replace('{PAGENO}', $pnstr, $html);
9607 $html = str_replace($this->aliasNbPgGp, $pntstr, $html); // {nbpg}
9608 $html = str_replace($this->aliasNbPg, $nb, $html); // {nb}
9609 $html = preg_replace_callback('/\{DATE\s+(.*?)\}/', array($this, 'date_callback'), $html); // mPDF 5.7
9610
9611
9612 $this->HTMLheaderPageLinks = array();
9613 $this->HTMLheaderPageAnnots = array();
9614 $this->HTMLheaderPageForms = array();
9615 $this->pageBackgrounds = array();
9616
9617 $this->writingHTMLfooter = true;
9618 $this->InFooter = true;
9619 $this->WriteHTML($html, 4); // parameter 4 saves output to $this->headerbuffer
9620 $this->InFooter = false;
9621 $this->Reset();
9622 $this->pageoutput[$n] = array();
9623
9624 $fheight = $this->y - $top_y;
9625 $adj = -$fheight;
9626
9627 $s = $this->PrintPageBackgrounds(-$adj);
9628 $this->headerbuffer = $s . $this->headerbuffer;
9629 $this->writingHTMLfooter = false; // mPDF 5.7.3 (moved after PrintPageBackgrounds so can adjust position of images in footer)
9630
9631 $os = '';
9632 $os .= $this->StartTransform(true) . "\n";
9633 if ($rotate) {
9634 $os .= sprintf('q 0 -1 1 0 0 %.3F cm ', ($this->w * _MPDFK));
9635 // To rotate the other way i.e. Header to left of page:
9636 //$os .= sprintf('q 0 1 -1 0 %.3F %.3F cm ',($this->h*_MPDFK), (($this->rMargin - $this->lMargin )*_MPDFK));
9637 }
9638 $os .= $this->transformTranslate(0, $adj, true) . "\n";
9639 $os .= $this->headerbuffer;
9640 if ($rotate) {
9641 $os .= ' Q' . "\n";
9642 }
9643 $os .= $this->StopTransform(true) . "\n";
9644 // Writes over the page background but behind any other output on page
9645 $os = preg_replace('/\\\\/', '\\\\\\\\', $os);
9646 $this->pages[$n] = preg_replace('/(___HEADER___MARKER' . $this->uniqstr . ')/', "\n" . $os . "\n" . '\\1', $this->pages[$n]);
9647
9648 $lks = $this->HTMLheaderPageLinks;
9649 foreach ($lks AS $lk) {
9650 $lk[1] -= $adj * _MPDFK;
9651 if ($rotate) {
9652 $lw = $lk[2];
9653 $lh = $lk[3];
9654 $lk[2] = $lh;
9655 $lk[3] = $lw; // swap width and height
9656
9657 $ax = $lk[0] / _MPDFK;
9658 $ay = $lk[1] / _MPDFK;
9659 $bx = $ay - ($lh / _MPDFK);
9660 $by = $this->w - $ax;
9661 $lk[0] = $bx * _MPDFK;
9662 $lk[1] = ($this->h - $by) * _MPDFK - $lw;
9663 }
9664 $this->PageLinks[$n][] = $lk;
9665 }
9666 /* -- FORMS -- */
9667 foreach ($this->HTMLheaderPageForms AS $f) {
9668 $f['y'] += $adj;
9669 $this->mpdfform->forms[$f['n']] = $f;
9670 }
9671 /* -- END FORMS -- */
9672 }
9673 }
9674 $this->page = $nb;
9675 $this->state = 1;
9676 }
9677
9678 function _putpages()
9679 {
9680 $nb = $this->page;
9681 $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
9682
9683 if ($this->DefOrientation == 'P') {
9684 $defwPt = $this->fwPt;
9685 $defhPt = $this->fhPt;
9686 } else {
9687 $defwPt = $this->fhPt;
9688 $defhPt = $this->fwPt;
9689 }
9690 $annotid = (3 + 2 * $nb);
9691
9692 // Active Forms
9693 $totaladdnum = 0;
9694 for ($n = 1; $n <= $nb; $n++) {
9695 if (isset($this->PageLinks[$n])) {
9696 $totaladdnum += count($this->PageLinks[$n]);
9697 }
9698 /* -- ANNOTATIONS -- */
9699 if (isset($this->PageAnnots[$n])) {
9700 foreach ($this->PageAnnots[$n] as $k => $pl) {
9701 if (!empty($pl['opt']['popup']) || !empty($pl['opt']['file'])) {
9702 $totaladdnum += 2;
9703 } else {
9704 $totaladdnum++;
9705 }
9706 }
9707 }
9708 /* -- END ANNOTATIONS -- */
9709
9710 /* -- FORMS -- */
9711 if (count($this->mpdfform->forms) > 0) {
9712 $this->mpdfform->countPageForms($n, $totaladdnum);
9713 }
9714 /* -- END FORMS -- */
9715 }
9716 /* -- FORMS -- */
9717 // Make a note in the radio button group of the obj_id it will have
9718 $ctr = 0;
9719 if (count($this->mpdfform->form_radio_groups)) {
9720 foreach ($this->mpdfform->form_radio_groups AS $name => $frg) {
9721 $this->mpdfform->form_radio_groups[$name]['obj_id'] = $annotid + $totaladdnum + $ctr;
9722 $ctr++;
9723 }
9724 }
9725 /* -- END FORMS -- */
9726
9727 // Select unused fonts (usually default font)
9728 $unused = array();
9729 foreach ($this->fonts as $fk => $font) {
9730 if (isset($font['type']) && $font['type'] == 'TTF' && !$font['used']) {
9731 $unused[] = $fk;
9732 }
9733 }
9734
9735
9736 for ($n = 1; $n <= $nb; $n++) {
9737 $thispage = $this->pages[$n];
9738 if (isset($this->OrientationChanges[$n])) {
9739 $hPt = $this->pageDim[$n]['w'] * _MPDFK;
9740 $wPt = $this->pageDim[$n]['h'] * _MPDFK;
9741 $owidthPt_LR = $this->pageDim[$n]['outer_width_TB'] * _MPDFK;
9742 $owidthPt_TB = $this->pageDim[$n]['outer_width_LR'] * _MPDFK;
9743 } else {
9744 $wPt = $this->pageDim[$n]['w'] * _MPDFK;
9745 $hPt = $this->pageDim[$n]['h'] * _MPDFK;
9746 $owidthPt_LR = $this->pageDim[$n]['outer_width_LR'] * _MPDFK;
9747 $owidthPt_TB = $this->pageDim[$n]['outer_width_TB'] * _MPDFK;
9748 }
9749 // Remove references to unused fonts (usually default font)
9750 foreach ($unused as $fk) {
9751 if ($this->fonts[$fk]['sip'] || $this->fonts[$fk]['smp']) {
9752 foreach ($this->fonts[$fk]['subsetfontids'] AS $k => $fid) {
9753 $thispage = preg_replace('/\s\/F' . $fid . ' \d[\d.]* Tf\s/is', ' ', $thispage);
9754 }
9755 } else {
9756 $thispage = preg_replace('/\s\/F' . $this->fonts[$fk]['i'] . ' \d[\d.]* Tf\s/is', ' ', $thispage);
9757 }
9758 }
9759 // Clean up repeated /GS1 gs statements
9760 // For some reason using + for repetition instead of {2,20} crashes PHP Script Interpreter ???
9761 $thispage = preg_replace('/(\/GS1 gs\n){2,20}/', "/GS1 gs\n", $thispage);
9762
9763 $thispage = preg_replace('/(\s*___BACKGROUND___PATTERNS' . $this->uniqstr . '\s*)/', " ", $thispage);
9764 $thispage = preg_replace('/(\s*___HEADER___MARKER' . $this->uniqstr . '\s*)/', " ", $thispage);
9765 $thispage = preg_replace('/(\s*___PAGE___START' . $this->uniqstr . '\s*)/', " ", $thispage);
9766 $thispage = preg_replace('/(\s*___TABLE___BACKGROUNDS' . $this->uniqstr . '\s*)/', " ", $thispage);
9767 // mPDF 5.7.3 TRANSFORMS
9768 while (preg_match('/(\% BTR(.*?)\% ETR)/is', $thispage, $m)) {
9769 $thispage = preg_replace('/(\% BTR.*?\% ETR)/is', '', $thispage, 1) . "\n" . $m[2];
9770 }
9771
9772 //Page
9773 $this->_newobj();
9774 $this->_out('<</Type /Page');
9775 $this->_out('/Parent 1 0 R');
9776 if (isset($this->OrientationChanges[$n])) {
9777 $this->_out(sprintf('/MediaBox [0 0 %.3F %.3F]', $hPt, $wPt));
9778 //If BleedBox is defined, it must be larger than the TrimBox, but smaller than the MediaBox
9779 $bleedMargin = $this->pageDim[$n]['bleedMargin'] * _MPDFK;
9780 if ($bleedMargin && ($owidthPt_TB || $owidthPt_LR)) {
9781 $x0 = $owidthPt_TB - $bleedMargin;
9782 $y0 = $owidthPt_LR - $bleedMargin;
9783 $x1 = $hPt - $owidthPt_TB + $bleedMargin;
9784 $y1 = $wPt - $owidthPt_LR + $bleedMargin;
9785 $this->_out(sprintf('/BleedBox [%.3F %.3F %.3F %.3F]', $x0, $y0, $x1, $y1));
9786 }
9787 $this->_out(sprintf('/TrimBox [%.3F %.3F %.3F %.3F]', $owidthPt_TB, $owidthPt_LR, ($hPt - $owidthPt_TB), ($wPt - $owidthPt_LR)));
9788 if (isset($this->OrientationChanges[$n]) && $this->displayDefaultOrientation) {
9789 if ($this->DefOrientation == 'P') {
9790 $this->_out('/Rotate 270');
9791 } else {
9792 $this->_out('/Rotate 90');
9793 }
9794 }
9795 }
9796 //elseif($wPt != $defwPt || $hPt != $defhPt) {
9797 else {
9798 $this->_out(sprintf('/MediaBox [0 0 %.3F %.3F]', $wPt, $hPt));
9799 $bleedMargin = $this->pageDim[$n]['bleedMargin'] * _MPDFK;
9800 if ($bleedMargin && ($owidthPt_TB || $owidthPt_LR)) {
9801 $x0 = $owidthPt_LR - $bleedMargin;
9802 $y0 = $owidthPt_TB - $bleedMargin;
9803 $x1 = $wPt - $owidthPt_LR + $bleedMargin;
9804 $y1 = $hPt - $owidthPt_TB + $bleedMargin;
9805 $this->_out(sprintf('/BleedBox [%.3F %.3F %.3F %.3F]', $x0, $y0, $x1, $y1));
9806 }
9807 $this->_out(sprintf('/TrimBox [%.3F %.3F %.3F %.3F]', $owidthPt_LR, $owidthPt_TB, ($wPt - $owidthPt_LR), ($hPt - $owidthPt_TB)));
9808 }
9809 $this->_out('/Resources 2 0 R');
9810
9811 // Important to keep in RGB colorSpace when using transparency
9812 if (!$this->PDFA && !$this->PDFX) {
9813 if ($this->restrictColorSpace == 3)
9814 $this->_out('/Group << /Type /Group /S /Transparency /CS /DeviceCMYK >> ');
9815 elseif ($this->restrictColorSpace == 1)
9816 $this->_out('/Group << /Type /Group /S /Transparency /CS /DeviceGray >> ');
9817 else
9818 $this->_out('/Group << /Type /Group /S /Transparency /CS /DeviceRGB >> ');
9819 }
9820
9821 $annotsnum = 0;
9822 $embeddedfiles = array(); // mPDF 5.7.2 /EmbeddedFiles
9823
9824 if (isset($this->PageLinks[$n])) {
9825 $annotsnum += count($this->PageLinks[$n]);
9826 }
9827 /* -- ANNOTATIONS -- */
9828 if (isset($this->PageAnnots[$n])) {
9829 foreach ($this->PageAnnots[$n] as $k => $pl) {
9830 if (!empty($pl['opt']['file'])) {
9831 $embeddedfiles[$annotsnum + 1] = true;
9832 } // mPDF 5.7.2 /EmbeddedFiles
9833 if (!empty($pl['opt']['popup']) || !empty($pl['opt']['file'])) {
9834 $annotsnum += 2;
9835 } else {
9836 $annotsnum++;
9837 }
9838 $this->PageAnnots[$n][$k]['pageobj'] = $this->n;
9839 }
9840 }
9841 /* -- END ANNOTATIONS -- */
9842
9843 /* -- FORMS -- */
9844 // Active Forms
9845 $formsnum = 0;
9846 if (count($this->mpdfform->forms) > 0) {
9847 foreach ($this->mpdfform->forms as $val) {
9848 if ($val['page'] == $n)
9849 $formsnum++;
9850 }
9851 }
9852 /* -- END FORMS -- */
9853 if ($annotsnum || $formsnum) {
9854 $s = '/Annots [ ';
9855 for ($i = 0; $i < $annotsnum; $i++) {
9856 if (!isset($embeddedfiles[$i])) {
9857 $s .= ($annotid + $i) . ' 0 R ';
9858 } // mPDF 5.7.2 /EmbeddedFiles
9859 }
9860 $annotid += $annotsnum;
9861 /* -- FORMS -- */
9862 if (count($this->mpdfform->forms) > 0) {
9863 $this->mpdfform->addFormIds($n, $s, $annotid);
9864 }
9865 /* -- END FORMS -- */
9866 $s .= '] ';
9867 $this->_out($s);
9868 }
9869
9870 $this->_out('/Contents ' . ($this->n + 1) . ' 0 R>>');
9871 $this->_out('endobj');
9872
9873 //Page content
9874 $this->_newobj();
9875 $p = ($this->compress) ? gzcompress($thispage) : $thispage;
9876 $this->_out('<<' . $filter . '/Length ' . strlen($p) . '>>');
9877 $this->_putstream($p);
9878 $this->_out('endobj');
9879 }
9880 $this->_putannots(); // mPDF 5.7.2
9881 //Pages root
9882 $this->offsets[1] = strlen($this->buffer);
9883 $this->_out('1 0 obj');
9884 $this->_out('<</Type /Pages');
9885 $kids = '/Kids [';
9886 for ($i = 0; $i < $nb; $i++)
9887 $kids.=(3 + 2 * $i) . ' 0 R ';
9888 $this->_out($kids . ']');
9889 $this->_out('/Count ' . $nb);
9890 $this->_out(sprintf('/MediaBox [0 0 %.3F %.3F]', $defwPt, $defhPt));
9891 $this->_out('>>');
9892 $this->_out('endobj');
9893 }
9894
9895 function _putannots()
9896 { // mPDF 5.7.2
9897 $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
9898 $nb = $this->page;
9899 for ($n = 1; $n <= $nb; $n++) {
9900 $annotobjs = array();
9901 if (isset($this->PageLinks[$n]) || isset($this->PageAnnots[$n]) || count($this->mpdfform->forms) > 0) {
9902 $wPt = $this->pageDim[$n]['w'] * _MPDFK;
9903 $hPt = $this->pageDim[$n]['h'] * _MPDFK;
9904
9905 //Links
9906 global $pdfprnt_links;
9907 if (isset($this->PageLinks[$n])) {
9908 foreach ($this->PageLinks[$n] as $key => $pl) {
9909 $this->_newobj();
9910 $annot = '';
9911 $rect = sprintf('%.3F %.3F %.3F %.3F', $pl[0], $pl[1], $pl[0] + $pl[2], $pl[1] - $pl[3]);
9912 $annot .= '<</Type /Annot /Subtype /Link /Rect [' . $rect . ']';
9913 $annot .= ( empty( $pdfprnt_links ) ) ? ' /Contents ' . $this->_UTF16BEtextstring($pl[4]) : '';
9914 $annot .= ' /NM ' . $this->_textstring(sprintf('%04u-%04u', $n, $key));
9915 $annot .= ' /M ' . $this->_textstring('D:' . date('YmdHis'));
9916 $annot .= ' /Border [0 0 0]';
9917 // Use this (instead of /Border) to specify border around link
9918 // $annot .= ' /BS <</W 1'; // Width on points; 0 = no line
9919 // $annot .= ' /S /D'; // style - [S]olid, [D]ashed, [B]eveled, [I]nset, [U]nderline
9920 // $annot .= ' /D [3 2]'; // Dash array - if dashed
9921 // $annot .= ' >>';
9922 // $annot .= ' /C [1 0 0]'; // Color RGB
9923
9924 if ($this->PDFA || $this->PDFX) {
9925 $annot .= ' /F 28';
9926 }
9927 if (strpos($pl[4], '@') === 0) {
9928 $p = substr($pl[4], 1);
9929 // $h=isset($this->OrientationChanges[$p]) ? $wPt : $hPt;
9930 $htarg = $this->pageDim[$p]['h'] * _MPDFK;
9931 $annot.=sprintf(' /Dest [%d 0 R /XYZ 0 %.3F null]>>', 1 + 2 * $p, $htarg);
9932 } elseif (is_string($pl[4])) {
9933 $annot .= ' /A <</S /URI /URI ' . $this->_textstring($pl[4]) . '>> >>';
9934 } else {
9935 $l = $this->links[$pl[4]];
9936 // may not be set if #link points to non-existent target
9937 if (isset($this->pageDim[$l[0]]['h'])) {
9938 $htarg = $this->pageDim[$l[0]]['h'] * _MPDFK;
9939 } else {
9940 $htarg = $this->h * _MPDFK;
9941 } // doesn't really matter
9942 $annot.=sprintf(' /Dest [%d 0 R /XYZ 0 %.3F null]>>', 1 + 2 * $l[0], $htarg - $l[1] * _MPDFK);
9943 }
9944 $this->_out($annot);
9945 $this->_out('endobj');
9946 }
9947 }
9948
9949
9950 /* -- ANNOTATIONS -- */
9951 if (isset($this->PageAnnots[$n])) {
9952 foreach ($this->PageAnnots[$n] as $key => $pl) {
9953 if ($pl['opt']['file']) {
9954 $FileAttachment = true;
9955 } else {
9956 $FileAttachment = false;
9957 }
9958 $this->_newobj();
9959 $annot = '';
9960 $pl['opt'] = array_change_key_case($pl['opt'], CASE_LOWER);
9961 $x = $pl['x'];
9962 if ($this->annotMargin <> 0 || $x == 0 || $x < 0) { // Odd page
9963 $x = ($wPt / _MPDFK) - $this->annotMargin;
9964 }
9965 $w = $h = 0;
9966 $a = $x * _MPDFK;
9967 $b = $hPt - ($pl['y'] * _MPDFK);
9968 $annot .= '<</Type /Annot ';
9969 if ($FileAttachment) {
9970 $annot .= '/Subtype /FileAttachment ';
9971 // Need to set a size for FileAttachment icons
9972 if ($pl['opt']['icon'] == 'Paperclip') {
9973 $w = 8.235;
9974 $h = 20;
9975 } // 7,17
9976 elseif ($pl['opt']['icon'] == 'Tag') {
9977 $w = 20;
9978 $h = 16;
9979 } elseif ($pl['opt']['icon'] == 'Graph') {
9980 $w = 20;
9981 $h = 20;
9982 } else {
9983 $w = 14;
9984 $h = 20;
9985 } // PushPin
9986 $f = $pl['opt']['file'];
9987 $f = preg_replace('/^.*\//', '', $f);
9988 $f = preg_replace('/[^a-zA-Z0-9._]/', '', $f);
9989 $annot .= '/FS <</Type /Filespec /F (' . $f . ')';
9990 $annot .= '/EF <</F ' . ($this->n + 1) . ' 0 R>>';
9991 $annot .= '>>';
9992 } else {
9993 $annot .= '/Subtype /Text';
9994 $w = 20;
9995 $h = 20; // mPDF 6
9996 }
9997 $rect = sprintf('%.3F %.3F %.3F %.3F', $a, $b - $h, $a + $w, $b);
9998 $annot .= ' /Rect [' . $rect . ']';
9999
10000 // contents = description of file in free text
10001 $annot .= ' /Contents ' . $this->_UTF16BEtextstring($pl['txt']);
10002
10003 $annot .= ' /NM ' . $this->_textstring(sprintf('%04u-%04u', $n, (2000 + $key)));
10004 $annot .= ' /M ' . $this->_textstring('D:' . date('YmdHis'));
10005 $annot .= ' /CreationDate ' . $this->_textstring('D:' . date('YmdHis'));
10006 $annot .= ' /Border [0 0 0]';
10007 if ($this->PDFA || $this->PDFX) {
10008 $annot .= ' /F 28';
10009 $annot .= ' /CA 1';
10010 } elseif ($pl['opt']['ca'] > 0) {
10011 $annot .= ' /CA ' . $pl['opt']['ca'];
10012 }
10013
10014 $annotcolor = ' /C [';
10015 if (isset($pl['opt']['c']) AND $pl['opt']['c']) {
10016 $col = $pl['opt']['c'];
10017 if ($col[0] == 3 || $col[0] == 5) {
10018 $annotcolor .= sprintf("%.3F %.3F %.3F", ord($col[1]) / 255, ord($col[2]) / 255, ord($col[3]) / 255);
10019 } elseif ($col[0] == 1) {
10020 $annotcolor .= sprintf("%.3F", ord($col[1]) / 255);
10021 } elseif ($col[0] == 4 || $col[0] == 6) {
10022 $annotcolor .= sprintf("%.3F %.3F %.3F %.3F", ord($col[1]) / 100, ord($col[2]) / 100, ord($col[3]) / 100, ord($col[4]) / 100);
10023 } else {
10024 $annotcolor .= '1 1 0';
10025 }
10026 } else {
10027 $annotcolor .= '1 1 0';
10028 }
10029 $annotcolor .= ']';
10030 $annot .= $annotcolor;
10031 // Usually Author
10032 // Use as Title for fileattachment
10033 if (isset($pl['opt']['t']) AND is_string($pl['opt']['t'])) {
10034 $annot .= ' /T ' . $this->_UTF16BEtextstring($pl['opt']['t']);
10035 }
10036 if ($FileAttachment) {
10037 $iconsapp = array('Paperclip', 'Graph', 'PushPin', 'Tag');
10038 } else {
10039 $iconsapp = array('Comment', 'Help', 'Insert', 'Key', 'NewParagraph', 'Note', 'Paragraph');
10040 }
10041 if (isset($pl['opt']['icon']) AND in_array($pl['opt']['icon'], $iconsapp)) {
10042 $annot .= ' /Name /' . $pl['opt']['icon'];
10043 } elseif ($FileAttachment) {
10044 $annot .= ' /Name /PushPin';
10045 } else {
10046 $annot .= ' /Name /Note';
10047 }
10048 if (!$FileAttachment) {
10049 // /Subj is PDF 1.5 spec.
10050 if (isset($pl['opt']['subj']) && !$this->PDFA && !$this->PDFX) {
10051 $annot .= ' /Subj ' . $this->_UTF16BEtextstring($pl['opt']['subj']);
10052 }
10053 if (!empty($pl['opt']['popup'])) {
10054 $annot .= ' /Open true';
10055 $annot .= ' /Popup ' . ($this->n + 1) . ' 0 R';
10056 } else {
10057 $annot .= ' /Open false';
10058 }
10059 }
10060 $annot .= ' /P ' . $pl['pageobj'] . ' 0 R';
10061 $annot .= '>>';
10062 $this->_out($annot);
10063 $this->_out('endobj');
10064
10065 if ($FileAttachment) {
10066 $file = @file_get_contents($pl['opt']['file']);
10067 if (!$file) {
10068 throw new MpdfException('mPDF Error: Cannot access file attachment - ' . $pl['opt']['file']);
10069 }
10070 $filestream = gzcompress($file);
10071 $this->_newobj();
10072 $this->_out('<</Type /EmbeddedFile');
10073 $this->_out('/Length ' . strlen($filestream));
10074 $this->_out('/Filter /FlateDecode');
10075 $this->_out('>>');
10076 $this->_putstream($filestream);
10077 $this->_out('endobj');
10078 } elseif (!empty($pl['opt']['popup'])) {
10079 $this->_newobj();
10080 $annot = '';
10081 if (is_array($pl['opt']['popup']) && isset($pl['opt']['popup'][0])) {
10082 $x = $pl['opt']['popup'][0] * _MPDFK;
10083 } else {
10084 $x = $pl['x'] * _MPDFK;
10085 }
10086 if (is_array($pl['opt']['popup']) && isset($pl['opt']['popup'][1])) {
10087 $y = $hPt - ($pl['opt']['popup'][1] * _MPDFK);
10088 } else {
10089 $y = $hPt - ($pl['y'] * _MPDFK);
10090 }
10091 if (is_array($pl['opt']['popup']) && isset($pl['opt']['popup'][2])) {
10092 $w = $pl['opt']['popup'][2] * _MPDFK;
10093 } else {
10094 $w = 180;
10095 }
10096 if (is_array($pl['opt']['popup']) && isset($pl['opt']['popup'][3])) {
10097 $h = $pl['opt']['popup'][3] * _MPDFK;
10098 } else {
10099 $h = 120;
10100 }
10101 $rect = sprintf('%.3F %.3F %.3F %.3F', $x, $y - $h, $x + $w, $y);
10102 $annot .= '<</Type /Annot /Subtype /Popup /Rect [' . $rect . ']';
10103 $annot .= ' /M ' . $this->_textstring('D:' . date('YmdHis'));
10104 if ($this->PDFA || $this->PDFX) {
10105 $annot .= ' /F 28';
10106 }
10107 $annot .= ' /Parent ' . ($this->n - 1) . ' 0 R';
10108 $annot .= '>>';
10109 $this->_out($annot);
10110 $this->_out('endobj');
10111 }
10112 }
10113 }
10114 /* -- END ANNOTATIONS -- */
10115
10116 /* -- FORMS -- */
10117 // Active Forms
10118 if (count($this->mpdfform->forms) > 0) {
10119 $this->mpdfform->_putFormItems($n, $hPt);
10120 }
10121 /* -- END FORMS -- */
10122 }
10123 }
10124 /* -- FORMS -- */
10125 // Active Forms - Radio Button Group entries
10126 // Output Radio Button Group form entries (radio_on_obj_id already determined)
10127 if (count($this->mpdfform->form_radio_groups)) {
10128 $this->mpdfform->_putRadioItems($n);
10129 }
10130 /* -- END FORMS -- */
10131 }
10132
10133 /* -- ANNOTATIONS -- */
10134
10135 function Annotation($text, $x = 0, $y = 0, $icon = 'Note', $author = '', $subject = '', $opacity = 0, $colarray = false, $popup = '', $file = '')
10136 {
10137 if (is_array($colarray) && count($colarray) == 3) {
10138 $colarray = $this->ConvertColor('rgb(' . $colarray[0] . ',' . $colarray[1] . ',' . $colarray[2] . ')');
10139 }
10140 if ($colarray === false) {
10141 $colarray = $this->ConvertColor('yellow');
10142 }
10143 if ($x == 0) {
10144 $x = $this->x;
10145 }
10146 if ($y == 0) {
10147 $y = $this->y;
10148 }
10149 $page = $this->page;
10150 if ($page < 1) { // Document has not been started - assume it's for first page
10151 $page = 1;
10152 if ($x == 0) {
10153 $x = $this->lMargin;
10154 }
10155 if ($y == 0) {
10156 $y = $this->tMargin;
10157 }
10158 }
10159
10160 if ($this->PDFA || $this->PDFX) {
10161 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
10162 $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)";
10163 }
10164 $x = ($this->w) - $this->rMargin * 0.66;
10165 }
10166 if (!$this->annotMargin) {
10167 $y -= $this->FontSize / 2;
10168 }
10169
10170 if (!$opacity && $this->annotMargin) {
10171 $opacity = 1;
10172 } elseif (!$opacity) {
10173 $opacity = $this->annotOpacity;
10174 }
10175
10176 $an = array('txt' => $text, 'x' => $x, 'y' => $y, 'opt' => array('Icon' => $icon, 'T' => $author, 'Subj' => $subject, 'C' => $colarray, 'CA' => $opacity, 'popup' => $popup, 'file' => $file));
10177
10178 if ($this->keep_block_together) { // don't write yet
10179 return;
10180 } elseif ($this->table_rotate) {
10181 $this->tbrot_Annots[$this->page][] = $an;
10182 return;
10183 } elseif ($this->kwt) {
10184 $this->kwt_Annots[$this->page][] = $an;
10185 return;
10186 }
10187 if ($this->writingHTMLheader || $this->writingHTMLfooter) {
10188 $this->HTMLheaderPageAnnots[] = $an;
10189 return;
10190 }
10191 //Put an Annotation on the page
10192 $this->PageAnnots[$page][] = $an;
10193 /* -- COLUMNS -- */
10194 // Save cross-reference to Column buffer
10195 $ref = count($this->PageAnnots[$this->page]) - 1;
10196 $this->columnAnnots[$this->CurrCol][INTVAL($this->x)][INTVAL($this->y)] = $ref;
10197 /* -- END COLUMNS -- */
10198 }
10199
10200 /* -- END ANNOTATIONS -- */
10201
10202 function _putfonts()
10203 {
10204 $nf = $this->n;
10205 foreach ($this->FontFiles as $fontkey => $info) {
10206 // TrueType embedded
10207 if (isset($info['type']) && $info['type'] == 'TTF' && !$info['sip'] && !$info['smp']) {
10208 $used = true;
10209 $asSubset = false;
10210 foreach ($this->fonts AS $k => $f) {
10211 if (isset($f['fontkey']) && $f['fontkey'] == $fontkey && $f['type'] == 'TTF') {
10212 $used = $f['used'];
10213 if ($used) {
10214 $nChars = (ord($f['cw'][0]) << 8) + ord($f['cw'][1]);
10215 $usage = intval(count($f['subset']) * 100 / $nChars);
10216 $fsize = $info['length1'];
10217 // Always subset the very large TTF files
10218 if ($fsize > ($this->maxTTFFilesize * 1024)) {
10219 $asSubset = true;
10220 } elseif ($usage < $this->percentSubset) {
10221 $asSubset = true;
10222 }
10223 }
10224 if ($this->PDFA || $this->PDFX)
10225 $asSubset = false;
10226 $this->fonts[$k]['asSubset'] = $asSubset;
10227 break;
10228 }
10229 }
10230 if ($used && !$asSubset) {
10231 //Font file embedding
10232 $this->_newobj();
10233 $this->FontFiles[$fontkey]['n'] = $this->n;
10234 $font = '';
10235 $originalsize = $info['length1'];
10236 if ($this->repackageTTF || $this->fonts[$fontkey]['TTCfontID'] > 0 || $this->fonts[$fontkey]['useOTL'] > 0) { // mPDF 5.7.1
10237 // First see if there is a cached compressed file
10238 if (file_exists(_MPDF_TTFONTDATAPATH . $fontkey . '.ps.z')) {
10239 $f = fopen(_MPDF_TTFONTDATAPATH . $fontkey . '.ps.z', 'rb');
10240 if (!$f) {
10241 throw new MpdfException('Font file .ps.z not found');
10242 }
10243 while (!feof($f)) {
10244 $font .= fread($f, 2048);
10245 }
10246 fclose($f);
10247 include(_MPDF_TTFONTDATAPATH . $fontkey . '.ps.php'); // sets $originalsize (of repackaged font)
10248 } else {
10249 if (!class_exists('TTFontFile', false)) {
10250 include(_MPDF_PATH . 'classes/ttfontsuni.php');
10251 }
10252 $ttf = new TTFontFile();
10253 $font = $ttf->repackageTTF($this->FontFiles[$fontkey]['ttffile'], $this->fonts[$fontkey]['TTCfontID'], $this->debugfonts, $this->fonts[$fontkey]['useOTL']); // mPDF 5.7.1
10254
10255 $originalsize = strlen($font);
10256 $font = gzcompress($font);
10257 unset($ttf);
10258 if (is_writable(dirname(_MPDF_TTFONTDATAPATH . 'x'))) {
10259 $fh = fopen(_MPDF_TTFONTDATAPATH . $fontkey . '.ps.z', "wb");
10260 fwrite($fh, $font, strlen($font));
10261 fclose($fh);
10262 $fh = fopen(_MPDF_TTFONTDATAPATH . $fontkey . '.ps.php', "wb");
10263 $len = "<?php \n";
10264 $len.='$originalsize=' . $originalsize . ";\n";
10265 $len.="?>";
10266 fwrite($fh, $len, strlen($len));
10267 fclose($fh);
10268 }
10269 }
10270 } else {
10271 // First see if there is a cached compressed file
10272 if (file_exists(_MPDF_TTFONTDATAPATH . $fontkey . '.z')) {
10273 $f = fopen(_MPDF_TTFONTDATAPATH . $fontkey . '.z', 'rb');
10274 if (!$f) {
10275 throw new MpdfException('Font file not found');
10276 }
10277 while (!feof($f)) {
10278 $font .= fread($f, 2048);
10279 }
10280 fclose($f);
10281 } else {
10282 $f = fopen($this->FontFiles[$fontkey]['ttffile'], 'rb');
10283 if (!$f) {
10284 throw new MpdfException('Font file not found');
10285 }
10286 while (!feof($f)) {
10287 $font .= fread($f, 2048);
10288 }
10289 fclose($f);
10290 $font = gzcompress($font);
10291 if (is_writable(dirname(_MPDF_TTFONTDATAPATH . 'x'))) {
10292 $fh = fopen(_MPDF_TTFONTDATAPATH . $fontkey . '.z', "wb");
10293 fwrite($fh, $font, strlen($font));
10294 fclose($fh);
10295 }
10296 }
10297 }
10298
10299 $this->_out('<</Length ' . strlen($font));
10300 $this->_out('/Filter /FlateDecode');
10301 $this->_out('/Length1 ' . $originalsize);
10302 $this->_out('>>');
10303 $this->_putstream($font);
10304 $this->_out('endobj');
10305 }
10306 }
10307 }
10308
10309 $nfonts = count($this->fonts);
10310 $fctr = 1;
10311 foreach ($this->fonts as $k => $font) {
10312 //Font objects
10313 $type = $font['type'];
10314 $name = $font['name'];
10315 if ((!isset($font['used']) || !$font['used']) && $type == 'TTF') {
10316 continue;
10317 }
10318 if ($this->progressBar) {
10319 $this->UpdateProgressBar(2, intval($fctr * 100 / $nfonts), 'Writing Fonts');
10320 $fctr++;
10321 } // *PROGRESS-BAR*
10322 if (isset($font['asSubset'])) {
10323 $asSubset = $font['asSubset'];
10324 } else {
10325 $asSubset = '';
10326 }
10327 /* -- CJK-FONTS -- */
10328 if ($type == 'Type0') { // = Adobe CJK Fonts
10329 $this->fonts[$k]['n'] = $this->n + 1;
10330 $this->_newobj();
10331 $this->_out('<</Type /Font');
10332 $this->_putType0($font);
10333 } else
10334 /* -- END CJK-FONTS -- */
10335 if ($type == 'core') {
10336 //Standard font
10337 $this->fonts[$k]['n'] = $this->n + 1;
10338 if ($this->PDFA || $this->PDFX) {
10339 throw new MpdfException('Core fonts are not allowed in PDF/A1-b or PDFX/1-a files (Times, Helvetica, Courier etc.)');
10340 }
10341 $this->_newobj();
10342 $this->_out('<</Type /Font');
10343 $this->_out('/BaseFont /' . $name);
10344 $this->_out('/Subtype /Type1');
10345 if ($name != 'Symbol' && $name != 'ZapfDingbats') {
10346 $this->_out('/Encoding /WinAnsiEncoding');
10347 }
10348 $this->_out('>>');
10349 $this->_out('endobj');
10350 }
10351 // TrueType embedded SUBSETS for SIP (CJK extB containing Supplementary Ideographic Plane 2)
10352 // Or Unicode Plane 1 - Supplementary Multilingual Plane
10353 elseif ($type == 'TTF' && ($font['sip'] || $font['smp'])) {
10354 if (!$font['used']) {
10355 continue;
10356 }
10357 $ssfaid = "AA";
10358 if (!class_exists('TTFontFile', false)) {
10359 include(_MPDF_PATH . 'classes/ttfontsuni.php');
10360 }
10361 $ttf = new TTFontFile();
10362 for ($sfid = 0; $sfid < count($font['subsetfontids']); $sfid++) {
10363 $this->fonts[$k]['n'][$sfid] = $this->n + 1; // NB an array for subset
10364 $subsetname = 'MPDF' . $ssfaid . '+' . $font['name'];
10365 $ssfaid++;
10366
10367 /* For some strange reason a subset ($sfid > 0) containing less than 97 characters causes an error
10368 so fill up the array */
10369 for ($j = count($font['subsets'][$sfid]); $j < 98; $j++) {
10370 $font['subsets'][$sfid][$j] = 0;
10371 }
10372
10373 $subset = $font['subsets'][$sfid];
10374 unset($subset[0]);
10375 $ttfontstream = $ttf->makeSubsetSIP($font['ttffile'], $subset, $font['TTCfontID'], $this->debugfonts, $font['useOTL']); // mPDF 5.7.1
10376 $ttfontsize = strlen($ttfontstream);
10377 $fontstream = gzcompress($ttfontstream);
10378 $widthstring = '';
10379 $toUnistring = '';
10380
10381
10382 foreach ($font['subsets'][$sfid] AS $cp => $u) {
10383 $w = $this->_getCharWidth($font['cw'], $u);
10384 if ($w !== false) {
10385 $widthstring .= $w . ' ';
10386 } else {
10387 $widthstring .= round($ttf->defaultWidth) . ' ';
10388 }
10389 if ($u > 65535) {
10390 $utf8 = chr(($u >> 18) + 240) . chr((($u >> 12) & 63) + 128) . chr((($u >> 6) & 63) + 128) . chr(($u & 63) + 128);
10391 $utf16 = mb_convert_encoding($utf8, 'UTF-16BE', 'UTF-8');
10392 $l1 = ord($utf16[0]);
10393 $h1 = ord($utf16[1]);
10394 $l2 = ord($utf16[2]);
10395 $h2 = ord($utf16[3]);
10396 $toUnistring .= sprintf("<%02s> <%02s%02s%02s%02s>\n", strtoupper(dechex($cp)), strtoupper(dechex($l1)), strtoupper(dechex($h1)), strtoupper(dechex($l2)), strtoupper(dechex($h2)));
10397 } else {
10398 $toUnistring .= sprintf("<%02s> <%04s>\n", strtoupper(dechex($cp)), strtoupper(dechex($u)));
10399 }
10400 }
10401
10402 //Additional Type1 or TrueType font
10403 $this->_newobj();
10404 $this->_out('<</Type /Font');
10405 $this->_out('/BaseFont /' . $subsetname);
10406 $this->_out('/Subtype /TrueType');
10407 $this->_out('/FirstChar 0 /LastChar ' . (count($font['subsets'][$sfid]) - 1));
10408 $this->_out('/Widths ' . ($this->n + 1) . ' 0 R');
10409 $this->_out('/FontDescriptor ' . ($this->n + 2) . ' 0 R');
10410 $this->_out('/ToUnicode ' . ($this->n + 3) . ' 0 R');
10411 $this->_out('>>');
10412 $this->_out('endobj');
10413
10414 //Widths
10415 $this->_newobj();
10416 $this->_out('[' . $widthstring . ']');
10417 $this->_out('endobj');
10418
10419 //Descriptor
10420 $this->_newobj();
10421 $s = '<</Type /FontDescriptor /FontName /' . $subsetname . "\n";
10422 foreach ($font['desc'] as $kd => $v) {
10423 if ($kd == 'Flags') {
10424 $v = $v | 4;
10425 $v = $v & ~32;
10426 } // SYMBOLIC font flag
10427 $s.=' /' . $kd . ' ' . $v . "\n";
10428 }
10429 $s.='/FontFile2 ' . ($this->n + 2) . ' 0 R';
10430 $this->_out($s . '>>');
10431 $this->_out('endobj');
10432
10433 // ToUnicode
10434 $this->_newobj();
10435 $toUni = "/CIDInit /ProcSet findresource begin\n";
10436 $toUni .= "12 dict begin\n";
10437 $toUni .= "begincmap\n";
10438 $toUni .= "/CIDSystemInfo\n";
10439 $toUni .= "<</Registry (Adobe)\n";
10440 $toUni .= "/Ordering (UCS)\n";
10441 $toUni .= "/Supplement 0\n";
10442 $toUni .= ">> def\n";
10443 $toUni .= "/CMapName /Adobe-Identity-UCS def\n";
10444 $toUni .= "/CMapType 2 def\n";
10445 $toUni .= "1 begincodespacerange\n";
10446 $toUni .= "<00> <FF>\n";
10447 //$toUni .= sprintf("<00> <%02s>\n", strtoupper(dechex(count($font['subsets'][$sfid])-1)));
10448 $toUni .= "endcodespacerange\n";
10449 $toUni .= count($font['subsets'][$sfid]) . " beginbfchar\n";
10450 $toUni .= $toUnistring;
10451 $toUni .= "endbfchar\n";
10452 $toUni .= "endcmap\n";
10453 $toUni .= "CMapName currentdict /CMap defineresource pop\n";
10454 $toUni .= "end\n";
10455 $toUni .= "end\n";
10456 $this->_out('<</Length ' . (strlen($toUni)) . '>>');
10457 $this->_putstream($toUni);
10458 $this->_out('endobj');
10459
10460 //Font file
10461 $this->_newobj();
10462 $this->_out('<</Length ' . strlen($fontstream));
10463 $this->_out('/Filter /FlateDecode');
10464 $this->_out('/Length1 ' . $ttfontsize);
10465 $this->_out('>>');
10466 $this->_putstream($fontstream);
10467 $this->_out('endobj');
10468 } // foreach subset
10469 unset($ttf);
10470 }
10471 // TrueType embedded SUBSETS or FULL
10472 elseif ($type == 'TTF') {
10473 $this->fonts[$k]['n'] = $this->n + 1;
10474 if ($asSubset) {
10475 $ssfaid = "A";
10476 if (!class_exists('TTFontFile', false)) {
10477 include(_MPDF_PATH . 'classes/ttfontsuni.php');
10478 }
10479 $ttf = new TTFontFile();
10480 $fontname = 'MPDFA' . $ssfaid . '+' . $font['name'];
10481 $subset = $font['subset'];
10482 unset($subset[0]);
10483 $ttfontstream = $ttf->makeSubset($font['ttffile'], $subset, $font['TTCfontID'], $this->debugfonts, $font['useOTL']);
10484 $ttfontsize = strlen($ttfontstream);
10485 $fontstream = gzcompress($ttfontstream);
10486 $codeToGlyph = $ttf->codeToGlyph;
10487 unset($codeToGlyph[0]);
10488 } else {
10489 $fontname = $font['name'];
10490 }
10491 // Type0 Font
10492 // A composite font - a font composed of other fonts, organized hierarchically
10493 $this->_newobj();
10494 $this->_out('<</Type /Font');
10495 $this->_out('/Subtype /Type0');
10496 $this->_out('/BaseFont /' . $fontname . '');
10497 $this->_out('/Encoding /Identity-H');
10498 $this->_out('/DescendantFonts [' . ($this->n + 1) . ' 0 R]');
10499 $this->_out('/ToUnicode ' . ($this->n + 2) . ' 0 R');
10500 $this->_out('>>');
10501 $this->_out('endobj');
10502
10503 // CIDFontType2
10504 // A CIDFont whose glyph descriptions are based on TrueType font technology
10505 $this->_newobj();
10506 $this->_out('<</Type /Font');
10507 $this->_out('/Subtype /CIDFontType2');
10508 $this->_out('/BaseFont /' . $fontname . '');
10509 $this->_out('/CIDSystemInfo ' . ($this->n + 2) . ' 0 R');
10510 $this->_out('/FontDescriptor ' . ($this->n + 3) . ' 0 R');
10511 if (isset($font['desc']['MissingWidth'])) {
10512 $this->_out('/DW ' . $font['desc']['MissingWidth'] . '');
10513 }
10514
10515 if (!$asSubset && file_exists(_MPDF_TTFONTDATAPATH . $font['fontkey'] . '.cw')) {
10516 $w = '';
10517 $w = file_get_contents(_MPDF_TTFONTDATAPATH . $font['fontkey'] . '.cw');
10518 $this->_out($w);
10519 } else {
10520 $this->_putTTfontwidths($font, $asSubset, ($asSubset ? $ttf->maxUni : 0));
10521 }
10522
10523 $this->_out('/CIDToGIDMap ' . ($this->n + 4) . ' 0 R');
10524 $this->_out('>>');
10525 $this->_out('endobj');
10526
10527 // ToUnicode
10528 $this->_newobj();
10529 $toUni = "/CIDInit /ProcSet findresource begin\n";
10530 $toUni .= "12 dict begin\n";
10531 $toUni .= "begincmap\n";
10532 $toUni .= "/CIDSystemInfo\n";
10533 $toUni .= "<</Registry (Adobe)\n";
10534 $toUni .= "/Ordering (UCS)\n";
10535 $toUni .= "/Supplement 0\n";
10536 $toUni .= ">> def\n";
10537 $toUni .= "/CMapName /Adobe-Identity-UCS def\n";
10538 $toUni .= "/CMapType 2 def\n";
10539 $toUni .= "1 begincodespacerange\n";
10540 $toUni .= "<0000> <FFFF>\n";
10541 $toUni .= "endcodespacerange\n";
10542 $toUni .= "1 beginbfrange\n";
10543 $toUni .= "<0000> <FFFF> <0000>\n";
10544 $toUni .= "endbfrange\n";
10545 $toUni .= "endcmap\n";
10546 $toUni .= "CMapName currentdict /CMap defineresource pop\n";
10547 $toUni .= "end\n";
10548 $toUni .= "end\n";
10549 $this->_out('<</Length ' . (strlen($toUni)) . '>>');
10550 $this->_putstream($toUni);
10551 $this->_out('endobj');
10552
10553
10554 // CIDSystemInfo dictionary
10555 $this->_newobj();
10556 $this->_out('<</Registry (Adobe)');
10557 $this->_out('/Ordering (UCS)');
10558 $this->_out('/Supplement 0');
10559 $this->_out('>>');
10560 $this->_out('endobj');
10561
10562 // Font descriptor
10563 $this->_newobj();
10564 $this->_out('<</Type /FontDescriptor');
10565 $this->_out('/FontName /' . $fontname);
10566 foreach ($font['desc'] as $kd => $v) {
10567 if ($asSubset && $kd == 'Flags') {
10568 $v = $v | 4;
10569 $v = $v & ~32;
10570 } // SYMBOLIC font flag
10571 $this->_out(' /' . $kd . ' ' . $v);
10572 }
10573 if ($font['panose']) {
10574 $this->_out(' /Style << /Panose <' . $font['panose'] . '> >>');
10575 }
10576 if ($asSubset) {
10577 $this->_out('/FontFile2 ' . ($this->n + 2) . ' 0 R');
10578 } elseif ($font['fontkey']) {
10579 // obj ID of a stream containing a TrueType font program
10580 $this->_out('/FontFile2 ' . $this->FontFiles[$font['fontkey']]['n'] . ' 0 R');
10581 }
10582 $this->_out('>>');
10583 $this->_out('endobj');
10584
10585 // Embed CIDToGIDMap
10586 // A specification of the mapping from CIDs to glyph indices
10587 if ($asSubset) {
10588 $cidtogidmap = '';
10589 $cidtogidmap = str_pad('', 256 * 256 * 2, "\x00");
10590 foreach ($codeToGlyph as $cc => $glyph) {
10591 $cidtogidmap[$cc * 2] = chr($glyph >> 8);
10592 $cidtogidmap[$cc * 2 + 1] = chr($glyph & 0xFF);
10593 }
10594 $cidtogidmap = gzcompress($cidtogidmap);
10595 } else {
10596 // First see if there is a cached CIDToGIDMapfile
10597 $cidtogidmap = '';
10598 if (file_exists(_MPDF_TTFONTDATAPATH . $font['fontkey'] . '.cgm')) {
10599 $f = fopen(_MPDF_TTFONTDATAPATH . $font['fontkey'] . '.cgm', 'rb');
10600 while (!feof($f)) {
10601 $cidtogidmap .= fread($f, 2048);
10602 }
10603 fclose($f);
10604 } else {
10605 if (!class_exists('TTFontFile', false)) {
10606 include(_MPDF_PATH . 'classes/ttfontsuni.php');
10607 }
10608 $ttf = new TTFontFile();
10609 $charToGlyph = $ttf->getCTG($font['ttffile'], $font['TTCfontID'], $this->debugfonts, $font['useOTL']);
10610 $cidtogidmap = str_pad('', 256 * 256 * 2, "\x00");
10611 foreach ($charToGlyph as $cc => $glyph) {
10612 $cidtogidmap[$cc * 2] = chr($glyph >> 8);
10613 $cidtogidmap[$cc * 2 + 1] = chr($glyph & 0xFF);
10614 }
10615 unset($ttf);
10616 $cidtogidmap = gzcompress($cidtogidmap);
10617 if (is_writable(dirname(_MPDF_TTFONTDATAPATH . 'x'))) {
10618 $fh = fopen(_MPDF_TTFONTDATAPATH . $font['fontkey'] . '.cgm', "wb");
10619 fwrite($fh, $cidtogidmap, strlen($cidtogidmap));
10620 fclose($fh);
10621 }
10622 }
10623 }
10624 $this->_newobj();
10625 $this->_out('<</Length ' . strlen($cidtogidmap) . '');
10626 $this->_out('/Filter /FlateDecode');
10627 $this->_out('>>');
10628 $this->_putstream($cidtogidmap);
10629 $this->_out('endobj');
10630
10631 //Font file
10632 if ($asSubset) {
10633 $this->_newobj();
10634 $this->_out('<</Length ' . strlen($fontstream));
10635 $this->_out('/Filter /FlateDecode');
10636 $this->_out('/Length1 ' . $ttfontsize);
10637 $this->_out('>>');
10638 $this->_putstream($fontstream);
10639 $this->_out('endobj');
10640 unset($ttf);
10641 }
10642 } else {
10643 throw new MpdfException('Unsupported font type: ' . $type . ' (' . $name . ')');
10644 }
10645 }
10646 }
10647
10648 function _putTTfontwidths(&$font, $asSubset, $maxUni)
10649 {
10650 if ($asSubset && file_exists(_MPDF_TTFONTDATAPATH . $font['fontkey'] . '.cw127.php')) {
10651 include(_MPDF_TTFONTDATAPATH . $font['fontkey'] . '.cw127.php');
10652 $startcid = 128;
10653 } else {
10654 $rangeid = 0;
10655 $range = array();
10656 $prevcid = -2;
10657 $prevwidth = -1;
10658 $interval = false;
10659 $startcid = 1;
10660 }
10661 if ($asSubset) {
10662 $cwlen = $maxUni + 1;
10663 } else {
10664 $cwlen = (strlen($font['cw']) / 2);
10665 }
10666
10667 // for each character
10668 for ($cid = $startcid; $cid < $cwlen; $cid++) {
10669 if ($cid == 128 && $asSubset && (!file_exists(_MPDF_TTFONTDATAPATH . $font['fontkey'] . '.cw127.php'))) {
10670 if (is_writable(dirname(_MPDF_TTFONTDATAPATH . 'x'))) {
10671 $fh = fopen(_MPDF_TTFONTDATAPATH . $font['fontkey'] . '.cw127.php', "wb");
10672 $cw127 = '<?php' . "\n";
10673 $cw127.='$rangeid=' . $rangeid . ";\n";
10674 $cw127.='$prevcid=' . $prevcid . ";\n";
10675 $cw127.='$prevwidth=' . $prevwidth . ";\n";
10676 if ($interval) {
10677 $cw127.='$interval=true' . ";\n";
10678 } else {
10679 $cw127.='$interval=false' . ";\n";
10680 }
10681 $cw127.='$range=' . var_export($range, true) . ";\n";
10682 $cw127.="?>";
10683 fwrite($fh, $cw127, strlen($cw127));
10684 fclose($fh);
10685 }
10686 }
10687 if ($font['cw'][$cid * 2] == "\00" && $font['cw'][$cid * 2 + 1] == "\00") {
10688 continue;
10689 }
10690 $width = (ord($font['cw'][$cid * 2]) << 8) + ord($font['cw'][$cid * 2 + 1]);
10691 if ($width == 65535) {
10692 $width = 0;
10693 }
10694 if ($asSubset && $cid > 255 && (!isset($font['subset'][$cid]) || !$font['subset'][$cid])) {
10695 continue;
10696 }
10697 if ($asSubset && $cid > 0xFFFF) {
10698 continue;
10699 } // mPDF 6
10700 if (!isset($font['dw']) || (isset($font['dw']) && $width != $font['dw'])) {
10701 if ($cid == ($prevcid + 1)) {
10702 // consecutive CID
10703 if ($width == $prevwidth) {
10704 if ($width == $range[$rangeid][0]) {
10705 $range[$rangeid][] = $width;
10706 } else {
10707 array_pop($range[$rangeid]);
10708 // new range
10709 $rangeid = $prevcid;
10710 $range[$rangeid] = array();
10711 $range[$rangeid][] = $prevwidth;
10712 $range[$rangeid][] = $width;
10713 }
10714 $interval = true;
10715 $range[$rangeid]['interval'] = true;
10716 } else {
10717 if ($interval) {
10718 // new range
10719 $rangeid = $cid;
10720 $range[$rangeid] = array();
10721 $range[$rangeid][] = $width;
10722 } else {
10723 $range[$rangeid][] = $width;
10724 }
10725 $interval = false;
10726 }
10727 } else {
10728 // new range
10729 $rangeid = $cid;
10730 $range[$rangeid] = array();
10731 $range[$rangeid][] = $width;
10732 $interval = false;
10733 }
10734 $prevcid = $cid;
10735 $prevwidth = $width;
10736 }
10737 }
10738 $w = $this->_putfontranges($range);
10739 $this->_out($w);
10740 if (!$asSubset) {
10741 if (is_writable(dirname(_MPDF_TTFONTDATAPATH . 'x'))) {
10742 $fh = fopen(_MPDF_TTFONTDATAPATH . $font['fontkey'] . '.cw', "wb");
10743 fwrite($fh, $w, strlen($w));
10744 fclose($fh);
10745 }
10746 }
10747 }
10748
10749 function _putfontranges(&$range)
10750 {
10751 // optimize ranges
10752 $prevk = -1;
10753 $nextk = -1;
10754 $prevint = false;
10755 foreach ($range as $k => $ws) {
10756 $cws = count($ws);
10757 if (($k == $nextk) AND ( !$prevint) AND ( (!isset($ws['interval'])) OR ( $cws < 4))) {
10758 if (isset($range[$k]['interval'])) {
10759 unset($range[$k]['interval']);
10760 }
10761 $range[$prevk] = array_merge($range[$prevk], $range[$k]);
10762 unset($range[$k]);
10763 } else {
10764 $prevk = $k;
10765 }
10766 $nextk = $k + $cws;
10767 if (isset($ws['interval'])) {
10768 if ($cws > 3) {
10769 $prevint = true;
10770 } else {
10771 $prevint = false;
10772 }
10773 unset($range[$k]['interval']);
10774 --$nextk;
10775 } else {
10776 $prevint = false;
10777 }
10778 }
10779 // output data
10780 $w = '';
10781 foreach ($range as $k => $ws) {
10782 if (count(array_count_values($ws)) == 1) {
10783 // interval mode is more compact
10784 $w .= ' ' . $k . ' ' . ($k + count($ws) - 1) . ' ' . $ws[0];
10785 } else {
10786 // range mode
10787 $w .= ' ' . $k . ' [ ' . implode(' ', $ws) . ' ]' . "\n";
10788 }
10789 }
10790 return '/W [' . $w . ' ]';
10791 }
10792
10793 function _putfontwidths(&$font, $cidoffset = 0)
10794 {
10795 ksort($font['cw']);
10796 unset($font['cw'][65535]);
10797 $rangeid = 0;
10798 $range = array();
10799 $prevcid = -2;
10800 $prevwidth = -1;
10801 $interval = false;
10802 // for each character
10803 foreach ($font['cw'] as $cid => $width) {
10804 $cid -= $cidoffset;
10805 if (!isset($font['dw']) || (isset($font['dw']) && $width != $font['dw'])) {
10806 if ($cid == ($prevcid + 1)) {
10807 // consecutive CID
10808 if ($width == $prevwidth) {
10809 if ($width == $range[$rangeid][0]) {
10810 $range[$rangeid][] = $width;
10811 } else {
10812 array_pop($range[$rangeid]);
10813 // new range
10814 $rangeid = $prevcid;
10815 $range[$rangeid] = array();
10816 $range[$rangeid][] = $prevwidth;
10817 $range[$rangeid][] = $width;
10818 }
10819 $interval = true;
10820 $range[$rangeid]['interval'] = true;
10821 } else {
10822 if ($interval) {
10823 // new range
10824 $rangeid = $cid;
10825 $range[$rangeid] = array();
10826 $range[$rangeid][] = $width;
10827 } else {
10828 $range[$rangeid][] = $width;
10829 }
10830 $interval = false;
10831 }
10832 } else {
10833 // new range
10834 $rangeid = $cid;
10835 $range[$rangeid] = array();
10836 $range[$rangeid][] = $width;
10837 $interval = false;
10838 }
10839 $prevcid = $cid;
10840 $prevwidth = $width;
10841 }
10842 }
10843 $this->_out($this->_putfontranges($range));
10844 }
10845
10846 /* -- CJK-FONTS -- */
10847
10848 // from class PDF_Chinese CJK EXTENSIONS
10849 function _putType0(&$font)
10850 {
10851 //Type0
10852 $this->_out('/Subtype /Type0');
10853 $this->_out('/BaseFont /' . $font['name'] . '-' . $font['CMap']);
10854 $this->_out('/Encoding /' . $font['CMap']);
10855 $this->_out('/DescendantFonts [' . ($this->n + 1) . ' 0 R]');
10856 $this->_out('>>');
10857 $this->_out('endobj');
10858 //CIDFont
10859 $this->_newobj();
10860 $this->_out('<</Type /Font');
10861 $this->_out('/Subtype /CIDFontType0');
10862 $this->_out('/BaseFont /' . $font['name']);
10863
10864 $cidinfo = '/Registry ' . $this->_textstring('Adobe');
10865 $cidinfo .= ' /Ordering ' . $this->_textstring($font['registry']['ordering']);
10866 $cidinfo .= ' /Supplement ' . $font['registry']['supplement'];
10867 $this->_out('/CIDSystemInfo <<' . $cidinfo . '>>');
10868
10869 $this->_out('/FontDescriptor ' . ($this->n + 1) . ' 0 R');
10870 if (isset($font['MissingWidth'])) {
10871 $this->_out('/DW ' . $font['MissingWidth'] . '');
10872 }
10873 $this->_putfontwidths($font, 31);
10874 $this->_out('>>');
10875 $this->_out('endobj');
10876
10877 //Font descriptor
10878 $this->_newobj();
10879 $s = '<</Type /FontDescriptor /FontName /' . $font['name'];
10880 foreach ($font['desc'] as $k => $v) {
10881 if ($k != 'Style') {
10882 $s .= ' /' . $k . ' ' . $v . '';
10883 }
10884 }
10885 $this->_out($s . '>>');
10886 $this->_out('endobj');
10887 }
10888
10889 /* -- END CJK-FONTS -- */
10890
10891 function _putimages()
10892 {
10893 $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
10894 reset($this->images);
10895 //while (list($file, $info) = each($this->images)) {
10896 foreach ($this->images as $file => $info) {
10897 $this->_newobj();
10898 $this->images[$file]['n'] = $this->n;
10899 $this->_out('<</Type /XObject');
10900 $this->_out('/Subtype /Image');
10901 $this->_out('/Width ' . $info['w']);
10902 $this->_out('/Height ' . $info['h']);
10903 if (isset($info['interpolation']) && $info['interpolation']) {
10904 $this->_out('/Interpolate true'); // mPDF 6 - image interpolation shall be performed by a conforming reader
10905 }
10906 if (isset($info['masked'])) {
10907 $this->_out('/SMask ' . ($this->n - 1) . ' 0 R');
10908 }
10909 // set color space
10910 $icc = false;
10911 if (isset($info['icc']) AND ( $info['icc'] !== false)) {
10912 // ICC Colour Space
10913 $icc = true;
10914 $this->_out('/ColorSpace [/ICCBased ' . ($this->n + 1) . ' 0 R]');
10915 } elseif ($info['cs'] == 'Indexed') {
10916 if ($this->PDFX || ($this->PDFA && $this->restrictColorSpace == 3)) {
10917 throw new MpdfException("PDFA1-b and PDFX/1-a files do not permit using mixed colour space (" . $file . ").");
10918 }
10919 $this->_out('/ColorSpace [/Indexed /DeviceRGB ' . (strlen($info['pal']) / 3 - 1) . ' ' . ($this->n + 1) . ' 0 R]');
10920 } else {
10921 $this->_out('/ColorSpace /' . $info['cs']);
10922 if ($info['cs'] == 'DeviceCMYK') {
10923 if ($this->PDFA && $this->restrictColorSpace != 3) {
10924 throw new MpdfException("PDFA1-b does not permit Images using mixed colour space (" . $file . ").");
10925 }
10926 if ($info['type'] == 'jpg') {
10927 $this->_out('/Decode [1 0 1 0 1 0 1 0]');
10928 }
10929 } elseif ($info['cs'] == 'DeviceRGB' && ($this->PDFX || ($this->PDFA && $this->restrictColorSpace == 3))) {
10930 throw new MpdfException("PDFA1-b and PDFX/1-a files do not permit using mixed colour space (" . $file . ").");
10931 }
10932 }
10933 $this->_out('/BitsPerComponent ' . $info['bpc']);
10934 if (isset($info['f']) && $info['f']) {
10935 $this->_out('/Filter /' . $info['f']);
10936 }
10937 if (isset($info['parms'])) {
10938 $this->_out($info['parms']);
10939 }
10940 if (isset($info['trns']) and is_array($info['trns'])) {
10941 $trns = '';
10942 for ($i = 0; $i < count($info['trns']); $i++)
10943 $trns.=$info['trns'][$i] . ' ' . $info['trns'][$i] . ' ';
10944 $this->_out('/Mask [' . $trns . ']');
10945 }
10946 $this->_out('/Length ' . strlen($info['data']) . '>>');
10947 $this->_putstream($info['data']);
10948 unset($this->images[$file]['data']);
10949 $this->_out('endobj');
10950
10951 // ICC colour profile
10952 if ($icc) {
10953 $this->_newobj();
10954 $icc = ($this->compress) ? gzcompress($info['icc']) : $info['icc'];
10955 $this->_out('<</N ' . $info['ch'] . ' ' . $filter . '/Length ' . strlen($icc) . '>>');
10956 $this->_putstream($icc);
10957 $this->_out('endobj');
10958 }
10959 //Palette
10960 elseif ($info['cs'] == 'Indexed') {
10961 $this->_newobj();
10962 $pal = ($this->compress) ? gzcompress($info['pal']) : $info['pal'];
10963 $this->_out('<<' . $filter . '/Length ' . strlen($pal) . '>>');
10964 $this->_putstream($pal);
10965 $this->_out('endobj');
10966 }
10967 }
10968 }
10969
10970 function _putinfo()
10971 {
10972 $this->_out('/Producer ' . $this->_UTF16BEtextstring('mPDF ' . mPDF_VERSION));
10973 if (!empty($this->title))
10974 $this->_out('/Title ' . $this->_UTF16BEtextstring($this->title));
10975 if (!empty($this->subject))
10976 $this->_out('/Subject ' . $this->_UTF16BEtextstring($this->subject));
10977 if (!empty($this->author))
10978 $this->_out('/Author ' . $this->_UTF16BEtextstring($this->author));
10979 if (!empty($this->keywords))
10980 $this->_out('/Keywords ' . $this->_UTF16BEtextstring($this->keywords));
10981 if (!empty($this->creator))
10982 $this->_out('/Creator ' . $this->_UTF16BEtextstring($this->creator));
10983
10984 $z = date('O'); // +0200
10985 $offset = substr($z, 0, 3) . "'" . substr($z, 3, 2) . "'";
10986 $this->_out('/CreationDate ' . $this->_textstring(date('YmdHis') . $offset));
10987 $this->_out('/ModDate ' . $this->_textstring(date('YmdHis') . $offset));
10988 if ($this->PDFX) {
10989 $this->_out('/Trapped/False');
10990 $this->_out('/GTS_PDFXVersion(PDF/X-1a:2003)');
10991 }
10992 }
10993
10994 function _putmetadata()
10995 {
10996 $this->_newobj();
10997 $this->MetadataRoot = $this->n;
10998 $Producer = 'mPDF ' . mPDF_VERSION;
10999 $z = date('O'); // +0200
11000 $offset = substr($z, 0, 3) . ':' . substr($z, 3, 2);
11001 $CreationDate = date('Y-m-d\TH:i:s') . $offset; // 2006-03-10T10:47:26-05:00 2006-06-19T09:05:17Z
11002 $uuid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff));
11003
11004
11005 $m = '<?xpacket begin="' . chr(239) . chr(187) . chr(191) . '" id="W5M0MpCehiHzreSzNTczkc9d"?>' . "\n"; // begin = FEFF BOM
11006 $m .= ' <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="3.1-701">' . "\n";
11007 $m .= ' <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">' . "\n";
11008 $m .= ' <rdf:Description rdf:about="uuid:' . $uuid . '" xmlns:pdf="http://ns.adobe.com/pdf/1.3/">' . "\n";
11009 $m .= ' <pdf:Producer>' . $Producer . '</pdf:Producer>' . "\n";
11010 if (!empty($this->keywords)) {
11011 $m .= ' <pdf:Keywords>' . $this->keywords . '</pdf:Keywords>' . "\n";
11012 }
11013 $m .= ' </rdf:Description>' . "\n";
11014
11015 $m .= ' <rdf:Description rdf:about="uuid:' . $uuid . '" xmlns:xmp="http://ns.adobe.com/xap/1.0/">' . "\n";
11016 $m .= ' <xmp:CreateDate>' . $CreationDate . '</xmp:CreateDate>' . "\n";
11017 $m .= ' <xmp:ModifyDate>' . $CreationDate . '</xmp:ModifyDate>' . "\n";
11018 $m .= ' <xmp:MetadataDate>' . $CreationDate . '</xmp:MetadataDate>' . "\n";
11019 if (!empty($this->creator)) {
11020 $m .= ' <xmp:CreatorTool>' . $this->creator . '</xmp:CreatorTool>' . "\n";
11021 }
11022 $m .= ' </rdf:Description>' . "\n";
11023
11024 // DC elements
11025 $m .= ' <rdf:Description rdf:about="uuid:' . $uuid . '" xmlns:dc="http://purl.org/dc/elements/1.1/">' . "\n";
11026 $m .= ' <dc:format>application/pdf</dc:format>' . "\n";
11027 if (!empty($this->title)) {
11028 $m .= ' <dc:title>
11029 <rdf:Alt>
11030 <rdf:li xml:lang="x-default">' . $this->title . '</rdf:li>
11031 </rdf:Alt>
11032 </dc:title>' . "\n";
11033 }
11034 if (!empty($this->keywords)) {
11035 $m .= ' <dc:subject>
11036 <rdf:Bag>
11037 <rdf:li>' . $this->keywords . '</rdf:li>
11038 </rdf:Bag>
11039 </dc:subject>' . "\n";
11040 }
11041 if (!empty($this->subject)) {
11042 $m .= ' <dc:description>
11043 <rdf:Alt>
11044 <rdf:li xml:lang="x-default">' . $this->subject . '</rdf:li>
11045 </rdf:Alt>
11046 </dc:description>' . "\n";
11047 }
11048 if (!empty($this->author)) {
11049 $m .= ' <dc:creator>
11050 <rdf:Seq>
11051 <rdf:li>' . $this->author . '</rdf:li>
11052 </rdf:Seq>
11053 </dc:creator>' . "\n";
11054 }
11055 $m .= ' </rdf:Description>' . "\n";
11056
11057
11058 // This bit is specific to PDFX-1a
11059 if ($this->PDFX) {
11060 $m .= ' <rdf:Description rdf:about="uuid:' . $uuid . '" xmlns:pdfx="http://ns.adobe.com/pdfx/1.3/" pdfx:Apag_PDFX_Checkup="1.3" pdfx:GTS_PDFXConformance="PDF/X-1a:2003" pdfx:GTS_PDFXVersion="PDF/X-1:2003"/>' . "\n";
11061 }
11062
11063 // This bit is specific to PDFA-1b
11064 elseif ($this->PDFA) {
11065 $m .= ' <rdf:Description rdf:about="uuid:' . $uuid . '" xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/" >' . "\n";
11066 $m .= ' <pdfaid:part>1</pdfaid:part>' . "\n";
11067 $m .= ' <pdfaid:conformance>B</pdfaid:conformance>' . "\n";
11068 $m .= ' <pdfaid:amd>2005</pdfaid:amd>' . "\n";
11069 $m .= ' </rdf:Description>' . "\n";
11070 }
11071
11072 $m .= ' <rdf:Description rdf:about="uuid:' . $uuid . '" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/">' . "\n";
11073 $m .= ' <xmpMM:DocumentID>uuid:' . $uuid . '</xmpMM:DocumentID>' . "\n";
11074 $m .= ' </rdf:Description>' . "\n";
11075 $m .= ' </rdf:RDF>' . "\n";
11076 $m .= ' </x:xmpmeta>' . "\n";
11077 $m .= str_repeat(str_repeat(' ', 100) . "\n", 20); // 2-4kB whitespace padding required
11078 $m .= '<?xpacket end="w"?>'; // "r" read only
11079 $this->_out('<</Type/Metadata/Subtype/XML/Length ' . strlen($m) . '>>');
11080 $this->_putstream($m);
11081 $this->_out('endobj');
11082 }
11083
11084 function _putoutputintent()
11085 {
11086 $this->_newobj();
11087 $this->OutputIntentRoot = $this->n;
11088 $this->_out('<</Type /OutputIntent');
11089
11090 if ($this->PDFA) {
11091 $this->_out('/S /GTS_PDFA1');
11092 if ($this->ICCProfile) {
11093 $this->_out('/Info (' . preg_replace('/_/', ' ', $this->ICCProfile) . ')');
11094 $this->_out('/OutputConditionIdentifier (Custom)');
11095 $this->_out('/OutputCondition ()');
11096 } else {
11097 $this->_out('/Info (sRGB IEC61966-2.1)');
11098 $this->_out('/OutputConditionIdentifier (sRGB IEC61966-2.1)');
11099 $this->_out('/OutputCondition ()');
11100 }
11101 $this->_out('/DestOutputProfile ' . ($this->n + 1) . ' 0 R');
11102 } elseif ($this->PDFX) { // always a CMYK profile
11103 $this->_out('/S /GTS_PDFX');
11104 if ($this->ICCProfile) {
11105 $this->_out('/Info (' . preg_replace('/_/', ' ', $this->ICCProfile) . ')');
11106 $this->_out('/OutputConditionIdentifier (Custom)');
11107 $this->_out('/OutputCondition ()');
11108 $this->_out('/DestOutputProfile ' . ($this->n + 1) . ' 0 R');
11109 } else {
11110 $this->_out('/Info (CGATS TR 001)');
11111 $this->_out('/OutputConditionIdentifier (CGATS TR 001)');
11112 $this->_out('/OutputCondition (CGATS TR 001 (SWOP))');
11113 $this->_out('/RegistryName (http://www.color.org)');
11114 }
11115 }
11116 $this->_out('>>');
11117 $this->_out('endobj');
11118
11119 if ($this->PDFX && !$this->ICCProfile) {
11120 return;
11121 } // no ICCProfile embedded
11122
11123 $this->_newobj();
11124 if ($this->ICCProfile)
11125 $s = file_get_contents(_MPDF_PATH . 'iccprofiles/' . $this->ICCProfile . '.icc');
11126 else
11127 $s = file_get_contents(_MPDF_PATH . 'iccprofiles/sRGB_IEC61966-2-1.icc');
11128 if ($this->compress) {
11129 $s = gzcompress($s);
11130 }
11131 $this->_out('<<');
11132 if ($this->PDFX || ($this->PDFA && $this->restrictColorSpace == 3)) {
11133 $this->_out('/N 4');
11134 } else {
11135 $this->_out('/N 3');
11136 }
11137 if ($this->compress)
11138 $this->_out('/Filter /FlateDecode ');
11139 $this->_out('/Length ' . strlen($s) . '>>');
11140 $this->_putstream($s);
11141 $this->_out('endobj');
11142 }
11143
11144 function _putcatalog()
11145 {
11146 $this->_out('/Type /Catalog');
11147 $this->_out('/Pages 1 0 R');
11148 if ($this->ZoomMode == 'fullpage')
11149 $this->_out('/OpenAction [3 0 R /Fit]');
11150 elseif ($this->ZoomMode == 'fullwidth')
11151 $this->_out('/OpenAction [3 0 R /FitH null]');
11152 elseif ($this->ZoomMode == 'real')
11153 $this->_out('/OpenAction [3 0 R /XYZ null null 1]');
11154 elseif (!is_string($this->ZoomMode))
11155 $this->_out('/OpenAction [3 0 R /XYZ null null ' . ($this->ZoomMode / 100) . ']');
11156 else
11157 $this->_out('/OpenAction [3 0 R /XYZ null null null]');
11158 if ($this->LayoutMode == 'single')
11159 $this->_out('/PageLayout /SinglePage');
11160 elseif ($this->LayoutMode == 'continuous')
11161 $this->_out('/PageLayout /OneColumn');
11162 elseif ($this->LayoutMode == 'twoleft')
11163 $this->_out('/PageLayout /TwoColumnLeft');
11164 elseif ($this->LayoutMode == 'tworight')
11165 $this->_out('/PageLayout /TwoColumnRight');
11166 elseif ($this->LayoutMode == 'two') {
11167 if ($this->mirrorMargins) {
11168 $this->_out('/PageLayout /TwoColumnRight');
11169 } else {
11170 $this->_out('/PageLayout /TwoColumnLeft');
11171 }
11172 }
11173
11174 /* -- BOOKMARKS -- */
11175 if (count($this->BMoutlines) > 0) {
11176 $this->_out('/Outlines ' . $this->OutlineRoot . ' 0 R');
11177 $this->_out('/PageMode /UseOutlines');
11178 }
11179 /* -- END BOOKMARKS -- */
11180 if (is_int(strpos($this->DisplayPreferences, 'FullScreen')))
11181 $this->_out('/PageMode /FullScreen');
11182
11183 // Metadata
11184 if ($this->PDFA || $this->PDFX) {
11185 $this->_out('/Metadata ' . $this->MetadataRoot . ' 0 R');
11186 }
11187 // OutputIntents
11188 if ($this->PDFA || $this->PDFX || $this->ICCProfile) {
11189 $this->_out('/OutputIntents [' . $this->OutputIntentRoot . ' 0 R]');
11190 }
11191
11192 /* -- FORMS -- */
11193 if (count($this->mpdfform->forms) > 0) {
11194 $this->mpdfform->_putFormsCatalog();
11195 }
11196 /* -- END FORMS -- */
11197 if (isset($this->js)) {
11198 $this->_out('/Names << /JavaScript ' . ($this->n_js) . ' 0 R >> ');
11199 }
11200
11201 if ($this->DisplayPreferences || $this->directionality == 'rtl' || $this->mirrorMargins) {
11202 $this->_out('/ViewerPreferences<<');
11203 if (is_int(strpos($this->DisplayPreferences, 'HideMenubar')))
11204 $this->_out('/HideMenubar true');
11205 if (is_int(strpos($this->DisplayPreferences, 'HideToolbar')))
11206 $this->_out('/HideToolbar true');
11207 if (is_int(strpos($this->DisplayPreferences, 'HideWindowUI')))
11208 $this->_out('/HideWindowUI true');
11209 if (is_int(strpos($this->DisplayPreferences, 'DisplayDocTitle')))
11210 $this->_out('/DisplayDocTitle true');
11211 if (is_int(strpos($this->DisplayPreferences, 'CenterWindow')))
11212 $this->_out('/CenterWindow true');
11213 if (is_int(strpos($this->DisplayPreferences, 'FitWindow')))
11214 $this->_out('/FitWindow true');
11215 // /PrintScaling is PDF 1.6 spec.
11216 if (is_int(strpos($this->DisplayPreferences, 'NoPrintScaling')) && !$this->PDFA && !$this->PDFX)
11217 $this->_out('/PrintScaling /None');
11218 if ($this->directionality == 'rtl')
11219 $this->_out('/Direction /R2L');
11220 // /Duplex is PDF 1.7 spec.
11221 if ($this->mirrorMargins && !$this->PDFA && !$this->PDFX) {
11222 // if ($this->DefOrientation=='P') $this->_out('/Duplex /DuplexFlipShortEdge');
11223 $this->_out('/Duplex /DuplexFlipLongEdge'); // PDF v1.7+
11224 }
11225 $this->_out('>>');
11226 }
11227 if ($this->open_layer_pane && ($this->hasOC || count($this->layers)))
11228 $this->_out('/PageMode /UseOC');
11229
11230 if ($this->hasOC || count($this->layers)) {
11231 $p = $v = $h = $l = $loff = $lall = $as = '';
11232 if ($this->hasOC) {
11233 if (($this->hasOC & 1) == 1)
11234 $p = $this->n_ocg_print . ' 0 R';
11235 if (($this->hasOC & 2) == 2)
11236 $v = $this->n_ocg_view . ' 0 R';
11237 if (($this->hasOC & 4) == 4)
11238 $h = $this->n_ocg_hidden . ' 0 R';
11239 $as = "<</Event /Print /OCGs [$p $v $h] /Category [/Print]>> <</Event /View /OCGs [$p $v $h] /Category [/View]>>";
11240 }
11241
11242 if (count($this->layers)) {
11243 foreach ($this->layers as $k => $layer) {
11244 if (strtolower($this->layerDetails[$k]['state']) == 'hidden') {
11245 $loff .= $layer['n'] . ' 0 R ';
11246 } else {
11247 $l .= $layer['n'] . ' 0 R ';
11248 }
11249 $lall .= $layer['n'] . ' 0 R ';
11250 }
11251 }
11252 $this->_out("/OCProperties <</OCGs [$p $v $h $lall] /D <</ON [$p $l] /OFF [$v $h $loff] ");
11253 $this->_out("/Order [$v $p $h $lall] ");
11254 if ($as)
11255 $this->_out("/AS [$as] ");
11256 $this->_out(">>>>");
11257 }
11258 }
11259
11260 // Inactive function left for backwards compatability
11261 function SetUserRights($enable = true, $annots = "", $form = "", $signature = "")
11262 {
11263 // Does nothing
11264 }
11265
11266 function _enddoc()
11267 {
11268 if ($this->progressBar) {
11269 $this->UpdateProgressBar(2, '10', 'Writing Headers & Footers');
11270 } // *PROGRESS-BAR*
11271 $this->_puthtmlheaders();
11272 if ($this->progressBar) {
11273 $this->UpdateProgressBar(2, '20', 'Writing Pages');
11274 } // *PROGRESS-BAR*
11275 // Remove references to unused fonts (usually default font)
11276 foreach ($this->fonts as $fk => $font) {
11277 if (isset($font['type']) && $font['type'] == 'TTF' && !$font['used']) {
11278 if ($font['sip'] || $font['smp']) {
11279 foreach ($font['subsetfontids'] AS $k => $fid) {
11280 foreach ($this->pages AS $pn => $page) {
11281 $this->pages[$pn] = preg_replace('/\s\/F' . $fid . ' \d[\d.]* Tf\s/is', ' ', $this->pages[$pn]);
11282 }
11283 }
11284 } else {
11285 foreach ($this->pages AS $pn => $page) {
11286 $this->pages[$pn] = preg_replace('/\s\/F' . $font['i'] . ' \d[\d.]* Tf\s/is', ' ', $this->pages[$pn]);
11287 }
11288 }
11289 }
11290 }
11291
11292 if (count($this->layers)) {
11293 foreach ($this->pages AS $pn => $page) {
11294 preg_match_all('/\/OCZ-index \/ZI(\d+) BDC(.*?)(EMCZ)-index/is', $this->pages[$pn], $m1);
11295 preg_match_all('/\/OCBZ-index \/ZI(\d+) BDC(.*?)(EMCBZ)-index/is', $this->pages[$pn], $m2);
11296 preg_match_all('/\/OCGZ-index \/ZI(\d+) BDC(.*?)(EMCGZ)-index/is', $this->pages[$pn], $m3);
11297 $m = array();
11298 for ($i = 0; $i < 4; $i++) {
11299 $m[$i] = array_merge($m1[$i], $m2[$i], $m3[$i]);
11300 }
11301 if (count($m[0])) {
11302 $sortarr = array();
11303 for ($i = 0; $i < count($m[0]); $i++) {
11304 $key = $m[1][$i] * 2;
11305 if ($m[3][$i] == 'EMCZ')
11306 $key +=2; // background first then gradient then normal
11307 elseif ($m[3][$i] == 'EMCGZ')
11308 $key +=1;
11309 $sortarr[$i] = $key;
11310 }
11311 asort($sortarr);
11312 foreach ($sortarr AS $i => $k) {
11313 $this->pages[$pn] = str_replace($m[0][$i], '', $this->pages[$pn]);
11314 $this->pages[$pn] .= "\n" . $m[0][$i] . "\n";
11315 }
11316 $this->pages[$pn] = preg_replace('/\/OC[BG]{0,1}Z-index \/ZI(\d+) BDC/is', '/OC /ZI\\1 BDC ', $this->pages[$pn]);
11317 $this->pages[$pn] = preg_replace('/EMC[BG]{0,1}Z-index/is', 'EMC', $this->pages[$pn]);
11318 }
11319 }
11320 }
11321
11322 $this->_putpages();
11323 if ($this->progressBar) {
11324 $this->UpdateProgressBar(2, '30', 'Writing document resources');
11325 } // *PROGRESS-BAR*
11326
11327 $this->_putresources();
11328 //Info
11329 $this->_newobj();
11330 $this->InfoRoot = $this->n;
11331 $this->_out('<<');
11332 if ($this->progressBar) {
11333 $this->UpdateProgressBar(2, '80', 'Writing document info');
11334 } // *PROGRESS-BAR*
11335 $this->_putinfo();
11336 $this->_out('>>');
11337 $this->_out('endobj');
11338
11339 // METADATA
11340 if ($this->PDFA || $this->PDFX) {
11341 $this->_putmetadata();
11342 }
11343 // OUTPUTINTENT
11344 if ($this->PDFA || $this->PDFX || $this->ICCProfile) {
11345 $this->_putoutputintent();
11346 }
11347
11348 //Catalog
11349 $this->_newobj();
11350 $this->_out('<<');
11351 if ($this->progressBar) {
11352 $this->UpdateProgressBar(2, '90', 'Writing document catalog');
11353 } // *PROGRESS-BAR*
11354 $this->_putcatalog();
11355 $this->_out('>>');
11356 $this->_out('endobj');
11357 //Cross-ref
11358 $o = strlen($this->buffer);
11359 $this->_out('xref');
11360 $this->_out('0 ' . ($this->n + 1));
11361 $this->_out('0000000000 65535 f ');
11362 for ($i = 1; $i <= $this->n; $i++)
11363 $this->_out(sprintf('%010d 00000 n ', $this->offsets[$i]));
11364 //Trailer
11365 $this->_out('trailer');
11366 $this->_out('<<');
11367 $this->_puttrailer();
11368 $this->_out('>>');
11369 $this->_out('startxref');
11370 $this->_out($o);
11371
11372 $this->buffer .= '%%EOF';
11373 $this->state = 3;
11374 /* -- IMPORTS -- */
11375
11376 if ($this->enableImports && count($this->parsers) > 0) {
11377 foreach ($this->parsers as $k => $_) {
11378 $this->parsers[$k]->closeFile();
11379 $this->parsers[$k] = null;
11380 unset($this->parsers[$k]);
11381 }
11382 }
11383 /* -- END IMPORTS -- */
11384 }
11385
11386 function _beginpage($orientation, $mgl = '', $mgr = '', $mgt = '', $mgb = '', $mgh = '', $mgf = '', $ohname = '', $ehname = '', $ofname = '', $efname = '', $ohvalue = 0, $ehvalue = 0, $ofvalue = 0, $efvalue = 0, $pagesel = '', $newformat = '')
11387 {
11388 if (!($pagesel && $this->page == 1 && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->tMargin)))) {
11389 $this->page++;
11390 $this->pages[$this->page] = '';
11391 }
11392 $this->state = 2;
11393 $resetHTMLHeadersrequired = false;
11394
11395 if ($newformat) {
11396 $this->_setPageSize($newformat, $orientation);
11397 }
11398 /* -- CSS-PAGE -- */
11399 // Paged media (page-box)
11400 if ($pagesel || (isset($this->page_box['using']) && $this->page_box['using'])) {
11401 if ($pagesel || $this->page == 1) {
11402 $first = true;
11403 } else {
11404 $first = false;
11405 }
11406 if ($this->mirrorMargins && ($this->page % 2 == 0)) {
11407 $oddEven = 'E';
11408 } else {
11409 $oddEven = 'O';
11410 }
11411 if ($pagesel) {
11412 $psel = $pagesel;
11413 } elseif ($this->page_box['current']) {
11414 $psel = $this->page_box['current'];
11415 } else {
11416 $psel = '';
11417 }
11418 list($orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $hname, $fname, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat) = $this->SetPagedMediaCSS($psel, $first, $oddEven);
11419 if ($this->mirrorMargins && ($this->page % 2 == 0)) {
11420 if ($hname) {
11421 $ehvalue = 1;
11422 $ehname = $hname;
11423 } else {
11424 $ehvalue = -1;
11425 }
11426 if ($fname) {
11427 $efvalue = 1;
11428 $efname = $fname;
11429 } else {
11430 $efvalue = -1;
11431 }
11432 } else {
11433 if ($hname) {
11434 $ohvalue = 1;
11435 $ohname = $hname;
11436 } else {
11437 $ohvalue = -1;
11438 }
11439 if ($fname) {
11440 $ofvalue = 1;
11441 $ofname = $fname;
11442 } else {
11443 $ofvalue = -1;
11444 }
11445 }
11446 if ($resetpagenum || $pagenumstyle || $suppress) {
11447 $this->PageNumSubstitutions[] = array('from' => ($this->page), 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress);
11448 }
11449 // PAGED MEDIA - CROP / CROSS MARKS from @PAGE
11450 $this->show_marks = $marks;
11451
11452 // Background color
11453 if (isset($bg['BACKGROUND-COLOR'])) {
11454 $cor = $this->ConvertColor($bg['BACKGROUND-COLOR']);
11455 if ($cor) {
11456 $this->bodyBackgroundColor = $cor;
11457 }
11458 } else {
11459 $this->bodyBackgroundColor = false;
11460 }
11461
11462 /* -- BACKGROUNDS -- */
11463 if (isset($bg['BACKGROUND-GRADIENT'])) {
11464 $this->bodyBackgroundGradient = $bg['BACKGROUND-GRADIENT'];
11465 } else {
11466 $this->bodyBackgroundGradient = false;
11467 }
11468
11469 // Tiling Patterns
11470 if (isset($bg['BACKGROUND-IMAGE']) && $bg['BACKGROUND-IMAGE']) {
11471 $ret = $this->SetBackground($bg, $this->pgwidth);
11472 if ($ret) {
11473 $this->bodyBackgroundImage = $ret;
11474 }
11475 } else {
11476 $this->bodyBackgroundImage = false;
11477 }
11478 /* -- END BACKGROUNDS -- */
11479
11480 $this->page_box['current'] = $psel;
11481 $this->page_box['using'] = true;
11482 }
11483 /* -- END CSS-PAGE -- */
11484
11485 //Page orientation
11486 if (!$orientation)
11487 $orientation = $this->DefOrientation;
11488 else {
11489 $orientation = strtoupper(substr($orientation, 0, 1));
11490 if ($orientation != $this->DefOrientation)
11491 $this->OrientationChanges[$this->page] = true;
11492 }
11493 if ($orientation != $this->CurOrientation || $newformat) {
11494
11495 //Change orientation
11496 if ($orientation == 'P') {
11497 $this->wPt = $this->fwPt;
11498 $this->hPt = $this->fhPt;
11499 $this->w = $this->fw;
11500 $this->h = $this->fh;
11501 if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation == 'P') {
11502 $this->tMargin = $this->orig_tMargin;
11503 $this->bMargin = $this->orig_bMargin;
11504 $this->DeflMargin = $this->orig_lMargin;
11505 $this->DefrMargin = $this->orig_rMargin;
11506 $this->margin_header = $this->orig_hMargin;
11507 $this->margin_footer = $this->orig_fMargin;
11508 } else {
11509 $resetHTMLHeadersrequired = true;
11510 }
11511 } else {
11512 $this->wPt = $this->fhPt;
11513 $this->hPt = $this->fwPt;
11514 $this->w = $this->fh;
11515 $this->h = $this->fw;
11516 if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation == 'P') {
11517 $this->tMargin = $this->orig_lMargin;
11518 $this->bMargin = $this->orig_rMargin;
11519 $this->DeflMargin = $this->orig_bMargin;
11520 $this->DefrMargin = $this->orig_tMargin;
11521 $this->margin_header = $this->orig_hMargin;
11522 $this->margin_footer = $this->orig_fMargin;
11523 } else {
11524 $resetHTMLHeadersrequired = true;
11525 }
11526 }
11527 $this->CurOrientation = $orientation;
11528 $this->ResetMargins();
11529 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
11530 $this->PageBreakTrigger = $this->h - $this->bMargin;
11531 }
11532
11533 $this->pageDim[$this->page]['w'] = $this->w;
11534 $this->pageDim[$this->page]['h'] = $this->h;
11535
11536 $this->pageDim[$this->page]['outer_width_LR'] = isset($this->page_box['outer_width_LR']) ? $this->page_box['outer_width_LR'] : 0;
11537 $this->pageDim[$this->page]['outer_width_TB'] = isset($this->page_box['outer_width_TB']) ? $this->page_box['outer_width_TB'] : 0;
11538 if (!isset($this->page_box['outer_width_LR']) && !isset($this->page_box['outer_width_TB'])) {
11539 $this->pageDim[$this->page]['bleedMargin'] = 0;
11540 } elseif ($this->bleedMargin <= $this->page_box['outer_width_LR'] && $this->bleedMargin <= $this->page_box['outer_width_TB']) {
11541 $this->pageDim[$this->page]['bleedMargin'] = $this->bleedMargin;
11542 } else {
11543 $this->pageDim[$this->page]['bleedMargin'] = min($this->page_box['outer_width_LR'], $this->page_box['outer_width_TB']) - 0.01;
11544 }
11545
11546 // If Page Margins are re-defined
11547 // strlen()>0 is used to pick up (integer) 0, (string) '0', or set value
11548 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)) {
11549 if (strlen($mgl) > 0)
11550 $this->DeflMargin = $mgl;
11551 if (strlen($mgr) > 0)
11552 $this->DefrMargin = $mgr;
11553 if (strlen($mgt) > 0)
11554 $this->tMargin = $mgt;
11555 if (strlen($mgb) > 0)
11556 $this->bMargin = $mgb;
11557 if (strlen($mgh) > 0)
11558 $this->margin_header = $mgh;
11559 if (strlen($mgf) > 0)
11560 $this->margin_footer = $mgf;
11561 $this->ResetMargins();
11562 $this->SetAutoPageBreak($this->autoPageBreak, $this->bMargin);
11563 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
11564 $resetHTMLHeadersrequired = true;
11565 }
11566
11567 $this->ResetMargins();
11568 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
11569 $this->SetAutoPageBreak($this->autoPageBreak, $this->bMargin);
11570
11571 // Reset column top margin
11572 $this->y0 = $this->tMargin;
11573
11574 $this->x = $this->lMargin;
11575 $this->y = $this->tMargin;
11576 $this->FontFamily = '';
11577
11578 // HEADERS AND FOOTERS // mPDF 6
11579 if ($ohvalue < 0 || strtoupper($ohvalue) == 'OFF') {
11580 $this->HTMLHeader = '';
11581 $resetHTMLHeadersrequired = true;
11582 } elseif ($ohname && $ohvalue > 0) {
11583 if (preg_match('/^html_(.*)$/i', $ohname, $n)) {
11584 $name = $n[1];
11585 } else {
11586 $name = $ohname;
11587 }
11588 if (isset($this->pageHTMLheaders[$name])) {
11589 $this->HTMLHeader = $this->pageHTMLheaders[$name];
11590 } else {
11591 $this->HTMLHeader = '';
11592 }
11593 $resetHTMLHeadersrequired = true;
11594 }
11595
11596 if ($ehvalue < 0 || strtoupper($ehvalue) == 'OFF') {
11597 $this->HTMLHeaderE = '';
11598 $resetHTMLHeadersrequired = true;
11599 } elseif ($ehname && $ehvalue > 0) {
11600 if (preg_match('/^html_(.*)$/i', $ehname, $n)) {
11601 $name = $n[1];
11602 } else {
11603 $name = $ehname;
11604 }
11605 if (isset($this->pageHTMLheaders[$name])) {
11606 $this->HTMLHeaderE = $this->pageHTMLheaders[$name];
11607 } else {
11608 $this->HTMLHeaderE = '';
11609 }
11610 $resetHTMLHeadersrequired = true;
11611 }
11612
11613 if ($ofvalue < 0 || strtoupper($ofvalue) == 'OFF') {
11614 $this->HTMLFooter = '';
11615 $resetHTMLHeadersrequired = true;
11616 } elseif ($ofname && $ofvalue > 0) {
11617 if (preg_match('/^html_(.*)$/i', $ofname, $n)) {
11618 $name = $n[1];
11619 } else {
11620 $name = $ofname;
11621 }
11622 if (isset($this->pageHTMLfooters[$name])) {
11623 $this->HTMLFooter = $this->pageHTMLfooters[$name];
11624 } else {
11625 $this->HTMLFooter = '';
11626 }
11627 $resetHTMLHeadersrequired = true;
11628 }
11629
11630 if ($efvalue < 0 || strtoupper($efvalue) == 'OFF') {
11631 $this->HTMLFooterE = '';
11632 $resetHTMLHeadersrequired = true;
11633 } elseif ($efname && $efvalue > 0) {
11634 if (preg_match('/^html_(.*)$/i', $efname, $n)) {
11635 $name = $n[1];
11636 } else {
11637 $name = $efname;
11638 }
11639 if (isset($this->pageHTMLfooters[$name])) {
11640 $this->HTMLFooterE = $this->pageHTMLfooters[$name];
11641 } else {
11642 $this->HTMLFooterE = '';
11643 }
11644 $resetHTMLHeadersrequired = true;
11645 }
11646 if ($resetHTMLHeadersrequired) {
11647 $this->SetHTMLHeader($this->HTMLHeader);
11648 $this->SetHTMLHeader($this->HTMLHeaderE, 'E');
11649 $this->SetHTMLFooter($this->HTMLFooter);
11650 $this->SetHTMLFooter($this->HTMLFooterE, 'E');
11651 }
11652
11653
11654 if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
11655 $this->_setAutoHeaderHeight($this->HTMLHeaderE);
11656 $this->_setAutoFooterHeight($this->HTMLFooterE);
11657 } else { // ODD or DEFAULT
11658 $this->_setAutoHeaderHeight($this->HTMLHeader);
11659 $this->_setAutoFooterHeight($this->HTMLFooter);
11660 }
11661 // Reset column top margin
11662 $this->y0 = $this->tMargin;
11663
11664 $this->x = $this->lMargin;
11665 $this->y = $this->tMargin;
11666 }
11667
11668 // mPDF 6
11669 function _setAutoHeaderHeight(&$htmlh)
11670 {
11671 if ($this->setAutoTopMargin == 'pad') {
11672 if (isset($htmlh['h']) && $htmlh['h']) {
11673 $h = $htmlh['h'];
11674 } // 5.7.3
11675 else {
11676 $h = 0;
11677 }
11678 $this->tMargin = $this->margin_header + $h + $this->orig_tMargin;
11679 } elseif ($this->setAutoTopMargin == 'stretch') {
11680 if (isset($htmlh['h']) && $htmlh['h']) {
11681 $h = $htmlh['h'];
11682 } // 5.7.3
11683 else {
11684 $h = 0;
11685 }
11686 $this->tMargin = max($this->orig_tMargin, $this->margin_header + $h + $this->autoMarginPadding);
11687 }
11688 }
11689
11690 // mPDF 6
11691 function _setAutoFooterHeight(&$htmlf)
11692 {
11693 if ($this->setAutoBottomMargin == 'pad') {
11694 if (isset($htmlf['h']) && $htmlf['h']) {
11695 $h = $htmlf['h'];
11696 } // 5.7.3
11697 else {
11698 $h = 0;
11699 }
11700 $this->bMargin = $this->margin_footer + $h + $this->orig_bMargin;
11701 $this->PageBreakTrigger = $this->h - $this->bMargin;
11702 } elseif ($this->setAutoBottomMargin == 'stretch') {
11703 if (isset($htmlf['h']) && $htmlf['h']) {
11704 $h = $htmlf['h'];
11705 } // 5.7.3
11706 else {
11707 $h = 0;
11708 }
11709 $this->bMargin = max($this->orig_bMargin, $this->margin_footer + $h + $this->autoMarginPadding);
11710 $this->PageBreakTrigger = $this->h - $this->bMargin;
11711 }
11712 }
11713
11714 function _endpage()
11715 {
11716 /* -- CSS-IMAGE-FLOAT -- */
11717 $this->printfloatbuffer();
11718 /* -- END CSS-IMAGE-FLOAT -- */
11719
11720 if ($this->visibility != 'visible')
11721 $this->SetVisibility('visible');
11722 $this->EndLayer();
11723 //End of page contents
11724 $this->state = 1;
11725 }
11726
11727 function _newobj($obj_id = false, $onlynewobj = false)
11728 {
11729 if (!$obj_id) {
11730 $obj_id = ++$this->n;
11731 }
11732 //Begin a new object
11733 if (!$onlynewobj) {
11734 $this->offsets[$obj_id] = strlen($this->buffer);
11735 $this->_out($obj_id . ' 0 obj');
11736 $this->_current_obj_id = $obj_id; // for later use with encryption
11737 }
11738 }
11739
11740 function _dounderline($x, $y, $txt, $OTLdata = false, $textvar = 0)
11741 {
11742 // Now print line exactly where $y secifies - called from Text() and Cell() - adjust position there
11743 // WORD SPACING
11744 $w = ($this->GetStringWidth($txt, false, $OTLdata, $textvar) * _MPDFK) + ($this->charspacing * mb_strlen($txt, $this->mb_enc)) + ( $this->ws * mb_substr_count($txt, ' ', $this->mb_enc));
11745 //Draw a line
11746 return sprintf('%.3F %.3F m %.3F %.3F l S', $x * _MPDFK, ($this->h - $y) * _MPDFK, ($x * _MPDFK) + $w, ($this->h - $y) * _MPDFK);
11747 }
11748
11749 function _imageError($file, $firsttime, $msg)
11750 {
11751 // Save re-trying image URL's which have already failed
11752 $this->failedimages[$file] = true;
11753 if ($firsttime && ($this->showImageErrors || $this->debug)) {
11754 throw new MpdfException("IMAGE Error (" . $file . "): " . $msg);
11755 }
11756 return false;
11757 }
11758
11759 function _getImage(&$file, $firsttime = true, $allowvector = true, $orig_srcpath = false, $interpolation = false)
11760 { // mPDF 6
11761 // firsttime i.e. whether to add to this->images - use false when calling iteratively
11762 // Image Data passed directly as var:varname
11763 if (preg_match('/var:\s*(.*)/', $file, $v)) {
11764 $data = $this->$v[1];
11765 $file = md5($data);
11766 }
11767 if (preg_match('/data:image\/(gif|jpeg|png);base64,(.*)/', $file, $v)) {
11768 $type = $v[1];
11769 $data = base64_decode($v[2]);
11770 $file = md5($data);
11771 }
11772
11773 // mPDF 5.7.4 URLs
11774 if ($firsttime && $file && substr($file, 0, 5) != 'data:') {
11775 $file = str_replace(" ", "%20", $file);
11776 }
11777 if ($firsttime && $orig_srcpath) {
11778 // If orig_srcpath is a relative file path (and not a URL), then it needs to be URL decoded
11779 if (substr($orig_srcpath, 0, 5) != 'data:') {
11780 $orig_srcpath = str_replace(" ", "%20", $orig_srcpath);
11781 }
11782 if (!preg_match('/^(http|ftp)/', $orig_srcpath)) {
11783 $orig_srcpath = urldecode_parts($orig_srcpath);
11784 }
11785 }
11786
11787 $ppUx = 0;
11788 if ($orig_srcpath && isset($this->images[$orig_srcpath])) {
11789 $file = $orig_srcpath;
11790 return $this->images[$orig_srcpath];
11791 }
11792 if (isset($this->images[$file])) {
11793 return $this->images[$file];
11794 } elseif ($orig_srcpath && isset($this->formobjects[$orig_srcpath])) {
11795 $file = $orig_srcpath;
11796 return $this->formobjects[$file];
11797 } elseif (isset($this->formobjects[$file])) {
11798 return $this->formobjects[$file];
11799 }
11800 // Save re-trying image URL's which have already failed
11801 elseif ($firsttime && isset($this->failedimages[$file])) {
11802 return $this->_imageError($file, $firsttime, '');
11803 }
11804 if (empty($data)) {
11805 $type = '';
11806 $data = '';
11807
11808 if ($orig_srcpath && $this->basepathIsLocal && $check = @fopen($orig_srcpath, "rb")) {
11809 fclose($check);
11810 $file = $orig_srcpath;
11811 $data = file_get_contents($file);
11812 $type = $this->_imageTypeFromString($data);
11813 }
11814 if (!$data && $check = @fopen($file, "rb")) {
11815 fclose($check);
11816 $data = file_get_contents($file);
11817 $type = $this->_imageTypeFromString($data);
11818 }
11819 if ((!$data || !$type) && !ini_get('allow_url_fopen')) { // only worth trying if remote file and !ini_get('allow_url_fopen')
11820 $this->file_get_contents_by_socket($file, $data); // needs full url?? even on local (never needed for local)
11821 if ($data) {
11822 $type = $this->_imageTypeFromString($data);
11823 }
11824 }
11825 if ((!$data || !$type) && function_exists("curl_init")) { // mPDF 5.7.4
11826 $this->file_get_contents_by_curl($file, $data); // needs full url?? even on local (never needed for local)
11827 if ($data) {
11828 $type = $this->_imageTypeFromString($data);
11829 }
11830 }
11831 }
11832 if (!$data) {
11833 return $this->_imageError($file, $firsttime, 'Could not find image file');
11834 }
11835 if (empty($type)) {
11836 $type = $this->_imageTypeFromString($data);
11837 }
11838 if (($type == 'wmf' || $type == 'svg') && !$allowvector) {
11839 return $this->_imageError($file, $firsttime, 'WMF or SVG image file not supported in this context');
11840 }
11841
11842 // SVG
11843 if ($type == 'svg') {
11844 if (!class_exists('SVG', false)) {
11845 include(_MPDF_PATH . 'classes/svg.php');
11846 }
11847 $svg = new SVG($this);
11848 $family = $this->FontFamily;
11849 $style = $this->FontStyle;
11850 $size = $this->FontSizePt;
11851 $info = $svg->ImageSVG($data);
11852 //Restore font
11853 if ($family)
11854 $this->SetFont($family, $style, $size, false);
11855 if (!$info) {
11856 return $this->_imageError($file, $firsttime, 'Error parsing SVG file');
11857 }
11858 $info['type'] = 'svg';
11859 $info['i'] = count($this->formobjects) + 1;
11860 $this->formobjects[$file] = $info;
11861 return $info;
11862 }
11863
11864 // JPEG
11865 if ($type == 'jpeg' || $type == 'jpg') {
11866 $hdr = $this->_jpgHeaderFromString($data);
11867 if (!$hdr) {
11868 return $this->_imageError($file, $firsttime, 'Error parsing JPG header');
11869 }
11870 $a = $this->_jpgDataFromHeader($hdr);
11871 $channels = intval($a[4]);
11872 $j = strpos($data, 'JFIF');
11873 if ($j) {
11874 //Read resolution
11875 $unitSp = ord(substr($data, ($j + 7), 1));
11876 if ($unitSp > 0) {
11877 $ppUx = $this->_twobytes2int(substr($data, ($j + 8), 2)); // horizontal pixels per meter, usually set to zero
11878 if ($unitSp == 2) { // = dots per cm (if == 1 set as dpi)
11879 $ppUx = round($ppUx / 10 * 25.4);
11880 }
11881 }
11882 }
11883 if ($a[2] == 'DeviceCMYK' && (($this->PDFA && $this->restrictColorSpace != 3) || $this->restrictColorSpace == 2)) {
11884 // convert to RGB image
11885 if (!function_exists("gd_info")) {
11886 throw new MpdfException("JPG image may not use CMYK color space (" . $file . ").");
11887 }
11888 if ($this->PDFA && !$this->PDFAauto) {
11889 $this->PDFAXwarnings[] = "JPG image may not use CMYK color space - " . $file . " - (Image converted to RGB. NB This will alter the colour profile of the image.)";
11890 }
11891 $im = @imagecreatefromstring($data);
11892 if ($im) {
11893 $tempfile = _MPDF_TEMP_PATH . '_tempImgPNG' . md5($file) . RAND(1, 10000) . '.png';
11894 imageinterlace($im, false);
11895 $check = @imagepng($im, $tempfile);
11896 if (!$check) {
11897 return $this->_imageError($file, $firsttime, 'Error creating temporary file (' . $tempfile . ') whilst using GD library to parse JPG(CMYK) image');
11898 }
11899 $info = $this->_getImage($tempfile, false);
11900 if (!$info) {
11901 return $this->_imageError($file, $firsttime, 'Error parsing temporary file (' . $tempfile . ') created with GD library to parse JPG(CMYK) image');
11902 }
11903 imagedestroy($im);
11904 unlink($tempfile);
11905 $info['type'] = 'jpg';
11906 if ($firsttime) {
11907 $info['i'] = count($this->images) + 1;
11908 $info['interpolation'] = $interpolation; // mPDF 6
11909 $this->images[$file] = $info;
11910 }
11911 return $info;
11912 } else {
11913 return $this->_imageError($file, $firsttime, 'Error creating GD image file from JPG(CMYK) image');
11914 }
11915 } elseif ($a[2] == 'DeviceRGB' && ($this->PDFX || $this->restrictColorSpace == 3)) {
11916 // Convert to CMYK image stream - nominally returned as type='png'
11917 $info = $this->_convImage($data, $a[2], 'DeviceCMYK', $a[0], $a[1], $ppUx, false);
11918 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
11919 $this->PDFAXwarnings[] = "JPG image may not use RGB color space - " . $file . " - (Image converted to CMYK. NB This will alter the colour profile of the image.)";
11920 }
11921 } elseif (($a[2] == 'DeviceRGB' || $a[2] == 'DeviceCMYK') && $this->restrictColorSpace == 1) {
11922 // Convert to Grayscale image stream - nominally returned as type='png'
11923 $info = $this->_convImage($data, $a[2], 'DeviceGray', $a[0], $a[1], $ppUx, false);
11924 } else {
11925
11926 // mPDF 6 Detect Adobe APP14 Tag
11927 //$pos = strpos($data, "\xFF\xEE\x00\x0EAdobe\0");
11928 //if ($pos !== false) {
11929 //}
11930 // mPDF 6 ICC profile
11931 $offset = 0;
11932 $icc = array();
11933 while (($pos = strpos($data, "ICC_PROFILE\0", $offset)) !== false) {
11934 // get ICC sequence length
11935 $length = $this->_twobytes2int(substr($data, ($pos - 2), 2)) - 16;
11936 $sn = max(1, ord($data[($pos + 12)]));
11937 $nom = max(1, ord($data[($pos + 13)]));
11938 $icc[($sn - 1)] = substr($data, ($pos + 14), $length);
11939 $offset = ($pos + 14 + $length);
11940 }
11941 // order and compact ICC segments
11942 if (count($icc) > 0) {
11943 ksort($icc);
11944 $icc = implode('', $icc);
11945 if (substr($icc, 36, 4) != 'acsp') {
11946 // invalid ICC profile
11947 $icc = false;
11948 }
11949 $input = substr($icc, 16, 4);
11950 $output = substr($icc, 20, 4);
11951 // Ignore Color profiles for conversion to other colorspaces e.g. CMYK/Lab
11952 if ($input != 'RGB ' || $output != 'XYZ ') {
11953 $icc = false;
11954 }
11955 } else {
11956 $icc = false;
11957 }
11958
11959 $info = array('w' => $a[0], 'h' => $a[1], 'cs' => $a[2], 'bpc' => $a[3], 'f' => 'DCTDecode', 'data' => $data, 'type' => 'jpg', 'ch' => $channels, 'icc' => $icc);
11960 if ($ppUx) {
11961 $info['set-dpi'] = $ppUx;
11962 }
11963 }
11964 if (!$info) {
11965 return $this->_imageError($file, $firsttime, 'Error parsing or converting JPG image');
11966 }
11967 if ($firsttime) {
11968 $info['i'] = count($this->images) + 1;
11969 $info['interpolation'] = $interpolation; // mPDF 6
11970 $this->images[$file] = $info;
11971 }
11972 return $info;
11973 }
11974
11975 // PNG
11976 elseif ($type == 'png') {
11977 //Check signature
11978 if (substr($data, 0, 8) != chr(137) . 'PNG' . chr(13) . chr(10) . chr(26) . chr(10)) {
11979 return $this->_imageError($file, $firsttime, 'Error parsing PNG identifier');
11980 }
11981 //Read header chunk
11982 if (substr($data, 12, 4) != 'IHDR') {
11983 return $this->_imageError($file, $firsttime, 'Incorrect PNG file (no IHDR block found)');
11984 }
11985
11986 $w = $this->_fourbytes2int(substr($data, 16, 4));
11987 $h = $this->_fourbytes2int(substr($data, 20, 4));
11988 $bpc = ord(substr($data, 24, 1));
11989 $errpng = false;
11990 $pngalpha = false;
11991 $channels = 0;
11992
11993 // if($bpc>8) { $errpng = 'not 8-bit depth'; } // mPDF 6 Allow through to be handled as native PNG
11994
11995 $ct = ord(substr($data, 25, 1));
11996 if ($ct == 0) {
11997 $colspace = 'DeviceGray';
11998 $channels = 1;
11999 } elseif ($ct == 2) {
12000 $colspace = 'DeviceRGB';
12001 $channels = 3;
12002 } elseif ($ct == 3) {
12003 $colspace = 'Indexed';
12004 $channels = 1;
12005 } elseif ($ct == 4) {
12006 $colspace = 'DeviceGray';
12007 $channels = 1;
12008 $errpng = 'alpha channel';
12009 $pngalpha = true;
12010 } else {
12011 $colspace = 'DeviceRGB';
12012 $channels = 3;
12013 $errpng = 'alpha channel';
12014 $pngalpha = true;
12015 }
12016
12017 if ($ct < 4 && strpos($data, 'tRNS') !== false) {
12018 $errpng = 'transparency';
12019 $pngalpha = true;
12020 } // mPDF 6
12021
12022 if ($ct == 3 && strpos($data, 'iCCP') !== false) {
12023 $errpng = 'indexed plus ICC';
12024 } // mPDF 6
12025 // $pngalpha is used as a FLAG of any kind of transparency which COULD be tranferred to an alpha channel
12026 // incl. single-color tarnsparency, depending which type of handling occurs later
12027
12028 if (ord(substr($data, 26, 1)) != 0) {
12029 $errpng = 'compression method';
12030 } // only 0 should be specified
12031 if (ord(substr($data, 27, 1)) != 0) {
12032 $errpng = 'filter method';
12033 } // only 0 should be specified
12034 if (ord(substr($data, 28, 1)) != 0) {
12035 $errpng = 'interlaced file';
12036 }
12037
12038 $j = strpos($data, 'pHYs');
12039 if ($j) {
12040 //Read resolution
12041 $unitSp = ord(substr($data, ($j + 12), 1));
12042 if ($unitSp == 1) {
12043 $ppUx = $this->_fourbytes2int(substr($data, ($j + 4), 4)); // horizontal pixels per meter, usually set to zero
12044 $ppUx = round($ppUx / 1000 * 25.4);
12045 }
12046 }
12047
12048 // mPDF 6 Gamma correction
12049 $gamma_correction = 0;
12050 $gAMA = 0;
12051 $j = strpos($data, 'gAMA');
12052 if ($j && strpos($data, 'sRGB') === false) { // sRGB colorspace - overrides gAMA
12053 $gAMA = $this->_fourbytes2int(substr($data, ($j + 4), 4)); // Gamma value times 100000
12054 $gAMA /= 100000;
12055
12056 // http://www.libpng.org/pub/png/spec/1.2/PNG-Encoders.html
12057 // "If the source file's gamma value is greater than 1.0, it is probably a display system exponent,..."
12058 // ("..and you should use its reciprocal for the PNG gamma.")
12059 //if ($gAMA > 1) { $gAMA = 1/$gAMA; }
12060 // (Some) Applications seem to ignore it... appearing how it was probably intended
12061 // Test Case - image(s) on http://www.w3.org/TR/CSS21/intro.html - PNG has gAMA set as 1.45454
12062 // Probably unintentional as mentioned above and should be 0.45454 which is 1 / 2.2
12063 // Tested on Windows PC
12064 // Firefox and Opera display gray as 234 (correct, but looks wrong)
12065 // IE9 and Safari display gray as 193 (incorrect but looks right)
12066 // See test different gamma chunks at http://www.libpng.org/pub/png/pngsuite-all-good.html
12067 }
12068
12069 if ($gAMA) {
12070 $gamma_correction = 1 / $gAMA;
12071 }
12072
12073 // Don't need to apply gamma correction if == default i.e. 2.2
12074 if ($gamma_correction > 2.15 && $gamma_correction < 2.25) {
12075 $gamma_correction = 0;
12076 }
12077
12078 // NOT supported at present
12079 //$j = strpos($data,'sRGB'); // sRGB colorspace - overrides gAMA
12080 //$j = strpos($data,'cHRM'); // Chromaticity and Whitepoint
12081 // $firsttime added mPDF 6 so when PNG Grayscale with alpha using resrtictcolorspace to CMYK
12082 // the alpha channel is sent through as secondtime as Indexed and should not be converted to CMYK
12083 if ($firsttime && ($colspace == 'DeviceRGB' || $colspace == 'Indexed') && ($this->PDFX || $this->restrictColorSpace == 3)) {
12084 // Convert to CMYK image stream - nominally returned as type='png'
12085 $info = $this->_convImage($data, $colspace, 'DeviceCMYK', $w, $h, $ppUx, $pngalpha, $gamma_correction, $ct); // mPDF 5.7.2 Gamma correction
12086 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
12087 $this->PDFAXwarnings[] = "PNG image may not use RGB color space - " . $file . " - (Image converted to CMYK. NB This will alter the colour profile of the image.)";
12088 }
12089 }
12090 // $firsttime added mPDF 6 so when PNG Grayscale with alpha using resrtictcolorspace to CMYK
12091 // the alpha channel is sent through as secondtime as Indexed and should not be converted to CMYK
12092 elseif ($firsttime && ($colspace == 'DeviceRGB' || $colspace == 'Indexed') && $this->restrictColorSpace == 1) {
12093 // Convert to Grayscale image stream - nominally returned as type='png'
12094 $info = $this->_convImage($data, $colspace, 'DeviceGray', $w, $h, $ppUx, $pngalpha, $gamma_correction, $ct); // mPDF 5.7.2 Gamma correction
12095 } elseif (($this->PDFA || $this->PDFX) && $pngalpha) {
12096
12097 // Remove alpha channel
12098 if ($this->restrictColorSpace == 1) { // Grayscale
12099 $info = $this->_convImage($data, $colspace, 'DeviceGray', $w, $h, $ppUx, $pngalpha, $gamma_correction, $ct); // mPDF 5.7.2 Gamma correction
12100 } elseif ($this->restrictColorSpace == 3) { // CMYK
12101 $info = $this->_convImage($data, $colspace, 'DeviceCMYK', $w, $h, $ppUx, $pngalpha, $gamma_correction, $ct); // mPDF 5.7.2 Gamma correction
12102 } elseif ($this->PDFA) { // RGB
12103 $info = $this->_convImage($data, $colspace, 'DeviceRGB', $w, $h, $ppUx, $pngalpha, $gamma_correction, $ct); // mPDF 5.7.2 Gamma correction
12104 }
12105 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
12106 $this->PDFAXwarnings[] = "Transparency (alpha channel) not permitted in PDFA or PDFX files - " . $file . " - (Image converted to one without transparency.)";
12107 }
12108 } elseif ($firsttime && ($errpng || $pngalpha || $gamma_correction)) { // mPDF 5.7.2 Gamma correction
12109 if (function_exists('gd_info')) {
12110 $gd = gd_info();
12111 } else {
12112 $gd = array();
12113 }
12114 if (!isset($gd['PNG Support'])) {
12115 return $this->_imageError($file, $firsttime, 'GD library required for PNG image (' . $errpng . ')');
12116 }
12117 $im = imagecreatefromstring($data);
12118
12119 if (!$im) {
12120 return $this->_imageError($file, $firsttime, 'Error creating GD image from PNG file (' . $errpng . ')');
12121 }
12122 $w = imagesx($im);
12123 $h = imagesy($im);
12124 if ($im) {
12125 $tempfile = _MPDF_TEMP_PATH . '_tempImgPNG' . md5($file) . RAND(1, 10000) . '.png';
12126
12127 // Alpha channel set (including using tRNS for Paletted images)
12128 if ($pngalpha) {
12129 if ($this->PDFA) {
12130 throw new MpdfException("PDFA1-b does not permit images with alpha channel transparency (" . $file . ").");
12131 }
12132
12133 $imgalpha = imagecreate($w, $h);
12134 // generate gray scale pallete
12135 for ($c = 0; $c < 256; ++$c) {
12136 imagecolorallocate($imgalpha, $c, $c, $c);
12137 }
12138
12139 // mPDF 6
12140 if ($colspace == 'Indexed') { // generate Alpha channel values from tRNS
12141 //Read transparency info
12142 $transparency = '';
12143 $p = strpos($data, 'tRNS');
12144 if ($p) {
12145 $n = $this->_fourbytes2int(substr($data, ($p - 4), 4));
12146 $transparency = substr($data, ($p + 4), $n);
12147 // ord($transparency{$index}) = the alpha value for that index
12148 // generate alpha channel
12149 for ($ypx = 0; $ypx < $h; ++$ypx) {
12150 for ($xpx = 0; $xpx < $w; ++$xpx) {
12151 $colorindex = imagecolorat($im, $xpx, $ypx);
12152 if ($colorindex >= $n) {
12153 $alpha = 255;
12154 } else {
12155 $alpha = ord($transparency[$colorindex]);
12156 } // 0-255
12157 if ($alpha > 0) {
12158 imagesetpixel($imgalpha, $xpx, $ypx, $alpha);
12159 }
12160 }
12161 }
12162 }
12163 } elseif ($ct === 0 || $ct == 2) { // generate Alpha channel values from tRNS
12164 // Get transparency as array of RGB
12165 $p = strpos($data, 'tRNS');
12166 if ($p) {
12167 $trns = '';
12168 $n = $this->_fourbytes2int(substr($data, ($p - 4), 4));
12169 $t = substr($data, ($p + 4), $n);
12170 if ($colspace == 'DeviceGray') { // ct===0
12171 $trns = array($this->_trnsvalue(substr($t, 0, 2), $bpc));
12172 } else /* $colspace=='DeviceRGB' */ { // ct==2
12173 $trns = array();
12174 $trns[0] = $this->_trnsvalue(substr($t, 0, 2), $bpc);
12175 $trns[1] = $this->_trnsvalue(substr($t, 2, 2), $bpc);
12176 $trns[2] = $this->_trnsvalue(substr($t, 4, 2), $bpc);
12177 }
12178
12179 // generate alpha channel
12180 for ($ypx = 0; $ypx < $h; ++$ypx) {
12181 for ($xpx = 0; $xpx < $w; ++$xpx) {
12182 $rgb = imagecolorat($im, $xpx, $ypx);
12183 $r = ($rgb >> 16) & 0xFF;
12184 $g = ($rgb >> 8) & 0xFF;
12185 $b = $rgb & 0xFF;
12186 if ($colspace == 'DeviceGray' && $b == $trns[0]) {
12187 $alpha = 0;
12188 } elseif ($r == $trns[0] && $g == $trns[1] && $b == $trns[2]) {
12189 $alpha = 0;
12190 } // ct==2
12191 else {
12192 $alpha = 255;
12193 }
12194 if ($alpha > 0) {
12195 imagesetpixel($imgalpha, $xpx, $ypx, $alpha);
12196 }
12197 }
12198 }
12199 }
12200 } else {
12201 // extract alpha channel
12202 for ($ypx = 0; $ypx < $h; ++$ypx) {
12203 for ($xpx = 0; $xpx < $w; ++$xpx) {
12204 $alpha = (imagecolorat($im, $xpx, $ypx) & 0x7F000000) >> 24;
12205 if ($alpha < 127) {
12206 imagesetpixel($imgalpha, $xpx, $ypx, (255 - ($alpha * 2)));
12207 }
12208 }
12209 }
12210 }
12211
12212
12213 // NB This must happen after the Alpha channel is extracted
12214 // imagegammacorrect() removes the alpha channel data in $im - (I think this is a bug in PHP)
12215 if ($gamma_correction) {
12216 imagegammacorrect($im, $gamma_correction, 2.2);
12217 } // mPDF 6 Gamma correction
12218 // create temp alpha file
12219 $tempfile_alpha = _MPDF_TEMP_PATH . '_tempMskPNG' . md5($file) . RAND(1, 10000) . '.png';
12220 if (!is_writable(_MPDF_TEMP_PATH)) { // mPDF 5.7.2
12221 ob_start();
12222 $check = @imagepng($imgalpha);
12223 if (!$check) {
12224 return $this->_imageError($file, $firsttime, 'Error creating temporary image object whilst using GD library to parse PNG image');
12225 }
12226 imagedestroy($imgalpha);
12227 $this->_tempimg = ob_get_contents();
12228 $this->_tempimglnk = 'var:_tempimg';
12229 ob_end_clean();
12230 // extract image without alpha channel
12231 $imgplain = imagecreatetruecolor($w, $h);
12232 imagealphablending($imgplain, false); // mPDF 5.7.2
12233 imagecopy($imgplain, $im, 0, 0, 0, 0, $w, $h);
12234 // create temp image file
12235 $minfo = $this->_getImage($this->_tempimglnk, false);
12236 if (!$minfo) {
12237 return $this->_imageError($file, $firsttime, 'Error parsing temporary file image object created with GD library to parse PNG image');
12238 }
12239 ob_start();
12240 $check = @imagepng($imgplain);
12241 if (!$check) {
12242 return $this->_imageError($file, $firsttime, 'Error creating temporary image object whilst using GD library to parse PNG image');
12243 }
12244 $this->_tempimg = ob_get_contents();
12245 $this->_tempimglnk = 'var:_tempimg';
12246 ob_end_clean();
12247 $info = $this->_getImage($this->_tempimglnk, false);
12248 if (!$info) {
12249 return $this->_imageError($file, $firsttime, 'Error parsing temporary file image object created with GD library to parse PNG image');
12250 }
12251 imagedestroy($imgplain);
12252 $imgmask = count($this->images) + 1;
12253 $minfo['cs'] = 'DeviceGray';
12254 $minfo['i'] = $imgmask;
12255 $this->images[$tempfile_alpha] = $minfo;
12256 } else {
12257 $check = @imagepng($imgalpha, $tempfile_alpha);
12258 if (!$check) {
12259 return $this->_imageError($file, $firsttime, 'Failed to create temporary image file (' . $tempfile_alpha . ') parsing PNG image with alpha channel (' . $errpng . ')');
12260 }
12261 imagedestroy($imgalpha);
12262 // extract image without alpha channel
12263 $imgplain = imagecreatetruecolor($w, $h);
12264 imagealphablending($imgplain, false); // mPDF 5.7.2
12265 imagecopy($imgplain, $im, 0, 0, 0, 0, $w, $h);
12266
12267 // create temp image file
12268 $check = @imagepng($imgplain, $tempfile);
12269 if (!$check) {
12270 return $this->_imageError($file, $firsttime, 'Failed to create temporary image file (' . $tempfile . ') parsing PNG image with alpha channel (' . $errpng . ')');
12271 }
12272 imagedestroy($imgplain);
12273 // embed mask image
12274 $minfo = $this->_getImage($tempfile_alpha, false);
12275 unlink($tempfile_alpha);
12276 if (!$minfo) {
12277 return $this->_imageError($file, $firsttime, 'Error parsing temporary file (' . $tempfile_alpha . ') created with GD library to parse PNG image');
12278 }
12279 $imgmask = count($this->images) + 1;
12280 $minfo['cs'] = 'DeviceGray';
12281 $minfo['i'] = $imgmask;
12282 $this->images[$tempfile_alpha] = $minfo;
12283 // embed image, masked with previously embedded mask
12284 $info = $this->_getImage($tempfile, false);
12285 unlink($tempfile);
12286 if (!$info) {
12287 return $this->_imageError($file, $firsttime, 'Error parsing temporary file (' . $tempfile . ') created with GD library to parse PNG image');
12288 }
12289 }
12290 $info['masked'] = $imgmask;
12291 if ($ppUx) {
12292 $info['set-dpi'] = $ppUx;
12293 }
12294 $info['type'] = 'png';
12295 if ($firsttime) {
12296 $info['i'] = count($this->images) + 1;
12297 $info['interpolation'] = $interpolation; // mPDF 6
12298 $this->images[$file] = $info;
12299 }
12300
12301 return $info;
12302 } else { // No alpha/transparency set (but cannot read directly because e.g. bit-depth != 8, interlaced etc)
12303 // ICC profile
12304 $icc = false;
12305 $p = strpos($data, 'iCCP');
12306 if ($p && $colspace == "Indexed") { // Cannot have ICC profile and Indexed together
12307 $p += 4;
12308 $n = $this->_fourbytes2int(substr($data, ($p - 8), 4));
12309 $nullsep = strpos(substr($data, $p, 80), chr(0));
12310 $icc = substr($data, ($p + $nullsep + 2), ($n - ($nullsep + 2)));
12311 $icc = @gzuncompress($icc); // Ignored if fails
12312 if ($icc) {
12313 if (substr($icc, 36, 4) != 'acsp') {
12314 $icc = false;
12315 } // invalid ICC profile
12316 else {
12317 $input = substr($icc, 16, 4);
12318 $output = substr($icc, 20, 4);
12319 // Ignore Color profiles for conversion to other colorspaces e.g. CMYK/Lab
12320 if ($input != 'RGB ' || $output != 'XYZ ') {
12321 $icc = false;
12322 }
12323 }
12324 }
12325 // Convert to RGB colorspace so can use ICC Profile
12326 if ($icc) {
12327 imagepalettetotruecolor($im);
12328 $colspace = 'DeviceRGB';
12329 $channels = 3;
12330 }
12331 }
12332
12333 if ($gamma_correction) {
12334 imagegammacorrect($im, $gamma_correction, 2.2);
12335 } // mPDF 6 Gamma correction
12336 imagealphablending($im, false);
12337 imagesavealpha($im, false);
12338 imageinterlace($im, false);
12339 if (!is_writable(_MPDF_TEMP_PATH)) { // mPDF 5.7.2
12340 ob_start();
12341 $check = @imagepng($im);
12342 if (!$check) {
12343 return $this->_imageError($file, $firsttime, 'Error creating temporary image object whilst using GD library to parse PNG image');
12344 }
12345 $this->_tempimg = ob_get_contents();
12346 $this->_tempimglnk = 'var:_tempimg';
12347 ob_end_clean();
12348 $info = $this->_getImage($this->_tempimglnk, false);
12349 if (!$info) {
12350 return $this->_imageError($file, $firsttime, 'Error parsing temporary file image object created with GD library to parse PNG image');
12351 }
12352 imagedestroy($im);
12353 } else {
12354 $check = @imagepng($im, $tempfile);
12355 if (!$check) {
12356 return $this->_imageError($file, $firsttime, 'Failed to create temporary image file (' . $tempfile . ') parsing PNG image (' . $errpng . ')');
12357 }
12358 imagedestroy($im);
12359 $info = $this->_getImage($tempfile, false);
12360 unlink($tempfile);
12361 if (!$info) {
12362 return $this->_imageError($file, $firsttime, 'Error parsing temporary file (' . $tempfile . ') created with GD library to parse PNG image');
12363 }
12364 }
12365 if ($ppUx) {
12366 $info['set-dpi'] = $ppUx;
12367 }
12368 $info['type'] = 'png';
12369 if ($firsttime) {
12370 $info['i'] = count($this->images) + 1;
12371 $info['interpolation'] = $interpolation; // mPDF 6
12372 if ($icc) {
12373 $info['ch'] = $channels;
12374 $info['icc'] = $icc;
12375 }
12376 $this->images[$file] = $info;
12377 }
12378 return $info;
12379 }
12380 }
12381 } else { // PNG image with no need to convert alph channels, bpc <> 8 etc.
12382 $parms = '/DecodeParms <</Predictor 15 /Colors ' . $channels . ' /BitsPerComponent ' . $bpc . ' /Columns ' . $w . '>>';
12383 //Scan chunks looking for palette, transparency and image data
12384 $pal = '';
12385 $trns = '';
12386 $pngdata = '';
12387 $icc = false;
12388 $p = 33;
12389 do {
12390 $n = $this->_fourbytes2int(substr($data, $p, 4));
12391 $p += 4;
12392 $type = substr($data, $p, 4);
12393 $p += 4;
12394 if ($type == 'PLTE') {
12395 //Read palette
12396 $pal = substr($data, $p, $n);
12397 $p += $n;
12398 $p += 4;
12399 } elseif ($type == 'tRNS') {
12400 //Read transparency info
12401 $t = substr($data, $p, $n);
12402 $p += $n;
12403 if ($ct == 0)
12404 $trns = array(ord(substr($t, 1, 1)));
12405 elseif ($ct == 2)
12406 $trns = array(ord(substr($t, 1, 1)), ord(substr($t, 3, 1)), ord(substr($t, 5, 1)));
12407 else {
12408 $pos = strpos($t, chr(0));
12409 if (is_int($pos))
12410 $trns = array($pos);
12411 }
12412 $p += 4;
12413 }
12414 elseif ($type == 'IDAT') {
12415 $pngdata.=substr($data, $p, $n);
12416 $p += $n;
12417 $p += 4;
12418 } elseif ($type == 'iCCP') {
12419 $nullsep = strpos(substr($data, $p, 80), chr(0));
12420 $icc = substr($data, ($p + $nullsep + 2), ($n - ($nullsep + 2)));
12421 $icc = @gzuncompress($icc); // Ignored if fails
12422 if ($icc) {
12423 if (substr($icc, 36, 4) != 'acsp') {
12424 $icc = false;
12425 } // invalid ICC profile
12426 else {
12427 $input = substr($icc, 16, 4);
12428 $output = substr($icc, 20, 4);
12429 // Ignore Color profiles for conversion to other colorspaces e.g. CMYK/Lab
12430 if ($input != 'RGB ' || $output != 'XYZ ') {
12431 $icc = false;
12432 }
12433 }
12434 }
12435 $p += $n;
12436 $p += 4;
12437 } elseif ($type == 'IEND') {
12438 break;
12439 } elseif (preg_match('/[a-zA-Z]{4}/', $type)) {
12440 $p += $n + 4;
12441 } else {
12442 return $this->_imageError($file, $firsttime, 'Error parsing PNG image data');
12443 }
12444 } while ($n);
12445 if (!$pngdata) {
12446 return $this->_imageError($file, $firsttime, 'Error parsing PNG image data - no IDAT data found');
12447 }
12448 if ($colspace == 'Indexed' && empty($pal)) {
12449 return $this->_imageError($file, $firsttime, 'Error parsing PNG image data - missing colour palette');
12450 }
12451
12452 if ($colspace == 'Indexed' && $icc) {
12453 $icc = false;
12454 } // mPDF 6 cannot have ICC profile and Indexed in a PDF document as both use the colorspace tag.
12455
12456 $info = array('w' => $w, 'h' => $h, 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'FlateDecode', 'parms' => $parms, 'pal' => $pal, 'trns' => $trns, 'data' => $pngdata, 'ch' => $channels, 'icc' => $icc);
12457 $info['type'] = 'png';
12458 if ($ppUx) {
12459 $info['set-dpi'] = $ppUx;
12460 }
12461 }
12462
12463 if (!$info) {
12464 return $this->_imageError($file, $firsttime, 'Error parsing or converting PNG image');
12465 }
12466
12467 if ($firsttime) {
12468 $info['i'] = count($this->images) + 1;
12469 $info['interpolation'] = $interpolation; // mPDF 6
12470 $this->images[$file] = $info;
12471 }
12472 return $info;
12473 }
12474
12475 // GIF
12476 elseif ($type == 'gif') {
12477 if (function_exists('gd_info')) {
12478 $gd = gd_info();
12479 } else {
12480 $gd = array();
12481 }
12482 if (isset($gd['GIF Read Support']) && $gd['GIF Read Support']) {
12483 $im = @imagecreatefromstring($data);
12484 if ($im) {
12485 $tempfile = _MPDF_TEMP_PATH . '_tempImgPNG' . md5($file) . RAND(1, 10000) . '.png';
12486 imagealphablending($im, false);
12487 imagesavealpha($im, false);
12488 imageinterlace($im, false);
12489 if (!is_writable($tempfile)) {
12490 ob_start();
12491 $check = @imagepng($im);
12492 if (!$check) {
12493 return $this->_imageError($file, $firsttime, 'Error creating temporary image object whilst using GD library to parse GIF image');
12494 }
12495 $this->_tempimg = ob_get_contents();
12496 $this->_tempimglnk = 'var:_tempimg';
12497 ob_end_clean();
12498 $info = $this->_getImage($this->_tempimglnk, false);
12499 if (!$info) {
12500 return $this->_imageError($file, $firsttime, 'Error parsing temporary file image object created with GD library to parse GIF image');
12501 }
12502 imagedestroy($im);
12503 } else {
12504 $check = @imagepng($im, $tempfile);
12505 if (!$check) {
12506 return $this->_imageError($file, $firsttime, 'Error creating temporary file (' . $tempfile . ') whilst using GD library to parse GIF image');
12507 }
12508 $info = $this->_getImage($tempfile, false);
12509 if (!$info) {
12510 return $this->_imageError($file, $firsttime, 'Error parsing temporary file (' . $tempfile . ') created with GD library to parse GIF image');
12511 }
12512 imagedestroy($im);
12513 unlink($tempfile);
12514 }
12515 $info['type'] = 'gif';
12516 if ($firsttime) {
12517 $info['i'] = count($this->images) + 1;
12518 $info['interpolation'] = $interpolation; // mPDF 6
12519 $this->images[$file] = $info;
12520 }
12521 return $info;
12522 } else {
12523 return $this->_imageError($file, $firsttime, 'Error creating GD image file from GIF image');
12524 }
12525 }
12526
12527 if (!class_exists('gif', false)) {
12528 include_once(_MPDF_PATH . 'classes/gif.php');
12529 }
12530 $gif = new CGIF();
12531
12532 $h = 0;
12533 $w = 0;
12534 $gif->loadFile($data, 0);
12535
12536 if (isset($gif->m_img->m_gih->m_bLocalClr) && $gif->m_img->m_gih->m_bLocalClr) {
12537 $nColors = $gif->m_img->m_gih->m_nTableSize;
12538 $pal = $gif->m_img->m_gih->m_colorTable->toString();
12539 if ((isset($bgColor)) and $bgColor != -1) { // mPDF 5.7.3
12540 $bgColor = $gif->m_img->m_gih->m_colorTable->colorIndex($bgColor);
12541 }
12542 $colspace = 'Indexed';
12543 } elseif (isset($gif->m_gfh->m_bGlobalClr) && $gif->m_gfh->m_bGlobalClr) {
12544 $nColors = $gif->m_gfh->m_nTableSize;
12545 $pal = $gif->m_gfh->m_colorTable->toString();
12546 if ((isset($bgColor)) and $bgColor != -1) {
12547 $bgColor = $gif->m_gfh->m_colorTable->colorIndex($bgColor);
12548 }
12549 $colspace = 'Indexed';
12550 } else {
12551 $nColors = 0;
12552 $bgColor = -1;
12553 $colspace = 'DeviceGray';
12554 $pal = '';
12555 }
12556
12557 $trns = '';
12558 if (isset($gif->m_img->m_bTrans) && $gif->m_img->m_bTrans && ($nColors > 0)) {
12559 $trns = array($gif->m_img->m_nTrans);
12560 }
12561 $gifdata = $gif->m_img->m_data;
12562 $w = $gif->m_gfh->m_nWidth;
12563 $h = $gif->m_gfh->m_nHeight;
12564 $gif->ClearData();
12565
12566 if ($colspace == 'Indexed' and empty($pal)) {
12567 return $this->_imageError($file, $firsttime, 'Error parsing GIF image - missing colour palette');
12568 }
12569 if ($this->compress) {
12570 $gifdata = gzcompress($gifdata);
12571 $info = array('w' => $w, 'h' => $h, 'cs' => $colspace, 'bpc' => 8, 'f' => 'FlateDecode', 'pal' => $pal, 'trns' => $trns, 'data' => $gifdata);
12572 } else {
12573 $info = array('w' => $w, 'h' => $h, 'cs' => $colspace, 'bpc' => 8, 'pal' => $pal, 'trns' => $trns, 'data' => $gifdata);
12574 }
12575 $info['type'] = 'gif';
12576 if ($firsttime) {
12577 $info['i'] = count($this->images) + 1;
12578 $info['interpolation'] = $interpolation; // mPDF 6
12579 $this->images[$file] = $info;
12580 }
12581 return $info;
12582 }
12583
12584 /* -- IMAGES-BMP -- */
12585 // BMP (Windows Bitmap)
12586 elseif ($type == 'bmp') {
12587 if (!class_exists('bmp', false)) {
12588 include(_MPDF_PATH . 'classes/bmp.php');
12589 }
12590 if (empty($this->bmp)) {
12591 $this->bmp = new bmp($this);
12592 }
12593 $info = $this->bmp->_getBMPimage($data, $file);
12594 if (isset($info['error'])) {
12595 return $this->_imageError($file, $firsttime, $info['error']);
12596 }
12597 if ($firsttime) {
12598 $info['i'] = count($this->images) + 1;
12599 $info['interpolation'] = $interpolation; // mPDF 6
12600 $this->images[$file] = $info;
12601 }
12602 return $info;
12603 }
12604 /* -- END IMAGES-BMP -- */
12605 /* -- IMAGES-WMF -- */
12606 // WMF
12607 elseif ($type == 'wmf') {
12608 if (!class_exists('wmf', false)) {
12609 include(_MPDF_PATH . 'classes/wmf.php');
12610 }
12611 if (empty($this->wmf)) {
12612 $this->wmf = new wmf($this);
12613 }
12614 $wmfres = $this->wmf->_getWMFimage($data);
12615 if ($wmfres[0] == 0) {
12616 if ($wmfres[1]) {
12617 return $this->_imageError($file, $firsttime, $wmfres[1]);
12618 }
12619 return $this->_imageError($file, $firsttime, 'Error parsing WMF image');
12620 }
12621 $info = array('x' => $wmfres[2][0], 'y' => $wmfres[2][1], 'w' => $wmfres[3][0], 'h' => $wmfres[3][1], 'data' => $wmfres[1]);
12622 $info['i'] = count($this->formobjects) + 1;
12623 $info['type'] = 'wmf';
12624 $this->formobjects[$file] = $info;
12625 return $info;
12626 }
12627 /* -- END IMAGES-WMF -- */
12628
12629 // UNKNOWN TYPE - try GD imagecreatefromstring
12630 else {
12631 if (function_exists('gd_info')) {
12632 $gd = gd_info();
12633 } else {
12634 $gd = array();
12635 }
12636 if (isset($gd['PNG Support']) && $gd['PNG Support']) {
12637 $im = @imagecreatefromstring($data);
12638 if (!$im) {
12639 return $this->_imageError($file, $firsttime, 'Error parsing image file - image type not recognised, and not supported by GD imagecreate');
12640 }
12641 $tempfile = _MPDF_TEMP_PATH . '_tempImgPNG' . md5($file) . RAND(1, 10000) . '.png';
12642 imagealphablending($im, false);
12643 imagesavealpha($im, false);
12644 imageinterlace($im, false);
12645 $check = @imagepng($im, $tempfile);
12646 if (!$check) {
12647 return $this->_imageError($file, $firsttime, 'Error creating temporary file (' . $tempfile . ') whilst using GD library to parse unknown image type');
12648 }
12649 $info = $this->_getImage($tempfile, false);
12650 imagedestroy($im);
12651 unlink($tempfile);
12652 if (!$info) {
12653 return $this->_imageError($file, $firsttime, 'Error parsing temporary file (' . $tempfile . ') created with GD library to parse unknown image type');
12654 }
12655 $info['type'] = 'png';
12656 if ($firsttime) {
12657 $info['i'] = count($this->images) + 1;
12658 $info['interpolation'] = $interpolation; // mPDF 6
12659 $this->images[$file] = $info;
12660 }
12661 return $info;
12662 }
12663 }
12664
12665 return $this->_imageError($file, $firsttime, 'Error parsing image file - image type not recognised');
12666 }
12667
12668 //==============================================================
12669 function _convImage(&$data, $colspace, $targetcs, $w, $h, $dpi, $mask, $gamma_correction = false, $pngcolortype = false)
12670 { // mPDF 5.7.2 Gamma correction
12671 if ($this->PDFA || $this->PDFX) {
12672 $mask = false;
12673 }
12674 $im = @imagecreatefromstring($data);
12675 $info = array();
12676 $bpc = ord(substr($data, 24, 1));
12677 if ($im) {
12678
12679 $imgdata = '';
12680 $mimgdata = '';
12681 $minfo = array();
12682
12683 // mPDF 6 Gamma correction
12684 // Need to extract alpha channel info before imagegammacorrect (which loses the data)
12685 if ($mask) { // i.e. $pngalpha for PNG
12686 // mPDF 6
12687 if ($colspace == 'Indexed') { // generate Alpha channel values from tRNS - only from PNG
12688 //Read transparency info
12689 $transparency = '';
12690 $p = strpos($data, 'tRNS');
12691 if ($p) {
12692 $n = $this->_fourbytes2int(substr($data, ($p - 4), 4));
12693 $transparency = substr($data, ($p + 4), $n);
12694 // ord($transparency{$index}) = the alpha value for that index
12695 // generate alpha channel
12696 for ($ypx = 0; $ypx < $h; ++$ypx) {
12697 for ($xpx = 0; $xpx < $w; ++$xpx) {
12698 $colorindex = imagecolorat($im, $xpx, $ypx);
12699 if ($colorindex >= $n) {
12700 $alpha = 255;
12701 } else {
12702 $alpha = ord($transparency[$colorindex]);
12703 } // 0-255
12704 $mimgdata .= chr($alpha);
12705 }
12706 }
12707 }
12708 } elseif ($pngcolortype === 0 || $pngcolortype == 2) { // generate Alpha channel values from tRNS
12709 // Get transparency as array of RGB
12710 $p = strpos($data, 'tRNS');
12711 if ($p) {
12712 $trns = '';
12713 $n = $this->_fourbytes2int(substr($data, ($p - 4), 4));
12714 $t = substr($data, ($p + 4), $n);
12715 if ($colspace == 'DeviceGray') { // ct===0
12716 $trns = array($this->_trnsvalue(substr($t, 0, 2), $bpc));
12717 } else /* $colspace=='DeviceRGB' */ { // ct==2
12718 $trns = array();
12719 $trns[0] = $this->_trnsvalue(substr($t, 0, 2), $bpc);
12720 $trns[1] = $this->_trnsvalue(substr($t, 2, 2), $bpc);
12721 $trns[2] = $this->_trnsvalue(substr($t, 4, 2), $bpc);
12722 }
12723
12724 // generate alpha channel
12725 for ($ypx = 0; $ypx < $h; ++$ypx) {
12726 for ($xpx = 0; $xpx < $w; ++$xpx) {
12727 $rgb = imagecolorat($im, $xpx, $ypx);
12728 $r = ($rgb >> 16) & 0xFF;
12729 $g = ($rgb >> 8) & 0xFF;
12730 $b = $rgb & 0xFF;
12731 if ($colspace == 'DeviceGray' && $b == $trns[0]) {
12732 $alpha = 0;
12733 } elseif ($r == $trns[0] && $g == $trns[1] && $b == $trns[2]) {
12734 $alpha = 0;
12735 } // ct==2
12736 else {
12737 $alpha = 255;
12738 }
12739 $mimgdata .= chr($alpha);
12740 }
12741 }
12742 }
12743 } else {
12744 for ($i = 0; $i < $h; $i++) {
12745 for ($j = 0; $j < $w; $j++) {
12746 $rgb = imagecolorat($im, $j, $i);
12747 $alpha = ($rgb & 0x7F000000) >> 24;
12748 if ($alpha < 127) {
12749 $mimgdata .= chr(255 - ($alpha * 2));
12750 } else {
12751 $mimgdata .= chr(0);
12752 }
12753 }
12754 }
12755 }
12756 }
12757
12758 if ($gamma_correction) {
12759 imagegammacorrect($im, $gamma_correction, 2.2);
12760 } // mPDF 6 Gamma correction
12761 //Read transparency info
12762 $trns = array();
12763 $trnsrgb = false;
12764 if (!$this->PDFA && !$this->PDFX && !$mask) { // mPDF 6 added NOT mask
12765 $p = strpos($data, 'tRNS');
12766 if ($p) {
12767 $n = $this->_fourbytes2int(substr($data, ($p - 4), 4));
12768 $t = substr($data, ($p + 4), $n);
12769 if ($colspace == 'DeviceGray') { // ct===0
12770 $trns = array($this->_trnsvalue(substr($t, 0, 2), $bpc));
12771 } elseif ($colspace == 'DeviceRGB') { // ct==2
12772 $trns[0] = $this->_trnsvalue(substr($t, 0, 2), $bpc);
12773 $trns[1] = $this->_trnsvalue(substr($t, 2, 2), $bpc);
12774 $trns[2] = $this->_trnsvalue(substr($t, 4, 2), $bpc);
12775 $trnsrgb = $trns;
12776 if ($targetcs == 'DeviceCMYK') {
12777 $col = $this->rgb2cmyk(array(3, $trns[0], $trns[1], $trns[2]));
12778 $c1 = intval($col[1] * 2.55);
12779 $c2 = intval($col[2] * 2.55);
12780 $c3 = intval($col[3] * 2.55);
12781 $c4 = intval($col[4] * 2.55);
12782 $trns = array($c1, $c2, $c3, $c4);
12783 } elseif ($targetcs == 'DeviceGray') {
12784 $c = intval(($trns[0] * .21) + ($trns[1] * .71) + ($trns[2] * .07));
12785 $trns = array($c);
12786 }
12787 } else { // Indexed
12788 $pos = strpos($t, chr(0));
12789 if (is_int($pos)) {
12790 $pal = imagecolorsforindex($im, $pos);
12791 $r = $pal['red'];
12792 $g = $pal['green'];
12793 $b = $pal['blue'];
12794 $trns = array($r, $g, $b); // ****
12795 $trnsrgb = $trns;
12796 if ($targetcs == 'DeviceCMYK') {
12797 $col = $this->rgb2cmyk(array(3, $r, $g, $b));
12798 $c1 = intval($col[1] * 2.55);
12799 $c2 = intval($col[2] * 2.55);
12800 $c3 = intval($col[3] * 2.55);
12801 $c4 = intval($col[4] * 2.55);
12802 $trns = array($c1, $c2, $c3, $c4);
12803 } elseif ($targetcs == 'DeviceGray') {
12804 $c = intval(($r * .21) + ($g * .71) + ($b * .07));
12805 $trns = array($c);
12806 }
12807 }
12808 }
12809 }
12810 }
12811 for ($i = 0; $i < $h; $i++) {
12812 for ($j = 0; $j < $w; $j++) {
12813 $rgb = imagecolorat($im, $j, $i);
12814 $r = ($rgb >> 16) & 0xFF;
12815 $g = ($rgb >> 8) & 0xFF;
12816 $b = $rgb & 0xFF;
12817 if ($colspace == 'Indexed') {
12818 $pal = imagecolorsforindex($im, $rgb);
12819 $r = $pal['red'];
12820 $g = $pal['green'];
12821 $b = $pal['blue'];
12822 }
12823
12824 if ($targetcs == 'DeviceCMYK') {
12825 $col = $this->rgb2cmyk(array(3, $r, $g, $b));
12826 $c1 = intval($col[1] * 2.55);
12827 $c2 = intval($col[2] * 2.55);
12828 $c3 = intval($col[3] * 2.55);
12829 $c4 = intval($col[4] * 2.55);
12830 if ($trnsrgb) {
12831 // original pixel was not set as transparent but processed color does match
12832 if ($trnsrgb != array($r, $g, $b) && $trns == array($c1, $c2, $c3, $c4)) {
12833 if ($c4 == 0) {
12834 $c4 = 1;
12835 } else {
12836 $c4--;
12837 }
12838 }
12839 }
12840 $imgdata .= chr($c1) . chr($c2) . chr($c3) . chr($c4);
12841 } elseif ($targetcs == 'DeviceGray') {
12842 $c = intval(($r * .21) + ($g * .71) + ($b * .07));
12843 if ($trnsrgb) {
12844 // original pixel was not set as transparent but processed color does match
12845 if ($trnsrgb != array($r, $g, $b) && $trns == array($c)) {
12846 if ($c == 0) {
12847 $c = 1;
12848 } else {
12849 $c--;
12850 }
12851 }
12852 }
12853 $imgdata .= chr($c);
12854 } elseif ($targetcs == 'DeviceRGB') {
12855 $imgdata .= chr($r) . chr($g) . chr($b);
12856 }
12857 }
12858 }
12859
12860 if ($targetcs == 'DeviceGray') {
12861 $ncols = 1;
12862 } elseif ($targetcs == 'DeviceRGB') {
12863 $ncols = 3;
12864 } elseif ($targetcs == 'DeviceCMYK') {
12865 $ncols = 4;
12866 }
12867
12868 $imgdata = gzcompress($imgdata);
12869 $info = array('w' => $w, 'h' => $h, 'cs' => $targetcs, 'bpc' => 8, 'f' => 'FlateDecode', 'data' => $imgdata, 'type' => 'png',
12870 'parms' => '/DecodeParms <</Colors ' . $ncols . ' /BitsPerComponent 8 /Columns ' . $w . '>>');
12871 if ($dpi) {
12872 $info['set-dpi'] = $dpi;
12873 }
12874 if ($mask) {
12875 $mimgdata = gzcompress($mimgdata);
12876 $minfo = array('w' => $w, 'h' => $h, 'cs' => 'DeviceGray', 'bpc' => 8, 'f' => 'FlateDecode', 'data' => $mimgdata, 'type' => 'png',
12877 'parms' => '/DecodeParms <</Colors ' . $ncols . ' /BitsPerComponent 8 /Columns ' . $w . '>>');
12878 if ($dpi) {
12879 $minfo['set-dpi'] = $dpi;
12880 }
12881 $tempfile = '_tempImgPNG' . md5($data) . RAND(1, 10000) . '.png';
12882 $imgmask = count($this->images) + 1;
12883 $minfo['i'] = $imgmask;
12884 $this->images[$tempfile] = $minfo;
12885 $info['masked'] = $imgmask;
12886 } elseif ($trns) {
12887 $info['trns'] = $trns;
12888 }
12889 imagedestroy($im);
12890 }
12891 return $info;
12892 }
12893
12894 function _trnsvalue($s, $bpc)
12895 {
12896 // Corrects 2-byte integer to 8-bit depth value
12897 // If original image is bpc != 8, tRNS will be in this bpc
12898 // $im from imagecreatefromstring will always be in bpc=8
12899 // So why do we only need to correct 16-bit tRNS and NOT 2 or 4-bit???
12900 $n = $this->_twobytes2int($s);
12901 if ($bpc == 16) {
12902 $n = ($n >> 8);
12903 }
12904 //elseif ($bpc==4) { $n = ($n << 2); }
12905 //elseif ($bpc==2) { $n = ($n << 4); }
12906 return $n;
12907 }
12908
12909 function _fourbytes2int($s)
12910 {
12911 //Read a 4-byte integer from string
12912 return (ord($s[0]) << 24) + (ord($s[1]) << 16) + (ord($s[2]) << 8) + ord($s[3]);
12913 }
12914
12915 function _twobytes2int($s)
12916 { // equivalent to _get_ushort
12917 //Read a 2-byte integer from string
12918 return (ord(substr($s, 0, 1)) << 8) + ord(substr($s, 1, 1));
12919 }
12920
12921 function _jpgHeaderFromString(&$data)
12922 {
12923 $p = 4;
12924 $p += $this->_twobytes2int(substr($data, $p, 2)); // Length of initial marker block
12925 $marker = substr($data, $p, 2);
12926 while ($marker != chr(255) . chr(192) && $marker != chr(255) . chr(194) && $p < strlen($data)) {
12927 // Start of frame marker (FFC0) or (FFC2) mPDF 4.4.004
12928 $p += ($this->_twobytes2int(substr($data, $p + 2, 2))) + 2; // Length of marker block
12929 $marker = substr($data, $p, 2);
12930 }
12931 if ($marker != chr(255) . chr(192) && $marker != chr(255) . chr(194)) {
12932 return false;
12933 }
12934 return substr($data, $p + 2, 10);
12935 }
12936
12937 function _jpgDataFromHeader($hdr)
12938 {
12939 $bpc = ord(substr($hdr, 2, 1));
12940 if (!$bpc) {
12941 $bpc = 8;
12942 }
12943 $h = $this->_twobytes2int(substr($hdr, 3, 2));
12944 $w = $this->_twobytes2int(substr($hdr, 5, 2));
12945 $channels = ord(substr($hdr, 7, 1));
12946 if ($channels == 3) {
12947 $colspace = 'DeviceRGB';
12948 } elseif ($channels == 4) {
12949 $colspace = 'DeviceCMYK';
12950 } else {
12951 $colspace = 'DeviceGray';
12952 }
12953 return array($w, $h, $colspace, $bpc, $channels);
12954 }
12955
12956 function file_get_contents_by_curl($url, &$data)
12957 {
12958 $timeout = 5;
12959 $ch = curl_init($url);
12960 curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:13.0) Gecko/20100101 Firefox/13.0.1'); // mPDF 5.7.4
12961 curl_setopt($ch, CURLOPT_HEADER, 0);
12962 curl_setopt($ch, CURLOPT_NOBODY, 0);
12963 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
12964 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
12965 $data = curl_exec($ch);
12966 curl_close($ch);
12967 }
12968
12969 function file_get_contents_by_socket($url, &$data)
12970 {
12971 // mPDF 5.7.3
12972 $timeout = 1;
12973 $p = parse_url($url);
12974 $file = $p['path'];
12975 if ($p['scheme'] == 'https') {
12976 $prefix = 'ssl://';
12977 $port = ($p['port'] ? $p['port'] : 443);
12978 } else {
12979 $prefix = '';
12980 $port = ($p['port'] ? $p['port'] : 80);
12981 }
12982 if ($p['query']) {
12983 $file .= '?' . $p['query'];
12984 }
12985 if (!($fh = @fsockopen($prefix . $p['host'], $port, $errno, $errstr, $timeout))) {
12986 return false;
12987 }
12988
12989 $getstring = "GET " . $file . " HTTP/1.0 \r\n" .
12990 "Host: " . $p['host'] . " \r\n" .
12991 "Connection: close\r\n\r\n";
12992 fwrite($fh, $getstring);
12993 // Get rid of HTTP header
12994 $s = fgets($fh, 1024);
12995 if (!$s) {
12996 return false;
12997 }
12998 $httpheader .= $s;
12999 while (!feof($fh)) {
13000 $s = fgets($fh, 1024);
13001 if ($s == "\r\n") {
13002 break;
13003 }
13004 }
13005 $data = '';
13006 while (!feof($fh)) {
13007 $data .= fgets($fh, 1024);
13008 }
13009 fclose($fh);
13010 }
13011
13012 //==============================================================
13013
13014 function _imageTypeFromString(&$data)
13015 {
13016 $type = '';
13017 if (substr($data, 6, 4) == 'JFIF' || substr($data, 6, 4) == 'Exif' || substr($data, 0, 2) == chr(255) . chr(216)) { // 0xFF 0xD8 // mpDF 5.7.2
13018 $type = 'jpeg';
13019 } elseif (substr($data, 0, 6) == "GIF87a" || substr($data, 0, 6) == "GIF89a") {
13020 $type = 'gif';
13021 } elseif (substr($data, 0, 8) == chr(137) . 'PNG' . chr(13) . chr(10) . chr(26) . chr(10)) {
13022 $type = 'png';
13023 }
13024 /* -- IMAGES-WMF -- */ elseif (substr($data, 0, 4) == chr(215) . chr(205) . chr(198) . chr(154)) {
13025 $type = 'wmf';
13026 }
13027 /* -- END IMAGES-WMF -- */ elseif (preg_match('/<svg.*<\/svg>/is', $data)) {
13028 $type = 'svg';
13029 }
13030 // BMP images
13031 elseif (substr($data, 0, 2) == "BM") {
13032 $type = 'bmp';
13033 }
13034 return $type;
13035 }
13036
13037 //==============================================================
13038 // Moved outside WMF as also needed for SVG
13039 function _putformobjects()
13040 {
13041 reset($this->formobjects);
13042 //while (list($file, $info) = each($this->formobjects)) {
13043 foreach( $this->formobjects as $file => $info ) {
13044 $this->_newobj();
13045 $this->formobjects[$file]['n'] = $this->n;
13046 $this->_out('<</Type /XObject');
13047 $this->_out('/Subtype /Form');
13048 $this->_out('/Group ' . ($this->n + 1) . ' 0 R');
13049 $this->_out('/BBox [' . $info['x'] . ' ' . $info['y'] . ' ' . ($info['w'] + $info['x']) . ' ' . ($info['h'] + $info['y']) . ']');
13050 if ($this->compress)
13051 $this->_out('/Filter /FlateDecode');
13052 $data = ($this->compress) ? gzcompress($info['data']) : $info['data'];
13053 $this->_out('/Length ' . strlen($data) . '>>');
13054 $this->_putstream($data);
13055 unset($this->formobjects[$file]['data']);
13056 $this->_out('endobj');
13057 // Required for SVG transparency (opacity) to work
13058 $this->_newobj();
13059 $this->_out('<</Type /Group');
13060 $this->_out('/S /Transparency');
13061 $this->_out('>>');
13062 $this->_out('endobj');
13063 }
13064 }
13065
13066 function _freadint($f)
13067 {
13068 //Read a 4-byte integer from file
13069 $i = ord(fread($f, 1)) << 24;
13070 $i+=ord(fread($f, 1)) << 16;
13071 $i+=ord(fread($f, 1)) << 8;
13072 $i+=ord(fread($f, 1));
13073 return $i;
13074 }
13075
13076 function _UTF16BEtextstring($s)
13077 {
13078 $s = $this->UTF8ToUTF16BE($s, true);
13079 /* -- ENCRYPTION -- */
13080 if ($this->encrypted) {
13081 $s = $this->_RC4($this->_objectkey($this->_current_obj_id), $s);
13082 }
13083 /* -- END ENCRYPTION -- */
13084 return '(' . $this->_escape($s) . ')';
13085 }
13086
13087 function _textstring($s)
13088 {
13089 /* -- ENCRYPTION -- */
13090 if ($this->encrypted) {
13091 $s = $this->_RC4($this->_objectkey($this->_current_obj_id), $s);
13092 }
13093 /* -- END ENCRYPTION -- */
13094 return '(' . $this->_escape($s) . ')';
13095 }
13096
13097 function _escape($s)
13098 {
13099 // the chr(13) substitution fixes the Bugs item #1421290.
13100 return strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\', chr(13) => '\r'));
13101 }
13102
13103 function _putstream($s)
13104 {
13105 /* -- ENCRYPTION -- */
13106 if ($this->encrypted) {
13107 $s = $this->_RC4($this->_objectkey($this->_current_obj_id), $s);
13108 }
13109 /* -- END ENCRYPTION -- */
13110 $this->_out('stream');
13111 $this->_out($s);
13112 $this->_out('endstream');
13113 }
13114
13115 function _out($s, $ln = true)
13116 {
13117 if ($this->state == 2) {
13118 if ($this->bufferoutput) {
13119 $this->headerbuffer.= $s . "\n";
13120 }
13121 /* -- COLUMNS -- */ elseif (($this->ColActive) && !$this->processingHeader && !$this->processingFooter) {
13122 // Captures everything in buffer for columns; Almost everything is sent from fn. Cell() except:
13123 // Images sent from Image() or
13124 // later sent as _out($textto) in printbuffer
13125 // Line()
13126 if (preg_match('/q \d+\.\d\d+ 0 0 (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ cm \/(I|FO)\d+ Do Q/', $s, $m)) { // Image data
13127 $h = ($m[1] / _MPDFK);
13128 // Update/overwrite the lowest bottom of printing y value for a column
13129 $this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y + $h;
13130 }
13131 /* -- TABLES -- */ elseif (preg_match('/\d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ ([\-]{0,1}\d+\.\d\d+) re/', $s, $m) && $this->tableLevel > 0) { // Rect in table
13132 $h = ($m[1] / _MPDFK);
13133 // Update/overwrite the lowest bottom of printing y value for a column
13134 $this->ColDetails[$this->CurrCol]['bottom_margin'] = max($this->ColDetails[$this->CurrCol]['bottom_margin'], ($this->y + $h));
13135 }
13136 /* -- END TABLES -- */ else { // Td Text Set in Cell()
13137 if (isset($this->ColDetails[$this->CurrCol]['bottom_margin'])) {
13138 $h = $this->ColDetails[$this->CurrCol]['bottom_margin'] - $this->y;
13139 } else {
13140 $h = 0;
13141 }
13142 }
13143 if ($h < 0) {
13144 $h = -$h;
13145 }
13146 $this->columnbuffer[] = array(
13147 's' => $s, // Text string to output
13148 'col' => $this->CurrCol, // Column when printed
13149 'x' => $this->x, // x when printed
13150 'y' => $this->y, // this->y when printed (after column break)
13151 'h' => $h // actual y at bottom when printed = y+h
13152 );
13153 }
13154 /* -- END COLUMNS -- */
13155 /* -- TABLES -- */ elseif ($this->table_rotate && !$this->processingHeader && !$this->processingFooter) {
13156 // Captures eveything in buffer for rotated tables;
13157 $this->tablebuffer .= $s . "\n";
13158 }
13159 /* -- END TABLES -- */ elseif ($this->kwt && !$this->processingHeader && !$this->processingFooter) {
13160 // Captures eveything in buffer for keep-with-table (h1-6);
13161 $this->kwt_buffer[] = array(
13162 's' => $s, // Text string to output
13163 'x' => $this->x, // x when printed
13164 'y' => $this->y, // y when printed
13165 );
13166 } elseif (($this->keep_block_together) && !$this->processingHeader && !$this->processingFooter) {
13167 // do nothing
13168 } else {
13169 $this->pages[$this->page] .= $s . ($ln == true ? "\n" : '');
13170 }
13171 } else {
13172 $this->buffer .= $s . ($ln == true ? "\n" : '');
13173 }
13174 }
13175
13176 /* -- WATERMARK -- */
13177
13178 // add a watermark
13179 function watermark($texte, $angle = 45, $fontsize = 96, $alpha = 0.2)
13180 {
13181 if ($this->PDFA || $this->PDFX) {
13182 throw new MpdfException('PDFA and PDFX do not permit transparency, so mPDF does not allow Watermarks!');
13183 }
13184 if (!$this->watermark_font) {
13185 $this->watermark_font = $this->default_font;
13186 }
13187 $this->SetFont($this->watermark_font, "B", $fontsize, false); // Don't output
13188 $texte = $this->purify_utf8_text($texte);
13189 if ($this->text_input_as_HTML) {
13190 $texte = $this->all_entities_to_utf8($texte);
13191 }
13192 if ($this->usingCoreFont) {
13193 $texte = mb_convert_encoding($texte, $this->mb_enc, 'UTF-8');
13194 }
13195
13196 // DIRECTIONALITY
13197 if (preg_match("/([" . $this->pregRTLchars . "])/u", $texte)) {
13198 $this->biDirectional = true;
13199 } // *OTL*
13200
13201 $textvar = 0;
13202 $save_OTLtags = $this->OTLtags;
13203 $this->OTLtags = array();
13204 if ($this->useKerning) {
13205 if ($this->CurrentFont['haskernGPOS']) {
13206 $this->OTLtags['Plus'] .= ' kern';
13207 } else {
13208 $textvar = ($textvar | FC_KERNING);
13209 }
13210 }
13211
13212 /* -- OTL -- */
13213 // Use OTL OpenType Table Layout - GSUB & GPOS
13214 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
13215 $texte = $this->otl->applyOTL($texte, $this->CurrentFont['useOTL']);
13216 $OTLdata = $this->otl->OTLdata;
13217 }
13218 /* -- END OTL -- */
13219 $this->OTLtags = $save_OTLtags;
13220
13221 $this->magic_reverse_dir($texte, $this->directionality, $OTLdata);
13222
13223 $this->SetAlpha($alpha);
13224
13225 $this->SetTColor($this->ConvertColor(0));
13226 $szfont = $fontsize;
13227 $loop = 0;
13228 $maxlen = (min($this->w, $this->h) ); // sets max length of text as 7/8 width/height of page
13229 while ($loop == 0) {
13230 $this->SetFont($this->watermark_font, "B", $szfont, false); // Don't output
13231 $offset = ((sin(deg2rad($angle))) * ($szfont / _MPDFK));
13232
13233 $strlen = $this->GetStringWidth($texte, true, $OTLdata, $textvar);
13234 if ($strlen > $maxlen - $offset)
13235 $szfont --;
13236 else
13237 $loop ++;
13238 }
13239
13240 $this->SetFont($this->watermark_font, "B", $szfont - 0.1, true, true); // Output The -0.1 is because SetFont above is not written to PDF
13241 // Repeating it will not output anything as mPDF thinks it is set
13242 $adj = ((cos(deg2rad($angle))) * ($strlen / 2));
13243 $opp = ((sin(deg2rad($angle))) * ($strlen / 2));
13244 $wx = ($this->w / 2) - $adj + $offset / 3;
13245 $wy = ($this->h / 2) + $opp;
13246 $this->Rotate($angle, $wx, $wy);
13247 $this->Text($wx, $wy, $texte, $OTLdata, $textvar);
13248 $this->Rotate(0);
13249 $this->SetTColor($this->ConvertColor(0));
13250
13251 $this->SetAlpha(1);
13252 }
13253
13254 function watermarkImg($src, $alpha = 0.2)
13255 {
13256 if ($this->PDFA || $this->PDFX) {
13257 throw new MpdfException('PDFA and PDFX do not permit transparency, so mPDF does not allow Watermarks!');
13258 }
13259 if ($this->watermarkImgBehind) {
13260 $this->watermarkImgAlpha = $this->SetAlpha($alpha, 'Normal', true);
13261 } else {
13262 $this->SetAlpha($alpha, $this->watermarkImgAlphaBlend);
13263 }
13264 $this->Image($src, 0, 0, 0, 0, '', '', true, true, true);
13265 if (!$this->watermarkImgBehind) {
13266 $this->SetAlpha(1);
13267 }
13268 }
13269
13270 /* -- END WATERMARK -- */
13271
13272 function Rotate($angle, $x = -1, $y = -1)
13273 {
13274 if ($x == -1)
13275 $x = $this->x;
13276 if ($y == -1)
13277 $y = $this->y;
13278 if ($this->angle != 0)
13279 $this->_out('Q');
13280 $this->angle = $angle;
13281 if ($angle != 0) {
13282 $angle*=M_PI / 180;
13283 $c = cos($angle);
13284 $s = sin($angle);
13285 $cx = $x * _MPDFK;
13286 $cy = ($this->h - $y) * _MPDFK;
13287 $this->_out(sprintf('q %.5F %.5F %.5F %.5F %.3F %.3F cm 1 0 0 1 %.3F %.3F cm', $c, $s, -$s, $c, $cx, $cy, -$cx, -$cy));
13288 }
13289 }
13290
13291 function CircularText($x, $y, $r, $text, $align = 'top', $fontfamily = '', $fontsize = 0, $fontstyle = '', $kerning = 120, $fontwidth = 100, $divider = '')
13292 {
13293 if (!class_exists('directw', false)) {
13294 include(_MPDF_PATH . 'classes/directw.php');
13295 }
13296 if (empty($this->directw)) {
13297 $this->directw = new directw($this);
13298 }
13299 $this->directw->CircularText($x, $y, $r, $text, $align, $fontfamily, $fontsize, $fontstyle, $kerning, $fontwidth, $divider);
13300 }
13301
13302 // From Invoice
13303 function RoundedRect($x, $y, $w, $h, $r, $style = '')
13304 {
13305 $hp = $this->h;
13306 if ($style == 'F')
13307 $op = 'f';
13308 elseif ($style == 'FD' or $style == 'DF')
13309 $op = 'B';
13310 else
13311 $op = 'S';
13312 $MyArc = 4 / 3 * (sqrt(2) - 1);
13313 $this->_out(sprintf('%.3F %.3F m', ($x + $r) * _MPDFK, ($hp - $y) * _MPDFK));
13314 $xc = $x + $w - $r;
13315 $yc = $y + $r;
13316 $this->_out(sprintf('%.3F %.3F l', $xc * _MPDFK, ($hp - $y) * _MPDFK));
13317
13318 $this->_Arc($xc + $r * $MyArc, $yc - $r, $xc + $r, $yc - $r * $MyArc, $xc + $r, $yc);
13319 $xc = $x + $w - $r;
13320 $yc = $y + $h - $r;
13321 $this->_out(sprintf('%.3F %.3F l', ($x + $w) * _MPDFK, ($hp - $yc) * _MPDFK));
13322 $this->_Arc($xc + $r, $yc + $r * $MyArc, $xc + $r * $MyArc, $yc + $r, $xc, $yc + $r);
13323 $xc = $x + $r;
13324 $yc = $y + $h - $r;
13325 $this->_out(sprintf('%.3F %.3F l', $xc * _MPDFK, ($hp - ($y + $h)) * _MPDFK));
13326 $this->_Arc($xc - $r * $MyArc, $yc + $r, $xc - $r, $yc + $r * $MyArc, $xc - $r, $yc);
13327 $xc = $x + $r;
13328 $yc = $y + $r;
13329 $this->_out(sprintf('%.3F %.3F l', ($x) * _MPDFK, ($hp - $yc) * _MPDFK));
13330 $this->_Arc($xc - $r, $yc - $r * $MyArc, $xc - $r * $MyArc, $yc - $r, $xc, $yc - $r);
13331 $this->_out($op);
13332 }
13333
13334 function _Arc($x1, $y1, $x2, $y2, $x3, $y3)
13335 {
13336 $h = $this->h;
13337 $this->_out(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $x1 * _MPDFK, ($h - $y1) * _MPDFK, $x2 * _MPDFK, ($h - $y2) * _MPDFK, $x3 * _MPDFK, ($h - $y3) * _MPDFK));
13338 }
13339
13340 //====================================================
13341
13342
13343
13344 /* -- DIRECTW -- */
13345 function Shaded_box($text, $font = '', $fontstyle = 'B', $szfont = '', $width = '70%', $style = 'DF', $radius = 2.5, $fill = '#FFFFFF', $color = '#000000', $pad = 2)
13346 {
13347 // F (shading - no line),S (line, no shading),DF (both)
13348 if (!class_exists('directw', false)) {
13349 include(_MPDF_PATH . 'classes/directw.php');
13350 }
13351 if (empty($this->directw)) {
13352 $this->directw = new directw($this);
13353 }
13354 $this->directw->Shaded_box($text, $font, $fontstyle, $szfont, $width, $style, $radius, $fill, $color, $pad);
13355 }
13356
13357 /* -- END DIRECTW -- */
13358
13359 function UTF8StringToArray($str, $addSubset = true)
13360 {
13361 $out = array();
13362 $len = strlen($str);
13363 for ($i = 0; $i < $len; $i++) {
13364 $uni = -1;
13365 $h = ord($str[$i]);
13366 if ($h <= 0x7F)
13367 $uni = $h;
13368 elseif ($h >= 0xC2) {
13369 if (($h <= 0xDF) && ($i < $len - 1))
13370 $uni = ($h & 0x1F) << 6 | (ord($str[++$i]) & 0x3F);
13371 elseif (($h <= 0xEF) && ($i < $len - 2))
13372 $uni = ($h & 0x0F) << 12 | (ord($str[++$i]) & 0x3F) << 6 | (ord($str[++$i]) & 0x3F);
13373 elseif (($h <= 0xF4) && ($i < $len - 3))
13374 $uni = ($h & 0x0F) << 18 | (ord($str[++$i]) & 0x3F) << 12 | (ord($str[++$i]) & 0x3F) << 6 | (ord($str[++$i]) & 0x3F);
13375 }
13376 if ($uni >= 0) {
13377 $out[] = $uni;
13378 if ($addSubset && isset($this->CurrentFont['subset'])) {
13379 $this->CurrentFont['subset'][$uni] = $uni;
13380 }
13381 }
13382 }
13383 return $out;
13384 }
13385
13386 //Convert utf-8 string to <HHHHHH> for Font Subsets
13387 function UTF8toSubset($str)
13388 {
13389 $ret = '<';
13390 //$str = preg_replace('/'.preg_quote($this->aliasNbPg,'/').'/', chr(7), $str ); // mPDF 6 deleted
13391 //$str = preg_replace('/'.preg_quote($this->aliasNbPgGp,'/').'/', chr(8), $str ); // mPDF 6 deleted
13392 $unicode = $this->UTF8StringToArray($str);
13393 $orig_fid = $this->CurrentFont['subsetfontids'][0];
13394 $last_fid = $this->CurrentFont['subsetfontids'][0];
13395 foreach ($unicode as $c) {
13396 /* // mPDF 6 deleted
13397 if ($c == 7 || $c == 8) {
13398 if ($orig_fid != $last_fid) {
13399 $ret .= '> Tj /F'.$orig_fid.' '.$this->FontSizePt.' Tf <';
13400 $last_fid = $orig_fid;
13401 }
13402 if ($c == 7) { $ret .= $this->aliasNbPgHex; }
13403 else { $ret .= $this->aliasNbPgGpHex; }
13404 continue;
13405 }
13406 */
13407 if (!$this->_charDefined($this->CurrentFont['cw'], $c)) {
13408 $c = 0;
13409 } // mPDF 6
13410 for ($i = 0; $i < 99; $i++) {
13411 // return c as decimal char
13412 $init = array_search($c, $this->CurrentFont['subsets'][$i]);
13413 if ($init !== false) {
13414 if ($this->CurrentFont['subsetfontids'][$i] != $last_fid) {
13415 $ret .= '> Tj /F' . $this->CurrentFont['subsetfontids'][$i] . ' ' . $this->FontSizePt . ' Tf <';
13416 $last_fid = $this->CurrentFont['subsetfontids'][$i];
13417 }
13418 $ret .= sprintf("%02s", strtoupper(dechex($init)));
13419 break;
13420 }
13421 // TrueType embedded SUBSETS
13422 elseif (count($this->CurrentFont['subsets'][$i]) < 255) {
13423 $n = count($this->CurrentFont['subsets'][$i]);
13424 $this->CurrentFont['subsets'][$i][$n] = $c;
13425 if ($this->CurrentFont['subsetfontids'][$i] != $last_fid) {
13426 $ret .= '> Tj /F' . $this->CurrentFont['subsetfontids'][$i] . ' ' . $this->FontSizePt . ' Tf <';
13427 $last_fid = $this->CurrentFont['subsetfontids'][$i];
13428 }
13429 $ret .= sprintf("%02s", strtoupper(dechex($n)));
13430 break;
13431 } elseif (!isset($this->CurrentFont['subsets'][($i + 1)])) {
13432 // TrueType embedded SUBSETS
13433 $this->CurrentFont['subsets'][($i + 1)] = array(0 => 0);
13434 $new_fid = count($this->fonts) + $this->extraFontSubsets + 1;
13435 $this->CurrentFont['subsetfontids'][($i + 1)] = $new_fid;
13436 $this->extraFontSubsets++;
13437 }
13438 }
13439 }
13440 $ret .= '>';
13441 if ($last_fid != $orig_fid) {
13442 $ret .= ' Tj /F' . $orig_fid . ' ' . $this->FontSizePt . ' Tf <> ';
13443 }
13444 return $ret;
13445 }
13446
13447 // Converts UTF-8 strings to UTF16-BE.
13448 function UTF8ToUTF16BE($str, $setbom = true)
13449 {
13450 if ($this->checkSIP && preg_match("/([\x{20000}-\x{2FFFF}])/u", $str)) {
13451 if (!in_array($this->currentfontfamily, array('gb', 'big5', 'sjis', 'uhc', 'gbB', 'big5B', 'sjisB', 'uhcB', 'gbI', 'big5I', 'sjisI', 'uhcI',
13452 'gbBI', 'big5BI', 'sjisBI', 'uhcBI'))) {
13453 $str = preg_replace("/[\x{20000}-\x{2FFFF}]/u", chr(0), $str);
13454 }
13455 }
13456 if ($this->checkSMP && preg_match("/([\x{10000}-\x{1FFFF}])/u", $str)) {
13457 $str = preg_replace("/[\x{10000}-\x{1FFFF}]/u", chr(0), $str);
13458 }
13459 $outstr = ""; // string to be returned
13460 if ($setbom) {
13461 $outstr .= "\xFE\xFF"; // Byte Order Mark (BOM)
13462 }
13463 $outstr .= mb_convert_encoding($str, 'UTF-16BE', 'UTF-8');
13464 return $outstr;
13465 }
13466
13467 // ====================================================
13468 // ====================================================
13469 /* -- CJK-FONTS -- */
13470
13471 // from class PDF_Chinese CJK EXTENSIONS
13472 function AddCIDFont($family, $style, $name, &$cw, $CMap, $registry, $desc)
13473 {
13474 $fontkey = strtolower($family) . strtoupper($style);
13475 if (isset($this->fonts[$fontkey]))
13476 throw new MpdfException("Font already added: $family $style");
13477 $i = count($this->fonts) + $this->extraFontSubsets + 1;
13478 $name = str_replace(' ', '', $name);
13479 if ($family == 'sjis') {
13480 $up = -120;
13481 } else {
13482 $up = -130;
13483 }
13484 // ? 'up' and 'ut' do not seem to be referenced anywhere
13485 $this->fonts[$fontkey] = array('i' => $i, 'type' => 'Type0', 'name' => $name, 'up' => $up, 'ut' => 40, 'cw' => $cw, 'CMap' => $CMap, 'registry' => $registry, 'MissingWidth' => 1000, 'desc' => $desc);
13486 }
13487
13488 function AddCJKFont($family)
13489 {
13490
13491 if ($this->PDFA || $this->PDFX) {
13492 throw new MpdfException("Adobe CJK fonts cannot be embedded in mPDF (required for PDFA1-b and PDFX/1-a).");
13493 }
13494 if ($family == 'big5') {
13495 $this->AddBig5Font();
13496 } elseif ($family == 'gb') {
13497 $this->AddGBFont();
13498 } elseif ($family == 'sjis') {
13499 $this->AddSJISFont();
13500 } elseif ($family == 'uhc') {
13501 $this->AddUHCFont();
13502 }
13503 }
13504
13505 function AddBig5Font()
13506 {
13507 //Add Big5 font with proportional Latin
13508 $family = 'big5';
13509 $name = 'MSungStd-Light-Acro';
13510 $cw = $this->Big5_widths;
13511 $CMap = 'UniCNS-UTF16-H';
13512 $registry = array('ordering' => 'CNS1', 'supplement' => 4);
13513 $desc = array(
13514 'Ascent' => 880,
13515 'Descent' => -120,
13516 'CapHeight' => 880,
13517 'Flags' => 6,
13518 'FontBBox' => '[-160 -249 1015 1071]',
13519 'ItalicAngle' => 0,
13520 'StemV' => 93,
13521 );
13522 $this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
13523 $this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
13524 $this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
13525 $this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
13526 }
13527
13528 function AddGBFont()
13529 {
13530 //Add GB font with proportional Latin
13531 $family = 'gb';
13532 $name = 'STSongStd-Light-Acro';
13533 $cw = $this->GB_widths;
13534 $CMap = 'UniGB-UTF16-H';
13535 $registry = array('ordering' => 'GB1', 'supplement' => 4);
13536 $desc = array(
13537 'Ascent' => 880,
13538 'Descent' => -120,
13539 'CapHeight' => 737,
13540 'Flags' => 6,
13541 'FontBBox' => '[-25 -254 1000 880]',
13542 'ItalicAngle' => 0,
13543 'StemV' => 58,
13544 'Style' => '<< /Panose <000000000400000000000000> >>',
13545 );
13546 $this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
13547 $this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
13548 $this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
13549 $this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
13550 }
13551
13552 function AddSJISFont()
13553 {
13554 //Add SJIS font with proportional Latin
13555 $family = 'sjis';
13556 $name = 'KozMinPro-Regular-Acro';
13557 $cw = $this->SJIS_widths;
13558 $CMap = 'UniJIS-UTF16-H';
13559 $registry = array('ordering' => 'Japan1', 'supplement' => 5);
13560 $desc = array(
13561 'Ascent' => 880,
13562 'Descent' => -120,
13563 'CapHeight' => 740,
13564 'Flags' => 6,
13565 'FontBBox' => '[-195 -272 1110 1075]',
13566 'ItalicAngle' => 0,
13567 'StemV' => 86,
13568 'XHeight' => 502,
13569 );
13570 $this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
13571 $this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
13572 $this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
13573 $this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
13574 }
13575
13576 function AddUHCFont()
13577 {
13578 //Add UHC font with proportional Latin
13579 $family = 'uhc';
13580 $name = 'HYSMyeongJoStd-Medium-Acro';
13581 $cw = $this->UHC_widths;
13582 $CMap = 'UniKS-UTF16-H';
13583 $registry = array('ordering' => 'Korea1', 'supplement' => 2);
13584 $desc = array(
13585 'Ascent' => 880,
13586 'Descent' => -120,
13587 'CapHeight' => 720,
13588 'Flags' => 6,
13589 'FontBBox' => '[-28 -148 1001 880]',
13590 'ItalicAngle' => 0,
13591 'StemV' => 60,
13592 'Style' => '<< /Panose <000000000600000000000000> >>',
13593 );
13594 $this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
13595 $this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
13596 $this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
13597 $this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
13598 }
13599
13600 /* -- END CJK-FONTS -- */
13601
13602 //////////////////////////////////////////////////////////////////////////////
13603 //////////////////////////////////////////////////////////////////////////////
13604 //////////////////////////////////////////////////////////////////////////////
13605 //////////////////////////////////////////////////////////////////////////////
13606 //////////////////////////////////////////////////////////////////////////////
13607 //////////////////////////////////////////////////////////////////////////////
13608 //////////////////////////////////////////////////////////////////////////////
13609
13610 function SetDefaultFont($font)
13611 {
13612 // Disallow embedded fonts to be used as defaults in PDFA
13613 if ($this->PDFA || $this->PDFX) {
13614 if (strtolower($font) == 'ctimes') {
13615 $font = 'serif';
13616 }
13617 if (strtolower($font) == 'ccourier') {
13618 $font = 'monospace';
13619 }
13620 if (strtolower($font) == 'chelvetica') {
13621 $font = 'sans-serif';
13622 }
13623 }
13624 $font = $this->SetFont($font); // returns substituted font if necessary
13625 $this->default_font = $font;
13626 $this->original_default_font = $font;
13627 if (!$this->watermark_font) {
13628 $this->watermark_font = $font;
13629 } // *WATERMARK*
13630 $this->defaultCSS['BODY']['FONT-FAMILY'] = $font;
13631 $this->cssmgr->CSS['BODY']['FONT-FAMILY'] = $font;
13632 }
13633
13634 function SetDefaultFontSize($fontsize)
13635 {
13636 $this->default_font_size = $fontsize;
13637 $this->original_default_font_size = $fontsize;
13638 $this->SetFontSize($fontsize);
13639 $this->defaultCSS['BODY']['FONT-SIZE'] = $fontsize . 'pt';
13640 $this->cssmgr->CSS['BODY']['FONT-SIZE'] = $fontsize . 'pt';
13641 }
13642
13643 function SetDefaultBodyCSS($prop, $val)
13644 {
13645 if ($prop) {
13646 $this->defaultCSS['BODY'][strtoupper($prop)] = $val;
13647 $this->cssmgr->CSS['BODY'][strtoupper($prop)] = $val;
13648 }
13649 }
13650
13651 function SetDirectionality($dir = 'ltr')
13652 {
13653 /* -- OTL -- */
13654 if (strtolower($dir) == 'rtl') {
13655 if ($this->directionality != 'rtl') {
13656 // Swop L/R Margins so page 1 RTL is an 'even' page
13657 $tmp = $this->DeflMargin;
13658 $this->DeflMargin = $this->DefrMargin;
13659 $this->DefrMargin = $tmp;
13660 $this->orig_lMargin = $this->DeflMargin;
13661 $this->orig_rMargin = $this->DefrMargin;
13662
13663 $this->SetMargins($this->DeflMargin, $this->DefrMargin, $this->tMargin);
13664 }
13665 $this->directionality = 'rtl';
13666 $this->defaultAlign = 'R';
13667 $this->defaultTableAlign = 'R';
13668 } else {
13669 /* -- END OTL -- */
13670 $this->directionality = 'ltr';
13671 $this->defaultAlign = 'L';
13672 $this->defaultTableAlign = 'L';
13673 } // *OTL*
13674 $this->cssmgr->CSS['BODY']['DIRECTION'] = $this->directionality;
13675 }
13676
13677 // Return either a number (factor) - based on current set fontsize (if % or em) - or exact lineheight (with 'mm' after it)
13678 function fixLineheight($v)
13679 {
13680 $lh = false;
13681 if (preg_match('/^[0-9\.,]*$/', $v) && $v >= 0) {
13682 return ($v + 0);
13683 } elseif (strtoupper($v) == 'NORMAL' || $v == 'N') {
13684 return 'N'; // mPDF 6
13685 } else {
13686 $tlh = $this->ConvertSize($v, $this->FontSize, $this->FontSize, true);
13687 if ($tlh) {
13688 return ($tlh . 'mm');
13689 }
13690 }
13691 return $this->normalLineheight;
13692 }
13693
13694 function _getNormalLineheight($desc = false)
13695 {
13696 if (!$desc) {
13697 $desc = $this->CurrentFont['desc'];
13698 }
13699 if (!isset($desc['Leading'])) {
13700 $desc['Leading'] = 0;
13701 }
13702 if ($this->useFixedNormalLineHeight) {
13703 $lh = $this->normalLineheight;
13704 } elseif (isset($desc['Ascent']) && $desc['Ascent']) {
13705 $lh = ($this->adjustFontDescLineheight * ($desc['Ascent'] - $desc['Descent'] + $desc['Leading']) / 1000);
13706 } else {
13707 $lh = $this->normalLineheight;
13708 }
13709 return $lh;
13710 }
13711
13712 // Set a (fixed) lineheight to an actual value - either to named fontsize(pts) or default
13713 function SetLineHeight($FontPt = '', $lh = '')
13714 {
13715 if (!$FontPt) {
13716 $FontPt = $this->FontSizePt;
13717 }
13718 $fs = $FontPt / _MPDFK;
13719 $this->lineheight = $this->_computeLineheight($lh, $fs);
13720 }
13721
13722 function _computeLineheight($lh, $fs = '')
13723 {
13724 if ($this->shrin_k > 1) {
13725 $k = $this->shrin_k;
13726 } else {
13727 $k = 1;
13728 }
13729 if (!$fs) {
13730 $fs = $this->FontSize;
13731 }
13732 if ($lh == 'N') {
13733 $lh = $this->_getNormalLineheight();
13734 }
13735 if (preg_match('/mm/', $lh)) {
13736 return (($lh + 0.0) / $k); // convert to number
13737 } elseif ($lh > 0) {
13738 return ($fs * $lh);
13739 }
13740 return ($fs * $this->normalLineheight);
13741 }
13742
13743 function _setLineYpos(&$fontsize, &$fontdesc, &$CSSlineheight, $blockYpos = false)
13744 {
13745 $ypos['glyphYorigin'] = 0;
13746 $ypos['baseline-shift'] = 0;
13747 $linegap = 0;
13748 $leading = 0;
13749
13750 if (isset($fontdesc['Ascent']) && $fontdesc['Ascent'] && !$this->useFixedTextBaseline) {
13751 // Fontsize uses font metrics - this method seems to produce results compatible with browsers (except IE9)
13752 $ypos['boxtop'] = $fontdesc['Ascent'] / 1000 * $fontsize;
13753 $ypos['boxbottom'] = $fontdesc['Descent'] / 1000 * $fontsize;
13754 if (isset($fontdesc['Leading'])) {
13755 $linegap = $fontdesc['Leading'] / 1000 * $fontsize;
13756 }
13757 }
13758 // Default if not set - uses baselineC
13759 else {
13760 $ypos['boxtop'] = (0.5 + $this->baselineC) * $fontsize;
13761 $ypos['boxbottom'] = -(0.5 - $this->baselineC) * $fontsize;
13762 }
13763 $fontheight = $ypos['boxtop'] - $ypos['boxbottom'];
13764
13765 if ($this->shrin_k > 1) {
13766 $shrin_k = $this->shrin_k;
13767 } else {
13768 $shrin_k = 1;
13769 }
13770
13771 $leading = 0;
13772 if ($CSSlineheight == 'N') {
13773 $lh = $this->_getNormalLineheight($fontdesc);
13774 $lineheight = ($fontsize * $lh);
13775 $leading += $linegap; // specified in hhea or sTypo in OpenType tables ****************************************
13776 } elseif (preg_match('/mm/', $CSSlineheight)) {
13777 $lineheight = (($CSSlineheight + 0.0) / $shrin_k);
13778 } // convert to number
13779 // ??? If lineheight is a factor e.g. 1.3 ?? use factor x 1em or ? use 'normal' lineheight * factor ******************************
13780 // Could depend on value for $text_height - a draft CSS value as set above for now
13781 elseif ($CSSlineheight > 0) {
13782 $lineheight = ($fontsize * $CSSlineheight);
13783 } else {
13784 $lineheight = ($fontsize * $this->normalLineheight);
13785 }
13786
13787 // In general, calculate the "leading" - the difference between the fontheight and the lineheight
13788 // and add half to the top and half to the bottom. BUT
13789 // If an inline element has a font-size less than the block element, and the line-height is set as an em or % value
13790 // it will add too much leading below the font and expand the height of the line - so just use the block element exttop/extbottom:
13791 if (preg_match('/mm/', $CSSlineheight) && $ypos['boxtop'] < $blockYpos['boxtop'] && $ypos['boxbottom'] > $blockYpos['boxbottom']) {
13792 $ypos['exttop'] = $blockYpos['exttop'];
13793 $ypos['extbottom'] = $blockYpos['extbottom'];
13794 } else {
13795 $leading += ($lineheight - $fontheight);
13796
13797 $ypos['exttop'] = $ypos['boxtop'] + $leading / 2;
13798 $ypos['extbottom'] = $ypos['boxbottom'] - $leading / 2;
13799 }
13800
13801
13802 // TEMP ONLY FOR DEBUGGING *********************************
13803 //$ypos['lineheight'] = $lineheight;
13804 //$ypos['fontheight'] = $fontheight;
13805 //$ypos['leading'] = $leading;
13806
13807 return $ypos;
13808 }
13809
13810 /* Called from WriteFlowingBlock() and finishFlowingBlock()
13811 Determines the line hieght and glyph/writing position
13812 for each element in the line to be written */
13813
13814 function _setInlineBlockHeights(&$lineBox, &$stackHeight, &$content, &$font, $is_table)
13815 {
13816 if ($this->shrin_k > 1) {
13817 $shrin_k = $this->shrin_k;
13818 } else {
13819 $shrin_k = 1;
13820 }
13821
13822 $ypos = array();
13823 $bordypos = array();
13824 $bgypos = array();
13825
13826 if ($is_table) {
13827 // FOR TABLE
13828 $fontsize = $this->FontSize;
13829 $fontkey = $this->FontFamily . $this->FontStyle;
13830 $fontdesc = $this->fonts[$fontkey]['desc'];
13831 $CSSlineheight = $this->cellLineHeight;
13832 $line_stacking_strategy = $this->cellLineStackingStrategy; // inline-line-height [default] | block-line-height | max-height | grid-height
13833 $line_stacking_shift = $this->cellLineStackingShift; // consider-shifts [default] | disregard-shifts
13834 } else {
13835 // FOR BLOCK FONT
13836 $fontsize = $this->blk[$this->blklvl]['InlineProperties']['size'];
13837 $fontkey = $this->blk[$this->blklvl]['InlineProperties']['family'] . $this->blk[$this->blklvl]['InlineProperties']['style'];
13838 $fontdesc = $this->fonts[$fontkey]['desc'];
13839 $CSSlineheight = $this->blk[$this->blklvl]['line_height'];
13840 // inline-line-height | block-line-height | max-height | grid-height
13841 $line_stacking_strategy = (isset($this->blk[$this->blklvl]['line_stacking_strategy']) ? $this->blk[$this->blklvl]['line_stacking_strategy'] : 'inline-line-height');
13842 // consider-shifts | disregard-shifts
13843 $line_stacking_shift = (isset($this->blk[$this->blklvl]['line_stacking_shift']) ? $this->blk[$this->blklvl]['line_stacking_shift'] : 'consider-shifts');
13844 }
13845 $boxLineHeight = $this->_computeLineheight($CSSlineheight, $fontsize);
13846
13847
13848 // First, set a "strut" using block font at index $lineBox[-1]
13849 $ypos[-1] = $this->_setLineYpos($fontsize, $fontdesc, $CSSlineheight);
13850
13851 // for the block element - always taking the block EXTENDED progression including leading - which may be negative
13852 if ($line_stacking_strategy == 'block-line-height') {
13853 $topy = $ypos[-1]['exttop'];
13854 $bottomy = $ypos[-1]['extbottom'];
13855 } else {
13856 $topy = 0;
13857 $bottomy = 0;
13858 }
13859
13860 // Get text-middle for aligning images/objects
13861 $midpoint = $ypos[-1]['boxtop'] - (($ypos[-1]['boxtop'] - $ypos[-1]['boxbottom']) / 2);
13862
13863 // for images / inline objects / replaced elements
13864 $mta = 0; // Maximum top-aligned
13865 $mba = 0; // Maximum bottom-aligned
13866 foreach ($content as $k => $chunk) {
13867 if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]['type'] == 'listmarker') {
13868 $ypos[$k] = $ypos[-1];
13869 // UPDATE Maximums
13870 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
13871 if ($ypos[$k]['boxtop'] > $topy)
13872 $topy = $ypos[$k]['boxtop'];
13873 if ($ypos[$k]['boxbottom'] < $bottomy)
13874 $bottomy = $ypos[$k]['boxbottom'];
13875 }
13876 else {
13877 if ($ypos[$k]['exttop'] > $topy)
13878 $topy = $ypos[$k]['exttop'];
13879 if ($ypos[$k]['extbottom'] < $bottomy)
13880 $bottomy = $ypos[$k]['extbottom'];
13881 }
13882 }
13883 elseif (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
13884 $fontsize = $font[$k]['size'];
13885 $fontdesc = $font[$k]['curr']['desc'];
13886 $lh = 1;
13887 $ypos[$k] = $this->_setLineYpos($fontsize, $fontdesc, $lh, $ypos[-1]); // Lineheight=1 fixed
13888 } elseif (isset($this->objectbuffer[$k])) {
13889 $oh = $this->objectbuffer[$k]['OUTER-HEIGHT'];
13890 $va = $this->objectbuffer[$k]['vertical-align'];
13891
13892 if ($va == 'BS') { // (BASELINE default)
13893 if ($oh > $topy)
13894 $topy = $oh;
13895 }
13896 elseif ($va == 'M') {
13897 if (($midpoint + $oh / 2) > $topy)
13898 $topy = $midpoint + $oh / 2;
13899 if (($midpoint - $oh / 2) < $bottomy)
13900 $bottomy = $midpoint - $oh / 2;
13901 }
13902 elseif ($va == 'TT') {
13903 if (($ypos[-1]['boxtop'] - $oh) < $bottomy) {
13904 $bottomy = $ypos[-1]['boxtop'] - $oh;
13905 $topy = max($topy, $ypos[-1]['boxtop']);
13906 }
13907 } elseif ($va == 'TB') {
13908 if (($ypos[-1]['boxbottom'] + $oh) > $topy) {
13909 $topy = $ypos[-1]['boxbottom'] + $oh;
13910 $bottomy = min($bottomy, $ypos[-1]['boxbottom']);
13911 }
13912 } elseif ($va == 'T') {
13913 if ($oh > $mta)
13914 $mta = $oh;
13915 }
13916 elseif ($va == 'B') {
13917 if ($oh > $mba)
13918 $mba = $oh;
13919 }
13920 }
13921 elseif ($content[$k] || $content[$k] === '0') {
13922 // FOR FLOWING BLOCK
13923 $fontsize = $font[$k]['size'];
13924 $fontdesc = $font[$k]['curr']['desc'];
13925 // In future could set CSS line-height from inline elements; for now, use block level:
13926 $ypos[$k] = $this->_setLineYpos($fontsize, $fontdesc, $CSSlineheight, $ypos[-1]);
13927
13928 if (isset($font[$k]['textparam']['text-baseline']) && $font[$k]['textparam']['text-baseline'] != 0) {
13929 $ypos[$k]['baseline-shift'] = $font[$k]['textparam']['text-baseline'];
13930 }
13931
13932 // DO ALIGNMENT FOR BASELINES *******************
13933 // Until most fonts have OpenType BASE tables, this won't work
13934 // $ypos[$k] compared to $ypos[-1] or $ypos[$k-1] using $dominant_baseline and $baseline_table
13935 // UPDATE Maximums
13936 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
13937 if ($line_stacking_shift == 'disregard-shifts') {
13938 if ($ypos[$k]['boxtop'] > $topy)
13939 $topy = $ypos[$k]['boxtop'];
13940 if ($ypos[$k]['boxbottom'] < $bottomy)
13941 $bottomy = $ypos[$k]['boxbottom'];
13942 }
13943 else {
13944 if (($ypos[$k]['boxtop'] + $ypos[$k]['baseline-shift']) > $topy)
13945 $topy = $ypos[$k]['boxtop'] + $ypos[$k]['baseline-shift'];
13946 if (($ypos[$k]['boxbottom'] + $ypos[$k]['baseline-shift']) < $bottomy)
13947 $bottomy = $ypos[$k]['boxbottom'] + $ypos[$k]['baseline-shift'];
13948 }
13949 }
13950 else {
13951 if ($line_stacking_shift == 'disregard-shifts') {
13952 if ($ypos[$k]['exttop'] > $topy)
13953 $topy = $ypos[$k]['exttop'];
13954 if ($ypos[$k]['extbottom'] < $bottomy)
13955 $bottomy = $ypos[$k]['extbottom'];
13956 }
13957 else {
13958 if (($ypos[$k]['exttop'] + $ypos[$k]['baseline-shift']) > $topy)
13959 $topy = $ypos[$k]['exttop'] + $ypos[$k]['baseline-shift'];
13960 if (($ypos[$k]['extbottom'] + $ypos[$k]['baseline-shift']) < $bottomy)
13961 $bottomy = $ypos[$k]['extbottom'] + $ypos[$k]['baseline-shift'];
13962 }
13963 }
13964
13965 // If BORDER set on inline element
13966 if (isset($font[$k]['bord']) && $font[$k]['bord']) {
13967 $bordfontsize = $font[$k]['textparam']['bord-decoration']['fontsize'] / $shrin_k;
13968 $bordfontkey = $font[$k]['textparam']['bord-decoration']['fontkey'];
13969 if ($bordfontkey != $fontkey || $bordfontsize != $fontsize || isset($font[$k]['textparam']['bord-decoration']['baseline'])) {
13970 $bordfontdesc = $this->fonts[$bordfontkey]['desc'];
13971 $bordypos[$k] = $this->_setLineYpos($bordfontsize, $bordfontdesc, $CSSlineheight, $ypos[-1]);
13972 if (isset($font[$k]['textparam']['bord-decoration']['baseline']) && $font[$k]['textparam']['bord-decoration']['baseline'] != 0) {
13973 $bordypos[$k]['baseline-shift'] = $font[$k]['textparam']['bord-decoration']['baseline'] / $shrin_k;
13974 }
13975 }
13976 }
13977 // If BACKGROUND set on inline element
13978 if (isset($font[$k]['spanbgcolor']) && $font[$k]['spanbgcolor']) {
13979 $bgfontsize = $font[$k]['textparam']['bg-decoration']['fontsize'] / $shrin_k;
13980 $bgfontkey = $font[$k]['textparam']['bg-decoration']['fontkey'];
13981 if ($bgfontkey != $fontkey || $bgfontsize != $fontsize || isset($font[$k]['textparam']['bg-decoration']['baseline'])) {
13982 $bgfontdesc = $this->fonts[$bgfontkey]['desc'];
13983 $bgypos[$k] = $this->_setLineYpos($bgfontsize, $bgfontdesc, $CSSlineheight, $ypos[-1]);
13984 if (isset($font[$k]['textparam']['bg-decoration']['baseline']) && $font[$k]['textparam']['bg-decoration']['baseline'] != 0) {
13985 $bgypos[$k]['baseline-shift'] = $font[$k]['textparam']['bg-decoration']['baseline'] / $shrin_k;
13986 }
13987 }
13988 }
13989 }
13990 }
13991
13992
13993 // TOP or BOTTOM aligned images
13994 if ($mta > ($topy - $bottomy)) {
13995 if (($topy - $mta) < $bottomy)
13996 $bottomy = $topy - $mta;
13997 }
13998 if ($mba > ($topy - $bottomy)) {
13999 if (($bottomy + $mba) > $topy)
14000 $topy = $bottomy + $mba;
14001 }
14002
14003 if ($line_stacking_strategy == 'block-line-height') { // fixed height set by block element (whether present or not)
14004 $topy = $ypos[-1]['exttop'];
14005 $bottomy = $ypos[-1]['extbottom'];
14006 }
14007
14008 $inclusiveHeight = $topy - $bottomy;
14009
14010 // SET $stackHeight taking note of line_stacking_strategy
14011 // NB inclusive height already takes account of need to consider block progression height (excludes leading set by lineheight)
14012 // or extended block progression height (includes leading set by lineheight)
14013 if ($line_stacking_strategy == 'block-line-height') { // fixed = extended block progression height of block element
14014 $stackHeight = $boxLineHeight;
14015 } elseif ($line_stacking_strategy == 'max-height') { // smallest height which includes extended block progression height of block element
14016 // and block progression heights of inline elements (NOT extended)
14017 $stackHeight = $inclusiveHeight;
14018 } elseif ($line_stacking_strategy == 'grid-height') { // smallest multiple of block element lineheight to include
14019 // block progression heights of inline elements (NOT extended)
14020 $stackHeight = $boxLineHeight;
14021 while ($stackHeight < $inclusiveHeight) {
14022 $stackHeight += $boxLineHeight;
14023 }
14024 } else { // 'inline-line-height' = default // smallest height which includes extended block progression height of block element
14025 // AND extended block progression heights of inline elements
14026 $stackHeight = $inclusiveHeight;
14027 }
14028
14029 $diff = $stackHeight - $inclusiveHeight;
14030 $topy += $diff / 2;
14031 $bottomy -= $diff / 2;
14032
14033 // ADJUST $ypos => lineBox using $stackHeight; lineBox are all offsets from the top of stackHeight in mm
14034 // and SET IMAGE OFFSETS
14035 $lineBox[-1]['boxtop'] = $topy - $ypos[-1]['boxtop'];
14036 $lineBox[-1]['boxbottom'] = $topy - $ypos[-1]['boxbottom'];
14037 // $lineBox[-1]['exttop'] = $topy - $ypos[-1]['exttop'];
14038 // $lineBox[-1]['extbottom'] = $topy - $ypos[-1]['extbottom'];
14039 $lineBox[-1]['glyphYorigin'] = $topy - $ypos[-1]['glyphYorigin'];
14040 $lineBox[-1]['baseline-shift'] = $ypos[-1]['baseline-shift'];
14041
14042 $midpoint = $lineBox[-1]['boxbottom'] - (($lineBox[-1]['boxbottom'] - $lineBox[-1]['boxtop']) / 2);
14043
14044 foreach ($content as $k => $chunk) {
14045 if (isset($this->objectbuffer[$k])) {
14046 $oh = $this->objectbuffer[$k]['OUTER-HEIGHT'];
14047 // LIST MARKERS
14048 if ($this->objectbuffer[$k]['type'] == 'listmarker') {
14049 $oh = $fontsize;
14050 } elseif ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
14051 $oh = $font[$k]['size']; // == $this->objectbuffer[$k]['fontsize']/_MPDFK;
14052 $lineBox[$k]['boxtop'] = $topy - $ypos[$k]['boxtop'];
14053 $lineBox[$k]['boxbottom'] = $topy - $ypos[$k]['boxbottom'];
14054 $lineBox[$k]['glyphYorigin'] = $topy - $ypos[$k]['glyphYorigin'];
14055 $lineBox[$k]['baseline-shift'] = 0;
14056 // continue;
14057 }
14058 $va = $this->objectbuffer[$k]['vertical-align']; // = $objattr['vertical-align'] = set as M,T,B,S
14059
14060 if ($va == 'BS') { // (BASELINE default)
14061 $lineBox[$k]['top'] = $lineBox[-1]['glyphYorigin'] - $oh;
14062 } elseif ($va == 'M') {
14063 $lineBox[$k]['top'] = $midpoint - $oh / 2;
14064 } elseif ($va == 'TT') {
14065 $lineBox[$k]['top'] = $lineBox[-1]['boxtop'];
14066 } elseif ($va == 'TB') {
14067 $lineBox[$k]['top'] = $lineBox[-1]['boxbottom'] - $oh;
14068 } elseif ($va == 'T') {
14069 $lineBox[$k]['top'] = 0;
14070 } elseif ($va == 'B') {
14071 $lineBox[$k]['top'] = $stackHeight - $oh;
14072 }
14073 } elseif ($content[$k] || $content[$k] === '0') {
14074 $lineBox[$k]['boxtop'] = $topy - $ypos[$k]['boxtop'];
14075 $lineBox[$k]['boxbottom'] = $topy - $ypos[$k]['boxbottom'];
14076 // $lineBox[$k]['exttop'] = $topy - $ypos[$k]['exttop'];
14077 // $lineBox[$k]['extbottom'] = $topy - $ypos[$k]['extbottom'];
14078 $lineBox[$k]['glyphYorigin'] = $topy - $ypos[$k]['glyphYorigin'];
14079 $lineBox[$k]['baseline-shift'] = $ypos[$k]['baseline-shift'];
14080 if (isset($bordypos[$k]['boxtop'])) {
14081 $lineBox[$k]['border-boxtop'] = $topy - $bordypos[$k]['boxtop'];
14082 $lineBox[$k]['border-boxbottom'] = $topy - $bordypos[$k]['boxbottom'];
14083 $lineBox[$k]['border-baseline-shift'] = $bordypos[$k]['baseline-shift'];
14084 }
14085 if (isset($bgypos[$k]['boxtop'])) {
14086 $lineBox[$k]['background-boxtop'] = $topy - $bgypos[$k]['boxtop'];
14087 $lineBox[$k]['background-boxbottom'] = $topy - $bgypos[$k]['boxbottom'];
14088 $lineBox[$k]['background-baseline-shift'] = $bgypos[$k]['baseline-shift'];
14089 }
14090 }
14091 }
14092 }
14093
14094 function SetBasePath($str = '')
14095 {
14096 if (isset($_SERVER['HTTP_HOST'])) {
14097 $host = $_SERVER['HTTP_HOST'];
14098 } elseif (isset($_SERVER['SERVER_NAME'])) {
14099 $host = $_SERVER['SERVER_NAME'];
14100 } else {
14101 $host = '';
14102 }
14103 if (!$str) {
14104 if ($_SERVER['SCRIPT_NAME']) {
14105 $currentPath = dirname($_SERVER['SCRIPT_NAME']);
14106 } else {
14107 $currentPath = dirname($_SERVER['PHP_SELF']);
14108 }
14109 $currentPath = str_replace("\\", "/", $currentPath);
14110 if ($currentPath == '/') {
14111 $currentPath = '';
14112 }
14113 if ($host) { // mPDF 6
14114 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']) {
14115 $currpath = 'https://' . $host . $currentPath . '/';
14116 } else {
14117 $currpath = 'http://' . $host . $currentPath . '/';
14118 }
14119 } else {
14120 $currpath = '';
14121 }
14122 $this->basepath = $currpath;
14123 $this->basepathIsLocal = true;
14124 return;
14125 }
14126 $str = preg_replace('/\?.*/', '', $str);
14127 if (!preg_match('/(http|https|ftp):\/\/.*\//i', $str)) {
14128 $str .= '/';
14129 }
14130 $str .= 'xxx'; // in case $str ends in / e.g. http://www.bbc.co.uk/
14131 $this->basepath = dirname($str) . "/"; // returns e.g. e.g. http://www.google.com/dir1/dir2/dir3/
14132 $this->basepath = str_replace("\\", "/", $this->basepath); //If on Windows
14133 $tr = parse_url($this->basepath);
14134 if (isset($tr['host']) && ($tr['host'] == $host)) {
14135 $this->basepathIsLocal = true;
14136 } else {
14137 $this->basepathIsLocal = false;
14138 }
14139 }
14140
14141 function GetFullPath(&$path, $basepath = '')
14142 {
14143 // When parsing CSS need to pass temporary basepath - so links are relative to current stylesheet
14144 if (!$basepath) {
14145 $basepath = $this->basepath;
14146 }
14147 //Fix path value
14148 $path = str_replace("\\", "/", $path); //If on Windows
14149 // mPDF 5.7.2
14150 if (substr($path, 0, 2) == "//") {
14151 $tr = parse_url($basepath);
14152 $path = $tr['scheme'] . ':' . $path; // mPDF 6
14153 }
14154
14155 $regexp = '|^./|'; // Inadvertently corrects "./path/etc" and "//www.domain.com/etc"
14156 $path = preg_replace($regexp, '', $path);
14157
14158 if (substr($path, 0, 1) == '#') {
14159 return;
14160 }
14161 if (preg_match('@^(mailto|tel|fax):.*@i', $path)) {
14162 return;
14163 }
14164 if (substr($path, 0, 3) == "../") { //It is a Relative Link
14165 $backtrackamount = substr_count($path, "../");
14166 $maxbacktrack = substr_count($basepath, "/") - 3;
14167 $filepath = str_replace("../", '', $path);
14168 $path = $basepath;
14169 //If it is an invalid relative link, then make it go to directory root
14170 if ($backtrackamount > $maxbacktrack)
14171 $backtrackamount = $maxbacktrack;
14172 //Backtrack some directories
14173 for ($i = 0; $i < $backtrackamount + 1; $i++)
14174 $path = substr($path, 0, strrpos($path, "/"));
14175 $path = $path . "/" . $filepath; //Make it an absolute path
14176 }
14177 elseif (strpos($path, ":/") === false || strpos($path, ":/") > 10) { //It is a Local Link
14178 if (substr($path, 0, 1) == "/") {
14179 $tr = parse_url($basepath);
14180 // mPDF 5.7.2
14181 $root = '';
14182 if (!empty($tr['scheme'])) {
14183 $root .= $tr['scheme'] . '://';
14184 }
14185 $root .= isset($tr['host']) ? $tr['host'] : '';
14186 $root .= ((isset($tr['port']) && $tr['port']) ? (':' . $tr['port']) : ''); // mPDF 5.7.3
14187 $path = $root . $path;
14188 } else {
14189 $path = $basepath . $path;
14190 }
14191 }
14192 //Do nothing if it is an Absolute Link
14193 }
14194
14195 // Used for external CSS files
14196 function _get_file($path)
14197 {
14198 // If local file try using local path (? quicker, but also allowed even if allow_url_fopen false)
14199 $contents = '';
14200 // mPDF 5.7.3
14201 if (strpos($path, "//") === false) {
14202 $path = preg_replace('/\.css\?.*$/', '.css', $path);
14203 }
14204 $contents = @file_get_contents($path);
14205 if ($contents) {
14206 return $contents;
14207 }
14208 if ($this->basepathIsLocal) {
14209 $tr = parse_url($path);
14210 $lp = getenv("SCRIPT_NAME");
14211 $ap = realpath($lp);
14212 $ap = str_replace("\\", "/", $ap);
14213 $docroot = substr($ap, 0, strpos($ap, $lp));
14214 // WriteHTML parses all paths to full URLs; may be local file name
14215 if ($tr['scheme'] && $tr['host'] && $_SERVER["DOCUMENT_ROOT"]) {
14216 $localpath = $_SERVER["DOCUMENT_ROOT"] . $tr['path'];
14217 }
14218 // DOCUMENT_ROOT is not returned on IIS
14219 elseif ($docroot) {
14220 $localpath = $docroot . $tr['path'];
14221 } else {
14222 $localpath = $path;
14223 }
14224 $contents = @file_get_contents($localpath);
14225 }
14226 // if not use full URL
14227 elseif (!$contents && !ini_get('allow_url_fopen') && function_exists("curl_init")) {
14228 $ch = curl_init($path);
14229 curl_setopt($ch, CURLOPT_HEADER, 0);
14230 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
14231 $contents = curl_exec($ch);
14232 curl_close($ch);
14233 }
14234 return $contents;
14235 }
14236
14237 function docPageNum($num = 0, $extras = false)
14238 {
14239 if ($num < 1) {
14240 $num = $this->page;
14241 }
14242 $type = $this->defaultPageNumStyle; // set default Page Number Style
14243 $ppgno = $num;
14244 $suppress = 0;
14245 $offset = 0;
14246 $lastreset = 0;
14247 foreach ($this->PageNumSubstitutions AS $psarr) {
14248 if ($num >= $psarr['from']) {
14249 if ($psarr['reset']) {
14250 if ($psarr['reset'] > 1) {
14251 $offset = $psarr['reset'] - 1;
14252 }
14253 $ppgno = $num - $psarr['from'] + 1 + $offset;
14254 $lastreset = $psarr['from'];
14255 }
14256 if ($psarr['type']) {
14257 $type = $psarr['type'];
14258 }
14259 if (strtoupper($psarr['suppress']) == 'ON' || $psarr['suppress'] == 1) {
14260 $suppress = 1;
14261 } elseif (strtoupper($psarr['suppress']) == 'OFF') {
14262 $suppress = 0;
14263 }
14264 }
14265 }
14266 if ($suppress) {
14267 return '';
14268 }
14269
14270 $ppgno = $this->_getStyledNumber($ppgno, $type);
14271 if ($extras) {
14272 $ppgno = $this->pagenumPrefix . $ppgno . $this->pagenumSuffix;
14273 }
14274 return $ppgno;
14275 }
14276
14277 function docPageNumTotal($num = 0, $extras = false)
14278 {
14279 if ($num < 1) {
14280 $num = $this->page;
14281 }
14282 $type = $this->defaultPageNumStyle; // set default Page Number Style
14283 $ppgstart = 1;
14284 $ppgend = count($this->pages) + 1;
14285 $suppress = 0;
14286 $offset = 0;
14287 foreach ($this->PageNumSubstitutions AS $psarr) {
14288 if ($num >= $psarr['from']) {
14289 if ($psarr['reset']) {
14290 if ($psarr['reset'] > 1) {
14291 $offset = $psarr['reset'] - 1;
14292 }
14293 $ppgstart = $psarr['from'] + $offset;
14294 $ppgend = count($this->pages) + 1 + $offset;
14295 }
14296 if ($psarr['type']) {
14297 $type = $psarr['type'];
14298 }
14299 if (strtoupper($psarr['suppress']) == 'ON' || $psarr['suppress'] == 1) {
14300 $suppress = 1;
14301 } elseif (strtoupper($psarr['suppress']) == 'OFF') {
14302 $suppress = 0;
14303 }
14304 }
14305 if ($num < $psarr['from']) {
14306 if ($psarr['reset']) {
14307 $ppgend = $psarr['from'] + $offset;
14308 break;
14309 }
14310 }
14311 }
14312 if ($suppress) {
14313 return '';
14314 }
14315 $ppgno = $ppgend - $ppgstart + $offset;
14316
14317 $ppgno = $this->_getStyledNumber($ppgno, $type);
14318 if ($extras) {
14319 $ppgno = $this->pagenumPrefix . $ppgno . $this->pagenumSuffix;
14320 }
14321 return $ppgno;
14322 }
14323
14324 // mPDF 6
14325 function _getStyledNumber($ppgno, $type, $listmarker = false)
14326 {
14327 if ($listmarker) {
14328 $reverse = true; // Reverse RTL numerals (Hebrew) when using for list
14329 $checkfont = true; // Using list - font is set, so check if character is available
14330 } else {
14331 $reverse = false; // For pagenumbers, RTL numerals (Hebrew) will get reversed later by bidi
14332 $checkfont = false; // For pagenumbers - font is not set, so no check
14333 }
14334 $lowertype = strtolower($type);
14335 if ($lowertype == 'upper-latin' || $lowertype == 'upper-alpha' || $type == 'A') {
14336 $ppgno = $this->dec2alpha($ppgno, true);
14337 } elseif ($lowertype == 'lower-latin' || $lowertype == 'lower-alpha' || $type == 'a') {
14338 $ppgno = $this->dec2alpha($ppgno, false);
14339 } elseif ($lowertype == 'upper-roman' || $type == 'I') {
14340 $ppgno = $this->dec2roman($ppgno, true);
14341 } elseif ($lowertype == 'lower-roman' || $type == 'i') {
14342 $ppgno = $this->dec2roman($ppgno, false);
14343 } elseif ($lowertype == 'hebrew') {
14344 $ppgno = $this->dec2hebrew($ppgno, $reverse);
14345 } elseif (preg_match('/(arabic-indic|bengali|devanagari|gujarati|gurmukhi|kannada|malayalam|oriya|persian|tamil|telugu|thai|urdu|cambodian|khmer|lao)/i', $lowertype, $m)) {
14346 switch ($m[1]) { //Format type
14347 case 'arabic-indic': $cp = 0x0660;
14348 break;
14349 case 'persian':
14350 case 'urdu': $cp = 0x06F0;
14351 break;
14352 case 'bengali': $cp = 0x09E6;
14353 break;
14354 case 'devanagari': $cp = 0x0966;
14355 break;
14356 case 'gujarati': $cp = 0x0AE6;
14357 break;
14358 case 'gurmukhi': $cp = 0x0A66;
14359 break;
14360 case 'kannada': $cp = 0x0CE6;
14361 break;
14362 case 'malayalam': $cp = 0x0D66;
14363 break;
14364 case 'oriya': $cp = 0x0B66;
14365 break;
14366 case 'telugu': $cp = 0x0C66;
14367 break;
14368 case 'tamil': $cp = 0x0BE6;
14369 break;
14370 case 'thai': $cp = 0x0E50;
14371 break;
14372 case 'khmer':
14373 case 'cambodian': $cp = 0x17E0;
14374 break;
14375 case 'lao': $cp = 0x0ED0;
14376 break;
14377 }
14378 $ppgno = $this->dec2other($ppgno, $cp, $checkfont);
14379 } elseif ($lowertype == 'cjk-decimal') {
14380 $ppgno = $this->dec2cjk($ppgno);
14381 }
14382 return $ppgno;
14383 }
14384
14385 function docPageSettings($num = 0)
14386 {
14387 // Returns current type (numberstyle), suppression state for this page number;
14388 // reset is only returned if set for this page number
14389 if ($num < 1) {
14390 $num = $this->page;
14391 }
14392 $type = $this->defaultPageNumStyle; // set default Page Number Style
14393 $ppgno = $num;
14394 $suppress = 0;
14395 $offset = 0;
14396 $reset = '';
14397 foreach ($this->PageNumSubstitutions AS $psarr) {
14398 if ($num >= $psarr['from']) {
14399 if ($psarr['reset']) {
14400 if ($psarr['reset'] > 1) {
14401 $offset = $psarr['reset'] - 1;
14402 }
14403 $ppgno = $num - $psarr['from'] + 1 + $offset;
14404 }
14405 if ($psarr['type']) {
14406 $type = $psarr['type'];
14407 }
14408 if (strtoupper($psarr['suppress']) == 'ON' || $psarr['suppress'] == 1) {
14409 $suppress = 1;
14410 } elseif (strtoupper($psarr['suppress']) == 'OFF') {
14411 $suppress = 0;
14412 }
14413 }
14414 if ($num == $psarr['from']) {
14415 $reset = $psarr['reset'];
14416 }
14417 }
14418 if ($suppress) {
14419 $suppress = 'on';
14420 } else {
14421 $suppress = 'off';
14422 }
14423 return array($type, $suppress, $reset);
14424 }
14425
14426 function RestartDocTemplate()
14427 {
14428 $this->docTemplateStart = $this->page;
14429 }
14430
14431 //Page header
14432 function Header($content = '')
14433 {
14434
14435 $this->cMarginL = 0;
14436 $this->cMarginR = 0;
14437
14438
14439 if (($this->mirrorMargins && ($this->page % 2 == 0) && $this->HTMLHeaderE) || ($this->mirrorMargins && ($this->page % 2 == 1) && $this->HTMLHeader) || (!$this->mirrorMargins && $this->HTMLHeader)) {
14440 $this->writeHTMLHeaders();
14441 return;
14442 }
14443 }
14444
14445 /* -- TABLES -- */
14446
14447 function TableHeaderFooter($content = '', $tablestartpage = '', $tablestartcolumn = '', $horf = 'H', $level = 0, $firstSpread = true, $finalSpread = true)
14448 {
14449 if (($horf == 'H' || $horf == 'F') && !empty($content)) { // mPDF 5.7.2
14450 $table = &$this->table[1][1];
14451
14452 // mPDF 5.7.2
14453 if ($horf == 'F') { // Table Footer
14454 $firstrow = count($table['cells']) - $table['footernrows'];
14455 $lastrow = count($table['cells']) - 1;
14456 } else { // Table Header
14457 $firstrow = 0;
14458 $lastrow = $table['headernrows'] - 1;
14459 }
14460 if (empty($content[$firstrow])) {
14461 if ($this->debug) {
14462 throw new MpdfException("&lt;tfoot&gt; must precede &lt;tbody&gt; in a table");
14463 } else {
14464 return;
14465 }
14466 }
14467
14468
14469 // Advance down page by half width of top border
14470 if ($horf == 'H') { // Only if header
14471 if ($table['borders_separate']) {
14472 $adv = $table['border_spacing_V'] / 2 + $table['border_details']['T']['w'] + $table['padding']['T'];
14473 } else {
14474 $adv = $table['max_cell_border_width']['T'] / 2;
14475 }
14476 if ($adv) {
14477 if ($this->table_rotate) {
14478 $this->y += ($adv);
14479 } else {
14480 $this->DivLn($adv, $this->blklvl, true);
14481 }
14482 }
14483 }
14484
14485 $topy = $content[$firstrow][0]['y'] - $this->y;
14486
14487 for ($i = $firstrow; $i <= $lastrow; $i++) {
14488
14489 $y = $this->y;
14490
14491 /* -- COLUMNS -- */
14492 // If outside columns, this is done in PaintDivBB
14493 if ($this->ColActive) {
14494 //OUTER FILL BGCOLOR of DIVS
14495 if ($this->blklvl > 0) {
14496 $firstblockfill = $this->GetFirstBlockFill();
14497 if ($firstblockfill && $this->blklvl >= $firstblockfill) {
14498 $divh = $content[$i][0]['h'];
14499 $bak_x = $this->x;
14500 $this->DivLn($divh, -3, false);
14501 // Reset current block fill
14502 $bcor = $this->blk[$this->blklvl]['bgcolorarray'];
14503 $this->SetFColor($bcor);
14504 $this->x = $bak_x;
14505 }
14506 }
14507 }
14508 /* -- END COLUMNS -- */
14509
14510 $colctr = 0;
14511 foreach ($content[$i] as $tablehf) {
14512 $colctr++;
14513 $y = $tablehf['y'] - $topy;
14514 $this->y = $y;
14515 //Set some cell values
14516 $x = $tablehf['x'];
14517 if (($this->mirrorMargins) && ($tablestartpage == 'ODD') && (($this->page) % 2 == 0)) { // EVEN
14518 $x = $x + $this->MarginCorrection;
14519 } elseif (($this->mirrorMargins) && ($tablestartpage == 'EVEN') && (($this->page) % 2 == 1)) { // ODD
14520 $x = $x + $this->MarginCorrection;
14521 }
14522 /* -- COLUMNS -- */
14523 // Added to correct for Columns
14524 if ($this->ColActive) {
14525 if ($this->directionality == 'rtl') { // *OTL*
14526 $x -= ($this->CurrCol - $tablestartcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
14527 } // *OTL*
14528 else { // *OTL*
14529 $x += ($this->CurrCol - $tablestartcolumn) * ($this->ColWidth + $this->ColGap);
14530 } // *OTL*
14531 }
14532 /* -- END COLUMNS -- */
14533
14534 if ($colctr == 1) {
14535 $x0 = $x;
14536 }
14537
14538 // mPDF ITERATION
14539 if ($this->iterationCounter) {
14540 foreach ($tablehf['textbuffer'] AS $k => $t) {
14541 if (!is_array($t[0]) && preg_match('/{iteration ([a-zA-Z0-9_]+)}/', $t[0], $m)) {
14542 $vname = '__' . $m[1] . '_';
14543 if (!isset($this->$vname)) {
14544 $this->$vname = 1;
14545 } else {
14546 $this->$vname++;
14547 }
14548 $tablehf['textbuffer'][$k][0] = preg_replace('/{iteration ' . $m[1] . '}/', $this->$vname, $tablehf['textbuffer'][$k][0]);
14549 }
14550 }
14551 }
14552
14553 $w = $tablehf['w'];
14554 $h = $tablehf['h'];
14555 $va = $tablehf['va'];
14556 $R = $tablehf['R'];
14557 $direction = $tablehf['direction'];
14558 $mih = $tablehf['mih'];
14559 $border = $tablehf['border'];
14560 $border_details = $tablehf['border_details'];
14561 $padding = $tablehf['padding'];
14562 $this->tabletheadjustfinished = true;
14563
14564 $textbuffer = $tablehf['textbuffer'];
14565
14566 //Align
14567 $align = $tablehf['a'];
14568 $this->cellTextAlign = $align;
14569
14570 $this->cellLineHeight = $tablehf['cellLineHeight'];
14571 $this->cellLineStackingStrategy = $tablehf['cellLineStackingStrategy'];
14572 $this->cellLineStackingShift = $tablehf['cellLineStackingShift'];
14573
14574 $this->x = $x;
14575
14576 if ($this->ColActive) {
14577 if ($table['borders_separate']) {
14578 $tablefill = isset($table['bgcolor'][-1]) ? $table['bgcolor'][-1] : 0;
14579 if ($tablefill) {
14580 $color = $this->ConvertColor($tablefill);
14581 if ($color) {
14582 $xadj = ($table['border_spacing_H'] / 2);
14583 $yadj = ($table['border_spacing_V'] / 2);
14584 $wadj = $table['border_spacing_H'];
14585 $hadj = $table['border_spacing_V'];
14586 if ($i == $firstrow && $horf == 'H') { // Top
14587 $yadj += $table['padding']['T'] + $table['border_details']['T']['w'];
14588 $hadj += $table['padding']['T'] + $table['border_details']['T']['w'];
14589 }
14590 if (($i == ($lastrow) || (isset($tablehf['rowspan']) && ($i + $tablehf['rowspan']) == ($lastrow + 1)) || (!isset($tablehf['rowspan']) && ($i + 1) == ($lastrow + 1))) && $horf == 'F') { // Bottom
14591 $hadj += $table['padding']['B'] + $table['border_details']['B']['w'];
14592 }
14593 if ($colctr == 1) { // Left
14594 $xadj += $table['padding']['L'] + $table['border_details']['L']['w'];
14595 $wadj += $table['padding']['L'] + $table['border_details']['L']['w'];
14596 }
14597 if ($colctr == count($content[$i])) { // Right
14598 $wadj += $table['padding']['R'] + $table['border_details']['R']['w'];
14599 }
14600 $this->SetFColor($color);
14601 $this->Rect($x - $xadj, $y - $yadj, $w + $wadj, $h + $hadj, 'F');
14602 }
14603 }
14604 }
14605 }
14606
14607 if ($table['empty_cells'] != 'hide' || !empty($textbuffer) || !$table['borders_separate']) {
14608 $paintcell = true;
14609 } else {
14610 $paintcell = false;
14611 }
14612
14613 //Vertical align
14614 if ($R && INTVAL($R) > 0 && isset($va) && $va != 'B') {
14615 $va = 'B';
14616 }
14617
14618 if (!isset($va) || empty($va) || $va == 'M')
14619 $this->y += ($h - $mih) / 2;
14620 elseif (isset($va) && $va == 'B')
14621 $this->y += $h - $mih;
14622
14623
14624 //TABLE ROW OR CELL FILL BGCOLOR
14625 $fill = 0;
14626 if (isset($tablehf['bgcolor']) && $tablehf['bgcolor'] && $tablehf['bgcolor'] != 'transparent') {
14627 $fill = $tablehf['bgcolor'];
14628 $leveladj = 6;
14629 } elseif (isset($content[$i][0]['trbgcolor']) && $content[$i][0]['trbgcolor'] && $content[$i][0]['trbgcolor'] != 'transparent') { // Row color
14630 $fill = $content[$i][0]['trbgcolor'];
14631 $leveladj = 3;
14632 }
14633 if ($fill && $paintcell) {
14634 $color = $this->ConvertColor($fill);
14635 if ($color) {
14636 if ($table['borders_separate']) {
14637 if ($this->ColActive) {
14638 $this->SetFColor($color);
14639 $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');
14640 } else {
14641 $this->tableBackgrounds[$level * 9 + $leveladj][] = array('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);
14642 }
14643 } else {
14644 if ($this->ColActive) {
14645 $this->SetFColor($color);
14646 $this->Rect($x, $y, $w, $h, 'F');
14647 } else {
14648 $this->tableBackgrounds[$level * 9 + $leveladj][] = array('gradient' => false, 'x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'col' => $color);
14649 }
14650 }
14651 }
14652 }
14653
14654
14655 /* -- BACKGROUNDS -- */
14656 if (isset($tablehf['gradient']) && $tablehf['gradient'] && $paintcell) {
14657 $g = $this->grad->parseBackgroundGradient($tablehf['gradient']);
14658 if ($g) {
14659 if ($table['borders_separate']) {
14660 $px = $x + ($table['border_spacing_H'] / 2);
14661 $py = $y + ($table['border_spacing_V'] / 2);
14662 $pw = $w - $table['border_spacing_H'];
14663 $ph = $h - $table['border_spacing_V'];
14664 } else {
14665 $px = $x;
14666 $py = $y;
14667 $pw = $w;
14668 $ph = $h;
14669 }
14670 if ($this->ColActive) {
14671 $this->grad->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
14672 } else {
14673 $this->tableBackgrounds[$level * 9 + 7][] = array('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' => '');
14674 }
14675 }
14676 }
14677
14678 if (isset($tablehf['background-image']) && $paintcell) {
14679 if ($tablehf['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $tablehf['background-image']['gradient'])) {
14680 $g = $this->grad->parseMozGradient($tablehf['background-image']['gradient']);
14681 if ($g) {
14682 if ($table['borders_separate']) {
14683 $px = $x + ($table['border_spacing_H'] / 2);
14684 $py = $y + ($table['border_spacing_V'] / 2);
14685 $pw = $w - $table['border_spacing_H'];
14686 $ph = $h - $table['border_spacing_V'];
14687 } else {
14688 $px = $x;
14689 $py = $y;
14690 $pw = $w;
14691 $ph = $h;
14692 }
14693 if ($this->ColActive) {
14694 $this->grad->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
14695 } else {
14696 $this->tableBackgrounds[$level * 9 + 7][] = array('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' => '');
14697 }
14698 }
14699 } elseif ($tablehf['background-image']['image_id']) { // Background pattern
14700 $n = count($this->patterns) + 1;
14701 if ($table['borders_separate']) {
14702 $px = $x + ($table['border_spacing_H'] / 2);
14703 $py = $y + ($table['border_spacing_V'] / 2);
14704 $pw = $w - $table['border_spacing_H'];
14705 $ph = $h - $table['border_spacing_V'];
14706 } else {
14707 $px = $x;
14708 $py = $y;
14709 $pw = $w;
14710 $ph = $h;
14711 }
14712 if ($this->ColActive) {
14713 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']);
14714 $this->patterns[$n] = array('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']);
14715 if ($tablehf['background-image']['opacity'] > 0 && $tablehf['background-image']['opacity'] < 1) {
14716 $opac = $this->SetAlpha($tablehf['background-image']['opacity'], 'Normal', true);
14717 } else {
14718 $opac = '';
14719 }
14720 $this->_out(sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $px * _MPDFK, ($this->h - $py) * _MPDFK, $pw * _MPDFK, -$ph * _MPDFK));
14721 } else {
14722 $this->tableBackgrounds[$level * 9 + 8][] = array('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']);
14723 }
14724 }
14725 }
14726 /* -- END BACKGROUNDS -- */
14727
14728 //Cell Border
14729 if ($table['borders_separate'] && $paintcell && $border) {
14730 $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']);
14731 } elseif ($paintcell && $border) {
14732 $this->_tableRect($x, $y, $w, $h, $border, $border_details, true, $table['borders_separate']); // true causes buffer
14733 }
14734
14735 //Print cell content
14736 if (!empty($textbuffer)) {
14737 if ($horf == 'F' && preg_match('/{colsum([0-9]*)[_]*}/', $textbuffer[0][0], $m)) {
14738 $rep = sprintf("%01." . intval($m[1]) . "f", $this->colsums[$colctr - 1]);
14739 $textbuffer[0][0] = preg_replace('/{colsum[0-9_]*}/', $rep, $textbuffer[0][0]);
14740 }
14741
14742 if ($R) {
14743 $cellPtSize = $textbuffer[0][11] / $this->shrin_k;
14744 if (!$cellPtSize) {
14745 $cellPtSize = $this->default_font_size;
14746 }
14747 $cellFontHeight = ($cellPtSize / _MPDFK);
14748 $opx = $this->x;
14749 $opy = $this->y;
14750 $angle = INTVAL($R);
14751 // Only allow 45 - 90 degrees (when bottom-aligned) or -90
14752 if ($angle > 90) {
14753 $angle = 90;
14754 } elseif ($angle > 0 && (isset($va) && $va != 'B')) {
14755 $angle = 90;
14756 } elseif ($angle > 0 && $angle < 45) {
14757 $angle = 45;
14758 } elseif ($angle < 0) {
14759 $angle = -90;
14760 }
14761 $offset = ((sin(deg2rad($angle))) * 0.37 * $cellFontHeight);
14762 if (isset($align) && $align == 'R') {
14763 $this->x += ($w) + ($offset) - ($cellFontHeight / 3) - ($padding['R'] + $border_details['R']['w']);
14764 } elseif (!isset($align) || $align == 'C') {
14765 $this->x += ($w / 2) + ($offset);
14766 } else {
14767 $this->x += ($offset) + ($cellFontHeight / 3) + ($padding['L'] + $border_details['L']['w']);
14768 }
14769 $str = '';
14770 foreach ($tablehf['textbuffer'] AS $t) {
14771 $str .= $t[0] . ' ';
14772 }
14773 $str = rtrim($str);
14774
14775 if (!isset($va) || $va == 'M') {
14776 $this->y -= ($h - $mih) / 2; //Undo what was added earlier VERTICAL ALIGN
14777 if ($angle > 0) {
14778 $this->y += (($h - $mih) / 2) + ($padding['T'] + $border_details['T']['w']) + ($mih - ($padding['T'] + $border_details['T']['w'] + $border_details['B']['w'] + $padding['B']));
14779 } elseif ($angle < 0) {
14780 $this->y += (($h - $mih) / 2) + ($padding['T'] + $border_details['T']['w']);
14781 }
14782 } elseif (isset($va) && $va == 'B') {
14783 $this->y -= $h - $mih; //Undo what was added earlier VERTICAL ALIGN
14784 if ($angle > 0) {
14785 $this->y += $h - ($border_details['B']['w'] + $padding['B']);
14786 } elseif ($angle < 0) {
14787 $this->y += $h - $mih + ($padding['T'] + $border_details['T']['w']);
14788 }
14789 } elseif (isset($va) && $va == 'T') {
14790 if ($angle > 0) {
14791 $this->y += $mih - ($border_details['B']['w'] + $padding['B']);
14792 } elseif ($angle < 0) {
14793 $this->y += ($padding['T'] + $border_details['T']['w']);
14794 }
14795 }
14796
14797 $this->Rotate($angle, $this->x, $this->y);
14798 $s_fs = $this->FontSizePt;
14799 $s_f = $this->FontFamily;
14800 $s_st = $this->FontStyle;
14801 if (!empty($textbuffer[0][3])) { //Font Color
14802 $cor = $textbuffer[0][3];
14803 $this->SetTColor($cor);
14804 }
14805 $this->SetFont($textbuffer[0][4], $textbuffer[0][2], $cellPtSize, true, true);
14806
14807 $this->magic_reverse_dir($str, $this->directionality, $textbuffer[0][18]);
14808 $this->Text($this->x, $this->y, $str, $textbuffer[0][18], $textbuffer[0][8]); // textvar
14809 $this->Rotate(0);
14810 $this->SetFont($s_f, $s_st, $s_fs, true, true);
14811 $this->SetTColor(0);
14812 $this->x = $opx;
14813 $this->y = $opy;
14814 } else {
14815 if ($table['borders_separate']) { // NB twice border width
14816 $xadj = $border_details['L']['w'] + $padding['L'] + ($table['border_spacing_H'] / 2);
14817 $wadj = $border_details['L']['w'] + $border_details['R']['w'] + $padding['L'] + $padding['R'] + $table['border_spacing_H'];
14818 $yadj = $border_details['T']['w'] + $padding['T'] + ($table['border_spacing_H'] / 2);
14819 } else {
14820 $xadj = $border_details['L']['w'] / 2 + $padding['L'];
14821 $wadj = ($border_details['L']['w'] + $border_details['R']['w']) / 2 + $padding['L'] + $padding['R'];
14822 $yadj = $border_details['T']['w'] / 2 + $padding['T'];
14823 }
14824
14825 $this->divwidth = $w - ($wadj);
14826 $this->x += $xadj;
14827 $this->y += $yadj;
14828 $this->printbuffer($textbuffer, '', true, false, $direction);
14829 }
14830 }
14831 $textbuffer = array();
14832
14833 /* -- BACKGROUNDS -- */
14834 if (!$this->ColActive) {
14835 if (isset($content[$i][0]['trgradients']) && ($colctr == 1 || $table['borders_separate'])) {
14836 $g = $this->grad->parseBackgroundGradient($content[$i][0]['trgradients']);
14837 if ($g) {
14838 $gx = $x0;
14839 $gy = $y;
14840 $gh = $h;
14841 $gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
14842 if ($table['borders_separate']) {
14843 $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
14844 $clx = $x + ($table['border_spacing_H'] / 2);
14845 $cly = $y + ($table['border_spacing_V'] / 2);
14846 $clw = $w - $table['border_spacing_H'];
14847 $clh = $h - $table['border_spacing_V'];
14848 // Set clipping path
14849 $s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
14850 $this->tableBackgrounds[$level * 9 + 4][] = array('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);
14851 } else {
14852 $this->tableBackgrounds[$level * 9 + 4][] = array('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' => '');
14853 }
14854 }
14855 }
14856
14857 if (isset($content[$i][0]['trbackground-images']) && ($colctr == 1 || $table['borders_separate'])) {
14858 if ($content[$i][0]['trbackground-images']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $content[$i][0]['trbackground-images']['gradient'])) {
14859 $g = $this->grad->parseMozGradient($content[$i][0]['trbackground-images']['gradient']);
14860 if ($g) {
14861 $gx = $x0;
14862 $gy = $y;
14863 $gh = $h;
14864 $gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
14865 if ($table['borders_separate']) {
14866 $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
14867 $clx = $x + ($table['border_spacing_H'] / 2);
14868 $cly = $y + ($table['border_spacing_V'] / 2);
14869 $clw = $w - $table['border_spacing_H'];
14870 $clh = $h - $table['border_spacing_V'];
14871 // Set clipping path
14872 $s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
14873 $this->tableBackgrounds[$level * 9 + 4][] = array('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);
14874 } else {
14875 $this->tableBackgrounds[$level * 9 + 4][] = array('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' => '');
14876 }
14877 }
14878 } else {
14879 $image_id = $content[$i][0]['trbackground-images']['image_id'];
14880 $orig_w = $content[$i][0]['trbackground-images']['orig_w'];
14881 $orig_h = $content[$i][0]['trbackground-images']['orig_h'];
14882 $x_pos = $content[$i][0]['trbackground-images']['x_pos'];
14883 $y_pos = $content[$i][0]['trbackground-images']['y_pos'];
14884 $x_repeat = $content[$i][0]['trbackground-images']['x_repeat'];
14885 $y_repeat = $content[$i][0]['trbackground-images']['y_repeat'];
14886 $resize = $content[$i][0]['trbackground-images']['resize'];
14887 $opacity = $content[$i][0]['trbackground-images']['opacity'];
14888 $itype = $content[$i][0]['trbackground-images']['itype'];
14889
14890 $clippath = '';
14891 $gx = $x0;
14892 $gy = $y;
14893 $gh = $h;
14894 $gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
14895 if ($table['borders_separate']) {
14896 $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
14897 $clx = $x + ($table['border_spacing_H'] / 2);
14898 $cly = $y + ($table['border_spacing_V'] / 2);
14899 $clw = $w - $table['border_spacing_H'];
14900 $clh = $h - $table['border_spacing_V'];
14901 // Set clipping path
14902 $s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
14903 $this->tableBackgrounds[$level * 9 + 5][] = array('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);
14904 } else {
14905 $this->tableBackgrounds[$level * 9 + 5][] = array('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);
14906 }
14907 }
14908 }
14909 }
14910 /* -- END BACKGROUNDS -- */
14911
14912 // TABLE BORDER - if separate OR collapsed and only table border
14913 if (($table['borders_separate'] || ($this->simpleTables && !$table['simple']['border'])) && $table['border']) {
14914 $halfspaceL = $table['padding']['L'] + ($table['border_spacing_H'] / 2);
14915 $halfspaceR = $table['padding']['R'] + ($table['border_spacing_H'] / 2);
14916 $halfspaceT = $table['padding']['T'] + ($table['border_spacing_V'] / 2);
14917 $halfspaceB = $table['padding']['B'] + ($table['border_spacing_V'] / 2);
14918 $tbx = $x;
14919 $tby = $y;
14920 $tbw = $w;
14921 $tbh = $h;
14922 $tab_bord = 0;
14923 $corner = '';
14924 if ($i == $firstrow && $horf == 'H') { // Top
14925 $tby -= $halfspaceT + ($table['border_details']['T']['w'] / 2);
14926 $tbh += $halfspaceT + ($table['border_details']['T']['w'] / 2);
14927 $this->setBorder($tab_bord, _BORDER_TOP);
14928 $corner .= 'T';
14929 }
14930 if (($i == ($lastrow) || (isset($tablehf['rowspan']) && ($i + $tablehf['rowspan']) == ($lastrow + 1))) && $horf == 'F') { // Bottom
14931 $tbh += $halfspaceB + ($table['border_details']['B']['w'] / 2);
14932 $this->setBorder($tab_bord, _BORDER_BOTTOM);
14933 $corner .= 'B';
14934 }
14935 if ($colctr == 1 && $firstSpread) { // Left
14936 $tbx -= $halfspaceL + ($table['border_details']['L']['w'] / 2);
14937 $tbw += $halfspaceL + ($table['border_details']['L']['w'] / 2);
14938 $this->setBorder($tab_bord, _BORDER_LEFT);
14939 $corner .= 'L';
14940 }
14941 if ($colctr == count($content[$i]) && $finalSpread) { // Right
14942 $tbw += $halfspaceR + ($table['border_details']['R']['w'] / 2);
14943 $this->setBorder($tab_bord, _BORDER_RIGHT);
14944 $corner .= 'R';
14945 }
14946 $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']);
14947 }
14948 }// end column $content
14949 $this->y = $y + $h; //Update y coordinate
14950 }// end row $i
14951 unset($table);
14952 $this->colsums = array();
14953 }
14954 }
14955
14956 /* -- END TABLES -- */
14957
14958 function SetHTMLHeader($header = '', $OE = '', $write = false)
14959 {
14960
14961 $height = 0;
14962 if (is_array($header) && isset($header['html']) && $header['html']) {
14963 $Hhtml = $header['html'];
14964 if ($this->setAutoTopMargin) {
14965 if (isset($header['h'])) {
14966 $height = $header['h'];
14967 } else {
14968 $height = $this->_gethtmlheight($Hhtml);
14969 }
14970 }
14971 } elseif (!is_array($header) && $header) {
14972 $Hhtml = $header;
14973 if ($this->setAutoTopMargin) {
14974 $height = $this->_gethtmlheight($Hhtml);
14975 }
14976 } else {
14977 $Hhtml = '';
14978 }
14979
14980 if ($OE != 'E') {
14981 $OE = 'O';
14982 }
14983 if ($OE == 'E') {
14984
14985 if ($Hhtml) {
14986 $this->HTMLHeaderE['html'] = $Hhtml;
14987 $this->HTMLHeaderE['h'] = $height;
14988 } else {
14989 $this->HTMLHeaderE = '';
14990 }
14991 } else {
14992
14993 if ($Hhtml) {
14994 $this->HTMLHeader['html'] = $Hhtml;
14995 $this->HTMLHeader['h'] = $height;
14996 } else {
14997 $this->HTMLHeader = '';
14998 }
14999 }
15000 if (!$this->mirrorMargins && $OE == 'E') {
15001 return;
15002 }
15003 if ($Hhtml == '') {
15004 return;
15005 }
15006
15007 if ($this->setAutoTopMargin == 'pad') {
15008 $this->tMargin = $this->margin_header + $height + $this->orig_tMargin;
15009 if (isset($this->saveHTMLHeader[$this->page][$OE]['mt'])) {
15010 $this->saveHTMLHeader[$this->page][$OE]['mt'] = $this->tMargin;
15011 }
15012 } elseif ($this->setAutoTopMargin == 'stretch') {
15013 $this->tMargin = max($this->orig_tMargin, $this->margin_header + $height + $this->autoMarginPadding);
15014 if (isset($this->saveHTMLHeader[$this->page][$OE]['mt'])) {
15015 $this->saveHTMLHeader[$this->page][$OE]['mt'] = $this->tMargin;
15016 }
15017 }
15018 if ($write && $this->state != 0 && (($this->mirrorMargins && $OE == 'E' && ($this->page) % 2 == 0) || ($this->mirrorMargins && $OE != 'E' && ($this->page) % 2 == 1) || !$this->mirrorMargins)) {
15019 $this->writeHTMLHeaders();
15020 }
15021 }
15022
15023 function SetHTMLFooter($footer = '', $OE = '')
15024 {
15025 $height = 0;
15026 if (is_array($footer) && isset($footer['html']) && $footer['html']) {
15027 $Fhtml = $footer['html'];
15028 if ($this->setAutoBottomMargin) {
15029 if (isset($footer['h'])) {
15030 $height = $footer['h'];
15031 } else {
15032 $height = $this->_gethtmlheight($Fhtml);
15033 }
15034 }
15035 } elseif (!is_array($footer) && $footer) {
15036 $Fhtml = $footer;
15037 if ($this->setAutoBottomMargin) {
15038 $height = $this->_gethtmlheight($Fhtml);
15039 }
15040 } else {
15041 $Fhtml = '';
15042 }
15043
15044 if ($OE != 'E') {
15045 $OE = 'O';
15046 }
15047 if ($OE == 'E') {
15048
15049 if ($Fhtml) {
15050 $this->HTMLFooterE['html'] = $Fhtml;
15051 $this->HTMLFooterE['h'] = $height;
15052 } else {
15053 $this->HTMLFooterE = '';
15054 }
15055 } else {
15056
15057 if ($Fhtml) {
15058 $this->HTMLFooter['html'] = $Fhtml;
15059 $this->HTMLFooter['h'] = $height;
15060 } else {
15061 $this->HTMLFooter = '';
15062 }
15063 }
15064 if (!$this->mirrorMargins && $OE == 'E') {
15065 return;
15066 }
15067 if ($Fhtml == '') {
15068 return false;
15069 }
15070
15071 if ($this->setAutoBottomMargin == 'pad') {
15072 $this->bMargin = $this->margin_footer + $height + $this->orig_bMargin;
15073 $this->PageBreakTrigger = $this->h - $this->bMargin;
15074 if (isset($this->saveHTMLHeader[$this->page][$OE]['mb'])) {
15075 $this->saveHTMLHeader[$this->page][$OE]['mb'] = $this->bMargin;
15076 }
15077 } elseif ($this->setAutoBottomMargin == 'stretch') {
15078 $this->bMargin = max($this->orig_bMargin, $this->margin_footer + $height + $this->autoMarginPadding);
15079 $this->PageBreakTrigger = $this->h - $this->bMargin;
15080 if (isset($this->saveHTMLHeader[$this->page][$OE]['mb'])) {
15081 $this->saveHTMLHeader[$this->page][$OE]['mb'] = $this->bMargin;
15082 }
15083 }
15084 }
15085
15086 function _getHtmlHeight($html)
15087 {
15088 $save_state = $this->state;
15089 if ($this->state == 0) {
15090 $this->AddPage($this->CurOrientation);
15091 }
15092 $this->state = 2;
15093 $this->Reset();
15094 $this->pageoutput[$this->page] = array();
15095 $save_x = $this->x;
15096 $save_y = $this->y;
15097 $this->x = $this->lMargin;
15098 $this->y = $this->margin_header;
15099 $html = str_replace('{PAGENO}', $this->pagenumPrefix . $this->docPageNum($this->page) . $this->pagenumSuffix, $html);
15100 $html = str_replace($this->aliasNbPgGp, $this->nbpgPrefix . $this->docPageNumTotal($this->page) . $this->nbpgSuffix, $html);
15101 $html = str_replace($this->aliasNbPg, $this->page, $html);
15102 $html = preg_replace_callback('/\{DATE\s+(.*?)\}/', array($this, 'date_callback'), $html); // mPDF 5.7
15103 $this->HTMLheaderPageLinks = array();
15104 $this->HTMLheaderPageAnnots = array();
15105 $this->HTMLheaderPageForms = array();
15106 $savepb = $this->pageBackgrounds;
15107 $this->writingHTMLheader = true;
15108 $this->WriteHTML($html, 4); // parameter 4 saves output to $this->headerbuffer
15109 $this->writingHTMLheader = false;
15110 $h = ($this->y - $this->margin_header);
15111 $this->Reset();
15112 // mPDF 5.7.2 - Clear in case Float used in Header/Footer
15113 $this->blk[0]['blockContext'] = 0;
15114 $this->blk[0]['float_endpos'] = 0;
15115
15116 $this->pageoutput[$this->page] = array();
15117 $this->headerbuffer = '';
15118 $this->pageBackgrounds = $savepb;
15119 $this->x = $save_x;
15120 $this->y = $save_y;
15121 $this->state = $save_state;
15122 if ($save_state == 0) {
15123 unset($this->pages[1]);
15124 $this->page = 0;
15125 }
15126 return $h;
15127 }
15128
15129 // Called internally from Header
15130 function writeHTMLHeaders()
15131 {
15132
15133 if ($this->mirrorMargins && ($this->page) % 2 == 0) {
15134 $OE = 'E';
15135 } // EVEN
15136 else {
15137 $OE = 'O';
15138 }
15139 if ($OE == 'E') {
15140 $this->saveHTMLHeader[$this->page][$OE]['html'] = $this->HTMLHeaderE['html'];
15141 } else {
15142 $this->saveHTMLHeader[$this->page][$OE]['html'] = $this->HTMLHeader['html'];
15143 }
15144 if ($this->forcePortraitHeaders && $this->CurOrientation == 'L' && $this->CurOrientation != $this->DefOrientation) {
15145 $this->saveHTMLHeader[$this->page][$OE]['rotate'] = true;
15146 $this->saveHTMLHeader[$this->page][$OE]['ml'] = $this->tMargin;
15147 $this->saveHTMLHeader[$this->page][$OE]['mr'] = $this->bMargin;
15148 $this->saveHTMLHeader[$this->page][$OE]['mh'] = $this->margin_header;
15149 $this->saveHTMLHeader[$this->page][$OE]['mf'] = $this->margin_footer;
15150 $this->saveHTMLHeader[$this->page][$OE]['pw'] = $this->h;
15151 $this->saveHTMLHeader[$this->page][$OE]['ph'] = $this->w;
15152 } else {
15153 $this->saveHTMLHeader[$this->page][$OE]['ml'] = $this->lMargin;
15154 $this->saveHTMLHeader[$this->page][$OE]['mr'] = $this->rMargin;
15155 $this->saveHTMLHeader[$this->page][$OE]['mh'] = $this->margin_header;
15156 $this->saveHTMLHeader[$this->page][$OE]['mf'] = $this->margin_footer;
15157 $this->saveHTMLHeader[$this->page][$OE]['pw'] = $this->w;
15158 $this->saveHTMLHeader[$this->page][$OE]['ph'] = $this->h;
15159 }
15160 }
15161
15162 function writeHTMLFooters()
15163 {
15164
15165 if ($this->mirrorMargins && ($this->page) % 2 == 0) {
15166 $OE = 'E';
15167 } // EVEN
15168 else {
15169 $OE = 'O';
15170 }
15171 if ($OE == 'E') {
15172 $this->saveHTMLFooter[$this->page][$OE]['html'] = $this->HTMLFooterE['html'];
15173 } else {
15174 $this->saveHTMLFooter[$this->page][$OE]['html'] = $this->HTMLFooter['html'];
15175 }
15176 if ($this->forcePortraitHeaders && $this->CurOrientation == 'L' && $this->CurOrientation != $this->DefOrientation) {
15177 $this->saveHTMLFooter[$this->page][$OE]['rotate'] = true;
15178 $this->saveHTMLFooter[$this->page][$OE]['ml'] = $this->tMargin;
15179 $this->saveHTMLFooter[$this->page][$OE]['mr'] = $this->bMargin;
15180 $this->saveHTMLFooter[$this->page][$OE]['mt'] = $this->rMargin;
15181 $this->saveHTMLFooter[$this->page][$OE]['mb'] = $this->lMargin;
15182 $this->saveHTMLFooter[$this->page][$OE]['mh'] = $this->margin_header;
15183 $this->saveHTMLFooter[$this->page][$OE]['mf'] = $this->margin_footer;
15184 $this->saveHTMLFooter[$this->page][$OE]['pw'] = $this->h;
15185 $this->saveHTMLFooter[$this->page][$OE]['ph'] = $this->w;
15186 } else {
15187 $this->saveHTMLFooter[$this->page][$OE]['ml'] = $this->lMargin;
15188 $this->saveHTMLFooter[$this->page][$OE]['mr'] = $this->rMargin;
15189 $this->saveHTMLFooter[$this->page][$OE]['mt'] = $this->tMargin;
15190 $this->saveHTMLFooter[$this->page][$OE]['mb'] = $this->bMargin;
15191 $this->saveHTMLFooter[$this->page][$OE]['mh'] = $this->margin_header;
15192 $this->saveHTMLFooter[$this->page][$OE]['mf'] = $this->margin_footer;
15193 $this->saveHTMLFooter[$this->page][$OE]['pw'] = $this->w;
15194 $this->saveHTMLFooter[$this->page][$OE]['ph'] = $this->h;
15195 }
15196 }
15197
15198 // mPDF 6
15199 function _shareHeaderFooterWidth($cl, $cc, $cr)
15200 { // mPDF 6
15201 $l = mb_strlen($cl, 'UTF-8');
15202 $c = mb_strlen($cc, 'UTF-8');
15203 $r = mb_strlen($cr, 'UTF-8');
15204 $s = max($l, $r);
15205 $tw = $c + 2 * $s;
15206 if ($tw > 0) {
15207 return array(intval($s * 100 / $tw), intval($c * 100 / $tw), intval($s * 100 / $tw));
15208 } else {
15209 return array(33, 33, 33);
15210 }
15211 }
15212
15213 // mPDF 6
15214 // Create an HTML header/footer from array (non-HTML header/footer)
15215 function _createHTMLheaderFooter($arr, $hf)
15216 {
15217 $lContent = (isset($arr['L']['content']) ? $arr['L']['content'] : '');
15218 $cContent = (isset($arr['C']['content']) ? $arr['C']['content'] : '');
15219 $rContent = (isset($arr['R']['content']) ? $arr['R']['content'] : '');
15220 list($lw, $cw, $rw) = $this->_shareHeaderFooterWidth($lContent, $cContent, $rContent);
15221 if ($hf == 'H') {
15222 $valign = 'bottom';
15223 $vpadding = '0 0 ' . $this->header_line_spacing . 'em 0';
15224 } else {
15225 $valign = 'top';
15226 $vpadding = '' . $this->footer_line_spacing . 'em 0 0 0';
15227 }
15228 if ($this->directionality == 'rtl') { // table columns get reversed so need different text-alignment
15229 $talignL = 'right';
15230 $talignR = 'left';
15231 } else {
15232 $talignL = 'left';
15233 $talignR = 'right';
15234 }
15235 $html = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: ' . $valign . '; color: #000000; ';
15236 if (isset($arr['line']) && $arr['line']) {
15237 $html .= ' border-' . $valign . ': 0.1mm solid #000000;';
15238 }
15239 $html .= '">';
15240 $html .= '<tr>';
15241 $html .= '<td width="' . $lw . '%" style="padding: ' . $vpadding . '; text-align: ' . $talignL . '; ';
15242 if (isset($arr['L']['font-family'])) {
15243 $html .= ' font-family: ' . $arr['L']['font-family'] . ';';
15244 }
15245 if (isset($arr['L']['color'])) {
15246 $html .= ' color: ' . $arr['L']['color'] . ';';
15247 }
15248 if (isset($arr['L']['font-size'])) {
15249 $html .= ' font-size: ' . $arr['L']['font-size'] . 'pt;';
15250 }
15251 if (isset($arr['L']['font-style'])) {
15252 if ($arr['L']['font-style'] == 'B' || $arr['L']['font-style'] == 'BI') {
15253 $html .= ' font-weight: bold;';
15254 }
15255 if ($arr['L']['font-style'] == 'I' || $arr['L']['font-style'] == 'BI') {
15256 $html .= ' font-style: italic;';
15257 }
15258 }
15259 $html .= '">' . $lContent . '</td>';
15260 $html .= '<td width="' . $cw . '%" style="padding: ' . $vpadding . '; text-align: center; ';
15261 if (isset($arr['C']['font-family'])) {
15262 $html .= ' font-family: ' . $arr['C']['font-family'] . ';';
15263 }
15264 if (isset($arr['C']['color'])) {
15265 $html .= ' color: ' . $arr['C']['color'] . ';';
15266 }
15267 if (isset($arr['C']['font-size'])) {
15268 $html .= ' font-size: ' . $arr['L']['font-size'] . 'pt;';
15269 }
15270 if (isset($arr['C']['font-style'])) {
15271 if ($arr['C']['font-style'] == 'B' || $arr['C']['font-style'] == 'BI') {
15272 $html .= ' font-weight: bold;';
15273 }
15274 if ($arr['C']['font-style'] == 'I' || $arr['C']['font-style'] == 'BI') {
15275 $html .= ' font-style: italic;';
15276 }
15277 }
15278 $html .= '">' . $cContent . '</td>';
15279 $html .= '<td width="' . $rw . '%" style="padding: ' . $vpadding . '; text-align: ' . $talignR . '; ';
15280 if (isset($arr['R']['font-family'])) {
15281 $html .= ' font-family: ' . $arr['R']['font-family'] . ';';
15282 }
15283 if (isset($arr['R']['color'])) {
15284 $html .= ' color: ' . $arr['R']['color'] . ';';
15285 }
15286 if (isset($arr['R']['font-size'])) {
15287 $html .= ' font-size: ' . $arr['R']['font-size'] . 'pt;';
15288 }
15289 if (isset($arr['R']['font-style'])) {
15290 if ($arr['R']['font-style'] == 'B' || $arr['R']['font-style'] == 'BI') {
15291 $html .= ' font-weight: bold;';
15292 }
15293 if ($arr['R']['font-style'] == 'I' || $arr['R']['font-style'] == 'BI') {
15294 $html .= ' font-style: italic;';
15295 }
15296 }
15297 $html .= '">' . $rContent . '</td>';
15298 $html .= '</tr></table>';
15299 return $html;
15300 }
15301
15302 function DefHeaderByName($name, $arr)
15303 {
15304 if (!$name) {
15305 $name = '_nonhtmldefault';
15306 }
15307 $html = $this->_createHTMLheaderFooter($arr, 'H');
15308
15309 $this->pageHTMLheaders[$name]['html'] = $html;
15310 $this->pageHTMLheaders[$name]['h'] = $this->_gethtmlheight($html);
15311 }
15312
15313 function DefFooterByName($name, $arr)
15314 {
15315 if (!$name) {
15316 $name = '_nonhtmldefault';
15317 }
15318 $html = $this->_createHTMLheaderFooter($arr, 'F');
15319
15320 $this->pageHTMLfooters[$name]['html'] = $html;
15321 $this->pageHTMLfooters[$name]['h'] = $this->_gethtmlheight($html);
15322 }
15323
15324 function SetHeaderByName($name, $side = 'O', $write = false)
15325 {
15326 if (!$name) {
15327 $name = '_nonhtmldefault';
15328 }
15329 $this->SetHTMLHeader($this->pageHTMLheaders[$name], $side, $write);
15330 }
15331
15332 function SetFooterByName($name, $side = 'O')
15333 {
15334 if (!$name) {
15335 $name = '_nonhtmldefault';
15336 }
15337 $this->SetHTMLFooter($this->pageHTMLfooters[$name], $side);
15338 }
15339
15340 function DefHTMLHeaderByName($name, $html)
15341 {
15342 if (!$name) {
15343 $name = '_default';
15344 }
15345
15346 $this->pageHTMLheaders[$name]['html'] = $html;
15347 $this->pageHTMLheaders[$name]['h'] = $this->_gethtmlheight($html);
15348 }
15349
15350 function DefHTMLFooterByName($name, $html)
15351 {
15352 if (!$name) {
15353 $name = '_default';
15354 }
15355
15356 $this->pageHTMLfooters[$name]['html'] = $html;
15357 $this->pageHTMLfooters[$name]['h'] = $this->_gethtmlheight($html);
15358 }
15359
15360 function SetHTMLHeaderByName($name, $side = 'O', $write = false)
15361 {
15362 if (!$name) {
15363 $name = '_default';
15364 }
15365 $this->SetHTMLHeader($this->pageHTMLheaders[$name], $side, $write);
15366 }
15367
15368 function SetHTMLFooterByName($name, $side = 'O')
15369 {
15370 if (!$name) {
15371 $name = '_default';
15372 }
15373 $this->SetHTMLFooter($this->pageHTMLfooters[$name], $side);
15374 }
15375
15376 function SetHeader($Harray = array(), $side = '', $write = false)
15377 {
15378 $oddhtml = '';
15379 $evenhtml = '';
15380 if (is_string($Harray)) {
15381 if (strlen($Harray) == 0) {
15382 $oddhtml = '';
15383 $evenhtml = '';
15384 } elseif (strpos($Harray, '|') !== false) {
15385 $hdet = explode('|', $Harray);
15386 list($lw, $cw, $rw) = $this->_shareHeaderFooterWidth($hdet[0], $hdet[1], $hdet[2]);
15387 $oddhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: bottom; color: #000000; ';
15388 if ($this->defaultheaderfontsize) {
15389 $oddhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
15390 }
15391 if ($this->defaultheaderfontstyle) {
15392 if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
15393 $oddhtml .= ' font-weight: bold;';
15394 }
15395 if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
15396 $oddhtml .= ' font-style: italic;';
15397 }
15398 }
15399 if ($this->defaultheaderline) {
15400 $oddhtml .= ' border-bottom: 0.1mm solid #000000;';
15401 }
15402 $oddhtml .= '">';
15403 $oddhtml .= '<tr>';
15404 $oddhtml .= '<td width="' . $lw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: left; ">' . $hdet[0] . '</td>';
15405 $oddhtml .= '<td width="' . $cw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: center; ">' . $hdet[1] . '</td>';
15406 $oddhtml .= '<td width="' . $rw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: right; ">' . $hdet[2] . '</td>';
15407 $oddhtml .= '</tr></table>';
15408
15409 $evenhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: bottom; color: #000000; ';
15410 if ($this->defaultheaderfontsize) {
15411 $evenhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
15412 }
15413 if ($this->defaultheaderfontstyle) {
15414 if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
15415 $evenhtml .= ' font-weight: bold;';
15416 }
15417 if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
15418 $evenhtml .= ' font-style: italic;';
15419 }
15420 }
15421 if ($this->defaultheaderline) {
15422 $evenhtml .= ' border-bottom: 0.1mm solid #000000;';
15423 }
15424 $evenhtml .= '">';
15425 $evenhtml .= '<tr>';
15426 $evenhtml .= '<td width="' . $rw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: left; ">' . $hdet[2] . '</td>';
15427 $evenhtml .= '<td width="' . $cw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: center; ">' . $hdet[1] . '</td>';
15428 $evenhtml .= '<td width="' . $lw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: right; ">' . $hdet[0] . '</td>';
15429 $evenhtml .= '</tr></table>';
15430 } else {
15431 $oddhtml = '<div style="margin: 0; color: #000000; ';
15432 if ($this->defaultheaderfontsize) {
15433 $oddhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
15434 }
15435 if ($this->defaultheaderfontstyle) {
15436 if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
15437 $oddhtml .= ' font-weight: bold;';
15438 }
15439 if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
15440 $oddhtml .= ' font-style: italic;';
15441 }
15442 }
15443 if ($this->defaultheaderline) {
15444 $oddhtml .= ' border-bottom: 0.1mm solid #000000;';
15445 }
15446 $oddhtml .= 'text-align: right; ">' . $Harray . '</div>';
15447
15448 $evenhtml = '<div style="margin: 0; color: #000000; ';
15449 if ($this->defaultheaderfontsize) {
15450 $evenhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
15451 }
15452 if ($this->defaultheaderfontstyle) {
15453 if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
15454 $evenhtml .= ' font-weight: bold;';
15455 }
15456 if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
15457 $evenhtml .= ' font-style: italic;';
15458 }
15459 }
15460 if ($this->defaultheaderline) {
15461 $evenhtml .= ' border-bottom: 0.1mm solid #000000;';
15462 }
15463 $evenhtml .= 'text-align: left; ">' . $Harray . '</div>';
15464 }
15465 } elseif (is_array($Harray) && !empty($Harray)) {
15466 if ($side == 'O') {
15467 $odd = $Harray;
15468 } elseif ($side == 'E') {
15469 $even = $Harray;
15470 } else {
15471 $odd = $Harray['odd'];
15472 $even = $Harray['even'];
15473 }
15474 $oddhtml = $this->_createHTMLheaderFooter($odd, 'H');
15475
15476 $evenhtml = $this->_createHTMLheaderFooter($even, 'H');
15477 }
15478
15479 if ($side == 'E') {
15480 $this->SetHTMLHeader($evenhtml, 'E', $write);
15481 } elseif ($side == 'O') {
15482 $this->SetHTMLHeader($oddhtml, 'O', $write);
15483 } else {
15484 $this->SetHTMLHeader($oddhtml, 'O', $write);
15485 $this->SetHTMLHeader($evenhtml, 'E', $write);
15486 }
15487 }
15488
15489 function SetFooter($Farray = array(), $side = '')
15490 {
15491 $oddhtml = '';
15492 $evenhtml = '';
15493 if (is_string($Farray)) {
15494 if (strlen($Farray) == 0) {
15495 $oddhtml = '';
15496 $evenhtml = '';
15497 } elseif (strpos($Farray, '|') !== false) {
15498 $hdet = explode('|', $Farray);
15499 $oddhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: top; color: #000000; ';
15500 if ($this->defaultfooterfontsize) {
15501 $oddhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
15502 }
15503 if ($this->defaultfooterfontstyle) {
15504 if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
15505 $oddhtml .= ' font-weight: bold;';
15506 }
15507 if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
15508 $oddhtml .= ' font-style: italic;';
15509 }
15510 }
15511 if ($this->defaultfooterline) {
15512 $oddhtml .= ' border-top: 0.1mm solid #000000;';
15513 }
15514 $oddhtml .= '">';
15515 $oddhtml .= '<tr>';
15516 $oddhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: left; ">' . $hdet[0] . '</td>';
15517 $oddhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: center; ">' . $hdet[1] . '</td>';
15518 $oddhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: right; ">' . $hdet[2] . '</td>';
15519 $oddhtml .= '</tr></table>';
15520
15521 $evenhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: top; color: #000000; ';
15522 if ($this->defaultfooterfontsize) {
15523 $evenhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
15524 }
15525 if ($this->defaultfooterfontstyle) {
15526 if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
15527 $evenhtml .= ' font-weight: bold;';
15528 }
15529 if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
15530 $evenhtml .= ' font-style: italic;';
15531 }
15532 }
15533 if ($this->defaultfooterline) {
15534 $evenhtml .= ' border-top: 0.1mm solid #000000;';
15535 }
15536 $evenhtml .= '">';
15537 $evenhtml .= '<tr>';
15538 $evenhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: left; ">' . $hdet[2] . '</td>';
15539 $evenhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: center; ">' . $hdet[1] . '</td>';
15540 $evenhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: right; ">' . $hdet[0] . '</td>';
15541 $evenhtml .= '</tr></table>';
15542 } else {
15543 $oddhtml = '<div style="margin: 0; color: #000000; ';
15544 if ($this->defaultfooterfontsize) {
15545 $oddhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
15546 }
15547 if ($this->defaultfooterfontstyle) {
15548 if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
15549 $oddhtml .= ' font-weight: bold;';
15550 }
15551 if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
15552 $oddhtml .= ' font-style: italic;';
15553 }
15554 }
15555 if ($this->defaultfooterline) {
15556 $oddhtml .= ' border-top: 0.1mm solid #000000;';
15557 }
15558 $oddhtml .= 'text-align: right; ">' . $Farray . '</div>';
15559
15560 $evenhtml = '<div style="margin: 0; color: #000000; ';
15561 if ($this->defaultfooterfontsize) {
15562 $evenhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
15563 }
15564 if ($this->defaultfooterfontstyle) {
15565 if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
15566 $evenhtml .= ' font-weight: bold;';
15567 }
15568 if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
15569 $evenhtml .= ' font-style: italic;';
15570 }
15571 }
15572 if ($this->defaultfooterline) {
15573 $evenhtml .= ' border-top: 0.1mm solid #000000;';
15574 }
15575 $evenhtml .= 'text-align: left; ">' . $Farray . '</div>';
15576 }
15577 } elseif (is_array($Farray)) {
15578 if ($side == 'O') {
15579 $odd = $Farray;
15580 } elseif ($side == 'E') {
15581 $even = $Farray;
15582 } else {
15583 if (isset($Farray['odd']))
15584 $odd = $Farray['odd'];
15585 if (isset($Farray['even']))
15586 $even = $Farray['even'];
15587 }
15588
15589 if (isset($odd))
15590 $oddhtml = $this->_createHTMLheaderFooter($odd, 'F');
15591
15592 if (isset($even))
15593 $evenhtml = $this->_createHTMLheaderFooter($even, 'F');
15594 }
15595 /* -- HTMLfooterS-FOOTERS -- */
15596 if ($side == 'E') {
15597 $this->SetHTMLfooter($evenhtml, 'E');
15598 } elseif ($side == 'O') {
15599 $this->SetHTMLfooter($oddhtml, 'O');
15600 } else {
15601 $this->SetHTMLfooter($oddhtml, 'O');
15602 $this->SetHTMLfooter($evenhtml, 'E');
15603 }
15604 /* -- END HTMLfooterS-FOOTERS -- */
15605 }
15606
15607 /* -- WATERMARK -- */
15608
15609 function SetWatermarkText($txt = '', $alpha = -1)
15610 {
15611 if ($alpha >= 0)
15612 $this->watermarkTextAlpha = $alpha;
15613 $this->watermarkText = $txt;
15614 }
15615
15616 function SetWatermarkImage($src, $alpha = -1, $size = 'D', $pos = 'F')
15617 {
15618 if ($alpha >= 0)
15619 $this->watermarkImageAlpha = $alpha;
15620 $this->watermarkImage = $src;
15621 $this->watermark_size = $size;
15622 $this->watermark_pos = $pos;
15623 }
15624
15625 /* -- END WATERMARK -- */
15626
15627 //Page footer
15628 function Footer()
15629 {
15630 /* -- CSS-PAGE -- */
15631 // PAGED MEDIA - CROP / CROSS MARKS from @PAGE
15632 if ($this->show_marks == 'CROP' || $this->show_marks == 'CROPCROSS') {
15633 // Show TICK MARKS
15634 $this->SetLineWidth(0.1); // = 0.1 mm
15635 $this->SetDColor($this->ConvertColor(0));
15636 $l = $this->cropMarkLength;
15637 $m = $this->cropMarkMargin; // Distance of crop mark from margin
15638 $b = $this->nonPrintMargin; // Non-printable border at edge of paper sheet
15639 $ax1 = $b;
15640 $bx = $this->page_box['outer_width_LR'] - $m;
15641 $ax = max($ax1, $bx - $l);
15642 $cx1 = $this->w - $b;
15643 $dx = $this->w - $this->page_box['outer_width_LR'] + $m;
15644 $cx = min($cx1, $dx + $l);
15645 $ay1 = $b;
15646 $by = $this->page_box['outer_width_TB'] - $m;
15647 $ay = max($ay1, $by - $l);
15648 $cy1 = $this->h - $b;
15649 $dy = $this->h - $this->page_box['outer_width_TB'] + $m;
15650 $cy = min($cy1, $dy + $l);
15651
15652 $this->Line($ax, $this->page_box['outer_width_TB'], $bx, $this->page_box['outer_width_TB']);
15653 $this->Line($cx, $this->page_box['outer_width_TB'], $dx, $this->page_box['outer_width_TB']);
15654 $this->Line($ax, $this->h - $this->page_box['outer_width_TB'], $bx, $this->h - $this->page_box['outer_width_TB']);
15655 $this->Line($cx, $this->h - $this->page_box['outer_width_TB'], $dx, $this->h - $this->page_box['outer_width_TB']);
15656 $this->Line($this->page_box['outer_width_LR'], $ay, $this->page_box['outer_width_LR'], $by);
15657 $this->Line($this->page_box['outer_width_LR'], $cy, $this->page_box['outer_width_LR'], $dy);
15658 $this->Line($this->w - $this->page_box['outer_width_LR'], $ay, $this->w - $this->page_box['outer_width_LR'], $by);
15659 $this->Line($this->w - $this->page_box['outer_width_LR'], $cy, $this->w - $this->page_box['outer_width_LR'], $dy);
15660
15661 if ($this->printers_info) {
15662 $hd = date('Y-m-d H:i') . ' Page ' . $this->page . ' of {nb}';
15663 $this->SetTColor($this->ConvertColor(0));
15664 $this->SetFont('arial', '', 7.5, true, true);
15665 $this->x = $this->page_box['outer_width_LR'] + 1.5;
15666 $this->y = 1;
15667 $this->Cell($headerpgwidth, $this->FontSize, $hd, 0, 0, 'L', 0, '', 0, 0, 0, 'M');
15668 $this->SetFont($this->default_font, '', $this->original_default_font_size);
15669 }
15670 }
15671 if ($this->show_marks == 'CROSS' || $this->show_marks == 'CROPCROSS') {
15672 $this->SetLineWidth(0.1); // = 0.1 mm
15673 $this->SetDColor($this->ConvertColor(0));
15674 $l = 14 / 2; // longer length of the cross line (half)
15675 $w = 6 / 2; // shorter width of the cross line (half)
15676 $r = 1.2; // radius of circle
15677 $m = $this->crossMarkMargin; // Distance of cross mark from margin
15678 $x1 = $this->page_box['outer_width_LR'] - $m;
15679 $x2 = $this->w - $this->page_box['outer_width_LR'] + $m;
15680 $y1 = $this->page_box['outer_width_TB'] - $m;
15681 $y2 = $this->h - $this->page_box['outer_width_TB'] + $m;
15682 // Left
15683 $this->Circle($x1, $this->h / 2, $r, 'S');
15684 $this->Line($x1 - $w, $this->h / 2, $x1 + $w, $this->h / 2);
15685 $this->Line($x1, $this->h / 2 - $l, $x1, $this->h / 2 + $l);
15686 // Right
15687 $this->Circle($x2, $this->h / 2, $r, 'S');
15688 $this->Line($x2 - $w, $this->h / 2, $x2 + $w, $this->h / 2);
15689 $this->Line($x2, $this->h / 2 - $l, $x2, $this->h / 2 + $l);
15690 // Top
15691 $this->Circle($this->w / 2, $y1, $r, 'S');
15692 $this->Line($this->w / 2, $y1 - $w, $this->w / 2, $y1 + $w);
15693 $this->Line($this->w / 2 - $l, $y1, $this->w / 2 + $l, $y1);
15694 // Bottom
15695 $this->Circle($this->w / 2, $y2, $r, 'S');
15696 $this->Line($this->w / 2, $y2 - $w, $this->w / 2, $y2 + $w);
15697 $this->Line($this->w / 2 - $l, $y2, $this->w / 2 + $l, $y2);
15698 }
15699
15700 /* -- END CSS-PAGE -- */
15701
15702 // mPDF 6
15703 // If @page set non-HTML headers/footers named, they were not read until later in the HTML code - so now set them
15704 if ($this->page == 1) {
15705 if ($this->firstPageBoxHeader) {
15706 if (isset($this->pageHTMLheaders[$this->firstPageBoxHeader])) {
15707 $this->HTMLHeader = $this->pageHTMLheaders[$this->firstPageBoxHeader];
15708 }
15709 $this->Header();
15710 }
15711 if ($this->firstPageBoxFooter) {
15712 if (isset($this->pageHTMLfooters[$this->firstPageBoxFooter])) {
15713 $this->HTMLFooter = $this->pageHTMLfooters[$this->firstPageBoxFooter];
15714 }
15715 }
15716 $this->firstPageBoxHeader = '';
15717 $this->firstPageBoxFooter = '';
15718 }
15719
15720
15721 if (($this->mirrorMargins && ($this->page % 2 == 0) && $this->HTMLFooterE) || ($this->mirrorMargins && ($this->page % 2 == 1) && $this->HTMLFooter) || (!$this->mirrorMargins && $this->HTMLFooter)) {
15722 $this->writeHTMLFooters();
15723 }
15724
15725 /* -- WATERMARK -- */
15726 if (($this->watermarkText) && ($this->showWatermarkText)) {
15727 $this->watermark($this->watermarkText, 45, 120, $this->watermarkTextAlpha); // Watermark text
15728 }
15729 if (($this->watermarkImage) && ($this->showWatermarkImage)) {
15730 $this->watermarkImg($this->watermarkImage, $this->watermarkImageAlpha); // Watermark image
15731 }
15732 /* -- END WATERMARK -- */
15733 }
15734
15735 /* -- HYPHENATION -- */
15736
15737 ///////////////////
15738 ///////////////////
15739 // HYPHENATION
15740 ///////////////////
15741 ///////////////////
15742 // Word hyphenation
15743 // mPDF 6
15744 function hyphenateWord($word, $currptr)
15745 {
15746 // Do everything inside this function in utf-8
15747 // Don't hyphenate web addresses
15748 if (preg_match('/^(http:|www\.)/', $word)) {
15749 return -1;
15750 }
15751
15752 $ptr = -1;
15753
15754 // Get dictionary
15755 if (!$this->loadedSHYdictionary) {
15756 if (file_exists(_MPDF_PATH . 'patterns/dictionary.txt')) {
15757 $this->SHYdictionary = file(_MPDF_PATH . 'patterns/dictionary.txt', FILE_SKIP_EMPTY_LINES);
15758 foreach ($this->SHYdictionary as $entry) {
15759 $entry = trim($entry);
15760 $poss = array();
15761 $offset = 0;
15762 $p = true;
15763 $wl = mb_strlen($entry, 'UTF-8');
15764 while ($offset < $wl) {
15765 $p = mb_strpos($entry, '/', $offset, 'UTF-8');
15766 if ($p !== false) {
15767 $poss[] = $p - count($poss);
15768 } else {
15769 break;
15770 }
15771 $offset = $p + 1;
15772 }
15773 if (count($poss)) {
15774 $this->SHYdictionaryWords[str_replace('/', '', mb_strtolower($entry))] = $poss;
15775 }
15776 }
15777 }
15778 $this->loadedSHYdictionary = true;
15779 }
15780
15781 if (!in_array($this->SHYlang, $this->SHYlanguages)) {
15782 return -1;
15783 }
15784 // If no pattern loaded or not the best one
15785 if (count($this->SHYpatterns) < 1 || ($this->loadedSHYpatterns && $this->loadedSHYpatterns != $this->SHYlang)) {
15786 include(_MPDF_PATH . "patterns/" . $this->SHYlang . ".php");
15787 $patterns = explode(' ', $patterns);
15788 $new_patterns = array();
15789 for ($i = 0; $i < count($patterns); $i++) {
15790 $value = $patterns[$i];
15791 $new_patterns[preg_replace('/[0-9]/', '', $value)] = $value;
15792 }
15793 $this->SHYpatterns = $new_patterns;
15794 $this->loadedSHYpatterns = $this->SHYlang;
15795 }
15796
15797 if ($this->usingCoreFont) {
15798 $word = mb_convert_encoding($word, 'UTF-8', $this->mb_enc);
15799 }
15800
15801 $prepre = '';
15802 $postpost = '';
15803 $startpunctuation = "\xc2\xab\xc2\xbf\xe2\x80\x98\xe2\x80\x9b\xe2\x80\x9c\xe2\x80\x9f";
15804 $endpunctuation = "\xe2\x80\x9e\xe2\x80\x9d\xe2\x80\x9a\xe2\x80\x99\xc2\xbb";
15805
15806
15807 if (preg_match('/^(["\'' . $startpunctuation . '])+(.{' . $this->SHYcharmin . ',})$/u', $word, $m)) {
15808 $prepre = $m[1];
15809 $word = $m[2];
15810 }
15811 if (preg_match('/^(.{' . $this->SHYcharmin . ',})([\'\.,;:!?"' . $endpunctuation . ']+)$/u', $word, $m)) {
15812 $word = $m[1];
15813 $postpost = $m[2];
15814 }
15815 if (mb_strlen($word, 'UTF-8') < $this->SHYcharmin) {
15816 return -1;
15817 }
15818 $success = false;
15819
15820 $preprelen = mb_strlen($prepre);
15821
15822 if (isset($this->SHYdictionaryWords[mb_strtolower($word)])) {
15823 foreach ($this->SHYdictionaryWords[mb_strtolower($word)] AS $i) {
15824 if (($i + $preprelen) >= $currptr) {
15825 break;
15826 }
15827 $ptr = $i + $preprelen;
15828 $success = true;
15829 }
15830 }
15831
15832 if (!$success) {
15833 $text_word = '_' . $word . '_';
15834 $word_length = mb_strlen($text_word, 'UTF-8');
15835 $text_word = mb_strtolower($text_word, 'UTF-8');
15836 $hyphenated_word = array();
15837 $numb3rs = array('0' => true, '1' => true, '2' => true, '3' => true, '4' => true, '5' => true, '6' => true, '7' => true, '8' => true, '9' => true);
15838 for ($position = 0; $position <= ($word_length - $this->SHYcharmin); $position++) {
15839 $maxwins = min(($word_length - $position), $this->SHYcharmax);
15840 for ($win = $this->SHYcharmin; $win <= $maxwins; $win++) {
15841 if (isset($this->SHYpatterns[mb_substr($text_word, $position, $win, 'UTF-8')])) {
15842 $pattern = $this->SHYpatterns[mb_substr($text_word, $position, $win, 'UTF-8')];
15843 $digits = 1;
15844 $pattern_length = mb_strlen($pattern, 'UTF-8');
15845 for ($i = 0; $i < $pattern_length; $i++) {
15846 $char = $pattern[$i];
15847 if (isset($numb3rs[$char])) {
15848 $zero = ($i == 0) ? $position - 1 : $position + $i - $digits;
15849 if (!isset($hyphenated_word[$zero]) || $hyphenated_word[$zero] != $char)
15850 $hyphenated_word[$zero] = $char;
15851 $digits++;
15852 }
15853 }
15854 }
15855 }
15856 }
15857 for ($i = $this->SHYleftmin; $i <= (mb_strlen($word, 'UTF-8') - $this->SHYrightmin); $i++) {
15858 if (isset($hyphenated_word[$i]) && $hyphenated_word[$i] % 2 != 0) {
15859 if (($i + $preprelen) > $currptr) {
15860 break;
15861 }
15862 $ptr = $i + $preprelen;
15863 }
15864 }
15865 }
15866 return $ptr;
15867 }
15868
15869 /* -- END HYPHENATION -- */
15870
15871
15872 /* -- HTML-CSS -- */
15873
15874 ///////////////////
15875 /// HTML parser ///
15876 ///////////////////
15877 function WriteHTML($html, $sub = 0, $init = true, $close = true)
15878 {
15879 // $sub - 0 = default; 1=headerCSS only; 2=HTML body (parts) only; 3 - HTML parses only
15880 // 4 - writes HTML headers/Fixed pos DIVs - stores in buffer - for single page only
15881 // $close - if false Leaves buffers etc. in current state, so that it can continue a block etc.
15882 // $init - Clears and sets buffers to Top level block etc.
15883
15884 /* Check $html is an integer, float, string, boolean or class with __toString(), otherwise throw exception */
15885 if (is_scalar($html) === false) {
15886 if(!is_object($html) || ! method_exists($html, '__toString')) {
15887 throw new MpdfException('WriteHTML() requires $html be an integer, float, string, boolean or an object with the __toString() magic method.');
15888 }
15889 }
15890
15891 /* Cast $html as a string */
15892 $html = (string) $html;
15893
15894 if ($this->progressBar) {
15895 $this->UpdateProgressBar(1, 0, 'Parsing CSS & Headers');
15896 } // *PROGRESS-BAR*
15897
15898 if ($init) {
15899 $this->headerbuffer = '';
15900 $this->textbuffer = array();
15901 $this->fixedPosBlockSave = array();
15902 }
15903 if ($sub == 1) {
15904 $html = '<style> ' . $html . ' </style>';
15905 } // stylesheet only
15906
15907 if ($this->allow_charset_conversion) {
15908 if ($sub < 1) {
15909 $this->ReadCharset($html);
15910 }
15911 if ($this->charset_in && $sub != 4) {
15912 $success = iconv($this->charset_in, 'UTF-8//TRANSLIT', $html);
15913 if ($success) {
15914 $html = $success;
15915 }
15916 }
15917 }
15918 $html = $this->purify_utf8($html, false);
15919 if ($init) {
15920 $this->blklvl = 0;
15921 $this->lastblocklevelchange = 0;
15922 $this->blk = array();
15923 $this->initialiseBlock($this->blk[0]);
15924 $this->blk[0]['width'] = & $this->pgwidth;
15925 $this->blk[0]['inner_width'] = & $this->pgwidth;
15926 $this->blk[0]['blockContext'] = $this->blockContext;
15927 }
15928
15929 $zproperties = array();
15930 if ($sub < 2) {
15931 $this->ReadMetaTags($html);
15932
15933 if (preg_match('/<base[^>]*href=["\']([^"\'>]*)["\']/i', $html, $m)) {
15934 $this->SetBasePath($m[1]);
15935 }
15936 $html = $this->cssmgr->ReadCSS($html);
15937
15938 if ($this->autoLangToFont && !$this->usingCoreFont && preg_match('/<html [^>]*lang=[\'\"](.*?)[\'\"]/ism', $html, $m)) {
15939 $html_lang = $m[1];
15940 }
15941
15942 if (preg_match('/<html [^>]*dir=[\'\"]\s*rtl\s*[\'\"]/ism', $html)) {
15943 $zproperties['DIRECTION'] = 'rtl';
15944 }
15945
15946 // allow in-line CSS for body tag to be parsed // Get <body> tag inline CSS
15947 if (preg_match('/<body([^>]*)>(.*?)<\/body>/ism', $html, $m) || preg_match('/<body([^>]*)>(.*)$/ism', $html, $m)) {
15948 $html = $m[2];
15949 // Changed to allow style="background: url('bg.jpg')"
15950 if (preg_match('/style=[\"](.*?)[\"]/ism', $m[1], $mm) || preg_match('/style=[\'](.*?)[\']/ism', $m[1], $mm)) {
15951 $zproperties = $this->cssmgr->readInlineCSS($mm[1]);
15952 }
15953 if (preg_match('/dir=[\'\"]\s*rtl\s*[\'\"]/ism', $m[1])) {
15954 $zproperties['DIRECTION'] = 'rtl';
15955 }
15956 if (isset($html_lang) && $html_lang) {
15957 $zproperties['LANG'] = $html_lang;
15958 }
15959 if ($this->autoLangToFont && !$this->onlyCoreFonts && preg_match('/lang=[\'\"](.*?)[\'\"]/ism', $m[1], $mm)) {
15960 $zproperties['LANG'] = $mm[1];
15961 }
15962 }
15963 }
15964 $properties = $this->cssmgr->MergeCSS('BLOCK', 'BODY', '');
15965 if ($zproperties) {
15966 $properties = $this->cssmgr->array_merge_recursive_unique($properties, $zproperties);
15967 }
15968
15969 if (isset($properties['DIRECTION']) && $properties['DIRECTION']) {
15970 $this->cssmgr->CSS['BODY']['DIRECTION'] = $properties['DIRECTION'];
15971 }
15972 if (!isset($this->cssmgr->CSS['BODY']['DIRECTION'])) {
15973 $this->cssmgr->CSS['BODY']['DIRECTION'] = $this->directionality;
15974 } else {
15975 $this->SetDirectionality($this->cssmgr->CSS['BODY']['DIRECTION']);
15976 }
15977
15978 $this->setCSS($properties, '', 'BODY');
15979
15980 $this->blk[0]['InlineProperties'] = $this->saveInlineProperties();
15981
15982 if ($sub == 1) {
15983 return '';
15984 }
15985 if (!isset($this->cssmgr->CSS['BODY'])) {
15986 $this->cssmgr->CSS['BODY'] = array();
15987 }
15988
15989 /* -- BACKGROUNDS -- */
15990 if (isset($properties['BACKGROUND-GRADIENT'])) {
15991 $this->bodyBackgroundGradient = $properties['BACKGROUND-GRADIENT'];
15992 }
15993
15994 if (isset($properties['BACKGROUND-IMAGE']) && $properties['BACKGROUND-IMAGE']) {
15995 $ret = $this->SetBackground($properties, $this->pgwidth);
15996 if ($ret) {
15997 $this->bodyBackgroundImage = $ret;
15998 }
15999 }
16000 /* -- END BACKGROUNDS -- */
16001
16002 /* -- CSS-PAGE -- */
16003 // If page-box is set
16004 if ($this->state == 0 && ((isset($this->cssmgr->CSS['@PAGE']) && $this->cssmgr->CSS['@PAGE']) || (isset($this->cssmgr->CSS['@PAGE>>PSEUDO>>FIRST']) && $this->cssmgr->CSS['@PAGE>>PSEUDO>>FIRST']))) { // mPDF 5.7.3
16005 $this->page_box['current'] = '';
16006 $this->page_box['using'] = true;
16007 list($pborientation, $pbmgl, $pbmgr, $pbmgt, $pbmgb, $pbmgh, $pbmgf, $hname, $fname, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat) = $this->SetPagedMediaCSS('', false, 'O');
16008 $this->DefOrientation = $this->CurOrientation = $pborientation;
16009 $this->orig_lMargin = $this->DeflMargin = $pbmgl;
16010 $this->orig_rMargin = $this->DefrMargin = $pbmgr;
16011 $this->orig_tMargin = $this->tMargin = $pbmgt;
16012 $this->orig_bMargin = $this->bMargin = $pbmgb;
16013 $this->orig_hMargin = $this->margin_header = $pbmgh;
16014 $this->orig_fMargin = $this->margin_footer = $pbmgf;
16015 list($pborientation, $pbmgl, $pbmgr, $pbmgt, $pbmgb, $pbmgh, $pbmgf, $hname, $fname, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat) = $this->SetPagedMediaCSS('', true, 'O'); // first page
16016 $this->show_marks = $marks;
16017 if ($hname)
16018 $this->firstPageBoxHeader = $hname;
16019 if ($fname)
16020 $this->firstPageBoxFooter = $fname;
16021 }
16022 /* -- END CSS-PAGE -- */
16023
16024 $parseonly = false;
16025 $this->bufferoutput = false;
16026 if ($sub == 3) {
16027 $parseonly = true;
16028 // Close any open block tags
16029 $arr = array();
16030 $ai = 0;
16031 for ($b = $this->blklvl; $b > 0; $b--) {
16032 $this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
16033 }
16034 // Output any text left in buffer
16035 if (count($this->textbuffer)) {
16036 $this->printbuffer($this->textbuffer);
16037 }
16038 $this->textbuffer = array();
16039 } elseif ($sub == 4) {
16040 // Close any open block tags
16041 $arr = array();
16042 $ai = 0;
16043 for ($b = $this->blklvl; $b > 0; $b--) {
16044 $this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
16045 }
16046 // Output any text left in buffer
16047 if (count($this->textbuffer)) {
16048 $this->printbuffer($this->textbuffer);
16049 }
16050 $this->bufferoutput = true;
16051 $this->textbuffer = array();
16052 $this->headerbuffer = '';
16053 $properties = $this->cssmgr->MergeCSS('BLOCK', 'BODY', '');
16054 $this->setCSS($properties, '', 'BODY');
16055 }
16056
16057 mb_internal_encoding('UTF-8');
16058
16059 $html = $this->AdjustHTML($html, $this->tabSpaces); //Try to make HTML look more like XHTML
16060
16061 if ($this->autoScriptToLang) {
16062 $html = $this->markScriptToLang($html);
16063 }
16064
16065 preg_match_all('/<htmlpageheader([^>]*)>(.*?)<\/htmlpageheader>/si', $html, $h);
16066 for ($i = 0; $i < count($h[1]); $i++) {
16067 if (preg_match('/name=[\'|\"](.*?)[\'|\"]/', $h[1][$i], $n)) {
16068 $this->pageHTMLheaders[$n[1]]['html'] = $h[2][$i];
16069 $this->pageHTMLheaders[$n[1]]['h'] = $this->_gethtmlheight($h[2][$i]);
16070 }
16071 }
16072 preg_match_all('/<htmlpagefooter([^>]*)>(.*?)<\/htmlpagefooter>/si', $html, $f);
16073 for ($i = 0; $i < count($f[1]); $i++) {
16074 if (preg_match('/name=[\'|\"](.*?)[\'|\"]/', $f[1][$i], $n)) {
16075 $this->pageHTMLfooters[$n[1]]['html'] = $f[2][$i];
16076 $this->pageHTMLfooters[$n[1]]['h'] = $this->_gethtmlheight($f[2][$i]);
16077 }
16078 }
16079
16080 $html = preg_replace('/<htmlpageheader.*?<\/htmlpageheader>/si', '', $html);
16081 $html = preg_replace('/<htmlpagefooter.*?<\/htmlpagefooter>/si', '', $html);
16082
16083 if ($this->state == 0 && $sub != 1 && $sub != 3 && $sub != 4) {
16084 $this->AddPage($this->CurOrientation);
16085 }
16086
16087
16088 if (isset($hname) && preg_match('/^html_(.*)$/i', $hname, $n))
16089 $this->SetHTMLHeader($this->pageHTMLheaders[$n[1]], 'O', true);
16090 if (isset($fname) && preg_match('/^html_(.*)$/i', $fname, $n))
16091 $this->SetHTMLFooter($this->pageHTMLfooters[$n[1]], 'O');
16092
16093
16094
16095 $html = str_replace('<?', '< ', $html); //Fix '<?XML' bug from HTML code generated by MS Word
16096
16097 $this->checkSIP = false;
16098 $this->checkSMP = false;
16099 $this->checkCJK = false;
16100 if ($this->onlyCoreFonts) {
16101 $html = $this->SubstituteChars($html);
16102 } else {
16103 if (preg_match("/([" . $this->pregRTLchars . "])/u", $html)) {
16104 $this->biDirectional = true;
16105 } // *OTL*
16106 if (preg_match("/([\x{20000}-\x{2FFFF}])/u", $html)) {
16107 $this->checkSIP = true;
16108 }
16109 if (preg_match("/([\x{10000}-\x{1FFFF}])/u", $html)) {
16110 $this->checkSMP = true;
16111 }
16112 /* -- CJK-FONTS -- */
16113 if (preg_match("/([" . $this->pregCJKchars . "])/u", $html)) {
16114 $this->checkCJK = true;
16115 }
16116 /* -- END CJK-FONTS -- */
16117 }
16118
16119 // Don't allow non-breaking spaces that are converted to substituted chars or will break anyway and mess up table width calc.
16120 $html = str_replace('<tta>160</tta>', chr(32), $html);
16121 $html = str_replace('</tta><tta>', '|', $html);
16122 $html = str_replace('</tts><tts>', '|', $html);
16123 $html = str_replace('</ttz><ttz>', '|', $html);
16124
16125 //Add new supported tags in the DisableTags function
16126 $html = strip_tags($html, $this->enabledtags); //remove all unsupported tags, but the ones inside the 'enabledtags' string
16127 //Explode the string in order to parse the HTML code
16128 $a = preg_split('/<(.*?)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
16129 // ? more accurate regexp that allows e.g. <a name="Silly <name>">
16130 // if changing - also change in fn.SubstituteChars()
16131 // $a = preg_split ('/<((?:[^<>]+(?:"[^"]*"|\'[^\']*\')?)+)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
16132
16133 if ($this->mb_enc) {
16134 mb_internal_encoding($this->mb_enc);
16135 }
16136 $pbc = 0;
16137 if ($this->progressBar) {
16138 $this->UpdateProgressBar(1, 0);
16139 } // *PROGRESS-BAR*
16140 $this->subPos = -1;
16141 $cnt = count($a);
16142 for ($i = 0; $i < $cnt; $i++) {
16143 $e = $a[$i];
16144 if ($i % 2 == 0) {
16145 //TEXT
16146 if ($this->blk[$this->blklvl]['hide']) {
16147 continue;
16148 }
16149 if ($this->inlineDisplayOff) {
16150 continue;
16151 }
16152 if ($this->inMeter) {
16153 continue;
16154 }
16155
16156 if ($this->inFixedPosBlock) {
16157 $this->fixedPosBlock .= $e;
16158 continue;
16159 } // *CSS-POSITION*
16160 if (strlen($e) == 0) {
16161 continue;
16162 }
16163
16164 if ($this->ignorefollowingspaces && !$this->ispre) {
16165 if (strlen(ltrim($e)) == 0) {
16166 continue;
16167 }
16168 if ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats' && substr($e, 0, 1) == ' ') {
16169 $this->ignorefollowingspaces = false;
16170 $e = ltrim($e);
16171 }
16172 }
16173
16174 $this->OTLdata = NULL; // mPDF 5.7.1
16175
16176 $e = strcode2utf($e);
16177 $e = $this->lesser_entity_decode($e);
16178
16179 if ($this->usingCoreFont) {
16180 // If core font is selected in document which is not onlyCoreFonts - substitute with non-core font
16181 if ($this->useSubstitutions && !$this->onlyCoreFonts && $this->subPos < $i && !$this->specialcontent) {
16182 $cnt += $this->SubstituteCharsNonCore($a, $i, $e);
16183 }
16184 // CONVERT ENCODING
16185 $e = mb_convert_encoding($e, $this->mb_enc, 'UTF-8');
16186 if ($this->textvar & FT_UPPERCASE) {
16187 $e = mb_strtoupper($e, $this->mb_enc);
16188 } // mPDF 5.7.1
16189 elseif ($this->textvar & FT_LOWERCASE) {
16190 $e = mb_strtolower($e, $this->mb_enc);
16191 } // mPDF 5.7.1
16192 elseif ($this->textvar & FT_CAPITALIZE) {
16193 $e = mb_convert_case($e, MB_CASE_TITLE, "UTF-8");
16194 } // mPDF 5.7.1
16195 } else {
16196 if ($this->checkSIP && $this->CurrentFont['sipext'] && $this->subPos < $i && (!$this->specialcontent || !$this->useActiveForms)) {
16197 $cnt += $this->SubstituteCharsSIP($a, $i, $e);
16198 }
16199
16200 if ($this->useSubstitutions && !$this->onlyCoreFonts && $this->CurrentFont['type'] != 'Type0' && $this->subPos < $i && (!$this->specialcontent || !$this->useActiveForms)) {
16201 $cnt += $this->SubstituteCharsMB($a, $i, $e);
16202 }
16203
16204 if ($this->textvar & FT_UPPERCASE) {
16205 $e = mb_strtoupper($e, $this->mb_enc);
16206 } elseif ($this->textvar & FT_LOWERCASE) {
16207 $e = mb_strtolower($e, $this->mb_enc);
16208 } elseif ($this->textvar & FT_CAPITALIZE) {
16209 $e = mb_convert_case($e, MB_CASE_TITLE, "UTF-8");
16210 }
16211
16212 /* -- OTL -- */
16213 // Use OTL OpenType Table Layout - GSUB & GPOS
16214 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL'] && (!$this->specialcontent || !$this->useActiveForms)) {
16215 $e = $this->otl->applyOTL($e, $this->CurrentFont['useOTL']);
16216 $this->OTLdata = $this->otl->OTLdata;
16217 $this->otl->removeChar($e, $this->OTLdata, "\xef\xbb\xbf"); // Remove ZWNBSP (also Byte order mark FEFF)
16218 }
16219 /* -- END OTL -- */ else { // *OTL*
16220 // removes U+200E/U+200F LTR and RTL mark and U+200C/U+200D Zero-width Joiner and Non-joiner
16221 $e = preg_replace("/[\xe2\x80\x8c\xe2\x80\x8d\xe2\x80\x8e\xe2\x80\x8f]/u", '', $e);
16222 $e = preg_replace("/[\xef\xbb\xbf]/u", '', $e); // Remove ZWNBSP (also Byte order mark FEFF)
16223 } // *OTL*
16224 }
16225 if (($this->tts) || ($this->ttz) || ($this->tta)) {
16226 $es = explode('|', $e);
16227 $e = '';
16228 foreach ($es AS $val) {
16229 $e .= chr($val);
16230 }
16231 }
16232
16233 // FORM ELEMENTS
16234 if ($this->specialcontent) {
16235 /* -- FORMS -- */
16236 //SELECT tag (form element)
16237 if ($this->specialcontent == "type=select") {
16238 $e = ltrim($e);
16239 if (!empty($this->OTLdata)) {
16240 $this->otl->trimOTLdata($this->OTLdata, true, false);
16241 } // *OTL*
16242 $stringwidth = $this->GetStringWidth($e);
16243 if (!isset($this->selectoption['MAXWIDTH']) || $stringwidth > $this->selectoption['MAXWIDTH']) {
16244 $this->selectoption['MAXWIDTH'] = $stringwidth;
16245 }
16246 if (!isset($this->selectoption['SELECTED']) || $this->selectoption['SELECTED'] == '') {
16247 $this->selectoption['SELECTED'] = $e;
16248 if (!empty($this->OTLdata)) {
16249 $this->selectoption['SELECTED-OTLDATA'] = $this->OTLdata;
16250 } // *OTL*
16251 }
16252 // Active Forms
16253 if (isset($this->selectoption['ACTIVE']) && $this->selectoption['ACTIVE']) {
16254 $this->selectoption['ITEMS'][] = array('exportValue' => $this->selectoption['currentVAL'], 'content' => $e, 'selected' => $this->selectoption['currentSEL']);
16255 }
16256 $this->OTLdata = array();
16257 }
16258 // TEXTAREA
16259 else {
16260 $objattr = unserialize($this->specialcontent);
16261 $objattr['text'] = $e;
16262 $objattr['OTLdata'] = $this->OTLdata;
16263 $this->OTLdata = array();
16264 $te = "\xbb\xa4\xactype=textarea,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
16265 if ($this->tdbegin) {
16266 $this->_saveCellTextBuffer($te, $this->HREF);
16267 } else {
16268 $this->_saveTextBuffer($te, $this->HREF);
16269 }
16270 }
16271 /* -- END FORMS -- */
16272 }
16273
16274 // TABLE
16275 elseif ($this->tableLevel) {
16276 /* -- TABLES -- */
16277 if ($this->tdbegin) {
16278 if (($this->ignorefollowingspaces) && !$this->ispre) {
16279 $e = ltrim($e);
16280 if (!empty($this->OTLdata)) {
16281 $this->otl->trimOTLdata($this->OTLdata, true, false);
16282 } // *OTL*
16283 }
16284 if ($e || $e === '0') {
16285 if ($this->blockjustfinished && $this->cell[$this->row][$this->col]['s'] > 0) {
16286 $this->_saveCellTextBuffer("\n");
16287 if (!isset($this->cell[$this->row][$this->col]['maxs'])) {
16288 $this->cell[$this->row][$this->col]['maxs'] = $this->cell[$this->row][$this->col]['s'];
16289 } elseif ($this->cell[$this->row][$this->col]['maxs'] < $this->cell[$this->row][$this->col]['s']) {
16290 $this->cell[$this->row][$this->col]['maxs'] = $this->cell[$this->row][$this->col]['s'];
16291 }
16292 $this->cell[$this->row][$this->col]['s'] = 0; // reset
16293 }
16294 $this->blockjustfinished = false;
16295
16296 if (!isset($this->cell[$this->row][$this->col]['R']) || !$this->cell[$this->row][$this->col]['R']) {
16297 if (isset($this->cell[$this->row][$this->col]['s'])) {
16298 $this->cell[$this->row][$this->col]['s'] += $this->GetStringWidth($e, false, $this->OTLdata, $this->textvar);
16299 } else {
16300 $this->cell[$this->row][$this->col]['s'] = $this->GetStringWidth($e, false, $this->OTLdata, $this->textvar);
16301 }
16302 if (!empty($this->spanborddet)) {
16303 $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);
16304 }
16305 }
16306 $this->_saveCellTextBuffer($e, $this->HREF);
16307 if (substr($this->cell[$this->row][$this->col]['a'], 0, 1) == 'D') {
16308 $dp = $this->decimal_align[substr($this->cell[$this->row][$this->col]['a'], 0, 2)];
16309 $s = preg_split('/' . preg_quote($dp, '/') . '/', $e, 2); // ? needs to be /u if not core
16310 $s0 = $this->GetStringWidth($s[0], false);
16311 if (isset($s[1]) && $s[1]) {
16312 $s1 = $this->GetStringWidth(($s[1] . $dp), false);
16313 } else
16314 $s1 = 0;
16315 if (!isset($this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs0'])) {
16316 $this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs0'] = $s0;
16317 } else {
16318 $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']);
16319 }
16320 if (!isset($this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs1'])) {
16321 $this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs1'] = $s1;
16322 } else {
16323 $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']);
16324 }
16325 }
16326
16327 if ($this->tableLevel == 1 && $this->useGraphs) {
16328 $this->graphs[$this->currentGraphId]['data'][$this->row][$this->col] = $e;
16329 }
16330 $this->nestedtablejustfinished = false;
16331 $this->linebreakjustfinished = false;
16332 }
16333 }
16334 /* -- END TABLES -- */
16335 }
16336 // ALL ELSE
16337 else {
16338 if ($this->ignorefollowingspaces && !$this->ispre) {
16339 $e = ltrim($e);
16340 if (!empty($this->OTLdata)) {
16341 $this->otl->trimOTLdata($this->OTLdata, true, false);
16342 } // *OTL*
16343 }
16344 if ($e || $e === '0')
16345 $this->_saveTextBuffer($e, $this->HREF);
16346 }
16347 if ($e || $e === '0')
16348 $this->ignorefollowingspaces = false; // mPDF 6
16349 if (substr($e, -1, 1) == ' ' && !$this->ispre && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
16350 $this->ignorefollowingspaces = true;
16351 }
16352 } else { // TAG **
16353 if (isset($e[0]) && $e[0] == '/') {
16354 /* -- PROGRESS-BAR -- */
16355 if ($this->progressBar) { // 10% increments
16356 if (intval($i * 10 / $cnt) != $pbc) {
16357 $pbc = intval($i * 10 / $cnt);
16358 $this->UpdateProgressBar(1, $pbc * 10, $tag);
16359 }
16360 }
16361 /* -- END PROGRESS-BAR -- */
16362
16363 $endtag = trim(strtoupper(substr($e, 1)));
16364
16365
16366 /* -- CSS-POSITION -- */
16367 // mPDF 6
16368 if ($this->inFixedPosBlock) {
16369 if (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags)) {
16370 $this->fixedPosBlockDepth--;
16371 }
16372 if ($this->fixedPosBlockDepth == 0) {
16373 $this->fixedPosBlockSave[] = array($this->fixedPosBlock, $this->fixedPosBlockBBox, $this->page);
16374 $this->fixedPosBlock = '';
16375 $this->inFixedPosBlock = false;
16376 continue;
16377 }
16378 $this->fixedPosBlock .= '<' . $e . '>';
16379 continue;
16380 }
16381 /* -- END CSS-POSITION -- */
16382
16383 // mPDF 6
16384 // Correct for tags where HTML5 specifies optional end tags (see also OpenTag() )
16385 if ($this->allow_html_optional_endtags && !$parseonly) {
16386 if (isset($this->blk[$this->blklvl]['tag'])) {
16387 $closed = false;
16388 // li end tag may be omitted if there is no more content in the parent element
16389 if (!$closed && $this->blk[$this->blklvl]['tag'] == 'LI' && $endtag != 'LI' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
16390 $this->tag->CloseTag('LI', $a, $i);
16391 $closed = true;
16392 }
16393 // dd end tag may be omitted if there is no more content in the parent element
16394 if (!$closed && $this->blk[$this->blklvl]['tag'] == 'DD' && $endtag != 'DD' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
16395 $this->tag->CloseTag('DD', $a, $i);
16396 $closed = true;
16397 }
16398 // 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 [??????]
16399 if (!$closed && $this->blk[$this->blklvl]['tag'] == 'P' && $endtag != 'P' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
16400 $this->tag->CloseTag('P', $a, $i);
16401 $closed = true;
16402 }
16403 // option end tag may be omitted if there is no more content in the parent element
16404 if (!$closed && $this->blk[$this->blklvl]['tag'] == 'OPTION' && $endtag != 'OPTION' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
16405 $this->tag->CloseTag('OPTION', $a, $i);
16406 $closed = true;
16407 }
16408 }
16409 /* -- TABLES -- */
16410 // Check for Table tags where HTML specifies optional end tags,
16411 if ($endtag == 'TABLE') {
16412 if ($this->lastoptionaltag == 'THEAD' || $this->lastoptionaltag == 'TBODY' || $this->lastoptionaltag == 'TFOOT') {
16413 $this->tag->CloseTag($this->lastoptionaltag, $a, $i);
16414 }
16415 if ($this->lastoptionaltag == 'TR') {
16416 $this->tag->CloseTag('TR', $a, $i);
16417 }
16418 if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') {
16419 $this->tag->CloseTag($this->lastoptionaltag, $a, $i);
16420 $this->tag->CloseTag('TR', $a, $i);
16421 }
16422 }
16423 if ($endtag == 'THEAD' || $endtag == 'TBODY' || $endtag == 'TFOOT') {
16424 if ($this->lastoptionaltag == 'TR') {
16425 $this->tag->CloseTag('TR', $a, $i);
16426 }
16427 if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') {
16428 $this->tag->CloseTag($this->lastoptionaltag, $a, $i);
16429 $this->tag->CloseTag('TR', $a, $i);
16430 }
16431 }
16432 if ($endtag == 'TR') {
16433 if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') {
16434 $this->tag->CloseTag($this->lastoptionaltag, $a, $i);
16435 }
16436 }
16437 /* -- END TABLES -- */
16438 }
16439
16440
16441 // mPDF 6
16442 if ($this->blk[$this->blklvl]['hide']) {
16443 if (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags)) {
16444 unset($this->blk[$this->blklvl]);
16445 $this->blklvl--;
16446 }
16447 continue;
16448 }
16449
16450 // mPDF 6
16451 $this->tag->CloseTag($endtag, $a, $i); // mPDF 6
16452 } else { // OPENING TAG
16453 if ($this->blk[$this->blklvl]['hide']) {
16454 if (strpos($e, ' ')) {
16455 $te = strtoupper(substr($e, 0, strpos($e, ' ')));
16456 } else {
16457 $te = strtoupper($e);
16458 }
16459 // mPDF 6
16460 if ($te == 'THEAD' || $te == 'TBODY' || $te == 'TFOOT' || $te == 'TR' || $te == 'TD' || $te == 'TH') {
16461 $this->lastoptionaltag = $te;
16462 }
16463 if (in_array($te, $this->outerblocktags) || in_array($te, $this->innerblocktags)) {
16464 $this->blklvl++;
16465 $this->blk[$this->blklvl]['hide'] = true;
16466 $this->blk[$this->blklvl]['tag'] = $te; // mPDF 6
16467 }
16468 continue;
16469 }
16470
16471 /* -- CSS-POSITION -- */
16472 if ($this->inFixedPosBlock) {
16473 if (strpos($e, ' ')) {
16474 $te = strtoupper(substr($e, 0, strpos($e, ' ')));
16475 } else {
16476 $te = strtoupper($e);
16477 }
16478 $this->fixedPosBlock .= '<' . $e . '>';
16479 if (in_array($te, $this->outerblocktags) || in_array($te, $this->innerblocktags)) {
16480 $this->fixedPosBlockDepth++;
16481 }
16482 continue;
16483 }
16484 /* -- END CSS-POSITION -- */
16485 $regexp = '|=\'(.*?)\'|s'; // eliminate single quotes, if any
16486 $e = preg_replace($regexp, "=\"\$1\"", $e);
16487 // changes anykey=anyvalue to anykey="anyvalue" (only do this inside [some] tags)
16488 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)
16489 $regexp = '| (\\w+?)=([^\\s>"]+)|si';
16490 $e = preg_replace($regexp, " \$1=\"\$2\"", $e);
16491 }
16492
16493 $e = preg_replace('/ (\\S+?)\s*=\s*"/i', " \\1=\"", $e);
16494
16495 //Fix path values, if needed
16496 $orig_srcpath = '';
16497 if ((stristr($e, "href=") !== false) or ( stristr($e, "src=") !== false)) {
16498 $regexp = '/ (href|src)\s*=\s*"(.*?)"/i';
16499 preg_match($regexp, $e, $auxiliararray);
16500 if (isset($auxiliararray[2])) {
16501 $path = $auxiliararray[2];
16502 } else {
16503 $path = '';
16504 }
16505 if (trim($path) != '' && !(stristr($e, "src=") !== false && substr($path, 0, 4) == 'var:') && substr($path, 0, 1) != '@') {
16506 $path = htmlspecialchars_decode($path); // mPDF 5.7.4 URLs
16507 $orig_srcpath = $path;
16508 $this->GetFullPath($path);
16509 $regexp = '/ (href|src)="(.*?)"/i';
16510 $e = preg_replace($regexp, ' \\1="' . $path . '"', $e);
16511 }
16512 }//END of Fix path values
16513 //Extract attributes
16514 $contents = array();
16515 $contents1 = array();
16516 $contents2 = array();
16517 // Changed to allow style="background: url('bg.jpg')"
16518 // Changed to improve performance; maximum length of \S (attribute) = 16
16519 // Increase allowed attribute name to 32 - cutting off "toc-even-header-name" etc.
16520 preg_match_all('/\\S{1,32}=["][^"]*["]/', $e, $contents1);
16521 preg_match_all('/\\S{1,32}=[\'][^\']*[\']/i', $e, $contents2);
16522
16523 $contents = array_merge($contents1, $contents2);
16524 preg_match('/\\S+/', $e, $a2);
16525 $tag = (isset($a2[0]) ? strtoupper($a2[0]) : '');
16526 $attr = array();
16527 if ($orig_srcpath) {
16528 $attr['ORIG_SRC'] = $orig_srcpath;
16529 }
16530 if (!empty($contents)) {
16531 foreach ($contents[0] as $v) {
16532 // Changed to allow style="background: url('bg.jpg')"
16533 if (preg_match('/^([^=]*)=["]?([^"]*)["]?$/', $v, $a3) || preg_match('/^([^=]*)=[\']?([^\']*)[\']?$/', $v, $a3)) {
16534 if (strtoupper($a3[1]) == 'ID' || strtoupper($a3[1]) == 'CLASS') { // 4.2.013 Omits STYLE
16535 $attr[strtoupper($a3[1])] = trim(strtoupper($a3[2]));
16536 }
16537 // includes header-style-right etc. used for <pageheader>
16538 elseif (preg_match('/^(HEADER|FOOTER)-STYLE/i', $a3[1])) {
16539 $attr[strtoupper($a3[1])] = trim(strtoupper($a3[2]));
16540 } else {
16541 $attr[strtoupper($a3[1])] = trim($a3[2]);
16542 }
16543 }
16544 }
16545 }
16546 $this->tag->OpenTag($tag, $attr, $a, $i); // mPDF 6
16547 /* -- CSS-POSITION -- */
16548 if ($this->inFixedPosBlock) {
16549 $this->fixedPosBlockBBox = array($tag, $attr, $this->x, $this->y);
16550 $this->fixedPosBlock = '';
16551 $this->fixedPosBlockDepth = 1;
16552 }
16553 /* -- END CSS-POSITION -- */
16554 if (preg_match('/\/$/', $e)) {
16555 $this->tag->CloseTag($tag, $a, $i);
16556 }
16557 }
16558 } // end TAG
16559 } //end of foreach($a as $i=>$e)
16560
16561 if ($close) {
16562
16563 // Close any open block tags
16564 for ($b = $this->blklvl; $b > 0; $b--) {
16565 $this->tag->CloseTag($this->blk[$b]['tag'], $a, $i);
16566 }
16567
16568 // Output any text left in buffer
16569 if (count($this->textbuffer) && !$parseonly) {
16570 $this->printbuffer($this->textbuffer);
16571 }
16572 if (!$parseonly)
16573 $this->textbuffer = array();
16574
16575 /* -- CSS-FLOAT -- */
16576 // If ended with a float, need to move to end page
16577 $currpos = $this->page * 1000 + $this->y;
16578 if (isset($this->blk[$this->blklvl]['float_endpos']) && $this->blk[$this->blklvl]['float_endpos'] > $currpos) {
16579 $old_page = $this->page;
16580 $new_page = intval($this->blk[$this->blklvl]['float_endpos'] / 1000);
16581 if ($old_page != $new_page) {
16582 $s = $this->PrintPageBackgrounds();
16583 // Writes after the marker so not overwritten later by page background etc.
16584 $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
16585 $this->pageBackgrounds = array();
16586 $this->page = $new_page;
16587 $this->ResetMargins();
16588 $this->Reset();
16589 $this->pageoutput[$this->page] = array();
16590 }
16591 $this->y = (($this->blk[$this->blklvl]['float_endpos'] * 1000) % 1000000) / 1000; // mod changes operands to integers before processing
16592 }
16593 /* -- END CSS-FLOAT -- */
16594
16595 /* -- CSS-IMAGE-FLOAT -- */
16596 $this->printfloatbuffer();
16597 /* -- END CSS-IMAGE-FLOAT -- */
16598
16599 //Create Internal Links, if needed
16600 if (!empty($this->internallink)) {
16601 foreach ($this->internallink as $k => $v) {
16602 if (strpos($k, "#") !== false) {
16603 continue;
16604 } //ignore
16605 $ypos = $v['Y'];
16606 $pagenum = $v['PAGE'];
16607 $sharp = "#";
16608 while (array_key_exists($sharp . $k, $this->internallink)) {
16609 $internallink = $this->internallink[$sharp . $k];
16610 $this->SetLink($internallink, $ypos, $pagenum);
16611 $sharp .= "#";
16612 }
16613 }
16614 }
16615
16616 $this->bufferoutput = false;
16617
16618 /* -- CSS-POSITION -- */
16619 if (count($this->fixedPosBlockSave) && $sub != 4) {
16620 foreach ($this->fixedPosBlockSave AS $fpbs) {
16621 $old_page = $this->page;
16622 $this->page = $fpbs[2];
16623 $this->WriteFixedPosHTML($fpbs[0], 0, 0, 100, 100, 'auto', $fpbs[1]); // 0,0,10,10 are overwritten by bbox
16624 $this->page = $old_page;
16625 }
16626 $this->fixedPosBlockSave = array();
16627 }
16628 /* -- END CSS-POSITION -- */
16629 }
16630 }
16631
16632 /* -- CSS-POSITION -- */
16633
16634 function WriteFixedPosHTML($html, $x, $y, $w, $h, $overflow = 'visible', $bounding = array())
16635 {
16636 // $overflow can be 'hidden', 'visible' or 'auto' - 'auto' causes autofit to size
16637 // Annotations disabled - enabled in mPDF 5.0
16638 // Links do work
16639 // Will always go on current page (or start Page 1 if required)
16640 // Probably INCOMPATIBLE WITH keep with table, columns etc.
16641 // Called externally or interally via <div style="position: [fixed|absolute]">
16642 // When used internally, $x $y $w $h and $overflow are all overridden by $bounding
16643
16644 $overflow = strtolower($overflow);
16645 if ($this->state == 0) {
16646 $this->AddPage($this->CurOrientation);
16647 }
16648 $save_y = $this->y;
16649 $save_x = $this->x;
16650 $this->fullImageHeight = $this->h;
16651 $save_cols = false;
16652 /* -- COLUMNS -- */
16653 if ($this->ColActive) {
16654 $save_cols = true;
16655 $save_nbcol = $this->NbCol; // other values of gap and vAlign will not change by setting Columns off
16656 $this->SetColumns(0);
16657 }
16658 /* -- END COLUMNS -- */
16659 $save_annots = $this->title2annots; // *ANNOTATIONS*
16660 $this->writingHTMLheader = true; // a FIX to stop pagebreaks etc.
16661 $this->writingHTMLfooter = true;
16662 $this->InFooter = true; // suppresses autopagebreaks
16663 $save_bgs = $this->pageBackgrounds;
16664 $checkinnerhtml = preg_replace('/\s/', '', $html);
16665
16666 if ($w > $this->w) {
16667 $x = 0;
16668 $w = $this->w;
16669 }
16670 if ($h > $this->h) {
16671 $y = 0;
16672 $h = $this->h;
16673 }
16674 if ($x > $this->w) {
16675 $x = $this->w - $w;
16676 }
16677 if ($y > $this->h) {
16678 $y = $this->h - $h;
16679 }
16680
16681 if (!empty($bounding)) {
16682 // $cont_ containing block = full physical page (position: absolute) or page inside margins (position: fixed)
16683 // $bbox_ Bounding box is the <div> which is positioned absolutely/fixed
16684 // top/left/right/bottom/width/height/background*/border*/padding*/margin* are taken from bounding
16685 // font*[family/size/style/weight]/line-height/text*[align/decoration/transform/indent]/color are transferred to $inner
16686 // as an enclosing <div> (after having checked ID/CLASS)
16687 // $x, $y, $w, $h are inside of $bbox_ = containing box for $inner_
16688 // $inner_ InnerHTML is the contents of that block to be output
16689 $tag = $bounding[0];
16690 $attr = $bounding[1];
16691 $orig_x0 = $bounding[2];
16692 $orig_y0 = $bounding[3];
16693
16694 // As in WriteHTML() initialising
16695 $this->blklvl = 0;
16696 $this->lastblocklevelchange = 0;
16697 $this->blk = array();
16698 $this->initialiseBlock($this->blk[0]);
16699
16700 $this->blk[0]['width'] = & $this->pgwidth;
16701 $this->blk[0]['inner_width'] = & $this->pgwidth;
16702
16703 $this->blk[0]['blockContext'] = $this->blockContext;
16704
16705 $properties = $this->cssmgr->MergeCSS('BLOCK', 'BODY', '');
16706 $this->setCSS($properties, '', 'BODY');
16707 $this->blklvl = 1;
16708 $this->initialiseBlock($this->blk[1]);
16709 $this->blk[1]['tag'] = $tag;
16710 $this->blk[1]['attr'] = $attr;
16711 $this->Reset();
16712 $p = $this->cssmgr->MergeCSS('BLOCK', $tag, $attr);
16713 if (isset($p['ROTATE']) && ($p['ROTATE'] == 90 || $p['ROTATE'] == -90 || $p['ROTATE'] == 180)) {
16714 $rotate = $p['ROTATE'];
16715 } // mPDF 6
16716 else {
16717 $rotate = 0;
16718 }
16719 if (isset($p['OVERFLOW'])) {
16720 $overflow = strtolower($p['OVERFLOW']);
16721 }
16722 if (strtolower($p['POSITION']) == 'fixed') {
16723 $cont_w = $this->pgwidth; // $this->blk[0]['inner_width'];
16724 $cont_h = $this->h - $this->tMargin - $this->bMargin;
16725 $cont_x = $this->lMargin;
16726 $cont_y = $this->tMargin;
16727 } else {
16728 $cont_w = $this->w; // ABSOLUTE;
16729 $cont_h = $this->h;
16730 $cont_x = 0;
16731 $cont_y = 0;
16732 }
16733
16734 // Pass on in-line properties to the innerhtml
16735 $css = '';
16736 if (isset($p['TEXT-ALIGN'])) {
16737 $css .= 'text-align: ' . strtolower($p['TEXT-ALIGN']) . '; ';
16738 }
16739 if (isset($p['TEXT-TRANSFORM'])) {
16740 $css .= 'text-transform: ' . strtolower($p['TEXT-TRANSFORM']) . '; ';
16741 }
16742 if (isset($p['TEXT-INDENT'])) {
16743 $css .= 'text-indent: ' . strtolower($p['TEXT-INDENT']) . '; ';
16744 }
16745 if (isset($p['TEXT-DECORATION'])) {
16746 $css .= 'text-decoration: ' . strtolower($p['TEXT-DECORATION']) . '; ';
16747 }
16748 if (isset($p['FONT-FAMILY'])) {
16749 $css .= 'font-family: ' . strtolower($p['FONT-FAMILY']) . '; ';
16750 }
16751 if (isset($p['FONT-STYLE'])) {
16752 $css .= 'font-style: ' . strtolower($p['FONT-STYLE']) . '; ';
16753 }
16754 if (isset($p['FONT-WEIGHT'])) {
16755 $css .= 'font-weight: ' . strtolower($p['FONT-WEIGHT']) . '; ';
16756 }
16757 if (isset($p['FONT-SIZE'])) {
16758 $css .= 'font-size: ' . strtolower($p['FONT-SIZE']) . '; ';
16759 }
16760 if (isset($p['LINE-HEIGHT'])) {
16761 $css .= 'line-height: ' . strtolower($p['LINE-HEIGHT']) . '; ';
16762 }
16763 if (isset($p['TEXT-SHADOW'])) {
16764 $css .= 'text-shadow: ' . strtolower($p['TEXT-SHADOW']) . '; ';
16765 }
16766 if (isset($p['LETTER-SPACING'])) {
16767 $css .= 'letter-spacing: ' . strtolower($p['LETTER-SPACING']) . '; ';
16768 }
16769 // mPDF 6
16770 if (isset($p['FONT-VARIANT-POSITION'])) {
16771 $css .= 'font-variant-position: ' . strtolower($p['FONT-VARIANT-POSITION']) . '; ';
16772 }
16773 if (isset($p['FONT-VARIANT-CAPS'])) {
16774 $css .= 'font-variant-caps: ' . strtolower($p['FONT-VARIANT-CAPS']) . '; ';
16775 }
16776 if (isset($p['FONT-VARIANT-LIGATURES'])) {
16777 $css .= 'font-variant-ligatures: ' . strtolower($p['FONT-VARIANT-LIGATURES']) . '; ';
16778 }
16779 if (isset($p['FONT-VARIANT-NUMERIC'])) {
16780 $css .= 'font-variant-numeric: ' . strtolower($p['FONT-VARIANT-NUMERIC']) . '; ';
16781 }
16782 if (isset($p['FONT-VARIANT-ALTERNATES'])) {
16783 $css .= 'font-variant-alternates: ' . strtolower($p['FONT-VARIANT-ALTERNATES']) . '; ';
16784 }
16785 if (isset($p['FONT-FEATURE-SETTINGS'])) {
16786 $css .= 'font-feature-settings: ' . strtolower($p['FONT-FEATURE-SETTINGS']) . '; ';
16787 }
16788 if (isset($p['FONT-LANGUAGE-OVERRIDE'])) {
16789 $css .= 'font-language-override: ' . strtolower($p['FONT-LANGUAGE-OVERRIDE']) . '; ';
16790 }
16791 if (isset($p['FONT-KERNING'])) {
16792 $css .= 'font-kerning: ' . strtolower($p['FONT-KERNING']) . '; ';
16793 }
16794
16795 if (isset($p['COLOR'])) {
16796 $css .= 'color: ' . strtolower($p['COLOR']) . '; ';
16797 }
16798 if (isset($p['Z-INDEX'])) {
16799 $css .= 'z-index: ' . $p['Z-INDEX'] . '; ';
16800 }
16801 if ($css) {
16802 $html = '<div style="' . $css . '">' . $html . '</div>';
16803 }
16804 // Copy over (only) the properties to set for border and background
16805 $pb = array();
16806 $pb['MARGIN-TOP'] = (isset($p['MARGIN-TOP']) ? $p['MARGIN-TOP'] : '');
16807 $pb['MARGIN-RIGHT'] = (isset($p['MARGIN-RIGHT']) ? $p['MARGIN-RIGHT'] : '');
16808 $pb['MARGIN-BOTTOM'] = (isset($p['MARGIN-BOTTOM']) ? $p['MARGIN-BOTTOM'] : '');
16809 $pb['MARGIN-LEFT'] = (isset($p['MARGIN-LEFT']) ? $p['MARGIN-LEFT'] : '');
16810 $pb['PADDING-TOP'] = (isset($p['PADDING-TOP']) ? $p['PADDING-TOP'] : '');
16811 $pb['PADDING-RIGHT'] = (isset($p['PADDING-RIGHT']) ? $p['PADDING-RIGHT'] : '');
16812 $pb['PADDING-BOTTOM'] = (isset($p['PADDING-BOTTOM']) ? $p['PADDING-BOTTOM'] : '');
16813 $pb['PADDING-LEFT'] = (isset($p['PADDING-LEFT']) ? $p['PADDING-LEFT'] : '');
16814 $pb['BORDER-TOP'] = (isset($p['BORDER-TOP']) ? $p['BORDER-TOP'] : '');
16815 $pb['BORDER-RIGHT'] = (isset($p['BORDER-RIGHT']) ? $p['BORDER-RIGHT'] : '');
16816 $pb['BORDER-BOTTOM'] = (isset($p['BORDER-BOTTOM']) ? $p['BORDER-BOTTOM'] : '');
16817 $pb['BORDER-LEFT'] = (isset($p['BORDER-LEFT']) ? $p['BORDER-LEFT'] : '');
16818 if (isset($p['BORDER-TOP-LEFT-RADIUS-H'])) {
16819 $pb['BORDER-TOP-LEFT-RADIUS-H'] = $p['BORDER-TOP-LEFT-RADIUS-H'];
16820 }
16821 if (isset($p['BORDER-TOP-LEFT-RADIUS-V'])) {
16822 $pb['BORDER-TOP-LEFT-RADIUS-V'] = $p['BORDER-TOP-LEFT-RADIUS-V'];
16823 }
16824 if (isset($p['BORDER-TOP-RIGHT-RADIUS-H'])) {
16825 $pb['BORDER-TOP-RIGHT-RADIUS-H'] = $p['BORDER-TOP-RIGHT-RADIUS-H'];
16826 }
16827 if (isset($p['BORDER-TOP-RIGHT-RADIUS-V'])) {
16828 $pb['BORDER-TOP-RIGHT-RADIUS-V'] = $p['BORDER-TOP-RIGHT-RADIUS-V'];
16829 }
16830 if (isset($p['BORDER-BOTTOM-LEFT-RADIUS-H'])) {
16831 $pb['BORDER-BOTTOM-LEFT-RADIUS-H'] = $p['BORDER-BOTTOM-LEFT-RADIUS-H'];
16832 }
16833 if (isset($p['BORDER-BOTTOM-LEFT-RADIUS-V'])) {
16834 $pb['BORDER-BOTTOM-LEFT-RADIUS-V'] = $p['BORDER-BOTTOM-LEFT-RADIUS-V'];
16835 }
16836 if (isset($p['BORDER-BOTTOM-RIGHT-RADIUS-H'])) {
16837 $pb['BORDER-BOTTOM-RIGHT-RADIUS-H'] = $p['BORDER-BOTTOM-RIGHT-RADIUS-H'];
16838 }
16839 if (isset($p['BORDER-BOTTOM-RIGHT-RADIUS-V'])) {
16840 $pb['BORDER-BOTTOM-RIGHT-RADIUS-V'] = $p['BORDER-BOTTOM-RIGHT-RADIUS-V'];
16841 }
16842 if (isset($p['BACKGROUND-COLOR'])) {
16843 $pb['BACKGROUND-COLOR'] = $p['BACKGROUND-COLOR'];
16844 }
16845 if (isset($p['BOX-SHADOW'])) {
16846 $pb['BOX-SHADOW'] = $p['BOX-SHADOW'];
16847 }
16848 /* -- BACKGROUNDS -- */
16849 if (isset($p['BACKGROUND-IMAGE'])) {
16850 $pb['BACKGROUND-IMAGE'] = $p['BACKGROUND-IMAGE'];
16851 }
16852 if (isset($p['BACKGROUND-IMAGE-RESIZE'])) {
16853 $pb['BACKGROUND-IMAGE-RESIZE'] = $p['BACKGROUND-IMAGE-RESIZE'];
16854 }
16855 if (isset($p['BACKGROUND-IMAGE-OPACITY'])) {
16856 $pb['BACKGROUND-IMAGE-OPACITY'] = $p['BACKGROUND-IMAGE-OPACITY'];
16857 }
16858 if (isset($p['BACKGROUND-REPEAT'])) {
16859 $pb['BACKGROUND-REPEAT'] = $p['BACKGROUND-REPEAT'];
16860 }
16861 if (isset($p['BACKGROUND-POSITION'])) {
16862 $pb['BACKGROUND-POSITION'] = $p['BACKGROUND-POSITION'];
16863 }
16864 if (isset($p['BACKGROUND-GRADIENT'])) {
16865 $pb['BACKGROUND-GRADIENT'] = $p['BACKGROUND-GRADIENT'];
16866 }
16867 if (isset($p['BACKGROUND-SIZE'])) {
16868 $pb['BACKGROUND-SIZE'] = $p['BACKGROUND-SIZE'];
16869 }
16870 if (isset($p['BACKGROUND-ORIGIN'])) {
16871 $pb['BACKGROUND-ORIGIN'] = $p['BACKGROUND-ORIGIN'];
16872 }
16873 if (isset($p['BACKGROUND-CLIP'])) {
16874 $pb['BACKGROUND-CLIP'] = $p['BACKGROUND-CLIP'];
16875 }
16876
16877 /* -- END BACKGROUNDS -- */
16878
16879 $this->setCSS($pb, 'BLOCK', $tag);
16880
16881 //================================================================
16882 $bbox_br = $this->blk[1]['border_right']['w'];
16883 $bbox_bl = $this->blk[1]['border_left']['w'];
16884 $bbox_bt = $this->blk[1]['border_top']['w'];
16885 $bbox_bb = $this->blk[1]['border_bottom']['w'];
16886 $bbox_pr = $this->blk[1]['padding_right'];
16887 $bbox_pl = $this->blk[1]['padding_left'];
16888 $bbox_pt = $this->blk[1]['padding_top'];
16889 $bbox_pb = $this->blk[1]['padding_bottom'];
16890 $bbox_mr = $this->blk[1]['margin_right'];
16891 if (isset($p['MARGIN-RIGHT']) && strtolower($p['MARGIN-RIGHT']) == 'auto') {
16892 $bbox_mr = 'auto';
16893 }
16894 $bbox_ml = $this->blk[1]['margin_left'];
16895 if (isset($p['MARGIN-LEFT']) && strtolower($p['MARGIN-LEFT']) == 'auto') {
16896 $bbox_ml = 'auto';
16897 }
16898 $bbox_mt = $this->blk[1]['margin_top'];
16899 if (isset($p['MARGIN-TOP']) && strtolower($p['MARGIN-TOP']) == 'auto') {
16900 $bbox_mt = 'auto';
16901 }
16902 $bbox_mb = $this->blk[1]['margin_bottom'];
16903 if (isset($p['MARGIN-BOTTOM']) && strtolower($p['MARGIN-BOTTOM']) == 'auto') {
16904 $bbox_mb = 'auto';
16905 }
16906 if (isset($p['LEFT']) && strtolower($p['LEFT']) != 'auto') {
16907 $bbox_left = $this->ConvertSize($p['LEFT'], $cont_w, $this->FontSize, false);
16908 } else {
16909 $bbox_left = 'auto';
16910 }
16911 if (isset($p['TOP']) && strtolower($p['TOP']) != 'auto') {
16912 $bbox_top = $this->ConvertSize($p['TOP'], $cont_h, $this->FontSize, false);
16913 } else {
16914 $bbox_top = 'auto';
16915 }
16916 if (isset($p['RIGHT']) && strtolower($p['RIGHT']) != 'auto') {
16917 $bbox_right = $this->ConvertSize($p['RIGHT'], $cont_w, $this->FontSize, false);
16918 } else {
16919 $bbox_right = 'auto';
16920 }
16921 if (isset($p['BOTTOM']) && strtolower($p['BOTTOM']) != 'auto') {
16922 $bbox_bottom = $this->ConvertSize($p['BOTTOM'], $cont_h, $this->FontSize, false);
16923 } else {
16924 $bbox_bottom = 'auto';
16925 }
16926 if (isset($p['WIDTH']) && strtolower($p['WIDTH']) != 'auto') {
16927 $inner_w = $this->ConvertSize($p['WIDTH'], $cont_w, $this->FontSize, false);
16928 } else {
16929 $inner_w = 'auto';
16930 }
16931 if (isset($p['HEIGHT']) && strtolower($p['HEIGHT']) != 'auto') {
16932 $inner_h = $this->ConvertSize($p['HEIGHT'], $cont_h, $this->FontSize, false);
16933 } else {
16934 $inner_h = 'auto';
16935 }
16936
16937 // If bottom or right pos are set and not left / top - save this to adjust rotated block later
16938 if ($rotate == 90 || $rotate == -90) { // mPDF 6
16939 if ($bbox_left === 'auto' && $bbox_right !== 'auto') {
16940 $rot_rpos = $bbox_right;
16941 } else {
16942 $rot_rpos = false;
16943 }
16944 if ($bbox_top === 'auto' && $bbox_bottom !== 'auto') {
16945 $rot_bpos = $bbox_bottom;
16946 } else {
16947 $rot_bpos = false;
16948 }
16949 }
16950
16951 //================================================================
16952 if ($checkinnerhtml == '' && $inner_h === 'auto') {
16953 $inner_h = 0.0001;
16954 }
16955 if ($checkinnerhtml == '' && $inner_w === 'auto') {
16956 $inner_w = 2 * $this->GetCharWidth('W', false);
16957 }
16958 //================================================================
16959 // Algorithm from CSS2.1 See http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height
16960 // mPD 5.3.14
16961 // Special case (not CSS) if all not specified, centre vertically on page
16962 $bbox_top_orig = '';
16963 if ($bbox_top === 'auto' && $inner_h === 'auto' && $bbox_bottom === 'auto' && $bbox_mt === 'auto' && $bbox_mb === 'auto') {
16964 $bbox_top_orig = $bbox_top;
16965 if ($bbox_mt === 'auto') {
16966 $bbox_mt = 0;
16967 }
16968 if ($bbox_mb === 'auto') {
16969 $bbox_mb = 0;
16970 }
16971 $bbox_top = $orig_y0 - $bbox_mt - $cont_y;
16972 // solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
16973 }
16974 // mPD 5.3.14
16975 elseif ($bbox_top === 'auto' && $inner_h === 'auto' && $bbox_bottom === 'auto') {
16976 $bbox_top_orig = $bbox_top = $orig_y0 - $cont_y;
16977 if ($bbox_mt === 'auto') {
16978 $bbox_mt = 0;
16979 }
16980 if ($bbox_mb === 'auto') {
16981 $bbox_mb = 0;
16982 }
16983 // solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
16984 } elseif ($bbox_top !== 'auto' && $inner_h !== 'auto' && $bbox_bottom !== 'auto') {
16985 if ($bbox_mt === 'auto' && $bbox_mb === 'auto') {
16986 $x = $cont_h - $bbox_top - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_bottom;
16987 $bbox_mt = $bbox_mb = ($x / 2);
16988 } elseif ($bbox_mt === 'auto') {
16989 $bbox_mt = $cont_h - $bbox_top - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
16990 } elseif ($bbox_mb === 'auto') {
16991 $bbox_mb = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_bottom;
16992 } else {
16993 $bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt;
16994 }
16995 } else {
16996 if ($bbox_mt === 'auto') {
16997 $bbox_mt = 0;
16998 }
16999 if ($bbox_mb === 'auto') {
17000 $bbox_mb = 0;
17001 }
17002 if ($bbox_top === 'auto' && $inner_h === 'auto' && $bbox_bottom !== 'auto') {
17003 // solve for $bbox_top when content_h known - $inner_h=='auto' && $bbox_top =='auto'
17004 } elseif ($bbox_top === 'auto' && $bbox_bottom === 'auto' && $inner_h !== 'auto') {
17005 $bbox_top = $orig_y0 - $bbox_mt - $cont_y;
17006 $bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt;
17007 } elseif ($inner_h === 'auto' && $bbox_bottom === 'auto' && $bbox_top !== 'auto') {
17008 // solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
17009 } elseif ($bbox_top === 'auto' && $inner_h !== 'auto' && $bbox_bottom !== 'auto') {
17010 $bbox_top = $cont_h - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt - $bbox_bottom;
17011 } elseif ($inner_h === 'auto' && $bbox_top !== 'auto' && $bbox_bottom !== 'auto') {
17012 $inner_h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mt - $bbox_bottom;
17013 } elseif ($bbox_bottom === 'auto' && $bbox_top !== 'auto' && $inner_h !== 'auto') {
17014 $bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt;
17015 }
17016 }
17017
17018 // THEN DO SAME FOR WIDTH
17019 // http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width
17020 if ($bbox_left === 'auto' && $inner_w === 'auto' && $bbox_right === 'auto') {
17021 if ($bbox_ml === 'auto') {
17022 $bbox_ml = 0;
17023 }
17024 if ($bbox_mr === 'auto') {
17025 $bbox_mr = 0;
17026 }
17027 // IF containing element RTL, should set $bbox_right
17028 $bbox_left = $orig_x0 - $bbox_ml - $cont_x;
17029 // solve for $bbox_right when content_w known - $inner_w=='auto' && $bbox_right=='auto'
17030 } elseif ($bbox_left !== 'auto' && $inner_w !== 'auto' && $bbox_right !== 'auto') {
17031 if ($bbox_ml === 'auto' && $bbox_mr === 'auto') {
17032 $x = $cont_w - $bbox_left - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_right;
17033 $bbox_ml = $bbox_mr = ($x / 2);
17034 } elseif ($bbox_ml === 'auto') {
17035 $bbox_ml = $cont_w - $bbox_left - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_mr - $bbox_right;
17036 } elseif ($bbox_mr === 'auto') {
17037 $bbox_mr = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_right;
17038 } else {
17039 $bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
17040 }
17041 } else {
17042 if ($bbox_ml === 'auto') {
17043 $bbox_ml = 0;
17044 }
17045 if ($bbox_mr === 'auto') {
17046 $bbox_mr = 0;
17047 }
17048 if ($bbox_left === 'auto' && $inner_w === 'auto' && $bbox_right !== 'auto') {
17049 // solve for $bbox_left when content_w known - $inner_w=='auto' && $bbox_left =='auto'
17050 } elseif ($bbox_left === 'auto' && $bbox_right === 'auto' && $inner_w !== 'auto') {
17051 // IF containing element RTL, should set $bbox_right
17052 $bbox_left = $orig_x0 - $bbox_ml - $cont_x;
17053 $bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
17054 } elseif ($inner_w === 'auto' && $bbox_right === 'auto' && $bbox_left !== 'auto') {
17055 // solve for $bbox_right when content_w known - $inner_w=='auto' && $bbox_right=='auto'
17056 } elseif ($bbox_left === 'auto' && $inner_w !== 'auto' && $bbox_right !== 'auto') {
17057 $bbox_left = $cont_w - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml - $bbox_right;
17058 } elseif ($inner_w === 'auto' && $bbox_left !== 'auto' && $bbox_right !== 'auto') {
17059 $inner_w = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $bbox_pr - $bbox_br - $bbox_ml - $bbox_right;
17060 } elseif ($bbox_right === 'auto' && $bbox_left !== 'auto' && $inner_w !== 'auto') {
17061 $bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
17062 }
17063 }
17064
17065 //================================================================
17066 //================================================================
17067 /* -- BACKGROUNDS -- */
17068 if (isset($pb['BACKGROUND-IMAGE']) && $pb['BACKGROUND-IMAGE']) {
17069 $ret = $this->SetBackground($pb, $this->blk[1]['inner_width']);
17070 if ($ret) {
17071 $this->blk[1]['background-image'] = $ret;
17072 }
17073 }
17074 /* -- END BACKGROUNDS -- */
17075
17076 //================================================================
17077 $y = $cont_y + $bbox_top + $bbox_mt + $bbox_bt + $bbox_pt;
17078 $h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
17079 $x = $cont_x + $bbox_left + $bbox_ml + $bbox_bl + $bbox_pl;
17080 $w = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $bbox_pr - $bbox_br - $bbox_mr - $bbox_right;
17081 // Set (temporary) values for x y w h to do first paint, if values are auto
17082 if ($inner_h === 'auto' && $bbox_top === 'auto') {
17083 $y = $cont_y + $bbox_mt + $bbox_bt + $bbox_pt;
17084 $h = $cont_h - ($bbox_bottom + $bbox_mt + $bbox_mb + $bbox_bt + $bbox_bb + $bbox_pt + $bbox_pb);
17085 } elseif ($inner_h === 'auto' && $bbox_bottom === 'auto') {
17086 $y = $cont_y + $bbox_top + $bbox_mt + $bbox_bt + $bbox_pt;
17087 $h = $cont_h - ($bbox_top + $bbox_mt + $bbox_mb + $bbox_bt + $bbox_bb + $bbox_pt + $bbox_pb);
17088 }
17089 if ($inner_w === 'auto' && $bbox_left === 'auto') {
17090 $x = $cont_x + $bbox_ml + $bbox_bl + $bbox_pl;
17091 $w = $cont_w - ($bbox_right + $bbox_ml + $bbox_mr + $bbox_bl + $bbox_br + $bbox_pl + $bbox_pr);
17092 } elseif ($inner_w === 'auto' && $bbox_right === 'auto') {
17093 $x = $cont_x + $bbox_left + $bbox_ml + $bbox_bl + $bbox_pl;
17094 $w = $cont_w - ($bbox_left + $bbox_ml + $bbox_mr + $bbox_bl + $bbox_br + $bbox_pl + $bbox_pr);
17095 }
17096 $bbox_y = $cont_y + $bbox_top + $bbox_mt;
17097 $bbox_x = $cont_x + $bbox_left + $bbox_ml;
17098 $saved_block1 = $this->blk[1];
17099 unset($p);
17100 unset($pb);
17101 //================================================================
17102 if ($inner_w === 'auto') { // do a first write
17103 $this->lMargin = $x;
17104 $this->rMargin = $this->w - $w - $x;
17105 // SET POSITION & FONT VALUES
17106 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
17107 $this->pageoutput[$this->page] = array();
17108 $this->x = $x;
17109 $this->y = $y;
17110 $this->HTMLheaderPageLinks = array();
17111 $this->HTMLheaderPageAnnots = array();
17112 $this->HTMLheaderPageForms = array();
17113 $this->pageBackgrounds = array();
17114 $this->maxPosR = 0;
17115 $this->maxPosL = $this->w; // For RTL
17116 $this->WriteHTML($html, 4);
17117 $inner_w = $this->maxPosR - $this->lMargin;
17118 if ($bbox_right === 'auto') {
17119 $bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
17120 } elseif ($bbox_left === 'auto') {
17121 $bbox_left = $cont_w - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml - $bbox_right;
17122 $bbox_x = $cont_x + $bbox_left + $bbox_ml;
17123 $inner_x = $bbox_x + $bbox_bl + $bbox_pl;
17124 $x = $inner_x;
17125 }
17126 $w = $inner_w;
17127 $bbox_y = $cont_y + $bbox_top + $bbox_mt;
17128 $bbox_x = $cont_x + $bbox_left + $bbox_ml;
17129 }
17130
17131 if ($inner_h === 'auto') { // do a first write
17132 $this->lMargin = $x;
17133 $this->rMargin = $this->w - $w - $x;
17134 // SET POSITION & FONT VALUES
17135 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
17136 $this->pageoutput[$this->page] = array();
17137 $this->x = $x;
17138 $this->y = $y;
17139 $this->HTMLheaderPageLinks = array();
17140 $this->HTMLheaderPageAnnots = array();
17141 $this->HTMLheaderPageForms = array();
17142 $this->pageBackgrounds = array();
17143 $this->WriteHTML($html, 4);
17144 $inner_h = $this->y - $y;
17145 if ($overflow != 'hidden' && $overflow != 'visible') { // constrained
17146 if (($this->y + $bbox_pb + $bbox_bb) > ($cont_y + $cont_h)) {
17147 $adj = ($this->y + $bbox_pb + $bbox_bb) - ($cont_y + $cont_h);
17148 $inner_h -= $adj;
17149 }
17150 }
17151 if ($bbox_bottom === 'auto' && $bbox_top_orig === 'auto') {
17152 $bbox_bottom = $bbox_top = ($cont_h - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb) / 2;
17153 if ($overflow != 'hidden' && $overflow != 'visible') { // constrained
17154 if ($bbox_top < 0) {
17155 $bbox_top = 0;
17156 $inner_h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
17157 }
17158 }
17159 $bbox_y = $cont_y + $bbox_top + $bbox_mt;
17160 $inner_y = $bbox_y + $bbox_bt + $bbox_pt;
17161 $y = $inner_y;
17162 } elseif ($bbox_bottom === 'auto') {
17163 $bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb;
17164 } elseif ($bbox_top === 'auto') {
17165 $bbox_top = $cont_h - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
17166 if ($overflow != 'hidden' && $overflow != 'visible') { // constrained
17167 if ($bbox_top < 0) {
17168 $bbox_top = 0;
17169 $inner_h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
17170 }
17171 }
17172 $bbox_y = $cont_y + $bbox_top + $bbox_mt;
17173 $inner_y = $bbox_y + $bbox_bt + $bbox_pt;
17174 $y = $inner_y;
17175 }
17176 $h = $inner_h;
17177 $bbox_y = $cont_y + $bbox_top + $bbox_mt;
17178 $bbox_x = $cont_x + $bbox_left + $bbox_ml;
17179 }
17180 $inner_w = $w;
17181 $inner_h = $h;
17182 }
17183 $this->lMargin = $x;
17184 $this->rMargin = $this->w - $w - $x;
17185 // SET POSITION & FONT VALUES
17186 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
17187 $this->pageoutput[$this->page] = array();
17188 $this->x = $x;
17189 $this->y = $y;
17190 $this->HTMLheaderPageLinks = array();
17191 $this->HTMLheaderPageAnnots = array();
17192 $this->HTMLheaderPageForms = array();
17193 $this->pageBackgrounds = array();
17194 $this->WriteHTML($html, 4); // parameter 4 saves output to $this->headerbuffer
17195 $actual_h = $this->y - $y;
17196 $use_w = $w;
17197 $use_h = $h;
17198 $ratio = $actual_h / $use_w;
17199
17200 if ($overflow != 'hidden' && $overflow != 'visible') {
17201 $target = $h / $w;
17202 if (($ratio / $target ) > 1) {
17203 $nl = CEIL($actual_h / $this->lineheight);
17204 $l = $use_w * $nl;
17205 $est_w = sqrt(($l * $this->lineheight) / $target) * 0.8;
17206 $use_w += ($est_w - $use_w) - ($w / 100);
17207 }
17208 $bpcstart = ($ratio / $target);
17209 $bpcctr = 1;
17210 while (($ratio / $target ) > 1) {
17211
17212 if ($this->progressBar) {
17213 $this->UpdateProgressBar(4, intval(100 / ($ratio / $target)), ('Auto-sizing fixed-position block: ' . $bpcctr++));
17214 } // *PROGRESS-BAR*
17215
17216 $this->x = $x;
17217 $this->y = $y;
17218
17219 if (($ratio / $target) > 1.5 || ($ratio / $target) < 0.6) {
17220 $use_w += ($w / $this->incrementFPR1);
17221 } elseif (($ratio / $target) > 1.2 || ($ratio / $target) < 0.85) {
17222 $use_w += ($w / $this->incrementFPR2);
17223 } elseif (($ratio / $target) > 1.1 || ($ratio / $target) < 0.91) {
17224 $use_w += ($w / $this->incrementFPR3);
17225 } else {
17226 $use_w += ($w / $this->incrementFPR4);
17227 }
17228
17229 $use_h = $use_w * $target;
17230 $this->rMargin = $this->w - $use_w - $x;
17231 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
17232 $this->HTMLheaderPageLinks = array();
17233 $this->HTMLheaderPageAnnots = array();
17234 $this->HTMLheaderPageForms = array();
17235 $this->pageBackgrounds = array();
17236 $this->WriteHTML($html, 4); // parameter 4 saves output to $this->headerbuffer
17237 $actual_h = $this->y - $y;
17238 $ratio = $actual_h / $use_w;
17239 }
17240 if ($this->progressBar) {
17241 $this->UpdateProgressBar(4, '100', ' ');
17242 } // *PROGRESS-BAR*
17243 }
17244 $shrink_f = $w / $use_w;
17245
17246 //================================================================
17247
17248 $this->pages[$this->page] .= '___BEFORE_BORDERS___';
17249 $block_s = $this->PrintPageBackgrounds(); // Save to print later inside clipping path
17250 $this->pageBackgrounds = array();
17251
17252 //================================================================
17253
17254 if ($rotate == 90 || $rotate == -90) { // mPDF 6
17255 $prerotw = $bbox_bl + $bbox_pl + $inner_w + $bbox_pr + $bbox_br;
17256 $preroth = $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb;
17257 $rot_start = " q\n";
17258 if ($rotate == 90) {
17259 if ($rot_rpos !== false) {
17260 $adjw = $prerotw;
17261 } // width before rotation
17262 else {
17263 $adjw = $preroth;
17264 } // height before rotation
17265 if ($rot_bpos !== false) {
17266 $adjh = -$prerotw + $preroth;
17267 } else {
17268 $adjh = 0;
17269 }
17270 } else {
17271 if ($rot_rpos !== false) {
17272 $adjw = $prerotw - $preroth;
17273 } else {
17274 $adjw = 0;
17275 }
17276 if ($rot_bpos !== false) {
17277 $adjh = $preroth;
17278 } // height before rotation
17279 else {
17280 $adjh = $prerotw;
17281 } // width before rotation
17282 }
17283 $rot_start .= $this->transformTranslate($adjw, $adjh, true) . "\n";
17284 $rot_start .= $this->transformRotate($rotate, $bbox_x, $bbox_y, true) . "\n";
17285 $rot_end = " Q\n";
17286 } elseif ($rotate == 180) { // mPDF 6
17287 $rot_start = " q\n";
17288 $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";
17289 $rot_start .= $this->transformRotate(180, $bbox_x, $bbox_y, true) . "\n";
17290 $rot_end = " Q\n";
17291 } else {
17292 $rot_start = '';
17293 $rot_end = '';
17294 }
17295
17296 //================================================================
17297 if (!empty($bounding)) {
17298 // WHEN HEIGHT // BOTTOM EDGE IS KNOWN and $this->y is set to the bottom
17299 // Re-instate saved $this->blk[1]
17300 $this->blk[1] = $saved_block1;
17301
17302 // These are only needed when painting border/background
17303 $this->blk[1]['width'] = $bbox_w = $cont_w - $bbox_left - $bbox_ml - $bbox_mr - $bbox_right;
17304 $this->blk[1]['x0'] = $bbox_x;
17305 $this->blk[1]['y0'] = $bbox_y;
17306 $this->blk[1]['startpage'] = $this->page;
17307 $this->blk[1]['y1'] = $bbox_y + $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb;
17308 $this->_out($rot_start);
17309 $this->PaintDivBB('', 0, 1); // Prints borders and sets backgrounds in $this->pageBackgrounds
17310 $this->_out($rot_end);
17311 }
17312
17313 $s = $this->PrintPageBackgrounds();
17314 $s = $rot_start . $s . $rot_end;
17315 $this->pages[$this->page] = preg_replace('/___BEFORE_BORDERS___/', "\n" . $s . "\n", $this->pages[$this->page]);
17316 $this->pageBackgrounds = array();
17317
17318 $this->_out($rot_start);
17319
17320 // Clipping Output
17321 if ($overflow == 'hidden') {
17322 //Bounding rectangle to clip
17323 $clip_y1 = $this->y;
17324 if (!empty($bounding) && ($this->y + $bbox_pb + $bbox_bb) > ($bbox_y + $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb )) {
17325 $clip_y1 = ($bbox_y + $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb ) - ($bbox_pb + $bbox_bb);
17326 }
17327 //$op = 'W* n'; // Clipping
17328 $op = 'W n'; // Clipping alternative mode
17329 $this->_out("q");
17330 $ch = $clip_y1 - $y;
17331 $this->_out(sprintf('%.3F %.3F %.3F %.3F re %s', $x * _MPDFK, ($this->h - $y) * _MPDFK, $w * _MPDFK, -$ch * _MPDFK, $op));
17332 if (!empty($block_s)) {
17333 $tmp = "q\n" . sprintf('%.3F %.3F %.3F %.3F re %s', $x * _MPDFK, ($this->h - $y) * _MPDFK, $w * _MPDFK, -$ch * _MPDFK, $op);
17334 $tmp .= "\n" . $block_s . "\nQ";
17335 $block_s = $tmp;
17336 }
17337 }
17338
17339
17340 if (!empty($block_s)) {
17341 if ($shrink_f != 1) { // i.e. autofit has resized the box
17342 $tmp = "q\n" . $this->transformScale(($shrink_f * 100), ($shrink_f * 100), $x, $y, true);
17343 $tmp .= "\n" . $block_s . "\nQ";
17344 $block_s = $tmp;
17345 }
17346 $this->_out($block_s);
17347 }
17348
17349
17350
17351 if ($shrink_f != 1) { // i.e. autofit has resized the box
17352 $this->StartTransform();
17353 $this->transformScale(($shrink_f * 100), ($shrink_f * 100), $x, $y);
17354 }
17355
17356 $this->_out($this->headerbuffer);
17357
17358 if ($shrink_f != 1) { // i.e. autofit has resized the box
17359 $this->StopTransform();
17360 }
17361
17362 if ($overflow == 'hidden') {
17363 //End clipping
17364 $this->_out("Q");
17365 }
17366
17367 $this->_out($rot_end);
17368
17369
17370 // Page Links
17371 foreach ($this->HTMLheaderPageLinks AS $lk) {
17372 if ($rotate) {
17373 $tmp = $lk[2]; // Switch h - w
17374 $lk[2] = $lk[3];
17375 $lk[3] = $tmp;
17376
17377 $lx1 = (($lk[0] / _MPDFK));
17378 $ly1 = (($this->h - ($lk[1] / _MPDFK)));
17379 if ($rotate == 90) {
17380 $adjx = -($lx1 - $bbox_x) + ($preroth - ($ly1 - $bbox_y));
17381 $adjy = -($ly1 - $bbox_y) + ($lx1 - $bbox_x);
17382 $lk[2] = -$lk[2];
17383 } elseif ($rotate == -90) {
17384 $adjx = -($lx1 - $bbox_x) + ($ly1 - $bbox_y);
17385 $adjy = -($ly1 - $bbox_y) - ($lx1 - $bbox_x) + $prerotw;
17386 $lk[3] = -$lk[3];
17387 }
17388 if ($rot_rpos !== false) {
17389 $adjx += $prerotw - $preroth;
17390 }
17391 if ($rot_bpos !== false) {
17392 $adjy += $preroth - $prerotw;
17393 }
17394 $lx1 += $adjx;
17395 $ly1 += $adjy;
17396
17397 $lk[0] = $lx1 * _MPDFK;
17398 $lk[1] = ($this->h - $ly1) * _MPDFK;
17399 }
17400 if ($shrink_f != 1) { // i.e. autofit has resized the box
17401 $lx1 = (($lk[0] / _MPDFK) - $x);
17402 $lx2 = $x + ($lx1 * $shrink_f);
17403 $lk[0] = $lx2 * _MPDFK;
17404 $ly1 = (($this->h - ($lk[1] / _MPDFK)) - $y);
17405 $ly2 = $y + ($ly1 * $shrink_f);
17406 $lk[1] = ($this->h - $ly2) * _MPDFK;
17407 $lk[2] *= $shrink_f; // width
17408 $lk[3] *= $shrink_f; // height
17409 }
17410 $this->PageLinks[$this->page][] = $lk;
17411 }
17412
17413 foreach ($this->HTMLheaderPageForms AS $n => $f) {
17414 if ($shrink_f != 1) { // i.e. autofit has resized the box
17415 $f['x'] = $x + (($f['x'] - $x) * $shrink_f);
17416 $f['y'] = $y + (($f['y'] - $y) * $shrink_f);
17417 $f['w'] *= $shrink_f;
17418 $f['h'] *= $shrink_f;
17419 $f['style']['fontsize'] *= $shrink_f;
17420 }
17421 $this->mpdfform->forms[$f['n']] = $f;
17422 }
17423 // Page Annotations
17424 foreach ($this->HTMLheaderPageAnnots AS $lk) {
17425 if ($rotate) {
17426 if ($rotate == 90) {
17427 $adjx = -($lk['x'] - $bbox_x) + ($preroth - ($lk['y'] - $bbox_y));
17428 $adjy = -($lk['y'] - $bbox_y) + ($lk['x'] - $bbox_x);
17429 } elseif ($rotate == -90) {
17430 $adjx = -($lk['x'] - $bbox_x) + ($lk['y'] - $bbox_y);
17431 $adjy = -($lk['y'] - $bbox_y) - ($lk['x'] - $bbox_x) + $prerotw;
17432 }
17433 if ($rot_rpos !== false) {
17434 $adjx += $prerotw - $preroth;
17435 }
17436 if ($rot_bpos !== false) {
17437 $adjy += $preroth - $prerotw;
17438 }
17439 $lk['x'] += $adjx;
17440 $lk['y'] += $adjy;
17441 }
17442 if ($shrink_f != 1) { // i.e. autofit has resized the box
17443 $lk['x'] = $x + (($lk['x'] - $x) * $shrink_f);
17444 $lk['y'] = $y + (($lk['y'] - $y) * $shrink_f);
17445 }
17446 $this->PageAnnots[$this->page][] = $lk;
17447 }
17448
17449 // Restore
17450 $this->headerbuffer = '';
17451 $this->HTMLheaderPageLinks = array();
17452 $this->HTMLheaderPageAnnots = array();
17453 $this->HTMLheaderPageForms = array();
17454 $this->pageBackgrounds = $save_bgs;
17455 $this->writingHTMLheader = false;
17456
17457 $this->writingHTMLfooter = false;
17458 $this->fullImageHeight = false;
17459 $this->ResetMargins();
17460 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
17461 $this->SetXY($save_x, $save_y);
17462 $this->title2annots = $save_annots; // *ANNOTATIONS*
17463 $this->InFooter = false; // turns back on autopagebreaks
17464 $this->pageoutput[$this->page] = array();
17465 $this->pageoutput[$this->page]['Font'] = '';
17466 /* -- COLUMNS -- */
17467 if ($save_cols) {
17468 $this->SetColumns($save_nbcol, $this->colvAlign, $this->ColGap);
17469 }
17470 /* -- END COLUMNS -- */
17471 }
17472
17473 /* -- END CSS-POSITION -- */
17474
17475 function initialiseBlock(&$blk)
17476 {
17477 $blk['margin_top'] = 0;
17478 $blk['margin_left'] = 0;
17479 $blk['margin_bottom'] = 0;
17480 $blk['margin_right'] = 0;
17481 $blk['padding_top'] = 0;
17482 $blk['padding_left'] = 0;
17483 $blk['padding_bottom'] = 0;
17484 $blk['padding_right'] = 0;
17485 $blk['border_top']['w'] = 0;
17486 $blk['border_left']['w'] = 0;
17487 $blk['border_bottom']['w'] = 0;
17488 $blk['border_right']['w'] = 0;
17489 $blk['direction'] = 'ltr';
17490 $blk['hide'] = false;
17491 $blk['outer_left_margin'] = 0;
17492 $blk['outer_right_margin'] = 0;
17493 $blk['cascadeCSS'] = array();
17494 $blk['block-align'] = false;
17495 $blk['bgcolor'] = false;
17496 $blk['page_break_after_avoid'] = false;
17497 $blk['keep_block_together'] = false;
17498 $blk['float'] = false;
17499 $blk['line_height'] = '';
17500 $blk['margin_collapse'] = false;
17501 }
17502
17503 function border_details($bd)
17504 {
17505 $prop = preg_split('/\s+/', trim($bd));
17506
17507 if (isset($this->blk[$this->blklvl]['inner_width'])) {
17508 $refw = $this->blk[$this->blklvl]['inner_width'];
17509 } elseif (isset($this->blk[$this->blklvl - 1]['inner_width'])) {
17510 $refw = $this->blk[$this->blklvl - 1]['inner_width'];
17511 } else {
17512 $refw = $this->w;
17513 }
17514 if (count($prop) == 1) {
17515 $bsize = $this->ConvertSize($prop[0], $refw, $this->FontSize, false);
17516 if ($bsize > 0) {
17517 return array('s' => 1, 'w' => $bsize, 'c' => $this->ConvertColor(0), 'style' => 'solid');
17518 } else {
17519 return array('w' => 0, 's' => 0);
17520 }
17521 } elseif (count($prop) == 2) {
17522 // 1px solid
17523 if (in_array($prop[1], $this->borderstyles) || $prop[1] == 'none' || $prop[1] == 'hidden') {
17524 $prop[2] = '';
17525 }
17526 // solid #000000
17527 elseif (in_array($prop[0], $this->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden') {
17528 $prop[0] = '';
17529 $prop[1] = $prop[0];
17530 $prop[2] = $prop[1];
17531 }
17532 // 1px #000000
17533 else {
17534 $prop[1] = '';
17535 $prop[2] = $prop[1];
17536 }
17537 } elseif (count($prop) == 3) {
17538 // Change #000000 1px solid to 1px solid #000000 (proper)
17539 if (substr($prop[0], 0, 1) == '#') {
17540 $tmp = $prop[0];
17541 $prop[0] = $prop[1];
17542 $prop[1] = $prop[2];
17543 $prop[2] = $tmp;
17544 }
17545 // Change solid #000000 1px to 1px solid #000000 (proper)
17546 elseif (substr($prop[0], 1, 1) == '#') {
17547 $tmp = $prop[1];
17548 $prop[0] = $prop[2];
17549 $prop[1] = $prop[0];
17550 $prop[2] = $tmp;
17551 }
17552 // Change solid 1px #000000 to 1px solid #000000 (proper)
17553 elseif (in_array($prop[0], $this->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden') {
17554 $tmp = $prop[0];
17555 $prop[0] = $prop[1];
17556 $prop[1] = $tmp;
17557 }
17558 } else {
17559 return array();
17560 }
17561 // Size
17562 $bsize = $this->ConvertSize($prop[0], $refw, $this->FontSize, false);
17563 //color
17564 $coul = $this->ConvertColor($prop[2]); // returns array
17565 // Style
17566 $prop[1] = strtolower($prop[1]);
17567 if (in_array($prop[1], $this->borderstyles) && $bsize > 0) {
17568 $on = 1;
17569 } elseif ($prop[1] == 'hidden') {
17570 $on = 1;
17571 $bsize = 0;
17572 $coul = '';
17573 } elseif ($prop[1] == 'none') {
17574 $on = 0;
17575 $bsize = 0;
17576 $coul = '';
17577 } else {
17578 $on = 0;
17579 $bsize = 0;
17580 $coul = '';
17581 $prop[1] = '';
17582 }
17583 return array('s' => $on, 'w' => $bsize, 'c' => $coul, 'style' => $prop[1]);
17584 }
17585
17586 /* -- END HTML-CSS -- */
17587
17588
17589 /* -- BORDER-RADIUS -- */
17590
17591 function _borderPadding($a, $b, &$px, &$py)
17592 {
17593 // $px and py are padding long axis (x) and short axis (y)
17594 $added = 0; // extra padding
17595
17596 $x = $a - $px;
17597 $y = $b - $py;
17598 // Check if Falls within ellipse of border radius
17599 if (( (($x + $added) * ($x + $added)) / ($a * $a) + (($y + $added) * ($y + $added)) / ($b * $b) ) <= 1) {
17600 return false;
17601 }
17602
17603 $t = atan2($y, $x);
17604
17605 $newx = $b / sqrt((($b * $b) / ($a * $a)) + ( tan($t) * tan($t) ));
17606 $newy = $a / sqrt((($a * $a) / ($b * $b)) + ( (1 / tan($t)) * (1 / tan($t)) ));
17607 $px = max($px, $a - $newx + $added);
17608 $py = max($py, $b - $newy + $added);
17609 }
17610
17611 /* -- END BORDER-RADIUS -- */
17612
17613
17614
17615 /* -- HTML-CSS -- */
17616
17617
17618 /* -- CSS-PAGE -- */
17619
17620 function SetPagedMediaCSS($name, $first, $oddEven)
17621 {
17622 if ($oddEven == 'E') {
17623 if ($this->directionality == 'rtl') {
17624 $side = 'R';
17625 } else {
17626 $side = 'L';
17627 }
17628 } else {
17629 if ($this->directionality == 'rtl') {
17630 $side = 'L';
17631 } else {
17632 $side = 'R';
17633 }
17634 }
17635 $name = strtoupper($name);
17636 $p = array();
17637 $p['SIZE'] = 'AUTO';
17638
17639 // Uses mPDF original margins as default
17640 $p['MARGIN-RIGHT'] = strval($this->orig_rMargin) . 'mm';
17641 $p['MARGIN-LEFT'] = strval($this->orig_lMargin) . 'mm';
17642 $p['MARGIN-TOP'] = strval($this->orig_tMargin) . 'mm';
17643 $p['MARGIN-BOTTOM'] = strval($this->orig_bMargin) . 'mm';
17644 $p['MARGIN-HEADER'] = strval($this->orig_hMargin) . 'mm';
17645 $p['MARGIN-FOOTER'] = strval($this->orig_fMargin) . 'mm';
17646
17647 // Basic page + selector
17648 if (isset($this->cssmgr->CSS['@PAGE'])) {
17649 $zp = $this->cssmgr->CSS['@PAGE'];
17650 } else {
17651 $zp = array();
17652 }
17653 if (is_array($zp) && !empty($zp)) {
17654 $p = array_merge($p, $zp);
17655 }
17656
17657 if (isset($p['EVEN-HEADER-NAME']) && $oddEven == 'E') {
17658 $p['HEADER'] = $p['EVEN-HEADER-NAME'];
17659 unset($p['EVEN-HEADER-NAME']);
17660 }
17661 if (isset($p['ODD-HEADER-NAME']) && $oddEven != 'E') {
17662 $p['HEADER'] = $p['ODD-HEADER-NAME'];
17663 unset($p['ODD-HEADER-NAME']);
17664 }
17665 if (isset($p['EVEN-FOOTER-NAME']) && $oddEven == 'E') {
17666 $p['FOOTER'] = $p['EVEN-FOOTER-NAME'];
17667 unset($p['EVEN-FOOTER-NAME']);
17668 }
17669 if (isset($p['ODD-FOOTER-NAME']) && $oddEven != 'E') {
17670 $p['FOOTER'] = $p['ODD-FOOTER-NAME'];
17671 unset($p['ODD-FOOTER-NAME']);
17672 }
17673
17674 // If right/Odd page
17675 if (isset($this->cssmgr->CSS['@PAGE>>PSEUDO>>RIGHT']) && $side == 'R') {
17676 $zp = $this->cssmgr->CSS['@PAGE>>PSEUDO>>RIGHT'];
17677 } else {
17678 $zp = array();
17679 }
17680 if (isset($zp['SIZE'])) {
17681 unset($zp['SIZE']);
17682 }
17683 if (isset($zp['SHEET-SIZE'])) {
17684 unset($zp['SHEET-SIZE']);
17685 }
17686 // Disallow margin-left or -right on :LEFT or :RIGHT
17687 if (isset($zp['MARGIN-LEFT'])) {
17688 unset($zp['MARGIN-LEFT']);
17689 }
17690 if (isset($zp['MARGIN-RIGHT'])) {
17691 unset($zp['MARGIN-RIGHT']);
17692 }
17693 if (is_array($zp) && !empty($zp)) {
17694 $p = array_merge($p, $zp);
17695 }
17696
17697 // If left/Even page
17698 if (isset($this->cssmgr->CSS['@PAGE>>PSEUDO>>LEFT']) && $side == 'L') {
17699 $zp = $this->cssmgr->CSS['@PAGE>>PSEUDO>>LEFT'];
17700 } else {
17701 $zp = array();
17702 }
17703 if (isset($zp['SIZE'])) {
17704 unset($zp['SIZE']);
17705 }
17706 if (isset($zp['SHEET-SIZE'])) {
17707 unset($zp['SHEET-SIZE']);
17708 }
17709 // Disallow margin-left or -right on :LEFT or :RIGHT
17710 if (isset($zp['MARGIN-LEFT'])) {
17711 unset($zp['MARGIN-LEFT']);
17712 }
17713 if (isset($zp['MARGIN-RIGHT'])) {
17714 unset($zp['MARGIN-RIGHT']);
17715 }
17716 if (is_array($zp) && !empty($zp)) {
17717 $p = array_merge($p, $zp);
17718 }
17719
17720 // If first page
17721 if (isset($this->cssmgr->CSS['@PAGE>>PSEUDO>>FIRST']) && $first) {
17722 $zp = $this->cssmgr->CSS['@PAGE>>PSEUDO>>FIRST'];
17723 } else {
17724 $zp = array();
17725 }
17726 if (isset($zp['SIZE'])) {
17727 unset($zp['SIZE']);
17728 }
17729 if (isset($zp['SHEET-SIZE'])) {
17730 unset($zp['SHEET-SIZE']);
17731 }
17732 // Disallow margin-left or -right on :FIRST // mPDF 5.7.3
17733 if (isset($zp['MARGIN-LEFT'])) {
17734 unset($zp['MARGIN-LEFT']);
17735 }
17736 if (isset($zp['MARGIN-RIGHT'])) {
17737 unset($zp['MARGIN-RIGHT']);
17738 }
17739 if (is_array($zp) && !empty($zp)) {
17740 $p = array_merge($p, $zp);
17741 }
17742
17743 // If named page
17744 if ($name) {
17745 if (isset($this->cssmgr->CSS['@PAGE>>NAMED>>' . $name])) {
17746 $zp = $this->cssmgr->CSS['@PAGE>>NAMED>>' . $name];
17747 } else {
17748 $zp = array();
17749 }
17750 if (is_array($zp) && !empty($zp)) {
17751 $p = array_merge($p, $zp);
17752 }
17753
17754 if (isset($p['EVEN-HEADER-NAME']) && $oddEven == 'E') {
17755 $p['HEADER'] = $p['EVEN-HEADER-NAME'];
17756 unset($p['EVEN-HEADER-NAME']);
17757 }
17758 if (isset($p['ODD-HEADER-NAME']) && $oddEven != 'E') {
17759 $p['HEADER'] = $p['ODD-HEADER-NAME'];
17760 unset($p['ODD-HEADER-NAME']);
17761 }
17762 if (isset($p['EVEN-FOOTER-NAME']) && $oddEven == 'E') {
17763 $p['FOOTER'] = $p['EVEN-FOOTER-NAME'];
17764 unset($p['EVEN-FOOTER-NAME']);
17765 }
17766 if (isset($p['ODD-FOOTER-NAME']) && $oddEven != 'E') {
17767 $p['FOOTER'] = $p['ODD-FOOTER-NAME'];
17768 unset($p['ODD-FOOTER-NAME']);
17769 }
17770
17771 // If named right/Odd page
17772 if (isset($this->cssmgr->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>RIGHT']) && $side == 'R') {
17773 $zp = $this->cssmgr->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>RIGHT'];
17774 } else {
17775 $zp = array();
17776 }
17777 if (isset($zp['SIZE'])) {
17778 unset($zp['SIZE']);
17779 }
17780 if (isset($zp['SHEET-SIZE'])) {
17781 unset($zp['SHEET-SIZE']);
17782 }
17783 // Disallow margin-left or -right on :LEFT or :RIGHT
17784 if (isset($zp['MARGIN-LEFT'])) {
17785 unset($zp['MARGIN-LEFT']);
17786 }
17787 if (isset($zp['MARGIN-RIGHT'])) {
17788 unset($zp['MARGIN-RIGHT']);
17789 }
17790 if (is_array($zp) && !empty($zp)) {
17791 $p = array_merge($p, $zp);
17792 }
17793
17794 // If named left/Even page
17795 if (isset($this->cssmgr->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>LEFT']) && $side == 'L') {
17796 $zp = $this->cssmgr->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>LEFT'];
17797 } else {
17798 $zp = array();
17799 }
17800 if (isset($zp['SIZE'])) {
17801 unset($zp['SIZE']);
17802 }
17803 if (isset($zp['SHEET-SIZE'])) {
17804 unset($zp['SHEET-SIZE']);
17805 }
17806 // Disallow margin-left or -right on :LEFT or :RIGHT
17807 if (isset($zp['MARGIN-LEFT'])) {
17808 unset($zp['MARGIN-LEFT']);
17809 }
17810 if (isset($zp['MARGIN-RIGHT'])) {
17811 unset($zp['MARGIN-RIGHT']);
17812 }
17813 if (is_array($zp) && !empty($zp)) {
17814 $p = array_merge($p, $zp);
17815 }
17816
17817 // If named first page
17818 if (isset($this->cssmgr->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>FIRST']) && $first) {
17819 $zp = $this->cssmgr->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>FIRST'];
17820 } else {
17821 $zp = array();
17822 }
17823 if (isset($zp['SIZE'])) {
17824 unset($zp['SIZE']);
17825 }
17826 if (isset($zp['SHEET-SIZE'])) {
17827 unset($zp['SHEET-SIZE']);
17828 }
17829 // Disallow margin-left or -right on :FIRST // mPDF 5.7.3
17830 if (isset($zp['MARGIN-LEFT'])) {
17831 unset($zp['MARGIN-LEFT']);
17832 }
17833 if (isset($zp['MARGIN-RIGHT'])) {
17834 unset($zp['MARGIN-RIGHT']);
17835 }
17836 if (is_array($zp) && !empty($zp)) {
17837 $p = array_merge($p, $zp);
17838 }
17839 }
17840
17841 $orientation = $mgl = $mgr = $mgt = $mgb = $mgh = $mgf = '';
17842 $header = $footer = '';
17843 $resetpagenum = $pagenumstyle = $suppress = '';
17844 $marks = '';
17845 $bg = array();
17846
17847 $newformat = '';
17848
17849
17850 if (isset($p['SHEET-SIZE']) && is_array($p['SHEET-SIZE'])) {
17851 $newformat = $p['SHEET-SIZE'];
17852 if ($newformat[0] > $newformat[1]) { // landscape
17853 $newformat = array_reverse($newformat);
17854 $p['ORIENTATION'] = 'L';
17855 } else {
17856 $p['ORIENTATION'] = 'P';
17857 }
17858 $this->_setPageSize($newformat, $p['ORIENTATION']);
17859 }
17860
17861 if (isset($p['SIZE']) && is_array($p['SIZE']) && !$newformat) {
17862 if ($p['SIZE']['W'] > $p['SIZE']['H']) {
17863 $p['ORIENTATION'] = 'L';
17864 } else {
17865 $p['ORIENTATION'] = 'P';
17866 }
17867 }
17868 if (is_array($p['SIZE'])) {
17869 if ($p['SIZE']['W'] > $this->fw) {
17870 $p['SIZE']['W'] = $this->fw;
17871 } // mPD 4.2 use fw not fPt
17872 if ($p['SIZE']['H'] > $this->fh) {
17873 $p['SIZE']['H'] = $this->fh;
17874 }
17875 if (($p['ORIENTATION'] == $this->DefOrientation && !$newformat) || ($newformat && $p['ORIENTATION'] == 'P')) {
17876 $outer_width_LR = ($this->fw - $p['SIZE']['W']) / 2;
17877 $outer_width_TB = ($this->fh - $p['SIZE']['H']) / 2;
17878 } else {
17879 $outer_width_LR = ($this->fh - $p['SIZE']['W']) / 2;
17880 $outer_width_TB = ($this->fw - $p['SIZE']['H']) / 2;
17881 }
17882 $pgw = $p['SIZE']['W'];
17883 $pgh = $p['SIZE']['H'];
17884 } else { // AUTO LANDSCAPE PORTRAIT
17885 $outer_width_LR = 0;
17886 $outer_width_TB = 0;
17887 if (!$newformat) {
17888 if (strtoupper($p['SIZE']) == 'AUTO') {
17889 $p['ORIENTATION'] = $this->DefOrientation;
17890 } elseif (strtoupper($p['SIZE']) == 'LANDSCAPE') {
17891 $p['ORIENTATION'] = 'L';
17892 } else {
17893 $p['ORIENTATION'] = 'P';
17894 }
17895 }
17896 if (($p['ORIENTATION'] == $this->DefOrientation && !$newformat) || ($newformat && $p['ORIENTATION'] == 'P')) {
17897 $pgw = $this->fw;
17898 $pgh = $this->fh;
17899 } else {
17900 $pgw = $this->fh;
17901 $pgh = $this->fw;
17902 }
17903 }
17904
17905 if (isset($p['HEADER']) && $p['HEADER']) {
17906 $header = $p['HEADER'];
17907 }
17908 if (isset($p['FOOTER']) && $p['FOOTER']) {
17909 $footer = $p['FOOTER'];
17910 }
17911 if (isset($p['RESETPAGENUM']) && $p['RESETPAGENUM']) {
17912 $resetpagenum = $p['RESETPAGENUM'];
17913 }
17914 if (isset($p['PAGENUMSTYLE']) && $p['PAGENUMSTYLE']) {
17915 $pagenumstyle = $p['PAGENUMSTYLE'];
17916 }
17917 if (isset($p['SUPPRESS']) && $p['SUPPRESS']) {
17918 $suppress = $p['SUPPRESS'];
17919 }
17920
17921 if (isset($p['MARKS'])) {
17922 if (preg_match('/cross/i', $p['MARKS']) && preg_match('/crop/i', $p['MARKS'])) {
17923 $marks = 'CROPCROSS';
17924 } elseif (strtoupper($p['MARKS']) == 'CROP') {
17925 $marks = 'CROP';
17926 } elseif (strtoupper($p['MARKS']) == 'CROSS') {
17927 $marks = 'CROSS';
17928 }
17929 }
17930
17931 if (isset($p['BACKGROUND-COLOR']) && $p['BACKGROUND-COLOR']) {
17932 $bg['BACKGROUND-COLOR'] = $p['BACKGROUND-COLOR'];
17933 }
17934 /* -- BACKGROUNDS -- */
17935 if (isset($p['BACKGROUND-GRADIENT']) && $p['BACKGROUND-GRADIENT']) {
17936 $bg['BACKGROUND-GRADIENT'] = $p['BACKGROUND-GRADIENT'];
17937 }
17938 if (isset($p['BACKGROUND-IMAGE']) && $p['BACKGROUND-IMAGE']) {
17939 $bg['BACKGROUND-IMAGE'] = $p['BACKGROUND-IMAGE'];
17940 }
17941 if (isset($p['BACKGROUND-REPEAT']) && $p['BACKGROUND-REPEAT']) {
17942 $bg['BACKGROUND-REPEAT'] = $p['BACKGROUND-REPEAT'];
17943 }
17944 if (isset($p['BACKGROUND-POSITION']) && $p['BACKGROUND-POSITION']) {
17945 $bg['BACKGROUND-POSITION'] = $p['BACKGROUND-POSITION'];
17946 }
17947 if (isset($p['BACKGROUND-IMAGE-RESIZE']) && $p['BACKGROUND-IMAGE-RESIZE']) {
17948 $bg['BACKGROUND-IMAGE-RESIZE'] = $p['BACKGROUND-IMAGE-RESIZE'];
17949 }
17950 if (isset($p['BACKGROUND-IMAGE-OPACITY'])) {
17951 $bg['BACKGROUND-IMAGE-OPACITY'] = $p['BACKGROUND-IMAGE-OPACITY'];
17952 }
17953 /* -- END BACKGROUNDS -- */
17954
17955 if (isset($p['MARGIN-LEFT'])) {
17956 $mgl = $this->ConvertSize($p['MARGIN-LEFT'], $pgw) + $outer_width_LR;
17957 }
17958 if (isset($p['MARGIN-RIGHT'])) {
17959 $mgr = $this->ConvertSize($p['MARGIN-RIGHT'], $pgw) + $outer_width_LR;
17960 }
17961 if (isset($p['MARGIN-BOTTOM'])) {
17962 $mgb = $this->ConvertSize($p['MARGIN-BOTTOM'], $pgh) + $outer_width_TB;
17963 }
17964 if (isset($p['MARGIN-TOP'])) {
17965 $mgt = $this->ConvertSize($p['MARGIN-TOP'], $pgh) + $outer_width_TB;
17966 }
17967 if (isset($p['MARGIN-HEADER'])) {
17968 $mgh = $this->ConvertSize($p['MARGIN-HEADER'], $pgh) + $outer_width_TB;
17969 }
17970 if (isset($p['MARGIN-FOOTER'])) {
17971 $mgf = $this->ConvertSize($p['MARGIN-FOOTER'], $pgh) + $outer_width_TB;
17972 }
17973
17974 if (isset($p['ORIENTATION']) && $p['ORIENTATION']) {
17975 $orientation = $p['ORIENTATION'];
17976 }
17977 $this->page_box['outer_width_LR'] = $outer_width_LR; // Used in MARKS:crop etc.
17978 $this->page_box['outer_width_TB'] = $outer_width_TB;
17979
17980 return array($orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $header, $footer, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat);
17981 }
17982
17983 /* -- END CSS-PAGE -- */
17984
17985
17986
17987 /* -- CSS-FLOAT -- */
17988
17989 // Added mPDF 3.0 Float DIV - CLEAR
17990 function ClearFloats($clear, $blklvl = 0)
17991 {
17992 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($blklvl, true);
17993 $end = $currpos = ($this->page * 1000 + $this->y);
17994 if ($clear == 'BOTH' && ($l_exists || $r_exists)) {
17995 $this->pageoutput[$this->page] = array();
17996 $end = max($l_max, $r_max, $currpos);
17997 } elseif ($clear == 'RIGHT' && $r_exists) {
17998 $this->pageoutput[$this->page] = array();
17999 $end = max($r_max, $currpos);
18000 } elseif ($clear == 'LEFT' && $l_exists) {
18001 $this->pageoutput[$this->page] = array();
18002 $end = max($l_max, $currpos);
18003 } else {
18004 return;
18005 }
18006 $old_page = $this->page;
18007 $new_page = intval($end / 1000);
18008 if ($old_page != $new_page) {
18009 $s = $this->PrintPageBackgrounds();
18010 // Writes after the marker so not overwritten later by page background etc.
18011 $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
18012 $this->pageBackgrounds = array();
18013 $this->page = $new_page;
18014 }
18015 $this->ResetMargins();
18016 $this->pageoutput[$this->page] = array();
18017 $this->y = (($end * 1000) % 1000000) / 1000; // mod changes operands to integers before processing
18018 }
18019
18020 // Added mPDF 3.0 Float DIV
18021 function GetFloatDivInfo($blklvl = 0, $clear = false)
18022 {
18023 // If blklvl specified, only returns floats at that level - for ClearFloats
18024 $l_exists = false;
18025 $r_exists = false;
18026 $l_max = 0;
18027 $r_max = 0;
18028 $l_width = 0;
18029 $r_width = 0;
18030 if (count($this->floatDivs)) {
18031 $currpos = ($this->page * 1000 + $this->y);
18032 foreach ($this->floatDivs AS $f) {
18033 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'])) {
18034 if ($f['side'] == 'L') {
18035 $l_exists = true;
18036 $l_max = max($l_max, $f['endpos']);
18037 $l_width = max($l_width, $f['w']);
18038 }
18039 if ($f['side'] == 'R') {
18040 $r_exists = true;
18041 $r_max = max($r_max, $f['endpos']);
18042 $r_width = max($r_width, $f['w']);
18043 }
18044 }
18045 }
18046 }
18047 return array($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width);
18048 }
18049
18050 /* -- END CSS-FLOAT -- */
18051
18052 // LIST MARKERS // mPDF 6 Lists
18053 function _setListMarker($listitemtype, $listitemimage, $listitemposition)
18054 {
18055 // if position:inside (and NOT table) - output now as a textbuffer; (so if next is block, will move to new line)
18056 // elseif position:outside (and NOT table) - output in front of first textbuffer output by setting listitem (cf. _saveTextBuffer)
18057 $e = '';
18058 $this->listitem = '';
18059 $spacer = ' ';
18060 // IMAGE
18061 if ($listitemimage && $listitemimage != 'none') {
18062 $listitemimage = trim(preg_replace('/url\(["\']*(.*?)["\']*\)/', '\\1', $listitemimage));
18063
18064 // ? Restrict maximum height/width of list marker??
18065 $maxWidth = 100;
18066 $maxHeight = 100;
18067
18068 $objattr = array();
18069 $objattr['margin_top'] = 0;
18070 $objattr['margin_bottom'] = 0;
18071 $objattr['margin_left'] = 0;
18072 $objattr['margin_right'] = 0;
18073 $objattr['padding_top'] = 0;
18074 $objattr['padding_bottom'] = 0;
18075 $objattr['padding_left'] = 0;
18076 $objattr['padding_right'] = 0;
18077 $objattr['width'] = 0;
18078 $objattr['height'] = 0;
18079 $objattr['border_top']['w'] = 0;
18080 $objattr['border_bottom']['w'] = 0;
18081 $objattr['border_left']['w'] = 0;
18082 $objattr['border_right']['w'] = 0;
18083 $objattr['visibility'] = 'visible';
18084 $srcpath = $listitemimage;
18085 $orig_srcpath = $listitemimage;
18086
18087 $objattr['vertical-align'] = 'BS'; // vertical alignment of marker (baseline)
18088 $w = 0;
18089 $h = 0;
18090
18091 // Image file
18092 $info = $this->_getImage($srcpath, true, true, $orig_srcpath);
18093 if (!$info)
18094 return;
18095 if ($info['w'] == 0 && $info['h'] == 0) {
18096 $info['h'] = $this->ConvertSize('1em', $this->blk[$this->blklvl]['inner_width'], $this->FontSize, false);
18097 }
18098 $objattr['file'] = $srcpath;
18099 //Default width and height calculation if needed
18100 if ($w == 0 and $h == 0) {
18101 /* -- IMAGES-WMF -- */
18102 if ($info['type'] == 'wmf') {
18103 // WMF units are twips (1/20pt)
18104 // divide by 20 to get points
18105 // divide by k to get user units
18106 $w = abs($info['w']) / (20 * _MPDFK);
18107 $h = abs($info['h']) / (20 * _MPDFK);
18108 } else
18109 /* -- END IMAGES-WMF -- */
18110 if ($info['type'] == 'svg') {
18111 // SVG units are pixels
18112 $w = abs($info['w']) / _MPDFK;
18113 $h = abs($info['h']) / _MPDFK;
18114 } else {
18115 //Put image at default image dpi
18116 $w = ($info['w'] / _MPDFK) * (72 / $this->img_dpi);
18117 $h = ($info['h'] / _MPDFK) * (72 / $this->img_dpi);
18118 }
18119 }
18120 // IF WIDTH OR HEIGHT SPECIFIED
18121 if ($w == 0)
18122 $w = abs($h * $info['w'] / $info['h']);
18123 if ($h == 0)
18124 $h = abs($w * $info['h'] / $info['w']);
18125
18126 if ($w > $maxWidth) {
18127 $w = $maxWidth;
18128 $h = abs($w * $info['h'] / $info['w']);
18129 }
18130
18131 if ($h > $maxHeight) {
18132 $h = $maxHeight;
18133 $w = abs($h * $info['w'] / $info['h']);
18134 }
18135 $objattr['type'] = 'image';
18136 $objattr['itype'] = $info['type'];
18137
18138 $objattr['orig_h'] = $info['h'];
18139 $objattr['orig_w'] = $info['w'];
18140 /* -- IMAGES-WMF -- */
18141 if ($info['type'] == 'wmf') {
18142 $objattr['wmf_x'] = $info['x'];
18143 $objattr['wmf_y'] = $info['y'];
18144 } else
18145 /* -- END IMAGES-WMF -- */
18146 if ($info['type'] == 'svg') {
18147 $objattr['wmf_x'] = $info['x'];
18148 $objattr['wmf_y'] = $info['y'];
18149 }
18150 $objattr['height'] = $h;
18151 $objattr['width'] = $w;
18152 $objattr['image_height'] = $h;
18153 $objattr['image_width'] = $w;
18154
18155 $objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
18156 $objattr['listmarker'] = true;
18157
18158 $objattr['listmarkerposition'] = $listitemposition;
18159
18160 $e = "\xbb\xa4\xactype=image,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
18161 $this->_saveTextBuffer($e);
18162
18163 if ($listitemposition == 'inside') {
18164 $e = $spacer;
18165 $this->_saveTextBuffer($e);
18166 }
18167 }
18168 // SYMBOL (needs new font)
18169 elseif ($listitemtype == 'disc' || $listitemtype == 'circle' || $listitemtype == 'square') {
18170 $objattr = array();
18171 $objattr['type'] = 'listmarker';
18172 $objattr['listmarkerposition'] = $listitemposition;
18173 $objattr['width'] = 0;
18174 $size = $this->ConvertSize($this->list_symbol_size, $this->FontSize);
18175 $objattr['size'] = $size;
18176 $objattr['offset'] = $this->ConvertSize($this->list_marker_offset, $this->FontSize);
18177
18178 if ($listitemposition == 'inside') {
18179 $objattr['width'] = $size + $objattr['offset'];
18180 }
18181
18182 $objattr['height'] = $this->FontSize;
18183 $objattr['vertical-align'] = 'T';
18184 $objattr['text'] = '';
18185 $objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
18186 $objattr['bullet'] = $listitemtype;
18187 $objattr['colorarray'] = $this->colorarray;
18188 $objattr['fontfamily'] = $this->FontFamily;
18189 $objattr['fontsize'] = $this->FontSize;
18190 $objattr['fontsizept'] = $this->FontSizePt;
18191 $objattr['fontstyle'] = $this->FontStyle;
18192
18193 $e = "\xbb\xa4\xactype=listmarker,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
18194 $this->listitem = $this->_saveTextBuffer($e, '', '', true); // true returns array
18195 // if ($listitemposition == 'inside') {
18196 // $e = $spacer;
18197 // $this->_saveTextBuffer($e);
18198 // }
18199 }
18200 // SYMBOL 2 (needs new font)
18201 elseif (preg_match('/U\+([a-fA-F0-9]+)/i', $listitemtype, $m)) {
18202 if ($this->_charDefined($this->CurrentFont['cw'], hexdec($m[1]))) {
18203 $list_item_marker = codeHex2utf($m[1]);
18204 } else {
18205 $list_item_marker = '-';
18206 }
18207 if (preg_match('/rgb\(.*?\)/', $listitemtype, $m)) {
18208 $list_item_color = $this->ConvertColor($m[0]);
18209 } else {
18210 $list_item_color = '';
18211 }
18212
18213 // SAVE then SET COLR
18214 $save_colorarray = $this->colorarray;
18215 if ($list_item_color) {
18216 $this->colorarray = $list_item_color;
18217 }
18218
18219 if ($listitemposition == 'inside') {
18220 $e = $list_item_marker . $spacer;
18221 $this->_saveTextBuffer($e);
18222 } else {
18223 $objattr = array();
18224 $objattr['type'] = 'listmarker';
18225 $objattr['width'] = 0;
18226 $objattr['height'] = $this->FontSize;
18227 $objattr['vertical-align'] = 'T';
18228 $objattr['text'] = $list_item_marker;
18229 $objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
18230 $objattr['colorarray'] = $this->colorarray;
18231 $objattr['fontfamily'] = $this->FontFamily;
18232 $objattr['fontsize'] = $this->FontSize;
18233 $objattr['fontsizept'] = $this->FontSizePt;
18234 $objattr['fontstyle'] = $this->FontStyle;
18235 $e = "\xbb\xa4\xactype=listmarker,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
18236 $this->listitem = $this->_saveTextBuffer($e, '', '', true); // true returns array
18237 }
18238 // RESET COLOR
18239 $this->colorarray = $save_colorarray;
18240 }
18241 // TEXT
18242 else {
18243 $counter = $this->listcounter[$this->listlvl];
18244 if ($listitemtype == 'none') {
18245 return;
18246 }
18247 $num = $this->_getStyledNumber($counter, $listitemtype, true);
18248
18249 if ($listitemposition == 'inside') {
18250 $e = $num . $this->list_number_suffix . $spacer;
18251 $this->_saveTextBuffer($e);
18252 } else {
18253 if (isset($this->blk[$this->blklvl]['direction']) && $this->blk[$this->blklvl]['direction'] == 'rtl') {
18254 // REPLACE MIRRORED RTL $this->list_number_suffix e.g. ) -> ( (NB could use UCDN::$mirror_pairs)
18255 $m = strtr($this->list_number_suffix, ")]}", "([{") . $num;
18256 } else {
18257 $m = $num . $this->list_number_suffix;
18258 }
18259
18260 $objattr = array();
18261 $objattr['type'] = 'listmarker';
18262 $objattr['width'] = 0;
18263 $objattr['height'] = $this->FontSize;
18264 $objattr['vertical-align'] = 'T';
18265 $objattr['text'] = $m;
18266 $objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
18267 $objattr['colorarray'] = $this->colorarray;
18268 $objattr['fontfamily'] = $this->FontFamily;
18269 $objattr['fontsize'] = $this->FontSize;
18270 $objattr['fontsizept'] = $this->FontSizePt;
18271 $objattr['fontstyle'] = $this->FontStyle;
18272 $e = "\xbb\xa4\xactype=listmarker,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
18273
18274 $this->listitem = $this->_saveTextBuffer($e, '', '', true); // true returns array
18275 }
18276 }
18277 }
18278
18279 // mPDF Lists
18280 function _getListMarkerWidth(&$currblk, &$a, &$i)
18281 {
18282 $blt_width = 0;
18283
18284 $markeroffset = $this->ConvertSize($this->list_marker_offset, $this->FontSize);
18285
18286 // Get Maximum number in the list
18287 $maxnum = $this->listcounter[$this->listlvl];
18288 if ($currblk['list_style_type'] != 'disc' && $currblk['list_style_type'] != 'circle' && $currblk['list_style_type'] != 'square') {
18289 $lvl = 1;
18290 for ($j = $i + 2; $j < count($a); $j+=2) {
18291 $e = $a[$j];
18292 if (!$e) {
18293 continue;
18294 }
18295 if ($e[0] == '/') { // end tag
18296 $e = strtoupper(substr($e, 1));
18297 if ($e == 'OL' || $e == 'UL') {
18298 if ($lvl == 1) {
18299 break;
18300 }
18301 $lvl--;
18302 }
18303 } else { // opening tag
18304 if (strpos($e, ' ')) {
18305 $e = substr($e, 0, strpos($e, ' '));
18306 }
18307 $e = strtoupper($e);
18308 if ($e == 'LI') {
18309 if ($lvl == 1) {
18310 $maxnum++;
18311 }
18312 } elseif ($e == 'OL' || $e == 'UL') {
18313 $lvl++;
18314 }
18315 }
18316 }
18317 }
18318
18319 switch ($currblk['list_style_type']) {
18320 case 'decimal':
18321 case '1':
18322 $blt_width = $this->GetStringWidth(str_repeat('5', strlen($maxnum)) . $this->list_number_suffix);
18323 break;
18324 case 'none':
18325 $blt_width = 0;
18326 break;
18327 case 'upper-alpha':
18328 case 'upper-latin':
18329 case 'A':
18330 $maxnumA = $this->dec2alpha($maxnum, true);
18331 if ($maxnum < 13) {
18332 $blt_width = $this->GetStringWidth('D' . $this->list_number_suffix);
18333 } else {
18334 $blt_width = $this->GetStringWidth(str_repeat('W', strlen($maxnumA)) . $this->list_number_suffix);
18335 }
18336 break;
18337 case 'lower-alpha':
18338 case 'lower-latin':
18339 case 'a':
18340 $maxnuma = $this->dec2alpha($maxnum, false);
18341 if ($maxnum < 13) {
18342 $blt_width = $this->GetStringWidth('b' . $this->list_number_suffix);
18343 } else {
18344 $blt_width = $this->GetStringWidth(str_repeat('m', strlen($maxnuma)) . $this->list_number_suffix);
18345 }
18346 break;
18347 case 'upper-roman':
18348 case 'I':
18349 if ($maxnum > 87) {
18350 $bbit = 87;
18351 } elseif ($maxnum > 86) {
18352 $bbit = 86;
18353 } elseif ($maxnum > 37) {
18354 $bbit = 38;
18355 } elseif ($maxnum > 36) {
18356 $bbit = 37;
18357 } elseif ($maxnum > 27) {
18358 $bbit = 28;
18359 } elseif ($maxnum > 26) {
18360 $bbit = 27;
18361 } elseif ($maxnum > 17) {
18362 $bbit = 18;
18363 } elseif ($maxnum > 16) {
18364 $bbit = 17;
18365 } elseif ($maxnum > 7) {
18366 $bbit = 8;
18367 } elseif ($maxnum > 6) {
18368 $bbit = 7;
18369 } elseif ($maxnum > 3) {
18370 $bbit = 4;
18371 } else {
18372 $bbit = $maxnum;
18373 }
18374 $maxlnum = $this->dec2roman($bbit, true);
18375 $blt_width = $this->GetStringWidth($maxlnum . $this->list_number_suffix);
18376 break;
18377 case 'lower-roman':
18378 case 'i':
18379 if ($maxnum > 87) {
18380 $bbit = 87;
18381 } elseif ($maxnum > 86) {
18382 $bbit = 86;
18383 } elseif ($maxnum > 37) {
18384 $bbit = 38;
18385 } elseif ($maxnum > 36) {
18386 $bbit = 37;
18387 } elseif ($maxnum > 27) {
18388 $bbit = 28;
18389 } elseif ($maxnum > 26) {
18390 $bbit = 27;
18391 } elseif ($maxnum > 17) {
18392 $bbit = 18;
18393 } elseif ($maxnum > 16) {
18394 $bbit = 17;
18395 } elseif ($maxnum > 7) {
18396 $bbit = 8;
18397 } elseif ($maxnum > 6) {
18398 $bbit = 7;
18399 } elseif ($maxnum > 3) {
18400 $bbit = 4;
18401 } else {
18402 $bbit = $maxnum;
18403 }
18404 $maxlnum = $this->dec2roman($bbit, false);
18405 $blt_width = $this->GetStringWidth($maxlnum . $this->list_number_suffix);
18406 break;
18407
18408 case 'disc':
18409 case 'circle':
18410 case 'square':
18411 $size = $this->ConvertSize($this->list_symbol_size, $this->FontSize);
18412 $offset = $this->ConvertSize($this->list_marker_offset, $this->FontSize);
18413 $blt_width = $size + $offset;
18414 break;
18415
18416 case 'arabic-indic':
18417 $blt_width = $this->GetStringWidth(str_repeat($this->dec2other(3, 0x0660), strlen($maxnum)) . $this->list_number_suffix);
18418 break;
18419 case 'persian':
18420 case 'urdu':
18421 $blt_width = $this->GetStringWidth(str_repeat($this->dec2other(3, 0x06F0), strlen($maxnum)) . $this->list_number_suffix);
18422 break;
18423 case 'bengali':
18424 $blt_width = $this->GetStringWidth(str_repeat($this->dec2other(3, 0x09E6), strlen($maxnum)) . $this->list_number_suffix);
18425 break;
18426 case 'devanagari':
18427 $blt_width = $this->GetStringWidth(str_repeat($this->dec2other(3, 0x0966), strlen($maxnum)) . $this->list_number_suffix);
18428 break;
18429 case 'gujarati':
18430 $blt_width = $this->GetStringWidth(str_repeat($this->dec2other(3, 0x0AE6), strlen($maxnum)) . $this->list_number_suffix);
18431 break;
18432 case 'gurmukhi':
18433 $blt_width = $this->GetStringWidth(str_repeat($this->dec2other(3, 0x0A66), strlen($maxnum)) . $this->list_number_suffix);
18434 break;
18435 case 'kannada':
18436 $blt_width = $this->GetStringWidth(str_repeat($this->dec2other(3, 0x0CE6), strlen($maxnum)) . $this->list_number_suffix);
18437 break;
18438 case 'malayalam':
18439 $blt_width = $this->GetStringWidth(str_repeat($this->dec2other(6, 0x0D66), strlen($maxnum)) . $this->list_number_suffix);
18440 break;
18441 case 'oriya':
18442 $blt_width = $this->GetStringWidth(str_repeat($this->dec2other(3, 0x0B66), strlen($maxnum)) . $this->list_number_suffix);
18443 break;
18444 case 'telugu':
18445 $blt_width = $this->GetStringWidth(str_repeat($this->dec2other(3, 0x0C66), strlen($maxnum)) . $this->list_number_suffix);
18446 break;
18447 case 'tamil':
18448 $blt_width = $this->GetStringWidth(str_repeat($this->dec2other(9, 0x0BE6), strlen($maxnum)) . $this->list_number_suffix);
18449 break;
18450 case 'thai':
18451 $blt_width = $this->GetStringWidth(str_repeat($this->dec2other(5, 0x0E50), strlen($maxnum)) . $this->list_number_suffix);
18452 break;
18453 default:
18454 $blt_width = $this->GetStringWidth(str_repeat('5', strlen($maxnum)) . $this->list_number_suffix);
18455 break;
18456 }
18457
18458 return ($blt_width + $markeroffset);
18459 }
18460
18461 /* -- TABLES -- */
18462
18463 // This function determines the shrink factor when resizing tables
18464 // val is the table_height / page_height_available
18465 // returns a scaling factor used as $shrin_k to resize the table
18466 // Overcompensating will be quicker but may unnecessarily shrink table too much
18467 // Undercompensating means it will reiterate more times (taking more processing time)
18468 function tbsqrt($val, $iteration = 3)
18469 {
18470 $k = 4; // Alters number of iterations until it returns $val itself - Must be > 2
18471 // Probably best guess and most accurate
18472 if ($iteration == 1)
18473 return sqrt($val);
18474 // Faster than using sqrt (because it won't undercompensate), and gives reasonable results
18475 //return 1+(($val-1)/2);
18476 $x = 2 - (($iteration - 2) / ($k - 2));
18477 if ($x == 0) {
18478 $ret = $val + 0.00001;
18479 } elseif ($x < 0) {
18480 $ret = 1 + ( pow(2, ($iteration - 2 - $k)) / 1000 );
18481 } else {
18482 $ret = 1 + (($val - 1) / $x);
18483 }
18484 return $ret;
18485 }
18486
18487 /* -- END TABLES -- */
18488
18489 function _saveTextBuffer($t, $link = '', $intlink = '', $return = false)
18490 { // mPDF 6 Lists
18491 $arr = array();
18492 $arr[0] = $t;
18493 if (isset($link) && $link)
18494 $arr[1] = $link;
18495 $arr[2] = $this->currentfontstyle;
18496 if (isset($this->colorarray) && $this->colorarray)
18497 $arr[3] = $this->colorarray;
18498 $arr[4] = $this->currentfontfamily;
18499 $arr[5] = $this->currentLang; // mPDF 6
18500 if (isset($intlink) && $intlink)
18501 $arr[7] = $intlink;
18502 // mPDF 6
18503 // If Kerning set for OTL, and useOTL has positive value, but has not set for this particular script,
18504 // set for kerning via kern table
18505 // e.g. Latin script when useOTL set as 0x80
18506 if (isset($this->OTLtags['Plus']) && strpos($this->OTLtags['Plus'], 'kern') !== false && empty($this->OTLdata['GPOSinfo'])) {
18507 $this->textvar = ($this->textvar | FC_KERNING);
18508 }
18509 $arr[8] = $this->textvar; // mPDF 5.7.1
18510 if (isset($this->textparam) && $this->textparam)
18511 $arr[9] = $this->textparam;
18512 if (isset($this->spanbgcolorarray) && $this->spanbgcolorarray)
18513 $arr[10] = $this->spanbgcolorarray;
18514 $arr[11] = $this->currentfontsize;
18515 if (isset($this->ReqFontStyle) && $this->ReqFontStyle)
18516 $arr[12] = $this->ReqFontStyle;
18517 if (isset($this->lSpacingCSS) && $this->lSpacingCSS)
18518 $arr[14] = $this->lSpacingCSS;
18519 if (isset($this->wSpacingCSS) && $this->wSpacingCSS)
18520 $arr[15] = $this->wSpacingCSS;
18521 if (isset($this->spanborddet) && $this->spanborddet)
18522 $arr[16] = $this->spanborddet;
18523 if (isset($this->textshadow) && $this->textshadow)
18524 $arr[17] = $this->textshadow;
18525 if (isset($this->OTLdata) && $this->OTLdata) {
18526 $arr[18] = $this->OTLdata;
18527 $this->OTLdata = array();
18528 } // mPDF 5.7.1
18529 else {
18530 $arr[18] = NULL;
18531 }
18532 // mPDF 6 Lists
18533 if ($return) {
18534 return ($arr);
18535 }
18536 if ($this->listitem) {
18537 $this->textbuffer[] = $this->listitem;
18538 $this->listitem = array();
18539 }
18540 $this->textbuffer[] = $arr;
18541 }
18542
18543 function _saveCellTextBuffer($t, $link = '', $intlink = '')
18544 {
18545 $arr = array();
18546 $arr[0] = $t;
18547 if (isset($link) && $link)
18548 $arr[1] = $link;
18549 $arr[2] = $this->currentfontstyle;
18550 if (isset($this->colorarray) && $this->colorarray)
18551 $arr[3] = $this->colorarray;
18552 $arr[4] = $this->currentfontfamily;
18553 if (isset($intlink) && $intlink)
18554 $arr[7] = $intlink;
18555 // mPDF 6
18556 // If Kerning set for OTL, and useOTL has positive value, but has not set for this particular script,
18557 // set for kerning via kern table
18558 // e.g. Latin script when useOTL set as 0x80
18559 if (isset($this->OTLtags['Plus']) && strpos($this->OTLtags['Plus'], 'kern') !== false && empty($this->OTLdata['GPOSinfo'])) {
18560 $this->textvar = ($this->textvar | FC_KERNING);
18561 }
18562 $arr[8] = $this->textvar; // mPDF 5.7.1
18563 if (isset($this->textparam) && $this->textparam)
18564 $arr[9] = $this->textparam;
18565 if (isset($this->spanbgcolorarray) && $this->spanbgcolorarray)
18566 $arr[10] = $this->spanbgcolorarray;
18567 $arr[11] = $this->currentfontsize;
18568 if (isset($this->ReqFontStyle) && $this->ReqFontStyle)
18569 $arr[12] = $this->ReqFontStyle;
18570 if (isset($this->lSpacingCSS) && $this->lSpacingCSS)
18571 $arr[14] = $this->lSpacingCSS;
18572 if (isset($this->wSpacingCSS) && $this->wSpacingCSS)
18573 $arr[15] = $this->wSpacingCSS;
18574 if (isset($this->spanborddet) && $this->spanborddet)
18575 $arr[16] = $this->spanborddet;
18576 if (isset($this->textshadow) && $this->textshadow)
18577 $arr[17] = $this->textshadow;
18578 if (isset($this->OTLdata) && $this->OTLdata) {
18579 $arr[18] = $this->OTLdata;
18580 $this->OTLdata = array();
18581 } // mPDF 5.7.1
18582 else {
18583 $arr[18] = NULL;
18584 }
18585 $this->cell[$this->row][$this->col]['textbuffer'][] = $arr;
18586 }
18587
18588 function printbuffer($arrayaux, $blockstate = 0, $is_table = false, $table_draft = false, $cell_dir = '')
18589 {
18590 // $blockstate = 0; // NO margins/padding
18591 // $blockstate = 1; // Top margins/padding only
18592 // $blockstate = 2; // Bottom margins/padding only
18593 // $blockstate = 3; // Top & bottom margins/padding
18594 $this->spanbgcolorarray = '';
18595 $this->spanbgcolor = false;
18596 $this->spanborder = false;
18597 $this->spanborddet = array();
18598 $paint_ht_corr = 0;
18599 /* -- CSS-FLOAT -- */
18600 if (count($this->floatDivs)) {
18601 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
18602 if (($this->blk[$this->blklvl]['inner_width'] - $l_width - $r_width) < (2 * $this->GetCharWidth('W', false))) {
18603 // Too narrow to fit - try to move down past L or R float
18604 if ($l_max < $r_max && ($this->blk[$this->blklvl]['inner_width'] - $r_width) > (2 * $this->GetCharWidth('W', false))) {
18605 $this->ClearFloats('LEFT', $this->blklvl);
18606 } elseif ($r_max < $l_max && ($this->blk[$this->blklvl]['inner_width'] - $l_width) > (2 * $this->GetCharWidth('W', false))) {
18607 $this->ClearFloats('RIGHT', $this->blklvl);
18608 } else {
18609 $this->ClearFloats('BOTH', $this->blklvl);
18610 }
18611 }
18612 }
18613 /* -- END CSS-FLOAT -- */
18614 $bak_y = $this->y;
18615 $bak_x = $this->x;
18616 $align = '';
18617 if (!$is_table) {
18618 if (isset($this->blk[$this->blklvl]['align']) && $this->blk[$this->blklvl]['align']) {
18619 $align = $this->blk[$this->blklvl]['align'];
18620 }
18621 // Block-align is set by e.g. <.. align="center"> Takes priority for this block but not inherited
18622 if (isset($this->blk[$this->blklvl]['block-align']) && $this->blk[$this->blklvl]['block-align']) {
18623 $align = $this->blk[$this->blklvl]['block-align'];
18624 }
18625 if (isset($this->blk[$this->blklvl]['direction']))
18626 $blockdir = $this->blk[$this->blklvl]['direction'];
18627 else
18628 $blockdir = "";
18629 $this->divwidth = $this->blk[$this->blklvl]['width'];
18630 }
18631 else {
18632 $align = $this->cellTextAlign;
18633 $blockdir = $cell_dir;
18634 }
18635 $oldpage = $this->page;
18636
18637 // ADDED for Out of Block now done as Flowing Block
18638 if ($this->divwidth == 0) {
18639 $this->divwidth = $this->pgwidth;
18640 }
18641
18642 if (!$is_table) {
18643 $this->SetLineHeight($this->FontSizePt, $this->blk[$this->blklvl]['line_height']);
18644 }
18645 $this->divheight = $this->lineheight;
18646 $old_height = $this->divheight;
18647
18648 // As a failsafe - if font has been set but not output to page
18649 if (!$table_draft)
18650 $this->SetFont($this->default_font, '', $this->default_font_size, true, true); // force output to page
18651
18652 $this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, true, $blockdir, $table_draft);
18653
18654 $array_size = count($arrayaux);
18655
18656 // Added - Otherwise <div><div><p> did not output top margins/padding for 1st/2nd div
18657 if ($array_size == 0) {
18658 $this->finishFlowingBlock(true);
18659 } // true = END of flowing block
18660 // mPDF 6
18661 // ALL the chunks of textbuffer need to have at least basic OTLdata set
18662 // First make sure each element/chunk has the OTLdata for Bidi set.
18663 for ($i = 0; $i < $array_size; $i++) {
18664 if (empty($arrayaux[$i][18])) {
18665 if (substr($arrayaux[$i][0], 0, 3) == "\xbb\xa4\xac") { // object identifier has been identified!
18666 $unicode = array(0xFFFC); // Object replacement character
18667 } else {
18668 $unicode = $this->UTF8StringToArray($arrayaux[$i][0], false);
18669 }
18670 $is_strong = false;
18671 $this->getBasicOTLdata($arrayaux[$i][18], $unicode, $is_strong);
18672 }
18673 // Gets messed up if try and use core fonts inside a paragraph of text which needs to be BiDi re-ordered or OTLdata set
18674 if (($blockdir == 'rtl' || $this->biDirectional) && isset($arrayaux[$i][4]) && in_array($arrayaux[$i][4], array('ccourier', 'ctimes', 'chelvetica', 'csymbol', 'czapfdingbats'))) {
18675 throw new MpdfException("You cannot use core fonts in a document which contains RTL text.");
18676 }
18677 }
18678 // mPDF 6
18679 // Process bidirectional text ready for bidi-re-ordering (which is done after line-breaks are established in WriteFlowingBlock etc.)
18680 if (($blockdir == 'rtl' || $this->biDirectional) && !$table_draft) {
18681 if (!class_exists('otl', false)) {
18682 include(_MPDF_PATH . 'classes/otl.php');
18683 }
18684 if (empty($this->otl)) {
18685 $this->otl = new otl($this);
18686 }
18687 $this->otl->_bidiPrepare($arrayaux, $blockdir);
18688 $array_size = count($arrayaux);
18689 }
18690
18691
18692 // Remove empty items // mPDF 6
18693 for ($i = $array_size - 1; $i > 0; $i--) {
18694 if (empty($arrayaux[$i][0]) && (isset($arrayaux[$i][16]) && $arrayaux[$i][16] !== '0') && empty($arrayaux[$i][7])) {
18695 unset($arrayaux[$i]);
18696 }
18697 }
18698
18699 // Correct adjoining borders for inline elements
18700 if (isset($arrayaux[0][16])) {
18701 $lastspanborder = $arrayaux[0][16];
18702 } else {
18703 $lastspanborder = false;
18704 }
18705 for ($i = 1; $i < $array_size; $i++) {
18706 if (isset($arrayaux[$i][16]) && $arrayaux[$i][16] == $lastspanborder &&
18707 ((!isset($arrayaux[$i][9]['bord-decoration']) && !isset($arrayaux[$i - 1][9]['bord-decoration'])) ||
18708 (isset($arrayaux[$i][9]['bord-decoration']) && isset($arrayaux[$i - 1][9]['bord-decoration']) && $arrayaux[$i][9]['bord-decoration'] == $arrayaux[$i - 1][9]['bord-decoration'])
18709 )
18710 ) {
18711 if (isset($arrayaux[$i][16]['R'])) {
18712 $lastspanborder = $arrayaux[$i][16];
18713 } else {
18714 $lastspanborder = false;
18715 }
18716 $arrayaux[$i][16]['L']['s'] = 0;
18717 $arrayaux[$i][16]['L']['w'] = 0;
18718 $arrayaux[$i - 1][16]['R']['s'] = 0;
18719 $arrayaux[$i - 1][16]['R']['w'] = 0;
18720 } else {
18721 if (isset($arrayaux[$i][16]['R'])) {
18722 $lastspanborder = $arrayaux[$i][16];
18723 } else {
18724 $lastspanborder = false;
18725 }
18726 }
18727 }
18728
18729 for ($i = 0; $i < $array_size; $i++) {
18730 // COLS
18731 $oldcolumn = $this->CurrCol;
18732 $vetor = isset($arrayaux[$i]) ? $arrayaux[$i] : NULL;
18733 if ($i == 0 && $vetor[0] != "\n" && ! $this->ispre) {
18734 $vetor[0] = ltrim($vetor[0]);
18735 if (!empty($vetor[18])) {
18736 $this->otl->trimOTLdata($vetor[18], true, false);
18737 } // *OTL*
18738 }
18739
18740 // FIXED TO ALLOW IT TO SHOW '0'
18741 if (empty($vetor[0]) && !($vetor[0] === '0') && empty($vetor[7])) { //Ignore empty text and not carrying an internal link
18742 //Check if it is the last element. If so then finish printing the block
18743 if ($i == ($array_size - 1)) {
18744 $this->finishFlowingBlock(true);
18745 } // true = END of flowing block
18746 continue;
18747 }
18748
18749
18750 //Activating buffer properties
18751 if (isset($vetor[11]) && $vetor[11] != '') { // Font Size
18752 if ($is_table && $this->shrin_k) {
18753 $this->SetFontSize($vetor[11] / $this->shrin_k, false);
18754 } else {
18755 $this->SetFontSize($vetor[11], false);
18756 }
18757 }
18758
18759 if (isset($vetor[17]) && !empty($vetor[17])) { //TextShadow
18760 $this->textshadow = $vetor[17];
18761 }
18762 if (isset($vetor[16]) && !empty($vetor[16])) { //Border
18763 $this->spanborddet = $vetor[16];
18764 $this->spanborder = true;
18765 }
18766
18767 if (isset($vetor[15])) { // Word spacing
18768 $this->wSpacingCSS = $vetor[15];
18769 if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
18770 $this->minwSpacing = $this->ConvertSize($this->wSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
18771 }
18772 }
18773 if (isset($vetor[14])) { // Letter spacing
18774 $this->lSpacingCSS = $vetor[14];
18775 if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
18776 $this->fixedlSpacing = $this->ConvertSize($this->lSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
18777 }
18778 }
18779
18780
18781 if (isset($vetor[10]) and ! empty($vetor[10])) { //Background color
18782 $this->spanbgcolorarray = $vetor[10];
18783 $this->spanbgcolor = true;
18784 }
18785 if (isset($vetor[9]) and ! empty($vetor[9])) { // Text parameters - Outline + hyphens
18786 $this->textparam = $vetor[9];
18787 $this->SetTextOutline($this->textparam);
18788 // mPDF 5.7.3 inline text-decoration parameters
18789 if ($is_table && $this->shrin_k) {
18790 if (isset($this->textparam['text-baseline'])) {
18791 $this->textparam['text-baseline'] /= $this->shrin_k;
18792 }
18793 if (isset($this->textparam['decoration-baseline'])) {
18794 $this->textparam['decoration-baseline'] /= $this->shrin_k;
18795 }
18796 if (isset($this->textparam['decoration-fontsize'])) {
18797 $this->textparam['decoration-fontsize'] /= $this->shrin_k;
18798 }
18799 }
18800 }
18801 if (isset($vetor[8])) { // mPDF 5.7.1
18802 $this->textvar = $vetor[8];
18803 }
18804 if (isset($vetor[7]) and $vetor[7] != '') { // internal target: <a name="anyvalue">
18805 $ily = $this->y;
18806 if ($this->table_rotate) {
18807 $this->internallink[$vetor[7]] = array("Y" => $ily, "PAGE" => $this->page, "tbrot" => true);
18808 } elseif ($this->kwt) {
18809 $this->internallink[$vetor[7]] = array("Y" => $ily, "PAGE" => $this->page, "kwt" => true);
18810 } elseif ($this->ColActive) {
18811 $this->internallink[$vetor[7]] = array("Y" => $ily, "PAGE" => $this->page, "col" => $this->CurrCol);
18812 } elseif (!$this->keep_block_together) {
18813 $this->internallink[$vetor[7]] = array("Y" => $ily, "PAGE" => $this->page);
18814 }
18815 if (empty($vetor[0])) { //Ignore empty text
18816 //Check if it is the last element. If so then finish printing the block
18817 if ($i == ($array_size - 1)) {
18818 $this->finishFlowingBlock(true);
18819 } // true = END of flowing block
18820 continue;
18821 }
18822 }
18823 if (isset($vetor[5]) and $vetor[5] != '') { // Language // mPDF 6
18824 $this->currentLang = $vetor[5];
18825 }
18826 if (isset($vetor[4]) and $vetor[4] != '') { // Font Family
18827 $font = $this->SetFont($vetor[4], $this->FontStyle, 0, false);
18828 }
18829 if (!empty($vetor[3])) { //Font Color
18830 $cor = $vetor[3];
18831 $this->SetTColor($cor);
18832 }
18833 if (isset($vetor[2]) and $vetor[2] != '') { //Bold,Italic styles
18834 $this->SetStyles($vetor[2]);
18835 }
18836
18837 if (isset($vetor[12]) and $vetor[12] != '') { //Requested Bold,Italic
18838 $this->ReqFontStyle = $vetor[12];
18839 }
18840 if (isset($vetor[1]) and $vetor[1] != '') { //LINK
18841 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.)
18842 //Repeated reference to same anchor?
18843 while (array_key_exists($vetor[1], $this->internallink))
18844 $vetor[1] = "#" . $vetor[1];
18845 $this->internallink[$vetor[1]] = $this->AddLink();
18846 $vetor[1] = $this->internallink[$vetor[1]];
18847 }
18848 $this->HREF = $vetor[1]; // HREF link style set here ******
18849 }
18850
18851 // SPECIAL CONTENT - IMAGES & FORM OBJECTS
18852 //Print-out special content
18853
18854 if (substr($vetor[0], 0, 3) == "\xbb\xa4\xac") { //identifier has been identified!
18855 $objattr = $this->_getObjAttr($vetor[0]);
18856
18857 /* -- TABLES -- */
18858 if ($objattr['type'] == 'nestedtable') {
18859 if ($objattr['nestedcontent']) {
18860 $level = $objattr['level'];
18861 $table = &$this->table[$level][$objattr['table']];
18862
18863 if ($table_draft) {
18864 $this->y += $this->table[($level + 1)][$objattr['nestedcontent']]['h']; // nested table height
18865 $this->finishFlowingBlock(false, 'nestedtable');
18866 } else {
18867
18868 $cell = &$table['cells'][$objattr['row']][$objattr['col']];
18869 $this->finishFlowingBlock(false, 'nestedtable');
18870 $save_dw = $this->divwidth;
18871 $save_buffer = $this->cellBorderBuffer;
18872 $this->cellBorderBuffer = array();
18873 $ncx = $this->x;
18874 list($dummyx, $w) = $this->_tableGetWidth($table, $objattr['row'], $objattr['col']);
18875 $ntw = $this->table[($level + 1)][$objattr['nestedcontent']]['w']; // nested table width
18876 if (!$this->simpleTables) {
18877 if ($this->packTableData) {
18878 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cell['borderbin']);
18879 } else {
18880 $br = $cell['border_details']['R']['w'];
18881 $bl = $cell['border_details']['L']['w'];
18882 }
18883 if ($table['borders_separate']) {
18884 $innerw = $w - $bl - $br - $cell['padding']['L'] - $cell['padding']['R'] - $table['border_spacing_H'];
18885 } else {
18886 $innerw = $w - $bl / 2 - $br / 2 - $cell['padding']['L'] - $cell['padding']['R'];
18887 }
18888 } elseif ($this->simpleTables) {
18889 if ($table['borders_separate']) {
18890 $innerw = $w - $table['simple']['border_details']['L']['w'] - $table['simple']['border_details']['R']['w'] - $cell['padding']['L'] - $cell['padding']['R'] - $table['border_spacing_H'];
18891 } else {
18892 $innerw = $w - $table['simple']['border_details']['L']['w'] / 2 - $table['simple']['border_details']['R']['w'] / 2 - $cell['padding']['L'] - $cell['padding']['R'];
18893 }
18894 }
18895 if ($cell['a'] == 'C' || $this->table[($level + 1)][$objattr['nestedcontent']]['a'] == 'C') {
18896 $ncx += ($innerw - $ntw) / 2;
18897 } elseif ($cell['a'] == 'R' || $this->table[($level + 1)][$objattr['nestedcontent']]['a'] == 'R') {
18898 $ncx += $innerw - $ntw;
18899 }
18900 $this->x = $ncx;
18901
18902 $this->_tableWrite($this->table[($level + 1)][$objattr['nestedcontent']]);
18903 $this->cellBorderBuffer = $save_buffer;
18904 $this->x = $bak_x;
18905 $this->divwidth = $save_dw;
18906 }
18907
18908 $this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, false, $blockdir, $table_draft);
18909 }
18910 } else {
18911 /* -- END TABLES -- */
18912 if ($is_table) { // *TABLES*
18913 $maxWidth = $this->divwidth; // *TABLES*
18914 } // *TABLES*
18915 else { // *TABLES*
18916 $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']);
18917 } // *TABLES*
18918
18919 /* -- CSS-IMAGE-FLOAT -- */
18920 // If float (already) exists at this level
18921 if (isset($this->floatmargins['R']) && $this->y <= $this->floatmargins['R']['y1'] && $this->y >= $this->floatmargins['R']['y0']) {
18922 $maxWidth -= $this->floatmargins['R']['w'];
18923 }
18924 if (isset($this->floatmargins['L']) && $this->y <= $this->floatmargins['L']['y1'] && $this->y >= $this->floatmargins['L']['y0']) {
18925 $maxWidth -= $this->floatmargins['L']['w'];
18926 }
18927 /* -- END CSS-IMAGE-FLOAT -- */
18928
18929 list($skipln) = $this->inlineObject($objattr['type'], '', $this->y, $objattr, $this->lMargin, ($this->flowingBlockAttr['contentWidth'] / _MPDFK), $maxWidth, $this->flowingBlockAttr['height'], false, $is_table);
18930 // 1 -> New line needed because of width
18931 // -1 -> Will fit width on line but NEW PAGE REQUIRED because of height
18932 // -2 -> Will not fit on line therefore needs new line but thus NEW PAGE REQUIRED
18933 $iby = $this->y;
18934 $oldpage = $this->page;
18935 $oldcol = $this->CurrCol;
18936 if (($skipln == 1 || $skipln == -2) && !isset($objattr['float'])) {
18937 $this->finishFlowingBlock(false, $objattr['type']);
18938 $this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, false, $blockdir, $table_draft);
18939 }
18940
18941 if (!$table_draft) {
18942 $thispage = $this->page;
18943 if ($this->CurrCol != $oldcol) {
18944 $changedcol = true;
18945 } else {
18946 $changedcol = false;
18947 }
18948
18949 // the previous lines can already have triggered page break or column change
18950 if (!$changedcol && $skipln < 0 && $this->AcceptPageBreak() && $thispage == $oldpage) {
18951
18952 $this->AddPage($this->CurOrientation);
18953
18954 // Added to correct Images already set on line before page advanced
18955 // i.e. if second inline image on line is higher than first and forces new page
18956 if (count($this->objectbuffer)) {
18957 $yadj = $iby - $this->y;
18958 foreach ($this->objectbuffer AS $ib => $val) {
18959 if ($this->objectbuffer[$ib]['OUTER-Y'])
18960 $this->objectbuffer[$ib]['OUTER-Y'] -= $yadj;
18961 if ($this->objectbuffer[$ib]['BORDER-Y'])
18962 $this->objectbuffer[$ib]['BORDER-Y'] -= $yadj;
18963 if ($this->objectbuffer[$ib]['INNER-Y'])
18964 $this->objectbuffer[$ib]['INNER-Y'] -= $yadj;
18965 }
18966 }
18967 }
18968
18969 // Added to correct for OddEven Margins
18970 if ($this->page != $oldpage) {
18971 if (($this->page - $oldpage) % 2 == 1) {
18972 $bak_x += $this->MarginCorrection;
18973 }
18974 $oldpage = $this->page;
18975 $y = $this->tMargin - $paint_ht_corr;
18976 $this->oldy = $this->tMargin - $paint_ht_corr;
18977 $old_height = 0;
18978 }
18979 $this->x = $bak_x;
18980 /* -- COLUMNS -- */
18981 // COLS
18982 // OR COLUMN CHANGE
18983 if ($this->CurrCol != $oldcolumn) {
18984 if ($this->directionality == 'rtl') { // *OTL*
18985 $bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
18986 } // *OTL*
18987 else { // *OTL*
18988 $bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
18989 } // *OTL*
18990 $this->x = $bak_x;
18991 $oldcolumn = $this->CurrCol;
18992 $y = $this->y0 - $paint_ht_corr;
18993 $this->oldy = $this->y0 - $paint_ht_corr;
18994 $old_height = 0;
18995 }
18996 /* -- END COLUMNS -- */
18997 }
18998
18999 /* -- CSS-IMAGE-FLOAT -- */
19000 if ($objattr['type'] == 'image' && isset($objattr['float'])) {
19001 $fy = $this->y;
19002
19003 // DIV TOP MARGIN/BORDER/PADDING
19004 if ($this->flowingBlockAttr['newblock'] && ($this->flowingBlockAttr['blockstate'] == 1 || $this->flowingBlockAttr['blockstate'] == 3) && $this->flowingBlockAttr['lineCount'] == 0) {
19005 $fy += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
19006 }
19007
19008 if ($objattr['float'] == 'R') {
19009 $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']);
19010 } elseif ($objattr['float'] == 'L') {
19011 $fx = $this->lMargin + ($this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_left']);
19012 }
19013 $w = $objattr['width'];
19014 $h = abs($objattr['height']);
19015
19016 $widthLeft = $maxWidth - ($this->flowingBlockAttr['contentWidth'] / _MPDFK);
19017 $maxHeight = $this->h - ($this->tMargin + $this->margin_header + $this->bMargin + 10);
19018 // For Images
19019 $extraWidth = ($objattr['border_left']['w'] + $objattr['border_right']['w'] + $objattr['margin_left'] + $objattr['margin_right']);
19020 $extraHeight = ($objattr['border_top']['w'] + $objattr['border_bottom']['w'] + $objattr['margin_top'] + $objattr['margin_bottom']);
19021
19022 if ($objattr['itype'] == 'wmf' || $objattr['itype'] == 'svg') {
19023 $file = $objattr['file'];
19024 $info = $this->formobjects[$file];
19025 } else {
19026 $file = $objattr['file'];
19027 $info = $this->images[$file];
19028 }
19029 $img_w = $w - $extraWidth;
19030 $img_h = $h - $extraHeight;
19031 if ($objattr['border_left']['w']) {
19032 $objattr['BORDER-WIDTH'] = $img_w + (($objattr['border_left']['w'] + $objattr['border_right']['w']) / 2);
19033 $objattr['BORDER-HEIGHT'] = $img_h + (($objattr['border_top']['w'] + $objattr['border_bottom']['w']) / 2);
19034 $objattr['BORDER-X'] = $fx + $objattr['margin_left'] + (($objattr['border_left']['w']) / 2);
19035 $objattr['BORDER-Y'] = $fy + $objattr['margin_top'] + (($objattr['border_top']['w']) / 2);
19036 }
19037 $objattr['INNER-WIDTH'] = $img_w;
19038 $objattr['INNER-HEIGHT'] = $img_h;
19039 $objattr['INNER-X'] = $fx + $objattr['margin_left'] + ($objattr['border_left']['w']);
19040 $objattr['INNER-Y'] = $fy + $objattr['margin_top'] + ($objattr['border_top']['w']);
19041 $objattr['ID'] = $info['i'];
19042 $objattr['OUTER-WIDTH'] = $w;
19043 $objattr['OUTER-HEIGHT'] = $h;
19044 $objattr['OUTER-X'] = $fx;
19045 $objattr['OUTER-Y'] = $fy;
19046 if ($objattr['float'] == 'R') {
19047 // If R float already exists at this level
19048 $this->floatmargins['R']['skipline'] = false;
19049 if (isset($this->floatmargins['R']['y1']) && $this->floatmargins['R']['y1'] > 0 && $fy < $this->floatmargins['R']['y1']) {
19050 $this->WriteFlowingBlock($vetor[0], $vetor[18]); // mPDF 5.7.1
19051 }
19052 // If L float already exists at this level
19053 elseif (isset($this->floatmargins['L']['y1']) && $this->floatmargins['L']['y1'] > 0 && $fy < $this->floatmargins['L']['y1']) {
19054 // Final check distance between floats is not now too narrow to fit text
19055 $mw = 2 * $this->GetCharWidth('W', false);
19056 if (($this->blk[$this->blklvl]['inner_width'] - $w - $this->floatmargins['L']['w']) < $mw) {
19057 $this->WriteFlowingBlock($vetor[0], $vetor[18]); // mPDF 5.7.1
19058 } else {
19059 $this->floatmargins['R']['x'] = $fx;
19060 $this->floatmargins['R']['w'] = $w;
19061 $this->floatmargins['R']['y0'] = $fy;
19062 $this->floatmargins['R']['y1'] = $fy + $h;
19063 if ($skipln == 1) {
19064 $this->floatmargins['R']['skipline'] = true;
19065 $this->floatmargins['R']['id'] = count($this->floatbuffer) + 0;
19066 $objattr['skipline'] = true;
19067 }
19068 $this->floatbuffer[] = $objattr;
19069 }
19070 } else {
19071 $this->floatmargins['R']['x'] = $fx;
19072 $this->floatmargins['R']['w'] = $w;
19073 $this->floatmargins['R']['y0'] = $fy;
19074 $this->floatmargins['R']['y1'] = $fy + $h;
19075 if ($skipln == 1) {
19076 $this->floatmargins['R']['skipline'] = true;
19077 $this->floatmargins['R']['id'] = count($this->floatbuffer) + 0;
19078 $objattr['skipline'] = true;
19079 }
19080 $this->floatbuffer[] = $objattr;
19081 }
19082 } elseif ($objattr['float'] == 'L') {
19083 // If L float already exists at this level
19084 $this->floatmargins['L']['skipline'] = false;
19085 if (isset($this->floatmargins['L']['y1']) && $this->floatmargins['L']['y1'] > 0 && $fy < $this->floatmargins['L']['y1']) {
19086 $this->floatmargins['L']['skipline'] = false;
19087 $this->WriteFlowingBlock($vetor[0], $vetor[18]); // mPDF 5.7.1
19088 }
19089 // If R float already exists at this level
19090 elseif (isset($this->floatmargins['R']['y1']) && $this->floatmargins['R']['y1'] > 0 && $fy < $this->floatmargins['R']['y1']) {
19091 // Final check distance between floats is not now too narrow to fit text
19092 $mw = 2 * $this->GetCharWidth('W', false);
19093 if (($this->blk[$this->blklvl]['inner_width'] - $w - $this->floatmargins['R']['w']) < $mw) {
19094 $this->WriteFlowingBlock($vetor[0], $vetor[18]); // mPDF 5.7.1
19095 } else {
19096 $this->floatmargins['L']['x'] = $fx + $w;
19097 $this->floatmargins['L']['w'] = $w;
19098 $this->floatmargins['L']['y0'] = $fy;
19099 $this->floatmargins['L']['y1'] = $fy + $h;
19100 if ($skipln == 1) {
19101 $this->floatmargins['L']['skipline'] = true;
19102 $this->floatmargins['L']['id'] = count($this->floatbuffer) + 0;
19103 $objattr['skipline'] = true;
19104 }
19105 $this->floatbuffer[] = $objattr;
19106 }
19107 } else {
19108 $this->floatmargins['L']['x'] = $fx + $w;
19109 $this->floatmargins['L']['w'] = $w;
19110 $this->floatmargins['L']['y0'] = $fy;
19111 $this->floatmargins['L']['y1'] = $fy + $h;
19112 if ($skipln == 1) {
19113 $this->floatmargins['L']['skipline'] = true;
19114 $this->floatmargins['L']['id'] = count($this->floatbuffer) + 0;
19115 $objattr['skipline'] = true;
19116 }
19117 $this->floatbuffer[] = $objattr;
19118 }
19119 }
19120 } else {
19121 /* -- END CSS-IMAGE-FLOAT -- */
19122 $this->WriteFlowingBlock($vetor[0], (isset($vetor[18]) ? $vetor[18] : NULL)); // mPDF 5.7.1
19123 /* -- CSS-IMAGE-FLOAT -- */
19124 }
19125 /* -- END CSS-IMAGE-FLOAT -- */
19126 } // *TABLES*
19127 } // END If special content
19128 else { //THE text
19129 if ($this->tableLevel) {
19130 $paint_ht_corr = 0;
19131 } // To move the y up when new column/page started if div border needed
19132 else {
19133 $paint_ht_corr = $this->blk[$this->blklvl]['border_top']['w'];
19134 }
19135
19136 if ($vetor[0] == "\n") { //We are reading a <BR> now turned into newline ("\n")
19137 if ($this->flowingBlockAttr['content']) {
19138 $this->finishFlowingBlock(false, 'br');
19139 } elseif ($is_table) {
19140 $this->y+= $this->_computeLineheight($this->cellLineHeight);
19141 } elseif (!$is_table) {
19142 $this->DivLn($this->lineheight);
19143 if ($this->ColActive) {
19144 $this->breakpoints[$this->CurrCol][] = $this->y;
19145 } // *COLUMNS*
19146 }
19147 // Added to correct for OddEven Margins
19148 if ($this->page != $oldpage) {
19149 if (($this->page - $oldpage) % 2 == 1) {
19150 $bak_x += $this->MarginCorrection;
19151 }
19152 $oldpage = $this->page;
19153 $y = $this->tMargin - $paint_ht_corr;
19154 $this->oldy = $this->tMargin - $paint_ht_corr;
19155 $old_height = 0;
19156 }
19157 $this->x = $bak_x;
19158 /* -- COLUMNS -- */
19159 // COLS
19160 // OR COLUMN CHANGE
19161 if ($this->CurrCol != $oldcolumn) {
19162 if ($this->directionality == 'rtl') { // *OTL*
19163 $bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
19164 } // *OTL*
19165 else { // *OTL*
19166 $bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
19167 } // *OTL*
19168 $this->x = $bak_x;
19169 $oldcolumn = $this->CurrCol;
19170 $y = $this->y0 - $paint_ht_corr;
19171 $this->oldy = $this->y0 - $paint_ht_corr;
19172 $old_height = 0;
19173 }
19174 /* -- END COLUMNS -- */
19175 $this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, false, $blockdir, $table_draft);
19176 } else {
19177 $this->WriteFlowingBlock($vetor[0], $vetor[18]); // mPDF 5.7.1
19178 // Added to correct for OddEven Margins
19179 if ($this->page != $oldpage) {
19180 if (($this->page - $oldpage) % 2 == 1) {
19181 $bak_x += $this->MarginCorrection;
19182 $this->x = $bak_x;
19183 }
19184 $oldpage = $this->page;
19185 $y = $this->tMargin - $paint_ht_corr;
19186 $this->oldy = $this->tMargin - $paint_ht_corr;
19187 $old_height = 0;
19188 }
19189 /* -- COLUMNS -- */
19190 // COLS
19191 // OR COLUMN CHANGE
19192 if ($this->CurrCol != $oldcolumn) {
19193 if ($this->directionality == 'rtl') { // *OTL*
19194 $bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
19195 } // *OTL*
19196 else { // *OTL*
19197 $bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
19198 } // *OTL*
19199 $this->x = $bak_x;
19200 $oldcolumn = $this->CurrCol;
19201 $y = $this->y0 - $paint_ht_corr;
19202 $this->oldy = $this->y0 - $paint_ht_corr;
19203 $old_height = 0;
19204 }
19205 /* -- END COLUMNS -- */
19206 }
19207 }
19208
19209 //Check if it is the last element. If so then finish printing the block
19210 if ($i == ($array_size - 1)) {
19211 $this->finishFlowingBlock(true); // true = END of flowing block
19212 // Added to correct for OddEven Margins
19213 if ($this->page != $oldpage) {
19214 if (($this->page - $oldpage) % 2 == 1) {
19215 $bak_x += $this->MarginCorrection;
19216 $this->x = $bak_x;
19217 }
19218 $oldpage = $this->page;
19219 $y = $this->tMargin - $paint_ht_corr;
19220 $this->oldy = $this->tMargin - $paint_ht_corr;
19221 $old_height = 0;
19222 }
19223
19224 /* -- COLUMNS -- */
19225 // COLS
19226 // OR COLUMN CHANGE
19227 if ($this->CurrCol != $oldcolumn) {
19228 if ($this->directionality == 'rtl') { // *OTL*
19229 $bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
19230 } // *OTL*
19231 else { // *OTL*
19232 $bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
19233 } // *OTL*
19234 $this->x = $bak_x;
19235 $oldcolumn = $this->CurrCol;
19236 $y = $this->y0 - $paint_ht_corr;
19237 $this->oldy = $this->y0 - $paint_ht_corr;
19238 $old_height = 0;
19239 }
19240 /* -- END COLUMNS -- */
19241 }
19242
19243 // RESETTING VALUES
19244 $this->SetTColor($this->ConvertColor(0));
19245 $this->SetDColor($this->ConvertColor(0));
19246 $this->SetFColor($this->ConvertColor(255));
19247 $this->colorarray = '';
19248 $this->spanbgcolorarray = '';
19249 $this->spanbgcolor = false;
19250 $this->spanborder = false;
19251 $this->spanborddet = array();
19252 $this->HREF = '';
19253 $this->textparam = array();
19254 $this->SetTextOutline();
19255
19256 $this->textvar = 0x00; // mPDF 5.7.1
19257 $this->OTLtags = array();
19258 $this->textshadow = '';
19259
19260 $this->currentfontfamily = '';
19261 $this->currentfontsize = '';
19262 $this->currentfontstyle = '';
19263 $this->currentLang = $this->default_lang; // mPDF 6
19264 $this->RestrictUnicodeFonts($this->default_available_fonts); // mPDF 6
19265 /* -- TABLES -- */
19266 if ($this->tableLevel) {
19267 $this->SetLineHeight('', $this->table[1][1]['cellLineHeight']); // *TABLES*
19268 } else
19269 /* -- END TABLES -- */
19270 if (isset($this->blk[$this->blklvl]['line_height']) && $this->blk[$this->blklvl]['line_height']) {
19271 $this->SetLineHeight('', $this->blk[$this->blklvl]['line_height']); // sets default line height
19272 }
19273 $this->ResetStyles();
19274 $this->lSpacingCSS = '';
19275 $this->wSpacingCSS = '';
19276 $this->fixedlSpacing = false;
19277 $this->minwSpacing = 0;
19278 $this->SetDash();
19279 $this->dash_on = false;
19280 $this->dotted_on = false;
19281 }//end of for(i=0;i<arraysize;i++)
19282
19283 $this->Reset(); // mPDF 6
19284 // PAINT DIV BORDER // DISABLED IN COLUMNS AS DOESN'T WORK WHEN BROKEN ACROSS COLS??
19285 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)) {
19286 $bottom_y = $this->y; // Does not include Bottom Margin
19287 if (isset($this->blk[$this->blklvl]['startpage']) && $this->blk[$this->blklvl]['startpage'] != $this->page && $blockstate != 1) {
19288 $this->PaintDivBB('pagetop', $blockstate);
19289 } elseif ($blockstate != 1) {
19290 $this->PaintDivBB('', $blockstate);
19291 }
19292 $this->y = $bottom_y;
19293 $this->x = $bak_x;
19294 }
19295
19296 // Reset Font
19297 $this->SetFontSize($this->default_font_size, false);
19298 if ($table_draft) {
19299 $ch = $this->y - $bak_y;
19300 $this->y = $bak_y;
19301 $this->x = $bak_x;
19302 return $ch;
19303 }
19304 }
19305
19306 function _setDashBorder($style, $div, $cp, $side)
19307 {
19308 if ($style == 'dashed' && (($side == 'L' || $side == 'R') || ($side == 'T' && $div != 'pagetop' && !$cp) || ($side == 'B' && $div != 'pagebottom') )) {
19309 $dashsize = 2; // final dash will be this + 1*linewidth
19310 $dashsizek = 1.5; // ratio of Dash/Blank
19311 $this->SetDash($dashsize, ($dashsize / $dashsizek) + ($this->LineWidth * 2));
19312 } elseif ($style == 'dotted' || ($side == 'T' && ($div == 'pagetop' || $cp)) || ($side == 'B' && $div == 'pagebottom')) {
19313 //Round join and cap
19314 $this->SetLineJoin(1);
19315 $this->SetLineCap(1);
19316 $this->SetDash(0.001, ($this->LineWidth * 3));
19317 }
19318 }
19319
19320 function _setBorderLine($b, $k = 1)
19321 {
19322 $this->SetLineWidth($b['w'] / $k);
19323 $this->SetDColor($b['c']);
19324 if ($b['c'][0] == 5) { // RGBa
19325 $this->SetAlpha(ord($b['c'][4]) / 100, 'Normal', false, 'S') . "\n"; // mPDF 5.7.2
19326 } elseif ($b['c'][0] == 6) { // CMYKa
19327 $this->SetAlpha(ord($b['c'][5]) / 100, 'Normal', false, 'S') . "\n"; // mPDF 5.7.2
19328 }
19329 }
19330
19331 function PaintDivBB($divider = '', $blockstate = 0, $blvl = 0)
19332 {
19333 // Borders & backgrounds are done elsewhere for columns - messes up the repositioning in printcolumnbuffer
19334 if ($this->ColActive) {
19335 return;
19336 } // *COLUMNS*
19337 if ($this->keep_block_together) {
19338 return;
19339 } // mPDF 6
19340 $save_y = $this->y;
19341 if (!$blvl) {
19342 $blvl = $this->blklvl;
19343 }
19344 $x0 = $x1 = $y0 = $y1 = 0;
19345
19346 // Added mPDF 3.0 Float DIV
19347 if (isset($this->blk[$blvl]['bb_painted'][$this->page]) && $this->blk[$blvl]['bb_painted'][$this->page]) {
19348 return;
19349 } // *CSS-FLOAT*
19350
19351 if (isset($this->blk[$blvl]['x0'])) {
19352 $x0 = $this->blk[$blvl]['x0'];
19353 } // left
19354 if (isset($this->blk[$blvl]['y1'])) {
19355 $y1 = $this->blk[$blvl]['y1'];
19356 } // bottom
19357 // Added mPDF 3.0 Float DIV - ensures backgrounds/borders are drawn to bottom of page
19358 if ($y1 == 0) {
19359 if ($divider == 'pagebottom') {
19360 $y1 = $this->h - $this->bMargin;
19361 } else {
19362 $y1 = $this->y;
19363 }
19364 }
19365
19366 if (isset($this->blk[$blvl]['startpage']) && $this->blk[$blvl]['startpage'] != $this->page) {
19367 $continuingpage = true;
19368 } else {
19369 $continuingpage = false;
19370 }
19371
19372 if (isset($this->blk[$blvl]['y0'])) {
19373 $y0 = $this->blk[$blvl]['y0'];
19374 }
19375 $h = $y1 - $y0;
19376 $w = $this->blk[$blvl]['width'];
19377 $x1 = $x0 + $w;
19378
19379 // Set border-widths as used here
19380 $border_top = $this->blk[$blvl]['border_top']['w'];
19381 $border_bottom = $this->blk[$blvl]['border_bottom']['w'];
19382 $border_left = $this->blk[$blvl]['border_left']['w'];
19383 $border_right = $this->blk[$blvl]['border_right']['w'];
19384 if (!$this->blk[$blvl]['border_top'] || $divider == 'pagetop' || $continuingpage) {
19385 $border_top = 0;
19386 }
19387 if (!$this->blk[$blvl]['border_bottom'] || $blockstate == 1 || $divider == 'pagebottom') {
19388 $border_bottom = 0;
19389 }
19390
19391 $brTL_H = 0;
19392 $brTL_V = 0;
19393 $brTR_H = 0;
19394 $brTR_V = 0;
19395 $brBL_H = 0;
19396 $brBL_V = 0;
19397 $brBR_H = 0;
19398 $brBR_V = 0;
19399
19400 $brset = false;
19401 /* -- BORDER-RADIUS -- */
19402 if (isset($this->blk[$blvl]['border_radius_TL_H'])) {
19403 $brTL_H = $this->blk[$blvl]['border_radius_TL_H'];
19404 $brset = true;
19405 }
19406 if (isset($this->blk[$blvl]['border_radius_TL_V'])) {
19407 $brTL_V = $this->blk[$blvl]['border_radius_TL_V'];
19408 $brset = true;
19409 }
19410 if (isset($this->blk[$blvl]['border_radius_TR_H'])) {
19411 $brTR_H = $this->blk[$blvl]['border_radius_TR_H'];
19412 $brset = true;
19413 }
19414 if (isset($this->blk[$blvl]['border_radius_TR_V'])) {
19415 $brTR_V = $this->blk[$blvl]['border_radius_TR_V'];
19416 $brset = true;
19417 }
19418 if (isset($this->blk[$blvl]['border_radius_BR_H'])) {
19419 $brBR_H = $this->blk[$blvl]['border_radius_BR_H'];
19420 $brset = true;
19421 }
19422 if (isset($this->blk[$blvl]['border_radius_BR_V'])) {
19423 $brBR_V = $this->blk[$blvl]['border_radius_BR_V'];
19424 $brset = true;
19425 }
19426 if (isset($this->blk[$blvl]['border_radius_BL_H'])) {
19427 $brBL_H = $this->blk[$blvl]['border_radius_BL_H'];
19428 $brset = true;
19429 }
19430 if (isset($this->blk[$blvl]['border_radius_BL_V'])) {
19431 $brBL_V = $this->blk[$blvl]['border_radius_BL_V'];
19432 $brset = true;
19433 }
19434
19435 if (!$this->blk[$blvl]['border_top'] || $divider == 'pagetop' || $continuingpage) {
19436 $brTL_H = 0;
19437 $brTL_V = 0;
19438 $brTR_H = 0;
19439 $brTR_V = 0;
19440 }
19441 if (!$this->blk[$blvl]['border_bottom'] || $blockstate == 1 || $divider == 'pagebottom') {
19442 $brBL_H = 0;
19443 $brBL_V = 0;
19444 $brBR_H = 0;
19445 $brBR_V = 0;
19446 }
19447
19448 // Disallow border-radius if it is smaller than the border width.
19449 if ($brTL_H < min($border_left, $border_top)) {
19450 $brTL_H = $brTL_V = 0;
19451 }
19452 if ($brTL_V < min($border_left, $border_top)) {
19453 $brTL_V = $brTL_H = 0;
19454 }
19455 if ($brTR_H < min($border_right, $border_top)) {
19456 $brTR_H = $brTR_V = 0;
19457 }
19458 if ($brTR_V < min($border_right, $border_top)) {
19459 $brTR_V = $brTR_H = 0;
19460 }
19461 if ($brBL_H < min($border_left, $border_bottom)) {
19462 $brBL_H = $brBL_V = 0;
19463 }
19464 if ($brBL_V < min($border_left, $border_bottom)) {
19465 $brBL_V = $brBL_H = 0;
19466 }
19467 if ($brBR_H < min($border_right, $border_bottom)) {
19468 $brBR_H = $brBR_V = 0;
19469 }
19470 if ($brBR_V < min($border_right, $border_bottom)) {
19471 $brBR_V = $brBR_H = 0;
19472 }
19473
19474 // CHECK FOR radii that sum to > width or height of div ********
19475 $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));
19476 if ($f < 1) {
19477 $brTL_H *= $f;
19478 $brTL_V *= $f;
19479 $brTR_H *= $f;
19480 $brTR_V *= $f;
19481 $brBL_H *= $f;
19482 $brBL_V *= $f;
19483 $brBR_H *= $f;
19484 $brBR_V *= $f;
19485 }
19486 /* -- END BORDER-RADIUS -- */
19487
19488 $tbcol = $this->ConvertColor(255);
19489 for ($l = 0; $l <= $blvl; $l++) {
19490 if ($this->blk[$l]['bgcolor']) {
19491 $tbcol = $this->blk[$l]['bgcolorarray'];
19492 }
19493 }
19494
19495 // BORDERS
19496 if (isset($this->blk[$blvl]['y0']) && $this->blk[$blvl]['y0']) {
19497 $y0 = $this->blk[$blvl]['y0'];
19498 }
19499 $h = $y1 - $y0;
19500 $w = $this->blk[$blvl]['width'];
19501
19502 if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
19503 $tbd = $this->blk[$blvl]['border_top'];
19504
19505 $legend = '';
19506 $legbreakL = 0;
19507 $legbreakR = 0;
19508 // BORDER LEGEND
19509 if (isset($this->blk[$blvl]['border_legend']) && $this->blk[$blvl]['border_legend']) {
19510 $legend = $this->blk[$blvl]['border_legend']; // Same structure array as textbuffer
19511 $txt = $legend[0] = ltrim($legend[0]);
19512 if (!empty($legend[18])) {
19513 $this->otl->trimOTLdata($legend[18], true, false);
19514 } // *OTL*
19515 //Set font, size, style, color
19516 $this->SetFont($legend[4], $legend[2], $legend[11]);
19517 if (isset($legend[3]) && $legend[3]) {
19518 $cor = $legend[3];
19519 $this->SetTColor($cor);
19520 }
19521 $stringWidth = $this->GetStringWidth($txt, true, $legend[18], $legend[8]);
19522 $save_x = $this->x;
19523 $save_y = $this->y;
19524 $save_currentfontfamily = $this->FontFamily;
19525 $save_currentfontsize = $this->FontSizePt;
19526 $save_currentfontstyle = $this->FontStyle;
19527 $this->y = $y0 - $this->FontSize / 2 + $this->blk[$blvl]['border_top']['w'] / 2;
19528 $this->x = $x0 + $this->blk[$blvl]['padding_left'] + $this->blk[$blvl]['border_left']['w'];
19529
19530 // Set the distance from the border line to the text ? make configurable variable
19531 $gap = 0.2 * $this->FontSize;
19532 $legbreakL = $this->x - $gap;
19533 $legbreakR = $this->x + $stringWidth + $gap;
19534 $this->magic_reverse_dir($txt, $this->blk[$blvl]['direction'], $legend[18]);
19535 $fill = '';
19536 $this->Cell($stringWidth, $this->FontSize, $txt, '', 0, 'C', $fill, '', 0, 0, 0, 'M', $fill, false, $legend[18], $legend[8]);
19537 // Reset
19538 $this->x = $save_x;
19539 $this->y = $save_y;
19540 $this->SetFont($save_currentfontfamily, $save_currentfontstyle, $save_currentfontsize);
19541 $this->SetTColor($this->ConvertColor(0));
19542 }
19543
19544 if (isset($tbd['s']) && $tbd['s']) {
19545 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
19546 $this->_out('q');
19547 $this->SetLineWidth(0);
19548 $this->_out(sprintf('%.3F %.3F m ', ($x0) * _MPDFK, ($this->h - ($y0)) * _MPDFK));
19549 $this->_out(sprintf('%.3F %.3F l ', ($x0 + $border_left) * _MPDFK, ($this->h - ($y0 + $border_top)) * _MPDFK));
19550 $this->_out(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * _MPDFK, ($this->h - ($y0 + $border_top)) * _MPDFK));
19551 $this->_out(sprintf('%.3F %.3F l ', ($x0 + $w) * _MPDFK, ($this->h - ($y0)) * _MPDFK));
19552 $this->_out(' h W n '); // Ends path no-op & Sets the clipping path
19553 }
19554
19555 $this->_setBorderLine($tbd);
19556 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
19557 $legbreakL -= $border_top / 2; // because line cap different
19558 $legbreakR += $border_top / 2;
19559 $this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'T');
19560 }
19561 /* -- BORDER-RADIUS -- */ elseif (($brTL_V && $brTL_H) || ($brTR_V && $brTR_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19562 $this->SetLineJoin(0);
19563 $this->SetLineCap(0);
19564 }
19565 $s = '';
19566 if ($brTR_H && $brTR_V) {
19567 $s .= ($this->_EllipseArc($x0 + $w - $brTR_H, $y0 + $brTR_V, $brTR_H - $border_top / 2, $brTR_V - $border_top / 2, 1, 2, true)) . "\n";
19568 } else
19569 /* -- END BORDER-RADIUS -- */
19570 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19571 $s .= (sprintf('%.3F %.3F m ', ($x0 + $w) * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19572 } else {
19573 $s .= (sprintf('%.3F %.3F m ', ($x0 + $w - ($border_top / 2)) * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19574 }
19575 /* -- BORDER-RADIUS -- */
19576 if ($brTL_H && $brTL_V) {
19577 if ($legend) {
19578 if ($legbreakR < ($x0 + $w - $brTR_H)) {
19579 $s .= (sprintf('%.3F %.3F l ', $legbreakR * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19580 }
19581 if ($legbreakL > ($x0 + $brTL_H )) {
19582 $s .= (sprintf('%.3F %.3F m ', $legbreakL * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19583 $s .= (sprintf('%.3F %.3F l ', ($x0 + $brTL_H ) * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK) . "\n");
19584 } else {
19585 $s .= (sprintf('%.3F %.3F m ', ($x0 + $brTL_H ) * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19586 }
19587 } else {
19588 $s .= (sprintf('%.3F %.3F l ', ($x0 + $brTL_H ) * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19589 }
19590 $s .= ($this->_EllipseArc($x0 + $brTL_H, $y0 + $brTL_V, $brTL_H - $border_top / 2, $brTL_V - $border_top / 2, 2, 1)) . "\n";
19591 } else {
19592 /* -- END BORDER-RADIUS -- */
19593 if ($legend) {
19594 if ($legbreakR < ($x0 + $w)) {
19595 $s .= (sprintf('%.3F %.3F l ', $legbreakR * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19596 }
19597 if ($legbreakL > ($x0)) {
19598 $s .= (sprintf('%.3F %.3F m ', $legbreakL * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19599 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19600 $s .= (sprintf('%.3F %.3F l ', ($x0) * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19601 } else {
19602 $s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_top / 2)) * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19603 }
19604 } elseif ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19605 $s .= (sprintf('%.3F %.3F m ', ($x0) * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19606 } else {
19607 $s .= (sprintf('%.3F %.3F m ', ($x0 + $border_top / 2) * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19608 }
19609 } elseif ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19610 $s .= (sprintf('%.3F %.3F l ', ($x0) * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19611 } else {
19612 $s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_top / 2)) * _MPDFK, ($this->h - ($y0 + ($border_top / 2))) * _MPDFK)) . "\n";
19613 }
19614 /* -- BORDER-RADIUS -- */
19615 }
19616 /* -- END BORDER-RADIUS -- */
19617 $s .= 'S' . "\n";
19618 $this->_out($s);
19619
19620 if ($tbd['style'] == 'double') {
19621 $this->SetLineWidth($tbd['w'] / 3);
19622 $this->SetDColor($tbcol);
19623 $this->_out($s);
19624 }
19625 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
19626 $this->_out('Q');
19627 }
19628
19629 // Reset Corners and Dash off
19630 $this->SetLineWidth(0.1);
19631 $this->SetDColor($this->ConvertColor(0));
19632 $this->SetLineJoin(2);
19633 $this->SetLineCap(2);
19634 $this->SetDash();
19635 }
19636 }
19637 // Reinstate line above for dotted line divider when block border crosses a page
19638 //elseif ($divider == 'pagetop' || $continuingpage) {
19639
19640 if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
19641 $tbd = $this->blk[$blvl]['border_bottom'];
19642 if (isset($tbd['s']) && $tbd['s']) {
19643 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
19644 $this->_out('q');
19645 $this->SetLineWidth(0);
19646 $this->_out(sprintf('%.3F %.3F m ', ($x0) * _MPDFK, ($this->h - ($y0 + $h)) * _MPDFK));
19647 $this->_out(sprintf('%.3F %.3F l ', ($x0 + $border_left) * _MPDFK, ($this->h - ($y0 + $h - $border_bottom)) * _MPDFK));
19648 $this->_out(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * _MPDFK, ($this->h - ($y0 + $h - $border_bottom)) * _MPDFK));
19649 $this->_out(sprintf('%.3F %.3F l ', ($x0 + $w) * _MPDFK, ($this->h - ($y0 + $h)) * _MPDFK));
19650 $this->_out(' h W n '); // Ends path no-op & Sets the clipping path
19651 }
19652
19653 $this->_setBorderLine($tbd);
19654 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
19655 $this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'B');
19656 }
19657 /* -- BORDER-RADIUS -- */ elseif (($brBL_V && $brBL_H) || ($brBR_V && $brBR_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19658 $this->SetLineJoin(0);
19659 $this->SetLineCap(0);
19660 }
19661 $s = '';
19662 if ($brBL_H && $brBL_V) {
19663 $s .= ($this->_EllipseArc($x0 + $brBL_H, $y0 + $h - $brBL_V, $brBL_H - $border_bottom / 2, $brBL_V - $border_bottom / 2, 3, 2, true)) . "\n";
19664 } else
19665 /* -- END BORDER-RADIUS -- */
19666 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19667 $s .= (sprintf('%.3F %.3F m ', ($x0) * _MPDFK, ($this->h - ($y0 + $h - ($border_bottom / 2))) * _MPDFK)) . "\n";
19668 } else {
19669 $s .= (sprintf('%.3F %.3F m ', ($x0 + ($border_bottom / 2)) * _MPDFK, ($this->h - ($y0 + $h - ($border_bottom / 2))) * _MPDFK)) . "\n";
19670 }
19671 /* -- BORDER-RADIUS -- */
19672 if ($brBR_H && $brBR_V) {
19673 $s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_bottom / 2) - $brBR_H ) * _MPDFK, ($this->h - ($y0 + $h - ($border_bottom / 2))) * _MPDFK)) . "\n";
19674 $s .= ($this->_EllipseArc($x0 + $w - $brBR_H, $y0 + $h - $brBR_V, $brBR_H - $border_bottom / 2, $brBR_V - $border_bottom / 2, 4, 1)) . "\n";
19675 } else
19676 /* -- END BORDER-RADIUS -- */
19677 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19678 $s .= (sprintf('%.3F %.3F l ', ($x0 + $w) * _MPDFK, ($this->h - ($y0 + $h - ($border_bottom / 2))) * _MPDFK)) . "\n";
19679 } else {
19680 $s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_bottom / 2)) * _MPDFK, ($this->h - ($y0 + $h - ($border_bottom / 2))) * _MPDFK)) . "\n";
19681 }
19682 $s .= 'S' . "\n";
19683 $this->_out($s);
19684
19685 if ($tbd['style'] == 'double') {
19686 $this->SetLineWidth($tbd['w'] / 3);
19687 $this->SetDColor($tbcol);
19688 $this->_out($s);
19689 }
19690 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
19691 $this->_out('Q');
19692 }
19693
19694
19695 // Reset Corners and Dash off
19696 $this->SetLineWidth(0.1);
19697 $this->SetDColor($this->ConvertColor(0));
19698 $this->SetLineJoin(2);
19699 $this->SetLineCap(2);
19700 $this->SetDash();
19701 }
19702 }
19703 // Reinstate line below for dotted line divider when block border crosses a page
19704 //elseif ($blockstate == 1 || $divider == 'pagebottom') {
19705
19706 if ($this->blk[$blvl]['border_left']) {
19707 $tbd = $this->blk[$blvl]['border_left'];
19708 if (isset($tbd['s']) && $tbd['s']) {
19709 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
19710 $this->_out('q');
19711 $this->SetLineWidth(0);
19712 $this->_out(sprintf('%.3F %.3F m ', ($x0) * _MPDFK, ($this->h - ($y0)) * _MPDFK));
19713 $this->_out(sprintf('%.3F %.3F l ', ($x0 + $border_left) * _MPDFK, ($this->h - ($y0 + $border_top)) * _MPDFK));
19714 $this->_out(sprintf('%.3F %.3F l ', ($x0 + $border_left) * _MPDFK, ($this->h - ($y0 + $h - $border_bottom)) * _MPDFK));
19715 $this->_out(sprintf('%.3F %.3F l ', ($x0) * _MPDFK, ($this->h - ($y0 + $h)) * _MPDFK));
19716 $this->_out(' h W n '); // Ends path no-op & Sets the clipping path
19717 }
19718
19719 $this->_setBorderLine($tbd);
19720 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
19721 $this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'L');
19722 }
19723 /* -- BORDER-RADIUS -- */ elseif (($brTL_V && $brTL_H) || ($brBL_V && $brBL_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19724 $this->SetLineJoin(0);
19725 $this->SetLineCap(0);
19726 }
19727 $s = '';
19728 if ($brTL_V && $brTL_H) {
19729 $s .= ($this->_EllipseArc($x0 + $brTL_H, $y0 + $brTL_V, $brTL_H - $border_left / 2, $brTL_V - $border_left / 2, 2, 2, true)) . "\n";
19730 } else
19731 /* -- END BORDER-RADIUS -- */
19732 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19733 $s .= (sprintf('%.3F %.3F m ', ($x0 + ($border_left / 2)) * _MPDFK, ($this->h - ($y0)) * _MPDFK)) . "\n";
19734 } else {
19735 $s .= (sprintf('%.3F %.3F m ', ($x0 + ($border_left / 2)) * _MPDFK, ($this->h - ($y0 + ($border_left / 2))) * _MPDFK)) . "\n";
19736 }
19737 /* -- BORDER-RADIUS -- */
19738 if ($brBL_V && $brBL_H) {
19739 $s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_left / 2)) * _MPDFK, ($this->h - ($y0 + $h - ($border_left / 2) - $brBL_V) ) * _MPDFK)) . "\n";
19740 $s .= ($this->_EllipseArc($x0 + $brBL_H, $y0 + $h - $brBL_V, $brBL_H - $border_left / 2, $brBL_V - $border_left / 2, 3, 1)) . "\n";
19741 } else
19742 /* -- END BORDER-RADIUS -- */
19743 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19744 $s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_left / 2)) * _MPDFK, ($this->h - ($y0 + $h) ) * _MPDFK)) . "\n";
19745 } else {
19746 $s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_left / 2)) * _MPDFK, ($this->h - ($y0 + $h - ($border_left / 2)) ) * _MPDFK)) . "\n";
19747 }
19748 $s .= 'S' . "\n";
19749 $this->_out($s);
19750
19751 if ($tbd['style'] == 'double') {
19752 $this->SetLineWidth($tbd['w'] / 3);
19753 $this->SetDColor($tbcol);
19754 $this->_out($s);
19755 }
19756 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
19757 $this->_out('Q');
19758 }
19759
19760 // Reset Corners and Dash off
19761 $this->SetLineWidth(0.1);
19762 $this->SetDColor($this->ConvertColor(0));
19763 $this->SetLineJoin(2);
19764 $this->SetLineCap(2);
19765 $this->SetDash();
19766 }
19767 }
19768 if ($this->blk[$blvl]['border_right']) {
19769 $tbd = $this->blk[$blvl]['border_right'];
19770 if (isset($tbd['s']) && $tbd['s']) {
19771 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
19772 $this->_out('q');
19773 $this->SetLineWidth(0);
19774 $this->_out(sprintf('%.3F %.3F m ', ($x0 + $w) * _MPDFK, ($this->h - ($y0)) * _MPDFK));
19775 $this->_out(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * _MPDFK, ($this->h - ($y0 + $border_top)) * _MPDFK));
19776 $this->_out(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * _MPDFK, ($this->h - ($y0 + $h - $border_bottom)) * _MPDFK));
19777 $this->_out(sprintf('%.3F %.3F l ', ($x0 + $w) * _MPDFK, ($this->h - ($y0 + $h)) * _MPDFK));
19778 $this->_out(' h W n '); // Ends path no-op & Sets the clipping path
19779 }
19780
19781 $this->_setBorderLine($tbd);
19782 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
19783 $this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'R');
19784 }
19785 /* -- BORDER-RADIUS -- */ elseif (($brTR_V && $brTR_H) || ($brBR_V && $brBR_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19786 $this->SetLineJoin(0);
19787 $this->SetLineCap(0);
19788 }
19789 $s = '';
19790 if ($brBR_V && $brBR_H) {
19791 $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";
19792 } else
19793 /* -- END BORDER-RADIUS -- */
19794 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19795 $s .= (sprintf('%.3F %.3F m ', ($x0 + $w - ($border_right / 2)) * _MPDFK, ($this->h - ($y0 + $h)) * _MPDFK)) . "\n";
19796 } else {
19797 $s .= (sprintf('%.3F %.3F m ', ($x0 + $w - ($border_right / 2)) * _MPDFK, ($this->h - ($y0 + $h - ($border_right / 2))) * _MPDFK)) . "\n";
19798 }
19799 /* -- BORDER-RADIUS -- */
19800 if ($brTR_V && $brTR_H) {
19801 $s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_right / 2)) * _MPDFK, ($this->h - ($y0 + ($border_right / 2) + $brTR_V) ) * _MPDFK)) . "\n";
19802 $s .= ($this->_EllipseArc($x0 + $w - $brTR_H, $y0 + $brTR_V, $brTR_H - $border_right / 2, $brTR_V - $border_right / 2, 1, 1)) . "\n";
19803 } else
19804 /* -- END BORDER-RADIUS -- */
19805 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
19806 $s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_right / 2)) * _MPDFK, ($this->h - ($y0) ) * _MPDFK)) . "\n";
19807 } else {
19808 $s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_right / 2)) * _MPDFK, ($this->h - ($y0 + ($border_right / 2)) ) * _MPDFK)) . "\n";
19809 }
19810 $s .= 'S' . "\n";
19811 $this->_out($s);
19812
19813 if ($tbd['style'] == 'double') {
19814 $this->SetLineWidth($tbd['w'] / 3);
19815 $this->SetDColor($tbcol);
19816 $this->_out($s);
19817 }
19818 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
19819 $this->_out('Q');
19820 }
19821
19822 // Reset Corners and Dash off
19823 $this->SetLineWidth(0.1);
19824 $this->SetDColor($this->ConvertColor(0));
19825 $this->SetLineJoin(2);
19826 $this->SetLineCap(2);
19827 $this->SetDash();
19828 }
19829 }
19830
19831
19832 $this->SetDash();
19833 $this->y = $save_y;
19834
19835
19836 // BACKGROUNDS are disabled in columns/kbt/headers - messes up the repositioning in printcolumnbuffer
19837 if ($this->ColActive || $this->kwt || $this->keep_block_together) {
19838 return;
19839 }
19840
19841
19842 $bgx0 = $x0;
19843 $bgx1 = $x1;
19844 $bgy0 = $y0;
19845 $bgy1 = $y1;
19846
19847 // Defined br values represent the radius of the outer curve - need to take border-width/2 from each radius for drawing the borders
19848 if (isset($this->blk[$blvl]['background_clip']) && $this->blk[$blvl]['background_clip'] == 'padding-box') {
19849 $brbgTL_H = max(0, $brTL_H - $this->blk[$blvl]['border_left']['w']);
19850 $brbgTL_V = max(0, $brTL_V - $this->blk[$blvl]['border_top']['w']);
19851 $brbgTR_H = max(0, $brTR_H - $this->blk[$blvl]['border_right']['w']);
19852 $brbgTR_V = max(0, $brTR_V - $this->blk[$blvl]['border_top']['w']);
19853 $brbgBL_H = max(0, $brBL_H - $this->blk[$blvl]['border_left']['w']);
19854 $brbgBL_V = max(0, $brBL_V - $this->blk[$blvl]['border_bottom']['w']);
19855 $brbgBR_H = max(0, $brBR_H - $this->blk[$blvl]['border_right']['w']);
19856 $brbgBR_V = max(0, $brBR_V - $this->blk[$blvl]['border_bottom']['w']);
19857 $bgx0 += $this->blk[$blvl]['border_left']['w'];
19858 $bgx1 -= $this->blk[$blvl]['border_right']['w'];
19859 if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
19860 $bgy0 += $this->blk[$blvl]['border_top']['w'];
19861 }
19862 if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
19863 $bgy1 -= $this->blk[$blvl]['border_bottom']['w'];
19864 }
19865 } elseif (isset($this->blk[$blvl]['background_clip']) && $this->blk[$blvl]['background_clip'] == 'content-box') {
19866 $brbgTL_H = max(0, $brTL_H - $this->blk[$blvl]['border_left']['w'] - $this->blk[$blvl]['padding_left']);
19867 $brbgTL_V = max(0, $brTL_V - $this->blk[$blvl]['border_top']['w'] - $this->blk[$blvl]['padding_top']);
19868 $brbgTR_H = max(0, $brTR_H - $this->blk[$blvl]['border_right']['w'] - $this->blk[$blvl]['padding_right']);
19869 $brbgTR_V = max(0, $brTR_V - $this->blk[$blvl]['border_top']['w'] - $this->blk[$blvl]['padding_top']);
19870 $brbgBL_H = max(0, $brBL_H - $this->blk[$blvl]['border_left']['w'] - $this->blk[$blvl]['padding_left']);
19871 $brbgBL_V = max(0, $brBL_V - $this->blk[$blvl]['border_bottom']['w'] - $this->blk[$blvl]['padding_bottom']);
19872 $brbgBR_H = max(0, $brBR_H - $this->blk[$blvl]['border_right']['w'] - $this->blk[$blvl]['padding_right']);
19873 $brbgBR_V = max(0, $brBR_V - $this->blk[$blvl]['border_bottom']['w'] - $this->blk[$blvl]['padding_bottom']);
19874 $bgx0 += $this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'];
19875 $bgx1 -= $this->blk[$blvl]['border_right']['w'] + $this->blk[$blvl]['padding_right'];
19876 if (($this->blk[$blvl]['border_top']['w'] || $this->blk[$blvl]['padding_top']) && $divider != 'pagetop' && !$continuingpage) {
19877 $bgy0 += $this->blk[$blvl]['border_top']['w'] + $this->blk[$blvl]['padding_top'];
19878 }
19879 if (($this->blk[$blvl]['border_bottom']['w'] || $this->blk[$blvl]['padding_bottom']) && $blockstate != 1 && $divider != 'pagebottom') {
19880 $bgy1 -= $this->blk[$blvl]['border_bottom']['w'] + $this->blk[$blvl]['padding_bottom'];
19881 }
19882 } else {
19883 $brbgTL_H = $brTL_H;
19884 $brbgTL_V = $brTL_V;
19885 $brbgTR_H = $brTR_H;
19886 $brbgTR_V = $brTR_V;
19887 $brbgBL_H = $brBL_H;
19888 $brbgBL_V = $brBL_V;
19889 $brbgBR_H = $brBR_H;
19890 $brbgBR_V = $brBR_V;
19891 }
19892
19893 // Set clipping path
19894 $s = ' q 0 w '; // Line width=0
19895 $s .= sprintf('%.3F %.3F m ', ($bgx0 + $brbgTL_H ) * _MPDFK, ($this->h - $bgy0) * _MPDFK); // start point TL before the arc
19896 /* -- BORDER-RADIUS -- */
19897 if ($brbgTL_H || $brbgTL_V) {
19898 $s .= $this->_EllipseArc($bgx0 + $brbgTL_H, $bgy0 + $brbgTL_V, $brbgTL_H, $brbgTL_V, 2); // segment 2 TL
19899 }
19900 /* -- END BORDER-RADIUS -- */
19901 $s .= sprintf('%.3F %.3F l ', ($bgx0) * _MPDFK, ($this->h - ($bgy1 - $brbgBL_V )) * _MPDFK); // line to BL
19902 /* -- BORDER-RADIUS -- */
19903 if ($brbgBL_H || $brbgBL_V) {
19904 $s .= $this->_EllipseArc($bgx0 + $brbgBL_H, $bgy1 - $brbgBL_V, $brbgBL_H, $brbgBL_V, 3); // segment 3 BL
19905 }
19906 /* -- END BORDER-RADIUS -- */
19907 $s .= sprintf('%.3F %.3F l ', ($bgx1 - $brbgBR_H ) * _MPDFK, ($this->h - ($bgy1)) * _MPDFK); // line to BR
19908 /* -- BORDER-RADIUS -- */
19909 if ($brbgBR_H || $brbgBR_V) {
19910 $s .= $this->_EllipseArc($bgx1 - $brbgBR_H, $bgy1 - $brbgBR_V, $brbgBR_H, $brbgBR_V, 4); // segment 4 BR
19911 }
19912 /* -- END BORDER-RADIUS -- */
19913 $s .= sprintf('%.3F %.3F l ', ($bgx1) * _MPDFK, ($this->h - ($bgy0 + $brbgTR_V)) * _MPDFK); // line to TR
19914 /* -- BORDER-RADIUS -- */
19915 if ($brbgTR_H || $brbgTR_V) {
19916 $s .= $this->_EllipseArc($bgx1 - $brbgTR_H, $bgy0 + $brbgTR_V, $brbgTR_H, $brbgTR_V, 1); // segment 1 TR
19917 }
19918 /* -- END BORDER-RADIUS -- */
19919 $s .= sprintf('%.3F %.3F l ', ($bgx0 + $brbgTL_H ) * _MPDFK, ($this->h - $bgy0) * _MPDFK); // line to TL
19920 // Box Shadow
19921 $shadow = '';
19922 if (isset($this->blk[$blvl]['box_shadow']) && $this->blk[$blvl]['box_shadow'] && $h > 0) {
19923 foreach ($this->blk[$blvl]['box_shadow'] AS $sh) {
19924 // Colors
19925 if ($sh['col'][0] == 1) {
19926 $colspace = 'Gray';
19927 if ($sh['col'][2] == 1) {
19928 $col1 = '1' . $sh['col'][1] . '1' . $sh['col'][3];
19929 } else {
19930 $col1 = '1' . $sh['col'][1] . '1' . chr(100);
19931 }
19932 $col2 = '1' . $sh['col'][1] . '1' . chr(0);
19933 } elseif ($sh['col'][0] == 4) { // CMYK
19934 $colspace = 'CMYK';
19935 $col1 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . chr(100);
19936 $col2 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . chr(0);
19937 } elseif ($sh['col'][0] == 5) { // RGBa
19938 $colspace = 'RGB';
19939 $col1 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4];
19940 $col2 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . chr(0);
19941 } elseif ($sh['col'][0] == 6) { // CMYKa
19942 $colspace = 'CMYK';
19943 $col1 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . $sh['col'][5];
19944 $col2 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . chr(0);
19945 } else {
19946 $colspace = 'RGB';
19947 $col1 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . chr(100);
19948 $col2 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . chr(0);
19949 }
19950
19951 // Use clipping path as set above (and rectangle around page) to clip area outside box
19952 $shadow .= $s; // Use the clipping path with W*
19953 $shadow .= sprintf('0 %.3F m %.3F %.3F l ', $this->h * _MPDFK, $this->w * _MPDFK, $this->h * _MPDFK);
19954 $shadow .= sprintf('%.3F 0 l 0 0 l 0 %.3F l ', $this->w * _MPDFK, $this->h * _MPDFK);
19955 $shadow .= 'W n' . "\n";
19956
19957 $sh['blur'] = abs($sh['blur']); // cannot have negative blur value
19958 // Ensure spread/blur do not make effective shadow width/height < 0
19959 // Could do more complex things but this just adjusts spread value
19960 if (-$sh['spread'] + $sh['blur'] / 2 > min($w / 2, $h / 2)) {
19961 $sh['spread'] = $sh['blur'] / 2 - min($w / 2, $h / 2) + 0.01;
19962 }
19963 // Shadow Offset
19964 if ($sh['x'] || $sh['y'])
19965 $shadow .= sprintf(' q 1 0 0 1 %.4F %.4F cm', $sh['x'] * _MPDFK, -$sh['y'] * _MPDFK) . "\n";
19966
19967 // Set path for INNER shadow
19968 $shadow .= ' q 0 w ';
19969 $shadow .= $this->SetFColor($col1, true) . "\n";
19970 if ($col1[0] == 5 && ord($col1[4]) < 100) { // RGBa
19971 $shadow .= $this->SetAlpha(ord($col1[4]) / 100, 'Normal', true, 'F') . "\n";
19972 } elseif ($col1[0] == 6 && ord($col1[5]) < 100) { // CMYKa
19973 $shadow .= $this->SetAlpha(ord($col1[5]) / 100, 'Normal', true, 'F') . "\n";
19974 } elseif ($col1[0] == 1 && $col1[2] == 1 && ord($col1[3]) < 100) { // Gray
19975 $shadow .= $this->SetAlpha(ord($col1[3]) / 100, 'Normal', true, 'F') . "\n";
19976 }
19977
19978 // Blur edges
19979 $mag = 0.551784; // Bezier Control magic number for 4-part spline for circle/ellipse
19980 $mag2 = 0.551784; // Bezier Control magic number to fill in edge of blurred rectangle
19981 $d1 = $sh['spread'] + $sh['blur'] / 2;
19982 $d2 = $sh['spread'] - $sh['blur'] / 2;
19983 $bl = $sh['blur'];
19984 $x00 = $x0 - $d1;
19985 $y00 = $y0 - $d1;
19986 $w00 = $w + $d1 * 2;
19987 $h00 = $h + $d1 * 2;
19988
19989 // If any border-radius is greater width-negative spread(inner edge), ignore radii for shadow or screws up
19990 $flatten = false;
19991 if (max($brbgTR_H, $brbgTL_H, $brbgBR_H, $brbgBL_H) >= $w + $d2) {
19992 $flatten = true;
19993 }
19994 if (max($brbgTR_V, $brbgTL_V, $brbgBR_V, $brbgBL_V) >= $h + $d2) {
19995 $flatten = true;
19996 }
19997
19998
19999 // TOP RIGHT corner
20000 $p1x = $x00 + $w00 - $d1 - $brbgTR_H;
20001 $p1c2x = $p1x + ($d2 + $brbgTR_H) * $mag;
20002 $p1y = $y00 + $bl;
20003 $p2x = $x00 + $w00 - $d1 - $brbgTR_H;
20004 $p2c2x = $p2x + ($d1 + $brbgTR_H) * $mag;
20005 $p2y = $y00;
20006 $p2c1y = $p2y + $bl / 2;
20007 $p3x = $x00 + $w00;
20008 $p3c2x = $p3x - $bl / 2;
20009 $p3y = $y00 + $d1 + $brbgTR_V;
20010 $p3c1y = $p3y - ($d1 + $brbgTR_V) * $mag;
20011 $p4x = $x00 + $w00 - $bl;
20012 $p4y = $y00 + $d1 + $brbgTR_V;
20013 $p4c2y = $p4y - ($d2 + $brbgTR_V) * $mag;
20014 if (-$d2 > min($brbgTR_H, $brbgTR_V) || $flatten) {
20015 $p1x = $x00 + $w00 - $bl;
20016 $p1c2x = $p1x;
20017 $p2x = $x00 + $w00 - $bl;
20018 $p2c2x = $p2x + $bl * $mag2;
20019 $p3y = $y00 + $bl;
20020 $p3c1y = $p3y - $bl * $mag2;
20021 $p4y = $y00 + $bl;
20022 $p4c2y = $p4y;
20023 }
20024
20025 $shadow .= sprintf('%.3F %.3F m ', ($p1x ) * _MPDFK, ($this->h - ($p1y )) * _MPDFK);
20026 $shadow .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($p1c2x) * _MPDFK, ($this->h - ($p1y)) * _MPDFK, ($p4x) * _MPDFK, ($this->h - ($p4c2y)) * _MPDFK, ($p4x) * _MPDFK, ($this->h - ($p4y)) * _MPDFK);
20027 $patch_array[0]['f'] = 0;
20028 $patch_array[0]['points'] = array($p1x, $p1y, $p1x, $p1y,
20029 $p2x, $p2c1y, $p2x, $p2y, $p2c2x, $p2y,
20030 $p3x, $p3c1y, $p3x, $p3y, $p3c2x, $p3y,
20031 $p4x, $p4y, $p4x, $p4y, $p4x, $p4c2y,
20032 $p1c2x, $p1y);
20033 $patch_array[0]['colors'] = array($col1, $col2, $col2, $col1);
20034
20035
20036 // RIGHT
20037 $p1x = $x00 + $w00; // control point only matches p3 preceding
20038 $p1y = $y00 + $d1 + $brbgTR_V;
20039 $p2x = $x00 + $w00 - $bl; // control point only matches p4 preceding
20040 $p2y = $y00 + $d1 + $brbgTR_V;
20041 $p3x = $x00 + $w00 - $bl;
20042 $p3y = $y00 + $h00 - $d1 - $brbgBR_V;
20043 $p4x = $x00 + $w00;
20044 $p4c1x = $p4x - $bl / 2;
20045 $p4y = $y00 + $h00 - $d1 - $brbgBR_V;
20046 if (-$d2 > min($brbgTR_H, $brbgTR_V) || $flatten) {
20047 $p1y = $y00 + $bl;
20048 $p2y = $y00 + $bl;
20049 }
20050 if (-$d2 > min($brbgBR_H, $brbgBR_V) || $flatten) {
20051 $p3y = $y00 + $h00 - $bl;
20052 $p4y = $y00 + $h00 - $bl;
20053 }
20054
20055 $shadow .= sprintf('%.3F %.3F l ', ($p3x ) * _MPDFK, ($this->h - ($p3y )) * _MPDFK);
20056 $patch_array[1]['f'] = 2;
20057 $patch_array[1]['points'] = array($p2x, $p2y,
20058 $p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
20059 $p4c1x, $p4y, $p4x, $p4y, $p4x, $p4y,
20060 $p1x, $p1y);
20061 $patch_array[1]['colors'] = array($col1, $col2);
20062
20063
20064 // BOTTOM RIGHT corner
20065 $p1x = $x00 + $w00 - $bl; // control points only matches p3 preceding
20066 $p1y = $y00 + $h00 - $d1 - $brbgBR_V;
20067 $p1c2y = $p1y + ($d2 + $brbgBR_V) * $mag;
20068 $p2x = $x00 + $w00; // control point only matches p4 preceding
20069 $p2y = $y00 + $h00 - $d1 - $brbgBR_V;
20070 $p2c2y = $p2y + ($d1 + $brbgBR_V) * $mag;
20071 $p3x = $x00 + $w00 - $d1 - $brbgBR_H;
20072 $p3c1x = $p3x + ($d1 + $brbgBR_H) * $mag;
20073 $p3y = $y00 + $h00;
20074 $p3c2y = $p3y - $bl / 2;
20075 $p4x = $x00 + $w00 - $d1 - $brbgBR_H;
20076 $p4c2x = $p4x + ($d2 + $brbgBR_H) * $mag;
20077 $p4y = $y00 + $h00 - $bl;
20078
20079 if (-$d2 > min($brbgBR_H, $brbgBR_V) || $flatten) {
20080 $p1y = $y00 + $h00 - $bl;
20081 $p1c2y = $p1y;
20082 $p2y = $y00 + $h00 - $bl;
20083 $p2c2y = $p2y + $bl * $mag2;
20084 $p3x = $x00 + $w00 - $bl;
20085 $p3c1x = $p3x + $bl * $mag2;
20086 $p4x = $x00 + $w00 - $bl;
20087 $p4c2x = $p4x;
20088 }
20089
20090 $shadow .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($p1x) * _MPDFK, ($this->h - ($p1c2y)) * _MPDFK, ($p4c2x) * _MPDFK, ($this->h - ($p4y)) * _MPDFK, ($p4x) * _MPDFK, ($this->h - ($p4y)) * _MPDFK);
20091 $patch_array[2]['f'] = 2;
20092 $patch_array[2]['points'] = array($p2x, $p2c2y,
20093 $p3c1x, $p3y, $p3x, $p3y, $p3x, $p3c2y,
20094 $p4x, $p4y, $p4x, $p4y, $p4c2x, $p4y,
20095 $p1x, $p1c2y);
20096 $patch_array[2]['colors'] = array($col2, $col1);
20097
20098
20099
20100 // BOTTOM
20101 $p1x = $x00 + $w00 - $d1 - $brbgBR_H; // control point only matches p3 preceding
20102 $p1y = $y00 + $h00;
20103 $p2x = $x00 + $w00 - $d1 - $brbgBR_H; // control point only matches p4 preceding
20104 $p2y = $y00 + $h00 - $bl;
20105 $p3x = $x00 + $d1 + $brbgBL_H;
20106 $p3y = $y00 + $h00 - $bl;
20107 $p4x = $x00 + $d1 + $brbgBL_H;
20108 $p4y = $y00 + $h00;
20109 $p4c1y = $p4y - $bl / 2;
20110
20111 if (-$d2 > min($brbgBR_H, $brbgBR_V) || $flatten) {
20112 $p1x = $x00 + $w00 - $bl;
20113 $p2x = $x00 + $w00 - $bl;
20114 }
20115 if (-$d2 > min($brbgBL_H, $brbgBL_V) || $flatten) {
20116 $p3x = $x00 + $bl;
20117 $p4x = $x00 + $bl;
20118 }
20119
20120 $shadow .= sprintf('%.3F %.3F l ', ($p3x ) * _MPDFK, ($this->h - ($p3y )) * _MPDFK);
20121 $patch_array[3]['f'] = 2;
20122 $patch_array[3]['points'] = array($p2x, $p2y,
20123 $p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
20124 $p4x, $p4c1y, $p4x, $p4y, $p4x, $p4y,
20125 $p1x, $p1y);
20126 $patch_array[3]['colors'] = array($col1, $col2);
20127
20128 // BOTTOM LEFT corner
20129 $p1x = $x00 + $d1 + $brbgBL_H;
20130 $p1c2x = $p1x - ($d2 + $brbgBL_H) * $mag; // control points only matches p3 preceding
20131 $p1y = $y00 + $h00 - $bl;
20132 $p2x = $x00 + $d1 + $brbgBL_H;
20133 $p2c2x = $p2x - ($d1 + $brbgBL_H) * $mag; // control point only matches p4 preceding
20134 $p2y = $y00 + $h00;
20135 $p3x = $x00;
20136 $p3c2x = $p3x + $bl / 2;
20137 $p3y = $y00 + $h00 - $d1 - $brbgBL_V;
20138 $p3c1y = $p3y + ($d1 + $brbgBL_V) * $mag;
20139 $p4x = $x00 + $bl;
20140 $p4y = $y00 + $h00 - $d1 - $brbgBL_V;
20141 $p4c2y = $p4y + ($d2 + $brbgBL_V) * $mag;
20142 if (-$d2 > min($brbgBL_H, $brbgBL_V) || $flatten) {
20143 $p1x = $x00 + $bl;
20144 $p1c2x = $p1x;
20145 $p2x = $x00 + $bl;
20146 $p2c2x = $p2x - $bl * $mag2;
20147 $p3y = $y00 + $h00 - $bl;
20148 $p3c1y = $p3y + $bl * $mag2;
20149 $p4y = $y00 + $h00 - $bl;
20150 $p4c2y = $p4y;
20151 }
20152
20153 $shadow .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($p1c2x) * _MPDFK, ($this->h - ($p1y)) * _MPDFK, ($p4x) * _MPDFK, ($this->h - ($p4c2y)) * _MPDFK, ($p4x) * _MPDFK, ($this->h - ($p4y)) * _MPDFK);
20154 $patch_array[4]['f'] = 2;
20155 $patch_array[4]['points'] = array($p2c2x, $p2y,
20156 $p3x, $p3c1y, $p3x, $p3y, $p3c2x, $p3y,
20157 $p4x, $p4y, $p4x, $p4y, $p4x, $p4c2y,
20158 $p1c2x, $p1y);
20159 $patch_array[4]['colors'] = array($col2, $col1);
20160
20161
20162 // LEFT - joins on the right (C3-C4 of previous): f = 2
20163 $p1x = $x00; // control point only matches p3 preceding
20164 $p1y = $y00 + $h00 - $d1 - $brbgBL_V;
20165 $p2x = $x00 + $bl; // control point only matches p4 preceding
20166 $p2y = $y00 + $h00 - $d1 - $brbgBL_V;
20167 $p3x = $x00 + $bl;
20168 $p3y = $y00 + $d1 + $brbgTL_V;
20169 $p4x = $x00;
20170 $p4c1x = $p4x + $bl / 2;
20171 $p4y = $y00 + $d1 + $brbgTL_V;
20172 if (-$d2 > min($brbgBL_H, $brbgBL_V) || $flatten) {
20173 $p1y = $y00 + $h00 - $bl;
20174 $p2y = $y00 + $h00 - $bl;
20175 }
20176 if (-$d2 > min($brbgTL_H, $brbgTL_V) || $flatten) {
20177 $p3y = $y00 + $bl;
20178 $p4y = $y00 + $bl;
20179 }
20180
20181 $shadow .= sprintf('%.3F %.3F l ', ($p3x ) * _MPDFK, ($this->h - ($p3y )) * _MPDFK);
20182 $patch_array[5]['f'] = 2;
20183 $patch_array[5]['points'] = array($p2x, $p2y,
20184 $p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
20185 $p4c1x, $p4y, $p4x, $p4y, $p4x, $p4y,
20186 $p1x, $p1y);
20187 $patch_array[5]['colors'] = array($col1, $col2);
20188
20189 // TOP LEFT corner
20190 $p1x = $x00 + $bl; // control points only matches p3 preceding
20191 $p1y = $y00 + $d1 + $brbgTL_V;
20192 $p1c2y = $p1y - ($d2 + $brbgTL_V) * $mag;
20193 $p2x = $x00; // control point only matches p4 preceding
20194 $p2y = $y00 + $d1 + $brbgTL_V;
20195 $p2c2y = $p2y - ($d1 + $brbgTL_V) * $mag;
20196 $p3x = $x00 + $d1 + $brbgTL_H;
20197 $p3c1x = $p3x - ($d1 + $brbgTL_H) * $mag;
20198 $p3y = $y00;
20199 $p3c2y = $p3y + $bl / 2;
20200 $p4x = $x00 + $d1 + $brbgTL_H;
20201 $p4c2x = $p4x - ($d2 + $brbgTL_H) * $mag;
20202 $p4y = $y00 + $bl;
20203
20204 if (-$d2 > min($brbgTL_H, $brbgTL_V) || $flatten) {
20205 $p1y = $y00 + $bl;
20206 $p1c2y = $p1y;
20207 $p2y = $y00 + $bl;
20208 $p2c2y = $p2y - $bl * $mag2;
20209 $p3x = $x00 + $bl;
20210 $p3c1x = $p3x - $bl * $mag2;
20211 $p4x = $x00 + $bl;
20212 $p4c2x = $p4x;
20213 }
20214
20215 $shadow .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($p1x) * _MPDFK, ($this->h - ($p1c2y)) * _MPDFK, ($p4c2x) * _MPDFK, ($this->h - ($p4y)) * _MPDFK, ($p4x) * _MPDFK, ($this->h - ($p4y)) * _MPDFK);
20216 $patch_array[6]['f'] = 2;
20217 $patch_array[6]['points'] = array($p2x, $p2c2y,
20218 $p3c1x, $p3y, $p3x, $p3y, $p3x, $p3c2y,
20219 $p4x, $p4y, $p4x, $p4y, $p4c2x, $p4y,
20220 $p1x, $p1c2y);
20221 $patch_array[6]['colors'] = array($col2, $col1);
20222
20223
20224 // TOP - joins on the right (C3-C4 of previous): f = 2
20225 $p1x = $x00 + $d1 + $brbgTL_H; // control point only matches p3 preceding
20226 $p1y = $y00;
20227 $p2x = $x00 + $d1 + $brbgTL_H; // control point only matches p4 preceding
20228 $p2y = $y00 + $bl;
20229 $p3x = $x00 + $w00 - $d1 - $brbgTR_H;
20230 $p3y = $y00 + $bl;
20231 $p4x = $x00 + $w00 - $d1 - $brbgTR_H;
20232 $p4y = $y00;
20233 $p4c1y = $p4y + $bl / 2;
20234 if (-$d2 > min($brbgTL_H, $brbgTL_V) || $flatten) {
20235 $p1x = $x00 + $bl;
20236 $p2x = $x00 + $bl;
20237 }
20238 if (-$d2 > min($brbgTR_H, $brbgTR_V) || $flatten) {
20239 $p3x = $x00 + $w00 - $bl;
20240 $p4x = $x00 + $w00 - $bl;
20241 }
20242
20243 $shadow .= sprintf('%.3F %.3F l ', ($p3x ) * _MPDFK, ($this->h - ($p3y )) * _MPDFK);
20244 $patch_array[7]['f'] = 2;
20245 $patch_array[7]['points'] = array($p2x, $p2y,
20246 $p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
20247 $p4x, $p4c1y, $p4x, $p4y, $p4x, $p4y,
20248 $p1x, $p1y);
20249 $patch_array[7]['colors'] = array($col1, $col2);
20250
20251 $shadow .= ' h f Q ' . "\n"; // Close path and Fill the inner solid shadow
20252
20253 if ($bl)
20254 $shadow .= $this->grad->CoonsPatchMesh($x00, $y00, $w00, $h00, $patch_array, $x00, $x00 + $w00, $y00, $y00 + $h00, $colspace, true);
20255
20256 if ($sh['x'] || $sh['y'])
20257 $shadow .= ' Q' . "\n"; // Shadow Offset
20258 $shadow .= ' Q' . "\n"; // Ends path no-op & Sets the clipping path
20259 }
20260 }
20261
20262 $s .= ' W n '; // Ends path no-op & Sets the clipping path
20263
20264 if ($this->blk[$blvl]['bgcolor']) {
20265 $this->pageBackgrounds[$blvl][] = array('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);
20266 } elseif ($shadow) {
20267 $this->pageBackgrounds[$blvl][] = array('shadowonly' => true, 'col' => '', 'clippath' => '', 'visibility' => $this->visibility, 'shadow' => $shadow, 'z-index' => $this->current_layer);
20268 }
20269
20270 /* -- BACKGROUNDS -- */
20271 if (isset($this->blk[$blvl]['gradient'])) {
20272 $g = $this->grad->parseBackgroundGradient($this->blk[$blvl]['gradient']);
20273 if ($g) {
20274 $gx = $x0;
20275 $gy = $y0;
20276 $this->pageBackgrounds[$blvl][] = array('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);
20277 }
20278 }
20279 if (isset($this->blk[$blvl]['background-image'])) {
20280 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'])) {
20281 $g = $this->grad->parseMozGradient($this->blk[$blvl]['background-image']['gradient']);
20282 if ($g) {
20283 $gx = $x0;
20284 $gy = $y0;
20285 // origin specifies the background-positioning-area (bpa)
20286 if ($this->blk[$blvl]['background-image']['origin'] == 'padding-box') {
20287 $gx += $this->blk[$blvl]['border_left']['w'];
20288 $w -= ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['border_right']['w']);
20289 if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
20290 $gy += $this->blk[$blvl]['border_top']['w'];
20291 }
20292 if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
20293 $gy1 = $y1 - $this->blk[$blvl]['border_bottom']['w'];
20294 } else {
20295 $gy1 = $y1;
20296 }
20297 $h = $gy1 - $gy;
20298 } elseif ($this->blk[$blvl]['background-image']['origin'] == 'content-box') {
20299 $gx += $this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'];
20300 $w -= ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'] + $this->blk[$blvl]['border_right']['w'] + $this->blk[$blvl]['padding_right']);
20301 if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
20302 $gy += $this->blk[$blvl]['border_top']['w'] + $this->blk[$blvl]['padding_top'];
20303 }
20304 if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
20305 $gy1 = $y1 - ($this->blk[$blvl]['border_bottom']['w'] + $this->blk[$blvl]['padding_bottom']);
20306 } else {
20307 $gy1 = $y1 - $this->blk[$blvl]['padding_bottom'];
20308 }
20309 $h = $gy1 - $gy;
20310 }
20311
20312 if (isset($this->blk[$blvl]['background-image']['size']['w']) && $this->blk[$blvl]['background-image']['size']['w']) {
20313 $size = $this->blk[$blvl]['background-image']['size'];
20314 if ($size['w'] != 'contain' && $size['w'] != 'cover') {
20315 if (stristr($size['w'], '%')) {
20316 $size['w'] += 0;
20317 $size['w'] /= 100;
20318 $w *= $size['w'];
20319 } elseif ($size['w'] != 'auto') {
20320 $w = $size['w'];
20321 }
20322 if (stristr($size['h'], '%')) {
20323 $size['h'] += 0;
20324 $size['h'] /= 100;
20325 $h *= $size['h'];
20326 } elseif ($size['h'] != 'auto') {
20327 $h = $size['h'];
20328 }
20329 }
20330 }
20331 $this->pageBackgrounds[$blvl][] = array('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);
20332 }
20333 } else {
20334 $image_id = $this->blk[$blvl]['background-image']['image_id'];
20335 $orig_w = $this->blk[$blvl]['background-image']['orig_w'];
20336 $orig_h = $this->blk[$blvl]['background-image']['orig_h'];
20337 $x_pos = $this->blk[$blvl]['background-image']['x_pos'];
20338 $y_pos = $this->blk[$blvl]['background-image']['y_pos'];
20339 $x_repeat = $this->blk[$blvl]['background-image']['x_repeat'];
20340 $y_repeat = $this->blk[$blvl]['background-image']['y_repeat'];
20341 $resize = $this->blk[$blvl]['background-image']['resize'];
20342 $opacity = $this->blk[$blvl]['background-image']['opacity'];
20343 $itype = $this->blk[$blvl]['background-image']['itype'];
20344 $size = $this->blk[$blvl]['background-image']['size'];
20345 // origin specifies the background-positioning-area (bpa)
20346 $bpa = array('x' => $x0, 'y' => $y0, 'w' => $w, 'h' => $h);
20347 if ($this->blk[$blvl]['background-image']['origin'] == 'padding-box') {
20348 $bpa['x'] = $x0 + $this->blk[$blvl]['border_left']['w'];
20349 $bpa['w'] = $w - ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['border_right']['w']);
20350 if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
20351 $bpa['y'] = $y0 + $this->blk[$blvl]['border_top']['w'];
20352 } else {
20353 $bpa['y'] = $y0;
20354 }
20355 if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
20356 $bpay = $y1 - $this->blk[$blvl]['border_bottom']['w'];
20357 } else {
20358 $bpay = $y1;
20359 }
20360 $bpa['h'] = $bpay - $bpa['y'];
20361 } elseif ($this->blk[$blvl]['background-image']['origin'] == 'content-box') {
20362 $bpa['x'] = $x0 + $this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'];
20363 $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']);
20364 if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
20365 $bpa['y'] = $y0 + $this->blk[$blvl]['border_top']['w'] + $this->blk[$blvl]['padding_top'];
20366 } else {
20367 $bpa['y'] = $y0 + $this->blk[$blvl]['padding_top'];
20368 }
20369 if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
20370 $bpay = $y1 - ($this->blk[$blvl]['border_bottom']['w'] + $this->blk[$blvl]['padding_bottom']);
20371 } else {
20372 $bpay = $y1 - $this->blk[$blvl]['padding_bottom'];
20373 }
20374 $bpa['h'] = $bpay - $bpa['y'];
20375 }
20376 $this->pageBackgrounds[$blvl][] = array('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);
20377 }
20378 }
20379 /* -- END BACKGROUNDS -- */
20380
20381 // Float DIV
20382 $this->blk[$blvl]['bb_painted'][$this->page] = true;
20383 }
20384
20385 /* -- BORDER-RADIUS -- */
20386
20387 function _EllipseArc($x0, $y0, $rx, $ry, $seg = 1, $part = false, $start = false)
20388 { // Anticlockwise segment 1-4 TR-TL-BL-BR (part=1 or 2)
20389 $s = '';
20390 if ($rx < 0) {
20391 $rx = 0;
20392 }
20393 if ($ry < 0) {
20394 $ry = 0;
20395 }
20396 $rx *= _MPDFK;
20397 $ry *= _MPDFK;
20398 $astart = 0;
20399 if ($seg == 1) { // Top Right
20400 $afinish = 90;
20401 $nSeg = 4;
20402 } elseif ($seg == 2) { // Top Left
20403 $afinish = 180;
20404 $nSeg = 8;
20405 } elseif ($seg == 3) { // Bottom Left
20406 $afinish = 270;
20407 $nSeg = 12;
20408 } else { // Bottom Right
20409 $afinish = 360;
20410 $nSeg = 16;
20411 }
20412 $astart = deg2rad((float) $astart);
20413 $afinish = deg2rad((float) $afinish);
20414 $totalAngle = $afinish - $astart;
20415 $dt = $totalAngle / $nSeg; // segment angle
20416 $dtm = $dt / 3;
20417 $x0 *= _MPDFK;
20418 $y0 = ($this->h - $y0) * _MPDFK;
20419 $t1 = $astart;
20420 $a0 = $x0 + ($rx * cos($t1));
20421 $b0 = $y0 + ($ry * sin($t1));
20422 $c0 = -$rx * sin($t1);
20423 $d0 = $ry * cos($t1);
20424 $op = false;
20425 for ($i = 1; $i <= $nSeg; $i++) {
20426 // Draw this bit of the total curve
20427 $t1 = ($i * $dt) + $astart;
20428 $a1 = $x0 + ($rx * cos($t1));
20429 $b1 = $y0 + ($ry * sin($t1));
20430 $c1 = -$rx * sin($t1);
20431 $d1 = $ry * cos($t1);
20432 if ($i > ($nSeg - 4) && (!$part || ($part == 1 && $i <= $nSeg - 2) || ($part == 2 && $i > $nSeg - 2))) {
20433 if ($start && !$op) {
20434 $s .= sprintf('%.3F %.3F m ', $a0, $b0);
20435 }
20436 $s .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($a0 + ($c0 * $dtm)), ($b0 + ($d0 * $dtm)), ($a1 - ($c1 * $dtm)), ($b1 - ($d1 * $dtm)), $a1, $b1);
20437 $op = true;
20438 }
20439 $a0 = $a1;
20440 $b0 = $b1;
20441 $c0 = $c1;
20442 $d0 = $d1;
20443 }
20444 return $s;
20445 }
20446
20447 /* -- END BORDER-RADIUS -- */
20448
20449 function PaintDivLnBorder($state = 0, $blvl = 0, $h)
20450 {
20451 // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
20452 $this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y + $h;
20453
20454 $save_y = $this->y;
20455
20456 $w = $this->blk[$blvl]['width'];
20457 $x0 = $this->x; // left
20458 $y0 = $this->y; // top
20459 $x1 = $this->x + $w; // bottom
20460 $y1 = $this->y + $h; // bottom
20461
20462 if ($this->blk[$blvl]['border_top'] && ($state == 1 || $state == 3)) {
20463 $tbd = $this->blk[$blvl]['border_top'];
20464 if (isset($tbd['s']) && $tbd['s']) {
20465 $this->_setBorderLine($tbd);
20466 $this->y = $y0 + ($tbd['w'] / 2);
20467 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
20468 $this->_setDashBorder($tbd['style'], '', $continuingpage, 'T');
20469 $this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $this->y);
20470 } else {
20471 $this->SetLineJoin(0);
20472 $this->SetLineCap(0);
20473 $this->Line($x0, $this->y, $x0 + $w, $this->y);
20474 }
20475 $this->y += $tbd['w'];
20476 // Reset Corners and Dash off
20477 $this->SetLineJoin(2);
20478 $this->SetLineCap(2);
20479 $this->SetDash();
20480 }
20481 }
20482 if ($this->blk[$blvl]['border_left']) {
20483 $tbd = $this->blk[$blvl]['border_left'];
20484 if (isset($tbd['s']) && $tbd['s']) {
20485 $this->_setBorderLine($tbd);
20486 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
20487 $this->y = $y0 + ($tbd['w'] / 2);
20488 $this->_setDashBorder($tbd['style'], '', $continuingpage, 'L');
20489 $this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + ($tbd['w'] / 2), $y0 + $h - ($tbd['w'] / 2));
20490 } else {
20491 $this->y = $y0;
20492 $this->SetLineJoin(0);
20493 $this->SetLineCap(0);
20494 $this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + ($tbd['w'] / 2), $y0 + $h);
20495 }
20496 $this->y += $tbd['w'];
20497 // Reset Corners and Dash off
20498 $this->SetLineJoin(2);
20499 $this->SetLineCap(2);
20500 $this->SetDash();
20501 }
20502 }
20503 if ($this->blk[$blvl]['border_right']) {
20504 $tbd = $this->blk[$blvl]['border_right'];
20505 if (isset($tbd['s']) && $tbd['s']) {
20506 $this->_setBorderLine($tbd);
20507 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
20508 $this->y = $y0 + ($tbd['w'] / 2);
20509 $this->_setDashBorder($tbd['style'], '', $continuingpage, 'R');
20510 $this->Line($x0 + $w - ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $y0 + $h - ($tbd['w'] / 2));
20511 } else {
20512 $this->y = $y0;
20513 $this->SetLineJoin(0);
20514 $this->SetLineCap(0);
20515 $this->Line($x0 + $w - ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $y0 + $h);
20516 }
20517 $this->y += $tbd['w'];
20518 // Reset Corners and Dash off
20519 $this->SetLineJoin(2);
20520 $this->SetLineCap(2);
20521 $this->SetDash();
20522 }
20523 }
20524 if ($this->blk[$blvl]['border_bottom'] && $state > 1) {
20525 $tbd = $this->blk[$blvl]['border_bottom'];
20526 if (isset($tbd['s']) && $tbd['s']) {
20527 $this->_setBorderLine($tbd);
20528 $this->y = $y0 + $h - ($tbd['w'] / 2);
20529 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
20530 $this->_setDashBorder($tbd['style'], '', $continuingpage, 'B');
20531 $this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $this->y);
20532 } else {
20533 $this->SetLineJoin(0);
20534 $this->SetLineCap(0);
20535 $this->Line($x0, $this->y, $x0 + $w, $this->y);
20536 }
20537 $this->y += $tbd['w'];
20538 // Reset Corners and Dash off
20539 $this->SetLineJoin(2);
20540 $this->SetLineCap(2);
20541 $this->SetDash();
20542 }
20543 }
20544 $this->SetDash();
20545 $this->y = $save_y;
20546 }
20547
20548 function PaintImgBorder($objattr, $is_table)
20549 {
20550 // Borders are disabled in columns - messes up the repositioning in printcolumnbuffer
20551 if ($this->ColActive) {
20552 return;
20553 } // *COLUMNS*
20554 if ($is_table) {
20555 $k = $this->shrin_k;
20556 } else {
20557 $k = 1;
20558 }
20559 $h = (isset($objattr['BORDER-HEIGHT']) ? $objattr['BORDER-HEIGHT'] : 0);
20560 $w = (isset($objattr['BORDER-WIDTH']) ? $objattr['BORDER-WIDTH'] : 0);
20561 $x0 = (isset($objattr['BORDER-X']) ? $objattr['BORDER-X'] : 0);
20562 $y0 = (isset($objattr['BORDER-Y']) ? $objattr['BORDER-Y'] : 0);
20563
20564 // BORDERS
20565 if ($objattr['border_top']) {
20566 $tbd = $objattr['border_top'];
20567 if (!empty($tbd['s'])) {
20568 $this->_setBorderLine($tbd, $k);
20569 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
20570 $this->_setDashBorder($tbd['style'], '', '', 'T');
20571 }
20572 $this->Line($x0, $y0, $x0 + $w, $y0);
20573 // Reset Corners and Dash off
20574 $this->SetLineJoin(2);
20575 $this->SetLineCap(2);
20576 $this->SetDash();
20577 }
20578 }
20579 if ($objattr['border_left']) {
20580 $tbd = $objattr['border_left'];
20581 if (!empty($tbd['s'])) {
20582 $this->_setBorderLine($tbd, $k);
20583 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
20584 $this->_setDashBorder($tbd['style'], '', '', 'L');
20585 }
20586 $this->Line($x0, $y0, $x0, $y0 + $h);
20587 // Reset Corners and Dash off
20588 $this->SetLineJoin(2);
20589 $this->SetLineCap(2);
20590 $this->SetDash();
20591 }
20592 }
20593 if ($objattr['border_right']) {
20594 $tbd = $objattr['border_right'];
20595 if (!empty($tbd['s'])) {
20596 $this->_setBorderLine($tbd, $k);
20597 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
20598 $this->_setDashBorder($tbd['style'], '', '', 'R');
20599 }
20600 $this->Line($x0 + $w, $y0, $x0 + $w, $y0 + $h);
20601 // Reset Corners and Dash off
20602 $this->SetLineJoin(2);
20603 $this->SetLineCap(2);
20604 $this->SetDash();
20605 }
20606 }
20607 if ($objattr['border_bottom']) {
20608 $tbd = $objattr['border_bottom'];
20609 if (!empty($tbd['s'])) {
20610 $this->_setBorderLine($tbd, $k);
20611 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
20612 $this->_setDashBorder($tbd['style'], '', '', 'B');
20613 }
20614 $this->Line($x0, $y0 + $h, $x0 + $w, $y0 + $h);
20615 // Reset Corners and Dash off
20616 $this->SetLineJoin(2);
20617 $this->SetLineCap(2);
20618 $this->SetDash();
20619 }
20620 }
20621 $this->SetDash();
20622 $this->SetAlpha(1);
20623 }
20624
20625 /* -- END HTML-CSS -- */
20626
20627 function Reset()
20628 {
20629 $this->SetTColor($this->ConvertColor(0));
20630 $this->SetDColor($this->ConvertColor(0));
20631 $this->SetFColor($this->ConvertColor(255));
20632 $this->SetAlpha(1);
20633 $this->colorarray = '';
20634
20635 $this->spanbgcolorarray = '';
20636 $this->spanbgcolor = false;
20637 $this->spanborder = false;
20638 $this->spanborddet = array();
20639
20640 $this->ResetStyles();
20641
20642 $this->HREF = '';
20643 $this->textparam = array();
20644 $this->SetTextOutline();
20645
20646 $this->textvar = 0x00; // mPDF 5.7.1
20647 $this->OTLtags = array();
20648 $this->textshadow = '';
20649
20650 $this->currentLang = $this->default_lang; // mPDF 6
20651 $this->RestrictUnicodeFonts($this->default_available_fonts); // mPDF 6
20652 $this->SetFont($this->default_font, '', 0, false);
20653 $this->SetFontSize($this->default_font_size, false);
20654
20655 $this->currentfontfamily = '';
20656 $this->currentfontsize = '';
20657 $this->currentfontstyle = '';
20658
20659 /* -- TABLES -- */
20660 if ($this->tableLevel && isset($this->table[1][1]['cellLineHeight'])) {
20661 $this->SetLineHeight('', $this->table[1][1]['cellLineHeight']); // *TABLES*
20662 } else
20663 /* -- END TABLES -- */
20664 if (isset($this->blk[$this->blklvl]['line_height']) && $this->blk[$this->blklvl]['line_height']) {
20665 $this->SetLineHeight('', $this->blk[$this->blklvl]['line_height']); // sets default line height
20666 }
20667
20668 $this->lSpacingCSS = '';
20669 $this->wSpacingCSS = '';
20670 $this->fixedlSpacing = false;
20671 $this->minwSpacing = 0;
20672 $this->SetDash(); //restore to no dash
20673 $this->dash_on = false;
20674 $this->dotted_on = false;
20675 $this->divwidth = 0;
20676 $this->divheight = 0;
20677 $this->cellTextAlign = '';
20678 $this->cellLineHeight = '';
20679 $this->cellLineStackingStrategy = '';
20680 $this->cellLineStackingShift = '';
20681 $this->oldy = -1;
20682
20683 $bodystyle = array();
20684 if (isset($this->cssmgr->CSS['BODY']['FONT-STYLE'])) {
20685 $bodystyle['FONT-STYLE'] = $this->cssmgr->CSS['BODY']['FONT-STYLE'];
20686 }
20687 if (isset($this->cssmgr->CSS['BODY']['FONT-WEIGHT'])) {
20688 $bodystyle['FONT-WEIGHT'] = $this->cssmgr->CSS['BODY']['FONT-WEIGHT'];
20689 }
20690 if (isset($this->cssmgr->CSS['BODY']['COLOR'])) {
20691 $bodystyle['COLOR'] = $this->cssmgr->CSS['BODY']['COLOR'];
20692 }
20693 if (isset($bodystyle)) {
20694 $this->setCSS($bodystyle, 'BLOCK', 'BODY');
20695 }
20696 }
20697
20698 /* -- HTML-CSS -- */
20699
20700 function ReadMetaTags($html)
20701 {
20702 // changes anykey=anyvalue to anykey="anyvalue" (only do this when this happens inside tags)
20703 $regexp = '/ (\\w+?)=([^\\s>"]+)/si';
20704 $html = preg_replace($regexp, " \$1=\"\$2\"", $html);
20705 if (preg_match('/<title>(.*?)<\/title>/si', $html, $m)) {
20706 $this->SetTitle($m[1]);
20707 }
20708 preg_match_all('/<meta [^>]*?(name|content)="([^>]*?)" [^>]*?(name|content)="([^>]*?)".*?>/si', $html, $aux);
20709 $firstattr = $aux[1];
20710 $secondattr = $aux[3];
20711 for ($i = 0; $i < count($aux[0]); $i++) {
20712
20713 $name = ( strtoupper($firstattr[$i]) == "NAME" ) ? strtoupper($aux[2][$i]) : strtoupper($aux[4][$i]);
20714 $content = ( strtoupper($firstattr[$i]) == "CONTENT" ) ? $aux[2][$i] : $aux[4][$i];
20715 switch ($name) {
20716 case "KEYWORDS": $this->SetKeywords($content);
20717 break;
20718 case "AUTHOR": $this->SetAuthor($content);
20719 break;
20720 case "DESCRIPTION": $this->SetSubject($content);
20721 break;
20722 }
20723 }
20724 }
20725
20726 function ReadCharset($html)
20727 {
20728 // Charset conversion
20729 if ($this->allow_charset_conversion) {
20730 if (preg_match('/<head.*charset=([^\'\"\s]*).*<\/head>/si', $html, $m)) {
20731 if (strtoupper($m[1]) != 'UTF-8') {
20732 $this->charset_in = strtoupper($m[1]);
20733 }
20734 }
20735 }
20736 }
20737
20738 function setCSS($arrayaux, $type = '', $tag = '')
20739 { // type= INLINE | BLOCK | TABLECELL // tag= BODY
20740 if (!is_array($arrayaux))
20741 return; //Removes PHP Warning
20742
20743 // mPDF 5.7.3 inline text-decoration parameters
20744 $preceeding_fontkey = $this->FontFamily . $this->FontStyle;
20745 $preceeding_fontsize = $this->FontSize;
20746 $spanbordset = false;
20747 $spanbgset = false;
20748 // mPDF 6
20749 $prevlevel = (($this->blklvl == 0) ? 0 : $this->blklvl - 1);
20750
20751 // Set font size first so that e.g. MARGIN 0.83em works on font size for this element
20752 if (isset($arrayaux['FONT-SIZE'])) {
20753 $v = $arrayaux['FONT-SIZE'];
20754 if (is_numeric($v[0])) {
20755 if ($type == 'BLOCK' && $this->blklvl > 0 && isset($this->blk[$this->blklvl - 1]['InlineProperties']) && isset($this->blk[$this->blklvl - 1]['InlineProperties']['size'])) {
20756 $mmsize = $this->ConvertSize($v, $this->blk[$this->blklvl - 1]['InlineProperties']['size']);
20757 } elseif ($type == 'TABLECELL') {
20758 $mmsize = $this->ConvertSize($v, $this->default_font_size / _MPDFK);
20759 } else {
20760 $mmsize = $this->ConvertSize($v, $this->FontSize);
20761 }
20762 $this->SetFontSize($mmsize * (_MPDFK), false); //Get size in points (pt)
20763 } else {
20764 $v = strtoupper($v);
20765 if (isset($this->fontsizes[$v])) {
20766 $this->SetFontSize($this->fontsizes[$v] * $this->default_font_size, false);
20767 }
20768 }
20769 if ($tag == 'BODY') {
20770 $this->SetDefaultFontSize($this->FontSizePt);
20771 }
20772 }
20773
20774 // mPDF 6
20775 if (isset($arrayaux['LANG']) && $arrayaux['LANG']) {
20776 if ($this->autoLangToFont && !$this->usingCoreFont) {
20777 if ($arrayaux['LANG'] != $this->default_lang && $arrayaux['LANG'] != 'UTF-8') {
20778 list ($coreSuitable, $mpdf_pdf_unifont) = GetLangOpts($arrayaux['LANG'], $this->useAdobeCJK, $this->fontdata);
20779 if ($mpdf_pdf_unifont) {
20780 $arrayaux['FONT-FAMILY'] = $mpdf_pdf_unifont;
20781 }
20782 if ($tag == 'BODY') {
20783 $this->default_lang = $arrayaux['LANG'];
20784 }
20785 }
20786 }
20787 $this->currentLang = $arrayaux['LANG'];
20788 }
20789
20790 // FOR INLINE and BLOCK OR 'BODY'
20791 if (isset($arrayaux['FONT-FAMILY'])) {
20792 $v = $arrayaux['FONT-FAMILY'];
20793 //If it is a font list, get all font types
20794 $aux_fontlist = explode(",", $v);
20795 $found = 0;
20796 foreach ($aux_fontlist AS $f) {
20797 $fonttype = trim($f);
20798 $fonttype = preg_replace('/["\']*(.*?)["\']*/', '\\1', $fonttype);
20799 $fonttype = preg_replace('/ /', '', $fonttype);
20800 $v = strtolower(trim($fonttype));
20801 if (isset($this->fonttrans[$v]) && $this->fonttrans[$v]) {
20802 $v = $this->fonttrans[$v];
20803 }
20804 if ((!$this->onlyCoreFonts && in_array($v, $this->available_unifonts)) ||
20805 in_array($v, array('ccourier', 'ctimes', 'chelvetica')) ||
20806 ($this->onlyCoreFonts && in_array($v, array('courier', 'times', 'helvetica', 'arial'))) ||
20807 in_array($v, array('sjis', 'uhc', 'big5', 'gb'))) {
20808 $fonttype = $v;
20809 $found = 1;
20810 break;
20811 }
20812 }
20813 if (!$found) {
20814 foreach ($aux_fontlist AS $f) {
20815 $fonttype = trim($f);
20816 $fonttype = preg_replace('/["\']*(.*?)["\']*/', '\\1', $fonttype);
20817 $fonttype = preg_replace('/ /', '', $fonttype);
20818 $v = strtolower(trim($fonttype));
20819 if (isset($this->fonttrans[$v]) && $this->fonttrans[$v]) {
20820 $v = $this->fonttrans[$v];
20821 }
20822 if (in_array($v, $this->sans_fonts) || in_array($v, $this->serif_fonts) || in_array($v, $this->mono_fonts)) {
20823 $fonttype = $v;
20824 break;
20825 }
20826 }
20827 }
20828
20829 if ($tag == 'BODY') {
20830 $this->SetDefaultFont($fonttype);
20831 }
20832 $this->SetFont($fonttype, $this->currentfontstyle, 0, false);
20833 } else {
20834 $this->SetFont($this->currentfontfamily, $this->currentfontstyle, 0, false);
20835 }
20836
20837 foreach ($arrayaux as $k => $v) {
20838 if ($type != 'INLINE' && $tag != 'BODY' && $type != 'TABLECELL') {
20839 switch ($k) {
20840 // BORDERS
20841 case 'BORDER-TOP':
20842 $this->blk[$this->blklvl]['border_top'] = $this->border_details($v);
20843 if ($this->blk[$this->blklvl]['border_top']['s']) {
20844 $this->blk[$this->blklvl]['border'] = 1;
20845 }
20846 break;
20847 case 'BORDER-BOTTOM':
20848 $this->blk[$this->blklvl]['border_bottom'] = $this->border_details($v);
20849 if ($this->blk[$this->blklvl]['border_bottom']['s']) {
20850 $this->blk[$this->blklvl]['border'] = 1;
20851 }
20852 break;
20853 case 'BORDER-LEFT':
20854 $this->blk[$this->blklvl]['border_left'] = $this->border_details($v);
20855 if ($this->blk[$this->blklvl]['border_left']['s']) {
20856 $this->blk[$this->blklvl]['border'] = 1;
20857 }
20858 break;
20859 case 'BORDER-RIGHT':
20860 $this->blk[$this->blklvl]['border_right'] = $this->border_details($v);
20861 if ($this->blk[$this->blklvl]['border_right']['s']) {
20862 $this->blk[$this->blklvl]['border'] = 1;
20863 }
20864 break;
20865
20866 // PADDING
20867 case 'PADDING-TOP':
20868 $this->blk[$this->blklvl]['padding_top'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20869 break;
20870 case 'PADDING-BOTTOM':
20871 $this->blk[$this->blklvl]['padding_bottom'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20872 break;
20873 case 'PADDING-LEFT':
20874 if (($tag == 'UL' || $tag == 'OL') && $v == 'auto') {
20875 $this->blk[$this->blklvl]['padding_left'] = 'auto';
20876 break;
20877 }
20878 $this->blk[$this->blklvl]['padding_left'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20879 break;
20880 case 'PADDING-RIGHT':
20881 if (($tag == 'UL' || $tag == 'OL') && $v == 'auto') {
20882 $this->blk[$this->blklvl]['padding_right'] = 'auto';
20883 break;
20884 }
20885 $this->blk[$this->blklvl]['padding_right'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20886 break;
20887
20888 // MARGINS
20889 case 'MARGIN-TOP':
20890 $tmp = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20891 if (isset($this->blk[$this->blklvl]['lastbottommargin'])) {
20892 if ($tmp > $this->blk[$this->blklvl]['lastbottommargin']) {
20893 $tmp -= $this->blk[$this->blklvl]['lastbottommargin'];
20894 } else {
20895 $tmp = 0;
20896 }
20897 }
20898 $this->blk[$this->blklvl]['margin_top'] = $tmp;
20899 break;
20900 case 'MARGIN-BOTTOM':
20901 $this->blk[$this->blklvl]['margin_bottom'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20902 break;
20903 case 'MARGIN-LEFT':
20904 $this->blk[$this->blklvl]['margin_left'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20905 break;
20906 case 'MARGIN-RIGHT':
20907 $this->blk[$this->blklvl]['margin_right'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20908 break;
20909
20910 /* -- BORDER-RADIUS -- */
20911 case 'BORDER-TOP-LEFT-RADIUS-H':
20912 $this->blk[$this->blklvl]['border_radius_TL_H'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20913 break;
20914 case 'BORDER-TOP-LEFT-RADIUS-V':
20915 $this->blk[$this->blklvl]['border_radius_TL_V'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20916 break;
20917 case 'BORDER-TOP-RIGHT-RADIUS-H':
20918 $this->blk[$this->blklvl]['border_radius_TR_H'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20919 break;
20920 case 'BORDER-TOP-RIGHT-RADIUS-V':
20921 $this->blk[$this->blklvl]['border_radius_TR_V'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20922 break;
20923 case 'BORDER-BOTTOM-LEFT-RADIUS-H':
20924 $this->blk[$this->blklvl]['border_radius_BL_H'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20925 break;
20926 case 'BORDER-BOTTOM-LEFT-RADIUS-V':
20927 $this->blk[$this->blklvl]['border_radius_BL_V'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20928 break;
20929 case 'BORDER-BOTTOM-RIGHT-RADIUS-H':
20930 $this->blk[$this->blklvl]['border_radius_BR_H'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20931 break;
20932 case 'BORDER-BOTTOM-RIGHT-RADIUS-V':
20933 $this->blk[$this->blklvl]['border_radius_BR_V'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20934 break;
20935 /* -- END BORDER-RADIUS -- */
20936
20937 case 'BOX-SHADOW':
20938 $bs = $this->cssmgr->setCSSboxshadow($v);
20939 if ($bs) {
20940 $this->blk[$this->blklvl]['box_shadow'] = $bs;
20941 }
20942 break;
20943
20944 case 'BACKGROUND-CLIP':
20945 if (strtoupper($v) == 'PADDING-BOX') {
20946 $this->blk[$this->blklvl]['background_clip'] = 'padding-box';
20947 } elseif (strtoupper($v) == 'CONTENT-BOX') {
20948 $this->blk[$this->blklvl]['background_clip'] = 'content-box';
20949 }
20950 break;
20951
20952 case 'PAGE-BREAK-AFTER':
20953 if (strtoupper($v) == 'AVOID') {
20954 $this->blk[$this->blklvl]['page_break_after_avoid'] = true;
20955 } elseif (strtoupper($v) == 'ALWAYS' || strtoupper($v) == 'LEFT' || strtoupper($v) == 'RIGHT') {
20956 $this->blk[$this->blklvl]['page_break_after'] = strtoupper($v);
20957 }
20958 break;
20959
20960 // mPDF 6 pagebreaktype
20961 case 'BOX-DECORATION-BREAK':
20962 if (strtoupper($v) == 'CLONE') {
20963 $this->blk[$this->blklvl]['box_decoration_break'] = 'clone';
20964 } elseif (strtoupper($v) == 'SLICE') {
20965 $this->blk[$this->blklvl]['box_decoration_break'] = 'slice';
20966 }
20967 break;
20968
20969 case 'WIDTH':
20970 if (strtoupper($v) != 'AUTO') {
20971 $this->blk[$this->blklvl]['css_set_width'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
20972 }
20973 break;
20974
20975 // mPDF 6 Lists
20976 // LISTS
20977 case 'LIST-STYLE-TYPE':
20978 $this->blk[$this->blklvl]['list_style_type'] = strtolower($v);
20979 break;
20980 case 'LIST-STYLE-IMAGE':
20981 $this->blk[$this->blklvl]['list_style_image'] = strtolower($v);
20982 break;
20983 case 'LIST-STYLE-POSITION':
20984 $this->blk[$this->blklvl]['list_style_position'] = strtolower($v);
20985 break;
20986 }//end of switch($k)
20987 }
20988
20989
20990 if ($type != 'INLINE' && $type != 'TABLECELL') { // All block-level, including BODY tag
20991 switch ($k) {
20992
20993 case 'TEXT-INDENT':
20994 // Computed value - to inherit
20995 $this->blk[$this->blklvl]['text_indent'] = $this->ConvertSize($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false) . 'mm';
20996 break;
20997
20998 case 'MARGIN-COLLAPSE': // Custom tag to collapse margins at top and bottom of page
20999 if (strtoupper($v) == 'COLLAPSE') {
21000 $this->blk[$this->blklvl]['margin_collapse'] = true;
21001 }
21002 break;
21003
21004 case 'LINE-HEIGHT':
21005 $this->blk[$this->blklvl]['line_height'] = $this->fixLineheight($v);
21006 if (!$this->blk[$this->blklvl]['line_height']) {
21007 $this->blk[$this->blklvl]['line_height'] = 'N';
21008 } // mPDF 6
21009 break;
21010
21011 // mPDF 6
21012 case 'LINE-STACKING-STRATEGY':
21013 $this->blk[$this->blklvl]['line_stacking_strategy'] = strtolower($v);
21014 break;
21015
21016 case 'LINE-STACKING-SHIFT':
21017 $this->blk[$this->blklvl]['line_stacking_shift'] = strtolower($v);
21018 break;
21019
21020 case 'TEXT-ALIGN': //left right center justify
21021 switch (strtoupper($v)) {
21022 case 'LEFT':
21023 $this->blk[$this->blklvl]['align'] = "L";
21024 break;
21025 case 'CENTER':
21026 $this->blk[$this->blklvl]['align'] = "C";
21027 break;
21028 case 'RIGHT':
21029 $this->blk[$this->blklvl]['align'] = "R";
21030 break;
21031 case 'JUSTIFY':
21032 $this->blk[$this->blklvl]['align'] = "J";
21033 break;
21034 }
21035 break;
21036
21037 /* -- BACKGROUNDS -- */
21038 case 'BACKGROUND-GRADIENT':
21039 if ($type == 'BLOCK') {
21040 $this->blk[$this->blklvl]['gradient'] = $v;
21041 }
21042 break;
21043 /* -- END BACKGROUNDS -- */
21044
21045 case 'DIRECTION':
21046 if ($v) {
21047 $this->blk[$this->blklvl]['direction'] = strtolower($v);
21048 }
21049 break;
21050 }//end of switch($k)
21051 }
21052
21053 // FOR INLINE ONLY
21054 if ($type == 'INLINE') {
21055 switch ($k) {
21056 case 'DISPLAY':
21057 if (strtoupper($v) == 'NONE') {
21058 $this->inlineDisplayOff = true;
21059 }
21060 break;
21061 case 'DIRECTION':
21062 break;
21063 }//end of switch($k)
21064 }
21065 // FOR INLINE ONLY
21066 if ($type == 'INLINE') {
21067 switch ($k) {
21068 // BORDERS
21069 case 'BORDER-TOP':
21070 $this->spanborddet['T'] = $this->border_details($v);
21071 $this->spanborder = true;
21072 $spanbordset = true;
21073 break;
21074 case 'BORDER-BOTTOM':
21075 $this->spanborddet['B'] = $this->border_details($v);
21076 $this->spanborder = true;
21077 $spanbordset = true;
21078 break;
21079 case 'BORDER-LEFT':
21080 $this->spanborddet['L'] = $this->border_details($v);
21081 $this->spanborder = true;
21082 $spanbordset = true;
21083 break;
21084 case 'BORDER-RIGHT':
21085 $this->spanborddet['R'] = $this->border_details($v);
21086 $this->spanborder = true;
21087 $spanbordset = true;
21088 break;
21089 case 'VISIBILITY': // block is set in OpenTag
21090 $v = strtolower($v);
21091 if ($v == 'visible' || $v == 'hidden' || $v == 'printonly' || $v == 'screenonly') {
21092 $this->textparam['visibility'] = $v;
21093 }
21094 break;
21095 }//end of switch($k)
21096 }
21097
21098 if ($type != 'TABLECELL') {
21099 // FOR INLINE and BLOCK
21100 switch ($k) {
21101 case 'TEXT-ALIGN': //left right center justify
21102 if (strtoupper($v) == 'NOJUSTIFY' && $this->blk[$this->blklvl]['align'] == "J") {
21103 $this->blk[$this->blklvl]['align'] = "";
21104 }
21105 break;
21106 // bgcolor only - to stay consistent with original html2fpdf
21107 case 'BACKGROUND':
21108 case 'BACKGROUND-COLOR':
21109 $cor = $this->ConvertColor($v);
21110 if ($cor) {
21111 if ($tag == 'BODY') {
21112 $this->bodyBackgroundColor = $cor;
21113 } elseif ($type == 'INLINE') {
21114 $this->spanbgcolorarray = $cor;
21115 $this->spanbgcolor = true;
21116 $spanbgset = true;
21117 } else {
21118 $this->blk[$this->blklvl]['bgcolorarray'] = $cor;
21119 $this->blk[$this->blklvl]['bgcolor'] = true;
21120 }
21121 } elseif ($type != 'INLINE') {
21122 if ($this->ColActive) {
21123 $this->blk[$this->blklvl]['bgcolorarray'] = $this->blk[$prevlevel]['bgcolorarray'];
21124 $this->blk[$this->blklvl]['bgcolor'] = $this->blk[$prevlevel]['bgcolor'];
21125 }
21126 }
21127 break;
21128
21129 case 'VERTICAL-ALIGN': //super and sub only dealt with here e.g. <SUB> and <SUP>
21130 switch (strtoupper($v)) {
21131 case 'SUPER':
21132 $this->textvar = ($this->textvar | FA_SUPERSCRIPT); // mPDF 5.7.1
21133 $this->textvar = ($this->textvar & ~FA_SUBSCRIPT);
21134 // mPDF 5.7.3 inline text-decoration parameters
21135 if (isset($this->textparam['text-baseline'])) {
21136 $this->textparam['text-baseline'] += ($this->baselineSup) * $preceeding_fontsize;
21137 } else {
21138 $this->textparam['text-baseline'] = ($this->baselineSup) * $preceeding_fontsize;
21139 }
21140 break;
21141 case 'SUB':
21142 $this->textvar = ($this->textvar | FA_SUBSCRIPT);
21143 $this->textvar = ($this->textvar & ~FA_SUPERSCRIPT);
21144 // mPDF 5.7.3 inline text-decoration parameters
21145 if (isset($this->textparam['text-baseline'])) {
21146 $this->textparam['text-baseline'] += ($this->baselineSub) * $preceeding_fontsize;
21147 } else {
21148 $this->textparam['text-baseline'] = ($this->baselineSub) * $preceeding_fontsize;
21149 }
21150 break;
21151 case 'BASELINE':
21152 $this->textvar = ($this->textvar & ~FA_SUBSCRIPT);
21153 $this->textvar = ($this->textvar & ~FA_SUPERSCRIPT);
21154 // mPDF 5.7.3 inline text-decoration parameters
21155 if (isset($this->textparam['text-baseline'])) {
21156 unset($this->textparam['text-baseline']);
21157 }
21158 break;
21159 // mPDF 5.7.3 inline text-decoration parameters
21160 default:
21161 $lh = $this->_computeLineheight($this->blk[$this->blklvl]['line_height']);
21162 $sz = $this->ConvertSize($v, $lh, $this->FontSize, false);
21163 $this->textvar = ($this->textvar & ~FA_SUBSCRIPT);
21164 $this->textvar = ($this->textvar & ~FA_SUPERSCRIPT);
21165 if ($sz) {
21166 if ($sz > 0) {
21167 $this->textvar = ($this->textvar | FA_SUPERSCRIPT);
21168 } else {
21169 $this->textvar = ($this->textvar | FA_SUBSCRIPT);
21170 }
21171 if (isset($this->textparam['text-baseline'])) {
21172 $this->textparam['text-baseline'] += $sz;
21173 } else {
21174 $this->textparam['text-baseline'] = $sz;
21175 }
21176 }
21177 }
21178 break;
21179 }//end of switch($k)
21180 }
21181
21182
21183 // FOR ALL
21184 switch ($k) {
21185 case 'LETTER-SPACING':
21186 $this->lSpacingCSS = $v;
21187 if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
21188 $this->fixedlSpacing = $this->ConvertSize($this->lSpacingCSS, $this->FontSize);
21189 }
21190 break;
21191
21192 case 'WORD-SPACING':
21193 $this->wSpacingCSS = $v;
21194 if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
21195 $this->minwSpacing = $this->ConvertSize($this->wSpacingCSS, $this->FontSize);
21196 }
21197 break;
21198
21199 case 'FONT-STYLE': // italic normal oblique
21200 switch (strtoupper($v)) {
21201 case 'ITALIC':
21202 case 'OBLIQUE':
21203 $this->SetStyle('I', true);
21204 break;
21205 case 'NORMAL':
21206 $this->SetStyle('I', false);
21207 break;
21208 }
21209 break;
21210
21211 case 'FONT-WEIGHT': // normal bold //Does not support: bolder, lighter, 100..900(step value=100)
21212 switch (strtoupper($v)) {
21213 case 'BOLD':
21214 $this->SetStyle('B', true);
21215 break;
21216 case 'NORMAL':
21217 $this->SetStyle('B', false);
21218 break;
21219 }
21220 break;
21221
21222 case 'FONT-KERNING':
21223 if (strtoupper($v) == 'NORMAL' || (strtoupper($v) == 'AUTO' && $this->useKerning)) {
21224 /* -- OTL -- */
21225 if ($this->CurrentFont['haskernGPOS']) {
21226 if (isset($this->OTLtags['Plus'])) {
21227 $this->OTLtags['Plus'] .= ' kern';
21228 } else {
21229 $this->OTLtags['Plus'] = ' kern';
21230 }
21231 }
21232 /* -- END OTL -- */ else { // *OTL*
21233 $this->textvar = ($this->textvar | FC_KERNING);
21234 } // *OTL*
21235 } elseif (strtoupper($v) == 'NONE' || (strtoupper($v) == 'AUTO' && !$this->useKerning)) {
21236 if (isset($this->OTLtags['Plus']))
21237 $this->OTLtags['Plus'] = str_replace('kern', '', $this->OTLtags['Plus']); // *OTL*
21238 if (isset($this->OTLtags['FFPlus']))
21239 $this->OTLtags['FFPlus'] = preg_replace('/kern[\d]*/', '', $this->OTLtags['FFPlus']);
21240 $this->textvar = ($this->textvar & ~FC_KERNING);
21241 }
21242 break;
21243
21244 /* -- OTL -- */
21245 case 'FONT-LANGUAGE-OVERRIDE':
21246 $v = strtoupper($v);
21247 if (strpos($v, 'NORMAL') !== false) {
21248 $this->fontLanguageOverride = '';
21249 } else {
21250 $this->fontLanguageOverride = trim($v);
21251 }
21252 break;
21253
21254
21255 case 'FONT-VARIANT-POSITION':
21256 if (isset($this->OTLtags['Plus']))
21257 $this->OTLtags['Plus'] = str_replace(array('sups', 'subs'), '', $this->OTLtags['Plus']);
21258 switch (strtoupper($v)) {
21259 case 'SUPER':
21260 $this->OTLtags['Plus'] .= ' sups';
21261 break;
21262 case 'SUB':
21263 $this->OTLtags['Plus'] .= ' subs';
21264 break;
21265 case 'NORMAL':
21266 break;
21267 }
21268 break;
21269
21270 case 'FONT-VARIANT-CAPS':
21271 $v = strtoupper($v);
21272 if (!isset($this->OTLtags['Plus'])) {
21273 $this->OTLtags['Plus'] = '';
21274 }
21275 $this->OTLtags['Plus'] = str_replace(array('c2sc', 'smcp', 'c2pc', 'pcap', 'unic', 'titl'), '', $this->OTLtags['Plus']);
21276 $this->textvar = ($this->textvar & ~FC_SMALLCAPS); // ?????????????? <small-caps>
21277 if (strpos($v, 'ALL-SMALL-CAPS') !== false) {
21278 $this->OTLtags['Plus'] .= ' c2sc smcp';
21279 } elseif (strpos($v, 'SMALL-CAPS') !== false) {
21280 if (isset($this->CurrentFont['hassmallcapsGSUB']) && $this->CurrentFont['hassmallcapsGSUB']) {
21281 $this->OTLtags['Plus'] .= ' smcp';
21282 } else {
21283 $this->textvar = ($this->textvar | FC_SMALLCAPS);
21284 }
21285 } elseif (strpos($v, 'ALL-PETITE-CAPS') !== false) {
21286 $this->OTLtags['Plus'] .= ' c2pc pcap';
21287 } elseif (strpos($v, 'PETITE-CAPS') !== false) {
21288 $this->OTLtags['Plus'] .= ' pcap';
21289 } elseif (strpos($v, 'UNICASE') !== false) {
21290 $this->OTLtags['Plus'] .= ' unic';
21291 } elseif (strpos($v, 'TITLING-CAPS') !== false) {
21292 $this->OTLtags['Plus'] .= ' titl';
21293 }
21294 break;
21295
21296 case 'FONT-VARIANT-LIGATURES':
21297 $v = strtoupper($v);
21298 if (!isset($this->OTLtags['Plus'])) {
21299 $this->OTLtags['Plus'] = '';
21300 }
21301 if (!isset($this->OTLtags['Minus'])) {
21302 $this->OTLtags['Minus'] = '';
21303 }
21304 if (strpos($v, 'NORMAL') !== false) {
21305 $this->OTLtags['Minus'] = str_replace(array('liga', 'clig', 'calt'), '', $this->OTLtags['Minus']);
21306 $this->OTLtags['Plus'] = str_replace(array('dlig', 'hlig'), '', $this->OTLtags['Plus']);
21307 } elseif (strpos($v, 'NONE') !== false) {
21308 $this->OTLtags['Minus'] .= ' liga clig calt';
21309 $this->OTLtags['Plus'] = str_replace(array('dlig', 'hlig'), '', $this->OTLtags['Plus']);
21310 }
21311 if (strpos($v, 'NO-COMMON-LIGATURES') !== false) {
21312 $this->OTLtags['Minus'] .= ' liga clig';
21313 } elseif (strpos($v, 'COMMON-LIGATURES') !== false) {
21314 $this->OTLtags['Minus'] = str_replace(array('liga', 'clig'), '', $this->OTLtags['Minus']);
21315 }
21316 if (strpos($v, 'NO-CONTEXTUAL') !== false) {
21317 $this->OTLtags['Minus'] .= ' calt';
21318 } elseif (strpos($v, 'CONTEXTUAL') !== false) {
21319 $this->OTLtags['Minus'] = str_replace('calt', '', $this->OTLtags['Minus']);
21320 }
21321 if (strpos($v, 'NO-DISCRETIONARY-LIGATURES') !== false) {
21322 $this->OTLtags['Plus'] = str_replace('dlig', '', $this->OTLtags['Plus']);
21323 } elseif (strpos($v, 'DISCRETIONARY-LIGATURES') !== false) {
21324 $this->OTLtags['Plus'] .= ' dlig';
21325 }
21326 if (strpos($v, 'NO-HISTORICAL-LIGATURES') !== false) {
21327 $this->OTLtags['Plus'] = str_replace('hlig', '', $this->OTLtags['Plus']);
21328 } elseif (strpos($v, 'HISTORICAL-LIGATURES') !== false) {
21329 $this->OTLtags['Plus'] .= ' hlig';
21330 }
21331
21332 break;
21333
21334 case 'FONT-VARIANT-NUMERIC':
21335 $v = strtoupper($v);
21336 if (!isset($this->OTLtags['Plus'])) {
21337 $this->OTLtags['Plus'] = '';
21338 }
21339 if (strpos($v, 'NORMAL') !== false) {
21340 $this->OTLtags['Plus'] = str_replace(array('ordn', 'zero', 'lnum', 'onum', 'pnum', 'tnum', 'frac', 'afrc'), '', $this->OTLtags['Plus']);
21341 }
21342 if (strpos($v, 'ORDINAL') !== false) {
21343 $this->OTLtags['Plus'] .= ' ordn';
21344 }
21345 if (strpos($v, 'SLASHED-ZERO') !== false) {
21346 $this->OTLtags['Plus'] .= ' zero';
21347 }
21348 if (strpos($v, 'LINING-NUMS') !== false) {
21349 $this->OTLtags['Plus'] .= ' lnum';
21350 $this->OTLtags['Plus'] = str_replace('onum', '', $this->OTLtags['Plus']);
21351 } elseif (strpos($v, 'OLDSTYLE-NUMS') !== false) {
21352 $this->OTLtags['Plus'] .= ' onum';
21353 $this->OTLtags['Plus'] = str_replace('lnum', '', $this->OTLtags['Plus']);
21354 }
21355 if (strpos($v, 'PROPORTIONAL-NUMS') !== false) {
21356 $this->OTLtags['Plus'] .= ' pnum';
21357 $this->OTLtags['Plus'] = str_replace('tnum', '', $this->OTLtags['Plus']);
21358 } elseif (strpos($v, 'TABULAR-NUMS') !== false) {
21359 $this->OTLtags['Plus'] .= ' tnum';
21360 $this->OTLtags['Plus'] = str_replace('pnum', '', $this->OTLtags['Plus']);
21361 }
21362 if (strpos($v, 'DIAGONAL-FRACTIONS') !== false) {
21363 $this->OTLtags['Plus'] .= ' frac';
21364 $this->OTLtags['Plus'] = str_replace('afrc', '', $this->OTLtags['Plus']);
21365 } elseif (strpos($v, 'STACKED-FRACTIONS') !== false) {
21366 $this->OTLtags['Plus'] .= ' afrc';
21367 $this->OTLtags['Plus'] = str_replace('frac', '', $this->OTLtags['Plus']);
21368 }
21369 break;
21370
21371 case 'FONT-VARIANT-ALTERNATES': // Only supports historical-forms
21372 $v = strtoupper($v);
21373 if (!isset($this->OTLtags['Plus'])) {
21374 $this->OTLtags['Plus'] = '';
21375 }
21376 if (strpos($v, 'NORMAL') !== false) {
21377 $this->OTLtags['Plus'] = str_replace('hist', '', $this->OTLtags['Plus']);
21378 }
21379 if (strpos($v, 'HISTORICAL-FORMS') !== false) {
21380 $this->OTLtags['Plus'] .= ' hist';
21381 }
21382 break;
21383
21384
21385 case 'FONT-FEATURE-SETTINGS':
21386 $v = strtolower($v);
21387 if (strpos($v, 'normal') !== false) {
21388 $this->OTLtags['FFMinus'] = '';
21389 $this->OTLtags['FFPlus'] = '';
21390 } else {
21391 if (!isset($this->OTLtags['FFPlus'])) {
21392 $this->OTLtags['FFPlus'] = '';
21393 }
21394 if (!isset($this->OTLtags['FFMinus'])) {
21395 $this->OTLtags['FFMinus'] = '';
21396 }
21397 $tags = preg_split('/[,]/', $v);
21398 foreach ($tags AS $t) {
21399 if (preg_match('/[\"\']([a-zA-Z0-9]{4})[\"\']\s*(on|off|\d*){0,1}/', $t, $m)) {
21400 if ($m[2] == 'off' || $m[2] === '0') {
21401 if (strpos($this->OTLtags['FFMinus'], $m[1]) === false) {
21402 $this->OTLtags['FFMinus'] .= ' ' . $m[1];
21403 }
21404 $this->OTLtags['FFPlus'] = preg_replace('/' . $m[1] . '[\d]*/', '', $this->OTLtags['FFPlus']);
21405 } else {
21406 if ($m[2] == 'on') {
21407 $m[2] = '1';
21408 }
21409 if (strpos($this->OTLtags['FFPlus'], $m[1]) === false) {
21410 $this->OTLtags['FFPlus'] .= ' ' . $m[1] . $m[2];
21411 }
21412 $this->OTLtags['FFMinus'] = str_replace($m[1], '', $this->OTLtags['FFMinus']);
21413 }
21414 }
21415 }
21416 }
21417 break;
21418 /* -- END OTL -- */
21419
21420
21421 case 'TEXT-TRANSFORM': // none uppercase lowercase //Does support: capitalize
21422 switch (strtoupper($v)) { //Not working 100%
21423 case 'CAPITALIZE':
21424 $this->textvar = ($this->textvar | FT_CAPITALIZE); // mPDF 5.7.1
21425 $this->textvar = ($this->textvar & ~FT_UPPERCASE); // mPDF 5.7.1
21426 $this->textvar = ($this->textvar & ~FT_LOWERCASE); // mPDF 5.7.1
21427 break;
21428 case 'UPPERCASE':
21429 $this->textvar = ($this->textvar | FT_UPPERCASE); // mPDF 5.7.1
21430 $this->textvar = ($this->textvar & ~FT_LOWERCASE); // mPDF 5.7.1
21431 $this->textvar = ($this->textvar & ~FT_CAPITALIZE); // mPDF 5.7.1
21432 break;
21433 case 'LOWERCASE':
21434 $this->textvar = ($this->textvar | FT_LOWERCASE); // mPDF 5.7.1
21435 $this->textvar = ($this->textvar & ~FT_UPPERCASE); // mPDF 5.7.1
21436 $this->textvar = ($this->textvar & ~FT_CAPITALIZE); // mPDF 5.7.1
21437 break;
21438 case 'NONE': break;
21439 $this->textvar = ($this->textvar & ~FT_UPPERCASE); // mPDF 5.7.1
21440 $this->textvar = ($this->textvar & ~FT_LOWERCASE); // mPDF 5.7.1
21441 $this->textvar = ($this->textvar & ~FT_CAPITALIZE); // mPDF 5.7.1
21442 }
21443 break;
21444
21445 case 'TEXT-SHADOW':
21446 $ts = $this->cssmgr->setCSStextshadow($v);
21447 if ($ts) {
21448 $this->textshadow = $ts;
21449 }
21450 break;
21451
21452 case 'HYPHENS':
21453 if (strtoupper($v) == 'NONE') {
21454 $this->textparam['hyphens'] = 2;
21455 } elseif (strtoupper($v) == 'AUTO') {
21456 $this->textparam['hyphens'] = 1;
21457 } elseif (strtoupper($v) == 'MANUAL') {
21458 $this->textparam['hyphens'] = 0;
21459 }
21460 break;
21461
21462 case 'TEXT-OUTLINE':
21463 if (strtoupper($v) == 'NONE') {
21464 $this->textparam['outline-s'] = false;
21465 }
21466 break;
21467
21468 case 'TEXT-OUTLINE-WIDTH':
21469 case 'OUTLINE-WIDTH':
21470 switch (strtoupper($v)) {
21471 case 'THIN': $v = '0.03em';
21472 break;
21473 case 'MEDIUM': $v = '0.05em';
21474 break;
21475 case 'THICK': $v = '0.07em';
21476 break;
21477 }
21478 $w = $this->ConvertSize($v, $this->FontSize, $this->FontSize);
21479 if ($w) {
21480 $this->textparam['outline-WIDTH'] = $w;
21481 $this->textparam['outline-s'] = true;
21482 } else {
21483 $this->textparam['outline-s'] = false;
21484 }
21485 break;
21486
21487 case 'TEXT-OUTLINE-COLOR':
21488 case 'OUTLINE-COLOR':
21489 if (strtoupper($v) == 'INVERT') {
21490 if ($this->colorarray) {
21491 $cor = $this->colorarray;
21492 $this->textparam['outline-COLOR'] = $this->_invertColor($cor);
21493 } else {
21494 $this->textparam['outline-COLOR'] = $this->ConvertColor(255);
21495 }
21496 } else {
21497 $cor = $this->ConvertColor($v);
21498 if ($cor) {
21499 $this->textparam['outline-COLOR'] = $cor;
21500 }
21501 }
21502 break;
21503
21504 case 'COLOR': // font color
21505 $cor = $this->ConvertColor($v);
21506 if ($cor) {
21507 $this->colorarray = $cor;
21508 $this->SetTColor($cor);
21509 }
21510 break;
21511 }//end of switch($k)
21512 }//end of foreach
21513 // mPDF 5.7.3 inline text-decoration parameters
21514 // Needs to be set at the end - after vertical-align = super/sub, so that textparam['text-baseline'] is set
21515 if (isset($arrayaux['TEXT-DECORATION'])) {
21516 $v = $arrayaux['TEXT-DECORATION']; // none underline line-through (strikeout) //Does not support: blink
21517 if (stristr($v, 'LINE-THROUGH')) {
21518 $this->textvar = ($this->textvar | FD_LINETHROUGH);
21519 // mPDF 5.7.3 inline text-decoration parameters
21520 if (isset($this->textparam['text-baseline'])) {
21521 $this->textparam['s-decoration']['baseline'] = $this->textparam['text-baseline'];
21522 } else {
21523 $this->textparam['s-decoration']['baseline'] = 0;
21524 }
21525 $this->textparam['s-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
21526 $this->textparam['s-decoration']['fontsize'] = $this->FontSize;
21527 $this->textparam['s-decoration']['color'] = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
21528 }
21529 if (stristr($v, 'UNDERLINE')) {
21530 $this->textvar = ($this->textvar | FD_UNDERLINE);
21531 // mPDF 5.7.3 inline text-decoration parameters
21532 if (isset($this->textparam['text-baseline'])) {
21533 $this->textparam['u-decoration']['baseline'] = $this->textparam['text-baseline'];
21534 } else {
21535 $this->textparam['u-decoration']['baseline'] = 0;
21536 }
21537 $this->textparam['u-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
21538 $this->textparam['u-decoration']['fontsize'] = $this->FontSize;
21539 $this->textparam['u-decoration']['color'] = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
21540 }
21541 if (stristr($v, 'OVERLINE')) {
21542 $this->textvar = ($this->textvar | FD_OVERLINE);
21543 // mPDF 5.7.3 inline text-decoration parameters
21544 if (isset($this->textparam['text-baseline'])) {
21545 $this->textparam['o-decoration']['baseline'] = $this->textparam['text-baseline'];
21546 } else {
21547 $this->textparam['o-decoration']['baseline'] = 0;
21548 }
21549 $this->textparam['o-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
21550 $this->textparam['o-decoration']['fontsize'] = $this->FontSize;
21551 $this->textparam['o-decoration']['color'] = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
21552 }
21553 if (stristr($v, 'NONE')) {
21554 $this->textvar = ($this->textvar & ~FD_UNDERLINE);
21555 $this->textvar = ($this->textvar & ~FD_LINETHROUGH);
21556 $this->textvar = ($this->textvar & ~FD_OVERLINE);
21557 // mPDF 5.7.3 inline text-decoration parameters
21558 if (isset($this->textparam['u-decoration'])) {
21559 unset($this->textparam['u-decoration']);
21560 }
21561 if (isset($this->textparam['s-decoration'])) {
21562 unset($this->textparam['s-decoration']);
21563 }
21564 if (isset($this->textparam['o-decoration'])) {
21565 unset($this->textparam['o-decoration']);
21566 }
21567 }
21568 }
21569 // mPDF 6
21570 if ($spanbordset) { // BORDER has been set on this INLINE element
21571 if (isset($this->textparam['text-baseline'])) {
21572 $this->textparam['bord-decoration']['baseline'] = $this->textparam['text-baseline'];
21573 } else {
21574 $this->textparam['bord-decoration']['baseline'] = 0;
21575 }
21576 $this->textparam['bord-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
21577 $this->textparam['bord-decoration']['fontsize'] = $this->FontSize;
21578 }
21579 if ($spanbgset) { // BACKGROUND[-COLOR] has been set on this INLINE element
21580 if (isset($this->textparam['text-baseline'])) {
21581 $this->textparam['bg-decoration']['baseline'] = $this->textparam['text-baseline'];
21582 } else {
21583 $this->textparam['bg-decoration']['baseline'] = 0;
21584 }
21585 $this->textparam['bg-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
21586 $this->textparam['bg-decoration']['fontsize'] = $this->FontSize;
21587 }
21588 }
21589
21590 /* -- END HTML-CSS -- */
21591
21592 function SetStyle($tag, $enable)
21593 {
21594 $this->$tag = $enable;
21595 $style = '';
21596 foreach (array('B', 'I') as $s) {
21597 if ($this->$s) {
21598 $style.=$s;
21599 }
21600 }
21601 $this->currentfontstyle = $style;
21602 $this->SetFont('', $style, 0, false);
21603 }
21604
21605 // Set multiple styles at one time
21606 function SetStylesArray($arr)
21607 {
21608 $style = '';
21609 foreach (array('B', 'I') as $s) {
21610 if (isset($arr[$s])) {
21611 if ($arr[$s]) {
21612 $this->$s = true;
21613 $style.=$s;
21614 } else {
21615 $this->$s = false;
21616 }
21617 } elseif ($this->$s) {
21618 $style.=$s;
21619 }
21620 }
21621 $this->currentfontstyle = $style;
21622 $this->SetFont('', $style, 0, false);
21623 }
21624
21625 // Set multiple styles at one $str e.g. "BI"
21626 function SetStyles($str)
21627 {
21628 $style = '';
21629 foreach (array('B', 'I') as $s) {
21630 if (strpos($str, $s) !== false) {
21631 $this->$s = true;
21632 $style.=$s;
21633 } else {
21634 $this->$s = false;
21635 }
21636 }
21637 $this->currentfontstyle = $style;
21638 $this->SetFont('', $style, 0, false);
21639 }
21640
21641 function ResetStyles()
21642 {
21643 foreach (array('B', 'I') as $s) {
21644 $this->$s = false;
21645 }
21646 $this->currentfontstyle = '';
21647 $this->SetFont('', '', 0, false);
21648 }
21649
21650 function DisableTags($str = '')
21651 {
21652 if ($str == '') { //enable all tags
21653 //Insert new supported tags in the long string below.
21654 $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><jpgraph><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>";
21655 } else {
21656 $str = explode(",", $str);
21657 foreach ($str as $v)
21658 $this->enabledtags = str_replace(trim($v), '', $this->enabledtags);
21659 }
21660 }
21661
21662 /* -- TABLES -- */
21663
21664 function TableCheckMinWidth($maxwidth, $forcewrap = 0, $textbuffer, $checkletter = false)
21665 { // mPDF 6
21666 $acclength = 0; // mPDF 6 (accumulated length across > 1 chunk)
21667 $acclongest = 0; // mPDF 6 (accumulated length max across > 1 chunk)
21668 $biggestword = 0;
21669 $toonarrow = false;
21670 if ((count($textbuffer) == 0) or ( (count($textbuffer) == 1) && ($textbuffer[0][0] == ''))) {
21671 return 0;
21672 }
21673
21674 foreach ($textbuffer as $chunk) {
21675
21676 $line = $chunk[0];
21677 $OTLdata = (isset($chunk[18]) ? $chunk[18] : NULL);
21678
21679 // mPDF ITERATION
21680 if ($this->iterationCounter)
21681 $line = preg_replace('/{iteration ([a-zA-Z0-9_]+)}/', '\\1', $line);
21682
21683 // IMAGES & FORM ELEMENTS
21684 if (substr($line, 0, 3) == "\xbb\xa4\xac") { //inline object - FORM element or IMAGE!
21685 $objattr = $this->_getObjAttr($line);
21686 if ($objattr['type'] != 'hr' && isset($objattr['width']) && ($objattr['width'] / $this->shrin_k) > ($maxwidth + 0.0001)) {
21687 if (($objattr['width'] / $this->shrin_k) > $biggestword) {
21688 $biggestword = ($objattr['width'] / $this->shrin_k);
21689 }
21690 $toonarrow = true;
21691 }
21692 continue;
21693 }
21694
21695 if ($line == "\n") {
21696 $acclength = 0; // mPDF 6 (accumulated length across > 1 chunk)
21697 continue;
21698 }
21699 $line = trim($line);
21700 if (!empty($OTLdata)) {
21701 $this->otl->trimOTLdata($OTLdata, true, true);
21702 } // *OTL*
21703 // SET FONT SIZE/STYLE from $chunk[n]
21704 // FONTSIZE
21705 if (isset($chunk[11]) and $chunk[11] != '') {
21706 if ($this->shrin_k) {
21707 $this->SetFontSize($chunk[11] / $this->shrin_k, false);
21708 } else {
21709 $this->SetFontSize($chunk[11], false);
21710 }
21711 }
21712 // FONTFAMILY
21713 if (isset($chunk[4]) and $chunk[4] != '') {
21714 $font = $this->SetFont($chunk[4], $this->FontStyle, 0, false);
21715 }
21716 // B I
21717 if (isset($chunk[2]) and $chunk[2] != '') {
21718 $this->SetStyles($chunk[2]);
21719 }
21720
21721 $lbw = $rbw = 0; // Border widths
21722 if (isset($chunk[16]) && !empty($chunk[16])) { //Border
21723 $this->spanborddet = $chunk[16];
21724 $lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
21725 $rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
21726 }
21727 if (isset($chunk[15])) { // Word spacing
21728 $this->wSpacingCSS = $chunk[15];
21729 if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
21730 $this->minwSpacing = $this->ConvertSize($this->wSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
21731 }
21732 }
21733 if (isset($chunk[14])) { // Letter spacing
21734 $this->lSpacingCSS = $chunk[14];
21735 if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
21736 $this->fixedlSpacing = $this->ConvertSize($this->lSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
21737 }
21738 }
21739 if (isset($chunk[8])) { // mPDF 5.7.1
21740 $this->textvar = $chunk[8];
21741 }
21742
21743 // mPDF 6
21744 // If overflow==wrap ($checkletter) OR (No word breaks and contains CJK)
21745 if ($checkletter || (!preg_match('/(\xe2\x80\x8b| )/', trim($line)) && preg_match("/([" . $this->pregCJKchars . "])/u", $line) )) {
21746 if (preg_match("/([" . $this->pregCJKchars . "])/u", $line)) {
21747 $checkCJK = true;
21748 } else {
21749 $checkCJK = false;
21750 }
21751
21752 $letters = preg_split('//u', $line);
21753 foreach ($letters as $k => $letter) {
21754
21755 // mPDF 6
21756 if ($checkCJK) {
21757 if (preg_match("/[" . $this->CJKleading . "]/u", $letter) && $k > 0) {
21758 $letter = $letters[$k - 1] . $letter;
21759 }
21760 if (preg_match("/[" . $this->CJKfollowing . "]/u", $letter) && $k < (count($letters) - 1)) {
21761 $letter = $letter . $letters[$k + 1];
21762 }
21763 }
21764
21765 $letterwidth = $this->GetStringWidth($letter, false, false, $chunk[8]); // Pass $textvar ($chunk[8]), but do OTLdata here
21766 // so don't have to split OTLdata for each word
21767 if ($k == 0) {
21768 $letterwidth += $lbw;
21769 }
21770 if ($k == (count($letters) - 1)) {
21771 $letterwidth += $rbw;
21772 }
21773
21774 //Warn user that maxwidth is insufficient
21775 if ($letterwidth > $maxwidth + 0.0001) {
21776 if ($letterwidth > $biggestword) {
21777 $biggestword = $letterwidth;
21778 }
21779 $toonarrow = true;
21780 }
21781 }
21782 } else {
21783 // mPDF 6
21784 // Need to account for any XAdvance in GPOSinfo (OTLdata = $chunk[18])
21785 $wordXAdvance = array();
21786 if (isset($chunk[18]) && $chunk[18]) {
21787 preg_match_all('/(\xe2\x80\x8b| )/', $line, $spaces, PREG_OFFSET_CAPTURE); // U+200B Zero Width word boundary, or space
21788 $lastoffset = 0;
21789 $k = -1; // Added so that if no spaces found, "last word" later is calculated for the one and only word
21790 foreach ($spaces[0] as $k => $m) {
21791 $offset = $m[1];
21792 // ...TableCheckMinWidth...
21793 // At this point, BIDI not applied, Writing direction is not set, and XAdvanceL balances XAdvanceR
21794 for ($n = $lastoffset; $n < $offset; $n++) {
21795 if (isset($chunk[18]['GPOSinfo'][$n]['XAdvanceL'])) {
21796 if (isset($wordXAdvance[$k])) {
21797 $wordXAdvance[$k] += $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
21798 } else {
21799 $wordXAdvance[$k] = $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
21800 }
21801 }
21802 }
21803 $lastoffset = $offset + 1;
21804 }
21805
21806 $k++; // last word
21807 foreach ($chunk[18]['GPOSinfo'] AS $n => $gpos) {
21808 if ($n >= $lastoffset && isset($chunk[18]['GPOSinfo'][$n]['XAdvanceL'])) {
21809 if (isset($wordXAdvance[$k])) {
21810 $wordXAdvance[$k] += $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
21811 } else {
21812 $wordXAdvance[$k] = $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
21813 }
21814 }
21815 }
21816 }
21817
21818 $words = preg_split('/(\xe2\x80\x8b| )/', $line); // U+200B Zero Width word boundary, or space
21819 foreach ($words as $k => $word) {
21820 $word = trim($word);
21821 $wordwidth = $this->GetStringWidth($word, false, false, $chunk[8]); // Pass $textvar ($chunk[8]), but do OTLdata here
21822 // so don't have to split OTLdata for each word
21823 if (isset($wordXAdvance[$k])) {
21824 $wordwidth += ($wordXAdvance[$k] * 1000 / $this->CurrentFont['unitsPerEm']) * ($this->FontSize / 1000);
21825 }
21826 if ($k == 0) {
21827 $wordwidth += $lbw;
21828 }
21829 if ($k == (count($words) - 1)) {
21830 $wordwidth += $rbw;
21831 }
21832
21833 // mPDF 6
21834 if (count($words) == 1 && substr($chunk[0], 0, 1) != ' ') {
21835 $acclength += $wordwidth;
21836 } elseif (count($words) > 1 && $k == 0 && substr($chunk[0], 0, 1) != ' ') {
21837 $acclength += $wordwidth;
21838 } else {
21839 $acclength = $wordwidth;
21840 }
21841 $acclongest = max($acclongest, $acclength);
21842 if (count($words) == 1 && substr($chunk[0], -1, 1) == ' ') {
21843 $acclength = 0;
21844 } elseif (count($words) > 1 && ($k != (count($words) - 1) || substr($chunk[0], -1, 1) == ' ')) {
21845 $acclength = 0;
21846 }
21847
21848 //Warn user that maxwidth is insufficient
21849 if ($wordwidth > $maxwidth + 0.0001) {
21850 if ($wordwidth > $biggestword) {
21851 $biggestword = $wordwidth;
21852 }
21853 $toonarrow = true;
21854 }
21855 }
21856 }
21857
21858 // mPDF 6 Accumulated length of biggest word - across multiple chunks
21859 if ($acclongest > $maxwidth + 0.0001) {
21860 if ($acclongest > $biggestword) {
21861 $biggestword = $acclongest;
21862 }
21863 $toonarrow = true;
21864 }
21865
21866 // RESET FONT SIZE/STYLE
21867 // RESETTING VALUES
21868 //Now we must deactivate what we have used
21869 if (isset($chunk[2]) and $chunk[2] != '') {
21870 $this->ResetStyles();
21871 }
21872 if (isset($chunk[4]) and $chunk[4] != '') {
21873 $this->SetFont($this->default_font, $this->FontStyle, 0, false);
21874 }
21875 if (isset($chunk[11]) and $chunk[11] != '') {
21876 $this->SetFontSize($this->default_font_size, false);
21877 }
21878 $this->spanborddet = array();
21879 $this->textvar = 0x00; // mPDF 5.7.1
21880 $this->OTLtags = array();
21881 $this->lSpacingCSS = '';
21882 $this->wSpacingCSS = '';
21883 $this->fixedlSpacing = false;
21884 $this->minwSpacing = 0;
21885 }
21886
21887 //Return -(wordsize) if word is bigger than maxwidth
21888 // ADDED
21889 if (($toonarrow) && ($this->table_error_report)) {
21890 throw new MpdfException("Word is too long to fit in table - " . $this->table_error_report_param);
21891 }
21892 if ($toonarrow)
21893 return -$biggestword;
21894 else
21895 return 1;
21896 }
21897
21898 function shrinkTable(&$table, $k)
21899 {
21900 $table['border_spacing_H'] /= $k;
21901 $table['border_spacing_V'] /= $k;
21902
21903 $table['padding']['T'] /= $k;
21904 $table['padding']['R'] /= $k;
21905 $table['padding']['B'] /= $k;
21906 $table['padding']['L'] /= $k;
21907
21908 $table['margin']['T'] /= $k;
21909 $table['margin']['R'] /= $k;
21910 $table['margin']['B'] /= $k;
21911 $table['margin']['L'] /= $k;
21912
21913 $table['border_details']['T']['w'] /= $k;
21914 $table['border_details']['R']['w'] /= $k;
21915 $table['border_details']['B']['w'] /= $k;
21916 $table['border_details']['L']['w'] /= $k;
21917
21918 if (isset($table['max_cell_border_width']['T']))
21919 $table['max_cell_border_width']['T'] /= $k;
21920 if (isset($table['max_cell_border_width']['R']))
21921 $table['max_cell_border_width']['R'] /= $k;
21922 if (isset($table['max_cell_border_width']['B']))
21923 $table['max_cell_border_width']['B'] /= $k;
21924 if (isset($table['max_cell_border_width']['L']))
21925 $table['max_cell_border_width']['L'] /= $k;
21926
21927 if ($this->simpleTables) {
21928 $table['simple']['border_details']['T']['w'] /= $k;
21929 $table['simple']['border_details']['R']['w'] /= $k;
21930 $table['simple']['border_details']['B']['w'] /= $k;
21931 $table['simple']['border_details']['L']['w'] /= $k;
21932 }
21933
21934 $table['miw'] /= $k;
21935 $table['maw'] /= $k;
21936
21937 for ($j = 0; $j < $table['nc']; $j++) { //columns
21938 $table['wc'][$j]['miw'] /= $k;
21939 $table['wc'][$j]['maw'] /= $k;
21940
21941 if (isset($table['decimal_align'][$j]['maxs0']) && $table['decimal_align'][$j]['maxs0']) {
21942 $table['decimal_align'][$j]['maxs0'] /= $k;
21943 }
21944 if (isset($table['decimal_align'][$j]['maxs1']) && $table['decimal_align'][$j]['maxs1']) {
21945 $table['decimal_align'][$j]['maxs1'] /= $k;
21946 }
21947
21948 if (isset($table['wc'][$j]['absmiw']) && $table['wc'][$j]['absmiw'])
21949 $table['wc'][$j]['absmiw'] /= $k;
21950
21951 for ($i = 0; $i < $table['nr']; $i++) { //rows
21952 $c = &$table['cells'][$i][$j];
21953 if (isset($c) && $c) {
21954 if (!$this->simpleTables) {
21955 if ($this->packTableData) {
21956 $cell = $this->_unpackCellBorder($c['borderbin']);
21957 $cell['border_details']['T']['w'] /= $k;
21958 $cell['border_details']['R']['w'] /= $k;
21959 $cell['border_details']['B']['w'] /= $k;
21960 $cell['border_details']['L']['w'] /= $k;
21961 $cell['border_details']['mbw']['TL'] /= $k;
21962 $cell['border_details']['mbw']['TR'] /= $k;
21963 $cell['border_details']['mbw']['BL'] /= $k;
21964 $cell['border_details']['mbw']['BR'] /= $k;
21965 $cell['border_details']['mbw']['LT'] /= $k;
21966 $cell['border_details']['mbw']['LB'] /= $k;
21967 $cell['border_details']['mbw']['RT'] /= $k;
21968 $cell['border_details']['mbw']['RB'] /= $k;
21969 $c['borderbin'] = $this->_packCellBorder($cell);
21970 } else {
21971 $c['border_details']['T']['w'] /= $k;
21972 $c['border_details']['R']['w'] /= $k;
21973 $c['border_details']['B']['w'] /= $k;
21974 $c['border_details']['L']['w'] /= $k;
21975 $c['border_details']['mbw']['TL'] /= $k;
21976 $c['border_details']['mbw']['TR'] /= $k;
21977 $c['border_details']['mbw']['BL'] /= $k;
21978 $c['border_details']['mbw']['BR'] /= $k;
21979 $c['border_details']['mbw']['LT'] /= $k;
21980 $c['border_details']['mbw']['LB'] /= $k;
21981 $c['border_details']['mbw']['RT'] /= $k;
21982 $c['border_details']['mbw']['RB'] /= $k;
21983 }
21984 }
21985 $c['padding']['T'] /= $k;
21986 $c['padding']['R'] /= $k;
21987 $c['padding']['B'] /= $k;
21988 $c['padding']['L'] /= $k;
21989 if (isset($c['maxs'])) {
21990 $c['maxs'] /= $k;
21991 }
21992 if (isset($c['w'])) {
21993 $c['w'] /= $k;
21994 }
21995 $c['s'] /= $k;
21996 $c['maw'] /= $k;
21997 $c['miw'] /= $k;
21998 if (isset($c['h'])) {
21999 $c['h'] /= $k;
22000 } // mPDF 5.7.4
22001 if (isset($c['absmiw']))
22002 $c['absmiw'] /= $k;
22003 if (isset($c['nestedmaw']))
22004 $c['nestedmaw'] /= $k;
22005 if (isset($c['nestedmiw']))
22006 $c['nestedmiw'] /= $k;
22007 if (isset($c['textbuffer'])) {
22008 foreach ($c['textbuffer'] AS $n => $tb) {
22009 if (!empty($tb[16])) {
22010 $c['textbuffer'][$n][16]['T']['w'] /= $k;
22011 $c['textbuffer'][$n][16]['B']['w'] /= $k;
22012 $c['textbuffer'][$n][16]['L']['w'] /= $k;
22013 $c['textbuffer'][$n][16]['R']['w'] /= $k;
22014 }
22015 }
22016 }
22017 unset($c);
22018 }
22019 }//rows
22020 }//columns
22021 }
22022
22023 function read_short(&$fh)
22024 {
22025 $s = fread($fh, 2);
22026 $a = (ord($s[0]) << 8) + ord($s[1]);
22027 if ($a & (1 << 15)) {
22028 $a = ($a - (1 << 16));
22029 }
22030 return $a;
22031 }
22032
22033 function _packCellBorder($cell)
22034 {
22035 if (!is_array($cell) || !isset($cell)) {
22036 return '';
22037 }
22038
22039 if (!$this->packTableData) {
22040 return $cell;
22041 }
22042 // = 186 bytes
22043 $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)
22044 );
22045 return $bindata;
22046 }
22047
22048 function _getBorderWidths($bindata)
22049 {
22050 if (!$bindata) {
22051 return array(0, 0, 0, 0);
22052 }
22053 if (!$this->packTableData) {
22054 return array($bindata['border_details']['T']['w'], $bindata['border_details']['R']['w'], $bindata['border_details']['B']['w'], $bindata['border_details']['L']['w']);
22055 }
22056
22057 $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);
22058 $cell['border_details']['R']['w'] = $bd['rw'];
22059 $cell['border_details']['L']['w'] = $bd['lw'];
22060 $cell['border_details']['T']['w'] = $bd['tw'];
22061 $cell['border_details']['B']['w'] = $bd['bw'];
22062 return array($bd['tw'], $bd['rw'], $bd['bw'], $bd['lw']);
22063 }
22064
22065 function _unpackCellBorder($bindata)
22066 {
22067 if (!$bindata) {
22068 return array();
22069 }
22070 if (!$this->packTableData) {
22071 return $bindata;
22072 }
22073
22074 $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);
22075
22076 $cell['border'] = $bd['bord'];
22077 $cell['border_details']['R']['s'] = $bd['rs'];
22078 $cell['border_details']['R']['w'] = $bd['rw'];
22079 $cell['border_details']['R']['c'] = str_pad($bd['rca'], 6, "\x00");
22080 $cell['border_details']['R']['style'] = trim($bd['rst']);
22081 $cell['border_details']['R']['dom'] = $bd['rd'];
22082
22083 $cell['border_details']['L']['s'] = $bd['ls'];
22084 $cell['border_details']['L']['w'] = $bd['lw'];
22085 $cell['border_details']['L']['c'] = str_pad($bd['lca'], 6, "\x00");
22086 $cell['border_details']['L']['style'] = trim($bd['lst']);
22087 $cell['border_details']['L']['dom'] = $bd['ld'];
22088
22089 $cell['border_details']['T']['s'] = $bd['ts'];
22090 $cell['border_details']['T']['w'] = $bd['tw'];
22091 $cell['border_details']['T']['c'] = str_pad($bd['tca'], 6, "\x00");
22092 $cell['border_details']['T']['style'] = trim($bd['tst']);
22093 $cell['border_details']['T']['dom'] = $bd['td'];
22094
22095 $cell['border_details']['B']['s'] = $bd['bs'];
22096 $cell['border_details']['B']['w'] = $bd['bw'];
22097 $cell['border_details']['B']['c'] = str_pad($bd['bca'], 6, "\x00");
22098 $cell['border_details']['B']['style'] = trim($bd['bst']);
22099 $cell['border_details']['B']['dom'] = $bd['bd'];
22100
22101 $cell['border_details']['mbw']['BL'] = $bd['mbl'];
22102 $cell['border_details']['mbw']['BR'] = $bd['mbr'];
22103 $cell['border_details']['mbw']['RT'] = $bd['mrt'];
22104 $cell['border_details']['mbw']['RB'] = $bd['mrb'];
22105 $cell['border_details']['mbw']['TL'] = $bd['mtl'];
22106 $cell['border_details']['mbw']['TR'] = $bd['mtr'];
22107 $cell['border_details']['mbw']['LT'] = $bd['mlt'];
22108 $cell['border_details']['mbw']['LB'] = $bd['mlb'];
22109 $cell['border_details']['cellposdom'] = $bd['cpd'];
22110
22111
22112 return($cell);
22113 }
22114
22115 ////////////////////////TABLE CODE (from PDFTable)/////////////////////////////////////
22116 ////////////////////////TABLE CODE (from PDFTable)/////////////////////////////////////
22117 ////////////////////////TABLE CODE (from PDFTable)/////////////////////////////////////
22118 //table Array of (w, h, bc, nr, wc, hr, cells)
22119 //w Width of table
22120 //h Height of table
22121 //nc Number column
22122 //nr Number row
22123 //hr List of height of each row
22124 //wc List of width of each column
22125 //cells List of cells of each rows, cells[i][j] is a cell in the table
22126 function _tableColumnWidth(&$table, $firstpass = false)
22127 {
22128 $cs = &$table['cells'];
22129
22130 $nc = $table['nc'];
22131 $nr = $table['nr'];
22132 $listspan = array();
22133
22134 if ($table['borders_separate']) {
22135 $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'];
22136 } else {
22137 $tblbw = $table['max_cell_border_width']['L'] / 2 + $table['max_cell_border_width']['R'] / 2 + $table['margin']['L'] + $table['margin']['R'];
22138 }
22139
22140 // ADDED table['l'][colno]
22141 // = total length of text approx (using $c['s']) in that column - used to approximately distribute col widths in _tableWidth
22142 //
22143 for ($j = 0; $j < $nc; $j++) { //columns
22144 $wc = &$table['wc'][$j];
22145 for ($i = 0; $i < $nr; $i++) { //rows
22146 if (isset($cs[$i][$j]) && $cs[$i][$j]) {
22147 $c = &$cs[$i][$j];
22148
22149 if ($this->simpleTables) {
22150 if ($table['borders_separate']) { // NB twice border width
22151 $extrcw = $table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w'] + $c['padding']['L'] + $c['padding']['R'] + $table['border_spacing_H'];
22152 } else {
22153 $extrcw = $table['simple']['border_details']['L']['w'] / 2 + $table['simple']['border_details']['R']['w'] / 2 + $c['padding']['L'] + $c['padding']['R'];
22154 }
22155 } else {
22156 if ($this->packTableData) {
22157 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($c['borderbin']);
22158 } else {
22159 $br = $c['border_details']['R']['w'];
22160 $bl = $c['border_details']['L']['w'];
22161 }
22162 if ($table['borders_separate']) { // NB twice border width
22163 $extrcw = $bl + $br + $c['padding']['L'] + $c['padding']['R'] + $table['border_spacing_H'];
22164 } else {
22165 $extrcw = $bl / 2 + $br / 2 + $c['padding']['L'] + $c['padding']['R'];
22166 }
22167 }
22168
22169 //$mw = $this->GetStringWidth('W') + $extrcw ;
22170 $mw = $extrcw; // mPDF 6
22171 if (substr($c['a'], 0, 1) == 'D') {
22172 $mw = $table['decimal_align'][$j]['maxs0'] + $table['decimal_align'][$j]['maxs1'] + $extrcw;
22173 }
22174
22175 $c['absmiw'] = $mw;
22176
22177 if (isset($c['R']) && $c['R']) {
22178 $c['maw'] = $c['miw'] = $this->FontSize + $extrcw;
22179 if (isset($c['w'])) { // If cell width is specified
22180 if ($c['miw'] < $c['w']) {
22181 $c['miw'] = $c['w'];
22182 }
22183 }
22184 if (!isset($c['colspan'])) {
22185 if ($wc['miw'] < $c['miw']) {
22186 $wc['miw'] = $c['miw'];
22187 }
22188 if ($wc['maw'] < $c['maw']) {
22189 $wc['maw'] = $c['maw'];
22190 }
22191
22192 if ($firstpass) {
22193 if (isset($table['l'][$j])) {
22194 $table['l'][$j] += $c['miw'];
22195 } else {
22196 $table['l'][$j] = $c['miw'];
22197 }
22198 }
22199 }
22200 if ($c['miw'] > $wc['miw']) {
22201 $wc['miw'] = $c['miw'];
22202 }
22203 if ($wc['miw'] > $wc['maw']) {
22204 $wc['maw'] = $wc['miw'];
22205 }
22206 continue;
22207 }
22208
22209 if ($firstpass) {
22210 if (isset($c['s'])) {
22211 $c['s'] += $extrcw;
22212 }
22213 if (isset($c['maxs'])) {
22214 $c['maxs'] += $extrcw;
22215 }
22216 if (isset($c['nestedmiw'])) {
22217 $c['nestedmiw'] += $extrcw;
22218 }
22219 if (isset($c['nestedmaw'])) {
22220 $c['nestedmaw'] += $extrcw;
22221 }
22222 }
22223
22224
22225 // If minimum width has already been set by a nested table or inline object (image/form), use it
22226 if (isset($c['nestedmiw']) && (!isset($this->table[1][1]['overflow']) || $this->table[1][1]['overflow'] != 'visible')) {
22227 $miw = $c['nestedmiw'];
22228 } else {
22229 $miw = $mw;
22230 }
22231
22232 if (isset($c['maxs']) && $c['maxs'] != '') {
22233 $c['s'] = $c['maxs'];
22234 }
22235
22236 // If maximum width has already been set by a nested table, use it
22237 if (isset($c['nestedmaw'])) {
22238 $c['maw'] = $c['nestedmaw'];
22239 } else
22240 $c['maw'] = $c['s'];
22241
22242 if (isset($table['overflow']) && $table['overflow'] == 'visible' && $table['level'] == 1) {
22243 if (($c['maw'] + $tblbw) > $this->blk[$this->blklvl]['inner_width']) {
22244 $c['maw'] = $this->blk[$this->blklvl]['inner_width'] - $tblbw;
22245 }
22246 }
22247
22248 if (isset($c['nowrap']) && $c['nowrap']) {
22249 $miw = $c['maw'];
22250 }
22251
22252 if (isset($c['wpercent']) && $firstpass) {
22253 if (isset($c['colspan'])) { // Not perfect - but % set on colspan is shared equally on cols.
22254 for ($k = 0; $k < $c['colspan']; $k++) {
22255 $table['wc'][($j + $k)]['wpercent'] = $c['wpercent'] / $c['colspan'];
22256 }
22257 } else {
22258 if (isset($table['w']) && $table['w']) {
22259 $c['w'] = $c['wpercent'] / 100 * ($table['w'] - $tblbw );
22260 }
22261 $wc['wpercent'] = $c['wpercent'];
22262 }
22263 }
22264
22265 if (isset($table['overflow']) && $table['overflow'] == 'visible' && $table['level'] == 1) {
22266 if (isset($c['w']) && ($c['w'] + $tblbw) > $this->blk[$this->blklvl]['inner_width']) {
22267 $c['w'] = $this->blk[$this->blklvl]['inner_width'] - $tblbw;
22268 }
22269 }
22270
22271
22272 if (isset($c['w'])) { // If cell width is specified
22273 if ($miw < $c['w']) {
22274 $c['miw'] = $c['w'];
22275 } // Cell min width = that specified
22276 if ($miw > $c['w']) {
22277 $c['miw'] = $c['w'] = $miw;
22278 } // If width specified is less than minimum allowed (W) increase it
22279 // mPDF 5.7.4 Do not set column width in colspan
22280 // cf. http://www.mpdf1.com/forum/discussion/2221/colspan-bug
22281 if (!isset($c['colspan'])) {
22282 if (!isset($wc['w'])) {
22283 $wc['w'] = 1;
22284 } // If the Col width is not specified = set it to 1
22285 }
22286 // mPDF 5.7.3 cf. http://www.mpdf1.com/forum/discussion/1648/nested-table-bug-
22287 $c['maw'] = $c['w'];
22288 } else {
22289 $c['miw'] = $miw;
22290 } // If cell width not specified -> set Cell min width it to minimum allowed (W)
22291
22292 if (isset($c['miw']) && $c['maw'] < $c['miw']) {
22293 $c['maw'] = $c['miw'];
22294 } // If Cell max width < Minwidth - increase it to =
22295 if (!isset($c['colspan'])) {
22296 if (isset($c['miw']) && $wc['miw'] < $c['miw']) {
22297 $wc['miw'] = $c['miw'];
22298 } // Update Col Minimum and maximum widths
22299 if ($wc['maw'] < $c['maw']) {
22300 $wc['maw'] = $c['maw'];
22301 }
22302 if ((isset($wc['absmiw']) && $wc['absmiw'] < $c['absmiw']) || !isset($wc['absmiw'])) {
22303 $wc['absmiw'] = $c['absmiw'];
22304 } // Update Col Minimum and maximum widths
22305
22306 if (isset($table['l'][$j])) {
22307 $table['l'][$j] += $c['s'];
22308 } else {
22309 $table['l'][$j] = $c['s'];
22310 }
22311 } else {
22312 $listspan[] = array($i, $j);
22313 }
22314
22315 //Check if minimum width of the whole column is big enough for largest word to fit
22316 // mPDF 6
22317 if (isset($c['textbuffer'])) {
22318 if (isset($table['overflow']) && $table['overflow'] == 'wrap') {
22319 $letter = true;
22320 } // check for maximum width of letters
22321 else {
22322 $letter = false;
22323 }
22324 $minwidth = $this->TableCheckMinWidth($wc['miw'] - $extrcw, 0, $c['textbuffer'], $letter);
22325 } else {
22326 $minwidth = 0;
22327 }
22328 if ($minwidth < 0) {
22329 //increase minimum width
22330 if (!isset($c['colspan'])) {
22331 $wc['miw'] = max($wc['miw'], ((-$minwidth) + $extrcw));
22332 } else {
22333 $c['miw'] = max($c['miw'], ((-$minwidth) + $extrcw));
22334 }
22335 }
22336 if (!isset($c['colspan'])) {
22337 if ($wc['miw'] > $wc['maw']) {
22338 $wc['maw'] = $wc['miw'];
22339 } //update maximum width, if needed
22340 }
22341 }
22342 unset($c);
22343 }//rows
22344 }//columns
22345 // COLUMN SPANS
22346 $wc = &$table['wc'];
22347 foreach ($listspan as $span) {
22348 list($i, $j) = $span;
22349 $c = &$cs[$i][$j];
22350 $lc = $j + $c['colspan'];
22351 if ($lc > $nc) {
22352 $lc = $nc;
22353 }
22354 $wis = $wisa = 0;
22355 $was = $wasa = 0;
22356 $list = array();
22357 for ($k = $j; $k < $lc; $k++) {
22358 if (isset($table['l'][$k])) {
22359 if ($c['R']) {
22360 $table['l'][$k] += $c['miw'] / $c['colspan'];
22361 } else {
22362 $table['l'][$k] += $c['s'] / $c['colspan'];
22363 }
22364 } else {
22365 if ($c['R']) {
22366 $table['l'][$k] = $c['miw'] / $c['colspan'];
22367 } else {
22368 $table['l'][$k] = $c['s'] / $c['colspan'];
22369 }
22370 }
22371 $wis += $wc[$k]['miw']; // $wis is the sum of the column miw in the colspan
22372 $was += $wc[$k]['maw']; // $was is the sum of the column maw in the colspan
22373 if (!isset($c['w'])) {
22374 $list[] = $k;
22375 $wisa += $wc[$k]['miw']; // $wisa is the sum of the column miw in cells with no width specified in the colspan
22376 $wasa += $wc[$k]['maw']; // $wasa is the sum of the column maw in cells with no width specified in the colspan
22377 }
22378 }
22379 if ($c['miw'] > $wis) {
22380 if (!$wis) {
22381 for ($k = $j; $k < $lc; $k++) {
22382 $wc[$k]['miw'] = $c['miw'] / $c['colspan'];
22383 }
22384 } elseif (!count($list)) {
22385 $wi = $c['miw'] - $wis;
22386 for ($k = $j; $k < $lc; $k++) {
22387 $wc[$k]['miw'] += ($wc[$k]['miw'] / $wis) * $wi;
22388 }
22389 } else {
22390 $wi = $c['miw'] - $wis;
22391 // mPDF 5.7.2 Extra min width distributed proportionately to all cells in colspan without a specified width
22392 // cf. http://www.mpdf1.com/forum/discussion/1607#Item_4
22393 foreach ($list as $k) {
22394 if (!isset($wc[$k]['w']) || !$wc[$k]['w'])
22395 $wc[$k]['miw'] += ($wc[$k]['miw'] / $wisa) * $wi;
22396 } // mPDF 5.7.2
22397 }
22398 }
22399 if ($c['maw'] > $was) {
22400 if (!$wis) {
22401 for ($k = $j; $k < $lc; $k++) {
22402 $wc[$k]['maw'] = $c['maw'] / $c['colspan'];
22403 }
22404 } elseif (!count($list)) {
22405 $wi = $c['maw'] - $was;
22406 for ($k = $j; $k < $lc; $k++) {
22407 $wc[$k]['maw'] += ($wc[$k]['maw'] / $was) * $wi;
22408 }
22409 } else {
22410 $wi = $c['maw'] - $was;
22411 // mPDF 5.7.4 Extra max width distributed evenly to all cells in colspan without a specified width
22412 // cf. http://www.mpdf1.com/forum/discussion/2221/colspan-bug
22413 foreach ($list as $k) {
22414 $wc[$k]['maw'] += $wi / count($list);
22415 }
22416 }
22417 }
22418 unset($c);
22419 }
22420
22421 $checkminwidth = 0;
22422 $checkmaxwidth = 0;
22423 $totallength = 0;
22424
22425 for ($i = 0; $i < $nc; $i++) {
22426 $checkminwidth += $table['wc'][$i]['miw'];
22427 $checkmaxwidth += $table['wc'][$i]['maw'];
22428 $totallength += $table['l'][$i];
22429 }
22430
22431 if (!isset($table['w']) && $firstpass) {
22432 $sumpc = 0;
22433 $notset = 0;
22434 for ($i = 0; $i < $nc; $i++) {
22435 if (isset($table['wc'][$i]['wpercent']) && $table['wc'][$i]['wpercent']) {
22436 $sumpc += $table['wc'][$i]['wpercent'];
22437 } else {
22438 $notset++;
22439 }
22440 }
22441
22442 // If sum of widths as % >= 100% and not all columns are set
22443 // Set a nominal width of 1% for unset columns
22444 if ($sumpc >= 100 && $notset) {
22445 for ($i = 0; $i < $nc; $i++) {
22446 if ((!isset($table['wc'][$i]['wpercent']) || !$table['wc'][$i]['wpercent']) &&
22447 (!isset($table['wc'][$i]['w']) || !$table['wc'][$i]['w'])) {
22448 $table['wc'][$i]['wpercent'] = 1;
22449 }
22450 }
22451 }
22452
22453
22454 if ($sumpc) { // if any percents are set
22455 $sumnonpc = (100 - $sumpc);
22456 $sumpc = max($sumpc, 100);
22457 $miwleft = 0;
22458 $miwleftcount = 0;
22459 $miwsurplusnonpc = 0;
22460 $maxcalcmiw = 0;
22461 $mawleft = 0;
22462 $mawleftcount = 0;
22463 $mawsurplusnonpc = 0;
22464 $maxcalcmaw = 0;
22465 $mawnon = 0;
22466 $miwnon = 0;
22467 for ($i = 0; $i < $nc; $i++) {
22468 if (isset($table['wc'][$i]['wpercent'])) {
22469 $maxcalcmiw = max($maxcalcmiw, ($table['wc'][$i]['miw'] * $sumpc / $table['wc'][$i]['wpercent']));
22470 $maxcalcmaw = max($maxcalcmaw, ($table['wc'][$i]['maw'] * $sumpc / $table['wc'][$i]['wpercent']));
22471 } else {
22472 $miwleft += $table['wc'][$i]['miw'];
22473 $mawleft += $table['wc'][$i]['maw'];
22474 if (!isset($table['wc'][$i]['w'])) {
22475 $miwleftcount++;
22476 $mawleftcount++;
22477 }
22478 }
22479 }
22480 if ($miwleft && $sumnonpc > 0) {
22481 $miwnon = $miwleft * 100 / $sumnonpc;
22482 }
22483 if ($mawleft && $sumnonpc > 0) {
22484 $mawnon = $mawleft * 100 / $sumnonpc;
22485 }
22486 if (($miwnon > $checkminwidth || $maxcalcmiw > $checkminwidth) && $this->keep_table_proportions) {
22487 if ($miwnon > $maxcalcmiw) {
22488 $miwsurplusnonpc = round((($miwnon * $sumnonpc / 100) - $miwleft), 3);
22489 $checkminwidth = $miwnon;
22490 } else {
22491 $checkminwidth = $maxcalcmiw;
22492 }
22493 for ($i = 0; $i < $nc; $i++) {
22494 if (isset($table['wc'][$i]['wpercent'])) {
22495 $newmiw = $checkminwidth * $table['wc'][$i]['wpercent'] / 100;
22496 if ($table['wc'][$i]['miw'] < $newmiw) {
22497 $table['wc'][$i]['miw'] = $newmiw;
22498 }
22499 $table['wc'][$i]['w'] = 1;
22500 } elseif ($miwsurplusnonpc && !$table['wc'][$i]['w']) {
22501 $table['wc'][$i]['miw'] += $miwsurplusnonpc / $miwleftcount;
22502 }
22503 }
22504 }
22505 if (($mawnon > $checkmaxwidth || $maxcalcmaw > $checkmaxwidth)) {
22506 if ($mawnon > $maxcalcmaw) {
22507 $mawsurplusnonpc = round((($mawnon * $sumnonpc / 100) - $mawleft), 3);
22508 $checkmaxwidth = $mawnon;
22509 } else {
22510 $checkmaxwidth = $maxcalcmaw;
22511 }
22512 for ($i = 0; $i < $nc; $i++) {
22513 if (isset($table['wc'][$i]['wpercent'])) {
22514 $newmaw = $checkmaxwidth * $table['wc'][$i]['wpercent'] / 100;
22515 if ($table['wc'][$i]['maw'] < $newmaw) {
22516 $table['wc'][$i]['maw'] = $newmaw;
22517 }
22518 $table['wc'][$i]['w'] = 1;
22519 } elseif ($mawsurplusnonpc && !$table['wc'][$i]['w']) {
22520 $table['wc'][$i]['maw'] += $mawsurplusnonpc / $mawleftcount;
22521 }
22522 if ($table['wc'][$i]['maw'] < $table['wc'][$i]['miw']) {
22523 $table['wc'][$i]['maw'] = $table['wc'][$i]['miw'];
22524 }
22525 }
22526 }
22527 if ($checkminwidth > $checkmaxwidth) {
22528 $checkmaxwidth = $checkminwidth;
22529 }
22530 }
22531 }
22532
22533 if (isset($table['wpercent']) && $table['wpercent']) {
22534 $checkminwidth *= (100 / $table['wpercent']);
22535 $checkmaxwidth *= (100 / $table['wpercent']);
22536 }
22537
22538
22539 $checkminwidth += $tblbw;
22540 $checkmaxwidth += $tblbw;
22541
22542 // Table['miw'] set by percent in first pass may be larger than sum of column miw
22543 if ((isset($table['miw']) && $checkminwidth > $table['miw']) || !isset($table['miw'])) {
22544 $table['miw'] = $checkminwidth;
22545 }
22546 if ((isset($table['maw']) && $checkmaxwidth > $table['maw']) || !isset($table['maw'])) {
22547 $table['maw'] = $checkmaxwidth;
22548 }
22549 $table['tl'] = $totallength;
22550
22551
22552 // mPDF 6
22553 if ($this->table_rotate) {
22554 $mxw = $this->tbrot_maxw;
22555 } else {
22556 $mxw = $this->blk[$this->blklvl]['inner_width'];
22557 }
22558 if (!isset($table['overflow'])) {
22559 $table['overflow'] = null;
22560 }
22561 if ($table['overflow'] == 'visible') {
22562 return array(0, 0);
22563 } elseif ($table['overflow'] == 'hidden' && !$this->table_rotate && !$this->ColActive && $checkminwidth > $mxw) {
22564 $table['w'] = $table['miw'];
22565 return array(0, 0);
22566 }
22567 //elseif ($table['overflow']=='wrap') { return array(0,0); } // mPDF 6
22568
22569 if (isset($table['w']) && $table['w']) {
22570 if ($table['w'] >= $checkminwidth && $table['w'] <= $mxw) {
22571 $table['maw'] = $mxw = $table['w'];
22572 } elseif ($table['w'] >= $checkminwidth && $table['w'] > $mxw && $this->keep_table_proportions) {
22573 $checkminwidth = $table['w'];
22574 } elseif ($table['w'] < $checkminwidth && $checkminwidth < $mxw && $this->keep_table_proportions) {
22575 $table['maw'] = $table['w'] = $checkminwidth;
22576 } // mPDF 5.7.4
22577 else {
22578 unset($table['w']);
22579 }
22580 }
22581 $ratio = $checkminwidth / $mxw;
22582 if ($checkminwidth > $mxw) {
22583 return array(($ratio + 0.001), $checkminwidth);
22584 } // 0.001 to allow for rounded numbers when resizing
22585 unset($cs);
22586 return array(0, 0);
22587 }
22588
22589 function _tableWidth(&$table)
22590 {
22591 $widthcols = &$table['wc'];
22592 $numcols = $table['nc'];
22593 $tablewidth = 0;
22594 if ($table['borders_separate']) {
22595 $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'];
22596 } else {
22597 $tblbw = $table['max_cell_border_width']['L'] / 2 + $table['max_cell_border_width']['R'] / 2 + $table['margin']['L'] + $table['margin']['R'];
22598 }
22599
22600 if ($table['level'] > 1 && isset($table['w'])) {
22601 if (isset($table['wpercent']) && $table['wpercent']) {
22602 $table['w'] = $temppgwidth = (($table['w'] - $tblbw) * $table['wpercent'] / 100) + $tblbw;
22603 } else {
22604 $temppgwidth = $table['w'];
22605 }
22606 } elseif ($this->table_rotate) {
22607 $temppgwidth = $this->tbrot_maxw;
22608 // If it is less than 1/20th of the remaining page height to finish the DIV (i.e. DIV padding + table bottom margin)
22609 // then allow for this
22610 $enddiv = $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'];
22611 if ($enddiv / $temppgwidth < 0.05) {
22612 $temppgwidth -= $enddiv;
22613 }
22614 } else {
22615 if (isset($table['w']) && $table['w'] < $this->blk[$this->blklvl]['inner_width']) {
22616 $notfullwidth = 1;
22617 $temppgwidth = $table['w'];
22618 } elseif ($table['overflow'] == 'visible' && $table['level'] == 1) {
22619 $temppgwidth = null;
22620 } elseif ($table['overflow'] == 'hidden' && !$this->ColActive && isset($table['w']) && $table['w'] > $this->blk[$this->blklvl]['inner_width'] && $table['w'] == $table['miw']) {
22621 //$temppgwidth = $this->blk[$this->blklvl]['inner_width'];
22622 $temppgwidth = $table['w'];
22623 } else {
22624 $temppgwidth = $this->blk[$this->blklvl]['inner_width'];
22625 }
22626 }
22627
22628
22629 $totaltextlength = 0; // Added - to sum $table['l'][colno]
22630 $totalatextlength = 0; // Added - to sum $table['l'][colno] for those columns where width not set
22631 $percentages_set = 0;
22632 for ($i = 0; $i < $numcols; $i++) {
22633 if (isset($widthcols[$i]['wpercent'])) {
22634 $tablewidth += $widthcols[$i]['maw'];
22635 $percentages_set = 1;
22636 } elseif (isset($widthcols[$i]['w'])) {
22637 $tablewidth += $widthcols[$i]['miw'];
22638 } else {
22639 $tablewidth += $widthcols[$i]['maw'];
22640 }
22641 $totaltextlength += $table['l'][$i];
22642 }
22643 if (!$totaltextlength) {
22644 $totaltextlength = 1;
22645 }
22646 $tablewidth += $tblbw; // Outer half of table borders
22647
22648 if ($tablewidth > $temppgwidth) {
22649 $table['w'] = $temppgwidth;
22650 }
22651 // if any widths set as percentages and max width fits < page width
22652 elseif ($tablewidth < $temppgwidth && !isset($table['w']) && $percentages_set) {
22653 $table['w'] = $table['maw'];
22654 }
22655 // if table width is set and is > allowed width
22656 if (isset($table['w']) && $table['w'] > $temppgwidth) {
22657 $table['w'] = $temppgwidth;
22658 }
22659
22660 // IF the table width is now set - Need to distribute columns widths
22661 // mPDF 5.7.3
22662 // If the table width is already set to the maximum width (e.g. nested table), then use maximum column widths exactly
22663 if (isset($table['w']) && ($table['w'] == $tablewidth) && !$percentages_set) {
22664 // This sets the columns all to maximum width
22665 for ($i = 0; $i < $numcols; $i++) {
22666 $widthcols[$i] = $widthcols[$i]['maw'];
22667 }
22668 }
22669 // elseif the table width is set distribute width using algorithm
22670 elseif (isset($table['w'])) {
22671 $wis = $wisa = 0;
22672 $list = array();
22673 $notsetlist = array();
22674 for ($i = 0; $i < $numcols; $i++) {
22675 $wis += $widthcols[$i]['miw'];
22676 if (!isset($widthcols[$i]['w']) || ($widthcols[$i]['w'] && $table['w'] > $temppgwidth && !$this->keep_table_proportions && !$notfullwidth )) {
22677 $list[] = $i;
22678 $wisa += $widthcols[$i]['miw'];
22679 $totalatextlength += $table['l'][$i];
22680 }
22681 }
22682 if (!$totalatextlength) {
22683 $totalatextlength = 1;
22684 }
22685
22686 // Allocate spare (more than col's minimum width) across the cols according to their approx total text length
22687 // Do it by setting minimum width here
22688 if ($table['w'] > $wis + $tblbw) {
22689 // First set any cell widths set as percentages
22690 if ($table['w'] < $temppgwidth || $this->keep_table_proportions) {
22691 for ($k = 0; $k < $numcols; $k++) {
22692 if (isset($widthcols[$k]['wpercent'])) {
22693 $curr = $widthcols[$k]['miw'];
22694 $widthcols[$k]['miw'] = ($table['w'] - $tblbw) * $widthcols[$k]['wpercent'] / 100;
22695 $wis += $widthcols[$k]['miw'] - $curr;
22696 $wisa += $widthcols[$k]['miw'] - $curr;
22697 }
22698 }
22699 }
22700 // Now allocate surplus up to maximum width of each column
22701 $surplus = 0;
22702 $ttl = 0; // number of surplus columns
22703 if (!count($list)) {
22704 $wi = ($table['w'] - ($wis + $tblbw)); // i.e. extra space to distribute
22705 for ($k = 0; $k < $numcols; $k++) {
22706 $spareratio = ($table['l'][$k] / $totaltextlength); // gives ratio to divide up free space
22707 // Don't allocate more than Maximum required width - save rest in surplus
22708 if ($widthcols[$k]['miw'] + ($wi * $spareratio) >= $widthcols[$k]['maw']) { // mPDF 5.7.3
22709 $surplus += ($wi * $spareratio) - ($widthcols[$k]['maw'] - $widthcols[$k]['miw']);
22710 $widthcols[$k]['miw'] = $widthcols[$k]['maw'];
22711 } else {
22712 $notsetlist[] = $k;
22713 $ttl += $table['l'][$k];
22714 $widthcols[$k]['miw'] += ($wi * $spareratio);
22715 }
22716 }
22717 } else {
22718 $wi = ($table['w'] - ($wis + $tblbw)); // i.e. extra space to distribute
22719 foreach ($list as $k) {
22720 $spareratio = ($table['l'][$k] / $totalatextlength); // gives ratio to divide up free space
22721 // Don't allocate more than Maximum required width - save rest in surplus
22722 if ($widthcols[$k]['miw'] + ($wi * $spareratio) >= $widthcols[$k]['maw']) { // mPDF 5.7.3
22723 $surplus += ($wi * $spareratio) - ($widthcols[$k]['maw'] - $widthcols[$k]['miw']);
22724 $widthcols[$k]['miw'] = $widthcols[$k]['maw'];
22725 } else {
22726 $notsetlist[] = $k;
22727 $ttl += $table['l'][$k];
22728 $widthcols[$k]['miw'] += ($wi * $spareratio);
22729 }
22730 }
22731 }
22732 // If surplus still left over apportion it across columns
22733 if ($surplus) {
22734 // if some are set only add to remaining - otherwise add to all of them
22735 if (count($notsetlist) && count($notsetlist) < $numcols) {
22736 foreach ($notsetlist AS $i) {
22737 if ($ttl)
22738 $widthcols[$i]['miw'] += $surplus * $table['l'][$i] / $ttl;
22739 }
22740 }
22741 // If some widths are defined, and others have been added up to their maxmum
22742 elseif (count($list) && count($list) < $numcols) {
22743 foreach ($list AS $i) {
22744 $widthcols[$i]['miw'] += $surplus / count($list);
22745 }
22746 } elseif ($numcols) { // If all columns
22747 $ttl = array_sum($table['l']);
22748 for ($i = 0; $i < $numcols; $i++) {
22749 $widthcols[$i]['miw'] += $surplus * $table['l'][$i] / $ttl;
22750 }
22751 }
22752 }
22753 }
22754
22755 // This sets the columns all to minimum width (which has been increased above if appropriate)
22756 for ($i = 0; $i < $numcols; $i++) {
22757 $widthcols[$i] = $widthcols[$i]['miw'];
22758 }
22759
22760 // TABLE NOT WIDE ENOUGH EVEN FOR MINIMUM CONTENT WIDTH
22761 // If sum of column widths set are too wide for table
22762 $checktablewidth = 0;
22763 for ($i = 0; $i < $numcols; $i++) {
22764 $checktablewidth += $widthcols[$i];
22765 }
22766 if ($checktablewidth > ($temppgwidth + 0.001 - $tblbw)) {
22767 $usedup = 0;
22768 $numleft = 0;
22769 for ($i = 0; $i < $numcols; $i++) {
22770 if ((isset($widthcols[$i]) && $widthcols[$i] > (($temppgwidth - $tblbw) / $numcols)) && (!isset($widthcols[$i]['w']))) {
22771 $numleft++;
22772 unset($widthcols[$i]);
22773 } else {
22774 $usedup += $widthcols[$i];
22775 }
22776 }
22777 for ($i = 0; $i < $numcols; $i++) {
22778 if (!isset($widthcols[$i]) || !$widthcols[$i]) {
22779 $widthcols[$i] = ((($temppgwidth - $tblbw) - $usedup) / ($numleft));
22780 }
22781 }
22782 }
22783 } else { //table has no width defined
22784 $table['w'] = $tablewidth;
22785 for ($i = 0; $i < $numcols; $i++) {
22786 if (isset($widthcols[$i]['wpercent']) && $this->keep_table_proportions) {
22787 $colwidth = $widthcols[$i]['maw'];
22788 } elseif (isset($widthcols[$i]['w'])) {
22789 $colwidth = $widthcols[$i]['miw'];
22790 } else {
22791 $colwidth = $widthcols[$i]['maw'];
22792 }
22793 unset($widthcols[$i]);
22794 $widthcols[$i] = $colwidth;
22795 }
22796 }
22797
22798 if ($table['overflow'] == 'visible' && $table['level'] == 1) {
22799 if ($tablewidth > $this->blk[$this->blklvl]['inner_width']) {
22800 for ($j = 0; $j < $numcols; $j++) { //columns
22801 for ($i = 0; $i < $table['nr']; $i++) { //rows
22802 if (isset($table['cells'][$i][$j]) && $table['cells'][$i][$j]) {
22803 $colspan = (isset($table['cells'][$i][$j]['colspan']) ? $table['cells'][$i][$j]['colspan'] : 1);
22804 if ($colspan > 1) {
22805 $w = 0;
22806 for ($c = $j; $c < ($j + $colspan); $c++) {
22807 $w += $widthcols[$c];
22808 }
22809 if ($w > $this->blk[$this->blklvl]['inner_width']) {
22810 $diff = $w - ($this->blk[$this->blklvl]['inner_width'] - $tblbw);
22811 for ($c = $j; $c < ($j + $colspan); $c++) {
22812 $widthcols[$c] -= $diff * ($widthcols[$c] / $w);
22813 }
22814 $table['w'] -= $diff;
22815 $table['csp'][$j] = $w - $diff;
22816 }
22817 }
22818 }
22819 }
22820 }
22821 }
22822 $pgNo = 0;
22823 $currWc = 0;
22824 for ($i = 0; $i < $numcols; $i++) { //columns
22825 if (isset($table['csp'][$i])) {
22826 $w = $table['csp'][$i];
22827 unset($table['csp'][$i]);
22828 } else {
22829 $w = $widthcols[$i];
22830 }
22831 if (($currWc + $w + $tblbw) > $this->blk[$this->blklvl]['inner_width']) {
22832 $pgNo++;
22833 $currWc = $widthcols[$i];
22834 } else {
22835 $currWc += $widthcols[$i];
22836 }
22837 $table['colPg'][$i] = $pgNo;
22838 }
22839 }
22840 }
22841
22842 function _tableHeight(&$table)
22843 {
22844 $level = $table['level'];
22845 $levelid = $table['levelid'];
22846 $cells = &$table['cells'];
22847 $numcols = $table['nc'];
22848 $numrows = $table['nr'];
22849 $listspan = array();
22850 $checkmaxheight = 0;
22851 $headerrowheight = 0;
22852 $checkmaxheightplus = 0;
22853 $headerrowheightplus = 0;
22854 $firstrowheight = 0;
22855
22856 $footerrowheight = 0;
22857 $footerrowheightplus = 0;
22858 if ($this->table_rotate) {
22859 $temppgheight = $this->tbrot_maxh;
22860 $remainingpage = $this->tbrot_maxh;
22861 } else {
22862 $temppgheight = ($this->h - $this->bMargin - $this->tMargin) - $this->kwt_height;
22863 $remainingpage = ($this->h - $this->bMargin - $this->y) - $this->kwt_height;
22864
22865 // If it is less than 1/20th of the remaining page height to finish the DIV (i.e. DIV padding + table bottom margin)
22866 // then allow for this
22867 $enddiv = $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $table['margin']['B'];
22868 if ($remainingpage > $enddiv && $enddiv / $remainingpage < 0.05) {
22869 $remainingpage -= $enddiv;
22870 } elseif ($remainingpage == 0) {
22871 $remainingpage = 0.001;
22872 }
22873 if ($temppgheight > $enddiv && $enddiv / $temppgheight < 0.05) {
22874 $temppgheight -= $enddiv;
22875 } elseif ($temppgheight == 0) {
22876 $temppgheight = 0.001;
22877 }
22878 }
22879 if ($remainingpage < 0) {
22880 $remainingpage = 0.001;
22881 }
22882 if ($temppgheight < 0) {
22883 $temppgheight = 0.001;
22884 }
22885
22886 for ($i = 0; $i < $numrows; $i++) { //rows
22887 $heightrow = &$table['hr'][$i];
22888 for ($j = 0; $j < $numcols; $j++) { //columns
22889 if (isset($cells[$i][$j]) && $cells[$i][$j]) {
22890 $c = &$cells[$i][$j];
22891
22892 if ($this->simpleTables) {
22893 if ($table['borders_separate']) { // NB twice border width
22894 $extraWLR = ($table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w']) + ($c['padding']['L'] + $c['padding']['R']) + $table['border_spacing_H'];
22895 $extrh = ($table['simple']['border_details']['T']['w'] + $table['simple']['border_details']['B']['w']) + ($c['padding']['T'] + $c['padding']['B']) + $table['border_spacing_V'];
22896 } else {
22897 $extraWLR = ($table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w']) / 2 + ($c['padding']['L'] + $c['padding']['R']);
22898 $extrh = ($table['simple']['border_details']['T']['w'] + $table['simple']['border_details']['B']['w']) / 2 + ($c['padding']['T'] + $c['padding']['B']);
22899 }
22900 } else {
22901 if ($this->packTableData) {
22902 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($c['borderbin']);
22903 } else {
22904 $bt = $c['border_details']['T']['w'];
22905 $bb = $c['border_details']['B']['w'];
22906 $br = $c['border_details']['R']['w'];
22907 $bl = $c['border_details']['L']['w'];
22908 }
22909 if ($table['borders_separate']) { // NB twice border width
22910 $extraWLR = $bl + $br + $c['padding']['L'] + $c['padding']['R'] + $table['border_spacing_H'];
22911 $extrh = $bt + $bb + $c['padding']['T'] + $c['padding']['B'] + $table['border_spacing_V'];
22912 } else {
22913 $extraWLR = $bl / 2 + $br / 2 + $c['padding']['L'] + $c['padding']['R'];
22914 $extrh = $bt / 2 + $bb / 2 + $c['padding']['T'] + $c['padding']['B'];
22915 }
22916 }
22917
22918 if ($table['overflow'] == 'visible' && $level == 1)
22919 list($x, $cw) = $this->_splitTableGetWidth($table, $i, $j);
22920 else
22921 list($x, $cw) = $this->_tableGetWidth($table, $i, $j);
22922
22923
22924 // Get CELL HEIGHT
22925 // ++ extra parameter forces wrap to break word
22926 if ($c['R'] && isset($c['textbuffer'])) {
22927 $str = '';
22928 foreach ($c['textbuffer'] AS $t) {
22929 $str .= $t[0] . ' ';
22930 }
22931 $str = rtrim($str);
22932 $s_fs = $this->FontSizePt;
22933 $s_f = $this->FontFamily;
22934 $s_st = $this->FontStyle;
22935 $this->SetFont($c['textbuffer'][0][4], $c['textbuffer'][0][2], $c['textbuffer'][0][11] / $this->shrin_k, true, true);
22936 $tempch = $this->GetStringWidth($str, true, $c['textbuffer'][0][18], $c['textbuffer'][0][8]);
22937 if ($c['R'] >= 45 && $c['R'] < 90) {
22938 $tempch = ((sin(deg2rad($c['R']))) * $tempch ) + ((sin(deg2rad($c['R']))) * (($c['textbuffer'][0][11] / _MPDFK) / $this->shrin_k));
22939 }
22940 $this->SetFont($s_f, $s_st, $s_fs, true, true);
22941 $ch = ($tempch ) + $extrh;
22942 } else {
22943 if (isset($c['textbuffer']) && !empty($c['textbuffer'])) {
22944 $this->cellLineHeight = $c['cellLineHeight'];
22945 $this->cellLineStackingStrategy = $c['cellLineStackingStrategy'];
22946 $this->cellLineStackingShift = $c['cellLineStackingShift'];
22947 $this->divwidth = $cw - $extraWLR;
22948 $tempch = $this->printbuffer($c['textbuffer'], '', true, true);
22949 } else {
22950 $tempch = 0;
22951 }
22952
22953 // Added cellpadding top and bottom. (Lineheight already adjusted)
22954 $ch = $tempch + $extrh;
22955 }
22956 //If height is defined and it is bigger than calculated $ch then update values
22957 if (isset($c['h']) && $c['h'] > $ch) {
22958 $c['mih'] = $ch; //in order to keep valign working
22959 $ch = $c['h'];
22960 } else
22961 $c['mih'] = $ch;
22962 if (isset($c['rowspan']))
22963 $listspan[] = array($i, $j);
22964 elseif ($heightrow < $ch)
22965 $heightrow = $ch;
22966
22967 // this is the extra used in _tableWrite to determine whether to trigger a page change
22968 if ($table['borders_separate']) {
22969 if ($i == ($numrows - 1) || (isset($c['rowspan']) && ($i + $c['rowspan']) == ($numrows))) {
22970 $extra = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
22971 } else {
22972 $extra = $table['border_spacing_V'] / 2;
22973 }
22974 } else {
22975 if (!$this->simpleTables) {
22976 $extra = $bb / 2;
22977 } elseif ($this->simpleTables) {
22978 $extra = $table['simple']['border_details']['B']['w'] / 2;
22979 }
22980 }
22981 if (isset($table['is_thead'][$i]) && $table['is_thead'][$i]) {
22982 if ($j == 0) {
22983 $headerrowheight += $ch;
22984 $headerrowheightplus += $ch + $extra;
22985 }
22986 } elseif (isset($table['is_tfoot'][$i]) && $table['is_tfoot'][$i]) {
22987 if ($j == 0) {
22988 $footerrowheight += $ch;
22989 $footerrowheightplus += $ch + $extra;
22990 }
22991 } else {
22992 $checkmaxheight = max($checkmaxheight, $ch);
22993 $checkmaxheightplus = max($checkmaxheightplus, $ch + $extra);
22994 }
22995 if ($this->tableLevel == 1 && $i == (isset($table['headernrows']) ? $table['headernrows'] : 0)) {
22996 $firstrowheight = max($ch, $firstrowheight);
22997 }
22998 unset($c);
22999 }
23000 }//end of columns
23001 }//end of rows
23002
23003 $heightrow = &$table['hr'];
23004 foreach ($listspan as $span) {
23005 list($i, $j) = $span;
23006 $c = &$cells[$i][$j];
23007 $lr = $i + $c['rowspan'];
23008 if ($lr > $numrows)
23009 $lr = $numrows;
23010 $hs = $hsa = 0;
23011 $list = array();
23012 for ($k = $i; $k < $lr; $k++) {
23013 $hs += $heightrow[$k];
23014 // mPDF 6
23015 $sh = false; // specified height
23016 for ($m = 0; $m < $numcols; $m++) { //columns
23017 $tc = &$cells[$k][$m];
23018 if (isset($tc['rowspan'])) {
23019 continue;
23020 }
23021 if (isset($tc['h'])) {
23022 $sh = true;
23023 break;
23024 }
23025 }
23026 if (!$sh) {
23027 $list[] = $k;
23028 }
23029 }
23030
23031 if ($table['borders_separate']) {
23032 if ($i == ($numrows - 1) || ($i + $c['rowspan']) == ($numrows)) {
23033 $extra = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
23034 } else {
23035 $extra = $table['border_spacing_V'] / 2;
23036 }
23037 } else {
23038 if (!$this->simpleTables) {
23039 if ($this->packTableData) {
23040 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($c['borderbin']);
23041 } else {
23042 $bb = $c['border_details']['B']['w'];
23043 }
23044 $extra = $bb / 2;
23045 } elseif ($this->simpleTables) {
23046 $extra = $table['simple']['border_details']['B']['w'] / 2;
23047 }
23048 }
23049 if (!empty($table['is_thead'][$i])) {
23050 $headerrowheight = max($headerrowheight, $hs);
23051 $headerrowheightplus = max($headerrowheightplus, $hs + $extra);
23052 } elseif (!empty($table['is_tfoot'][$i])) {
23053 $footerrowheight = max($footerrowheight, $hs);
23054 $footerrowheightplus = max($footerrowheightplus, $hs + $extra);
23055 } else {
23056 $checkmaxheight = max($checkmaxheight, $hs);
23057 $checkmaxheightplus = max($checkmaxheightplus, $hs + $extra);
23058 }
23059 if ($this->tableLevel == 1 && $i == (isset($table['headernrows']) ? $table['headernrows'] : 0)) {
23060 $firstrowheight = max($hs, $firstrowheight);
23061 }
23062
23063 if ($c['mih'] > $hs) {
23064 if (!$hs) {
23065 for ($k = $i; $k < $lr; $k++)
23066 $heightrow[$k] = $c['mih'] / $c['rowspan'];
23067 } elseif (!count($list)) { // no rows in the rowspan have a height specified, so share amongst all rows equally
23068 $hi = $c['mih'] - $hs;
23069 for ($k = $i; $k < $lr; $k++)
23070 $heightrow[$k] += ($heightrow[$k] / $hs) * $hi;
23071 } else {
23072 $hi = $c['mih'] - $hs; // mPDF 6
23073 foreach ($list as $k)
23074 $heightrow[$k] += $hi / (count($list)); // mPDF 6
23075 }
23076 }
23077 unset($c);
23078
23079 // If rowspans overlap so that one or more rows do not have a height set...
23080 // i.e. for one or more rows, the only cells (explicit) in that row have rowspan>1
23081 // so heightrow is still == 0
23082 if ($heightrow[$i] == 0) {
23083 // Get row extent to analyse above and below
23084 $top = $i;
23085 foreach ($listspan as $checkspan) {
23086 list($cki, $ckj) = $checkspan;
23087 $c = &$cells[$cki][$ckj];
23088 if (isset($c['rowspan']) && $c['rowspan'] > 1) {
23089 if (($cki + $c['rowspan'] - 1) >= $i) {
23090 $top = min($top, $cki);
23091 }
23092 }
23093 }
23094 $bottom = $i + $c['rowspan'] - 1;
23095 // Check for overconstrained conditions
23096 for ($k = $top; $k <= $bottom; $k++) {
23097 // if ['hr'] for any of the others is also 0, then abort (too complicated)
23098 if ($k != $i && $heightrow[$k] == 0) {
23099 break(1);
23100 }
23101 // check again that top and bottom are not crossed by rowspans - or abort (too complicated)
23102 if ($k == $top) {
23103 // ???? take account of colspan as well???
23104 for ($m = 0; $m < $numcols; $m++) { //columns
23105 if (!isset($cells[$k][$m]) || $cells[$k][$m] == 0) {
23106 break(2);
23107 }
23108 }
23109 } elseif ($k == $bottom) {
23110 // ???? take account of colspan as well???
23111 for ($m = 0; $m < $numcols; $m++) { //columns
23112 $c = &$cells[$k][$m];
23113 if (isset($c['rowspan']) && $c['rowspan'] > 1) {
23114 break(2);
23115 }
23116 }
23117 }
23118 }
23119 // By columns add up col height using ['h'] if set or ['mih'] if not
23120 // Intentionally do not substract border-spacing
23121 $colH = array();
23122 $extH = 0;
23123 $newhr = array();
23124 for ($m = 0; $m < $numcols; $m++) { //columns
23125 for ($k = $top; $k <= $bottom; $k++) {
23126 if (isset($cells[$k][$m]) && $cells[$k][$m] != 0) {
23127 $c = &$cells[$k][$m];
23128 if (isset($c['h']) && $c['h']) {
23129 $useh = $c['h'];
23130 }
23131 // ???? take account of colspan as well???
23132 else {
23133 $useh = $c['mih'];
23134 }
23135 if (isset($colH[$m])) {
23136 $colH[$m] += $useh;
23137 } else {
23138 $colH[$m] = $useh;
23139 }
23140 if (!isset($c['rowspan']) || $c['rowspan'] < 2) {
23141 $newhr[$k] = max((isset($newhr[$k]) ? $newhr[$k] : 0), $useh);
23142 }
23143 }
23144 }
23145 $extH = max($extH, $colH[$m]); // mPDF 6
23146 }
23147 $newhr[$i] = $extH - array_sum($newhr);
23148 for ($k = $top; $k <= $bottom; $k++) {
23149 $heightrow[$k] = $newhr[$k];
23150 }
23151 }
23152
23153
23154 unset($c);
23155 }
23156
23157 $table['h'] = array_sum($heightrow);
23158 unset($heightrow);
23159
23160 if ($table['borders_separate']) {
23161 $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'];
23162 } else {
23163 $table['h'] += $table['margin']['T'] + $table['margin']['B'] + $table['max_cell_border_width']['T'] / 2 + $table['max_cell_border_width']['B'] / 2;
23164 }
23165
23166 $maxrowheight = $checkmaxheightplus + $headerrowheightplus + $footerrowheightplus;
23167 $maxfirstrowheight = $firstrowheight + $headerrowheightplus + $footerrowheightplus; // includes thead, 1st row and tfoot
23168 return array($table['h'], $maxrowheight, $temppgheight, $remainingpage, $maxfirstrowheight);
23169 }
23170
23171 function _tableGetWidth(&$table, $i, $j)
23172 {
23173 $cell = &$table['cells'][$i][$j];
23174 if ($cell) {
23175 if (isset($cell['x0'])) {
23176 return array($cell['x0'], $cell['w0']);
23177 }
23178 $x = 0;
23179 $widthcols = &$table['wc'];
23180 for ($k = 0; $k < $j; $k++)
23181 $x += $widthcols[$k];
23182 $w = $widthcols[$j];
23183 if (isset($cell['colspan'])) {
23184 for ($k = $j + $cell['colspan'] - 1; $k > $j; $k--)
23185 $w += $widthcols[$k];
23186 }
23187 $cell['x0'] = $x;
23188 $cell['w0'] = $w;
23189 return array($x, $w);
23190 }
23191 return array(0, 0);
23192 }
23193
23194 function _splitTableGetWidth(&$table, $i, $j)
23195 {
23196 $cell = &$table['cells'][$i][$j];
23197 if ($cell) {
23198 if (isset($cell['x0']))
23199 return array($cell['x0'], $cell['w0']);
23200 $x = 0;
23201 $widthcols = &$table['wc'];
23202 $pg = $table['colPg'][$j];
23203 for ($k = 0; $k < $j; $k++) {
23204 if ($table['colPg'][$k] == $pg)
23205 $x += $widthcols[$k];
23206 }
23207 $w = $widthcols[$j];
23208 if (isset($cell['colspan'])) {
23209 for ($k = $j + $cell['colspan'] - 1; $k > $j; $k--)
23210 if ($table['colPg'][$k] == $pg)
23211 $w += $widthcols[$k];
23212 }
23213 $cell['x0'] = $x;
23214 $cell['w0'] = $w;
23215 return array($x, $w);
23216 }
23217 return array(0, 0);
23218 }
23219
23220 function _tableGetHeight(&$table, $i, $j)
23221 {
23222 $cell = &$table['cells'][$i][$j];
23223 if ($cell) {
23224 if (isset($cell['y0']))
23225 return array($cell['y0'], $cell['h0']);
23226 $y = 0;
23227 $heightrow = &$table['hr'];
23228 for ($k = 0; $k < $i; $k++)
23229 $y += $heightrow[$k];
23230 $h = $heightrow[$i];
23231 if (isset($cell['rowspan'])) {
23232 for ($k = $i + $cell['rowspan'] - 1; $k > $i; $k--)
23233 $h += $heightrow[$k];
23234 }
23235 $cell['y0'] = $y;
23236 $cell['h0'] = $h;
23237 return array($y, $h);
23238 }
23239 return array(0, 0);
23240 }
23241
23242 function _tableGetMaxRowHeight($table, $row)
23243 {
23244 if ($row == $table['nc'] - 1) {
23245 return $table['hr'][$row];
23246 }
23247 $maxrowheight = $table['hr'][$row];
23248 for ($i = $row + 1; $i < $table['nr']; $i++) {
23249 $cellsset = 0;
23250 for ($j = 0; $j < $table['nc']; $j++) {
23251 if ($table['cells'][$i][$j]) {
23252 if (isset($table['cells'][$i][$j]['colspan'])) {
23253 $cellsset += $table['cells'][$i][$j]['colspan'];
23254 } else
23255 $cellsset += 1;
23256 }
23257 }
23258 if ($cellsset == $table['nc']) {
23259 return $maxrowheight;
23260 } else {
23261 $maxrowheight += $table['hr'][$i];
23262 }
23263 }
23264 return $maxrowheight;
23265 }
23266
23267 // CHANGED TO ALLOW TABLE BORDER TO BE SPECIFIED CORRECTLY - added border_details
23268 function _tableRect($x, $y, $w, $h, $bord = -1, $details = array(), $buffer = false, $bSeparate = false, $cort = 'cell', $tablecorner = '', $bsv = 0, $bsh = 0)
23269 {
23270 $cellBorderOverlay = array();
23271
23272 if ($bord == -1) {
23273 $this->Rect($x, $y, $w, $h);
23274 } elseif ($this->simpleTables && ($cort == 'cell')) {
23275 $this->SetLineWidth($details['L']['w']);
23276 if ($details['L']['c']) {
23277 $this->SetDColor($details['L']['c']);
23278 } else {
23279 $this->SetDColor($this->ConvertColor(0));
23280 }
23281 $this->SetLineJoin(0);
23282 $this->Rect($x, $y, $w, $h);
23283 } elseif ($bord) {
23284 if (!$bSeparate && $buffer) {
23285 $priority = 'LRTB';
23286 for ($p = 0; $p < strlen($priority); $p++) {
23287 $side = $priority[$p];
23288 $details['p'] = $side;
23289
23290 $dom = 0;
23291 if (isset($details[$side]['w'])) {
23292 $dom += ($details[$side]['w'] * 100000);
23293 }
23294 if (isset($details[$side]['style'])) {
23295 $dom += (array_search($details[$side]['style'], $this->borderstyles) * 100);
23296 }
23297 if (isset($details[$side]['dom'])) {
23298 $dom += ($details[$side]['dom'] * 10);
23299 }
23300
23301 // Precedence to darker colours at joins
23302 $coldom = 0;
23303 if (isset($details[$side]['c']) && is_array($details[$side]['c'])) {
23304 if ($details[$side]['c'][0] == 3) { // RGB
23305 $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);
23306 }
23307 } // 10 black - 0 white
23308 if ($coldom) {
23309 $dom += $coldom;
23310 }
23311 // Lastly precedence to RIGHT and BOTTOM cells at joins
23312 if (isset($details['cellposdom'])) {
23313 $dom += $details['cellposdom'];
23314 }
23315
23316 $save = false;
23317 if ($side == 'T' && $this->issetBorder($bord, _BORDER_TOP)) {
23318 $cbord = _BORDER_TOP;
23319 $save = true;
23320 } elseif ($side == 'L' && $this->issetBorder($bord, _BORDER_LEFT)) {
23321 $cbord = _BORDER_LEFT;
23322 $save = true;
23323 } elseif ($side == 'R' && $this->issetBorder($bord, _BORDER_RIGHT)) {
23324 $cbord = _BORDER_RIGHT;
23325 $save = true;
23326 } elseif ($side == 'B' && $this->issetBorder($bord, _BORDER_BOTTOM)) {
23327 $cbord = _BORDER_BOTTOM;
23328 $save = true;
23329 }
23330
23331 if ($save) {
23332 $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
23333 );
23334 if ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'groove' || $details[$side]['style'] == 'inset' || $details[$side]['style'] == 'outset' || $details[$side]['style'] == 'double') {
23335 $details[$side]['overlay'] = true;
23336 $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
23337 );
23338 }
23339 }
23340 }
23341 return;
23342 }
23343
23344 if (isset($details['p']) && strlen($details['p']) > 1) {
23345 $priority = $details['p'];
23346 } else {
23347 $priority = 'LTRB';
23348 }
23349 $Tw = 0;
23350 $Rw = 0;
23351 $Bw = 0;
23352 $Lw = 0;
23353 if (isset($details['T']['w'])) {
23354 $Tw = $details['T']['w'];
23355 }
23356 if (isset($details['R']['w'])) {
23357 $Rw = $details['R']['w'];
23358 }
23359 if (isset($details['B']['w'])) {
23360 $Bw = $details['B']['w'];
23361 }
23362 if (isset($details['L']['w'])) {
23363 $Lw = $details['L']['w'];
23364 }
23365
23366 $x2 = $x + $w;
23367 $y2 = $y + $h;
23368 $oldlinewidth = $this->LineWidth;
23369
23370 for ($p = 0; $p < strlen($priority); $p++) {
23371 $side = $priority[$p];
23372 $xadj = 0;
23373 $xadj2 = 0;
23374 $yadj = 0;
23375 $yadj2 = 0;
23376 $print = false;
23377 if ($Tw && $side == 'T' && $this->issetBorder($bord, _BORDER_TOP)) { // TOP
23378 $ly1 = $y;
23379 $ly2 = $y;
23380 $lx1 = $x;
23381 $lx2 = $x2;
23382 $this->SetLineWidth($Tw);
23383 if ($cort == 'cell' || strpos($tablecorner, 'L') !== false) {
23384 if ($Tw > $Lw)
23385 $xadj = ($Tw - $Lw) / 2;
23386 if ($Tw < $Lw)
23387 $xadj = ($Tw + $Lw) / 2;
23388 }
23389 else {
23390 $xadj = $Tw / 2 - $bsh / 2;
23391 }
23392 if ($cort == 'cell' || strpos($tablecorner, 'R') !== false) {
23393 if ($Tw > $Rw)
23394 $xadj2 = ($Tw - $Rw) / 2;
23395 if ($Tw < $Rw)
23396 $xadj2 = ($Tw + $Rw) / 2;
23397 }
23398 else {
23399 $xadj2 = $Tw / 2 - $bsh / 2;
23400 }
23401 if (!$bSeparate && $details['mbw']['TL']) {
23402 $xadj = ($Tw - $details['mbw']['TL']) / 2;
23403 }
23404 if (!$bSeparate && $details['mbw']['TR']) {
23405 $xadj2 = ($Tw - $details['mbw']['TR']) / 2;
23406 }
23407 $print = true;
23408 }
23409 if ($Lw && $side == 'L' && $this->issetBorder($bord, _BORDER_LEFT)) { // LEFT
23410 $ly1 = $y;
23411 $ly2 = $y2;
23412 $lx1 = $x;
23413 $lx2 = $x;
23414 $this->SetLineWidth($Lw);
23415 if ($cort == 'cell' || strpos($tablecorner, 'T') !== false) {
23416 if ($Lw > $Tw)
23417 $yadj = ($Lw - $Tw) / 2;
23418 if ($Lw < $Tw)
23419 $yadj = ($Lw + $Tw) / 2;
23420 }
23421 else {
23422 $yadj = $Lw / 2 - $bsv / 2;
23423 }
23424 if ($cort == 'cell' || strpos($tablecorner, 'B') !== false) {
23425 if ($Lw > $Bw)
23426 $yadj2 = ($Lw - $Bw) / 2;
23427 if ($Lw < $Bw)
23428 $yadj2 = ($Lw + $Bw) / 2;
23429 }
23430 else {
23431 $yadj2 = $Lw / 2 - $bsv / 2;
23432 }
23433 if (!$bSeparate && $details['mbw']['LT']) {
23434 $yadj = ($Lw - $details['mbw']['LT']) / 2;
23435 }
23436 if (!$bSeparate && $details['mbw']['LB']) {
23437 $yadj2 = ($Lw - $details['mbw']['LB']) / 2;
23438 }
23439 $print = true;
23440 }
23441 if ($Rw && $side == 'R' && $this->issetBorder($bord, _BORDER_RIGHT)) { // RIGHT
23442 $ly1 = $y;
23443 $ly2 = $y2;
23444 $lx1 = $x2;
23445 $lx2 = $x2;
23446 $this->SetLineWidth($Rw);
23447 if ($cort == 'cell' || strpos($tablecorner, 'T') !== false) {
23448 if ($Rw < $Tw)
23449 $yadj = ($Rw + $Tw) / 2;
23450 if ($Rw > $Tw)
23451 $yadj = ($Rw - $Tw) / 2;
23452 }
23453 else {
23454 $yadj = $Rw / 2 - $bsv / 2;
23455 }
23456
23457 if ($cort == 'cell' || strpos($tablecorner, 'B') !== false) {
23458 if ($Rw > $Bw)
23459 $yadj2 = ($Rw - $Bw) / 2;
23460 if ($Rw < $Bw)
23461 $yadj2 = ($Rw + $Bw) / 2;
23462 }
23463 else {
23464 $yadj2 = $Rw / 2 - $bsv / 2;
23465 }
23466
23467 if (!$bSeparate && $details['mbw']['RT']) {
23468 $yadj = ($Rw - $details['mbw']['RT']) / 2;
23469 }
23470 if (!$bSeparate && $details['mbw']['RB']) {
23471 $yadj2 = ($Rw - $details['mbw']['RB']) / 2;
23472 }
23473 $print = true;
23474 }
23475 if ($Bw && $side == 'B' && $this->issetBorder($bord, _BORDER_BOTTOM)) { // BOTTOM
23476 $ly1 = $y2;
23477 $ly2 = $y2;
23478 $lx1 = $x;
23479 $lx2 = $x2;
23480 $this->SetLineWidth($Bw);
23481 if ($cort == 'cell' || strpos($tablecorner, 'L') !== false) {
23482 if ($Bw > $Lw)
23483 $xadj = ($Bw - $Lw) / 2;
23484 if ($Bw < $Lw)
23485 $xadj = ($Bw + $Lw) / 2;
23486 }
23487 else {
23488 $xadj = $Bw / 2 - $bsh / 2;
23489 }
23490 if ($cort == 'cell' || strpos($tablecorner, 'R') !== false) {
23491 if ($Bw > $Rw)
23492 $xadj2 = ($Bw - $Rw) / 2;
23493 if ($Bw < $Rw)
23494 $xadj2 = ($Bw + $Rw) / 2;
23495 }
23496 else {
23497 $xadj2 = $Bw / 2 - $bsh / 2;
23498 }
23499 if (!$bSeparate && $details['mbw']['BL']) {
23500 $xadj = ($Bw - $details['mbw']['BL']) / 2;
23501 }
23502 if (!$bSeparate && $details['mbw']['BR']) {
23503 $xadj2 = ($Bw - $details['mbw']['BR']) / 2;
23504 }
23505 $print = true;
23506 }
23507
23508 // Now draw line
23509 if ($print) {
23510 /* -- TABLES-ADVANCED-BORDERS -- */
23511 if ($details[$side]['style'] == 'double') {
23512 if (!isset($details[$side]['overlay']) || !$details[$side]['overlay'] || $bSeparate) {
23513 if ($details[$side]['c']) {
23514 $this->SetDColor($details[$side]['c']);
23515 } else {
23516 $this->SetDColor($this->ConvertColor(0));
23517 }
23518 $this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
23519 }
23520 if ((isset($details[$side]['overlay']) && $details[$side]['overlay']) || $bSeparate) {
23521 if ($bSeparate && $cort == 'table') {
23522 if ($side == 'T') {
23523 $xadj -= $this->LineWidth / 2;
23524 $xadj2 -= $this->LineWidth;
23525 if ($this->issetBorder($bord, _BORDER_LEFT)) {
23526 $xadj += $this->LineWidth / 2;
23527 }
23528 if ($this->issetBorder($bord, _BORDER_RIGHT)) {
23529 $xadj2 += $this->LineWidth;
23530 }
23531 }
23532 if ($side == 'L') {
23533 $yadj -= $this->LineWidth / 2;
23534 $yadj2 -= $this->LineWidth;
23535 if ($this->issetBorder($bord, _BORDER_TOP)) {
23536 $yadj += $this->LineWidth / 2;
23537 }
23538 if ($this->issetBorder($bord, _BORDER_BOTTOM)) {
23539 $yadj2 += $this->LineWidth;
23540 }
23541 }
23542 if ($side == 'B') {
23543 $xadj -= $this->LineWidth / 2;
23544 $xadj2 -= $this->LineWidth;
23545 if ($this->issetBorder($bord, _BORDER_LEFT)) {
23546 $xadj += $this->LineWidth / 2;
23547 }
23548 if ($this->issetBorder($bord, _BORDER_RIGHT)) {
23549 $xadj2 += $this->LineWidth;
23550 }
23551 }
23552 if ($side == 'R') {
23553 $yadj -= $this->LineWidth / 2;
23554 $yadj2 -= $this->LineWidth;
23555 if ($this->issetBorder($bord, _BORDER_TOP)) {
23556 $yadj += $this->LineWidth / 2;
23557 }
23558 if ($this->issetBorder($bord, _BORDER_BOTTOM)) {
23559 $yadj2 += $this->LineWidth;
23560 }
23561 }
23562 }
23563
23564 $this->SetLineWidth($this->LineWidth / 3);
23565
23566 $tbcol = $this->ConvertColor(255);
23567 for ($l = 0; $l <= $this->blklvl; $l++) {
23568 if ($this->blk[$l]['bgcolor']) {
23569 $tbcol = ($this->blk[$l]['bgcolorarray']);
23570 }
23571 }
23572
23573 if ($bSeparate) {
23574 $cellBorderOverlay[] = array(
23575 'x' => $lx1 + $xadj,
23576 'y' => $ly1 + $yadj,
23577 'x2' => $lx2 - $xadj2,
23578 'y2' => $ly2 - $yadj2,
23579 'col' => $tbcol,
23580 'lw' => $this->LineWidth,
23581 );
23582 } else {
23583 $this->SetDColor($tbcol);
23584 $this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
23585 }
23586 }
23587 } elseif (isset($details[$side]['style']) && ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'groove' || $details[$side]['style'] == 'inset' || $details[$side]['style'] == 'outset')) {
23588 if (!isset($details[$side]['overlay']) || !$details[$side]['overlay'] || $bSeparate) {
23589 if ($details[$side]['c']) {
23590 $this->SetDColor($details[$side]['c']);
23591 } else {
23592 $this->SetDColor($this->ConvertColor(0));
23593 }
23594 if ($details[$side]['style'] == 'outset' || $details[$side]['style'] == 'groove') {
23595 $nc = $this->_darkenColor($details[$side]['c']);
23596 $this->SetDColor($nc);
23597 } elseif ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'inset') {
23598 $nc = $this->_lightenColor($details[$side]['c']);
23599 $this->SetDColor($nc);
23600 }
23601 $this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
23602 }
23603 if ((isset($details[$side]['overlay']) && $details[$side]['overlay']) || $bSeparate) {
23604 if ($details[$side]['c']) {
23605 $this->SetDColor($details[$side]['c']);
23606 } else {
23607 $this->SetDColor($this->ConvertColor(0));
23608 }
23609 $doubleadj = ($this->LineWidth) / 3;
23610 $this->SetLineWidth($this->LineWidth / 2);
23611 $xadj3 = $yadj3 = $wadj3 = $hadj3 = 0;
23612
23613 if ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'inset') {
23614 $nc = $this->_darkenColor($details[$side]['c']);
23615
23616 if ($bSeparate && $cort == 'table') {
23617 if ($side == 'T') {
23618 $yadj3 = $this->LineWidth / 2;
23619 $xadj3 = -$this->LineWidth / 2;
23620 $wadj3 = $this->LineWidth;
23621 if ($this->issetBorder($bord, _BORDER_LEFT)) {
23622 $xadj3 += $this->LineWidth;
23623 $wadj3 -= $this->LineWidth;
23624 }
23625 if ($this->issetBorder($bord, _BORDER_RIGHT)) {
23626 $wadj3 -= $this->LineWidth * 2;
23627 }
23628 }
23629 if ($side == 'L') {
23630 $xadj3 = $this->LineWidth / 2;
23631 $yadj3 = -$this->LineWidth / 2;
23632 $hadj3 = $this->LineWidth;
23633 if ($this->issetBorder($bord, _BORDER_TOP)) {
23634 $yadj3 += $this->LineWidth;
23635 $hadj3 -= $this->LineWidth;
23636 }
23637 if ($this->issetBorder($bord, _BORDER_BOTTOM)) {
23638 $hadj3 -= $this->LineWidth * 2;
23639 }
23640 }
23641 if ($side == 'B') {
23642 $yadj3 = $this->LineWidth / 2;
23643 $xadj3 = -$this->LineWidth / 2;
23644 $wadj3 = $this->LineWidth;
23645 }
23646 if ($side == 'R') {
23647 $xadj3 = $this->LineWidth / 2;
23648 $yadj3 = -$this->LineWidth / 2;
23649 $hadj3 = $this->LineWidth;
23650 }
23651 } elseif ($side == 'T') {
23652 $yadj3 = $this->LineWidth / 2;
23653 $xadj3 = $this->LineWidth / 2;
23654 $wadj3 = -$this->LineWidth * 2;
23655 } elseif ($side == 'L') {
23656 $xadj3 = $this->LineWidth / 2;
23657 $yadj3 = $this->LineWidth / 2;
23658 $hadj3 = -$this->LineWidth * 2;
23659 } elseif ($side == 'B' && $bSeparate) {
23660 $yadj3 = $this->LineWidth / 2;
23661 $wadj3 = $this->LineWidth / 2;
23662 } elseif ($side == 'R' && $bSeparate) {
23663 $xadj3 = $this->LineWidth / 2;
23664 $hadj3 = $this->LineWidth / 2;
23665 } elseif ($side == 'B') {
23666 $yadj3 = $this->LineWidth / 2;
23667 $xadj3 = $this->LineWidth / 2;
23668 } elseif ($side == 'R') {
23669 $xadj3 = $this->LineWidth / 2;
23670 $yadj3 = $this->LineWidth / 2;
23671 }
23672 } else {
23673 $nc = $this->_lightenColor($details[$side]['c']);
23674
23675 if ($bSeparate && $cort == 'table') {
23676 if ($side == 'T') {
23677 $yadj3 = $this->LineWidth / 2;
23678 $xadj3 = -$this->LineWidth / 2;
23679 $wadj3 = $this->LineWidth;
23680 if ($this->issetBorder($bord, _BORDER_LEFT)) {
23681 $xadj3 += $this->LineWidth;
23682 $wadj3 -= $this->LineWidth;
23683 }
23684 }
23685 if ($side == 'L') {
23686 $xadj3 = $this->LineWidth / 2;
23687 $yadj3 = -$this->LineWidth / 2;
23688 $hadj3 = $this->LineWidth;
23689 if ($this->issetBorder($bord, _BORDER_TOP)) {
23690 $yadj3 += $this->LineWidth;
23691 $hadj3 -= $this->LineWidth;
23692 }
23693 }
23694 if ($side == 'B') {
23695 $yadj3 = $this->LineWidth / 2;
23696 $xadj3 = -$this->LineWidth / 2;
23697 $wadj3 = $this->LineWidth;
23698 if ($this->issetBorder($bord, _BORDER_LEFT)) {
23699 $xadj3 += $this->LineWidth;
23700 $wadj3 -= $this->LineWidth;
23701 }
23702 }
23703 if ($side == 'R') {
23704 $xadj3 = $this->LineWidth / 2;
23705 $yadj3 = -$this->LineWidth / 2;
23706 $hadj3 = $this->LineWidth;
23707 if ($this->issetBorder($bord, _BORDER_TOP)) {
23708 $yadj3 += $this->LineWidth;
23709 $hadj3 -= $this->LineWidth;
23710 }
23711 }
23712 } elseif ($side == 'T') {
23713 $yadj3 = $this->LineWidth / 2;
23714 $xadj3 = $this->LineWidth / 2;
23715 } elseif ($side == 'L') {
23716 $xadj3 = $this->LineWidth / 2;
23717 $yadj3 = $this->LineWidth / 2;
23718 } elseif ($side == 'B' && $bSeparate) {
23719 $yadj3 = $this->LineWidth / 2;
23720 $xadj3 = $this->LineWidth / 2;
23721 } elseif ($side == 'R' && $bSeparate) {
23722 $xadj3 = $this->LineWidth / 2;
23723 $yadj3 = $this->LineWidth / 2;
23724 } elseif ($side == 'B') {
23725 $yadj3 = $this->LineWidth / 2;
23726 $xadj3 = -$this->LineWidth / 2;
23727 $wadj3 = $this->LineWidth;
23728 } elseif ($side == 'R') {
23729 $xadj3 = $this->LineWidth / 2;
23730 $yadj3 = -$this->LineWidth / 2;
23731 $hadj3 = $this->LineWidth;
23732 }
23733 }
23734
23735 if ($bSeparate) {
23736 $cellBorderOverlay[] = array(
23737 'x' => $lx1 + $xadj + $xadj3,
23738 'y' => $ly1 + $yadj + $yadj3,
23739 'x2' => $lx2 - $xadj2 + $xadj3 + $wadj3,
23740 'y2' => $ly2 - $yadj2 + $yadj3 + $hadj3,
23741 'col' => $nc,
23742 'lw' => $this->LineWidth,
23743 );
23744 } else {
23745 $this->SetDColor($nc);
23746 $this->Line($lx1 + $xadj + $xadj3, $ly1 + $yadj + $yadj3, $lx2 - $xadj2 + $xadj3 + $wadj3, $ly2 - $yadj2 + $yadj3 + $hadj3);
23747 }
23748 }
23749 } else {
23750 /* -- END TABLES-ADVANCED-BORDERS -- */
23751 if ($details[$side]['style'] == 'dashed') {
23752 $dashsize = 2; // final dash will be this + 1*linewidth
23753 $dashsizek = 1.5; // ratio of Dash/Blank
23754 $this->SetDash($dashsize, ($dashsize / $dashsizek) + ($this->LineWidth * 2));
23755 } elseif ($details[$side]['style'] == 'dotted') {
23756 $this->SetLineJoin(1);
23757 $this->SetLineCap(1);
23758 $this->SetDash(0.001, ($this->LineWidth * 2));
23759 }
23760 if ($details[$side]['c']) {
23761 $this->SetDColor($details[$side]['c']);
23762 } else {
23763 $this->SetDColor($this->ConvertColor(0));
23764 }
23765 $this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
23766 /* -- TABLES-ADVANCED-BORDERS -- */
23767 }
23768 /* -- END TABLES-ADVANCED-BORDERS -- */
23769
23770 // Reset Corners
23771 $this->SetDash();
23772 //BUTT style line cap
23773 $this->SetLineCap(2);
23774 }
23775 }
23776
23777 if ($bSeparate && count($cellBorderOverlay)) {
23778 foreach ($cellBorderOverlay AS $cbo) {
23779 $this->SetLineWidth($cbo['lw']);
23780 $this->SetDColor($cbo['col']);
23781 $this->Line($cbo['x'], $cbo['y'], $cbo['x2'], $cbo['y2']);
23782 }
23783 }
23784
23785 // $this->SetLineWidth($oldlinewidth);
23786 // $this->SetDColor($this->ConvertColor(0));
23787 }
23788 }
23789
23790 /* -- TABLES -- */
23791 /* -- TABLES-ADVANCED-BORDERS -- */
23792
23793 function _lightenColor($c)
23794 {
23795 if (is_array($c)) {
23796 throw new MpdfException('Color error in _lightencolor');
23797 }
23798 if ($c[0] == 3 || $c[0] == 5) { // RGB
23799 list($h, $s, $l) = $this->rgb2hsl(ord($c[1]) / 255, ord($c[2]) / 255, ord($c[3]) / 255);
23800 $l += ((1 - $l) * 0.8);
23801 list($r, $g, $b) = $this->hsl2rgb($h, $s, $l);
23802 $ret = array(3, $r, $g, $b);
23803 } elseif ($c[0] == 4 || $c[0] == 6) { // CMYK
23804 $ret = array(4, max(0, (ord($c[1]) - 20)), max(0, (ord($c[2]) - 20)), max(0, (ord($c[3]) - 20)), max(0, (ord($c[4]) - 20)));
23805 } elseif ($c[0] == 1) { // Grayscale
23806 $ret = array(1, min(255, (ord($c[1]) + 32)));
23807 }
23808 $c = array_pad($ret, 6, 0);
23809 $cstr = pack("a1ccccc", $c[0], ($c[1] & 0xFF), ($c[2] & 0xFF), ($c[3] & 0xFF), ($c[4] & 0xFF), ($c[5] & 0xFF));
23810 return $cstr;
23811 }
23812
23813 function _darkenColor($c)
23814 {
23815 if (is_array($c)) {
23816 throw new MpdfException('Color error in _darkenColor');
23817 }
23818 if ($c[0] == 3 || $c[0] == 5) { // RGB
23819 list($h, $s, $l) = $this->rgb2hsl(ord($c[1]) / 255, ord($c[2]) / 255, ord($c[3]) / 255);
23820 $s *= 0.25;
23821 $l *= 0.75;
23822 list($r, $g, $b) = $this->hsl2rgb($h, $s, $l);
23823 $ret = array(3, $r, $g, $b);
23824 } elseif ($c[0] == 4 || $c[0] == 6) { // CMYK
23825 $ret = array(4, min(100, (ord($c[1]) + 20)), min(100, (ord($c[2]) + 20)), min(100, (ord($c[3]) + 20)), min(100, (ord($c[4]) + 20)));
23826 } elseif ($c[0] == 1) { // Grayscale
23827 $ret = array(1, max(0, (ord($c[1]) - 32)));
23828 }
23829 $c = array_pad($ret, 6, 0);
23830 $cstr = pack("a1ccccc", $c[0], ($c[1] & 0xFF), ($c[2] & 0xFF), ($c[3] & 0xFF), ($c[4] & 0xFF), ($c[5] & 0xFF));
23831 return $cstr;
23832 }
23833
23834 /* -- END TABLES-ADVANCED-BORDERS -- */
23835
23836 function setBorder(&$var, $flag, $set = true)
23837 {
23838 $flag = intval($flag);
23839 if ($set) {
23840 $set = true;
23841 }
23842 $var = intval($var);
23843 $var = $set ? ($var | $flag) : ($var & ~$flag);
23844 }
23845
23846 function issetBorder($var, $flag)
23847 {
23848 $flag = intval($flag);
23849 $var = intval($var);
23850 return (($var & $flag) == $flag);
23851 }
23852
23853 function _table2cellBorder(&$tableb, &$cbdb, &$cellb, $bval)
23854 {
23855 if ($tableb && $tableb['w'] > $cbdb['w']) {
23856 $cbdb = $tableb;
23857 $this->setBorder($cellb, $bval);
23858 } elseif ($tableb && $tableb['w'] == $cbdb['w'] && array_search($tableb['style'], $this->borderstyles) > array_search($cbdb['style'], $this->borderstyles)) {
23859 $cbdb = $tableb;
23860 $this->setBorder($cellb, $bval);
23861 }
23862 }
23863
23864 // FIX BORDERS ********************************************
23865 function _fixTableBorders(&$table)
23866 {
23867 if (!$table['borders_separate'] && $table['border_details']['L']['w']) {
23868 $table['max_cell_border_width']['L'] = $table['border_details']['L']['w'];
23869 }
23870 if (!$table['borders_separate'] && $table['border_details']['R']['w']) {
23871 $table['max_cell_border_width']['R'] = $table['border_details']['R']['w'];
23872 }
23873 if (!$table['borders_separate'] && $table['border_details']['T']['w']) {
23874 $table['max_cell_border_width']['T'] = $table['border_details']['T']['w'];
23875 }
23876 if (!$table['borders_separate'] && $table['border_details']['B']['w']) {
23877 $table['max_cell_border_width']['B'] = $table['border_details']['B']['w'];
23878 }
23879 if ($this->simpleTables) {
23880 return;
23881 }
23882 $cells = &$table['cells'];
23883 $numcols = $table['nc'];
23884 $numrows = $table['nr'];
23885 /* -- TABLES-ADVANCED-BORDERS -- */
23886 if (isset($table['topntail']) && $table['topntail']) {
23887 $tntborddet = $this->border_details($table['topntail']);
23888 }
23889 if (isset($table['thead-underline']) && $table['thead-underline']) {
23890 $thuborddet = $this->border_details($table['thead-underline']);
23891 }
23892 /* -- END TABLES-ADVANCED-BORDERS -- */
23893
23894 for ($i = 0; $i < $numrows; $i++) { //Rows
23895 for ($j = 0; $j < $numcols; $j++) { //Columns
23896 if (isset($cells[$i][$j]) && $cells[$i][$j]) {
23897 $cell = &$cells[$i][$j];
23898 if ($this->packTableData) {
23899 $cbord = $this->_unpackCellBorder($cell['borderbin']);
23900 } else {
23901 $cbord = &$cells[$i][$j];
23902 }
23903
23904 // mPDF 5.7.3
23905 if (!$cbord['border'] && $cbord['border'] !== 0 && isset($table['border']) && $table['border'] && $this->table_border_attr_set) {
23906 $cbord['border'] = $table['border'];
23907 $cbord['border_details'] = $table['border_details'];
23908 }
23909
23910 if (isset($cell['colspan']) && $cell['colspan'] > 1) {
23911 $ccolsp = $cell['colspan'];
23912 } else {
23913 $ccolsp = 1;
23914 }
23915 if (isset($cell['rowspan']) && $cell['rowspan'] > 1) {
23916 $crowsp = $cell['rowspan'];
23917 } else {
23918 $crowsp = 1;
23919 }
23920
23921 $cbord['border_details']['cellposdom'] = ((($i + 1) / $numrows) / 10000 ) + ((($j + 1) / $numcols) / 10 );
23922 // Inherit Cell border from Table border
23923 if ($this->table_border_css_set && !$table['borders_separate']) {
23924 if ($i == 0) {
23925 $this->_table2cellBorder($table['border_details']['T'], $cbord['border_details']['T'], $cbord['border'], _BORDER_TOP);
23926 }
23927 if ($i == ($numrows - 1) || ($i + $crowsp) == ($numrows)) {
23928 $this->_table2cellBorder($table['border_details']['B'], $cbord['border_details']['B'], $cbord['border'], _BORDER_BOTTOM);
23929 }
23930 if ($j == 0) {
23931 $this->_table2cellBorder($table['border_details']['L'], $cbord['border_details']['L'], $cbord['border'], _BORDER_LEFT);
23932 }
23933 if ($j == ($numcols - 1) || ($j + $ccolsp) == ($numcols)) {
23934 $this->_table2cellBorder($table['border_details']['R'], $cbord['border_details']['R'], $cbord['border'], _BORDER_RIGHT);
23935 }
23936 }
23937
23938 /* -- TABLES-ADVANCED-BORDERS -- */
23939 $fixbottom = true;
23940 if (isset($table['topntail']) && $table['topntail']) {
23941 if ($i == 0) {
23942 $cbord['border_details']['T'] = $tntborddet;
23943 $this->setBorder($cbord['border'], _BORDER_TOP);
23944 }
23945 if ($this->tableLevel == 1 && $table['headernrows'] > 0 && $i == $table['headernrows'] - 1) {
23946 $cbord['border_details']['B'] = $tntborddet;
23947 $this->setBorder($cbord['border'], _BORDER_BOTTOM);
23948 $fixbottom = false;
23949 } elseif ($this->tableLevel == 1 && $table['headernrows'] > 0 && $i == $table['headernrows']) {
23950 if (!$table['borders_separate']) {
23951 $cbord['border_details']['T'] = $tntborddet;
23952 $this->setBorder($cbord['border'], _BORDER_TOP);
23953 }
23954 }
23955 if ($this->tableLevel == 1 && $table['footernrows'] > 0 && $i == ($numrows - $table['footernrows'] - 1)) {
23956 if (!$table['borders_separate']) {
23957 $cbord['border_details']['B'] = $tntborddet;
23958 $this->setBorder($cbord['border'], _BORDER_BOTTOM);
23959 $fixbottom = false;
23960 }
23961 } elseif ($this->tableLevel == 1 && $table['footernrows'] > 0 && $i == ($numrows - $table['footernrows'])) {
23962 $cbord['border_details']['T'] = $tntborddet;
23963 $this->setBorder($cbord['border'], _BORDER_TOP);
23964 }
23965 if ($this->tabletheadjustfinished) { // $this->tabletheadjustfinished called from tableheader
23966 if (!$table['borders_separate']) {
23967 $cbord['border_details']['T'] = $tntborddet;
23968 $this->setBorder($cbord['border'], _BORDER_TOP);
23969 }
23970 }
23971 if ($i == ($numrows - 1) || ($i + $crowsp) == ($numrows)) {
23972 $cbord['border_details']['B'] = $tntborddet;
23973 $this->setBorder($cbord['border'], _BORDER_BOTTOM);
23974 }
23975 }
23976 if (isset($table['thead-underline']) && $table['thead-underline']) {
23977 if ($table['borders_separate']) {
23978 if ($i == 0) {
23979 $cbord['border_details']['B'] = $thuborddet;
23980 $this->setBorder($cbord['border'], _BORDER_BOTTOM);
23981 $fixbottom = false;
23982 }
23983 } else {
23984 if ($this->tableLevel == 1 && $table['headernrows'] > 0 && $i == $table['headernrows'] - 1) {
23985 $cbord['border_details']['T'] = $thuborddet;
23986 $this->setBorder($cbord['border'], _BORDER_TOP);
23987 } elseif ($this->tabletheadjustfinished) { // $this->tabletheadjustfinished called from tableheader
23988 $cbord['border_details']['T'] = $thuborddet;
23989 $this->setBorder($cbord['border'], _BORDER_TOP);
23990 }
23991 }
23992 }
23993
23994 // Collapse Border - Algorithm for conflicting borders
23995 // Hidden >> Width >> double>solid>dashed>dotted... >> style set on cell>table >> top/left>bottom/right
23996 // Do not turn off border which is overridden
23997 // Needed for page break for TOP/BOTTOM both to be defined in Collapsed borders
23998 // Means it is painted twice. (Left/Right can still disable overridden border)
23999 if (!$table['borders_separate']) {
24000 if (($i < ($numrows - 1) || ($i + $crowsp) < $numrows ) && $fixbottom) { // Bottom
24001 for ($cspi = 0; $cspi < $ccolsp; $cspi++) {
24002 // already defined Top for adjacent cell below
24003 if (isset($cells[($i + $crowsp)][$j + $cspi])) {
24004 if ($this->packTableData) {
24005 $adjc = $cells[($i + $crowsp)][$j + $cspi];
24006 $celladj = $this->_unpackCellBorder($adjc['borderbin']);
24007 } else {
24008 $celladj = & $cells[($i + $crowsp)][$j + $cspi];
24009 }
24010 } else {
24011 $celladj = false;
24012 }
24013 if ($celladj && $celladj['border_details']['T']['s'] == 1) {
24014 $csadj = $celladj['border_details']['T']['w'];
24015 $csthis = $cbord['border_details']['B']['w'];
24016 // Hidden
24017 if ($cbord['border_details']['B']['style'] == 'hidden') {
24018 $celladj['border_details']['T'] = $cbord['border_details']['B'];
24019 $this->setBorder($celladj['border'], _BORDER_TOP, false);
24020 $this->setBorder($cbord['border'], _BORDER_BOTTOM, false);
24021 } elseif ($celladj['border_details']['T']['style'] == 'hidden') {
24022 $cbord['border_details']['B'] = $celladj['border_details']['T'];
24023 $this->setBorder($cbord['border'], _BORDER_BOTTOM, false);
24024 $this->setBorder($celladj['border'], _BORDER_TOP, false);
24025 }
24026 // Width
24027 elseif ($csthis > $csadj) {
24028 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
24029 $celladj['border_details']['T'] = $cbord['border_details']['B'];
24030 $this->setBorder($cbord['border'], _BORDER_BOTTOM);
24031 }
24032 } elseif ($csadj > $csthis) {
24033 if ($ccolsp < 2) { // don't overwrite this cell if it spans
24034 $cbord['border_details']['B'] = $celladj['border_details']['T'];
24035 $this->setBorder($celladj['border'], _BORDER_TOP);
24036 }
24037 }
24038
24039 // double>solid>dashed>dotted...
24040 elseif (array_search($cbord['border_details']['B']['style'], $this->borderstyles) > array_search($celladj['border_details']['T']['style'], $this->borderstyles)) {
24041 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
24042 $celladj['border_details']['T'] = $cbord['border_details']['B'];
24043 $this->setBorder($cbord['border'], _BORDER_BOTTOM);
24044 }
24045 } elseif (array_search($celladj['border_details']['T']['style'], $this->borderstyles) > array_search($cbord['border_details']['B']['style'], $this->borderstyles)) {
24046 if ($ccolsp < 2) { // don't overwrite this cell if it spans
24047 $cbord['border_details']['B'] = $celladj['border_details']['T'];
24048 $this->setBorder($celladj['border'], _BORDER_TOP);
24049 }
24050 }
24051
24052
24053
24054 // Style set on cell vs. table
24055 elseif ($celladj['border_details']['T']['dom'] > $cbord['border_details']['B']['dom']) {
24056 if ($ccolsp < 2) { // don't overwrite this cell if it spans
24057 $cbord['border_details']['B'] = $celladj['border_details']['T'];
24058 $this->setBorder($celladj['border'], _BORDER_TOP);
24059 }
24060 }
24061 // Style set on cell vs. table - OR - LEFT/TOP (cell) in preference to BOTTOM/RIGHT
24062 else {
24063 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
24064 $celladj['border_details']['T'] = $cbord['border_details']['B'];
24065 $this->setBorder($cbord['border'], _BORDER_BOTTOM);
24066 }
24067 }
24068 } elseif ($celladj) {
24069 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
24070 $celladj['border_details']['T'] = $cbord['border_details']['B'];
24071 }
24072 }
24073 // mPDF 5.7.4
24074 if ($celladj && $this->packTableData) {
24075 $cells[$i + $crowsp][$j + $cspi]['borderbin'] = $this->_packCellBorder($celladj);
24076 }
24077 unset($celladj);
24078 }
24079 }
24080
24081 if ($j < ($numcols - 1) || ($j + $ccolsp) < $numcols) { // Right-Left
24082 for ($cspi = 0; $cspi < $crowsp; $cspi++) {
24083 // already defined Left for adjacent cell to R
24084 if (isset($cells[($i + $cspi)][$j + $ccolsp])) {
24085 if ($this->packTableData) {
24086 $adjc = $cells[($i + $cspi)][$j + $ccolsp];
24087 $celladj = $this->_unpackCellBorder($adjc['borderbin']);
24088 } else {
24089 $celladj = & $cells[$i + $cspi][$j + $ccolsp];
24090 }
24091 } else {
24092 $celladj = false;
24093 }
24094 if ($celladj && $celladj['border_details']['L']['s'] == 1) {
24095 $csadj = $celladj['border_details']['L']['w'];
24096 $csthis = $cbord['border_details']['R']['w'];
24097 // Hidden
24098 if ($cbord['border_details']['R']['style'] == 'hidden') {
24099 $celladj['border_details']['L'] = $cbord['border_details']['R'];
24100 $this->setBorder($celladj['border'], _BORDER_LEFT, false);
24101 $this->setBorder($cbord['border'], _BORDER_RIGHT, false);
24102 } elseif ($celladj['border_details']['L']['style'] == 'hidden') {
24103 $cbord['border_details']['R'] = $celladj['border_details']['L'];
24104 $this->setBorder($cbord['border'], _BORDER_RIGHT, false);
24105 $this->setBorder($celladj['border'], _BORDER_LEFT, false);
24106 }
24107 // Width
24108 elseif ($csthis > $csadj) {
24109 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
24110 $celladj['border_details']['L'] = $cbord['border_details']['R'];
24111 $this->setBorder($cbord['border'], _BORDER_RIGHT);
24112 $this->setBorder($celladj['border'], _BORDER_LEFT, false);
24113 }
24114 } elseif ($csadj > $csthis) {
24115 if ($crowsp < 2) { // don't overwrite this cell if it spans
24116 $cbord['border_details']['R'] = $celladj['border_details']['L'];
24117 $this->setBorder($cbord['border'], _BORDER_RIGHT, false);
24118 $this->setBorder($celladj['border'], _BORDER_LEFT);
24119 }
24120 }
24121
24122 // double>solid>dashed>dotted...
24123 elseif (array_search($cbord['border_details']['R']['style'], $this->borderstyles) > array_search($celladj['border_details']['L']['style'], $this->borderstyles)) {
24124 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
24125 $celladj['border_details']['L'] = $cbord['border_details']['R'];
24126 $this->setBorder($celladj['border'], _BORDER_LEFT, false);
24127 $this->setBorder($cbord['border'], _BORDER_RIGHT);
24128 }
24129 } elseif (array_search($celladj['border_details']['L']['style'], $this->borderstyles) > array_search($cbord['border_details']['R']['style'], $this->borderstyles)) {
24130 if ($crowsp < 2) { // don't overwrite this cell if it spans
24131 $cbord['border_details']['R'] = $celladj['border_details']['L'];
24132 $this->setBorder($cbord['border'], _BORDER_RIGHT, false);
24133 $this->setBorder($celladj['border'], _BORDER_LEFT);
24134 }
24135 }
24136
24137
24138 // Style set on cell vs. table
24139 elseif ($celladj['border_details']['L']['dom'] > $cbord['border_details']['R']['dom']) {
24140 if ($crowsp < 2) { // don't overwrite this cell if it spans
24141 $cbord['border_details']['R'] = $celladj['border_details']['L'];
24142 $this->setBorder($celladj['border'], _BORDER_LEFT);
24143 }
24144 }
24145 // Style set on cell vs. table - OR - LEFT/TOP (cell) in preference to BOTTOM/RIGHT
24146 else {
24147 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
24148 $celladj['border_details']['L'] = $cbord['border_details']['R'];
24149 $this->setBorder($cbord['border'], _BORDER_RIGHT);
24150 }
24151 }
24152 } elseif ($celladj) {
24153 // if right-cell border is not set
24154 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
24155 $celladj['border_details']['L'] = $cbord['border_details']['R'];
24156 }
24157 }
24158 // mPDF 5.7.4
24159 if ($celladj && $this->packTableData) {
24160 $cells[$i + $cspi][$j + $ccolsp]['borderbin'] = $this->_packCellBorder($celladj);
24161 }
24162 unset($celladj);
24163 }
24164 }
24165 }
24166
24167
24168 // Set maximum cell border width meeting at LRTB edges of cell - used for extended cell border
24169 // ['border_details']['mbw']['LT'] = meeting border width - Left border - Top end
24170 if (!$table['borders_separate']) {
24171 $cbord['border_details']['mbw']['BL'] = max($cbord['border_details']['mbw']['BL'], $cbord['border_details']['L']['w']);
24172 $cbord['border_details']['mbw']['BR'] = max($cbord['border_details']['mbw']['BR'], $cbord['border_details']['R']['w']);
24173 $cbord['border_details']['mbw']['RT'] = max($cbord['border_details']['mbw']['RT'], $cbord['border_details']['T']['w']);
24174 $cbord['border_details']['mbw']['RB'] = max($cbord['border_details']['mbw']['RB'], $cbord['border_details']['B']['w']);
24175 $cbord['border_details']['mbw']['TL'] = max($cbord['border_details']['mbw']['TL'], $cbord['border_details']['L']['w']);
24176 $cbord['border_details']['mbw']['TR'] = max($cbord['border_details']['mbw']['TR'], $cbord['border_details']['R']['w']);
24177 $cbord['border_details']['mbw']['LT'] = max($cbord['border_details']['mbw']['LT'], $cbord['border_details']['T']['w']);
24178 $cbord['border_details']['mbw']['LB'] = max($cbord['border_details']['mbw']['LB'], $cbord['border_details']['B']['w']);
24179 if (($i + $crowsp) < $numrows && isset($cells[$i + $crowsp][$j])) { // Has Bottom adjoining cell
24180 if ($this->packTableData) {
24181 $adjc = $cells[$i + $crowsp][$j];
24182 $celladj = $this->_unpackCellBorder($adjc['borderbin']);
24183 } else {
24184 $celladj = & $cells[$i + $crowsp][$j];
24185 }
24186 $cbord['border_details']['mbw']['BL'] = max($cbord['border_details']['mbw']['BL'], $celladj['border_details']['L']['w'], $celladj['border_details']['mbw']['TL']);
24187 $cbord['border_details']['mbw']['BR'] = max($cbord['border_details']['mbw']['BR'], $celladj['border_details']['R']['w'], $celladj['border_details']['mbw']['TR']);
24188 $cbord['border_details']['mbw']['LB'] = max($cbord['border_details']['mbw']['LB'], $celladj['border_details']['mbw']['LT']);
24189 $cbord['border_details']['mbw']['RB'] = max($cbord['border_details']['mbw']['RB'], $celladj['border_details']['mbw']['RT']);
24190 unset($celladj);
24191 }
24192 if (($j + $ccolsp) < $numcols && isset($cells[$i][$j + $ccolsp])) { // Has Right adjoining cell
24193 if ($this->packTableData) {
24194 $adjc = $cells[$i][$j + $ccolsp];
24195 $celladj = $this->_unpackCellBorder($adjc['borderbin']);
24196 } else {
24197 $celladj = & $cells[$i][$j + $ccolsp];
24198 }
24199 $cbord['border_details']['mbw']['RT'] = max($cbord['border_details']['mbw']['RT'], $celladj['border_details']['T']['w'], $celladj['border_details']['mbw']['LT']);
24200 $cbord['border_details']['mbw']['RB'] = max($cbord['border_details']['mbw']['RB'], $celladj['border_details']['B']['w'], $celladj['border_details']['mbw']['LB']);
24201 $cbord['border_details']['mbw']['TR'] = max($cbord['border_details']['mbw']['TR'], $celladj['border_details']['mbw']['TL']);
24202 $cbord['border_details']['mbw']['BR'] = max($cbord['border_details']['mbw']['BR'], $celladj['border_details']['mbw']['BL']);
24203 unset($celladj);
24204 }
24205
24206 if ($i > 0 && isset($cells[$i - 1][$j]) && (($this->packTableData && $cells[$i - 1][$j]['borderbin']) || $cells[$i - 1][$j]['border'])) { // Has Top adjoining cell
24207 if ($this->packTableData) {
24208 $adjc = $cells[$i - 1][$j];
24209 $celladj = $this->_unpackCellBorder($adjc['borderbin']);
24210 } else {
24211 $celladj = & $cells[$i - 1][$j];
24212 }
24213 $cbord['border_details']['mbw']['TL'] = max($cbord['border_details']['mbw']['TL'], $celladj['border_details']['L']['w'], $celladj['border_details']['mbw']['BL']);
24214 $cbord['border_details']['mbw']['TR'] = max($cbord['border_details']['mbw']['TR'], $celladj['border_details']['R']['w'], $celladj['border_details']['mbw']['BR']);
24215 $cbord['border_details']['mbw']['LT'] = max($cbord['border_details']['mbw']['LT'], $celladj['border_details']['mbw']['LB']);
24216 $cbord['border_details']['mbw']['RT'] = max($cbord['border_details']['mbw']['RT'], $celladj['border_details']['mbw']['RB']);
24217
24218 if ($celladj['border_details']['mbw']['BL']) {
24219 $celladj['border_details']['mbw']['BL'] = max($cbord['border_details']['mbw']['TL'], $celladj['border_details']['mbw']['BL']);
24220 }
24221 if ($celladj['border_details']['mbw']['BR']) {
24222 $celladj['border_details']['mbw']['BR'] = max($celladj['border_details']['mbw']['BR'], $cbord['border_details']['mbw']['TR']);
24223 }
24224 if ($this->packTableData) {
24225 $cells[$i - 1][$j]['borderbin'] = $this->_packCellBorder($celladj);
24226 }
24227 unset($celladj);
24228 }
24229 if ($j > 0 && isset($cells[$i][$j - 1]) && (($this->packTableData && $cells[$i][$j - 1]['borderbin']) || $cells[$i][$j - 1]['border'])) { // Has Left adjoining cell
24230 if ($this->packTableData) {
24231 $adjc = $cells[$i][$j - 1];
24232 $celladj = $this->_unpackCellBorder($adjc['borderbin']);
24233 } else {
24234 $celladj = & $cells[$i][$j - 1];
24235 }
24236 $cbord['border_details']['mbw']['LT'] = max($cbord['border_details']['mbw']['LT'], $celladj['border_details']['T']['w'], $celladj['border_details']['mbw']['RT']);
24237 $cbord['border_details']['mbw']['LB'] = max($cbord['border_details']['mbw']['LB'], $celladj['border_details']['B']['w'], $celladj['border_details']['mbw']['RB']);
24238 $cbord['border_details']['mbw']['BL'] = max($cbord['border_details']['mbw']['BL'], $celladj['border_details']['mbw']['BR']);
24239 $cbord['border_details']['mbw']['TL'] = max($cbord['border_details']['mbw']['TL'], $celladj['border_details']['mbw']['TR']);
24240
24241 if ($celladj['border_details']['mbw']['RT']) {
24242 $celladj['border_details']['mbw']['RT'] = max($celladj['border_details']['mbw']['RT'], $cbord['border_details']['mbw']['LT']);
24243 }
24244 if ($celladj['border_details']['mbw']['RB']) {
24245 $celladj['border_details']['mbw']['RB'] = max($celladj['border_details']['mbw']['RB'], $cbord['border_details']['mbw']['LB']);
24246 }
24247 if ($this->packTableData) {
24248 $cells[$i][$j - 1]['borderbin'] = $this->_packCellBorder($celladj);
24249 }
24250 unset($celladj);
24251 }
24252
24253
24254 // Update maximum cell border width at LRTB edges of table - used for overall table width
24255 if ($j == 0 && $cbord['border_details']['L']['w']) {
24256 $table['max_cell_border_width']['L'] = max($table['max_cell_border_width']['L'], $cbord['border_details']['L']['w']);
24257 }
24258 if (($j == ($numcols - 1) || ($j + $ccolsp) == $numcols ) && $cbord['border_details']['R']['w']) {
24259 $table['max_cell_border_width']['R'] = max($table['max_cell_border_width']['R'], $cbord['border_details']['R']['w']);
24260 }
24261 if ($i == 0 && $cbord['border_details']['T']['w']) {
24262 $table['max_cell_border_width']['T'] = max($table['max_cell_border_width']['T'], $cbord['border_details']['T']['w']);
24263 }
24264 if (($i == ($numrows - 1) || ($i + $crowsp) == $numrows ) && $cbord['border_details']['B']['w']) {
24265 $table['max_cell_border_width']['B'] = max($table['max_cell_border_width']['B'], $cbord['border_details']['B']['w']);
24266 }
24267 }
24268 /* -- END TABLES-ADVANCED-BORDERS -- */
24269
24270 if ($this->packTableData) {
24271 $cell['borderbin'] = $this->_packCellBorder($cbord);
24272 }
24273
24274 unset($cbord);
24275
24276 unset($cell);
24277 }
24278 }
24279 }
24280 unset($cell);
24281 }
24282
24283 // END FIX BORDERS ************************************************************************************
24284
24285 function _reverseTableDir(&$table)
24286 {
24287 $cells = &$table['cells'];
24288 $numcols = $table['nc'];
24289 $numrows = $table['nr'];
24290 for ($i = 0; $i < $numrows; $i++) { //Rows
24291 $row = array();
24292 for ($j = ($numcols - 1); $j >= 0; $j--) { //Columns
24293 if (isset($cells[$i][$j]) && $cells[$i][$j]) {
24294 $cell = &$cells[$i][$j];
24295 $col = $numcols - $j - 1;
24296 if (isset($cell['colspan']) && $cell['colspan'] > 1) {
24297 $col -= ($cell['colspan'] - 1);
24298 }
24299 // Nested content
24300 if (isset($cell['textbuffer'])) {
24301 for ($n = 0; $n < count($cell['textbuffer']); $n++) {
24302 $t = $cell['textbuffer'][$n][0];
24303 if (substr($t, 0, 19) == "\xbb\xa4\xactype=nestedtable") {
24304 $objattr = $this->_getObjAttr($t);
24305 $objattr['col'] = $col;
24306 $cell['textbuffer'][$n][0] = "\xbb\xa4\xactype=nestedtable,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
24307 $this->table[($this->tableLevel + 1)][$objattr['nestedcontent']]['nestedpos'][1] = $col;
24308 }
24309 }
24310 }
24311 $row[$col] = $cells[$i][$j];
24312 unset($cell);
24313 }
24314 }
24315 for ($f = 0; $f < $numcols; $f++) {
24316 if (!isset($row[$f])) {
24317 $row[$f] = 0;
24318 }
24319 }
24320 $table['cells'][$i] = $row;
24321 }
24322 }
24323
24324 function _tableWrite(&$table, $split = false, $startrow = 0, $startcol = 0, $splitpg = 0, $rety = 0)
24325 {
24326 $level = $table['level'];
24327 $levelid = $table['levelid'];
24328
24329 $cells = &$table['cells'];
24330 $numcols = $table['nc'];
24331 $numrows = $table['nr'];
24332 $maxbwtop = 0;
24333 if ($this->ColActive && $level == 1) {
24334 $this->breakpoints[$this->CurrCol][] = $this->y;
24335 } // *COLUMNS*
24336
24337 if (!$split || ($startrow == 0 && $splitpg == 0) || $startrow > 0) {
24338 // TABLE TOP MARGIN
24339 if ($table['margin']['T']) {
24340 if (!$this->table_rotate && $level == 1) {
24341 $this->DivLn($table['margin']['T'], $this->blklvl, true, 1); // collapsible
24342 } else {
24343 $this->y += ($table['margin']['T']);
24344 }
24345 }
24346 // Advance down page by half width of top border
24347 if ($table['borders_separate']) {
24348 if ($startrow > 0 && (!isset($table['is_thead']) || count($table['is_thead']) == 0))
24349 $adv = $table['border_spacing_V'] / 2;
24350 else
24351 $adv = $table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2;
24352 }
24353 else {
24354 $adv = $table['max_cell_border_width']['T'] / 2;
24355 }
24356 if (!$this->table_rotate && $level == 1) {
24357 $this->DivLn($adv);
24358 } else {
24359 $this->y += $adv;
24360 }
24361 }
24362
24363 if ($level == 1) {
24364 $this->x = $this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['padding_left'] + $this->blk[$this->blklvl]['border_left']['w'];
24365 $x0 = $this->x;
24366 $y0 = $this->y;
24367 $right = $x0 + $this->blk[$this->blklvl]['inner_width'];
24368 $outerfilled = $this->y; // Keep track of how far down the outer DIV bgcolor is painted (NB rowspans)
24369 $this->outerfilled = $this->y;
24370 $this->colsums = array();
24371 } else {
24372 $x0 = $this->x;
24373 $y0 = $this->y;
24374 $right = $x0 + $table['w'];
24375 }
24376
24377 if ($this->table_rotate) {
24378 $temppgwidth = $this->tbrot_maxw;
24379 $this->PageBreakTrigger = $pagetrigger = $y0 + ($this->blk[$this->blklvl]['inner_width']);
24380 if ($level == 1) {
24381 $this->tbrot_y0 = $this->y - $adv - $table['margin']['T'];
24382 $this->tbrot_x0 = $this->x;
24383 $this->tbrot_w = $table['w'];
24384 if ($table['borders_separate']) {
24385 $this->tbrot_h = $table['margin']['T'] + $table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2;
24386 } else {
24387 $this->tbrot_h = $table['margin']['T'] + $table['padding']['T'] + $table['max_cell_border_width']['T'];
24388 }
24389 }
24390 } else {
24391 $this->PageBreakTrigger = $pagetrigger = ($this->h - $this->bMargin);
24392 if ($level == 1) {
24393 $temppgwidth = $this->blk[$this->blklvl]['inner_width'];
24394 if (isset($table['a']) and ( $table['w'] < $this->blk[$this->blklvl]['inner_width'])) {
24395 if ($table['a'] == 'C') {
24396 $x0 += ((($right - $x0) - $table['w']) / 2);
24397 } elseif ($table['a'] == 'R') {
24398 $x0 = $right - $table['w'];
24399 }
24400 }
24401 } else {
24402 $temppgwidth = $table['w'];
24403 }
24404 }
24405 if (!isset($table['overflow'])) {
24406 $table['overflow'] = null;
24407 }
24408 if ($table['overflow'] == 'hidden' && $level == 1 && !$this->table_rotate && !$this->ColActive) {
24409 //Bounding rectangle to clip
24410 $this->tableClipPath = sprintf('q %.3F %.3F %.3F %.3F re W n', $x0 * _MPDFK, $this->h * _MPDFK, $this->blk[$this->blklvl]['inner_width'] * _MPDFK, -$this->h * _MPDFK);
24411 $this->_out($this->tableClipPath);
24412 } else {
24413 $this->tableClipPath = '';
24414 }
24415
24416
24417 if ($table['borders_separate']) {
24418 $indent = $table['margin']['L'] + $table['border_details']['L']['w'] + $table['padding']['L'] + $table['border_spacing_H'] / 2;
24419 } else {
24420 $indent = $table['margin']['L'] + $table['max_cell_border_width']['L'] / 2;
24421 }
24422 $x0 += $indent;
24423
24424 $returny = 0;
24425 $lastCol = 0;
24426 $tableheader = array();
24427 $tablefooter = array();
24428 $tableheaderrowheight = 0;
24429 $tablefooterrowheight = 0;
24430 $footery = 0;
24431
24432 // mPD 3.0 Set the Page & Column where table starts
24433 if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
24434 $tablestartpage = 'EVEN';
24435 } elseif (($this->mirrorMargins) && (($this->page) % 2 == 1)) { // ODD
24436 $tablestartpage = 'ODD';
24437 } else {
24438 $tablestartpage = '';
24439 }
24440 if ($this->ColActive) {
24441 $tablestartcolumn = $this->CurrCol;
24442 } else {
24443 $tablestartcolumn = '';
24444 }
24445
24446 $y = $h = 0;
24447 for ($i = 0; $i < $numrows; $i++) { //Rows
24448 if ($this->progressBar) {
24449 $this->UpdateProgressBar(7, intval(30 + ($i * 40 / $numrows)), ' ');
24450 } // *PROGRESS-BAR*
24451 if (isset($table['is_tfoot'][$i]) && $table['is_tfoot'][$i] && $level == 1) {
24452 $tablefooterrowheight += $table['hr'][$i];
24453 $tablefooter[$i][0]['trbackground-images'] = $table['trbackground-images'][$i];
24454 $tablefooter[$i][0]['trgradients'] = $table['trgradients'][$i];
24455 $tablefooter[$i][0]['trbgcolor'] = $table['bgcolor'][$i];
24456 for ($j = $startcol; $j < $numcols; $j++) { //Columns
24457 if (isset($cells[$i][$j]) && $cells[$i][$j]) {
24458 $cell = &$cells[$i][$j];
24459 if ($split) {
24460 if ($table['colPg'][$j] != $splitpg) {
24461 continue;
24462 }
24463 list($x, $w) = $this->_splitTableGetWidth($table, $i, $j);
24464 $js = $j - $startcol;
24465 } else {
24466 list($x, $w) = $this->_tableGetWidth($table, $i, $j);
24467 $js = $j;
24468 }
24469
24470 list($y, $h) = $this->_tableGetHeight($table, $i, $j);
24471 $x += $x0;
24472 $y += $y0;
24473 //Get info of tfoot ==>> table footer
24474 $tablefooter[$i][$js]['x'] = $x;
24475 $tablefooter[$i][$js]['y'] = $y;
24476 $tablefooter[$i][$js]['h'] = $h;
24477 $tablefooter[$i][$js]['w'] = $w;
24478 if (isset($cell['textbuffer'])) {
24479 $tablefooter[$i][$js]['textbuffer'] = $cell['textbuffer'];
24480 } else {
24481 $tablefooter[$i][$js]['textbuffer'] = '';
24482 }
24483 $tablefooter[$i][$js]['a'] = $cell['a'];
24484 $tablefooter[$i][$js]['R'] = $cell['R'];
24485 $tablefooter[$i][$js]['va'] = $cell['va'];
24486 $tablefooter[$i][$js]['mih'] = $cell['mih'];
24487 if (isset($cell['gradient']))
24488 $tablefooter[$i][$js]['gradient'] = $cell['gradient']; // *BACKGROUNDS*
24489 if (isset($cell['background-image']))
24490 $tablefooter[$i][$js]['background-image'] = $cell['background-image']; // *BACKGROUNDS*
24491
24492 //CELL FILL BGCOLOR
24493 if (!$this->simpleTables) {
24494 if ($this->packTableData) {
24495 $c = $this->_unpackCellBorder($cell['borderbin']);
24496 $tablefooter[$i][$js]['border'] = $c['border'];
24497 $tablefooter[$i][$js]['border_details'] = $c['border_details'];
24498 } else {
24499 $tablefooter[$i][$js]['border'] = $cell['border'];
24500 $tablefooter[$i][$js]['border_details'] = $cell['border_details'];
24501 }
24502 } elseif ($this->simpleTables) {
24503 $tablefooter[$i][$js]['border'] = $table['simple']['border'];
24504 $tablefooter[$i][$js]['border_details'] = $table['simple']['border_details'];
24505 }
24506 $tablefooter[$i][$js]['bgcolor'] = $cell['bgcolor'];
24507 $tablefooter[$i][$js]['padding'] = $cell['padding'];
24508 if (isset($cell['rowspan']))
24509 $tablefooter[$i][$js]['rowspan'] = $cell['rowspan'];
24510 if (isset($cell['colspan']))
24511 $tablefooter[$i][$js]['colspan'] = $cell['colspan'];
24512 if (isset($cell['direction']))
24513 $tablefooter[$i][$js]['direction'] = $cell['direction'];
24514 if (isset($cell['cellLineHeight']))
24515 $tablefooter[$i][$js]['cellLineHeight'] = $cell['cellLineHeight'];
24516 if (isset($cell['cellLineStackingStrategy']))
24517 $tablefooter[$i][$js]['cellLineStackingStrategy'] = $cell['cellLineStackingStrategy'];
24518 if (isset($cell['cellLineStackingShift']))
24519 $tablefooter[$i][$js]['cellLineStackingShift'] = $cell['cellLineStackingShift'];
24520 }
24521 }
24522 }
24523 }
24524
24525 if ($level == 1) {
24526 $this->_out('___TABLE___BACKGROUNDS' . $this->uniqstr);
24527 }
24528 $tableheaderadj = 0;
24529 $tablefooteradj = 0;
24530
24531 $tablestartpageno = $this->page;
24532
24533 //Draw Table Contents and Borders
24534 for ($i = 0; $i < $numrows; $i++) { //Rows
24535 if ($split && $startrow > 0) {
24536 $thnr = (isset($table['is_thead']) ? count($table['is_thead']) : 0);
24537 if ($i >= $thnr && $i < $startrow) {
24538 continue;
24539 }
24540 if ($i == $startrow) {
24541 $returny = $rety - $tableheaderrowheight;
24542 }
24543 }
24544
24545 // Get Maximum row/cell height in row - including rowspan>1 + 1 overlapping
24546 $maxrowheight = $this->_tableGetMaxRowHeight($table, $i);
24547
24548 $skippage = false;
24549 $newpagestarted = false;
24550 for ($j = $startcol; $j < $numcols; $j++) { //Columns
24551 if ($split) {
24552 if ($table['colPg'][$j] > $splitpg) {
24553 break;
24554 }
24555 $lastCol = $j;
24556 }
24557 if (isset($cells[$i][$j]) && $cells[$i][$j]) {
24558 $cell = &$cells[$i][$j];
24559 if ($split) {
24560 $lastCol = $j + (isset($cell['colspan']) ? ($cell['colspan'] - 1) : 0);
24561 list($x, $w) = $this->_splitTableGetWidth($table, $i, $j);
24562 } else {
24563 list($x, $w) = $this->_tableGetWidth($table, $i, $j);
24564 }
24565
24566 list($y, $h) = $this->_tableGetHeight($table, $i, $j);
24567 $x += $x0;
24568 $y += $y0;
24569 $y -= $returny;
24570
24571 if ($table['borders_separate']) {
24572 if (!empty($tablefooter) || $i == ($numrows - 1) || (isset($cell['rowspan']) && ($i + $cell['rowspan']) == $numrows) || (!isset($cell['rowspan']) && ($i + 1) == $numrows)) {
24573 $extra = $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
24574 //$extra = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V']/2;
24575 } else {
24576 $extra = $table['border_spacing_V'] / 2;
24577 }
24578 } else {
24579 $extra = $table['max_cell_border_width']['B'] / 2;
24580 }
24581
24582 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) {
24583
24584 if (!$skippage) {
24585 $finalSpread = true;
24586 $firstSpread = true;
24587 if ($split) {
24588 for ($t = $startcol; $t < $numcols; $t++) {
24589 // Are there more columns to print on a next page?
24590 if ($table['colPg'][$t] > $splitpg) {
24591 $finalSpread = false;
24592 break;
24593 }
24594 }
24595 if ($startcol > 0) {
24596 $firstSpread = false;
24597 }
24598 }
24599
24600 if (($this->keepColumns || !$this->ColActive) && !empty($tablefooter) && $i > 0) {
24601 $this->y = $y;
24602 $ya = $this->y;
24603 $this->TableHeaderFooter($tablefooter, $tablestartpage, $tablestartcolumn, 'F', $level, $firstSpread, $finalSpread);
24604 if ($this->table_rotate) {
24605 $this->tbrot_h += $this->y - $ya;
24606 }
24607 $tablefooteradj = $this->y - $ya;
24608 }
24609 $y -= $y0;
24610 $returny += $y;
24611
24612 $oldcolumn = $this->CurrCol;
24613 if ($this->AcceptPageBreak()) {
24614 $newpagestarted = true;
24615 $this->y = $y + $y0;
24616
24617 // Move down to account for border-spacing or
24618 // extra half border width in case page breaks in middle
24619 if ($i > 0 && !$this->table_rotate && $level == 1 && !$this->ColActive) {
24620 if ($table['borders_separate']) {
24621 $adv = $table['border_spacing_V'] / 2;
24622 // If table footer
24623 if (($this->keepColumns || !$this->ColActive) && !empty($tablefooter) && $i > 0) {
24624 $adv += ($table['padding']['B'] + $table['border_details']['B']['w']);
24625 }
24626 } else {
24627 $maxbwtop = 0;
24628 $maxbwbottom = 0;
24629 if (!$this->simpleTables) {
24630 if (!empty($tablefooter)) {
24631 $maxbwbottom = $table['max_cell_border_width']['B'];
24632 } else {
24633 $brow = $i - 1;
24634 for ($ctj = 0; $ctj < $numcols; $ctj++) {
24635 if (isset($cells[$brow][$ctj]) && $cells[$brow][$ctj]) {
24636 if ($this->packTableData) {
24637 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cells[$brow][$ctj]['borderbin']);
24638 } else {
24639 $bb = $cells[$brow][$ctj]['border_details']['B']['w'];
24640 }
24641 $maxbwbottom = max($maxbwbottom, $bb);
24642 }
24643 }
24644 }
24645 if (!empty($tableheader)) {
24646 $maxbwtop = $table['max_cell_border_width']['T'];
24647 } else {
24648 $trow = $i - 1;
24649 for ($ctj = 0; $ctj < $numcols; $ctj++) {
24650 if (isset($cells[$trow][$ctj]) && $cells[$trow][$ctj]) {
24651 if ($this->packTableData) {
24652 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cells[$trow][$ctj]['borderbin']);
24653 } else {
24654 $bt = $cells[$trow][$ctj]['border_details']['T']['w'];
24655 }
24656 $maxbwtop = max($maxbwtop, $bt);
24657 }
24658 }
24659 }
24660 } elseif ($this->simpleTables) {
24661 $maxbwtop = $table['simple']['border_details']['T']['w'];
24662 $maxbwbottom = $table['simple']['border_details']['B']['w'];
24663 }
24664 $adv = $maxbwbottom / 2;
24665 }
24666 $this->y += $adv;
24667 }
24668
24669 // Rotated table split over pages - needs this->y for borders/backgrounds
24670 if ($i > 0 && $this->table_rotate && $level == 1) {
24671 // $this->y = $y0 + $this->tbrot_w;
24672 }
24673
24674 if ($this->tableClipPath) {
24675 $this->_out("Q");
24676 }
24677
24678 $bx = $x0;
24679 $by = $y0;
24680
24681 if ($table['borders_separate']) {
24682 $bx -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['border_spacing_H'] / 2);
24683 if ($tablestartpageno != $this->page) { // IF already broken across a previous pagebreak
24684 $by += $table['max_cell_border_width']['T'] / 2;
24685 if (empty($tableheader)) {
24686 $by -= ($table['border_spacing_V'] / 2);
24687 }
24688 } else {
24689 $by -= ($table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2);
24690 }
24691 } elseif ($tablestartpageno != $this->page && !empty($tableheader)) {
24692 $by += $maxbwtop / 2;
24693 }
24694
24695 $by -= $tableheaderadj;
24696 $bh = $this->y - $by + $tablefooteradj;
24697 if (!$table['borders_separate']) {
24698 $bh -= $adv;
24699 }
24700 if ($split) {
24701 $bw = 0;
24702 for ($t = $startcol; $t < $numcols; $t++) {
24703 if ($table['colPg'][$t] == $splitpg) {
24704 $bw += $table['wc'][$t];
24705 }
24706 if ($table['colPg'][$t] > $splitpg) {
24707 break;
24708 }
24709 }
24710 if ($table['borders_separate']) {
24711 if ($firstSpread) {
24712 $bw += $table['padding']['L'] + $table['border_details']['L']['w'] + $table['border_spacing_H'];
24713 } else {
24714 $bx += ($table['padding']['L'] + $table['border_details']['L']['w']);
24715 $bw += $table['border_spacing_H'];
24716 }
24717 if ($finalSpread) {
24718 $bw += $table['padding']['R'] + $table['border_details']['R']['w'] / 2 + $table['border_spacing_H'];
24719 }
24720 }
24721 } else {
24722 $bw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
24723 }
24724
24725 if ($this->splitTableBorderWidth && ($this->keepColumns || !$this->ColActive) && empty($tablefooter) && $i > 0 && $table['border_details']['B']['w']) {
24726 $prevDrawColor = $this->DrawColor;
24727 $lw = $this->LineWidth;
24728 $this->SetLineWidth($this->splitTableBorderWidth);
24729 $this->SetDColor($table['border_details']['B']['c']);
24730 $this->SetLineJoin(0);
24731 $this->SetLineCap(0);
24732 $blx = $bx;
24733 $blw = $bw;
24734 if (!$table['borders_separate']) {
24735 $blx -= ($table['max_cell_border_width']['L'] / 2);
24736 $blw += ($table['max_cell_border_width']['L'] / 2 + $table['max_cell_border_width']['R'] / 2);
24737 }
24738 $this->Line($blx, $this->y + ($this->splitTableBorderWidth / 2), $blx + $blw, $this->y + ($this->splitTableBorderWidth / 2));
24739 $this->DrawColor = $prevDrawColor;
24740 $this->_out($this->DrawColor);
24741 $this->SetLineWidth($lw);
24742 $this->SetLineJoin(2);
24743 $this->SetLineCap(2);
24744 }
24745
24746 if (!$this->ColActive && ($i > 0 || $j > 0)) {
24747 if (isset($table['bgcolor'][-1])) {
24748 $color = $this->ConvertColor($table['bgcolor'][-1]);
24749 if ($color) {
24750 if (!$table['borders_separate']) {
24751 $bh -= $table['max_cell_border_width']['B'] / 2;
24752 }
24753 $this->tableBackgrounds[$level * 9][] = array('gradient' => false, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'col' => $color);
24754 }
24755 }
24756
24757 /* -- BACKGROUNDS -- */
24758 if (isset($table['gradient'])) {
24759 $g = $this->grad->parseBackgroundGradient($table['gradient']);
24760 if ($g) {
24761 $this->tableBackgrounds[$level * 9 + 1][] = array('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' => '');
24762 }
24763 }
24764
24765 if (isset($table['background-image'])) {
24766 if ($table['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $table['background-image']['gradient'])) {
24767 $g = $this->grad->parseMozGradient($table['background-image']['gradient']);
24768 if ($g) {
24769 $this->tableBackgrounds[$level * 9 + 1][] = array('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' => '');
24770 }
24771 } else {
24772 $image_id = $table['background-image']['image_id'];
24773 $orig_w = $table['background-image']['orig_w'];
24774 $orig_h = $table['background-image']['orig_h'];
24775 $x_pos = $table['background-image']['x_pos'];
24776 $y_pos = $table['background-image']['y_pos'];
24777 $x_repeat = $table['background-image']['x_repeat'];
24778 $y_repeat = $table['background-image']['y_repeat'];
24779 $resize = $table['background-image']['resize'];
24780 $opacity = $table['background-image']['opacity'];
24781 $itype = $table['background-image']['itype'];
24782 $this->tableBackgrounds[$level * 9 + 2][] = array('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);
24783 }
24784 }
24785 /* -- END BACKGROUNDS -- */
24786 }
24787
24788 // $this->AcceptPageBreak() has moved tablebuffer to $this->pages content
24789 if ($this->tableBackgrounds) {
24790 $s = $this->PrintTableBackgrounds();
24791 if ($this->bufferoutput) {
24792 $this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->headerbuffer);
24793 $this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->headerbuffer);
24794 } else {
24795 $this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
24796 $this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->pages[$this->page]);
24797 }
24798 $this->tableBackgrounds = array();
24799 }
24800
24801 if ($split) {
24802 if ($i == 0 && $j == 0) {
24803 $y0 = -1;
24804 } elseif ($finalSpread) {
24805 $splitpg = 0;
24806 $startcol = 0;
24807 $startrow = $i;
24808 } else {
24809 $splitpg++;
24810 $startcol = $t;
24811 $returny -= $y;
24812 }
24813 return array(false, $startrow, $startcol, $splitpg, $returny, $y0);
24814 }
24815
24816 $this->AddPage($this->CurOrientation);
24817
24818 $this->_out('___TABLE___BACKGROUNDS' . $this->uniqstr);
24819
24820
24821 if ($this->tableClipPath) {
24822 $this->_out($this->tableClipPath);
24823 }
24824
24825 // Added to correct for OddEven Margins
24826 $x = $x + $this->MarginCorrection;
24827 $x0 = $x0 + $this->MarginCorrection;
24828
24829 if ($this->splitTableBorderWidth && ($this->keepColumns || !$this->ColActive) && empty($tableheader) && $i > 0 && $table['border_details']['T']['w']) {
24830 $prevDrawColor = $this->DrawColor;
24831 $lw = $this->LineWidth;
24832 $this->SetLineWidth($this->splitTableBorderWidth);
24833 $this->SetDColor($table['border_details']['T']['c']);
24834 $this->SetLineJoin(0);
24835 $this->SetLineCap(0);
24836 $blx += $this->MarginCorrection;
24837 $this->Line($blx, $this->y - ($this->splitTableBorderWidth / 2), $blx + $blw, $this->y - ($this->splitTableBorderWidth / 2));
24838 $this->DrawColor = $prevDrawColor;
24839 $this->_out($this->DrawColor);
24840 $this->SetLineWidth($lw);
24841 $this->SetLineJoin(2);
24842 $this->SetLineCap(2);
24843 }
24844
24845 // Move down to account for half of top border-spacing or
24846 // extra half border width in case page was broken in middle
24847 if ($i > 0 && !$this->table_rotate && $level == 1 && $table['headernrows'] == 0) {
24848 if ($table['borders_separate']) {
24849 $adv = $table['border_spacing_V'] / 2;
24850 } else {
24851 $maxbwtop = 0;
24852 for ($ctj = 0; $ctj < $numcols; $ctj++) {
24853 if (isset($cells[$i][$ctj]) && $cells[$i][$ctj]) {
24854 if (!$this->simpleTables) {
24855 if ($this->packTableData) {
24856 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cells[$i][$ctj]['borderbin']);
24857 } else {
24858 $bt = $cells[$i][$ctj]['border_details']['T']['w'];
24859 }
24860 $maxbwtop = max($maxbwtop, $bt);
24861 } elseif ($this->simpleTables) {
24862 $maxbwtop = max($maxbwtop, $table['simple']['border_details']['T']['w']);
24863 }
24864 }
24865 }
24866 $adv = $maxbwtop / 2;
24867 }
24868 $this->y += $adv;
24869 }
24870
24871
24872 if ($this->table_rotate) {
24873 $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'];
24874 if ($table['borders_separate']) {
24875 $this->tbrot_h = $table['margin']['T'] + $table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2;
24876 } else {
24877 $this->tbrot_h = $table['margin']['T'] + $table['max_cell_border_width']['T'];
24878 }
24879 $this->tbrot_y0 = $this->y;
24880 $pagetrigger = $y0 - $tableheaderadj + ($this->blk[$this->blklvl]['inner_width']);
24881 } else {
24882 $pagetrigger = $this->PageBreakTrigger;
24883 }
24884
24885 if ($this->kwt_saved && $level == 1) {
24886 $this->kwt_moved = true;
24887 }
24888
24889
24890 if (!empty($tableheader)) {
24891 $ya = $this->y;
24892 $this->TableHeaderFooter($tableheader, $tablestartpage, $tablestartcolumn, 'H', $level);
24893 if ($this->table_rotate) {
24894 $this->tbrot_h = $this->y - $ya;
24895 }
24896 $tableheaderadj = $this->y - $ya;
24897 } elseif ($i == 0 && !$this->table_rotate && $level == 1 && !$this->ColActive) {
24898 // Advance down page
24899 if ($table['borders_separate']) {
24900 $adv = $table['border_spacing_V'] / 2 + $table['border_details']['T']['w'] + $table['padding']['T'];
24901 } else {
24902 $adv = $table['max_cell_border_width']['T'] / 2;
24903 }
24904 if ($adv) {
24905 if ($this->table_rotate) {
24906 $this->y += ($adv);
24907 } else {
24908 $this->DivLn($adv, $this->blklvl, true);
24909 }
24910 }
24911 }
24912
24913 $outerfilled = 0;
24914 $y = $y0 = $this->y;
24915 }
24916
24917 /* -- COLUMNS -- */
24918 // COLS
24919 // COLUMN CHANGE
24920 if ($this->CurrCol != $oldcolumn) {
24921 // Added to correct for Columns
24922 $x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
24923 $x0 += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
24924 if ($this->CurrCol == 0) { // just added a page - possibly with tableheader
24925 $y0 = $this->y; // this->y0 is global used by Columns - $y0 is internal to tablewrite
24926 } else {
24927 $y0 = $this->y0; // this->y0 is global used by Columns - $y0 is internal to tablewrite
24928 }
24929 $y = $y0;
24930 $outerfilled = 0;
24931 if ($this->CurrCol != 0 && ($this->keepColumns && $this->ColActive) && !empty($tableheader) && $i > 0) {
24932 $this->x = $x;
24933 $this->y = $y;
24934 $this->TableHeaderFooter($tableheader, $tablestartpage, $tablestartcolumn, 'H', $level);
24935 $y0 = $y = $this->y;
24936 }
24937 }
24938 /* -- END COLUMNS -- */
24939 }
24940 $skippage = true;
24941 }
24942
24943 $this->x = $x;
24944 $this->y = $y;
24945
24946 if ($this->kwt_saved && $level == 1) {
24947 $this->printkwtbuffer();
24948 $x0 = $x = $this->x;
24949 $y0 = $y = $this->y;
24950 $this->kwt_moved = false;
24951 $this->kwt_saved = false;
24952 }
24953
24954
24955 // Set the Page & Column where table actually starts
24956 if ($i == 0 && $j == 0 && $level == 1) {
24957 if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
24958 $tablestartpage = 'EVEN';
24959 } elseif (($this->mirrorMargins) && (($this->page) % 2 == 1)) { // ODD
24960 $tablestartpage = 'ODD';
24961 } else {
24962 $tablestartpage = '';
24963 }
24964 $tablestartpageno = $this->page;
24965 if ($this->ColActive) {
24966 $tablestartcolumn = $this->CurrCol;
24967 } // *COLUMNS*
24968 }
24969
24970
24971 //ALIGN
24972 $align = $cell['a'];
24973
24974
24975 /* -- COLUMNS -- */
24976 // If outside columns, this is done in PaintDivBB
24977 if ($this->ColActive) {
24978 //OUTER FILL BGCOLOR of DIVS
24979 if ($this->blklvl > 0 && ($j == 0) && !$this->table_rotate && $level == 1) {
24980 $firstblockfill = $this->GetFirstBlockFill();
24981 if ($firstblockfill && $this->blklvl >= $firstblockfill) {
24982 $divh = $maxrowheight;
24983 // Last row
24984 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)))) {
24985 if ($table['borders_separate']) {
24986 $adv = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
24987 } else {
24988 $adv = $table['margin']['B'] + $table['max_cell_border_width']['B'] / 2;
24989 }
24990 $divh += $adv; //last row: fill bottom half of bottom border (y advanced at end)
24991 }
24992
24993 if (($this->y + $divh) > $outerfilled) { // if not already painted by previous rowspan
24994 $bak_x = $this->x;
24995 $bak_y = $this->y;
24996 if ($outerfilled > $this->y) {
24997 $divh = ($this->y + $divh) - $outerfilled;
24998 $this->y = $outerfilled;
24999 }
25000
25001 $this->DivLn($divh, -3, false);
25002 $outerfilled = $this->y + $divh;
25003 // Reset current block fill
25004 $bcor = $this->blk[$this->blklvl]['bgcolorarray'];
25005 if ($bcor)
25006 $this->SetFColor($bcor);
25007 $this->x = $bak_x;
25008 $this->y = $bak_y;
25009 }
25010 }
25011 }
25012 }
25013
25014
25015 //TABLE BACKGROUND FILL BGCOLOR - for cellSpacing
25016 if ($this->ColActive) {
25017 if ($table['borders_separate']) {
25018 $fill = isset($table['bgcolor'][-1]) ? $table['bgcolor'][-1] : 0;
25019 if ($fill) {
25020 $color = $this->ConvertColor($fill);
25021 if ($color) {
25022 $xadj = ($table['border_spacing_H'] / 2);
25023 $yadj = ($table['border_spacing_V'] / 2);
25024 $wadj = $table['border_spacing_H'];
25025 $hadj = $table['border_spacing_V'];
25026 if ($i == 0) { // Top
25027 $yadj += $table['padding']['T'] + $table['border_details']['T']['w'];
25028 $hadj += $table['padding']['T'] + $table['border_details']['T']['w'];
25029 }
25030 if ($j == 0) { // Left
25031 $xadj += $table['padding']['L'] + $table['border_details']['L']['w'];
25032 $wadj += $table['padding']['L'] + $table['border_details']['L']['w'];
25033 }
25034 if ($i == ($numrows - 1) || (isset($cell['rowspan']) && ($i + $cell['rowspan']) == $numrows) || (!isset($cell['rowspan']) && ($i + 1) == $numrows)) { // Bottom
25035 $hadj += $table['padding']['B'] + $table['border_details']['B']['w'];
25036 }
25037 if ($j == ($numcols - 1) || (isset($cell['colspan']) && ($j + $cell['colspan']) == $numcols) || (!isset($cell['colspan']) && ($j + 1) == $numcols)) { // Right
25038 $wadj += $table['padding']['R'] + $table['border_details']['R']['w'];
25039 }
25040 $this->SetFColor($color);
25041 $this->Rect($x - $xadj, $y - $yadj, $w + $wadj, $h + $hadj, 'F');
25042 }
25043 }
25044 }
25045 }
25046 /* -- END COLUMNS -- */
25047
25048 if ($table['empty_cells'] != 'hide' || !empty($cell['textbuffer']) || (isset($cell['nestedcontent']) && $cell['nestedcontent']) || !$table['borders_separate']) {
25049 $paintcell = true;
25050 } else {
25051 $paintcell = false;
25052 }
25053
25054 //Set Borders
25055 $bord = 0;
25056 $bord_det = array();
25057
25058 if (!$this->simpleTables) {
25059 if ($this->packTableData) {
25060 $c = $this->_unpackCellBorder($cell['borderbin']);
25061 $bord = $c['border'];
25062 $bord_det = $c['border_details'];
25063 } else {
25064 $bord = $cell['border'];
25065 $bord_det = $cell['border_details'];
25066 }
25067 } elseif ($this->simpleTables) {
25068 $bord = $table['simple']['border'];
25069 $bord_det = $table['simple']['border_details'];
25070 }
25071
25072 //TABLE ROW OR CELL FILL BGCOLOR
25073 $fill = 0;
25074 if (isset($cell['bgcolor']) && $cell['bgcolor'] && $cell['bgcolor'] != 'transparent') {
25075 $fill = $cell['bgcolor'];
25076 $leveladj = 6;
25077 } elseif (isset($table['bgcolor'][$i]) && $table['bgcolor'][$i] && $table['bgcolor'][$i] != 'transparent') { // Row color
25078 $fill = $table['bgcolor'][$i];
25079 $leveladj = 3;
25080 }
25081 if ($fill && $paintcell) {
25082 $color = $this->ConvertColor($fill);
25083 if ($color) {
25084 if ($table['borders_separate']) {
25085 if ($this->ColActive) {
25086 $this->SetFColor($color);
25087 $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');
25088 } else {
25089 $this->tableBackgrounds[$level * 9 + $leveladj][] = array('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);
25090 }
25091 } else {
25092 if ($this->ColActive) {
25093 $this->SetFColor($color);
25094 $this->Rect($x, $y, $w, $h, 'F');
25095 } else {
25096 $this->tableBackgrounds[$level * 9 + $leveladj][] = array('gradient' => false, 'x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'col' => $color);
25097 }
25098 }
25099 }
25100 }
25101
25102 /* -- BACKGROUNDS -- */
25103 if (isset($cell['gradient']) && $cell['gradient'] && $paintcell) {
25104 $g = $this->grad->parseBackgroundGradient($cell['gradient']);
25105 if ($g) {
25106 if ($table['borders_separate']) {
25107 $px = $x + ($table['border_spacing_H'] / 2);
25108 $py = $y + ($table['border_spacing_V'] / 2);
25109 $pw = $w - $table['border_spacing_H'];
25110 $ph = $h - $table['border_spacing_V'];
25111 } else {
25112 $px = $x;
25113 $py = $y;
25114 $pw = $w;
25115 $ph = $h;
25116 }
25117 if ($this->ColActive) {
25118 $this->grad->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
25119 } else {
25120 $this->tableBackgrounds[$level * 9 + 7][] = array('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' => '');
25121 }
25122 }
25123 }
25124
25125 if (isset($cell['background-image']) && $paintcell) {
25126 if (isset($cell['background-image']['gradient']) && $cell['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $cell['background-image']['gradient'])) {
25127 $g = $this->grad->parseMozGradient($cell['background-image']['gradient']);
25128 if ($g) {
25129 if ($table['borders_separate']) {
25130 $px = $x + ($table['border_spacing_H'] / 2);
25131 $py = $y + ($table['border_spacing_V'] / 2);
25132 $pw = $w - $table['border_spacing_H'];
25133 $ph = $h - $table['border_spacing_V'];
25134 } else {
25135 $px = $x;
25136 $py = $y;
25137 $pw = $w;
25138 $ph = $h;
25139 }
25140 if ($this->ColActive) {
25141 $this->grad->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
25142 } else {
25143 $this->tableBackgrounds[$level * 9 + 7][] = array('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' => '');
25144 }
25145 }
25146 } elseif (isset($cell['background-image']['image_id']) && $cell['background-image']['image_id']) { // Background pattern
25147 $n = count($this->patterns) + 1;
25148 if ($table['borders_separate']) {
25149 $px = $x + ($table['border_spacing_H'] / 2);
25150 $py = $y + ($table['border_spacing_V'] / 2);
25151 $pw = $w - $table['border_spacing_H'];
25152 $ph = $h - $table['border_spacing_V'];
25153 } else {
25154 $px = $x;
25155 $py = $y;
25156 $pw = $w;
25157 $ph = $h;
25158 }
25159 if ($this->ColActive) {
25160 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']);
25161 $this->patterns[$n] = array('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);
25162 if ($cell['background-image']['opacity'] > 0 && $cell['background-image']['opacity'] < 1) {
25163 $opac = $this->SetAlpha($cell['background-image']['opacity'], 'Normal', true);
25164 } else {
25165 $opac = '';
25166 }
25167 $this->_out(sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $px * _MPDFK, ($this->h - $py) * _MPDFK, $pw * _MPDFK, -$ph * _MPDFK));
25168 } else {
25169 $image_id = $cell['background-image']['image_id'];
25170 $orig_w = $cell['background-image']['orig_w'];
25171 $orig_h = $cell['background-image']['orig_h'];
25172 $x_pos = $cell['background-image']['x_pos'];
25173 $y_pos = $cell['background-image']['y_pos'];
25174 $x_repeat = $cell['background-image']['x_repeat'];
25175 $y_repeat = $cell['background-image']['y_repeat'];
25176 $resize = $cell['background-image']['resize'];
25177 $opacity = $cell['background-image']['opacity'];
25178 $itype = $cell['background-image']['itype'];
25179 $this->tableBackgrounds[$level * 9 + 8][] = array('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);
25180 }
25181 }
25182 }
25183 /* -- END BACKGROUNDS -- */
25184
25185 if (isset($cell['colspan']) && $cell['colspan'] > 1) {
25186 $ccolsp = $cell['colspan'];
25187 } else {
25188 $ccolsp = 1;
25189 }
25190 if (isset($cell['rowspan']) && $cell['rowspan'] > 1) {
25191 $crowsp = $cell['rowspan'];
25192 } else {
25193 $crowsp = 1;
25194 }
25195
25196
25197 // but still need to do this for repeated headers...
25198 if (!$table['borders_separate'] && $this->tabletheadjustfinished && !$this->simpleTables) {
25199 if (isset($table['topntail']) && $table['topntail']) {
25200 $bord_det['T'] = $this->border_details($table['topntail']);
25201 $bord_det['T']['w'] /= $this->shrin_k;
25202 $this->setBorder($bord, _BORDER_TOP);
25203 }
25204 if (isset($table['thead-underline']) && $table['thead-underline']) {
25205 $bord_det['T'] = $this->border_details($table['thead-underline']);
25206 $bord_det['T']['w'] /= $this->shrin_k;
25207 $this->setBorder($bord, _BORDER_TOP);
25208 }
25209 }
25210
25211
25212 //Get info of first row ==>> table header
25213 //Use > 1 row if THEAD
25214 if (isset($table['is_thead'][$i]) && $table['is_thead'][$i] && $level == 1) {
25215 if ($j == 0)
25216 $tableheaderrowheight += $table['hr'][$i];
25217 $tableheader[$i][0]['trbackground-images'] = (isset($table['trbackground-images'][$i]) ? $table['trbackground-images'][$i] : null);
25218 $tableheader[$i][0]['trgradients'] = (isset($table['trgradients'][$i]) ? $table['trgradients'][$i] : null);
25219 $tableheader[$i][0]['trbgcolor'] = (isset($table['bgcolor'][$i]) ? $table['bgcolor'][$i] : null);
25220 $tableheader[$i][$j]['x'] = $x;
25221 $tableheader[$i][$j]['y'] = $y;
25222 $tableheader[$i][$j]['h'] = $h;
25223 $tableheader[$i][$j]['w'] = $w;
25224 if (isset($cell['textbuffer'])) {
25225 $tableheader[$i][$j]['textbuffer'] = $cell['textbuffer'];
25226 } else {
25227 $tableheader[$i][$j]['textbuffer'] = '';
25228 }
25229 $tableheader[$i][$j]['a'] = $cell['a'];
25230 $tableheader[$i][$j]['R'] = $cell['R'];
25231
25232 $tableheader[$i][$j]['va'] = $cell['va'];
25233 $tableheader[$i][$j]['mih'] = $cell['mih'];
25234 $tableheader[$i][$j]['gradient'] = (isset($cell['gradient']) ? $cell['gradient'] : null); // *BACKGROUNDS*
25235 $tableheader[$i][$j]['background-image'] = (isset($cell['background-image']) ? $cell['background-image'] : null); // *BACKGROUNDS*
25236 $tableheader[$i][$j]['rowspan'] = (isset($cell['rowspan']) ? $cell['rowspan'] : null);
25237 $tableheader[$i][$j]['colspan'] = (isset($cell['colspan']) ? $cell['colspan'] : null);
25238 $tableheader[$i][$j]['bgcolor'] = $cell['bgcolor'];
25239
25240 if (!$this->simpleTables) {
25241 $tableheader[$i][$j]['border'] = $bord;
25242 $tableheader[$i][$j]['border_details'] = $bord_det;
25243 } elseif ($this->simpleTables) {
25244 $tableheader[$i][$j]['border'] = $table['simple']['border'];
25245 $tableheader[$i][$j]['border_details'] = $table['simple']['border_details'];
25246 }
25247 $tableheader[$i][$j]['padding'] = $cell['padding'];
25248 if (isset($cell['direction']))
25249 $tableheader[$i][$j]['direction'] = $cell['direction'];
25250 if (isset($cell['cellLineHeight']))
25251 $tableheader[$i][$j]['cellLineHeight'] = $cell['cellLineHeight'];
25252 if (isset($cell['cellLineStackingStrategy']))
25253 $tableheader[$i][$j]['cellLineStackingStrategy'] = $cell['cellLineStackingStrategy'];
25254 if (isset($cell['cellLineStackingShift']))
25255 $tableheader[$i][$j]['cellLineStackingShift'] = $cell['cellLineStackingShift'];
25256 }
25257
25258 // CELL BORDER
25259 if ($bord) {
25260 if ($table['borders_separate'] && $paintcell) {
25261 $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']);
25262 } elseif (!$table['borders_separate']) {
25263 $this->_tableRect($x, $y, $w, $h, $bord, $bord_det, true, $table['borders_separate']); // true causes buffer
25264 }
25265 }
25266
25267 //VERTICAL ALIGN
25268 if ($cell['R'] && INTVAL($cell['R']) > 0 && INTVAL($cell['R']) < 90 && isset($cell['va']) && $cell['va'] != 'B') {
25269 $cell['va'] = 'B';
25270 }
25271 if (!isset($cell['va']) || $cell['va'] == 'M')
25272 $this->y += ($h - $cell['mih']) / 2;
25273 elseif (isset($cell['va']) && $cell['va'] == 'B')
25274 $this->y += $h - $cell['mih'];
25275
25276 // NESTED CONTENT
25277 // TEXT (and nested tables)
25278
25279 $this->divwidth = $w;
25280 if (!empty($cell['textbuffer'])) {
25281 $this->cellTextAlign = $align;
25282 $this->cellLineHeight = $cell['cellLineHeight'];
25283 $this->cellLineStackingStrategy = $cell['cellLineStackingStrategy'];
25284 $this->cellLineStackingShift = $cell['cellLineStackingShift'];
25285 if ($level == 1) {
25286 if (isset($table['is_tfoot'][$i]) && $table['is_tfoot'][$i]) {
25287 if (preg_match('/{colsum([0-9]*)[_]*}/', $cell['textbuffer'][0][0], $m)) {
25288 $rep = sprintf("%01." . intval($m[1]) . "f", $this->colsums[$j]);
25289 $cell['textbuffer'][0][0] = preg_replace('/{colsum[0-9_]*}/', $rep, $cell['textbuffer'][0][0]);
25290 }
25291 } elseif (!isset($table['is_thead'][$i])) {
25292 if (isset($this->colsums[$j])) {
25293 $this->colsums[$j] += floatval(preg_replace('/^[^0-9\.\,]*/', '', $cell['textbuffer'][0][0]));
25294 } else {
25295 $this->colsums[$j] = floatval(preg_replace('/^[^0-9\.\,]*/', '', $cell['textbuffer'][0][0]));
25296 }
25297 }
25298 }
25299 $opy = $this->y;
25300 // mPDF ITERATION
25301 if ($this->iterationCounter) {
25302 foreach ($cell['textbuffer'] AS $k => $t) {
25303 if (preg_match('/{iteration ([a-zA-Z0-9_]+)}/', $t[0], $m)) {
25304 $vname = '__' . $m[1] . '_';
25305 if (!isset($this->$vname)) {
25306 $this->$vname = 1;
25307 } else {
25308 $this->$vname++;
25309 }
25310 $cell['textbuffer'][$k][0] = preg_replace('/{iteration ' . $m[1] . '}/', $this->$vname, $cell['textbuffer'][$k][0]);
25311 }
25312 }
25313 }
25314
25315
25316 if ($cell['R']) {
25317 $cellPtSize = $cell['textbuffer'][0][11] / $this->shrin_k;
25318 if (!$cellPtSize) {
25319 $cellPtSize = $this->default_font_size;
25320 }
25321 $cellFontHeight = ($cellPtSize / _MPDFK);
25322 $opx = $this->x;
25323 $angle = INTVAL($cell['R']);
25324 // Only allow 45 to 89 degrees (when bottom-aligned) or exactly 90 or -90
25325 if ($angle > 90) {
25326 $angle = 90;
25327 } elseif ($angle > 0 && $angle < 45) {
25328 $angle = 45;
25329 } elseif ($angle < 0) {
25330 $angle = -90;
25331 }
25332 $offset = ((sin(deg2rad($angle))) * 0.37 * $cellFontHeight);
25333 if (isset($cell['a']) && $cell['a'] == 'R') {
25334 $this->x += ($w) + ($offset) - ($cellFontHeight / 3) - ($cell['padding']['R'] + ($table['border_spacing_H'] / 2));
25335 } elseif (!isset($cell['a']) || $cell['a'] == 'C') {
25336 $this->x += ($w / 2) + ($offset);
25337 } else {
25338 $this->x += ($offset) + ($cellFontHeight / 3) + ($cell['padding']['L'] + ($table['border_spacing_H'] / 2));
25339 }
25340 $str = '';
25341 foreach ($cell['textbuffer'] AS $t) {
25342 $str .= $t[0] . ' ';
25343 }
25344 $str = rtrim($str);
25345 if (!isset($cell['va']) || $cell['va'] == 'M') {
25346 $this->y -= ($h - $cell['mih']) / 2; //Undo what was added earlier VERTICAL ALIGN
25347 if ($angle > 0) {
25348 $this->y += (($h - $cell['mih']) / 2) + $cell['padding']['T'] + ($cell['mih'] - ($cell['padding']['T'] + $cell['padding']['B']));
25349 } elseif ($angle < 0) {
25350 $this->y += (($h - $cell['mih']) / 2) + ($cell['padding']['T'] + ($table['border_spacing_V'] / 2));
25351 }
25352 } elseif (isset($cell['va']) && $cell['va'] == 'B') {
25353 $this->y -= $h - $cell['mih']; //Undo what was added earlier VERTICAL ALIGN
25354 if ($angle > 0) {
25355 $this->y += $h - ($cell['padding']['B'] + ($table['border_spacing_V'] / 2));
25356 } elseif ($angle < 0) {
25357 $this->y += $h - $cell['mih'] + ($cell['padding']['T'] + ($table['border_spacing_V'] / 2));
25358 }
25359 } elseif (isset($cell['va']) && $cell['va'] == 'T') {
25360 if ($angle > 0) {
25361 $this->y += $cell['mih'] - ($cell['padding']['B'] + ($table['border_spacing_V'] / 2));
25362 } elseif ($angle < 0) {
25363 $this->y += ($cell['padding']['T'] + ($table['border_spacing_V'] / 2));
25364 }
25365 }
25366 $this->Rotate($angle, $this->x, $this->y);
25367 $s_fs = $this->FontSizePt;
25368 $s_f = $this->FontFamily;
25369 $s_st = $this->FontStyle;
25370 if (!empty($cell['textbuffer'][0][3])) { //Font Color
25371 $cor = $cell['textbuffer'][0][3];
25372 $this->SetTColor($cor);
25373 }
25374 $this->SetFont($cell['textbuffer'][0][4], $cell['textbuffer'][0][2], $cellPtSize, true, true);
25375
25376 $this->magic_reverse_dir($str, $this->directionality, $cell['textbuffer'][0][18]);
25377 $this->Text($this->x, $this->y, $str, $cell['textbuffer'][0][18], $cell['textbuffer'][0][8]); // textvar
25378 $this->Rotate(0);
25379 $this->SetFont($s_f, $s_st, $s_fs, true, true);
25380 $this->SetTColor(0);
25381 $this->x = $opx;
25382 } else {
25383
25384 if (!$this->simpleTables) {
25385 if ($bord_det) {
25386 $btlw = $bord_det['L']['w'];
25387 $btrw = $bord_det['R']['w'];
25388 $bttw = $bord_det['T']['w'];
25389 } else {
25390 $btlw = 0;
25391 $btrw = 0;
25392 $bttw = 0;
25393 }
25394 if ($table['borders_separate']) {
25395 $xadj = $btlw + $cell['padding']['L'] + ($table['border_spacing_H'] / 2);
25396 $wadj = $btlw + $btrw + $cell['padding']['L'] + $cell['padding']['R'] + $table['border_spacing_H'];
25397 $yadj = $bttw + $cell['padding']['T'] + ($table['border_spacing_H'] / 2);
25398 } else {
25399 $xadj = $btlw / 2 + $cell['padding']['L'];
25400 $wadj = ($btlw + $btrw) / 2 + $cell['padding']['L'] + $cell['padding']['R'];
25401 $yadj = $bttw / 2 + $cell['padding']['T'];
25402 }
25403 } elseif ($this->simpleTables) {
25404 if ($table['borders_separate']) { // NB twice border width
25405 $xadj = $table['simple']['border_details']['L']['w'] + $cell['padding']['L'] + ($table['border_spacing_H'] / 2);
25406 $wadj = $table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w'] + $cell['padding']['L'] + $cell['padding']['R'] + $table['border_spacing_H'];
25407 $yadj = $table['simple']['border_details']['T']['w'] + $cell['padding']['T'] + ($table['border_spacing_H'] / 2);
25408 } else {
25409 $xadj = $table['simple']['border_details']['L']['w'] / 2 + $cell['padding']['L'];
25410 $wadj = ($table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w']) / 2 + $cell['padding']['L'] + $cell['padding']['R'];
25411 $yadj = $table['simple']['border_details']['T']['w'] / 2 + $cell['padding']['T'];
25412 }
25413 }
25414 $this->decimal_offset = 0;
25415 if (substr($cell['a'], 0, 1) == 'D') {
25416 if (isset($cell['colspan']) && $cell['colspan'] > 1) {
25417 $this->cellTextAlign = $c['a'] = substr($cell['a'], 2, 1);
25418 } else {
25419 $smax = $table['decimal_align'][$j]['maxs0'];
25420 $d_content = $table['decimal_align'][$j]['maxs0'] + $table['decimal_align'][$j]['maxs1'];
25421 $this->decimal_offset = $smax;
25422 $extra = ($w - $d_content - $wadj);
25423 if ($extra > 0) {
25424 if (substr($cell['a'], 2, 1) == 'R') {
25425 $this->decimal_offset += $extra;
25426 } elseif (substr($cell['a'], 2, 1) == 'C') {
25427 $this->decimal_offset += ($extra) / 2;
25428 }
25429 }
25430 }
25431 }
25432 $this->divwidth = $w - $wadj;
25433 if ($this->divwidth == 0) {
25434 $this->divwidth = 0.0001;
25435 }
25436 $this->x += $xadj;
25437 $this->y += $yadj;
25438 $this->printbuffer($cell['textbuffer'], '', true, false, $cell['direction']);
25439 }
25440 $this->y = $opy;
25441 }
25442
25443 /* -- BACKGROUNDS -- */
25444 if (!$this->ColActive) {
25445 if (isset($table['trgradients'][$i]) && ($j == 0 || $table['borders_separate'])) {
25446 $g = $this->grad->parseBackgroundGradient($table['trgradients'][$i]);
25447 if ($g) {
25448 $gx = $x0;
25449 $gy = $y;
25450 $gh = $h;
25451 $gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
25452 if ($table['borders_separate']) {
25453 $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
25454 $clx = $x + ($table['border_spacing_H'] / 2);
25455 $cly = $y + ($table['border_spacing_V'] / 2);
25456 $clw = $w - $table['border_spacing_H'];
25457 $clh = $h - $table['border_spacing_V'];
25458 // Set clipping path
25459 $s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
25460 $this->tableBackgrounds[$level * 9 + 4][] = array('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);
25461 } else {
25462 $this->tableBackgrounds[$level * 9 + 4][] = array('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' => '');
25463 }
25464 }
25465 }
25466 if (isset($table['trbackground-images'][$i]) && ($j == 0 || $table['borders_separate'])) {
25467 if (isset($table['trbackground-images'][$i]['gradient']) && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $table['trbackground-images'][$i]['gradient'])) {
25468 $g = $this->grad->parseMozGradient($table['trbackground-images'][$i]['gradient']);
25469 if ($g) {
25470 $gx = $x0;
25471 $gy = $y;
25472 $gh = $h;
25473 $gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
25474 if ($table['borders_separate']) {
25475 $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
25476 $clx = $x + ($table['border_spacing_H'] / 2);
25477 $cly = $y + ($table['border_spacing_V'] / 2);
25478 $clw = $w - $table['border_spacing_H'];
25479 $clh = $h - $table['border_spacing_V'];
25480 // Set clipping path
25481 $s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
25482 $this->tableBackgrounds[$level * 9 + 4][] = array('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);
25483 } else {
25484 $this->tableBackgrounds[$level * 9 + 4][] = array('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' => '');
25485 }
25486 }
25487 } else {
25488 $image_id = $table['trbackground-images'][$i]['image_id'];
25489 $orig_w = $table['trbackground-images'][$i]['orig_w'];
25490 $orig_h = $table['trbackground-images'][$i]['orig_h'];
25491 $x_pos = $table['trbackground-images'][$i]['x_pos'];
25492 $y_pos = $table['trbackground-images'][$i]['y_pos'];
25493 $x_repeat = $table['trbackground-images'][$i]['x_repeat'];
25494 $y_repeat = $table['trbackground-images'][$i]['y_repeat'];
25495 $resize = $table['trbackground-images'][$i]['resize'];
25496 $opacity = $table['trbackground-images'][$i]['opacity'];
25497 $itype = $table['trbackground-images'][$i]['itype'];
25498 $clippath = '';
25499 $gx = $x0;
25500 $gy = $y;
25501 $gh = $h;
25502 $gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
25503 if ($table['borders_separate']) {
25504 $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
25505 $clx = $x + ($table['border_spacing_H'] / 2);
25506 $cly = $y + ($table['border_spacing_V'] / 2);
25507 $clw = $w - $table['border_spacing_H'];
25508 $clh = $h - $table['border_spacing_V'];
25509 // Set clipping path
25510 $s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
25511 $this->tableBackgrounds[$level * 9 + 5][] = array('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);
25512 } else {
25513 $this->tableBackgrounds[$level * 9 + 5][] = array('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);
25514 }
25515 }
25516 }
25517 }
25518
25519 /* -- END BACKGROUNDS -- */
25520
25521 // TABLE BORDER - if separate
25522 if (($table['borders_separate'] || ($this->simpleTables && !$table['simple']['border'])) && $table['border']) {
25523 $halfspaceL = $table['padding']['L'] + ($table['border_spacing_H'] / 2);
25524 $halfspaceR = $table['padding']['R'] + ($table['border_spacing_H'] / 2);
25525 $halfspaceT = $table['padding']['T'] + ($table['border_spacing_V'] / 2);
25526 $halfspaceB = $table['padding']['B'] + ($table['border_spacing_V'] / 2);
25527 $tbx = $x;
25528 $tby = $y;
25529 $tbw = $w;
25530 $tbh = $h;
25531 $tab_bord = 0;
25532
25533 $corner = '';
25534 if ($i == 0) { // Top
25535 $tby -= $halfspaceT + ($table['border_details']['T']['w'] / 2);
25536 $tbh += $halfspaceT + ($table['border_details']['T']['w'] / 2);
25537 $this->setBorder($tab_bord, _BORDER_TOP);
25538 $corner .= 'T';
25539 }
25540 if ($i == ($numrows - 1) || (isset($cell['rowspan']) && ($i + $cell['rowspan']) == $numrows)) { // Bottom
25541 $tbh += $halfspaceB + ($table['border_details']['B']['w'] / 2);
25542 $this->setBorder($tab_bord, _BORDER_BOTTOM);
25543 $corner .= 'B';
25544 }
25545 if ($j == 0) { // Left
25546 $tbx -= $halfspaceL + ($table['border_details']['L']['w'] / 2);
25547 $tbw += $halfspaceL + ($table['border_details']['L']['w'] / 2);
25548 $this->setBorder($tab_bord, _BORDER_LEFT);
25549 $corner .= 'L';
25550 }
25551 if ($j == ($numcols - 1) || (isset($cell['colspan']) && ($j + $cell['colspan']) == $numcols)) { // Right
25552 $tbw += $halfspaceR + ($table['border_details']['R']['w'] / 2);
25553 $this->setBorder($tab_bord, _BORDER_RIGHT);
25554 $corner .= 'R';
25555 }
25556 $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']);
25557 }
25558
25559 unset($cell);
25560 //Reset values
25561 $this->Reset();
25562 }//end of (if isset(cells)...)
25563 }// end of columns
25564
25565 $newpagestarted = false;
25566 $this->tabletheadjustfinished = false;
25567
25568 /* -- COLUMNS -- */
25569 if ($this->ColActive) {
25570 if (!$this->table_keep_together && $i < $numrows - 1 && $level == 1) {
25571 $this->breakpoints[$this->CurrCol][] = $y + $h;
25572 } // mPDF 6
25573 if (count($this->cellBorderBuffer)) {
25574 $this->printcellbuffer();
25575 }
25576 }
25577 /* -- END COLUMNS -- */
25578
25579 if ($i == $numrows - 1) {
25580 $this->y = $y + $h;
25581 } //last row jump (update this->y position)
25582 if ($this->table_rotate && $level == 1) {
25583 $this->tbrot_h += $h;
25584 }
25585 }// end of rows
25586
25587 if ($this->progressBar) {
25588 $this->UpdateProgressBar(7, 70, ' ');
25589 } // *PROGRESS-BAR*
25590
25591 if (count($this->cellBorderBuffer)) {
25592 $this->printcellbuffer();
25593 }
25594
25595
25596 if ($this->tableClipPath) {
25597 $this->_out("Q");
25598 }
25599 $this->tableClipPath = '';
25600
25601 // Advance down page by half width of bottom border
25602 if ($table['borders_separate']) {
25603 $this->y += $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
25604 } else {
25605 $this->y += $table['max_cell_border_width']['B'] / 2;
25606 }
25607
25608 if ($table['borders_separate'] && $level == 1) {
25609 $this->tbrot_h += $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
25610 } elseif ($level == 1) {
25611 $this->tbrot_h += $table['margin']['B'] + $table['max_cell_border_width']['B'] / 2;
25612 }
25613
25614 $bx = $x0;
25615 $by = $y0;
25616 if ($table['borders_separate']) {
25617 $bx -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['border_spacing_H'] / 2);
25618 if ($tablestartpageno != $this->page) { // IF broken across page
25619 $by += $table['max_cell_border_width']['T'] / 2;
25620 if (empty($tableheader)) {
25621 $by -= ($table['border_spacing_V'] / 2);
25622 }
25623 } elseif ($split && $startrow > 0 && empty($tableheader)) {
25624 $by -= ($table['border_spacing_V'] / 2);
25625 } else {
25626 $by -= ($table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2);
25627 }
25628 } elseif ($tablestartpageno != $this->page && !empty($tableheader)) {
25629 $by += $maxbwtop / 2;
25630 }
25631 $by -= $tableheaderadj;
25632 $bh = $this->y - $by;
25633 if (!$table['borders_separate']) {
25634 $bh -= $table['max_cell_border_width']['B'] / 2;
25635 }
25636
25637 if ($split) {
25638 $bw = 0;
25639 $finalSpread = true;
25640 for ($t = $startcol; $t < $numcols; $t++) {
25641 if ($table['colPg'][$t] == $splitpg) {
25642 $bw += $table['wc'][$t];
25643 }
25644 if ($table['colPg'][$t] > $splitpg) {
25645 $finalSpread = false;
25646 break;
25647 }
25648 }
25649 if ($startcol == 0) {
25650 $firstSpread = true;
25651 } else {
25652 $firstSpread = false;
25653 }
25654 if ($table['borders_separate']) {
25655 $bw += $table['border_spacing_H'];
25656 if ($firstSpread) {
25657 $bw += $table['padding']['L'] + $table['border_details']['L']['w'];
25658 } else {
25659 $bx += ($table['padding']['L'] + $table['border_details']['L']['w']);
25660 }
25661 if ($finalSpread) {
25662 $bw += $table['padding']['R'] + $table['border_details']['R']['w'];
25663 }
25664 }
25665 } else {
25666 $bw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
25667 }
25668
25669 if (!$this->ColActive) {
25670 if (isset($table['bgcolor'][-1])) {
25671 $color = $this->ConvertColor($table['bgcolor'][-1]);
25672 if ($color) {
25673 $this->tableBackgrounds[$level * 9][] = array('gradient' => false, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'col' => $color);
25674 }
25675 }
25676
25677 /* -- BACKGROUNDS -- */
25678 if (isset($table['gradient'])) {
25679 $g = $this->grad->parseBackgroundGradient($table['gradient']);
25680 if ($g) {
25681 $this->tableBackgrounds[$level * 9 + 1][] = array('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' => '');
25682 }
25683 }
25684
25685 if (isset($table['background-image'])) {
25686 if (isset($table['background-image']['gradient']) && $table['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $table['background-image']['gradient'])) {
25687 $g = $this->grad->parseMozGradient($table['background-image']['gradient']);
25688 if ($g) {
25689 $this->tableBackgrounds[$level * 9 + 1][] = array('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' => '');
25690 }
25691 } else {
25692 $image_id = $table['background-image']['image_id'];
25693 $orig_w = $table['background-image']['orig_w'];
25694 $orig_h = $table['background-image']['orig_h'];
25695 $x_pos = $table['background-image']['x_pos'];
25696 $y_pos = $table['background-image']['y_pos'];
25697 $x_repeat = $table['background-image']['x_repeat'];
25698 $y_repeat = $table['background-image']['y_repeat'];
25699 $resize = $table['background-image']['resize'];
25700 $opacity = $table['background-image']['opacity'];
25701 $itype = $table['background-image']['itype'];
25702 $this->tableBackgrounds[$level * 9 + 2][] = array('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);
25703 }
25704 }
25705 /* -- END BACKGROUNDS -- */
25706 }
25707
25708 if ($this->tableBackgrounds && $level == 1) {
25709 $s = $this->PrintTableBackgrounds();
25710 if ($this->table_rotate && !$this->processingHeader && !$this->processingFooter) {
25711 $this->tablebuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->tablebuffer);
25712 if ($level == 1) {
25713 $this->tablebuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->tablebuffer);
25714 }
25715 } elseif ($this->bufferoutput) {
25716 $this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->headerbuffer);
25717 if ($level == 1) {
25718 $this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->headerbuffer);
25719 }
25720 } else {
25721 $this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
25722 if ($level == 1) {
25723 $this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->pages[$this->page]);
25724 }
25725 }
25726 $this->tableBackgrounds = array();
25727 }
25728
25729
25730 // TABLE BOTTOM MARGIN
25731 if ($table['margin']['B']) {
25732 if (!$this->table_rotate && $level == 1) {
25733 $this->DivLn($table['margin']['B'], $this->blklvl, true); // collapsible
25734 } else {
25735 $this->y += ($table['margin']['B']);
25736 }
25737 }
25738
25739 if ($this->ColActive && $level == 1) {
25740 $this->breakpoints[$this->CurrCol][] = $this->y;
25741 } // *COLUMNS*
25742
25743 if ($split) {
25744 // Are there more columns to print on a next page?
25745 if ($lastCol < $numcols - 1) {
25746 $splitpg++;
25747 $startcol = $lastCol + 1;
25748 return array(false, $startrow, $startcol, $splitpg, $returny, $y0);
25749 } else {
25750 return array(true, 0, 0, 0, false, false);
25751 }
25752 }
25753 }
25754
25755 //END OF FUNCTION _tableWrite()
25756 /////////////////////////END OF TABLE CODE//////////////////////////////////
25757 /* -- END TABLES -- */
25758
25759 function _putextgstates()
25760 {
25761 for ($i = 1; $i <= count($this->extgstates); $i++) {
25762 $this->_newobj();
25763 $this->extgstates[$i]['n'] = $this->n;
25764 $this->_out('<</Type /ExtGState');
25765 foreach ($this->extgstates[$i]['parms'] as $k => $v)
25766 $this->_out('/' . $k . ' ' . $v);
25767 $this->_out('>>');
25768 $this->_out('endobj');
25769 }
25770 }
25771
25772 function _putocg()
25773 {
25774 if ($this->hasOC) {
25775 $this->_newobj();
25776 $this->n_ocg_print = $this->n;
25777 $this->_out('<</Type /OCG /Name ' . $this->_textstring('Print only'));
25778 $this->_out('/Usage <</Print <</PrintState /ON>> /View <</ViewState /OFF>>>>>>');
25779 $this->_out('endobj');
25780 $this->_newobj();
25781 $this->n_ocg_view = $this->n;
25782 $this->_out('<</Type /OCG /Name ' . $this->_textstring('Screen only'));
25783 $this->_out('/Usage <</Print <</PrintState /OFF>> /View <</ViewState /ON>>>>>>');
25784 $this->_out('endobj');
25785 $this->_newobj();
25786 $this->n_ocg_hidden = $this->n;
25787 $this->_out('<</Type /OCG /Name ' . $this->_textstring('Hidden'));
25788 $this->_out('/Usage <</Print <</PrintState /OFF>> /View <</ViewState /OFF>>>>>>');
25789 $this->_out('endobj');
25790 }
25791 if (count($this->layers)) {
25792 ksort($this->layers);
25793 foreach ($this->layers as $id => $layer) {
25794 $this->_newobj();
25795 $this->layers[$id]['n'] = $this->n;
25796 if (isset($this->layerDetails[$id]['name']) && $this->layerDetails[$id]['name']) {
25797 $name = $this->layerDetails[$id]['name'];
25798 } else {
25799 $name = $layer['name'];
25800 }
25801 $this->_out('<</Type /OCG /Name ' . $this->_UTF16BEtextstring($name) . '>>');
25802 $this->_out('endobj');
25803 }
25804 }
25805 }
25806
25807 /* -- IMPORTS -- */
25808
25809 // from mPDFI
25810 function _putimportedobjects()
25811 {
25812 if (is_array($this->parsers) && count($this->parsers) > 0) {
25813 foreach ($this->parsers AS $filename => $p) {
25814 $this->current_parser = $this->parsers[$filename];
25815 if (is_array($this->_obj_stack[$filename])) {
25816 while ($n = key($this->_obj_stack[$filename])) {
25817 $nObj = $this->current_parser->resolveObject($this->_obj_stack[$filename][$n][1]);
25818 $this->_newobj($this->_obj_stack[$filename][$n][0]);
25819 if ($nObj[0] == pdf_parser::TYPE_STREAM) {
25820 $this->pdf_write_value($nObj);
25821 } else {
25822 $this->pdf_write_value($nObj[1]);
25823 }
25824 $this->_out('endobj');
25825 $this->_obj_stack[$filename][$n] = null; // free memory
25826 unset($this->_obj_stack[$filename][$n]);
25827 reset($this->_obj_stack[$filename]);
25828 }
25829 }
25830 }
25831 }
25832 }
25833
25834 function _putformxobjects()
25835 {
25836 $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
25837 reset($this->tpls);
25838 foreach ($this->tpls AS $tplidx => $tpl) {
25839 $p = ($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer'];
25840 $this->_newobj();
25841 $this->tpls[$tplidx]['n'] = $this->n;
25842 $this->_out('<<' . $filter . '/Type /XObject');
25843 $this->_out('/Subtype /Form');
25844 $this->_out('/FormType 1');
25845 // Left/Bottom/Right/Top
25846 $this->_out(sprintf('/BBox [%.2F %.2F %.2F %.2F]', $tpl['box']['x'] * _MPDFK, $tpl['box']['y'] * _MPDFK, ($tpl['box']['x'] + $tpl['box']['w']) * _MPDFK, ($tpl['box']['y'] + $tpl['box']['h']) * _MPDFK)
25847 );
25848
25849
25850 if (isset($tpl['box']))
25851 $this->_out(sprintf('/Matrix [1 0 0 1 %.5F %.5F]', -$tpl['box']['x'] * _MPDFK, -$tpl['box']['y'] * _MPDFK));
25852 $this->_out('/Resources ');
25853
25854 if (isset($tpl['resources'])) {
25855 $this->current_parser = $tpl['parser'];
25856 $this->pdf_write_value($tpl['resources']);
25857 } else {
25858 $this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
25859 if (isset($this->_res['tpl'][$tplidx]['fonts']) && count($this->_res['tpl'][$tplidx]['fonts'])) {
25860 $this->_out('/Font <<');
25861 foreach ($this->_res['tpl'][$tplidx]['fonts'] as $font)
25862 $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R');
25863 $this->_out('>>');
25864 }
25865 if (isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images']) ||
25866 isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) {
25867 $this->_out('/XObject <<');
25868 if (isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images'])) {
25869 foreach ($this->_res['tpl'][$tplidx]['images'] as $image)
25870 $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R');
25871 }
25872 if (isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) {
25873 foreach ($this->_res['tpl'][$tplidx]['tpls'] as $i => $itpl)
25874 $this->_out($this->tplprefix . $i . ' ' . $itpl['n'] . ' 0 R');
25875 }
25876 $this->_out('>>');
25877 }
25878 $this->_out('>>');
25879 }
25880
25881 $this->_out('/Length ' . strlen($p) . ' >>');
25882 $this->_putstream($p);
25883 $this->_out('endobj');
25884 }
25885 }
25886
25887 /* -- END IMPORTS -- */
25888
25889 function _putpatterns()
25890 {
25891 for ($i = 1; $i <= count($this->patterns); $i++) {
25892 $x = $this->patterns[$i]['x'];
25893 $y = $this->patterns[$i]['y'];
25894 $w = $this->patterns[$i]['w'];
25895 $h = $this->patterns[$i]['h'];
25896 $pgh = $this->patterns[$i]['pgh'];
25897 $orig_w = $this->patterns[$i]['orig_w'];
25898 $orig_h = $this->patterns[$i]['orig_h'];
25899 $image_id = $this->patterns[$i]['image_id'];
25900 $itype = $this->patterns[$i]['itype'];
25901 if (isset($this->patterns[$i]['bpa'])) {
25902 $bpa = $this->patterns[$i]['bpa'];
25903 } // background positioning area
25904 else {
25905 $bpa = array();
25906 }
25907
25908 if ($this->patterns[$i]['x_repeat']) {
25909 $x_repeat = true;
25910 } else {
25911 $x_repeat = false;
25912 }
25913 if ($this->patterns[$i]['y_repeat']) {
25914 $y_repeat = true;
25915 } else {
25916 $y_repeat = false;
25917 }
25918 $x_pos = $this->patterns[$i]['x_pos'];
25919 if (stristr($x_pos, '%')) {
25920 $x_pos += 0;
25921 $x_pos /= 100;
25922 if (isset($bpa['w']) && $bpa['w'])
25923 $x_pos = ($bpa['w'] * $x_pos) - ($orig_w / _MPDFK * $x_pos);
25924 else
25925 $x_pos = ($w * $x_pos) - ($orig_w / _MPDFK * $x_pos);
25926 }
25927 $y_pos = $this->patterns[$i]['y_pos'];
25928 if (stristr($y_pos, '%')) {
25929 $y_pos += 0;
25930 $y_pos /= 100;
25931 if (isset($bpa['h']) && $bpa['h'])
25932 $y_pos = ($bpa['h'] * $y_pos) - ($orig_h / _MPDFK * $y_pos);
25933 else
25934 $y_pos = ($h * $y_pos) - ($orig_h / _MPDFK * $y_pos);
25935 }
25936 if (isset($bpa['x']) && $bpa['x'])
25937 $adj_x = ($x_pos + $bpa['x']) * _MPDFK;
25938 else
25939 $adj_x = ($x_pos + $x) * _MPDFK;
25940 if (isset($bpa['y']) && $bpa['y'])
25941 $adj_y = (($pgh - $y_pos - $bpa['y']) * _MPDFK) - $orig_h;
25942 else
25943 $adj_y = (($pgh - $y_pos - $y) * _MPDFK) - $orig_h;
25944 $img_obj = false;
25945 if ($itype == 'svg' || $itype == 'wmf') {
25946 foreach ($this->formobjects AS $fo) {
25947 if ($fo['i'] == $image_id) {
25948 $img_obj = $fo['n'];
25949 $fo_w = $fo['w'];
25950 $fo_h = -$fo['h'];
25951 $wmf_x = $fo['x'];
25952 $wmf_y = $fo['y'];
25953 break;
25954 }
25955 }
25956 } else {
25957 foreach ($this->images AS $img) {
25958 if ($img['i'] == $image_id) {
25959 $img_obj = $img['n'];
25960 break;
25961 }
25962 }
25963 }
25964 if (!$img_obj) {
25965 echo "Problem: Image object not found for background pattern " . $img['i'];
25966 exit;
25967 }
25968
25969 $this->_newobj();
25970 $this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
25971 if ($itype == 'svg' || $itype == 'wmf') {
25972 $this->_out('/XObject <</FO' . $image_id . ' ' . $img_obj . ' 0 R >>');
25973 // ******* ADD ANY ExtGStates, Shading AND Fonts needed for the FormObject
25974 // Set in classes/svg array['fo'] = true
25975 // Required that _putshaders comes before _putpatterns in _putresources
25976 // This adds any resources associated with any FormObject to every Formobject - overkill but works!
25977 if (count($this->extgstates)) {
25978 $this->_out('/ExtGState <<');
25979 foreach ($this->extgstates as $k => $extgstate)
25980 if (isset($extgstate['fo']) && $extgstate['fo']) {
25981 if (isset($extgstate['trans']))
25982 $this->_out('/' . $extgstate['trans'] . ' ' . $extgstate['n'] . ' 0 R');
25983 else
25984 $this->_out('/GS' . $k . ' ' . $extgstate['n'] . ' 0 R');
25985 }
25986 $this->_out('>>');
25987 }
25988 /* -- BACKGROUNDS -- */
25989 if (isset($this->gradients) AND ( count($this->gradients) > 0)) {
25990 $this->_out('/Shading <<');
25991 foreach ($this->gradients as $id => $grad) {
25992 if (isset($grad['fo']) && $grad['fo']) {
25993 $this->_out('/Sh' . $id . ' ' . $grad['id'] . ' 0 R');
25994 }
25995 }
25996 $this->_out('>>');
25997 }
25998 /* -- END BACKGROUNDS -- */
25999 $this->_out('/Font <<');
26000 foreach ($this->fonts as $font) {
26001 if (!$font['used'] && $font['type'] == 'TTF') {
26002 continue;
26003 }
26004 if (isset($font['fo']) && $font['fo']) {
26005 if ($font['type'] == 'TTF' && ($font['sip'] || $font['smp'])) {
26006 foreach ($font['n'] AS $k => $fid) {
26007 $this->_out('/F' . $font['subsetfontids'][$k] . ' ' . $font['n'][$k] . ' 0 R');
26008 }
26009 } else {
26010 $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R');
26011 }
26012 }
26013 }
26014 $this->_out('>>');
26015 } else {
26016 $this->_out('/XObject <</I' . $image_id . ' ' . $img_obj . ' 0 R >>');
26017 }
26018 $this->_out('>>');
26019 $this->_out('endobj');
26020
26021 $this->_newobj();
26022 $this->patterns[$i]['n'] = $this->n;
26023 $this->_out('<< /Type /Pattern /PatternType 1 /PaintType 1 /TilingType 2');
26024 $this->_out('/Resources ' . ($this->n - 1) . ' 0 R');
26025
26026 $this->_out(sprintf('/BBox [0 0 %.3F %.3F]', $orig_w, $orig_h));
26027 if ($x_repeat) {
26028 $this->_out(sprintf('/XStep %.3F', $orig_w));
26029 } else {
26030 $this->_out(sprintf('/XStep %d', 99999));
26031 }
26032 if ($y_repeat) {
26033 $this->_out(sprintf('/YStep %.3F', $orig_h));
26034 } else {
26035 $this->_out(sprintf('/YStep %d', 99999));
26036 }
26037
26038 if ($itype == 'svg' || $itype == 'wmf') {
26039 $this->_out(sprintf('/Matrix [1 0 0 -1 %.3F %.3F]', $adj_x, ($adj_y + $orig_h)));
26040 $s = sprintf("q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q", ($orig_w / $fo_w), (-$orig_h / $fo_h), -($orig_w / $fo_w) * $wmf_x, ($orig_w / $fo_w) * $wmf_y, $image_id);
26041 } else {
26042 $this->_out(sprintf('/Matrix [1 0 0 1 %.3F %.3F]', $adj_x, $adj_y));
26043 $s = sprintf("q %.3F 0 0 %.3F 0 0 cm /I%d Do Q", $orig_w, $orig_h, $image_id);
26044 }
26045
26046 if ($this->compress) {
26047 $this->_out('/Filter /FlateDecode');
26048 $s = gzcompress($s);
26049 }
26050 $this->_out('/Length ' . strlen($s) . '>>');
26051 $this->_putstream($s);
26052 $this->_out('endobj');
26053 }
26054 }
26055
26056 /* -- BACKGROUNDS -- */
26057
26058 function _putshaders()
26059 {
26060 $maxid = count($this->gradients); //index for transparency gradients
26061 foreach ($this->gradients as $id => $grad) {
26062 if (($grad['type'] == 2 || $grad['type'] == 3) && empty($grad['is_mask'])) {
26063 $this->_newobj();
26064 $this->_out('<<');
26065 $this->_out('/FunctionType 3');
26066 $this->_out('/Domain [0 1]');
26067 $fn = array();
26068 $bd = array();
26069 $en = array();
26070 for ($i = 0; $i < (count($grad['stops']) - 1); $i++) {
26071 $fn[] = ($this->n + 1 + $i) . ' 0 R';
26072 $en[] = '0 1';
26073 if ($i > 0) {
26074 $bd[] = sprintf('%.3F', $grad['stops'][$i]['offset']);
26075 }
26076 }
26077 $this->_out('/Functions [' . implode(' ', $fn) . ']');
26078 $this->_out('/Bounds [' . implode(' ', $bd) . ']');
26079 $this->_out('/Encode [' . implode(' ', $en) . ']');
26080 $this->_out('>>');
26081 $this->_out('endobj');
26082 $f1 = $this->n;
26083 for ($i = 0; $i < (count($grad['stops']) - 1); $i++) {
26084 $this->_newobj();
26085 $this->_out('<<');
26086 $this->_out('/FunctionType 2');
26087 $this->_out('/Domain [0 1]');
26088 $this->_out('/C0 [' . $grad['stops'][$i]['col'] . ']');
26089 $this->_out('/C1 [' . $grad['stops'][$i + 1]['col'] . ']');
26090 $this->_out('/N 1');
26091 $this->_out('>>');
26092 $this->_out('endobj');
26093 }
26094 }
26095 if ($grad['type'] == 2 || $grad['type'] == 3) {
26096 if (isset($grad['trans']) && $grad['trans']) {
26097 $this->_newobj();
26098 $this->_out('<<');
26099 $this->_out('/FunctionType 3');
26100 $this->_out('/Domain [0 1]');
26101 $fn = array();
26102 $bd = array();
26103 $en = array();
26104 for ($i = 0; $i < (count($grad['stops']) - 1); $i++) {
26105 $fn[] = ($this->n + 1 + $i) . ' 0 R';
26106 $en[] = '0 1';
26107 if ($i > 0) {
26108 $bd[] = sprintf('%.3F', $grad['stops'][$i]['offset']);
26109 }
26110 }
26111 $this->_out('/Functions [' . implode(' ', $fn) . ']');
26112 $this->_out('/Bounds [' . implode(' ', $bd) . ']');
26113 $this->_out('/Encode [' . implode(' ', $en) . ']');
26114 $this->_out('>>');
26115 $this->_out('endobj');
26116 $f2 = $this->n;
26117 for ($i = 0; $i < (count($grad['stops']) - 1); $i++) {
26118 $this->_newobj();
26119 $this->_out('<<');
26120 $this->_out('/FunctionType 2');
26121 $this->_out('/Domain [0 1]');
26122 $this->_out(sprintf('/C0 [%.3F]', $grad['stops'][$i]['opacity']));
26123 $this->_out(sprintf('/C1 [%.3F]', $grad['stops'][$i + 1]['opacity']));
26124 $this->_out('/N 1');
26125 $this->_out('>>');
26126 $this->_out('endobj');
26127 }
26128 }
26129 }
26130
26131 if (empty($grad['is_mask'])) {
26132 $this->_newobj();
26133 $this->_out('<<');
26134 $this->_out('/ShadingType ' . $grad['type']);
26135 if (isset($grad['colorspace'])) {
26136 $this->_out('/ColorSpace /Device' . $grad['colorspace']); // Can use CMYK if all C0 and C1 above have 4 values
26137 } else {
26138 $this->_out('/ColorSpace /DeviceRGB');
26139 }
26140 if ($grad['type'] == 2) {
26141 $this->_out(sprintf('/Coords [%.3F %.3F %.3F %.3F]', $grad['coords'][0], $grad['coords'][1], $grad['coords'][2], $grad['coords'][3]));
26142 $this->_out('/Function ' . $f1 . ' 0 R');
26143 $this->_out('/Extend [' . $grad['extend'][0] . ' ' . $grad['extend'][1] . '] ');
26144 $this->_out('>>');
26145 } elseif ($grad['type'] == 3) {
26146 //x0, y0, r0, x1, y1, r1
26147 //at this this time radius of inner circle is 0
26148 $ir = 0;
26149 if (isset($grad['coords'][5]) && $grad['coords'][5]) {
26150 $ir = $grad['coords'][5];
26151 }
26152 $this->_out(sprintf('/Coords [%.3F %.3F %.3F %.3F %.3F %.3F]', $grad['coords'][0], $grad['coords'][1], $ir, $grad['coords'][2], $grad['coords'][3], $grad['coords'][4]));
26153 $this->_out('/Function ' . $f1 . ' 0 R');
26154 $this->_out('/Extend [' . $grad['extend'][0] . ' ' . $grad['extend'][1] . '] ');
26155 $this->_out('>>');
26156 } elseif ($grad['type'] == 6) {
26157 $this->_out('/BitsPerCoordinate 16');
26158 $this->_out('/BitsPerComponent 8');
26159 if ($grad['colorspace'] == 'CMYK') {
26160 $this->_out('/Decode[0 1 0 1 0 1 0 1 0 1 0 1]');
26161 } elseif ($grad['colorspace'] == 'Gray') {
26162 $this->_out('/Decode[0 1 0 1 0 1]');
26163 } else {
26164 $this->_out('/Decode[0 1 0 1 0 1 0 1 0 1]');
26165 }
26166 $this->_out('/BitsPerFlag 8');
26167 $this->_out('/Length ' . strlen($grad['stream']));
26168 $this->_out('>>');
26169 $this->_putstream($grad['stream']);
26170 }
26171 $this->_out('endobj');
26172 }
26173
26174 $this->gradients[$id]['id'] = $this->n;
26175
26176 // set pattern object
26177 $this->_newobj();
26178 $out = '<< /Type /Pattern /PatternType 2';
26179 $out .= ' /Shading ' . $this->gradients[$id]['id'] . ' 0 R';
26180 $out .= ' >>';
26181 $out .= "\n" . 'endobj';
26182 $this->_out($out);
26183
26184
26185 $this->gradients[$id]['pattern'] = $this->n;
26186
26187 if (isset($grad['trans']) && $grad['trans']) {
26188 // luminosity pattern
26189 $transid = $id + $maxid;
26190 $this->_newobj();
26191 $this->_out('<<');
26192 $this->_out('/ShadingType ' . $grad['type']);
26193 $this->_out('/ColorSpace /DeviceGray');
26194 if ($grad['type'] == 2) {
26195 $this->_out(sprintf('/Coords [%.3F %.3F %.3F %.3F]', $grad['coords'][0], $grad['coords'][1], $grad['coords'][2], $grad['coords'][3]));
26196 $this->_out('/Function ' . $f2 . ' 0 R');
26197 $this->_out('/Extend [' . $grad['extend'][0] . ' ' . $grad['extend'][1] . '] ');
26198 $this->_out('>>');
26199 } elseif ($grad['type'] == 3) {
26200 //x0, y0, r0, x1, y1, r1
26201 //at this this time radius of inner circle is 0
26202 $ir = 0;
26203 if (isset($grad['coords'][5]) && $grad['coords'][5]) {
26204 $ir = $grad['coords'][5];
26205 }
26206 $this->_out(sprintf('/Coords [%.3F %.3F %.3F %.3F %.3F %.3F]', $grad['coords'][0], $grad['coords'][1], $ir, $grad['coords'][2], $grad['coords'][3], $grad['coords'][4]));
26207 $this->_out('/Function ' . $f2 . ' 0 R');
26208 $this->_out('/Extend [' . $grad['extend'][0] . ' ' . $grad['extend'][1] . '] ');
26209 $this->_out('>>');
26210 } elseif ($grad['type'] == 6) {
26211 $this->_out('/BitsPerCoordinate 16');
26212 $this->_out('/BitsPerComponent 8');
26213 $this->_out('/Decode[0 1 0 1 0 1]');
26214 $this->_out('/BitsPerFlag 8');
26215 $this->_out('/Length ' . strlen($grad['stream_trans']));
26216 $this->_out('>>');
26217 $this->_putstream($grad['stream_trans']);
26218 }
26219 $this->_out('endobj');
26220
26221 $this->gradients[$transid]['id'] = $this->n;
26222 $this->_newobj();
26223 $this->_out('<< /Type /Pattern /PatternType 2');
26224 $this->_out('/Shading ' . $this->gradients[$transid]['id'] . ' 0 R');
26225 $this->_out('>>');
26226 $this->_out('endobj');
26227 $this->gradients[$transid]['pattern'] = $this->n;
26228 $this->_newobj();
26229 // Need to extend size of viewing box in case of transformations
26230 $str = 'q /a0 gs /Pattern cs /p' . $transid . ' scn -' . ($this->wPt / 2) . ' -' . ($this->hPt / 2) . ' ' . (2 * $this->wPt) . ' ' . (2 * $this->hPt) . ' re f Q';
26231 $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
26232 $p = ($this->compress) ? gzcompress($str) : $str;
26233 $this->_out('<< /Type /XObject /Subtype /Form /FormType 1 ' . $filter);
26234 $this->_out('/Length ' . strlen($p));
26235 $this->_out('/BBox [-' . ($this->wPt / 2) . ' -' . ($this->hPt / 2) . ' ' . (2 * $this->wPt) . ' ' . (2 * $this->hPt) . ']');
26236 $this->_out('/Group << /Type /Group /S /Transparency /CS /DeviceGray >>');
26237 $this->_out('/Resources <<');
26238 $this->_out('/ExtGState << /a0 << /ca 1 /CA 1 >> >>');
26239 $this->_out('/Pattern << /p' . $transid . ' ' . $this->gradients[$transid]['pattern'] . ' 0 R >>');
26240 $this->_out('>>');
26241 $this->_out('>>');
26242 $this->_putstream($p);
26243 $this->_out('endobj');
26244 $this->_newobj();
26245 $this->_out('<< /Type /Mask /S /Luminosity /G ' . ($this->n - 1) . ' 0 R >>' . "\n" . 'endobj');
26246 $this->_newobj();
26247 $this->_out('<< /Type /ExtGState /SMask ' . ($this->n - 1) . ' 0 R /AIS false >>' . "\n" . 'endobj');
26248 if (isset($grad['fo']) && $grad['fo']) {
26249 $this->extgstates[] = array('n' => $this->n, 'trans' => 'TGS' . $id, 'fo' => true);
26250 } else {
26251 $this->extgstates[] = array('n' => $this->n, 'trans' => 'TGS' . $id);
26252 }
26253 }
26254 }
26255 }
26256
26257 /* -- END BACKGROUNDS -- */
26258
26259 function _putspotcolors()
26260 {
26261 foreach ($this->spotColors as $name => $color) {
26262 $this->_newobj();
26263 $this->_out('[/Separation /' . str_replace(' ', '#20', $name));
26264 $this->_out('/DeviceCMYK <<');
26265 $this->_out('/Range [0 1 0 1 0 1 0 1] /C0 [0 0 0 0] ');
26266 $this->_out(sprintf('/C1 [%.3F %.3F %.3F %.3F] ', $color['c'] / 100, $color['m'] / 100, $color['y'] / 100, $color['k'] / 100));
26267 $this->_out('/FunctionType 2 /Domain [0 1] /N 1>>]');
26268 $this->_out('endobj');
26269 $this->spotColors[$name]['n'] = $this->n;
26270 }
26271 }
26272
26273 function _putresources()
26274 {
26275 if ($this->hasOC || count($this->layers))
26276 $this->_putocg();
26277 $this->_putextgstates();
26278 $this->_putspotcolors();
26279 if ($this->progressBar) {
26280 $this->UpdateProgressBar(2, '40', 'Compiling Fonts');
26281 } // *PROGRESS-BAR*
26282 $this->_putfonts();
26283 if ($this->progressBar) {
26284 $this->UpdateProgressBar(2, '50', 'Compiling Images');
26285 } // *PROGRESS-BAR*
26286 $this->_putimages();
26287 $this->_putformobjects(); // *IMAGES-CORE*
26288
26289 /* -- IMPORTS -- */
26290 if ($this->enableImports) {
26291 $this->_putformxobjects();
26292 $this->_putimportedobjects();
26293 }
26294 /* -- END IMPORTS -- */
26295
26296 /* -- BACKGROUNDS -- */
26297 $this->_putshaders();
26298 $this->_putpatterns();
26299 /* -- END BACKGROUNDS -- */
26300
26301
26302 //Resource dictionary
26303 $this->offsets[2] = strlen($this->buffer);
26304 $this->_out('2 0 obj');
26305 $this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
26306
26307 $this->_out('/Font <<');
26308 foreach ($this->fonts as $font) {
26309 if (isset($font['type']) && $font['type'] == 'TTF' && !$font['used']) {
26310 continue;
26311 }
26312 if (isset($font['type']) && $font['type'] == 'TTF' && ($font['sip'] || $font['smp'])) {
26313 foreach ($font['n'] AS $k => $fid) {
26314 $this->_out('/F' . $font['subsetfontids'][$k] . ' ' . $font['n'][$k] . ' 0 R');
26315 }
26316 } else {
26317 $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R');
26318 }
26319 }
26320 $this->_out('>>');
26321
26322 if (count($this->spotColors)) {
26323 $this->_out('/ColorSpace <<');
26324 foreach ($this->spotColors as $color)
26325 $this->_out('/CS' . $color['i'] . ' ' . $color['n'] . ' 0 R');
26326 $this->_out('>>');
26327 }
26328
26329 if (count($this->extgstates)) {
26330 $this->_out('/ExtGState <<');
26331 foreach ($this->extgstates as $k => $extgstate)
26332 if (isset($extgstate['trans']))
26333 $this->_out('/' . $extgstate['trans'] . ' ' . $extgstate['n'] . ' 0 R');
26334 else
26335 $this->_out('/GS' . $k . ' ' . $extgstate['n'] . ' 0 R');
26336 $this->_out('>>');
26337 }
26338
26339 /* -- BACKGROUNDS -- */
26340 if ((isset($this->gradients) AND ( count($this->gradients) > 0)) || ($this->enableImports && count($this->tpls))) { // mPDF 5.7.3
26341 $this->_out('/Shading <<');
26342 foreach ($this->gradients as $id => $grad) {
26343 $this->_out('/Sh' . $id . ' ' . $grad['id'] . ' 0 R');
26344 }
26345 // mPDF 5.7.3
26346 // If a shading dictionary is in an object (tpl) imported from another PDF, it needs to be included
26347 // in the document resources, as well as the object resources
26348 // Otherwise get an error in some PDF viewers
26349 if ($this->enableImports && count($this->tpls)) {
26350 foreach ($this->tpls as $tplidx => $tpl) {
26351 if (isset($tpl['resources'])) {
26352 $this->current_parser = $tpl['parser'];
26353 reset($tpl['resources'][1]);
26354 while (list($k, $v) = each($tpl['resources'][1])) {
26355 if ($k == '/Shading') {
26356 while (list($k2, $v2) = each($v[1])) {
26357 $this->_out($k2 . " ", false);
26358 $this->pdf_write_value($v2);
26359 }
26360 }
26361 }
26362 }
26363 }
26364 }
26365
26366 $this->_out('>>');
26367 /*
26368 // ??? Not needed !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
26369 $this->_out('/Pattern <<');
26370 foreach ($this->gradients as $id => $grad) {
26371 $this->_out('/P'.$id.' '.$grad['pattern'].' 0 R');
26372 }
26373 $this->_out('>>');
26374 */
26375 }
26376 /* -- END BACKGROUNDS -- */
26377
26378
26379 if (count($this->images) || count($this->formobjects) || ($this->enableImports && count($this->tpls))) {
26380 $this->_out('/XObject <<');
26381 foreach ($this->images as $image)
26382 $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R');
26383 foreach ($this->formobjects as $formobject)
26384 $this->_out('/FO' . $formobject['i'] . ' ' . $formobject['n'] . ' 0 R');
26385 /* -- IMPORTS -- */
26386 if ($this->enableImports && count($this->tpls)) {
26387 foreach ($this->tpls as $tplidx => $tpl) {
26388 $this->_out($this->tplprefix . $tplidx . ' ' . $tpl['n'] . ' 0 R');
26389 }
26390 }
26391 /* -- END IMPORTS -- */
26392 $this->_out('>>');
26393 }
26394
26395 /* -- BACKGROUNDS -- */
26396
26397 if (count($this->patterns)) {
26398 $this->_out('/Pattern <<');
26399 foreach ($this->patterns as $k => $patterns)
26400 $this->_out('/P' . $k . ' ' . $patterns['n'] . ' 0 R');
26401 $this->_out('>>');
26402 }
26403 /* -- END BACKGROUNDS -- */
26404
26405 if ($this->hasOC || count($this->layers)) {
26406 $this->_out('/Properties <<');
26407 if ($this->hasOC) {
26408 $this->_out('/OC1 ' . $this->n_ocg_print . ' 0 R /OC2 ' . $this->n_ocg_view . ' 0 R /OC3 ' . $this->n_ocg_hidden . ' 0 R ');
26409 }
26410 if (count($this->layers)) {
26411 foreach ($this->layers as $id => $layer)
26412 $this->_out('/ZI' . $id . ' ' . $layer['n'] . ' 0 R');
26413 }
26414 $this->_out('>>');
26415 }
26416
26417 $this->_out('>>');
26418 $this->_out('endobj'); // end resource dictionary
26419
26420 $this->_putbookmarks(); // *BOOKMARKS*
26421
26422 if (isset($this->js) && $this->js) {
26423 $this->_putjavascript();
26424 }
26425
26426 /* -- ENCRYPTION -- */
26427 if ($this->encrypted) {
26428 $this->_newobj();
26429 $this->enc_obj_id = $this->n;
26430 $this->_out('<<');
26431 $this->_putencryption();
26432 $this->_out('>>');
26433 $this->_out('endobj');
26434 }
26435 /* -- END ENCRYPTION -- */
26436 }
26437
26438 function _putjavascript()
26439 {
26440 $this->_newobj();
26441 $this->n_js = $this->n;
26442 $this->_out('<<');
26443 $this->_out('/Names [(EmbeddedJS) ' . (1 + $this->n) . ' 0 R ]');
26444 $this->_out('>>');
26445 $this->_out('endobj');
26446
26447 $this->_newobj();
26448 $this->_out('<<');
26449 $this->_out('/S /JavaScript');
26450 $this->_out('/JS ' . $this->_textstring($this->js));
26451 $this->_out('>>');
26452 $this->_out('endobj');
26453 }
26454
26455 /* -- ENCRYPTION -- */
26456
26457 function _putencryption()
26458 {
26459 $this->_out('/Filter /Standard');
26460 if ($this->useRC128encryption) {
26461 $this->_out('/V 2');
26462 $this->_out('/R 3');
26463 $this->_out('/Length 128');
26464 } else {
26465 $this->_out('/V 1');
26466 $this->_out('/R 2');
26467 }
26468 $this->_out('/O (' . $this->_escape($this->Ovalue) . ')');
26469 $this->_out('/U (' . $this->_escape($this->Uvalue) . ')');
26470 $this->_out('/P ' . $this->Pvalue);
26471 }
26472
26473 /* -- END ENCRYPTION -- */
26474
26475 function _puttrailer()
26476 {
26477 $this->_out('/Size ' . ($this->n + 1));
26478 $this->_out('/Root ' . $this->n . ' 0 R');
26479 $this->_out('/Info ' . $this->InfoRoot . ' 0 R');
26480 /* -- ENCRYPTION -- */
26481 if ($this->encrypted) {
26482 $this->_out('/Encrypt ' . $this->enc_obj_id . ' 0 R');
26483 $this->_out('/ID [<' . $this->uniqid . '> <' . $this->uniqid . '>]');
26484 } else {
26485 /* -- END ENCRYPTION -- */
26486 $uniqid = md5(time() . $this->buffer);
26487 $this->_out('/ID [<' . $uniqid . '> <' . $uniqid . '>]');
26488 /* -- ENCRYPTION -- */
26489 }
26490 /* -- END ENCRYPTION -- */
26491 }
26492
26493 /* -- ENCRYPTION -- */
26494
26495 function SetProtection($permissions = array(), $user_pass = '', $owner_pass = null, $length = 40)
26496 {
26497 $this->encrypted = false;
26498 if (is_string($permissions) && strlen($permissions) > 0) {
26499 $permissions = array($permissions);
26500 } elseif (!is_array($permissions)) {
26501 return 0;
26502 }
26503 $this->last_rc4_key = '';
26504 $this->padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08" .
26505 "\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A";
26506
26507 $options = array(
26508 'print' => 4, // bit 3
26509 'modify' => 8, // bit 4
26510 'copy' => 16, // bit 5
26511 'annot-forms' => 32, // bit 6
26512 'fill-forms' => 256, // bit 9
26513 'extract' => 512, // bit 10
26514 'assemble' => 1024, // bit 11
26515 'print-highres' => 2048 // bit 12
26516 );
26517 // bit 31 = 1073741824
26518 // bit 32 = 2147483648
26519 // bits 13-31 = 2147479552
26520 // bits 13-32 = 4294963200 + 192 = 4294963392
26521 $protection = 4294963392; // bits 7,8,13-32
26522 foreach ($permissions as $permission) {
26523 if (!isset($options[$permission]))
26524 throw new MpdfException('Incorrect permission: ' . $permission);
26525 if ($options[$permission] > 32) {
26526 $this->useRC128encryption = true;
26527 }
26528 if (isset($options[$permission]))
26529 $protection += $options[$permission];
26530 }
26531 if ($length == 128) {
26532 $this->useRC128encryption = true;
26533 }
26534 if ($owner_pass === null)
26535 $owner_pass = uniqid(rand());
26536 $this->encrypted = true;
26537 $this->_generateencryptionkey($user_pass, $owner_pass, $protection);
26538 }
26539
26540 // Compute key depending on object number where the encrypted data is stored
26541 function _objectkey($n)
26542 {
26543 if ($this->useRC128encryption)
26544 $len = 16;
26545 else
26546 $len = 10;
26547 return substr($this->_md5_16($this->encryption_key . pack('VXxx', $n)), 0, $len);
26548 }
26549
26550 // RC4 is the standard encryption algorithm used in PDF format
26551 function _RC4($key, $text)
26552 {
26553 if ($this->last_rc4_key != $key) {
26554 $k = str_repeat($key, 256 / strlen($key) + 1);
26555 $rc4 = range(0, 255);
26556 $j = 0;
26557 for ($i = 0; $i < 256; $i++) {
26558 $t = $rc4[$i];
26559 $j = ($j + $t + ord($k[$i])) % 256;
26560 $rc4[$i] = $rc4[$j];
26561 $rc4[$j] = $t;
26562 }
26563 $this->last_rc4_key = $key;
26564 $this->last_rc4_key_c = $rc4;
26565 } else {
26566 $rc4 = $this->last_rc4_key_c;
26567 }
26568
26569 $len = strlen($text);
26570 $a = 0;
26571 $b = 0;
26572 $out = '';
26573 for ($i = 0; $i < $len; $i++) {
26574 $a = ($a + 1) % 256;
26575 $t = $rc4[$a];
26576 $b = ($b + $t) % 256;
26577 $rc4[$a] = $rc4[$b];
26578 $rc4[$b] = $t;
26579 $k = $rc4[($rc4[$a] + $rc4[$b]) % 256];
26580 $out.= chr(ord($text[$i]) ^ $k);
26581 }
26582 return $out;
26583 }
26584
26585 // Get MD5 as binary string
26586 function _md5_16($string)
26587 {
26588 return pack('H*', md5($string));
26589 }
26590
26591 // Compute O value
26592 function _Ovalue($user_pass, $owner_pass)
26593 {
26594 $tmp = $this->_md5_16($owner_pass);
26595 if ($this->useRC128encryption) {
26596 for ($i = 0; $i < 50; ++$i) {
26597 $tmp = $this->_md5_16($tmp);
26598 }
26599 }
26600 if ($this->useRC128encryption)
26601 $keybytelen = (128 / 8);
26602 else
26603 $keybytelen = (40 / 8);
26604 $owner_RC4_key = substr($tmp, 0, $keybytelen);
26605 $enc = $this->_RC4($owner_RC4_key, $user_pass);
26606 if ($this->useRC128encryption) {
26607 $len = strlen($owner_RC4_key);
26608 for ($i = 1; $i <= 19; ++$i) {
26609 $key = '';
26610 for ($j = 0; $j < $len; ++$j) {
26611 $key .= chr(ord($owner_RC4_key[$j]) ^ $i);
26612 }
26613 $enc = $this->_RC4($key, $enc);
26614 }
26615 }
26616 return $enc;
26617 }
26618
26619 // Compute U value
26620 function _Uvalue()
26621 {
26622 if ($this->useRC128encryption) {
26623 $tmp = $this->_md5_16($this->padding . $this->_hexToString($this->uniqid));
26624 $enc = $this->_RC4($this->encryption_key, $tmp);
26625 $len = strlen($tmp);
26626 for ($i = 1; $i <= 19; ++$i) {
26627 $key = '';
26628 for ($j = 0; $j < $len; ++$j) {
26629 $key .= chr(ord($this->encryption_key[$j]) ^ $i);
26630 }
26631 $enc = $this->_RC4($key, $enc);
26632 }
26633 $enc .= str_repeat("\x00", 16);
26634 return substr($enc, 0, 32);
26635 } else {
26636 return $this->_RC4($this->encryption_key, $this->padding);
26637 }
26638 }
26639
26640 // Compute encryption key
26641 function _generateencryptionkey($user_pass, $owner_pass, $protection)
26642 {
26643 // Pad passwords
26644 $user_pass = substr($user_pass . $this->padding, 0, 32);
26645 $owner_pass = substr($owner_pass . $this->padding, 0, 32);
26646 $chars = 'ABCDEF1234567890';
26647 $id = '';
26648 for ($i = 0; $i < 32; $i++) {
26649 $id .= $chars[rand(0, 15)];
26650 }
26651 $this->uniqid = md5($id);
26652 // Compute O value
26653 $this->Ovalue = $this->_Ovalue($user_pass, $owner_pass);
26654 // Compute encyption key
26655 if ($this->useRC128encryption)
26656 $keybytelen = (128 / 8);
26657 else
26658 $keybytelen = (40 / 8);
26659 $prot = sprintf('%032b', $protection);
26660 $perms = chr(bindec(substr($prot, 24, 8)));
26661 $perms .= chr(bindec(substr($prot, 16, 8)));
26662 $perms .= chr(bindec(substr($prot, 8, 8)));
26663 $perms .= chr(bindec(substr($prot, 0, 8)));
26664 $tmp = $this->_md5_16($user_pass . $this->Ovalue . $perms . $this->_hexToString($this->uniqid));
26665 if ($this->useRC128encryption) {
26666 for ($i = 0; $i < 50; ++$i) {
26667 $tmp = $this->_md5_16(substr($tmp, 0, $keybytelen));
26668 }
26669 }
26670 $this->encryption_key = substr($tmp, 0, $keybytelen);
26671 // Compute U value
26672 $this->Uvalue = $this->_Uvalue();
26673 // Compute P value
26674 $this->Pvalue = $protection;
26675 }
26676
26677 function _hexToString($hs)
26678 {
26679 $s = '';
26680 $len = strlen($hs);
26681 if (($len % 2) != 0) {
26682 $hs .= '0';
26683 ++$len;
26684 }
26685 for ($i = 0; $i < $len; $i += 2) {
26686 $s .= chr(hexdec($hs[$i] . $hs[($i + 1)]));
26687 }
26688 return $s;
26689 }
26690
26691 /* -- END ENCRYPTION -- */
26692
26693 //=========================================
26694 /* -- BOOKMARKS -- */
26695 // FROM class PDF_Bookmark
26696
26697 function Bookmark($txt, $level = 0, $y = 0)
26698 {
26699 $txt = $this->purify_utf8_text($txt);
26700 if ($this->text_input_as_HTML) {
26701 $txt = $this->all_entities_to_utf8($txt);
26702 }
26703 if ($y == -1) {
26704 if (!$this->ColActive) {
26705 $y = $this->y;
26706 } else {
26707 $y = $this->y0;
26708 } // If columns are on - mark top of columns
26709 }
26710 // else y is used as set, or =0 i.e. top of page
26711 // DIRECTIONALITY RTL
26712 $bmo = array('t' => $txt, 'l' => $level, 'y' => $y, 'p' => $this->page);
26713 if ($this->keep_block_together) {
26714 // do nothing
26715 }
26716 /* -- TABLES -- */ elseif ($this->table_rotate) {
26717 $this->tbrot_BMoutlines[] = $bmo;
26718 } elseif ($this->kwt) {
26719 $this->kwt_BMoutlines[] = $bmo;
26720 }
26721 /* -- END TABLES -- */ elseif ($this->ColActive) { // *COLUMNS*
26722 $this->col_BMoutlines[] = $bmo; // *COLUMNS*
26723 } // *COLUMNS*
26724 else {
26725 $this->BMoutlines[] = $bmo;
26726 }
26727 }
26728
26729 function _putbookmarks()
26730 {
26731 $nb = count($this->BMoutlines);
26732 if ($nb == 0)
26733 return;
26734
26735 $bmo = $this->BMoutlines;
26736 $this->BMoutlines = array();
26737 $lastlevel = -1;
26738 for ($i = 0; $i < count($bmo); $i++) {
26739 if ($bmo[$i]['l'] > 0) {
26740 while ($bmo[$i]['l'] - $lastlevel > 1) { // If jump down more than one level, insert a new entry
26741 $new = $bmo[$i];
26742 $new['t'] = "[" . $new['t'] . "]"; // Put [] around text/title to highlight
26743 $new['l'] = $lastlevel + 1;
26744 $lastlevel++;
26745 $this->BMoutlines[] = $new;
26746 }
26747 }
26748 $this->BMoutlines[] = $bmo[$i];
26749 $lastlevel = $bmo[$i]['l'];
26750 }
26751 $nb = count($this->BMoutlines);
26752
26753 $lru = array();
26754 $level = 0;
26755 foreach ($this->BMoutlines as $i => $o) {
26756 if ($o['l'] > 0) {
26757 $parent = $lru[$o['l'] - 1];
26758 //Set parent and last pointers
26759 $this->BMoutlines[$i]['parent'] = $parent;
26760 $this->BMoutlines[$parent]['last'] = $i;
26761 if ($o['l'] > $level) {
26762 //Level increasing: set first pointer
26763 $this->BMoutlines[$parent]['first'] = $i;
26764 }
26765 } else {
26766 $this->BMoutlines[$i]['parent'] = $nb;
26767 }
26768 if ($o['l'] <= $level and $i > 0) {
26769 //Set prev and next pointers
26770 $prev = $lru[$o['l']];
26771 $this->BMoutlines[$prev]['next'] = $i;
26772 $this->BMoutlines[$i]['prev'] = $prev;
26773 }
26774 $lru[$o['l']] = $i;
26775 $level = $o['l'];
26776 }
26777
26778
26779 //Outline items
26780 $n = $this->n + 1;
26781 foreach ($this->BMoutlines as $i => $o) {
26782 $this->_newobj();
26783 $this->_out('<</Title ' . $this->_UTF16BEtextstring($o['t']));
26784 $this->_out('/Parent ' . ($n + $o['parent']) . ' 0 R');
26785 if (isset($o['prev']))
26786 $this->_out('/Prev ' . ($n + $o['prev']) . ' 0 R');
26787 if (isset($o['next']))
26788 $this->_out('/Next ' . ($n + $o['next']) . ' 0 R');
26789 if (isset($o['first']))
26790 $this->_out('/First ' . ($n + $o['first']) . ' 0 R');
26791 if (isset($o['last']))
26792 $this->_out('/Last ' . ($n + $o['last']) . ' 0 R');
26793
26794
26795 if (isset($this->pageDim[$o['p']]['h'])) {
26796 $h = $this->pageDim[$o['p']]['h'];
26797 } else {
26798 $h = 0;
26799 }
26800
26801 $this->_out(sprintf('/Dest [%d 0 R /XYZ 0 %.3F null]', 1 + 2 * ($o['p']), ($h - $o['y']) * _MPDFK));
26802 if (isset($this->bookmarkStyles) && isset($this->bookmarkStyles[$o['l']])) {
26803 // font style
26804 $bms = $this->bookmarkStyles[$o['l']]['style'];
26805 $style = 0;
26806 if (strpos($bms, 'B') !== false) {
26807 $style += 2;
26808 }
26809 if (strpos($bms, 'I') !== false) {
26810 $style += 1;
26811 }
26812 $this->_out(sprintf('/F %d', $style));
26813 // Colour
26814 $col = $this->bookmarkStyles[$o['l']]['color'];
26815 if (isset($col) && is_array($col) && count($col) == 3) {
26816 $this->_out(sprintf('/C [%.3F %.3F %.3F]', ($col[0] / 255), ($col[1] / 255), ($col[2] / 255)));
26817 }
26818 }
26819
26820 $this->_out('/Count 0>>');
26821 $this->_out('endobj');
26822 }
26823 //Outline root
26824 $this->_newobj();
26825 $this->OutlineRoot = $this->n;
26826 $this->_out('<</Type /BMoutlines /First ' . $n . ' 0 R');
26827 $this->_out('/Last ' . ($n + $lru[0]) . ' 0 R>>');
26828 $this->_out('endobj');
26829 }
26830
26831 /* -- END BOOKMARKS -- */
26832
26833 //======================================================
26834 /* -- TOC -- */
26835 // ToC TABLE OF CONTENTS
26836 // Initiate, and Mark a place for the Table of Contents to be inserted
26837 function TOC($tocfont = '', $tocfontsize = 0, $tocindent = 0, $resetpagenum = '', $pagenumstyle = '', $suppress = '', $toc_orientation = '', $TOCusePaging = true, $TOCuseLinking = false, $toc_id = 0, $tocoutdent = '')
26838 {
26839 if (!class_exists('tocontents', false)) {
26840 include(_MPDF_PATH . 'classes/tocontents.php');
26841 }
26842 if (empty($this->tocontents)) {
26843 $this->tocontents = new tocontents($this);
26844 }
26845 $this->tocontents->TOC($tocfont, $tocfontsize, $tocindent, $resetpagenum, $pagenumstyle, $suppress, $toc_orientation, $TOCusePaging, $TOCuseLinking, $toc_id, $tocoutdent);
26846 }
26847
26848 function TOCpagebreakByArray($a)
26849 {
26850 if (!is_array($a)) {
26851 $a = array();
26852 }
26853 if (!class_exists('tocontents', false)) {
26854 include(_MPDF_PATH . 'classes/tocontents.php');
26855 }
26856 if (empty($this->tocontents)) {
26857 $this->tocontents = new tocontents($this);
26858 }
26859 $tocoutdent = (isset($a['tocoutdent']) ? $a['tocoutdent'] : (isset($a['outdent']) ? $a['outdent'] : ''));
26860 $TOCusePaging = (isset($a['TOCusePaging']) ? $a['TOCusePaging'] : (isset($a['paging']) ? $a['paging'] : true));
26861 $TOCuseLinking = (isset($a['TOCuseLinking']) ? $a['TOCuseLinking'] : (isset($a['links']) ? $a['links'] : ''));
26862 $toc_orientation = (isset($a['toc_orientation']) ? $a['toc_orientation'] : (isset($a['toc-orientation']) ? $a['toc-orientation'] : ''));
26863 $toc_mgl = (isset($a['toc_mgl']) ? $a['toc_mgl'] : (isset($a['toc-margin-left']) ? $a['toc-margin-left'] : ''));
26864 $toc_mgr = (isset($a['toc_mgr']) ? $a['toc_mgr'] : (isset($a['toc-margin-right']) ? $a['toc-margin-right'] : ''));
26865 $toc_mgt = (isset($a['toc_mgt']) ? $a['toc_mgt'] : (isset($a['toc-margin-top']) ? $a['toc-margin-top'] : ''));
26866 $toc_mgb = (isset($a['toc_mgb']) ? $a['toc_mgb'] : (isset($a['toc-margin-bottom']) ? $a['toc-margin-bottom'] : ''));
26867 $toc_mgh = (isset($a['toc_mgh']) ? $a['toc_mgh'] : (isset($a['toc-margin-header']) ? $a['toc-margin-header'] : ''));
26868 $toc_mgf = (isset($a['toc_mgf']) ? $a['toc_mgf'] : (isset($a['toc-margin-footer']) ? $a['toc-margin-footer'] : ''));
26869 $toc_ohname = (isset($a['toc_ohname']) ? $a['toc_ohname'] : (isset($a['toc-odd-header-name']) ? $a['toc-odd-header-name'] : ''));
26870 $toc_ehname = (isset($a['toc_ehname']) ? $a['toc_ehname'] : (isset($a['toc-even-header-name']) ? $a['toc-even-header-name'] : ''));
26871 $toc_ofname = (isset($a['toc_ofname']) ? $a['toc_ofname'] : (isset($a['toc-odd-footer-name']) ? $a['toc-odd-footer-name'] : ''));
26872 $toc_efname = (isset($a['toc_efname']) ? $a['toc_efname'] : (isset($a['toc-even-footer-name']) ? $a['toc-even-footer-name'] : ''));
26873 $toc_ohvalue = (isset($a['toc_ohvalue']) ? $a['toc_ohvalue'] : (isset($a['toc-odd-header-value']) ? $a['toc-odd-header-value'] : 0));
26874 $toc_ehvalue = (isset($a['toc_ehvalue']) ? $a['toc_ehvalue'] : (isset($a['toc-even-header-value']) ? $a['toc-even-header-value'] : 0));
26875 $toc_ofvalue = (isset($a['toc_ofvalue']) ? $a['toc_ofvalue'] : (isset($a['toc-odd-footer-value']) ? $a['toc-odd-footer-value'] : 0));
26876 $toc_efvalue = (isset($a['toc_efvalue']) ? $a['toc_efvalue'] : (isset($a['toc-even-footer-value']) ? $a['toc-even-footer-value'] : 0));
26877 $toc_preHTML = (isset($a['toc_preHTML']) ? $a['toc_preHTML'] : (isset($a['toc-preHTML']) ? $a['toc-preHTML'] : ''));
26878 $toc_postHTML = (isset($a['toc_postHTML']) ? $a['toc_postHTML'] : (isset($a['toc-postHTML']) ? $a['toc-postHTML'] : ''));
26879 $toc_bookmarkText = (isset($a['toc_bookmarkText']) ? $a['toc_bookmarkText'] : (isset($a['toc-bookmarkText']) ? $a['toc-bookmarkText'] : ''));
26880 $resetpagenum = (isset($a['resetpagenum']) ? $a['resetpagenum'] : '');
26881 $pagenumstyle = (isset($a['pagenumstyle']) ? $a['pagenumstyle'] : '');
26882 $suppress = (isset($a['suppress']) ? $a['suppress'] : '');
26883 $orientation = (isset($a['orientation']) ? $a['orientation'] : '');
26884 $mgl = (isset($a['mgl']) ? $a['mgl'] : (isset($a['margin-left']) ? $a['margin-left'] : ''));
26885 $mgr = (isset($a['mgr']) ? $a['mgr'] : (isset($a['margin-right']) ? $a['margin-right'] : ''));
26886 $mgt = (isset($a['mgt']) ? $a['mgt'] : (isset($a['margin-top']) ? $a['margin-top'] : ''));
26887 $mgb = (isset($a['mgb']) ? $a['mgb'] : (isset($a['margin-bottom']) ? $a['margin-bottom'] : ''));
26888 $mgh = (isset($a['mgh']) ? $a['mgh'] : (isset($a['margin-header']) ? $a['margin-header'] : ''));
26889 $mgf = (isset($a['mgf']) ? $a['mgf'] : (isset($a['margin-footer']) ? $a['margin-footer'] : ''));
26890 $ohname = (isset($a['ohname']) ? $a['ohname'] : (isset($a['odd-header-name']) ? $a['odd-header-name'] : ''));
26891 $ehname = (isset($a['ehname']) ? $a['ehname'] : (isset($a['even-header-name']) ? $a['even-header-name'] : ''));
26892 $ofname = (isset($a['ofname']) ? $a['ofname'] : (isset($a['odd-footer-name']) ? $a['odd-footer-name'] : ''));
26893 $efname = (isset($a['efname']) ? $a['efname'] : (isset($a['even-footer-name']) ? $a['even-footer-name'] : ''));
26894 $ohvalue = (isset($a['ohvalue']) ? $a['ohvalue'] : (isset($a['odd-header-value']) ? $a['odd-header-value'] : 0));
26895 $ehvalue = (isset($a['ehvalue']) ? $a['ehvalue'] : (isset($a['even-header-value']) ? $a['even-header-value'] : 0));
26896 $ofvalue = (isset($a['ofvalue']) ? $a['ofvalue'] : (isset($a['odd-footer-value']) ? $a['odd-footer-value'] : 0));
26897 $efvalue = (isset($a['efvalue']) ? $a['efvalue'] : (isset($a['even-footer-value']) ? $a['even-footer-value'] : 0));
26898 $toc_id = (isset($a['toc_id']) ? $a['toc_id'] : (isset($a['name']) ? $a['name'] : 0));
26899 $pagesel = (isset($a['pagesel']) ? $a['pagesel'] : (isset($a['pageselector']) ? $a['pageselector'] : ''));
26900 $toc_pagesel = (isset($a['toc_pagesel']) ? $a['toc_pagesel'] : (isset($a['toc-pageselector']) ? $a['toc-pageselector'] : ''));
26901 $sheetsize = (isset($a['sheetsize']) ? $a['sheetsize'] : (isset($a['sheet-size']) ? $a['sheet-size'] : ''));
26902 $toc_sheetsize = (isset($a['toc_sheetsize']) ? $a['toc_sheetsize'] : (isset($a['toc-sheet-size']) ? $a['toc-sheet-size'] : ''));
26903
26904 $this->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);
26905 }
26906
26907 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 = '')
26908 {
26909 if (!class_exists('tocontents', false)) {
26910 include(_MPDF_PATH . 'classes/tocontents.php');
26911 }
26912 if (empty($this->tocontents)) {
26913 $this->tocontents = new tocontents($this);
26914 }
26915 if (!$resetpagenum) {
26916 $resetpagenum = 1;
26917 } // mPDF 6
26918 //Start a new page
26919 if ($this->state == 0)
26920 $this->AddPage();
26921 if ($this->y == $this->tMargin && (!$this->mirrorMargins || ($this->mirrorMargins && $this->page % 2 == 1))) {
26922 // Don't add a page
26923 if ($this->page == 1 && count($this->PageNumSubstitutions) == 0) {
26924 if (!$suppress) {
26925 $suppress = 'off';
26926 }
26927 //$this->PageNumSubstitutions[] = array('from'=>1, 'reset'=> $resetpagenum, 'type'=>$pagenumstyle, 'suppress'=> $suppress);
26928 }
26929 $this->PageNumSubstitutions[] = array('from' => $this->page, 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress);
26930 } else {
26931 $this->AddPage($orientation, 'NEXT-ODD', $resetpagenum, $pagenumstyle, $suppress, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $sheetsize);
26932 }
26933 $this->tocontents->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);
26934 }
26935
26936 function TOC_Entry($txt, $level = 0, $toc_id = 0)
26937 {
26938 if ($this->ColActive) {
26939 $ily = $this->y0;
26940 } else {
26941 $ily = $this->y;
26942 } // use top of columns
26943
26944 if (!class_exists('tocontents', false)) {
26945 include(_MPDF_PATH . 'classes/tocontents.php');
26946 }
26947 if (empty($this->tocontents)) {
26948 $this->tocontents = new tocontents($this);
26949 }
26950 $linkn = $this->AddLink();
26951 $uid = '__mpdfinternallink_' . $linkn;
26952 if ($this->table_rotate) {
26953 $this->internallink[$uid] = array("Y" => $ily, "PAGE" => $this->page, "tbrot" => true);
26954 } elseif ($this->kwt) {
26955 $this->internallink[$uid] = array("Y" => $ily, "PAGE" => $this->page, "kwt" => true);
26956 } elseif ($this->ColActive) {
26957 $this->internallink[$uid] = array("Y" => $ily, "PAGE" => $this->page, "col" => $this->CurrCol);
26958 } elseif (!$this->keep_block_together) {
26959 $this->internallink[$uid] = array("Y" => $ily, "PAGE" => $this->page);
26960 }
26961 $this->internallink['#' . $uid] = $linkn;
26962 $this->SetLink($linkn, $ily, $this->page);
26963
26964 if (strtoupper($toc_id) == 'ALL') {
26965 $toc_id = '_mpdf_all';
26966 } elseif (!$toc_id) {
26967 $toc_id = 0;
26968 } else {
26969 $toc_id = strtolower($toc_id);
26970 }
26971 $btoc = array('t' => $txt, 'l' => $level, 'p' => $this->page, 'link' => $linkn, 'toc_id' => $toc_id);
26972 if ($this->keep_block_together) {
26973 // do nothing
26974 }
26975 /* -- TABLES -- */ elseif ($this->table_rotate) {
26976 $this->tbrot_toc[] = $btoc;
26977 } elseif ($this->kwt) {
26978 $this->kwt_toc[] = $btoc;
26979 }
26980 /* -- END TABLES -- */ elseif ($this->ColActive) { // *COLUMNS*
26981 $this->col_toc[] = $btoc; // *COLUMNS*
26982 } // *COLUMNS*
26983 else {
26984 $this->tocontents->_toc[] = $btoc;
26985 }
26986 }
26987
26988 /* -- END TOC -- */
26989
26990 //======================================================
26991 function MovePages($target_page, $start_page, $end_page = -1)
26992 {
26993 // move a page/pages EARLIER in the document
26994 if ($end_page < 1) {
26995 $end_page = $start_page;
26996 }
26997 $n_toc = $end_page - $start_page + 1;
26998
26999 // Set/Update PageNumSubstitutions changes before moving anything
27000 if (count($this->PageNumSubstitutions)) {
27001 $tp_present = false;
27002 $sp_present = false;
27003 $ep_present = false;
27004 foreach ($this->PageNumSubstitutions AS $k => $v) {
27005 if ($this->PageNumSubstitutions[$k]['from'] == $target_page) {
27006 $tp_present = true;
27007 if ($this->PageNumSubstitutions[$k]['suppress'] != 'on' && $this->PageNumSubstitutions[$k]['suppress'] != 1) {
27008 $this->PageNumSubstitutions[$k]['suppress'] = 'off';
27009 }
27010 }
27011 if ($this->PageNumSubstitutions[$k]['from'] == $start_page) {
27012 $sp_present = true;
27013 if ($this->PageNumSubstitutions[$k]['suppress'] != 'on' && $this->PageNumSubstitutions[$k]['suppress'] != 1) {
27014 $this->PageNumSubstitutions[$k]['suppress'] = 'off';
27015 }
27016 }
27017 if ($this->PageNumSubstitutions[$k]['from'] == ($end_page + 1)) {
27018 $ep_present = true;
27019 if ($this->PageNumSubstitutions[$k]['suppress'] != 'on' && $this->PageNumSubstitutions[$k]['suppress'] != 1) {
27020 $this->PageNumSubstitutions[$k]['suppress'] = 'off';
27021 }
27022 }
27023 }
27024
27025 if (!$tp_present) {
27026 list($tp_type, $tp_suppress, $tp_reset) = $this->docPageSettings($target_page);
27027 }
27028 if (!$sp_present) {
27029 list($sp_type, $sp_suppress, $sp_reset) = $this->docPageSettings($start_page);
27030 }
27031 if (!$ep_present) {
27032 list($ep_type, $ep_suppress, $ep_reset) = $this->docPageSettings($start_page - 1);
27033 }
27034 }
27035
27036 $last = array();
27037 //store pages
27038 for ($i = $start_page; $i <= $end_page; $i++)
27039 $last[] = $this->pages[$i];
27040 //move pages
27041 for ($i = $start_page - 1; $i >= ($target_page); $i--) {
27042 $this->pages[$i + $n_toc] = $this->pages[$i];
27043 }
27044 //Put toc pages at insert point
27045 for ($i = 0; $i < $n_toc; $i++) {
27046 $this->pages[$target_page + $i] = $last[$i];
27047 }
27048
27049 /* -- BOOKMARKS -- */
27050 // Update Bookmarks
27051 foreach ($this->BMoutlines as $i => $o) {
27052 if ($o['p'] >= $target_page) {
27053 $this->BMoutlines[$i]['p'] += $n_toc;
27054 }
27055 }
27056 /* -- END BOOKMARKS -- */
27057
27058 // Update Page Links
27059 if (count($this->PageLinks)) {
27060 $newarr = array();
27061 foreach ($this->PageLinks as $i => $o) {
27062 foreach ($this->PageLinks[$i] as $key => $pl) {
27063 if (strpos($pl[4], '@') === 0) {
27064 $p = substr($pl[4], 1);
27065 if ($p >= $start_page && $p <= $end_page) {
27066 $this->PageLinks[$i][$key][4] = '@' . ($p + ($target_page - $start_page));
27067 } elseif ($p >= $target_page && $p < $start_page) {
27068 $this->PageLinks[$i][$key][4] = '@' . ($p + $n_toc);
27069 }
27070 }
27071 }
27072 if ($i >= $start_page && $i <= $end_page) {
27073 $newarr[($i + ($target_page - $start_page))] = $this->PageLinks[$i];
27074 } elseif ($i >= $target_page && $i < $start_page) {
27075 $newarr[($i + $n_toc)] = $this->PageLinks[$i];
27076 } else {
27077 $newarr[$i] = $this->PageLinks[$i];
27078 }
27079 }
27080 $this->PageLinks = $newarr;
27081 }
27082
27083 // OrientationChanges
27084 if (count($this->OrientationChanges)) {
27085 $newarr = array();
27086 foreach ($this->OrientationChanges AS $p => $v) {
27087 if ($p >= $start_page && $p <= $end_page) {
27088 $newarr[($p + ($target_page - $start_page))] = $this->OrientationChanges[$p];
27089 } elseif ($p >= $target_page && $p < $start_page) {
27090 $newarr[$p + $n_toc] = $this->OrientationChanges[$p];
27091 } else {
27092 $newarr[$p] = $this->OrientationChanges[$p];
27093 }
27094 }
27095 ksort($newarr);
27096 $this->OrientationChanges = $newarr;
27097 }
27098
27099 // Page Dimensions
27100 if (count($this->pageDim)) {
27101 $newarr = array();
27102 foreach ($this->pageDim AS $p => $v) {
27103 if ($p >= $start_page && $p <= $end_page) {
27104 $newarr[($p + ($target_page - $start_page))] = $this->pageDim[$p];
27105 } elseif ($p >= $target_page && $p < $start_page) {
27106 $newarr[$p + $n_toc] = $this->pageDim[$p];
27107 } else {
27108 $newarr[$p] = $this->pageDim[$p];
27109 }
27110 }
27111 ksort($newarr);
27112 $this->pageDim = $newarr;
27113 }
27114
27115 // HTML Headers & Footers
27116 if (count($this->saveHTMLHeader)) {
27117 $newarr = array();
27118 foreach ($this->saveHTMLHeader AS $p => $v) {
27119 if ($p >= $start_page && $p <= $end_page) {
27120 $newarr[($p + ($target_page - $start_page))] = $this->saveHTMLHeader[$p];
27121 } elseif ($p >= $target_page && $p < $start_page) {
27122 $newarr[$p + $n_toc] = $this->saveHTMLHeader[$p];
27123 } else {
27124 $newarr[$p] = $this->saveHTMLHeader[$p];
27125 }
27126 }
27127 ksort($newarr);
27128 $this->saveHTMLHeader = $newarr;
27129 }
27130 if (count($this->saveHTMLFooter)) {
27131 $newarr = array();
27132 foreach ($this->saveHTMLFooter AS $p => $v) {
27133 if ($p >= $start_page && $p <= $end_page) {
27134 $newarr[($p + ($target_page - $start_page))] = $this->saveHTMLFooter[$p];
27135 } elseif ($p >= $target_page && $p < $start_page) {
27136 $newarr[$p + $n_toc] = $this->saveHTMLFooter[$p];
27137 } else {
27138 $newarr[$p] = $this->saveHTMLFooter[$p];
27139 }
27140 }
27141 ksort($newarr);
27142 $this->saveHTMLFooter = $newarr;
27143 }
27144
27145 // Update Internal Links
27146 if (count($this->internallink)) {
27147 foreach ($this->internallink as $key => $o) {
27148 if ($o['PAGE'] >= $start_page && $o['PAGE'] <= $end_page) {
27149 $this->internallink[$key]['PAGE'] += ($target_page - $start_page);
27150 } elseif ($o['PAGE'] >= $target_page && $o['PAGE'] < $start_page) {
27151 $this->internallink[$key]['PAGE'] += $n_toc;
27152 }
27153 }
27154 }
27155
27156 // Update Links
27157 if (count($this->links)) {
27158 foreach ($this->links as $key => $o) {
27159 if ($o[0] >= $start_page && $o[0] <= $end_page) {
27160 $this->links[$key][0] += ($target_page - $start_page);
27161 }
27162 if ($o[0] >= $target_page && $o[0] < $start_page) {
27163 $this->links[$key][0] += $n_toc;
27164 }
27165 }
27166 }
27167
27168 // Update Form fields
27169 if (count($this->mpdfform->forms)) {
27170 foreach ($this->mpdfform->forms as $key => $f) {
27171 if ($f['page'] >= $start_page && $f['page'] <= $end_page) {
27172 $this->mpdfform->forms[$key]['page'] += ($target_page - $start_page);
27173 }
27174 if ($f['page'] >= $target_page && $f['page'] < $start_page) {
27175 $this->mpdfform->forms[$key]['page'] += $n_toc;
27176 }
27177 }
27178 }
27179
27180 /* -- ANNOTATIONS -- */
27181 // Update Annotations
27182 if (count($this->PageAnnots)) {
27183 $newarr = array();
27184 foreach ($this->PageAnnots as $p => $anno) {
27185 if ($p >= $start_page && $p <= $end_page) {
27186 $np = $p + ($target_page - $start_page);
27187 foreach ($anno as $o) {
27188 $newarr[$np][] = $o;
27189 }
27190 } elseif ($p >= $target_page && $p < $start_page) {
27191 $np = $p + $n_toc;
27192 foreach ($anno as $o) {
27193 $newarr[$np][] = $o;
27194 }
27195 } else {
27196 $newarr[$p] = $this->PageAnnots[$p];
27197 }
27198 }
27199 $this->PageAnnots = $newarr;
27200 unset($newarr);
27201 }
27202 /* -- END ANNOTATIONS -- */
27203
27204 // Update PageNumSubstitutions
27205 if (count($this->PageNumSubstitutions)) {
27206 $newarr = array();
27207 foreach ($this->PageNumSubstitutions AS $k => $v) {
27208 if ($this->PageNumSubstitutions[$k]['from'] >= $start_page && $this->PageNumSubstitutions[$k]['from'] <= $end_page) {
27209 $this->PageNumSubstitutions[$k]['from'] += ($target_page - $start_page);
27210 $newarr[$this->PageNumSubstitutions[$k]['from']] = $this->PageNumSubstitutions[$k];
27211 } elseif ($this->PageNumSubstitutions[$k]['from'] >= $target_page && $this->PageNumSubstitutions[$k]['from'] < $start_page) {
27212 $this->PageNumSubstitutions[$k]['from'] += $n_toc;
27213 $newarr[$this->PageNumSubstitutions[$k]['from']] = $this->PageNumSubstitutions[$k];
27214 } else {
27215 $newarr[$this->PageNumSubstitutions[$k]['from']] = $this->PageNumSubstitutions[$k];
27216 }
27217 }
27218
27219 if (!$sp_present) {
27220 $newarr[$target_page] = array('from' => $target_page, 'suppress' => $sp_suppress, 'reset' => $sp_reset, 'type' => $sp_type);
27221 }
27222 if (!$tp_present) {
27223 $newarr[($target_page + $n_toc)] = array('from' => ($target_page + $n_toc), 'suppress' => $tp_suppress, 'reset' => $tp_reset, 'type' => $tp_type);
27224 }
27225 if (!$ep_present && $end_page > count($this->pages)) {
27226 $newarr[($end_page + 1)] = array('from' => ($end_page + 1), 'suppress' => $ep_suppress, 'reset' => $ep_reset, 'type' => $ep_type);
27227 }
27228 ksort($newarr);
27229 $this->PageNumSubstitutions = array();
27230 foreach ($newarr as $v) {
27231 $this->PageNumSubstitutions[] = $v;
27232 }
27233 }
27234 }
27235
27236 //======================================================
27237 function DeletePages($start_page, $end_page = -1)
27238 {
27239 // move a page/pages EARLIER in the document
27240 if ($end_page < 1) {
27241 $end_page = $start_page;
27242 }
27243 $n_tod = $end_page - $start_page + 1;
27244 $last_page = count($this->pages);
27245 $n_atend = $last_page - $end_page + 1;
27246
27247 //move pages
27248 for ($i = 0; $i < $n_atend; $i++) {
27249 $this->pages[$start_page + $i] = $this->pages[$end_page + 1 + $i];
27250 }
27251 //delete pages
27252 for ($i = 0; $i < $n_tod; $i++)
27253 unset($this->pages[$last_page - $i]);
27254
27255
27256 /* -- BOOKMARKS -- */
27257 // Update Bookmarks
27258 foreach ($this->BMoutlines as $i => $o) {
27259 if ($o['p'] >= $end_page) {
27260 $this->BMoutlines[$i]['p'] -= $n_tod;
27261 } elseif ($p < $start_page) {
27262 unset($this->BMoutlines[$i]);
27263 }
27264 }
27265 /* -- END BOOKMARKS -- */
27266
27267 // Update Page Links
27268 if (count($this->PageLinks)) {
27269 $newarr = array();
27270 foreach ($this->PageLinks as $i => $o) {
27271 foreach ($this->PageLinks[$i] as $key => $pl) {
27272 if (strpos($pl[4], '@') === 0) {
27273 $p = substr($pl[4], 1);
27274 if ($p > $end_page) {
27275 $this->PageLinks[$i][$key][4] = '@' . ($p - $n_tod);
27276 } elseif ($p < $start_page) {
27277 unset($this->PageLinks[$i][$key]);
27278 }
27279 }
27280 }
27281 if ($i > $end_page) {
27282 $newarr[($i - $n_tod)] = $this->PageLinks[$i];
27283 } elseif ($p < $start_page) {
27284 $newarr[$i] = $this->PageLinks[$i];
27285 }
27286 }
27287 $this->PageLinks = $newarr;
27288 }
27289
27290 // OrientationChanges
27291 if (count($this->OrientationChanges)) {
27292 $newarr = array();
27293 foreach ($this->OrientationChanges AS $p => $v) {
27294 if ($p > $end_page) {
27295 $newarr[($p - $t_tod)] = $this->OrientationChanges[$p];
27296 } elseif ($p < $start_page) {
27297 $newarr[$p] = $this->OrientationChanges[$p];
27298 }
27299 }
27300 ksort($newarr);
27301 $this->OrientationChanges = $newarr;
27302 }
27303
27304 // Page Dimensions
27305 if (count($this->pageDim)) {
27306 $newarr = array();
27307 foreach ($this->pageDim AS $p => $v) {
27308 if ($p > $end_page) {
27309 $newarr[($p - $n_tod)] = $this->pageDim[$p];
27310 } elseif ($p < $start_page) {
27311 $newarr[$p] = $this->pageDim[$p];
27312 }
27313 }
27314 ksort($newarr);
27315 $this->pageDim = $newarr;
27316 }
27317
27318 // HTML Headers & Footers
27319 if (count($this->saveHTMLHeader)) {
27320 foreach ($this->saveHTMLHeader AS $p => $v) {
27321 if ($p > $end_page) {
27322 $newarr[($p - $n_tod)] = $this->saveHTMLHeader[$p];
27323 } // mPDF 5.7.3
27324 elseif ($p < $start_page) {
27325 $newarr[$p] = $this->saveHTMLHeader[$p];
27326 }
27327 }
27328 ksort($newarr);
27329 $this->saveHTMLHeader = $newarr;
27330 }
27331 if (count($this->saveHTMLFooter)) {
27332 $newarr = array();
27333 foreach ($this->saveHTMLFooter AS $p => $v) {
27334 if ($p > $end_page) {
27335 $newarr[($p - $n_tod)] = $this->saveHTMLFooter[$p];
27336 } elseif ($p < $start_page) {
27337 $newarr[$p] = $this->saveHTMLFooter[$p];
27338 }
27339 }
27340 ksort($newarr);
27341 $this->saveHTMLFooter = $newarr;
27342 }
27343
27344 // Update Internal Links
27345 foreach ($this->internallink as $key => $o) {
27346 if ($o['PAGE'] > $end_page) {
27347 $this->internallink[$key]['PAGE'] -= $n_tod;
27348 } elseif ($o['PAGE'] < $start_page) {
27349 unset($this->internallink[$key]);
27350 }
27351 }
27352
27353 // Update Links
27354 foreach ($this->links as $key => $o) {
27355 if ($o[0] > $end_page) {
27356 $this->links[$key][0] -= $n_tod;
27357 } elseif ($o[0] < $start_page) {
27358 unset($this->links[$key]);
27359 }
27360 }
27361
27362 // Update Form fields
27363 foreach ($this->mpdfform->forms as $key => $f) {
27364 if ($f['page'] > $end_page) {
27365 $this->mpdfform->forms[$key]['page'] -= $n_tod;
27366 } elseif ($f['page'] < $start_page) {
27367 unset($this->mpdfform->forms[$key]);
27368 }
27369 }
27370
27371 /* -- ANNOTATIONS -- */
27372 // Update Annotations
27373 if (count($this->PageAnnots)) {
27374 $newarr = array();
27375 foreach ($this->PageAnnots as $p => $anno) {
27376 if ($p > $end_page) {
27377 foreach ($anno as $o) {
27378 $newarr[($p - $n_tod)][] = $o;
27379 }
27380 } elseif ($p < $start_page) {
27381 $newarr[$p] = $this->PageAnnots[$p];
27382 }
27383 }
27384 ksort($newarr);
27385 $this->PageAnnots = $newarr;
27386 }
27387 /* -- END ANNOTATIONS -- */
27388
27389 // Update PageNumSubstitutions
27390 foreach ($this->PageNumSubstitutions AS $k => $v) {
27391 if ($this->PageNumSubstitutions[$k]['from'] > $end_page) {
27392 $this->PageNumSubstitutions[$k]['from'] -= $n_tod;
27393 } elseif ($this->PageNumSubstitutions[$k]['from'] < $start_page) {
27394 unset($this->PageNumSubstitutions[$k]);
27395 }
27396 }
27397
27398 unset($newarr);
27399 $this->page = count($this->pages);
27400 }
27401
27402 //======================================================
27403 /* -- INDEX -- */
27404 // FROM class PDF_Ref == INDEX
27405
27406 function IndexEntry($txt, $xref = '')
27407 {
27408 if ($xref) {
27409 $this->IndexEntrySee($txt, $xref);
27410 return;
27411 }
27412
27413 //Search the reference (AND Ref/PageNo) in the array
27414 $Present = false;
27415 if ($this->keep_block_together) {
27416 // do nothing
27417 }
27418 /* -- TABLES -- */ elseif ($this->kwt) {
27419 $size = count($this->kwt_Reference);
27420 for ($i = 0; $i < $size; $i++) {
27421 if (isset($this->kwt_Reference[$i]['t']) && $this->kwt_Reference[$i]['t'] == $txt) {
27422 $Present = true;
27423 if ($this->page != $this->kwt_Reference[$i]['op']) {
27424 $this->kwt_Reference[$i]['op'] = $this->page;
27425 }
27426 }
27427 }
27428 if (!$Present) { //If not found, add it
27429 $this->kwt_Reference[] = array('t' => $txt, 'op' => $this->page);
27430 }
27431 }
27432 /* -- END TABLES -- */ else {
27433 $size = count($this->Reference);
27434 for ($i = 0; $i < $size; $i++) {
27435 if (isset($this->Reference[$i]['t']) && $this->Reference[$i]['t'] == $txt) {
27436 $Present = true;
27437 if (!in_array($this->page, $this->Reference[$i]['p'])) {
27438 $this->Reference[$i]['p'][] = $this->page;
27439 }
27440 }
27441 }
27442 if (!$Present) { //If not found, add it
27443 $this->Reference[] = array('t' => $txt, 'p' => array($this->page));
27444 }
27445 }
27446 }
27447
27448 // Added function to add a reference "Elephants. See Chickens"
27449 function IndexEntrySee($txta, $txtb)
27450 {
27451 if ($this->directionality == 'rtl') { // *OTL*
27452 // ONLY DO THIS IF NOT IN TAGS
27453 if ($txta == strip_tags($txta))
27454 $txta = str_replace(':', ' - ', $txta); // *OTL*
27455 if ($txtb == strip_tags($txtb))
27456 $txtb = str_replace(':', ' - ', $txtb); // *OTL*
27457 } // *OTL*
27458 else { // *OTL*
27459 if ($txta == strip_tags($txta))
27460 $txta = str_replace(':', ', ', $txta);
27461 if ($txtb == strip_tags($txtb))
27462 $txtb = str_replace(':', ', ', $txtb);
27463 } // *OTL*
27464 $this->Reference[] = array('t' => $txta . ' - see ' . $txtb, 'p' => array());
27465 }
27466
27467 function InsertIndex($usedivletters = 1, $useLinking = false, $indexCollationLocale = '', $indexCollationGroup = '')
27468 {
27469 $size = count($this->Reference);
27470 if ($size == 0) {
27471 return false;
27472 }
27473
27474 // $spacer used after named entry
27475 // $sep separates number [groups], $joiner joins numbers in range
27476 // e.g. "elephant 73, 97-99" = elephant[$spacer]73[$sep]97[$joiner]99
27477 // $subEntrySeparator separates main and subentry (if $this->indexUseSubentries == false;) e.g.
27478 // Mammal:elephant => Mammal[$subEntrySeparator]elephant
27479 // $subEntryInset specifies what precedes a subentry (if $this->indexUseSubentries == true;) e.g.
27480 // Mammal:elephant => [$subEntryInset]elephant
27481 $spacer = "\xc2\xa0 ";
27482 if ($this->directionality == 'rtl') {
27483 $sep = '&#x060c; ';
27484 $joiner = '-';
27485 $subEntrySeparator = '&#x060c; ';
27486 $subEntryInset = ' - ';
27487 } else {
27488 $sep = ', ';
27489 $joiner = '-';
27490 $subEntrySeparator = ', ';
27491 $subEntryInset = ' - ';
27492 }
27493
27494 for ($i = 0; $i < $size; $i++) {
27495 $txt = $this->Reference[$i]['t'];
27496 $txt = strip_tags($txt); // mPDF 6
27497 $txt = $this->purify_utf8($txt);
27498 $this->Reference[$i]['uf'] = $txt; // Unformatted e.g. pure utf-8 encoded characters, no mark-up/tags
27499 // Used for ordering and collation
27500 }
27501
27502 if ($usedivletters) {
27503 if ($indexCollationGroup) {
27504 require_once(_MPDF_PATH . 'collations/' . $indexCollationGroup . '.php');
27505 } else {
27506 $collation = array();
27507 }
27508 for ($i = 0; $i < $size; $i++) {
27509 if ($this->Reference[$i]['uf']) {
27510 $l = mb_substr($this->Reference[$i]['uf'], 0, 1, 'UTF-8');
27511 if (isset($this->indexCollationGroup) && $this->indexCollationGroup) {
27512 $uni = $this->UTF8StringToArray($l);
27513 $ucode = $uni[0];
27514 if (isset($collation[$ucode])) {
27515 $this->Reference[$i]['d'] = code2utf($collation[$ucode]);
27516 } else {
27517 $this->Reference[$i]['d'] = mb_strtolower($l, 'UTF-8');
27518 }
27519 } else {
27520 $this->Reference[$i]['d'] = mb_strtolower($l, 'UTF-8');
27521 }
27522 }
27523 }
27524 }
27525
27526 if (!function_exists('cmp')) {
27527
27528 function cmp($a, $b)
27529 {
27530 return strcoll(strtolower($a['uf']), strtolower($b['uf']));
27531 }
27532
27533 }
27534 //Alphabetic sort of the references
27535 $originalLocale = setlocale(LC_COLLATE, 0);
27536 if ($indexCollationLocale) {
27537 setlocale(LC_COLLATE, $indexCollationLocale);
27538 }
27539 usort($this->Reference, 'cmp');
27540 if ($indexCollationLocale) {
27541 setlocale(LC_COLLATE, $originalLocale);
27542 }
27543
27544 $html = '<div class="mpdf_index_main">';
27545
27546 $lett = '';
27547 $last_lett = '';
27548 $mainentry = '';
27549 for ($i = 0; $i < $size; $i++) {
27550 if ($this->Reference[$i]['t']) {
27551 if ($usedivletters) {
27552 $lett = $this->Reference[$i]['d'];
27553 if ($lett != $last_lett) {
27554 $html .= '<div class="mpdf_index_letter">' . $lett . '</div>';
27555 }
27556 }
27557 $txt = $this->Reference[$i]['t'];
27558
27559 // Sub-entries e.g. Mammals:elephant
27560 // But allow for tags e.g. <b>Mammal</b>:elephants
27561 $a = preg_split('/(<.*?>)/', $txt, -1, PREG_SPLIT_DELIM_CAPTURE);
27562 $txt = '';
27563 $marker = false;
27564 foreach ($a as $k => $e) {
27565 if ($k % 2 == 0 && !$marker) {
27566 if (strpos($e, ':') !== false) { // == SubEntry
27567 if ($this->indexUseSubentries) {
27568
27569 // If the Main entry does not have any page numbers associated with it
27570 // create and insert an entry
27571 list($txtmain, $sub) = preg_split('/[:]/', $e, 2);
27572 if (strip_tags($txt . $txtmain) != $mainentry) {
27573 $html .= '<div class="mpdf_index_entry">' . $txt . $txtmain . '</div>';
27574 $mainentry = strip_tags($txt . $txtmain);
27575 }
27576
27577 $txt = $subEntryInset;
27578 $e = $sub; // Only replace first one
27579 } else {
27580 $e = preg_replace('/[:]/', $subEntrySeparator, $e, 1); // Only replace first one
27581 }
27582 $marker = true; // Don't replace any more once the subentry marker has been found
27583 }
27584 }
27585 $txt .= $e;
27586 }
27587
27588 if (!$marker) {
27589 $mainentry = strip_tags($txt);
27590 }
27591
27592 $html .= '<div class="mpdf_index_entry">';
27593 $html .= $txt;
27594 $ppp = $this->Reference[$i]['p']; // = array of page numbers to point to
27595 if (count($ppp)) {
27596 sort($ppp);
27597 $newarr = array();
27598 $range_start = $ppp[0];
27599 $range_end = 0;
27600
27601 $html .= $spacer;
27602
27603 for ($zi = 1; $zi < count($ppp); $zi++) {
27604 if ($ppp[$zi] == ($ppp[($zi - 1)] + 1)) {
27605 $range_end = $ppp[$zi];
27606 } else {
27607 if ($range_end) {
27608 if ($range_end == $range_start + 1) {
27609 if ($useLinking) {
27610 $html .= '<a class="mpdf_index_link" href="@' . $range_start . '">';
27611 }
27612 $html .= $this->docPageNum($range_start);
27613 if ($useLinking) {
27614 $html .= '</a>';
27615 }
27616 $html .= $sep;
27617
27618 if ($useLinking) {
27619 $html .= '<a class="mpdf_index_link" href="@' . $ppp[$zi - 1] . '">';
27620 }
27621 $html .= $this->docPageNum($ppp[$zi - 1]);
27622 if ($useLinking) {
27623 $html .= '</a>';
27624 }
27625 $html .= $sep;
27626 }
27627 } else {
27628 if ($useLinking) {
27629 $html .= '<a class="mpdf_index_link" href="@' . $ppp[$zi - 1] . '">';
27630 }
27631 $html .= $this->docPageNum($ppp[$zi - 1]);
27632 if ($useLinking) {
27633 $html .= '</a>';
27634 }
27635 $html .= $sep;
27636 }
27637 $range_start = $ppp[$zi];
27638 $range_end = 0;
27639 }
27640 }
27641
27642 if ($range_end) {
27643 if ($useLinking) {
27644 $html .= '<a class="mpdf_index_link" href="@' . $range_start . '">';
27645 }
27646 $html .= $this->docPageNum($range_start);
27647 if ($range_end == $range_start + 1) {
27648 if ($useLinking) {
27649 $html .= '</a>';
27650 }
27651 $html .= $sep;
27652 if ($useLinking) {
27653 $html .= '<a class="mpdf_index_link" href="@' . $range_end . '">';
27654 }
27655 $html .= $this->docPageNum($range_end);
27656 if ($useLinking) {
27657 $html .= '</a>';
27658 }
27659 } else {
27660 $html .= $joiner;
27661 $html .= $this->docPageNum($range_end);
27662 if ($useLinking) {
27663 $html .= '</a>';
27664 }
27665 }
27666 } else {
27667 if ($useLinking) {
27668 $html .= '<a class="mpdf_index_link" href="@' . $ppp[(count($ppp) - 1)] . '">';
27669 }
27670 $html .= $this->docPageNum($ppp[(count($ppp) - 1)]);
27671 if ($useLinking) {
27672 $html .= '</a>';
27673 }
27674 }
27675 }
27676 }
27677 $html .= '</div>';
27678 $last_lett = $lett;
27679 }
27680 $html .= '</div>';
27681 $save_fpb = $this->fixedPosBlockSave;
27682 $this->WriteHTML($html);
27683 $this->fixedPosBlockSave = $save_fpb;
27684
27685 $this->breakpoints[$this->CurrCol][] = $this->y; // *COLUMNS*
27686 }
27687
27688 /* -- END INDEX -- */
27689
27690 function AcceptPageBreak()
27691 {
27692 if (count($this->cellBorderBuffer)) {
27693 $this->printcellbuffer();
27694 } // *TABLES*
27695 /* -- COLUMNS -- */
27696 if ($this->ColActive == 1) {
27697 if ($this->CurrCol < $this->NbCol - 1) {
27698 //Go to the next column
27699 $this->CurrCol++;
27700 $this->SetCol($this->CurrCol);
27701 $this->y = $this->y0;
27702 $this->ChangeColumn = 1; // Number (and direction) of columns changed +1, +2, -2 etc.
27703 // DIRECTIONALITY RTL
27704 if ($this->directionality == 'rtl') {
27705 $this->ChangeColumn = -($this->ChangeColumn);
27706 } // *OTL*
27707 //Stay on the page
27708 return false;
27709 } else {
27710 //Go back to the first column - NEW PAGE
27711 if (count($this->columnbuffer)) {
27712 $this->printcolumnbuffer();
27713 }
27714 $this->SetCol(0);
27715 $this->y0 = $this->tMargin;
27716 $this->ChangeColumn = -($this->NbCol - 1);
27717 // DIRECTIONALITY RTL
27718 if ($this->directionality == 'rtl') {
27719 $this->ChangeColumn = -($this->ChangeColumn);
27720 } // *OTL*
27721 //Page break
27722 return true;
27723 }
27724 }
27725 /* -- END COLUMNS -- */
27726 /* -- TABLES -- */ elseif ($this->table_rotate) {
27727 if ($this->tablebuffer) {
27728 $this->printtablebuffer();
27729 }
27730 return true;
27731 }
27732 /* -- END TABLES -- */ else { // *COLUMNS*
27733 $this->ChangeColumn = 0;
27734 return $this->autoPageBreak;
27735 } // *COLUMNS*
27736 return $this->autoPageBreak;
27737 }
27738
27739 //----------- COLUMNS ---------------------
27740 /* -- COLUMNS -- */
27741
27742 function SetColumns($NbCol, $vAlign = '', $gap = 5)
27743 {
27744 // NbCol = number of columns
27745 // Anything less than 2 turns columns off
27746 if ($NbCol < 2) { // SET COLUMNS OFF
27747 if ($this->ColActive) {
27748 $this->ColActive = 0;
27749 if (count($this->columnbuffer)) {
27750 $this->printcolumnbuffer();
27751 }
27752 $this->NbCol = 1;
27753 $this->ResetMargins();
27754 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
27755 $this->divwidth = 0;
27756 $this->Ln();
27757 }
27758 $this->ColActive = 0;
27759 $this->columnbuffer = array();
27760 $this->ColDetails = array();
27761 $this->columnLinks = array();
27762 $this->columnAnnots = array();
27763 $this->columnForms = array();
27764 $this->col_BMoutlines = array();
27765 $this->col_toc = array();
27766 $this->breakpoints = array();
27767 } else { // SET COLUMNS ON
27768 if ($this->ColActive) {
27769 $this->ColActive = 0;
27770 if (count($this->columnbuffer)) {
27771 $this->printcolumnbuffer();
27772 }
27773 $this->ResetMargins();
27774 }
27775 if (isset($this->y) && $this->y > $this->tMargin)
27776 $this->Ln();
27777 $this->NbCol = $NbCol;
27778 $this->ColGap = $gap;
27779 $this->divwidth = 0;
27780 $this->ColActive = 1;
27781 $this->ColumnAdjust = true; // enables column height adjustment for the page
27782 $this->columnbuffer = array();
27783 $this->ColDetails = array();
27784 $this->columnLinks = array();
27785 $this->columnAnnots = array();
27786 $this->columnForms = array();
27787 $this->col_BMoutlines = array();
27788 $this->col_toc = array();
27789 $this->breakpoints = array();
27790 if ((strtoupper($vAlign) == 'J') || (strtoupper($vAlign) == 'JUSTIFY')) {
27791 $vAlign = 'J';
27792 } else {
27793 $vAlign = '';
27794 }
27795 $this->colvAlign = $vAlign;
27796 //Save the ordinate
27797 $absL = $this->DeflMargin - ($gap / 2);
27798 $absR = $this->DefrMargin - ($gap / 2);
27799 $PageWidth = $this->w - $absL - $absR; // virtual pagewidth for calculation only
27800 $ColWidth = (($PageWidth - ($gap * ($NbCol))) / $NbCol);
27801 $this->ColWidth = $ColWidth;
27802 /* -- OTL -- */
27803
27804 if ($this->directionality == 'rtl') {
27805 for ($i = 0; $i < $this->NbCol; $i++) {
27806 $this->ColL[$i] = $absL + ($gap / 2) + (($NbCol - ($i + 1)) * ($PageWidth / $NbCol));
27807 $this->ColR[$i] = $this->ColL[$i] + $ColWidth; // NB This is not R margin -> R pos
27808 }
27809 } else {
27810 /* -- END OTL -- */
27811 for ($i = 0; $i < $this->NbCol; $i++) {
27812 $this->ColL[$i] = $absL + ($gap / 2) + ($i * ($PageWidth / $NbCol) );
27813 $this->ColR[$i] = $this->ColL[$i] + $ColWidth; // NB This is not R margin -> R pos
27814 }
27815 } // *OTL*
27816 $this->pgwidth = $ColWidth;
27817 $this->SetCol(0);
27818 $this->y0 = $this->y;
27819 }
27820 $this->x = $this->lMargin;
27821 }
27822
27823 function SetCol($CurrCol)
27824 {
27825 // Used internally to set column by number: 0 is 1st column
27826 //Set position on a column
27827 $this->CurrCol = $CurrCol;
27828 $x = $this->ColL[$CurrCol];
27829 $xR = $this->ColR[$CurrCol]; // NB This is not R margin -> R pos
27830 if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
27831 $x += $this->MarginCorrection;
27832 $xR += $this->MarginCorrection;
27833 }
27834 $this->SetMargins($x, ($this->w - $xR), $this->tMargin);
27835 }
27836
27837 function AddColumn()
27838 {
27839 $this->NewColumn();
27840 $this->ColumnAdjust = false; // disables all column height adjustment for the page.
27841 }
27842
27843 function NewColumn()
27844 {
27845 if ($this->ColActive == 1) {
27846 if ($this->CurrCol < $this->NbCol - 1) {
27847 //Go to the next column
27848 $this->CurrCol++;
27849 $this->SetCol($this->CurrCol);
27850 $this->y = $this->y0;
27851 $this->ChangeColumn = 1;
27852 // DIRECTIONALITY RTL
27853 if ($this->directionality == 'rtl') {
27854 $this->ChangeColumn = -($this->ChangeColumn);
27855 } // *OTL*
27856 //Stay on the page
27857 } else {
27858 //Go back to the first column
27859 //Page break
27860 if (count($this->columnbuffer)) {
27861 $this->printcolumnbuffer();
27862 }
27863 $this->AddPage($this->CurOrientation);
27864 $this->SetCol(0);
27865 $this->y0 = $this->tMargin;
27866 $this->ChangeColumn = -($this->NbCol - 1);
27867 // DIRECTIONALITY RTL
27868 if ($this->directionality == 'rtl') {
27869 $this->ChangeColumn = -($this->ChangeColumn);
27870 } // *OTL*
27871 }
27872 $this->x = $this->lMargin;
27873 } else {
27874 $this->AddPage($this->CurOrientation);
27875 }
27876 }
27877
27878 function printcolumnbuffer()
27879 {
27880 // Columns ended (but page not ended) -> try to match all columns - unless disabled by using a custom column-break
27881 if (!$this->ColActive && $this->ColumnAdjust && !$this->keepColumns) {
27882 // Calculate adjustment to add to each column to calculate rel_y value
27883 $this->ColDetails[0]['add_y'] = 0;
27884 $last_col = 0;
27885 // Recursively add previous column's height
27886 for ($i = 1; $i < $this->NbCol; $i++) {
27887 if (isset($this->ColDetails[$i]['bottom_margin']) && $this->ColDetails[$i]['bottom_margin']) { // If any entries in the column
27888 $this->ColDetails[$i]['add_y'] = ($this->ColDetails[$i - 1]['bottom_margin'] - $this->y0) + $this->ColDetails[$i - 1]['add_y'];
27889 $last_col = $i; // Last column actually printed
27890 }
27891 }
27892
27893 // Calculate value for each position sensitive entry as though for one column
27894 foreach ($this->columnbuffer AS $key => $s) {
27895 $t = $s['s'];
27896 if ($t == 'ACROFORM') {
27897 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
27898 $this->columnbuffer[$key]['s'] = '';
27899 } elseif (preg_match('/BT \d+\.\d\d+ (\d+\.\d\d+) Td/', $t)) {
27900 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
27901 } elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ [\-]{0,1}\d+\.\d\d+ re/', $t)) {
27902 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
27903 } elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) m/', $t)) {
27904 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
27905 } elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) l/', $t)) {
27906 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
27907 } 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)) {
27908 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
27909 } elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ c/', $t)) {
27910 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
27911 }
27912 }
27913 foreach ($this->internallink AS $key => $f) {
27914 if (is_array($f) && isset($f['col'])) {
27915 $this->internallink[$key]['rel_y'] = $f['Y'] + $this->ColDetails[$f['col']]['add_y'] - $this->y0;
27916 }
27917 }
27918
27919 $breaks = array();
27920 foreach ($this->breakpoints AS $c => $bpa) {
27921 foreach ($bpa AS $rely) {
27922 $breaks[] = $rely + $this->ColDetails[$c]['add_y'] - $this->y0;
27923 }
27924 }
27925
27926
27927 if (isset($this->ColDetails[$last_col]['bottom_margin'])) {
27928 $lcbm = $this->ColDetails[$last_col]['bottom_margin'];
27929 } else {
27930 $lcbm = 0;
27931 }
27932 $sum_h = $this->ColDetails[$last_col]['add_y'] + $lcbm - $this->y0;
27933 //$sum_h = max($this->ColDetails[$last_col]['add_y'] + $this->ColDetails[$last_col]['bottom_margin'] - $this->y0, end($breaks));
27934 $target_h = ($sum_h / $this->NbCol);
27935
27936 $cbr = array();
27937 for ($i = 1; $i < $this->NbCol; $i++) {
27938 $th = ($sum_h * $i / $this->NbCol);
27939 foreach ($breaks AS $bk => $val) {
27940 if ($val > $th) {
27941 if (($val - $th) < ($th - $breaks[$bk - 1])) {
27942 $cbr[$i - 1] = $val;
27943 } else {
27944 $cbr[$i - 1] = $breaks[$bk - 1];
27945 }
27946 break;
27947 }
27948 }
27949 }
27950 $cbr[($this->NbCol - 1)] = $sum_h;
27951
27952 // mPDF 6
27953 // Avoid outputing with 1st column empty
27954 if (isset($cbr[0]) && $cbr[0] == 0) {
27955 for ($i = 0; $i < $this->NbCol - 1; $i++) {
27956 $cbr[$i] = $cbr[$i + 1];
27957 }
27958 }
27959
27960 // Now update the columns - divide into columns of approximately equal value
27961 $last_new_col = 0;
27962 $yadj = 0; // mm
27963 $xadj = 0;
27964 $last_col_bottom = 0;
27965 $lowest_bottom_y = 0;
27966 $block_bottom = 0;
27967 $newcolumn = 0;
27968 foreach ($this->columnbuffer AS $key => $s) {
27969 if (isset($s['rel_y'])) { // only process position sensitive data
27970 if ($s['rel_y'] >= $cbr[$newcolumn]) {
27971 $newcolumn++;
27972 } else {
27973 $newcolumn = $last_new_col;
27974 }
27975
27976
27977 $block_bottom = max($block_bottom, ($s['rel_y'] + $s['h']));
27978
27979 if ($this->directionality == 'rtl') { // *OTL*
27980 $xadj = -(($newcolumn - $s['col']) * ($this->ColWidth + $this->ColGap)); // *OTL*
27981 } // *OTL*
27982 else { // *OTL*
27983 $xadj = ($newcolumn - $s['col']) * ($this->ColWidth + $this->ColGap);
27984 } // *OTL*
27985
27986 if ($last_new_col != $newcolumn) { // Added new column
27987 $last_col_bottom = $this->columnbuffer[$key]['rel_y'];
27988 $block_bottom = 0;
27989 }
27990 $yadj = ($s['rel_y'] - $s['y']) - ($last_col_bottom) + $this->y0;
27991 // callback function
27992 $t = $s['s'];
27993
27994 // mPDF 5.7+
27995 $t = $this->columnAdjustPregReplace('Td', $xadj, $yadj, '/BT (\d+\.\d\d+) (\d+\.\d\d+) Td/', $t);
27996 $t = $this->columnAdjustPregReplace('re', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) ([\-]{0,1}\d+\.\d\d+) re/', $t);
27997 $t = $this->columnAdjustPregReplace('l', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) l/', $t);
27998 $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);
27999 $t = $this->columnAdjustPregReplace('draw', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) m/', $t);
28000 $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);
28001
28002 $this->columnbuffer[$key]['s'] = $t;
28003 $this->columnbuffer[$key]['newcol'] = $newcolumn;
28004 $this->columnbuffer[$key]['newy'] = $s['y'] + $yadj;
28005 $last_new_col = $newcolumn;
28006 $clb = $s['y'] + $yadj + $s['h']; // bottom_margin of current
28007 if ((isset($this->ColDetails[$newcolumn]['max_bottom']) && $clb > $this->ColDetails[$newcolumn]['max_bottom']) || (!isset($this->ColDetails[$newcolumn]['max_bottom']) && $clb)) {
28008 $this->ColDetails[$newcolumn]['max_bottom'] = $clb;
28009 }
28010 if ($clb > $lowest_bottom_y) {
28011 $lowest_bottom_y = $clb;
28012 }
28013 // Adjust LINKS
28014 if (isset($this->columnLinks[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])])) {
28015 $ref = $this->columnLinks[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])];
28016 $this->PageLinks[$this->page][$ref][0] += ($xadj * _MPDFK);
28017 $this->PageLinks[$this->page][$ref][1] -= ($yadj * _MPDFK);
28018 unset($this->columnLinks[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])]);
28019 }
28020 // Adjust FORM FIELDS
28021 if (isset($this->columnForms[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])])) {
28022 $ref = $this->columnForms[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])];
28023 $this->mpdfform->forms[$ref]['x'] += ($xadj);
28024 $this->mpdfform->forms[$ref]['y'] += ($yadj);
28025 unset($this->columnForms[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])]);
28026 }
28027 /* -- ANNOTATIONS -- */
28028 if (isset($this->columnAnnots[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])])) {
28029 $ref = $this->columnAnnots[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])];
28030 if ($this->PageAnnots[$this->page][$ref]['x'] < 0) {
28031 $this->PageAnnots[$this->page][$ref]['x'] -= ($xadj);
28032 } else {
28033 $this->PageAnnots[$this->page][$ref]['x'] += ($xadj);
28034 }
28035 $this->PageAnnots[$this->page][$ref]['y'] += ($yadj); // unlike PageLinks, Page annots has y values from top in mm
28036 unset($this->columnAnnots[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])]);
28037 }
28038 /* -- END ANNOTATIONS -- */
28039 }
28040 }
28041
28042 /* -- BOOKMARKS -- */
28043 // Adjust Bookmarks
28044 foreach ($this->col_BMoutlines AS $v) {
28045 $this->BMoutlines[] = array('t' => $v['t'], 'l' => $v['l'], 'y' => $this->y0, 'p' => $v['p']);
28046 }
28047 /* -- END BOOKMARKS -- */
28048
28049 /* -- TOC -- */
28050
28051 // Adjust ToC
28052 foreach ($this->col_toc AS $v) {
28053 $this->tocontents->_toc[] = array('t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']);
28054 $this->links[$v['link']][1] = $this->y0;
28055 }
28056 /* -- END TOC -- */
28057
28058 // Adjust column length to be equal
28059 if ($this->colvAlign == 'J') {
28060 foreach ($this->columnbuffer AS $key => $s) {
28061 if (isset($s['rel_y'])) { // only process position sensitive data
28062 // Set ratio to expand y values or heights
28063 if (isset($this->ColDetails[$s['newcol']]['max_bottom']) && $this->ColDetails[$s['newcol']]['max_bottom'] && $this->ColDetails[$s['newcol']]['max_bottom'] != $this->y0) {
28064 $ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['newcol']]['max_bottom'] - ($this->y0));
28065 } else {
28066 $ratio = 1;
28067 }
28068 if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
28069 $yadj = ($s['newy'] - $this->y0) * ($ratio - 1);
28070
28071 // Adjust LINKS
28072 if (isset($this->columnLinks[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])])) {
28073 $ref = $this->columnLinks[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])];
28074 $this->PageLinks[$this->page][$ref][1] -= ($yadj * _MPDFK); // y value
28075 $this->PageLinks[$this->page][$ref][3] *= $ratio; // height
28076 unset($this->columnLinks[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])]);
28077 }
28078 // Adjust FORM FIELDS
28079 if (isset($this->columnForms[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])])) {
28080 $ref = $this->columnForms[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])];
28081 $this->mpdfform->forms[$ref]['x'] += ($xadj);
28082 $this->mpdfform->forms[$ref]['y'] += ($yadj);
28083 unset($this->columnForms[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])]);
28084 }
28085 /* -- ANNOTATIONS -- */
28086 if (isset($this->columnAnnots[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])])) {
28087 $ref = $this->columnAnnots[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])];
28088 $this->PageAnnots[$this->page][$ref]['y'] += ($yadj);
28089 unset($this->columnAnnots[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])]);
28090 }
28091 /* -- END ANNOTATIONS -- */
28092 }
28093 }
28094 }
28095 foreach ($this->internallink AS $key => $f) {
28096 if (is_array($f) && isset($f['col'])) {
28097 $last_col_bottom = 0;
28098 for ($nbc = 0; $nbc < $this->NbCol; $nbc++) {
28099 if ($f['rel_y'] >= $cbr[$nbc]) {
28100 $last_col_bottom = $cbr[$nbc];
28101 }
28102 }
28103 $yadj = ($f['rel_y'] - $f['Y']) - $last_col_bottom + $this->y0;
28104 $f['Y'] += $yadj;
28105 unset($f['col']);
28106 unset($f['rel_y']);
28107 $this->internallink[$key] = $f;
28108 }
28109 }
28110
28111 $last_col = -1;
28112 $trans_on = false;
28113 foreach ($this->columnbuffer AS $key => $s) {
28114 if (isset($s['rel_y'])) { // only process position sensitive data
28115 // Set ratio to expand y values or heights
28116 if (isset($this->ColDetails[$s['newcol']]['max_bottom']) && $this->ColDetails[$s['newcol']]['max_bottom'] && $this->ColDetails[$s['newcol']]['max_bottom'] != $this->y0) {
28117 $ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['newcol']]['max_bottom'] - ($this->y0));
28118 } else {
28119 $ratio = 1;
28120 }
28121 if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
28122 //Start Transformation
28123 $this->pages[$this->page] .= $this->StartTransform(true) . "\n";
28124 $this->pages[$this->page] .= $this->transformScale(100, $ratio * 100, $x = '', $this->y0, true) . "\n";
28125 $trans_on = true;
28126 }
28127 }
28128 // Now output the adjusted values
28129 $this->pages[$this->page] .= $s['s'] . "\n";
28130 if (isset($s['rel_y']) && ($ratio > 1) && ($ratio <= $this->max_colH_correction)) { // only process position sensitive data
28131 //Stop Transformation
28132 $this->pages[$this->page] .= $this->StopTransform(true) . "\n";
28133 $trans_on = false;
28134 }
28135 }
28136 if ($trans_on) {
28137 $this->pages[$this->page] .= $this->StopTransform(true) . "\n";
28138 }
28139 } else { // if NOT $this->colvAlign == 'J'
28140 // Now output the adjusted values
28141 foreach ($this->columnbuffer AS $s) {
28142 $this->pages[$this->page] .= $s['s'] . "\n";
28143 }
28144 }
28145 if ($lowest_bottom_y > 0) {
28146 $this->y = $lowest_bottom_y;
28147 }
28148 }
28149
28150 // Columns not ended but new page -> align columns (can leave the columns alone - just tidy up the height)
28151 elseif ($this->colvAlign == 'J' && $this->ColumnAdjust && !$this->keepColumns) {
28152 // calculate the lowest bottom margin
28153 $lowest_bottom_y = 0;
28154 foreach ($this->columnbuffer AS $key => $s) {
28155 // Only process output data
28156 $t = $s['s'];
28157 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)) ||
28158 (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) l/', $t)) ||
28159 (preg_match('/q \d+\.\d\d+ 0 0 \d+\.\d\d+ \d+\.\d\d+ (\d+\.\d\d+) cm \/(I|FO)\d+ Do Q/', $t)) ||
28160 (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) m/', $t)) ||
28161 (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ c/', $t))) {
28162
28163 $clb = $s['y'] + $s['h'];
28164 if ((isset($this->ColDetails[$s['col']]['max_bottom']) && $clb > $this->ColDetails[$s['col']]['max_bottom']) || !isset($this->ColDetails[$s['col']]['max_bottom'])) {
28165 $this->ColDetails[$s['col']]['max_bottom'] = $clb;
28166 }
28167 if ($clb > $lowest_bottom_y) {
28168 $lowest_bottom_y = $clb;
28169 }
28170 $this->columnbuffer[$key]['rel_y'] = $s['y']; // Marks position sensitive data to process later
28171 if ($t == 'ACROFORM') {
28172 $this->columnbuffer[$key]['s'] = '';
28173 }
28174 }
28175 }
28176 // Adjust column length equal
28177 foreach ($this->columnbuffer AS $key => $s) {
28178 // Set ratio to expand y values or heights
28179 if (isset($this->ColDetails[$s['col']]['max_bottom']) && $this->ColDetails[$s['col']]['max_bottom']) {
28180 $ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['col']]['max_bottom'] - ($this->y0));
28181 } else {
28182 $ratio = 1;
28183 }
28184 if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
28185 $yadj = ($s['y'] - $this->y0) * ($ratio - 1);
28186
28187 // Adjust LINKS
28188 if (isset($s['rel_y'])) { // only process position sensitive data
28189 // otherwise triggers for all entries in column buffer (.e.g. formatting) and makes below adjustments more than once
28190 if (isset($this->columnLinks[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])])) {
28191 $ref = $this->columnLinks[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])];
28192 $this->PageLinks[$this->page][$ref][1] -= ($yadj * _MPDFK); // y value
28193 $this->PageLinks[$this->page][$ref][3] *= $ratio; // height
28194 unset($this->columnLinks[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])]);
28195 }
28196 // Adjust FORM FIELDS
28197 if (isset($this->columnForms[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])])) {
28198 $ref = $this->columnForms[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])];
28199 $this->mpdfform->forms[$ref]['x'] += ($xadj);
28200 $this->mpdfform->forms[$ref]['y'] += ($yadj);
28201 unset($this->columnForms[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])]);
28202 }
28203 /* -- ANNOTATIONS -- */
28204 if (isset($this->columnAnnots[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])])) {
28205 $ref = $this->columnAnnots[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])];
28206 $this->PageAnnots[$this->page][$ref]['y'] += ($yadj);
28207 unset($this->columnAnnots[$s['col']][INTVAL($s['x'])][INTVAL($s['y'])]);
28208 }
28209 /* -- END ANNOTATIONS -- */
28210 }
28211 }
28212 }
28213
28214 /* -- BOOKMARKS -- */
28215
28216 // Adjust Bookmarks
28217 foreach ($this->col_BMoutlines AS $v) {
28218 $this->BMoutlines[] = array('t' => $v['t'], 'l' => $v['l'], 'y' => $this->y0, 'p' => $v['p']);
28219 }
28220 /* -- END BOOKMARKS -- */
28221
28222 /* -- TOC -- */
28223
28224 // Adjust ToC
28225 foreach ($this->col_toc AS $v) {
28226 $this->tocontents->_toc[] = array('t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']);
28227 $this->links[$v['link']][1] = $this->y0;
28228 }
28229 /* -- END TOC -- */
28230 $trans_on = false;
28231 foreach ($this->columnbuffer AS $key => $s) {
28232 if (isset($s['rel_y'])) { // only process position sensitive data
28233 // Set ratio to expand y values or heights
28234 if ($this->ColDetails[$s['col']]['max_bottom']) {
28235 $ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['col']]['max_bottom'] - ($this->y0));
28236 } else {
28237 $ratio = 1;
28238 }
28239 if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
28240 //Start Transformation
28241 $this->pages[$this->page] .= $this->StartTransform(true) . "\n";
28242 $this->pages[$this->page] .= $this->transformScale(100, $ratio * 100, $x = '', $this->y0, true) . "\n";
28243 $trans_on = true;
28244 }
28245 }
28246 // Now output the adjusted values
28247 $this->pages[$this->page] .= $s['s'] . "\n";
28248 if (isset($s['rel_y']) && ($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
28249 //Stop Transformation
28250 $this->pages[$this->page] .= $this->StopTransform(true) . "\n";
28251 $trans_on = false;
28252 }
28253 }
28254 if ($trans_on) {
28255 $this->pages[$this->page] .= $this->StopTransform(true) . "\n";
28256 }
28257
28258 if ($lowest_bottom_y > 0) {
28259 $this->y = $lowest_bottom_y;
28260 }
28261 }
28262
28263
28264 // Just reproduce the page as it was
28265 else {
28266 // If page has not ended but height adjustment was disabled by custom column-break - adjust y
28267 $lowest_bottom_y = 0;
28268 if (!$this->ColActive && (!$this->ColumnAdjust || $this->keepColumns)) {
28269 // calculate the lowest bottom margin
28270 foreach ($this->columnbuffer AS $key => $s) {
28271 // Only process output data
28272 $t = $s['s'];
28273 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)) ||
28274 (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) l/', $t)) ||
28275 (preg_match('/q \d+\.\d\d+ 0 0 \d+\.\d\d+ \d+\.\d\d+ (\d+\.\d\d+) cm \/(I|FO)\d+ Do Q/', $t)) ||
28276 (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) m/', $t)) ||
28277 (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ c/', $t))) {
28278
28279 $clb = $s['y'] + $s['h'];
28280 if ($clb > $this->ColDetails[$s['col']]['max_bottom']) {
28281 $this->ColDetails[$s['col']]['max_bottom'] = $clb;
28282 }
28283 if ($clb > $lowest_bottom_y) {
28284 $lowest_bottom_y = $clb;
28285 }
28286 }
28287 }
28288 }
28289 foreach ($this->columnbuffer AS $key => $s) {
28290 if ($s['s'] != 'ACROFORM')
28291 $this->pages[$this->page] .= $s['s'] . "\n";
28292 }
28293 if ($lowest_bottom_y > 0) {
28294 $this->y = $lowest_bottom_y;
28295 }
28296 /* -- BOOKMARKS -- */
28297 // Output Bookmarks
28298 foreach ($this->col_BMoutlines AS $v) {
28299 $this->BMoutlines[] = array('t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $v['p']);
28300 }
28301 /* -- END BOOKMARKS -- */
28302 /* -- TOC -- */
28303 // Output ToC
28304 foreach ($this->col_toc AS $v) {
28305 $this->tocontents->_toc[] = array('t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']);
28306 }
28307 /* -- END TOC -- */
28308 }
28309 foreach ($this->internallink AS $key => $f) {
28310 if (isset($this->internallink[$key]['col']))
28311 unset($this->internallink[$key]['col']);
28312 if (isset($this->internallink[$key]['rel_y']))
28313 unset($this->internallink[$key]['rel_y']);
28314 }
28315
28316 $this->columnbuffer = array();
28317 $this->ColDetails = array();
28318 $this->columnLinks = array();
28319 $this->columnAnnots = array();
28320 $this->columnForms = array();
28321
28322 $this->col_BMoutlines = array();
28323 $this->col_toc = array();
28324 $this->breakpoints = array();
28325 }
28326
28327 // mPDF 5.7+
28328 function columnAdjustPregReplace($type, $xadj, $yadj, $pattern, $subject)
28329 {
28330 preg_match($pattern, $subject, $matches);
28331 if (!count($matches)) {
28332 return $subject;
28333 }
28334 if (!isset($matches[3])) {
28335 $matches[3] = 0;
28336 }
28337 if (!isset($matches[4])) {
28338 $matches[4] = 0;
28339 }
28340 if (!isset($matches[5])) {
28341 $matches[5] = 0;
28342 }
28343 if (!isset($matches[6])) {
28344 $matches[6] = 0;
28345 }
28346 return str_replace($matches[0], $this->columnAdjustAdd($type, _MPDFK, $xadj, $yadj, $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]), $subject);
28347 }
28348
28349 /* -- END COLUMNS -- */
28350
28351 //==================================================================
28352 /* -- TABLES -- */
28353 function printcellbuffer()
28354 {
28355 if (count($this->cellBorderBuffer)) {
28356 sort($this->cellBorderBuffer);
28357 foreach ($this->cellBorderBuffer AS $cbb) {
28358 $cba = unpack("A16dom/nbord/A1side/ns/dbw/a6ca/A10style/dx/dy/dw/dh/dmbl/dmbr/dmrt/dmrb/dmtl/dmtr/dmlt/dmlb/dcpd/dover/", $cbb);
28359 $side = $cba['side'];
28360 $color = str_pad($cba['ca'], 6, "\x00");
28361 $details = array();
28362 $details[$side]['dom'] = (float) $cba['dom'];
28363 $details[$side]['s'] = $cba['s'];
28364 $details[$side]['w'] = $cba['bw'];
28365 $details[$side]['c'] = $color;
28366 $details[$side]['style'] = trim($cba['style']);
28367 $details['mbw']['BL'] = $cba['mbl'];
28368 $details['mbw']['BR'] = $cba['mbr'];
28369 $details['mbw']['RT'] = $cba['mrt'];
28370 $details['mbw']['RB'] = $cba['mrb'];
28371 $details['mbw']['TL'] = $cba['mtl'];
28372 $details['mbw']['TR'] = $cba['mtr'];
28373 $details['mbw']['LT'] = $cba['mlt'];
28374 $details['mbw']['LB'] = $cba['mlb'];
28375 $details['cellposdom'] = $cba['cpd'];
28376 $details['p'] = $side;
28377 if ($cba['over'] == 1) {
28378 $details[$side]['overlay'] = true;
28379 } else {
28380 $details[$side]['overlay'] = false;
28381 }
28382 $this->_tableRect($cba['x'], $cba['y'], $cba['w'], $cba['h'], $cba['bord'], $details, false, false);
28383 }
28384 $this->cellBorderBuffer = array();
28385 }
28386 }
28387
28388 //==================================================================
28389 function printtablebuffer()
28390 {
28391
28392 if (!$this->table_rotate) {
28393 $this->pages[$this->page] .= $this->tablebuffer;
28394 foreach ($this->tbrot_Links AS $p => $l) {
28395 foreach ($l AS $v) {
28396 $this->PageLinks[$p][] = $v;
28397 }
28398 }
28399 $this->tbrot_Links = array();
28400 /* -- ANNOTATIONS -- */
28401 foreach ($this->tbrot_Annots AS $p => $l) {
28402 foreach ($l AS $v) {
28403 $this->PageAnnots[$p][] = $v;
28404 }
28405 }
28406 $this->tbrot_Annots = array();
28407 /* -- END ANNOTATIONS -- */
28408
28409 /* -- BOOKMARKS -- */
28410 // Output Bookmarks
28411 foreach ($this->tbrot_BMoutlines AS $v) {
28412 $this->BMoutlines[] = array('t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $v['p']);
28413 }
28414 $this->tbrot_BMoutlines = array();
28415 /* -- END BOOKMARKS -- */
28416
28417 /* -- TOC -- */
28418 // Output ToC
28419 foreach ($this->tbrot_toc AS $v) {
28420 $this->tocontents->_toc[] = array('t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']);
28421 }
28422 $this->tbrot_toc = array();
28423 /* -- END TOC -- */
28424
28425 return;
28426 }
28427 // elseif rotated
28428 $lm = $this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_left'];
28429 $pw = $this->blk[$this->blklvl]['inner_width'];
28430 //Start Transformation
28431 $this->pages[$this->page] .= $this->StartTransform(true) . "\n";
28432
28433 if ($this->table_rotate > 1) { // clockwise
28434 if ($this->tbrot_align == 'L') {
28435 $xadj = $this->tbrot_h; // align L (as is)
28436 } elseif ($this->tbrot_align == 'R') {
28437 $xadj = $lm - $this->tbrot_x0 + ($pw); // align R
28438 } else {
28439 $xadj = $lm - $this->tbrot_x0 + (($pw + $this->tbrot_h) / 2); // align C
28440 }
28441 $yadj = 0;
28442 } else { // anti-clockwise
28443 if ($this->tbrot_align == 'L') {
28444 $xadj = 0; // align L (as is)
28445 } elseif ($this->tbrot_align == 'R') {
28446 $xadj = $lm - $this->tbrot_x0 + ($pw - $this->tbrot_h); // align R
28447 } else {
28448 $xadj = $lm - $this->tbrot_x0 + (($pw - $this->tbrot_h) / 2); // align C
28449 }
28450 $yadj = $this->tbrot_w;
28451 }
28452
28453
28454 $this->pages[$this->page] .= $this->transformTranslate($xadj, $yadj, true) . "\n";
28455 $this->pages[$this->page] .= $this->transformRotate($this->table_rotate, $this->tbrot_x0, $this->tbrot_y0, true) . "\n";
28456
28457 // Now output the adjusted values
28458 $this->pages[$this->page] .= $this->tablebuffer;
28459
28460
28461 foreach ($this->tbrot_Links AS $p => $l) {
28462 foreach ($l AS $v) {
28463 $w = $v[2] / _MPDFK;
28464 $h = $v[3] / _MPDFK;
28465 $ax = ($v[0] / _MPDFK) - $this->tbrot_x0;
28466 $ay = (($this->hPt - $v[1]) / _MPDFK) - $this->tbrot_y0;
28467 if ($this->table_rotate > 1) { // clockwise
28468 $bx = $this->tbrot_x0 + $xadj - $ay - $h;
28469 $by = $this->tbrot_y0 + $yadj + $ax;
28470 } else {
28471 $bx = $this->tbrot_x0 + $xadj + $ay;
28472 $by = $this->tbrot_y0 + $yadj - $ax - $w;
28473 }
28474 $v[0] = $bx * _MPDFK;
28475 $v[1] = ($this->h - $by) * _MPDFK;
28476 $v[2] = $h * _MPDFK; // swap width and height
28477 $v[3] = $w * _MPDFK;
28478 $this->PageLinks[$p][] = $v;
28479 }
28480 }
28481 $this->tbrot_Links = array();
28482 foreach ($this->internallink AS $key => $f) {
28483 if (is_array($f) && isset($f['tbrot'])) {
28484 $f['Y'] = $this->tbrot_y0;
28485 $f['PAGE'] = $this->page;
28486 unset($f['tbrot']);
28487 $this->internallink[$key] = $f;
28488 }
28489 }
28490 /* -- ANNOTATIONS -- */
28491 foreach ($this->tbrot_Annots AS $p => $l) {
28492 foreach ($l AS $v) {
28493 $ax = abs($v['x']) - $this->tbrot_x0; // abs because -ve values are internally set and held for reference if annotMargin set
28494 $ay = $v['y'] - $this->tbrot_y0;
28495 if ($this->table_rotate > 1) { // clockwise
28496 $bx = $this->tbrot_x0 + $xadj - $ay;
28497 $by = $this->tbrot_y0 + $yadj + $ax;
28498 } else {
28499 $bx = $this->tbrot_x0 + $xadj + $ay;
28500 $by = $this->tbrot_y0 + $yadj - $ax;
28501 }
28502 if ($v['x'] < 0) {
28503 $v['x'] = -$bx;
28504 } else {
28505 $v['x'] = $bx;
28506 }
28507 $v['y'] = ($by);
28508 $this->PageAnnots[$p][] = $v;
28509 }
28510 }
28511 $this->tbrot_Annots = array();
28512 /* -- END ANNOTATIONS -- */
28513
28514
28515 /* -- BOOKMARKS -- */
28516
28517 // Adjust Bookmarks
28518 foreach ($this->tbrot_BMoutlines AS $v) {
28519 $v['y'] = $this->tbrot_y0;
28520 $this->BMoutlines[] = array('t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $this->page);
28521 }
28522 /* -- END BOOKMARKS -- */
28523
28524 /* -- TOC -- */
28525
28526 // Adjust ToC - uses document page number
28527 foreach ($this->tbrot_toc AS $v) {
28528 $this->tocontents->_toc[] = array('t' => $v['t'], 'l' => $v['l'], 'p' => $this->page, 'link' => $v['link'], 'toc_id' => $v['toc_id']);
28529 $this->links[$v['link']][1] = $this->tbrot_y0;
28530 }
28531 /* -- END TOC -- */
28532
28533
28534
28535 $this->tbrot_BMoutlines = array();
28536 $this->tbrot_toc = array();
28537
28538 //Stop Transformation
28539 $this->pages[$this->page] .= $this->StopTransform(true) . "\n";
28540
28541
28542 $this->y = $this->tbrot_y0 + $this->tbrot_w;
28543 $this->x = $this->lMargin;
28544
28545 $this->tablebuffer = '';
28546 }
28547
28548 //==================================================================
28549 // Keep-with-table This buffers contents of h1-6 to keep on page with table
28550 function printkwtbuffer()
28551 {
28552 if (!$this->kwt_moved) {
28553 foreach ($this->kwt_buffer AS $s) {
28554 $this->pages[$this->page] .= $s['s'] . "\n";
28555 }
28556 foreach ($this->kwt_Links AS $p => $l) {
28557 foreach ($l AS $v) {
28558 $this->PageLinks[$p][] = $v;
28559 }
28560 }
28561 $this->kwt_Links = array();
28562 /* -- ANNOTATIONS -- */
28563 foreach ($this->kwt_Annots AS $p => $l) {
28564 foreach ($l AS $v) {
28565 $this->PageAnnots[$p][] = $v;
28566 }
28567 }
28568 $this->kwt_Annots = array();
28569 /* -- END ANNOTATIONS -- */
28570
28571 /* -- INDEX -- */
28572 // Output Reference (index)
28573 foreach ($this->kwt_Reference AS $v) {
28574 $Present = 0;
28575 for ($i = 0; $i < count($this->Reference); $i++) {
28576 if ($this->Reference[$i]['t'] == $v['t']) {
28577 $Present = 1;
28578 if (!in_array($v['op'], $this->Reference[$i]['p'])) {
28579 $this->Reference[$i]['p'][] = $v['op'];
28580 }
28581 }
28582 }
28583 if ($Present == 0) {
28584 $this->Reference[] = array('t' => $v['t'], 'p' => array($v['op']));
28585 }
28586 }
28587 $this->kwt_Reference = array();
28588 /* -- END INDEX -- */
28589
28590 /* -- BOOKMARKS -- */
28591 // Output Bookmarks
28592 foreach ($this->kwt_BMoutlines AS $v) {
28593 $this->BMoutlines[] = array('t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $v['p']);
28594 }
28595 $this->kwt_BMoutlines = array();
28596 /* -- END BOOKMARKS -- */
28597
28598 /* -- TOC -- */
28599 // Output ToC
28600 foreach ($this->kwt_toc AS $v) {
28601 $this->tocontents->_toc[] = array('t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']);
28602 }
28603 $this->kwt_toc = array();
28604 /* -- END TOC -- */
28605
28606 $this->pageoutput[$this->page] = array(); // mPDF 6
28607 return;
28608 }
28609
28610 //Start Transformation
28611 $this->pages[$this->page] .= $this->StartTransform(true) . "\n";
28612 $xadj = $this->lMargin - $this->kwt_x0;
28613 //$yadj = $this->y - $this->kwt_y0 ;
28614 $yadj = $this->tMargin - $this->kwt_y0;
28615
28616 $this->pages[$this->page] .= $this->transformTranslate($xadj, $yadj, true) . "\n";
28617
28618 // Now output the adjusted values
28619 foreach ($this->kwt_buffer AS $s) {
28620 $this->pages[$this->page] .= $s['s'] . "\n";
28621 }
28622
28623 // Adjust hyperLinks
28624 foreach ($this->kwt_Links AS $p => $l) {
28625 foreach ($l AS $v) {
28626 $bx = $this->kwt_x0 + $xadj;
28627 $by = $this->kwt_y0 + $yadj;
28628 $v[0] = $bx * _MPDFK;
28629 $v[1] = ($this->h - $by) * _MPDFK;
28630 $this->PageLinks[$p][] = $v;
28631 }
28632 }
28633 foreach ($this->internallink AS $key => $f) {
28634 if (is_array($f) && isset($f['kwt'])) {
28635 $f['Y'] += $yadj;
28636 $f['PAGE'] = $this->page;
28637 unset($f['kwt']);
28638 $this->internallink[$key] = $f;
28639 }
28640 }
28641 /* -- ANNOTATIONS -- */
28642 foreach ($this->kwt_Annots AS $p => $l) {
28643 foreach ($l AS $v) {
28644 $bx = $this->kwt_x0 + $xadj;
28645 $by = $this->kwt_y0 + $yadj;
28646 if ($v['x'] < 0) {
28647 $v['x'] = -$bx;
28648 } else {
28649 $v['x'] = $bx;
28650 }
28651 $v['y'] = $by;
28652 $this->PageAnnots[$p][] = $v;
28653 }
28654 }
28655 /* -- END ANNOTATIONS -- */
28656
28657 /* -- BOOKMARKS -- */
28658
28659 // Adjust Bookmarks
28660 foreach ($this->kwt_BMoutlines AS $v) {
28661 if ($v['y'] != 0) {
28662 $v['y'] += $yadj;
28663 }
28664 $this->BMoutlines[] = array('t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $this->page);
28665 }
28666 /* -- END BOOKMARKS -- */
28667
28668 /* -- INDEX -- */
28669
28670 // Adjust Reference (index)
28671 foreach ($this->kwt_Reference AS $v) {
28672 $Present = 0;
28673 //Search the reference (AND Ref/PageNo) in the array
28674 for ($i = 0; $i < count($this->Reference); $i++) {
28675 if ($this->Reference[$i]['t'] == $v['t']) {
28676 $Present = 1;
28677 if (!in_array($this->page, $this->Reference[$i]['p'])) {
28678 $this->Reference[$i]['p'][] = $this->page;
28679 }
28680 }
28681 }
28682 if ($Present == 0) {
28683 $this->Reference[] = array('t' => $v['t'], 'p' => array($this->page));
28684 }
28685 }
28686 /* -- END INDEX -- */
28687
28688 /* -- TOC -- */
28689
28690 // Adjust ToC
28691 foreach ($this->kwt_toc AS $v) {
28692 $this->tocontents->_toc[] = array('t' => $v['t'], 'l' => $v['l'], 'p' => $this->page, 'link' => $v['link'], 'toc_id' => $v['toc_id']);
28693 $this->links[$v['link']][0] = $this->page;
28694 $this->links[$v['link']][1] += $yadj;
28695 }
28696 /* -- END TOC -- */
28697
28698
28699 $this->kwt_Links = array();
28700 $this->kwt_Annots = array();
28701
28702 $this->kwt_Reference = array();
28703 $this->kwt_BMoutlines = array();
28704 $this->kwt_toc = array();
28705 //Stop Transformation
28706 $this->pages[$this->page] .= $this->StopTransform(true) . "\n";
28707
28708 $this->kwt_buffer = array();
28709
28710 $this->y += $this->kwt_height;
28711 $this->pageoutput[$this->page] = array(); // mPDF 6
28712 }
28713
28714 /* -- END TABLES -- */
28715
28716 //==================================================================
28717
28718 function printfloatbuffer()
28719 {
28720 if (count($this->floatbuffer)) {
28721 $this->objectbuffer = $this->floatbuffer;
28722 $this->printobjectbuffer(false);
28723 $this->objectbuffer = array();
28724 $this->floatbuffer = array();
28725 $this->floatmargins = array();
28726 }
28727 }
28728
28729 //==================================================================
28730 //==================================================================
28731 // Added ELLIPSES and CIRCLES
28732 function Circle($x, $y, $r, $style = 'S')
28733 {
28734 $this->Ellipse($x, $y, $r, $r, $style);
28735 }
28736
28737 function Ellipse($x, $y, $rx, $ry, $style = 'S')
28738 {
28739 if ($style == 'F') {
28740 $op = 'f';
28741 } elseif ($style == 'FD' or $style == 'DF') {
28742 $op = 'B';
28743 } else {
28744 $op = 'S';
28745 }
28746 $lx = 4 / 3 * (M_SQRT2 - 1) * $rx;
28747 $ly = 4 / 3 * (M_SQRT2 - 1) * $ry;
28748 $h = $this->h;
28749 $this->_out(sprintf('%.3F %.3F m %.3F %.3F %.3F %.3F %.3F %.3F c', ($x + $rx) * _MPDFK, ($h - $y) * _MPDFK, ($x + $rx) * _MPDFK, ($h - ($y - $ly)) * _MPDFK, ($x + $lx) * _MPDFK, ($h - ($y - $ry)) * _MPDFK, $x * _MPDFK, ($h - ($y - $ry)) * _MPDFK));
28750 $this->_out(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c', ($x - $lx) * _MPDFK, ($h - ($y - $ry)) * _MPDFK, ($x - $rx) * _MPDFK, ($h - ($y - $ly)) * _MPDFK, ($x - $rx) * _MPDFK, ($h - $y) * _MPDFK));
28751 $this->_out(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c', ($x - $rx) * _MPDFK, ($h - ($y + $ly)) * _MPDFK, ($x - $lx) * _MPDFK, ($h - ($y + $ry)) * _MPDFK, $x * _MPDFK, ($h - ($y + $ry)) * _MPDFK));
28752 $this->_out(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c %s', ($x + $lx) * _MPDFK, ($h - ($y + $ry)) * _MPDFK, ($x + $rx) * _MPDFK, ($h - ($y + $ly)) * _MPDFK, ($x + $rx) * _MPDFK, ($h - $y) * _MPDFK, $op));
28753 }
28754
28755 /* -- DIRECTW -- */
28756
28757 // Added adaptation of shaded_box = AUTOSIZE-TEXT
28758 function AutosizeText($text, $w, $font, $style, $szfont = 72)
28759 {
28760
28761 $text = ' ' . $text . ' ';
28762
28763 $this->SetFont($font, $style, $szfont, false);
28764
28765 $text = $this->purify_utf8_text($text);
28766 if ($this->text_input_as_HTML) {
28767 $text = $this->all_entities_to_utf8($text);
28768 }
28769 if ($this->usingCoreFont) {
28770 $text = mb_convert_encoding($text, $this->mb_enc, 'UTF-8');
28771 }
28772
28773 // DIRECTIONALITY
28774 if (preg_match("/([" . $this->pregRTLchars . "])/u", $text)) {
28775 $this->biDirectional = true;
28776 } // *OTL*
28777
28778 $textvar = 0;
28779 $save_OTLtags = $this->OTLtags;
28780 $this->OTLtags = array();
28781 if ($this->useKerning) {
28782 if ($this->CurrentFont['haskernGPOS']) {
28783 $this->OTLtags['Plus'] .= ' kern';
28784 } else {
28785 $textvar = ($textvar | FC_KERNING);
28786 }
28787 }
28788
28789 /* -- OTL -- */
28790 // Use OTL OpenType Table Layout - GSUB & GPOS
28791 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
28792 $text = $this->otl->applyOTL($text, $this->CurrentFont['useOTL']);
28793 $OTLdata = $this->otl->OTLdata;
28794 }
28795 /* -- END OTL -- */
28796 $this->OTLtags = $save_OTLtags;
28797
28798 $this->magic_reverse_dir($text, $this->directionality, $OTLdata);
28799
28800
28801 $width = $this->ConvertSize($w);
28802 $loop = 0;
28803 while ($loop == 0) {
28804 $this->SetFont($font, $style, $szfont, false);
28805 $sz = $this->GetStringWidth($text, true, $OTLdata, $textvar);
28806 if ($sz > $w) {
28807 $szfont --;
28808 } else {
28809 $loop ++;
28810 }
28811 }
28812 $this->SetFont($font, $style, $szfont, true, true);
28813 $this->Cell($w, 0, $text, 0, 0, "C", 0, '', 0, 0, 0, 'M', 0, false, $OTLdata, $textvar);
28814 }
28815
28816 /* -- END DIRECTW -- */
28817
28818 // ====================================================
28819 // ====================================================
28820
28821 function magic_reverse_dir(&$chunk, $dir, &$chunkOTLdata)
28822 {
28823 /* -- OTL -- */
28824 if ($this->usingCoreFont) {
28825 return 0;
28826 }
28827 if ($chunk == '') {
28828 return 0;
28829 }
28830
28831 if ($this->biDirectional || $dir == 'rtl') {
28832 // check if string contains RTL text
28833 // including any added from OTL tables (in PUA)
28834 $pregRTLchars = $this->pregRTLchars;
28835 if (isset($this->CurrentFont['rtlPUAstr']) && $this->CurrentFont['rtlPUAstr']) {
28836 $pregRTLchars .= $this->CurrentFont['rtlPUAstr'];
28837 }
28838 if (!preg_match("/[" . $pregRTLchars . "]/u", $chunk) && $dir != 'rtl') {
28839 return 0;
28840 } // Chunk doesn't contain RTL characters
28841
28842 $unicode = $this->UTF8StringToArray($chunk, false);
28843
28844 $is_strong = false;
28845 if (empty($chunkOTLdata)) {
28846 $this->getBasicOTLdata($chunkOTLdata, $unicode, $is_strong);
28847 }
28848
28849 if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0x80)) {
28850 $useGPOS = true;
28851 } else {
28852 $useGPOS = false;
28853 }
28854
28855 // NB Returned $chunk may be a shorter string (with adjusted $cOTLdata) by removal of LRE, RLE etc embedding codes.
28856 list($chunk, $rtl_content) = $this->otl->_bidiSort($unicode, $chunk, $dir, $chunkOTLdata, $useGPOS);
28857
28858 return $rtl_content;
28859 }
28860 /* -- END OTL -- */
28861 return 0;
28862 }
28863
28864 /* -- OTL -- */
28865
28866 function getBasicOTLdata(&$chunkOTLdata, $unicode, &$is_strong)
28867 {
28868 if (!class_exists('otl', false)) {
28869 include(_MPDF_PATH . 'classes/otl.php');
28870 }
28871 if (empty($this->otl)) {
28872 $this->otl = new otl($this);
28873 }
28874 $chunkOTLdata['group'] = '';
28875 $chunkOTLdata['GPOSinfo'] = array();
28876 $chunkOTLdata['char_data'] = array();
28877 foreach ($unicode as $char) {
28878 $ucd_record = UCDN::get_ucd_record($char);
28879 $chunkOTLdata['char_data'][] = array('bidi_class' => $ucd_record[2], 'uni' => $char);
28880 if ($ucd_record[2] == 0 || $ucd_record[2] == 3 || $ucd_record[2] == 4) {
28881 $is_strong = true;
28882 } // contains strong character
28883 if ($ucd_record[0] == UCDN::UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
28884 $chunkOTLdata['group'] .= 'M';
28885 } elseif ($char == 32 || $char == 12288) {
28886 $chunkOTLdata['group'] .= 'S';
28887 } else {
28888 $chunkOTLdata['group'] .= 'C';
28889 }
28890 }
28891 }
28892
28893 function _setBidiCodes($mode = 'start', $bdf)
28894 {
28895 $s = '';
28896 if ($mode == 'end') {
28897 // PDF comes before PDI to close isolate-override (e.g. "LRILROPDFPDI")
28898 if (strpos($bdf, 'PDF') !== false) {
28899 $s .= code2utf(0x202C);
28900 } // POP DIRECTIONAL FORMATTING
28901 if (strpos($bdf, 'PDI') !== false) {
28902 $s .= code2utf(0x2069);
28903 } // POP DIRECTIONAL ISOLATE
28904 } elseif ($mode == 'start') {
28905 // LRI comes before LRO to open isolate-override (e.g. "LRILROPDFPDI")
28906 if (strpos($bdf, 'LRI') !== false) {
28907 $s .= code2utf(0x2066);
28908 } // U+2066 LRI
28909 elseif (strpos($bdf, 'RLI') !== false) {
28910 $s .= code2utf(0x2067);
28911 } // U+2067 RLI
28912 elseif (strpos($bdf, 'FSI') !== false) {
28913 $s .= code2utf(0x2068);
28914 } // U+2068 FSI
28915 if (strpos($bdf, 'LRO') !== false) {
28916 $s .= code2utf(0x202D);
28917 } // U+202D LRO
28918 elseif (strpos($bdf, 'RLO') !== false) {
28919 $s .= code2utf(0x202E);
28920 } // U+202E RLO
28921 elseif (strpos($bdf, 'LRE') !== false) {
28922 $s .= code2utf(0x202A);
28923 } // U+202A LRE
28924 elseif (strpos($bdf, 'RLE') !== false) {
28925 $s .= code2utf(0x202B);
28926 } // U+202B RLE
28927 }
28928 return $s;
28929 }
28930
28931 /* -- END OTL -- */
28932
28933 //
28934 // ****************************
28935 // ****************************
28936
28937
28938 function SetSubstitutions()
28939 {
28940 $subsarray = array();
28941 @include(_MPDF_PATH . 'includes/subs_win-1252.php');
28942 $this->substitute = array();
28943 foreach ($subsarray AS $key => $val) {
28944 $this->substitute[code2utf($key)] = $val;
28945 }
28946 }
28947
28948 function SubstituteChars($html)
28949 {
28950 // only substitute characters between tags
28951 if (count($this->substitute)) {
28952 $a = preg_split('/(<.*?>)/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
28953 $html = '';
28954 foreach ($a as $i => $e) {
28955 if ($i % 2 == 0) {
28956 $e = strtr($e, $this->substitute);
28957 }
28958 $html .= $e;
28959 }
28960 }
28961 return $html;
28962 }
28963
28964 function SubstituteCharsSIP(&$writehtml_a, &$writehtml_i, &$writehtml_e)
28965 {
28966 if (preg_match("/^(.*?)([\x{20000}-\x{2FFFF}]+)(.*)/u", $writehtml_e, $m)) {
28967 if (isset($this->CurrentFont['sipext']) && $this->CurrentFont['sipext']) {
28968 $font = $this->CurrentFont['sipext'];
28969 if (!in_array($font, $this->available_unifonts)) {
28970 return 0;
28971 }
28972 $writehtml_a[$writehtml_i] = $writehtml_e = $m[1];
28973 array_splice($writehtml_a, $writehtml_i + 1, 0, array('span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]));
28974 $this->subPos = $writehtml_i;
28975 return 4;
28976 }
28977 }
28978 return 0;
28979 }
28980
28981 // If core font is selected in document which is not onlyCoreFonts - substitute with non-core font
28982 function SubstituteCharsNonCore(&$writehtml_a, &$writehtml_i, &$writehtml_e)
28983 {
28984 // Ignore if in Textarea
28985 if ($writehtml_i > 0 && strtolower(substr($writehtml_a[$writehtml_i - 1], 0, 8)) == 'textarea') {
28986 return 0;
28987 }
28988 if (mb_convert_encoding(mb_convert_encoding($writehtml_e, $this->mb_enc, "UTF-8"), "UTF-8", $this->mb_enc) == $writehtml_e) {
28989 return 0;
28990 }
28991 $cw = &$this->CurrentFont['cw'];
28992 $unicode = $this->UTF8StringToArray($writehtml_e, false);
28993 $start = -1;
28994 $end = 0;
28995 $flag = 0;
28996 $ftype = '';
28997 $u = array();
28998 if (!$this->subArrMB) {
28999 include(_MPDF_PATH . 'includes/subs_core.php');
29000 $this->subArrMB['a'] = $aarr;
29001 $this->subArrMB['s'] = $sarr;
29002 $this->subArrMB['z'] = $zarr;
29003 }
29004 foreach ($unicode AS $c => $char) {
29005 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)) {
29006 if ($flag == 0) {
29007 $start = $c;
29008 }
29009 $flag = 1;
29010 $u[] = $char;
29011 } elseif ($flag > 0) {
29012 $end = $c - 1;
29013 break;
29014 }
29015 }
29016 if ($flag > 0 && !$end) {
29017 $end = count($unicode) - 1;
29018 }
29019 if ($start == -1) {
29020 return 0;
29021 }
29022 // TRY IN BACKUP SUBS FONT
29023 if (!is_array($this->backupSubsFont)) {
29024 $this->backupSubsFont = array("$this->backupSubsFont");
29025 }
29026 foreach ($this->backupSubsFont AS $bsfctr => $bsf) {
29027 if ($this->fonttrans[$bsf] == 'chelvetica' || $this->fonttrans[$bsf] == 'ctimes' || $this->fonttrans[$bsf] == 'ccourier') {
29028 continue;
29029 }
29030 $font = $bsf;
29031 unset($cw);
29032 $cw = '';
29033 if (isset($this->fonts[$font])) {
29034 $cw = &$this->fonts[$font]['cw'];
29035 } elseif (file_exists(_MPDF_TTFONTDATAPATH . $font . '.cw.dat')) {
29036 $cw = @file_get_contents(_MPDF_TTFONTDATAPATH . $font . '.cw.dat');
29037 } else {
29038
29039 $prevFontFamily = $this->FontFamily;
29040 $prevFontStyle = $this->currentfontstyle;
29041 $prevFontSizePt = $this->FontSizePt;
29042 $this->SetFont($bsf, '', '', false);
29043 $cw = @file_get_contents(_MPDF_TTFONTDATAPATH . $font . '.cw.dat');
29044 $this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
29045 }
29046 if (!$cw) {
29047 continue;
29048 }
29049 $l = 0;
29050 foreach ($u AS $char) {
29051 if ($char == 173 || $this->_charDefined($cw, $char) || ($char > 1536 && $char < 1791) || ($char > 2304 && $char < 3455 )) {
29052 $l++;
29053 } else {
29054 if ($l == 0 && $bsfctr == (count($this->backupSubsFont) - 1)) { // Not found even in last backup font
29055 $cont = mb_substr($writehtml_e, $start + 1);
29056 $writehtml_e = mb_substr($writehtml_e, 0, $start + 1, 'UTF-8');
29057 array_splice($writehtml_a, $writehtml_i + 1, 0, array('', $cont));
29058 $this->subPos = $writehtml_i + 1;
29059 return 2;
29060 } else {
29061 break;
29062 }
29063 }
29064 }
29065 if ($l > 0) {
29066 $patt = mb_substr($writehtml_e, $start, $l, 'UTF-8');
29067 if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
29068 $writehtml_e = $m[1];
29069 array_splice($writehtml_a, $writehtml_i + 1, 0, array('span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]));
29070 $this->subPos = $writehtml_i + 3;
29071 return 4;
29072 }
29073 }
29074 }
29075
29076 unset($cw);
29077 return 0;
29078 }
29079
29080 function SubstituteCharsMB(&$writehtml_a, &$writehtml_i, &$writehtml_e)
29081 {
29082 // Ignore if in Textarea
29083 if ($writehtml_i > 0 && strtolower(substr($writehtml_a[$writehtml_i - 1], 0, 8)) == 'textarea') {
29084 return 0;
29085 }
29086 $cw = &$this->CurrentFont['cw'];
29087 $unicode = $this->UTF8StringToArray($writehtml_e, false);
29088 $start = -1;
29089 $end = 0;
29090 $flag = 0;
29091 $ftype = '';
29092 $u = array();
29093 foreach ($unicode AS $c => $char) {
29094 if (($flag == 0 || $flag == 2) && (!$this->_charDefined($cw, $char) || ($flag == 2 && $char == 32)) && $this->checkSIP && $char > 131071) { // Unicode Plane 2 (SIP)
29095 if (in_array($this->FontFamily, $this->available_CJK_fonts)) {
29096 return 0;
29097 }
29098 if ($flag == 0) {
29099 $start = $c;
29100 }
29101 $flag = 2;
29102 $u[] = $char;
29103 }
29104 //elseif (($flag == 0 || $flag==1) && $char != 173 && !$this->_charDefined($cw,$char) && ($char<1423 || ($char>3583 && $char < 11263))) {
29105 elseif (($flag == 0 || $flag == 1) && $char != 173 && (!$this->_charDefined($cw, $char) || ($flag == 1 && $char == 32)) && ($char < 1536 || ($char > 1791 && $char < 2304) || $char > 3455)) {
29106 if ($flag == 0) {
29107 $start = $c;
29108 }
29109 $flag = 1;
29110 $u[] = $char;
29111 } elseif ($flag > 0) {
29112 $end = $c - 1;
29113 break;
29114 }
29115 }
29116 if ($flag > 0 && !$end) {
29117 $end = count($unicode) - 1;
29118 }
29119 if ($start == -1) {
29120 return 0;
29121 }
29122 if ($flag == 2) { // SIP
29123 // Check if current CJK font has a ext-B related font
29124 if (isset($this->CurrentFont['sipext']) && $this->CurrentFont['sipext']) {
29125 $font = $this->CurrentFont['sipext'];
29126 unset($cw);
29127 $cw = '';
29128 if (isset($this->fonts[$font])) {
29129 $cw = &$this->fonts[$font]['cw'];
29130 } elseif (file_exists(_MPDF_TTFONTDATAPATH . $font . '.cw.dat')) {
29131 $cw = @file_get_contents(_MPDF_TTFONTDATAPATH . $font . '.cw.dat');
29132 } else {
29133 $prevFontFamily = $this->FontFamily;
29134 $prevFontStyle = $this->currentfontstyle;
29135 $prevFontSizePt = $this->FontSizePt;
29136 $this->SetFont($font, '', '', false);
29137 $cw = @file_get_contents(_MPDF_TTFONTDATAPATH . $font . '.cw.dat');
29138 $this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
29139 }
29140 if (!$cw) {
29141 return 0;
29142 }
29143 $l = 0;
29144 foreach ($u AS $char) {
29145 if ($this->_charDefined($cw, $char) || $char > 131071) {
29146 $l++;
29147 } else {
29148 break;
29149 }
29150 }
29151 if ($l > 0) {
29152 $patt = mb_substr($writehtml_e, $start, $l);
29153 if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
29154 $writehtml_e = $m[1];
29155 array_splice($writehtml_a, $writehtml_i + 1, 0, array('span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]));
29156 $this->subPos = $writehtml_i + 3;
29157 return 4;
29158 }
29159 }
29160 }
29161 // Check Backup SIP font (defined in config_fonts.php)
29162 if (isset($this->backupSIPFont) && $this->backupSIPFont) {
29163 if ($this->currentfontfamily != $this->backupSIPFont) {
29164 $font = $this->backupSIPFont;
29165 } else {
29166 unset($cw);
29167 return 0;
29168 }
29169 unset($cw);
29170 $cw = '';
29171 if (isset($this->fonts[$font])) {
29172 $cw = &$this->fonts[$font]['cw'];
29173 } elseif (file_exists(_MPDF_TTFONTDATAPATH . $font . '.cw.dat')) {
29174 $cw = @file_get_contents(_MPDF_TTFONTDATAPATH . $font . '.cw.dat');
29175 } else {
29176 $prevFontFamily = $this->FontFamily;
29177 $prevFontStyle = $this->currentfontstyle;
29178 $prevFontSizePt = $this->FontSizePt;
29179 $this->SetFont($this->backupSIPFont, '', '', false);
29180 $cw = @file_get_contents(_MPDF_TTFONTDATAPATH . $font . '.cw.dat');
29181 $this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
29182 }
29183 if (!$cw) {
29184 return 0;
29185 }
29186 $l = 0;
29187 foreach ($u AS $char) {
29188 if ($this->_charDefined($cw, $char) || $char > 131071) {
29189 $l++;
29190 } else {
29191 break;
29192 }
29193 }
29194 if ($l > 0) {
29195 $patt = mb_substr($writehtml_e, $start, $l);
29196 if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
29197 $writehtml_e = $m[1];
29198 array_splice($writehtml_a, $writehtml_i + 1, 0, array('span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]));
29199 $this->subPos = $writehtml_i + 3;
29200 return 4;
29201 }
29202 }
29203 }
29204 return 0;
29205 }
29206
29207
29208 // FIRST TRY CORE FONTS (when appropriate)
29209 if (!$this->PDFA && !$this->PDFX && !$this->biDirectional) { // mPDF 6
29210 $repl = array();
29211 if (!$this->subArrMB) {
29212 include(_MPDF_PATH . 'includes/subs_core.php');
29213 $this->subArrMB['a'] = $aarr;
29214 $this->subArrMB['s'] = $sarr;
29215 $this->subArrMB['z'] = $zarr;
29216 }
29217 if (isset($this->subArrMB['a'][$u[0]])) {
29218 $font = 'tta';
29219 $ftype = 'C';
29220 foreach ($u AS $char) {
29221 if (isset($this->subArrMB['a'][$char])) {
29222 $repl[] = $this->subArrMB['a'][$char];
29223 } else {
29224 break;
29225 }
29226 }
29227 } elseif (isset($this->subArrMB['z'][$u[0]])) {
29228 $font = 'ttz';
29229 $ftype = 'C';
29230 foreach ($u AS $char) {
29231 if (isset($this->subArrMB['z'][$char])) {
29232 $repl[] = $this->subArrMB['z'][$char];
29233 } else {
29234 break;
29235 }
29236 }
29237 } elseif (isset($this->subArrMB['s'][$u[0]])) {
29238 $font = 'tts';
29239 $ftype = 'C';
29240 foreach ($u AS $char) {
29241 if (isset($this->subArrMB['s'][$char])) {
29242 $repl[] = $this->subArrMB['s'][$char];
29243 } else {
29244 break;
29245 }
29246 }
29247 }
29248 if ($ftype == 'C') {
29249 $patt = mb_substr($writehtml_e, $start, count($repl));
29250 if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
29251 $writehtml_e = $m[1];
29252 array_splice($writehtml_a, $writehtml_i + 1, 0, array($font, implode('|', $repl), '/' . $font, $m[3])); // e.g. <tts>
29253 $this->subPos = $writehtml_i + 3;
29254 return 4;
29255 }
29256 return 0;
29257 }
29258 }
29259
29260 // LASTLY TRY IN BACKUP SUBS FONT
29261 if (!is_array($this->backupSubsFont)) {
29262 $this->backupSubsFont = array("$this->backupSubsFont");
29263 }
29264 foreach ($this->backupSubsFont AS $bsfctr => $bsf) {
29265 if ($this->currentfontfamily != $bsf) {
29266 $font = $bsf;
29267 } else {
29268 continue;
29269 }
29270 unset($cw);
29271 $cw = '';
29272 if (isset($this->fonts[$font])) {
29273 $cw = &$this->fonts[$font]['cw'];
29274 } elseif (file_exists(_MPDF_TTFONTDATAPATH . $font . '.cw.dat')) {
29275 $cw = @file_get_contents(_MPDF_TTFONTDATAPATH . $font . '.cw.dat');
29276 } else {
29277 $prevFontFamily = $this->FontFamily;
29278 $prevFontStyle = $this->currentfontstyle;
29279 $prevFontSizePt = $this->FontSizePt;
29280 $this->SetFont($bsf, '', '', false);
29281 $cw = @file_get_contents(_MPDF_TTFONTDATAPATH . $font . '.cw.dat');
29282 $this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
29283 }
29284 if (!$cw) {
29285 continue;
29286 }
29287 $l = 0;
29288 foreach ($u AS $char) {
29289 if ($char == 173 || $this->_charDefined($cw, $char) || ($char > 1536 && $char < 1791) || ($char > 2304 && $char < 3455 )) { // Arabic and Indic
29290 $l++;
29291 } else {
29292 if ($l == 0 && $bsfctr == (count($this->backupSubsFont) - 1)) { // Not found even in last backup font
29293 $cont = mb_substr($writehtml_e, $start + 1);
29294 $writehtml_e = mb_substr($writehtml_e, 0, $start + 1);
29295 array_splice($writehtml_a, $writehtml_i + 1, 0, array('', $cont));
29296 $this->subPos = $writehtml_i + 1;
29297 return 2;
29298 } else {
29299 break;
29300 }
29301 }
29302 }
29303 if ($l > 0) {
29304 $patt = mb_substr($writehtml_e, $start, $l);
29305 if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
29306 $writehtml_e = $m[1];
29307 array_splice($writehtml_a, $writehtml_i + 1, 0, array('span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]));
29308 $this->subPos = $writehtml_i + 3;
29309 return 4;
29310 }
29311 }
29312 }
29313
29314 unset($cw);
29315 return 0;
29316 }
29317
29318 function setHiEntitySubstitutions()
29319 {
29320 $entarr = array(
29321 'nbsp' => '160', 'iexcl' => '161', 'cent' => '162', 'pound' => '163', 'curren' => '164', 'yen' => '165', 'brvbar' => '166', 'sect' => '167',
29322 'uml' => '168', 'copy' => '169', 'ordf' => '170', 'laquo' => '171', 'not' => '172', 'shy' => '173', 'reg' => '174', 'macr' => '175',
29323 'deg' => '176', 'plusmn' => '177', 'sup2' => '178', 'sup3' => '179', 'acute' => '180', 'micro' => '181', 'para' => '182', 'middot' => '183',
29324 'cedil' => '184', 'sup1' => '185', 'ordm' => '186', 'raquo' => '187', 'frac14' => '188', 'frac12' => '189', 'frac34' => '190',
29325 'iquest' => '191', 'Agrave' => '192', 'Aacute' => '193', 'Acirc' => '194', 'Atilde' => '195', 'Auml' => '196', 'Aring' => '197',
29326 'AElig' => '198', 'Ccedil' => '199', 'Egrave' => '200', 'Eacute' => '201', 'Ecirc' => '202', 'Euml' => '203', 'Igrave' => '204',
29327 'Iacute' => '205', 'Icirc' => '206', 'Iuml' => '207', 'ETH' => '208', 'Ntilde' => '209', 'Ograve' => '210', 'Oacute' => '211',
29328 'Ocirc' => '212', 'Otilde' => '213', 'Ouml' => '214', 'times' => '215', 'Oslash' => '216', 'Ugrave' => '217', 'Uacute' => '218',
29329 'Ucirc' => '219', 'Uuml' => '220', 'Yacute' => '221', 'THORN' => '222', 'szlig' => '223', 'agrave' => '224', 'aacute' => '225',
29330 'acirc' => '226', 'atilde' => '227', 'auml' => '228', 'aring' => '229', 'aelig' => '230', 'ccedil' => '231', 'egrave' => '232',
29331 'eacute' => '233', 'ecirc' => '234', 'euml' => '235', 'igrave' => '236', 'iacute' => '237', 'icirc' => '238', 'iuml' => '239',
29332 'eth' => '240', 'ntilde' => '241', 'ograve' => '242', 'oacute' => '243', 'ocirc' => '244', 'otilde' => '245', 'ouml' => '246',
29333 'divide' => '247', 'oslash' => '248', 'ugrave' => '249', 'uacute' => '250', 'ucirc' => '251', 'uuml' => '252', 'yacute' => '253',
29334 'thorn' => '254', 'yuml' => '255', 'OElig' => '338', 'oelig' => '339', 'Scaron' => '352', 'scaron' => '353', 'Yuml' => '376',
29335 'fnof' => '402', 'circ' => '710', 'tilde' => '732', 'Alpha' => '913', 'Beta' => '914', 'Gamma' => '915', 'Delta' => '916',
29336 'Epsilon' => '917', 'Zeta' => '918', 'Eta' => '919', 'Theta' => '920', 'Iota' => '921', 'Kappa' => '922', 'Lambda' => '923',
29337 'Mu' => '924', 'Nu' => '925', 'Xi' => '926', 'Omicron' => '927', 'Pi' => '928', 'Rho' => '929', 'Sigma' => '931', 'Tau' => '932',
29338 'Upsilon' => '933', 'Phi' => '934', 'Chi' => '935', 'Psi' => '936', 'Omega' => '937', 'alpha' => '945', 'beta' => '946', 'gamma' => '947',
29339 'delta' => '948', 'epsilon' => '949', 'zeta' => '950', 'eta' => '951', 'theta' => '952', 'iota' => '953', 'kappa' => '954',
29340 'lambda' => '955', 'mu' => '956', 'nu' => '957', 'xi' => '958', 'omicron' => '959', 'pi' => '960', 'rho' => '961', 'sigmaf' => '962',
29341 'sigma' => '963', 'tau' => '964', 'upsilon' => '965', 'phi' => '966', 'chi' => '967', 'psi' => '968', 'omega' => '969',
29342 'thetasym' => '977', 'upsih' => '978', 'piv' => '982', 'ensp' => '8194', 'emsp' => '8195', 'thinsp' => '8201', 'zwnj' => '8204',
29343 'zwj' => '8205', 'lrm' => '8206', 'rlm' => '8207', 'ndash' => '8211', 'mdash' => '8212', 'lsquo' => '8216', 'rsquo' => '8217',
29344 'sbquo' => '8218', 'ldquo' => '8220', 'rdquo' => '8221', 'bdquo' => '8222', 'dagger' => '8224', 'Dagger' => '8225', 'bull' => '8226',
29345 'hellip' => '8230', 'permil' => '8240', 'prime' => '8242', 'Prime' => '8243', 'lsaquo' => '8249', 'rsaquo' => '8250', 'oline' => '8254',
29346 'frasl' => '8260', 'euro' => '8364', 'image' => '8465', 'weierp' => '8472', 'real' => '8476', 'trade' => '8482', 'alefsym' => '8501',
29347 'larr' => '8592', 'uarr' => '8593', 'rarr' => '8594', 'darr' => '8595', 'harr' => '8596', 'crarr' => '8629', 'lArr' => '8656',
29348 'uArr' => '8657', 'rArr' => '8658', 'dArr' => '8659', 'hArr' => '8660', 'forall' => '8704', 'part' => '8706', 'exist' => '8707',
29349 'empty' => '8709', 'nabla' => '8711', 'isin' => '8712', 'notin' => '8713', 'ni' => '8715', 'prod' => '8719', 'sum' => '8721',
29350 'minus' => '8722', 'lowast' => '8727', 'radic' => '8730', 'prop' => '8733', 'infin' => '8734', 'ang' => '8736', 'and' => '8743',
29351 'or' => '8744', 'cap' => '8745', 'cup' => '8746', 'int' => '8747', 'there4' => '8756', 'sim' => '8764', 'cong' => '8773',
29352 'asymp' => '8776', 'ne' => '8800', 'equiv' => '8801', 'le' => '8804', 'ge' => '8805', 'sub' => '8834', 'sup' => '8835', 'nsub' => '8836',
29353 'sube' => '8838', 'supe' => '8839', 'oplus' => '8853', 'otimes' => '8855', 'perp' => '8869', 'sdot' => '8901', 'lceil' => '8968',
29354 'rceil' => '8969', 'lfloor' => '8970', 'rfloor' => '8971', 'lang' => '9001', 'rang' => '9002', 'loz' => '9674', 'spades' => '9824',
29355 'clubs' => '9827', 'hearts' => '9829', 'diams' => '9830',
29356 );
29357 foreach ($entarr AS $key => $val) {
29358 $this->entsearch[] = '&' . $key . ';';
29359 $this->entsubstitute[] = code2utf($val);
29360 }
29361 }
29362
29363 function SubstituteHiEntities($html)
29364 {
29365 // converts html_entities > ASCII 127 to unicode
29366 // Leaves in particular &lt; to distinguish from tag marker
29367 if (count($this->entsearch)) {
29368 $html = str_replace($this->entsearch, $this->entsubstitute, $html);
29369 }
29370 return $html;
29371 }
29372
29373 // Edited v1.2 Pass by reference; option to continue if invalid UTF-8 chars
29374 function is_utf8(&$string)
29375 {
29376 if ($string === mb_convert_encoding(mb_convert_encoding($string, "UTF-32", "UTF-8"), "UTF-8", "UTF-32")) {
29377 return true;
29378 } else {
29379 if ($this->ignore_invalid_utf8) {
29380 $string = mb_convert_encoding(mb_convert_encoding($string, "UTF-32", "UTF-8"), "UTF-8", "UTF-32");
29381 return true;
29382 } else {
29383 return false;
29384 }
29385 }
29386 }
29387
29388 function purify_utf8($html, $lo = true)
29389 {
29390 // For HTML
29391 // Checks string is valid UTF-8 encoded
29392 // converts html_entities > ASCII 127 to UTF-8
29393 // Only exception - leaves low ASCII entities e.g. &lt; &amp; etc.
29394 // Leaves in particular &lt; to distinguish from tag marker
29395 if (!$this->is_utf8($html)) {
29396 echo "<p><b>HTML contains invalid UTF-8 character(s)</b></p>";
29397 while (mb_convert_encoding(mb_convert_encoding($html, "UTF-32", "UTF-8"), "UTF-8", "UTF-32") != $html) {
29398 $a = iconv('UTF-8', 'UTF-8', $html);
29399 echo ($a);
29400 $pos = $start = strlen($a);
29401 $err = '';
29402 while (ord(substr($html, $pos, 1)) > 128) {
29403 $err .= '[[#' . ord(substr($html, $pos, 1)) . ']]';
29404 $pos++;
29405 }
29406 echo '<span style="color:red; font-weight:bold">' . $err . '</span>';
29407 $html = substr($html, $pos);
29408 }
29409 echo $html;
29410 throw new MpdfException("");
29411 }
29412 $html = preg_replace("/\r/", "", $html);
29413
29414 // converts html_entities > ASCII 127 to UTF-8
29415 // Leaves in particular &lt; to distinguish from tag marker
29416 $html = $this->SubstituteHiEntities($html);
29417
29418 // converts all &#nnn; or &#xHHH; to UTF-8 multibyte
29419 // If $lo==true then includes ASCII < 128
29420 $html = strcode2utf($html, $lo);
29421 return ($html);
29422 }
29423
29424 function purify_utf8_text($txt)
29425 {
29426 // For TEXT
29427 // Make sure UTF-8 string of characters
29428 if (!$this->is_utf8($txt)) {
29429 throw new MpdfException("Text contains invalid UTF-8 character(s)");
29430 }
29431
29432 $txt = preg_replace("/\r/", "", $txt);
29433
29434 return ($txt);
29435 }
29436
29437 function all_entities_to_utf8($txt)
29438 {
29439 // converts txt_entities > ASCII 127 to UTF-8
29440 // Leaves in particular &lt; to distinguish from tag marker
29441 $txt = $this->SubstituteHiEntities($txt);
29442
29443 // converts all &#nnn; or &#xHHH; to UTF-8 multibyte
29444 $txt = strcode2utf($txt);
29445
29446 $txt = $this->lesser_entity_decode($txt);
29447 return ($txt);
29448 }
29449
29450 // ====================================================
29451 /* -- BARCODES -- */
29452 // UPC/EAN barcode
29453 // EAN13, EAN8, UPCA, UPCE, ISBN, ISSN
29454 // Accepts 12 or 13 digits with or without - hyphens
29455 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)
29456 {
29457 if (empty($code)) {
29458 return;
29459 }
29460 $codestr = $code;
29461 $code = preg_replace('/\-/', '', $code);
29462
29463 if (!class_exists('PDFBarcode', false)) {
29464 include(_MPDF_PATH . 'classes/barcode.php');
29465 }
29466 $this->barcode = new PDFBarcode();
29467 if ($btype == 'ISSN' || $btype == 'ISBN') {
29468 $arrcode = $this->barcode->getBarcodeArray($code, 'EAN13');
29469 } else {
29470 $arrcode = $this->barcode->getBarcodeArray($code, $btype);
29471 }
29472
29473 if ($arrcode === false) {
29474 throw new MpdfException('Error in barcode string: ' . $codestr);
29475 }
29476 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)) {
29477 $code .= $arrcode['checkdigit'];
29478 if (stristr($codestr, '-')) {
29479 $codestr .= '-' . $arrcode['checkdigit'];
29480 } else {
29481 $codestr .= $arrcode['checkdigit'];
29482 }
29483 }
29484 if ($btype == 'ISBN') {
29485 $codestr = 'ISBN ' . $codestr;
29486 }
29487 if ($btype == 'ISSN') {
29488 $codestr = 'ISSN ' . $codestr;
29489 }
29490
29491 if (empty($x)) {
29492 $x = $this->x;
29493 }
29494 if (empty($y)) {
29495 $y = $this->y;
29496 }
29497 // set foreground color
29498 $prevDrawColor = $this->DrawColor;
29499 $prevTextColor = $this->TextColor;
29500 $prevFillColor = $this->FillColor;
29501 $lw = $this->LineWidth;
29502 $this->SetLineWidth(0.01);
29503
29504 $size /= $k; // in case resized in a table
29505
29506 $xres = $arrcode['nom-X'] * $size;
29507 $llm = $arrcode['lightmL'] * $arrcode['nom-X'] * $size; // Left Light margin
29508 $rlm = $arrcode['lightmR'] * $arrcode['nom-X'] * $size; // Right Light margin
29509
29510 $bcw = ($arrcode["maxw"] * $xres); // Barcode width = Should always be 31.35mm * $size
29511
29512 $fbw = $bcw + $llm + $rlm; // Full barcode width incl. light margins
29513 $ow = $fbw + $paddingL + $paddingR; // Full overall width incl. user-defined padding
29514
29515 $fbwi = $fbw - 2; // Full barcode width incl. light margins - 2mm - for isbn string
29516 // cf. http://www.gs1uk.org/downloads/bar_code/Bar coding getting it right.pdf
29517 $num_height = 3 * $size; // Height of numerals
29518 $fbh = $arrcode['nom-H'] * $size * $height; // Full barcode height incl. numerals
29519 $bch = $fbh - (1.5 * $size); // Barcode height of bars (3mm for numerals)
29520
29521 if (($btype == 'EAN13' && $showtext) || $btype == 'ISSN' || $btype == 'ISBN') { // Add height for ISBN string + margin from top of bars
29522 $tisbnm = 1.5 * $size; // Top margin between isbn (if shown) & bars
29523 $codestr_fontsize = 2.1 * $size;
29524 $paddingT += $codestr_fontsize + $tisbnm;
29525 }
29526 $oh = $fbh + $paddingT + $paddingB; // Full overall height incl. user-defined padding
29527 // PRINT border background color
29528 $xpos = $x;
29529 $ypos = $y;
29530 if ($col) {
29531 $this->SetDColor($col);
29532 $this->SetTColor($col);
29533 } else {
29534 $this->SetDColor($this->ConvertColor(0));
29535 $this->SetTColor($this->ConvertColor(0));
29536 }
29537 if ($bgcol) {
29538 $this->SetFColor($bgcol);
29539 } else {
29540 $this->SetFColor($this->ConvertColor(255));
29541 }
29542 if (!$bgcol && !$col) { // fn. called directly - not via HTML
29543 if ($border) {
29544 $fillb = 'DF';
29545 } else {
29546 $fillb = 'F';
29547 }
29548 $this->Rect($xpos, $ypos, $ow, $oh, $fillb);
29549 }
29550
29551
29552 // PRINT BARS
29553 $xpos = $x + $paddingL + $llm;
29554 $ypos = $y + $paddingT;
29555 if ($col) {
29556 $this->SetFColor($col);
29557 } else {
29558 $this->SetFColor($this->ConvertColor(0));
29559 }
29560 if ($arrcode !== false) {
29561 foreach ($arrcode["bcode"] AS $v) {
29562 $bw = ($v["w"] * $xres);
29563 if ($v["t"]) {
29564 // draw a vertical bar
29565 $this->Rect($xpos, $ypos, $bw, $bch, 'F');
29566 }
29567 $xpos += $bw;
29568 }
29569 }
29570
29571
29572 // print text
29573 $prevFontFamily = $this->FontFamily;
29574 $prevFontStyle = $this->FontStyle;
29575 $prevFontSizePt = $this->FontSizePt;
29576
29577 // ISBN string
29578 if (($btype == 'EAN13' && $showtext) || $btype == 'ISBN' || $btype == 'ISSN') {
29579 if ($this->onlyCoreFonts) {
29580 $this->SetFont('chelvetica');
29581 } else {
29582 $this->SetFont('sans');
29583 }
29584
29585 if ($bgcol) {
29586 $this->SetFColor($bgcol);
29587 } else {
29588 $this->SetFColor($this->ConvertColor(255));
29589 }
29590 $this->x = $x + $paddingL + 1; // 1mm left margin (cf. $fbwi above)
29591 // max width is $fbwi
29592 $loop = 0;
29593 while ($loop == 0) {
29594 $this->SetFontSize($codestr_fontsize * 1.4 * _MPDFK, false); // don't write
29595 $sz = $this->GetStringWidth($codestr);
29596 if ($sz > $fbwi)
29597 $codestr_fontsize -= 0.1;
29598 else
29599 $loop ++;
29600 }
29601 $this->SetFont('', '', $codestr_fontsize * 1.4 * _MPDFK, true, true); // * 1.4 because font height is only 7/10 of given mm
29602 // WORD SPACING
29603 if ($fbwi > $sz) {
29604 $xtra = $fbwi - $sz;
29605 $charspacing = $xtra / (strlen($codestr) - 1);
29606 if ($charspacing) {
29607 $this->_out(sprintf('BT %.3F Tc ET', $charspacing * _MPDFK));
29608 }
29609 }
29610 $this->y = $y + $paddingT - ($codestr_fontsize ) - $tisbnm;
29611 $this->Cell($fbw, $codestr_fontsize, $codestr);
29612 if ($charspacing) {
29613 $this->_out('BT 0 Tc ET');
29614 }
29615 }
29616
29617
29618 // Bottom NUMERALS
29619 // mPDF 5.7.4
29620 if ($this->onlyCoreFonts) {
29621 $this->SetFont('ccourier');
29622 $fh = 1.3;
29623 } else {
29624 $this->SetFont('ocrb');
29625 $fh = 1.06;
29626 }
29627 $charRO = '';
29628 if ($btype == 'EAN13' || $btype == 'ISBN' || $btype == 'ISSN') {
29629 $outerfontsize = 3; // Inner fontsize = 3
29630 $outerp = $xres * 4;
29631 $innerp = $xres * 2.5;
29632 $textw = ($bcw * 0.5) - $outerp - $innerp;
29633 $chars = 6; // number of numerals in each half
29634 $charLO = substr($code, 0, 1); // Left Outer
29635 $charLI = substr($code, 1, 6); // Left Inner
29636 $charRI = substr($code, 7, 6); // Right Inner
29637 if (!$supplement)
29638 $charRO = '>'; // Right Outer
29639 }
29640 elseif ($btype == 'UPCA') {
29641 $outerfontsize = 2.3; // Inner fontsize = 3
29642 $outerp = $xres * 10;
29643 $innerp = $xres * 2.5;
29644 $textw = ($bcw * 0.5) - $outerp - $innerp;
29645 $chars = 5;
29646 $charLO = substr($code, 0, 1); // Left Outer
29647 $charLI = substr($code, 1, 5); // Left Inner
29648 $charRI = substr($code, 6, 5); // Right Inner
29649 $charRO = substr($code, 11, 1); // Right Outer
29650 } elseif ($btype == 'UPCE') {
29651 $outerfontsize = 2.3; // Inner fontsize = 3
29652 $outerp = $xres * 4;
29653 $innerp = 0;
29654 $textw = ($bcw * 0.5) - $outerp - $innerp;
29655 $chars = 3;
29656 $upce_code = $arrcode['code'];
29657 $charLO = substr($code, 0, 1); // Left Outer
29658 $charLI = substr($upce_code, 0, 3); // Left Inner
29659 $charRI = substr($upce_code, 3, 3); // Right Inner
29660 $charRO = substr($code, 11, 1); // Right Outer
29661 } elseif ($btype == 'EAN8') {
29662 $outerfontsize = 3; // Inner fontsize = 3
29663 $outerp = $xres * 4;
29664 $innerp = $xres * 2.5;
29665 $textw = ($bcw * 0.5) - $outerp - $innerp;
29666 $chars = 4;
29667 $charLO = '<'; // Left Outer
29668 $charLI = substr($code, 0, 4); // Left Inner
29669 $charRI = substr($code, 4, 4); // Right Inner
29670 if (!$supplement)
29671 $charRO = '>'; // Right Outer
29672 }
29673
29674 $this->SetFontSize(($outerfontsize / 3) * 3 * $fh * $size * _MPDFK); // 3mm numerals (FontSize is larger to account for space above/below characters)
29675
29676 if (!$this->usingCoreFont) {
29677 $cw = $this->_getCharWidth($this->CurrentFont['cw'], 32) * 3 * $fh * $size / 1000;
29678 } // character width at 3mm
29679 else {
29680 $cw = 600 * 3 * $fh * $size / 1000;
29681 } // mPDF 5.7.4
29682 // Outer left character
29683 $y_text = $y + $paddingT + $bch - ($num_height / 2);
29684 $y_text_outer = $y + $paddingT + $bch - ($num_height * ($outerfontsize / 3) / 2);
29685
29686 $this->x = $x + $paddingL - ($cw * ($outerfontsize / 3) * 0.1); // 0.1 is correction as char does not fill full width;
29687 $this->y = $y_text_outer;
29688 $this->Cell($cw, $num_height, $charLO);
29689
29690 // WORD SPACING for inner chars
29691 $xtra = $textw - ($cw * $chars);
29692 $charspacing = $xtra / ($chars - 1);
29693 if ($charspacing) {
29694 $this->_out(sprintf('BT %.3F Tc ET', $charspacing * _MPDFK));
29695 }
29696
29697 if ($bgcol) {
29698 $this->SetFColor($bgcol);
29699 } else {
29700 $this->SetFColor($this->ConvertColor(255));
29701 }
29702
29703 $this->SetFontSize(3 * $fh * $size * _MPDFK); // 3mm numerals (FontSize is larger to account for space above/below characters)
29704 // Inner left half characters
29705 $this->x = $x + $paddingL + $llm + $outerp;
29706 $this->y = $y_text;
29707 $this->Cell($textw, $num_height, $charLI, 0, 0, '', 1);
29708
29709 // Inner right half characters
29710 $this->x = $x + $paddingL + $llm + ($bcw * 0.5) + $innerp;
29711 $this->y = $y_text;
29712 $this->Cell($textw, $num_height, $charRI, 0, 0, '', 1);
29713
29714 if ($charspacing) {
29715 $this->_out('BT 0 Tc ET');
29716 }
29717
29718 // Outer Right character
29719 $this->SetFontSize(($outerfontsize / 3) * 3 * $fh * $size * _MPDFK); // 3mm numerals (FontSize is larger to account for space above/below characters)
29720
29721 $this->x = $x + $paddingL + $llm + $bcw + $rlm - ($cw * ($outerfontsize / 3) * 0.9); // 0.9 is correction as char does not fill full width
29722 $this->y = $y_text_outer;
29723 $this->Cell($cw * ($outerfontsize / 3), $num_height, $charRO, 0, 0, 'R');
29724
29725 if ($supplement) { // EAN-2 or -5 Supplement
29726 // PRINT BARS
29727 $supparrcode = $this->barcode->getBarcodeArray($supplement_code, 'EAN' . $supplement);
29728 if ($supparrcode === false) {
29729 throw new MpdfException('Error in barcode string (supplement): ' . $codestr . ' ' . $supplement_code);
29730 }
29731 if (strlen($supplement_code) != $supplement) {
29732 throw new MpdfException('Barcode supplement incorrect: ' . $supplement_code);
29733 }
29734 $llm = $fbw - (($arrcode['lightmR'] - $supparrcode['sepM']) * $arrcode['nom-X'] * $size); // Left Light margin
29735 $rlm = $arrcode['lightmR'] * $arrcode['nom-X'] * $size; // Right Light margin
29736
29737 $bcw = ($supparrcode["maxw"] * $xres); // Barcode width = Should always be 31.35mm * $size
29738
29739 $fbw = $bcw + $llm + $rlm; // Full barcode width incl. light margins
29740 $ow = $fbw + $paddingL + $paddingR; // Full overall width incl. user-defined padding
29741 $bch = $fbh - (1.5 * $size) - ($num_height + 0.5); // Barcode height of bars (3mm for numerals)
29742
29743 $xpos = $x + $paddingL + $llm;
29744 $ypos = $y + $paddingT + $num_height + 0.5;
29745 if ($col) {
29746 $this->SetFColor($col);
29747 } else {
29748 $this->SetFColor($this->ConvertColor(0));
29749 }
29750 if ($supparrcode !== false) {
29751 foreach ($supparrcode["bcode"] AS $v) {
29752 $bw = ($v["w"] * $xres);
29753 if ($v["t"]) {
29754 // draw a vertical bar
29755 $this->Rect($xpos, $ypos, $bw, $bch, 'F');
29756 }
29757 $xpos += $bw;
29758 }
29759 }
29760
29761 // Characters
29762 if ($bgcol) {
29763 $this->SetFColor($bgcol);
29764 } else {
29765 $this->SetFColor($this->ConvertColor(255));
29766 }
29767 $this->SetFontSize(3 * $fh * $size * _MPDFK); // 3mm numerals (FontSize is larger to account for space above/below characters)
29768 $this->x = $x + $paddingL + $llm;
29769 $this->y = $y + $paddingT;
29770 $this->Cell($bcw, $num_height, $supplement_code, 0, 0, 'C');
29771
29772 // Outer Right character (light margin)
29773 $this->SetFontSize(($outerfontsize / 3) * 3 * $fh * $size * _MPDFK); // 3mm numerals (FontSize is larger to account for space above/below characters)
29774 $this->x = $x + $paddingL + $llm + $bcw + $rlm - ($cw * 0.9); // 0.9 is correction as char does not fill full width
29775 $this->y = $y + $paddingT;
29776 $this->Cell($cw * ($outerfontsize / 3), $num_height, '>', 0, 0, 'R');
29777 }
29778
29779
29780
29781 // Restore **************
29782 $this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt);
29783 $this->DrawColor = $prevDrawColor;
29784 $this->TextColor = $prevTextColor;
29785 $this->FillColor = $prevFillColor;
29786 $this->SetLineWidth($lw);
29787 $this->SetY($y);
29788 }
29789
29790 // ====================================================
29791 // POSTAL and OTHER barcodes
29792 function WriteBarcode2($code, $x = '', $y = '', $size = 1, $height = 1, $bgcol = false, $col = false, $btype = 'IMB', $print_ratio = '', $k = 1)
29793 {
29794 if (empty($code)) {
29795 return;
29796 }
29797 if (!class_exists('PDFBarcode', false)) {
29798 include(_MPDF_PATH . 'classes/barcode.php');
29799 }
29800 $this->barcode = new PDFBarcode();
29801 $arrcode = $this->barcode->getBarcodeArray($code, $btype, $print_ratio);
29802
29803 if ($arrcode === false) {
29804 throw new MpdfException('Error in barcode string: ' . $code);
29805 }
29806 if (empty($x)) {
29807 $x = $this->x;
29808 }
29809 if (empty($y)) {
29810 $y = $this->y;
29811 }
29812 $prevDrawColor = $this->DrawColor;
29813 $prevTextColor = $this->TextColor;
29814 $prevFillColor = $this->FillColor;
29815 $lw = $this->LineWidth;
29816 $this->SetLineWidth(0.01);
29817 $size /= $k; // in case resized in a table
29818 $xres = $arrcode['nom-X'] * $size;
29819
29820 if ($btype == 'IMB' || $btype == 'RM4SCC' || $btype == 'KIX' || $btype == 'POSTNET' || $btype == 'PLANET') {
29821 $llm = $arrcode['quietL'] / $k; // Left Quiet margin
29822 $rlm = $arrcode['quietR'] / $k; // Right Quiet margin
29823 $tlm = $blm = $arrcode['quietTB'] / $k;
29824 $height = 1; // Overrides
29825 } elseif (in_array($btype, array('C128A', 'C128B', 'C128C', 'EAN128A', 'EAN128B', 'EAN128C', 'C39', 'C39+', 'C39E', 'C39E+', 'S25', 'S25+', 'I25', 'I25+', 'I25B', 'I25B+', 'C93', 'MSI', 'MSI+', 'CODABAR', 'CODE11'))) {
29826 $llm = $arrcode['lightmL'] * $xres; // Left Quiet margin
29827 $rlm = $arrcode['lightmR'] * $xres; // Right Quiet margin
29828 $tlm = $blm = $arrcode['lightTB'] * $xres * $height;
29829 }
29830
29831
29832 $bcw = ($arrcode["maxw"] * $xres);
29833 $fbw = $bcw + $llm + $rlm; // Full barcode width incl. light margins
29834
29835 $bch = ($arrcode["nom-H"] * $size * $height);
29836 $fbh = $bch + $tlm + $blm; // Full barcode height
29837 // PRINT border background color
29838 $xpos = $x;
29839 $ypos = $y;
29840 if ($col) {
29841 $this->SetDColor($col);
29842 $this->SetTColor($col);
29843 } else {
29844 $this->SetDColor($this->ConvertColor(0));
29845 $this->SetTColor($this->ConvertColor(0));
29846 }
29847 if ($bgcol) {
29848 $this->SetFColor($bgcol);
29849 } else {
29850 $this->SetFColor($this->ConvertColor(255));
29851 }
29852
29853 // PRINT BARS
29854 if ($col) {
29855 $this->SetFColor($col);
29856 } else {
29857 $this->SetFColor($this->ConvertColor(0));
29858 }
29859 $xpos = $x + $llm;
29860
29861 if ($arrcode !== false) {
29862 foreach ($arrcode["bcode"] AS $v) {
29863 $bw = ($v["w"] * $xres);
29864 if ($v["t"]) {
29865 $ypos = $y + $tlm + ($bch * $v['p'] / $arrcode['maxh']);
29866 $this->Rect($xpos, $ypos, $bw, ($v['h'] * $bch / $arrcode['maxh']), 'F');
29867 }
29868 $xpos += $bw;
29869 }
29870 }
29871
29872 // PRINT BEARER BARS
29873 if ($btype == 'I25B' || $btype == 'I25B+') {
29874 $this->Rect($x, $y, $fbw, ($arrcode['lightTB'] * $xres * $height), 'F');
29875 $this->Rect($x, $y + $tlm + $bch, $fbw, ($arrcode['lightTB'] * $xres * $height), 'F');
29876 }
29877
29878 // Restore **************
29879 $this->DrawColor = $prevDrawColor;
29880 $this->TextColor = $prevTextColor;
29881 $this->FillColor = $prevFillColor;
29882 $this->SetLineWidth($lw);
29883 $this->SetY($y);
29884 }
29885
29886 /* -- END BARCODES -- */
29887
29888 // ====================================================
29889 // ====================================================
29890
29891 function StartTransform($returnstring = false)
29892 {
29893 if ($returnstring) {
29894 return('q');
29895 } else {
29896 $this->_out('q');
29897 }
29898 }
29899
29900 function StopTransform($returnstring = false)
29901 {
29902 if ($returnstring) {
29903 return('Q');
29904 } else {
29905 $this->_out('Q');
29906 }
29907 }
29908
29909 function transformScale($s_x, $s_y, $x = '', $y = '', $returnstring = false)
29910 {
29911 if ($x === '') {
29912 $x = $this->x;
29913 }
29914 if ($y === '') {
29915 $y = $this->y;
29916 }
29917 if (($s_x == 0) OR ( $s_y == 0)) {
29918 throw new MpdfException('Please do not use values equal to zero for scaling');
29919 }
29920 $y = ($this->h - $y) * _MPDFK;
29921 $x *= _MPDFK;
29922 //calculate elements of transformation matrix
29923 $s_x /= 100;
29924 $s_y /= 100;
29925 $tm = array();
29926 $tm[0] = $s_x;
29927 $tm[1] = 0;
29928 $tm[2] = 0;
29929 $tm[3] = $s_y;
29930 $tm[4] = $x * (1 - $s_x);
29931 $tm[5] = $y * (1 - $s_y);
29932 //scale the coordinate system
29933 if ($returnstring) {
29934 return($this->_transform($tm, true));
29935 } else {
29936 $this->_transform($tm);
29937 }
29938 }
29939
29940 function transformTranslate($t_x, $t_y, $returnstring = false)
29941 {
29942 //calculate elements of transformation matrix
29943 $tm = array();
29944 $tm[0] = 1;
29945 $tm[1] = 0;
29946 $tm[2] = 0;
29947 $tm[3] = 1;
29948 $tm[4] = $t_x * _MPDFK;
29949 $tm[5] = -$t_y * _MPDFK;
29950 //translate the coordinate system
29951 if ($returnstring) {
29952 return($this->_transform($tm, true));
29953 } else {
29954 $this->_transform($tm);
29955 }
29956 }
29957
29958 function transformRotate($angle, $x = '', $y = '', $returnstring = false)
29959 {
29960 if ($x === '') {
29961 $x = $this->x;
29962 }
29963 if ($y === '') {
29964 $y = $this->y;
29965 }
29966 $angle = -$angle;
29967 $y = ($this->h - $y) * _MPDFK;
29968 $x *= _MPDFK;
29969 //calculate elements of transformation matrix
29970 $tm = array();
29971 $tm[0] = cos(deg2rad($angle));
29972 $tm[1] = sin(deg2rad($angle));
29973 $tm[2] = -$tm[1];
29974 $tm[3] = $tm[0];
29975 $tm[4] = $x + $tm[1] * $y - $tm[0] * $x;
29976 $tm[5] = $y - $tm[0] * $y - $tm[1] * $x;
29977 //rotate the coordinate system around ($x,$y)
29978 if ($returnstring) {
29979 return($this->_transform($tm, true));
29980 } else {
29981 $this->_transform($tm);
29982 }
29983 }
29984
29985 // mPDF 5.7.3 TRANSFORMS
29986 function transformSkew($angle_x, $angle_y, $x = '', $y = '', $returnstring = false)
29987 {
29988 if ($x === '') {
29989 $x = $this->x;
29990 }
29991 if ($y === '') {
29992 $y = $this->y;
29993 }
29994 $angle_x = -$angle_x;
29995 $angle_y = -$angle_y;
29996 $x *= _MPDFK;
29997 $y = ($this->h - $y) * _MPDFK;
29998 //calculate elements of transformation matrix
29999 $tm = array();
30000 $tm[0] = 1;
30001 $tm[1] = tan(deg2rad($angle_y));
30002 $tm[2] = tan(deg2rad($angle_x));
30003 $tm[3] = 1;
30004 $tm[4] = -$tm[2] * $y;
30005 $tm[5] = -$tm[1] * $x;
30006 //skew the coordinate system
30007 if ($returnstring) {
30008 return($this->_transform($tm, true));
30009 } else {
30010 $this->_transform($tm);
30011 }
30012 }
30013
30014 function _transform($tm, $returnstring = false)
30015 {
30016 if ($returnstring) {
30017 return(sprintf('%.4F %.4F %.4F %.4F %.4F %.4F cm', $tm[0], $tm[1], $tm[2], $tm[3], $tm[4], $tm[5]));
30018 } else {
30019 $this->_out(sprintf('%.4F %.4F %.4F %.4F %.4F %.4F cm', $tm[0], $tm[1], $tm[2], $tm[3], $tm[4], $tm[5]));
30020 }
30021 }
30022
30023 // AUTOFONT =========================
30024 function markScriptToLang($html)
30025 {
30026 if ($this->onlyCoreFonts) {
30027 return $html;
30028 }
30029
30030 // sets $this->script2lang
30031 if (empty($this->script2lang)) {
30032 include(_MPDF_PATH . 'config_script2lang.php');
30033 }
30034
30035 $n = '';
30036 $a = preg_split('/<(.*?)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
30037 foreach ($a as $i => $e) {
30038 if ($i % 2 == 0) {
30039 //ignore if in Textarea
30040 if ($i > 0 && strtolower(substr($a[$i - 1], 1, 8)) == 'textarea') {
30041 $a[$i] = $e;
30042 continue;
30043 }
30044 $e = strcode2utf($e);
30045 $e = $this->lesser_entity_decode($e);
30046
30047 $earr = $this->UTF8StringToArray($e, false);
30048
30049 $scriptblock = 0;
30050 $scriptblocks = array();
30051 $scriptblocks[0] = 0;
30052 $chardata = array();
30053 $subchunk = 0;
30054 $charctr = 0;
30055 foreach ($earr as $char) {
30056 $ucd_record = UCDN::get_ucd_record($char);
30057 $sbl = $ucd_record[6];
30058
30059 if ($sbl && $sbl != 40 && $sbl != 102) {
30060 if ($scriptblock == 0) {
30061 $scriptblock = $sbl;
30062 $scriptblocks[$subchunk] = $scriptblock;
30063 } elseif ($scriptblock > 0 && $scriptblock != $sbl) {
30064 // NEW (non-common) Script encountered in this chunk.
30065 // Start a new subchunk
30066 $subchunk++;
30067 $scriptblock = $sbl;
30068 $charctr = 0;
30069 $scriptblocks[$subchunk] = $scriptblock;
30070 }
30071 }
30072
30073 $chardata[$subchunk][$charctr]['script'] = $sbl;
30074 $chardata[$subchunk][$charctr]['uni'] = $char;
30075 $charctr++;
30076 }
30077
30078 // If scriptblock[x] = common & non-baseScript
30079 // and scriptblock[x+1] = baseScript
30080 // Move common script from end of x to start of x+1
30081 for ($sch = 0; $sch < $subchunk; $sch++) {
30082 if ($scriptblocks[$sch] > 0 && $scriptblocks[$sch] != $this->baseScript && $scriptblocks[$sch + 1] == $this->baseScript) {
30083 $end = count($chardata[$sch]) - 1;
30084 while ($chardata[$sch][$end]['script'] == 0 && $end > 1) { // common script
30085 $tmp = array_pop($chardata[$sch]);
30086 array_unshift($chardata[$sch + 1], $tmp);
30087 $end--;
30088 }
30089 }
30090 }
30091
30092 $o = '';
30093 for ($sch = 0; $sch <= $subchunk; $sch++) {
30094 if (isset($chardata[$sch])) {
30095 $s = '';
30096 for ($j = 0; $j < count($chardata[$sch]); $j++) {
30097 $s.=code2utf($chardata[$sch][$j]['uni']);
30098 }
30099 // ZZZ99 Undo lesser_entity_decode as above - but only for <>&
30100 $s = str_replace("&", "&amp;", $s);
30101 $s = str_replace("<", "&lt;", $s);
30102 $s = str_replace(">", "&gt;", $s);
30103
30104 // Check Vietnamese if Latin script - even if Basescript
30105 if ($scriptblocks[$sch] == UCDN::SCRIPT_LATIN && $this->autoVietnamese && preg_match("/([" . $this->viet . "])/u", $s)) {
30106 $o .= '<span lang="vi" class="lang_vi">' . $s . '</span>';
30107 }
30108 // Check Arabic for different languages if Arabic script - even if Basescript
30109 elseif ($scriptblocks[$sch] == UCDN::SCRIPT_ARABIC && $this->autoArabic) {
30110 if (preg_match("/[" . $this->sindhi . "]/u", $s)) {
30111 $o .= '<span lang="sd" class="lang_sd">' . $s . '</span>';
30112 } elseif (preg_match("/[" . $this->urdu . "]/u", $s)) {
30113 $o .= '<span lang="ur" class="lang_ur">' . $s . '</span>';
30114 } elseif (preg_match("/[" . $this->pashto . "]/u", $s)) {
30115 $o .= '<span lang="ps" class="lang_ps">' . $s . '</span>';
30116 } elseif (preg_match("/[" . $this->persian . "]/u", $s)) {
30117 $o .= '<span lang="fa" class="lang_fa">' . $s . '</span>';
30118 } elseif ($this->baseScript != UCDN::SCRIPT_ARABIC && isset($this->script2lang[$scriptblocks[$sch]])) {
30119 $o .= '<span lang="' . $this->script2lang[$scriptblocks[$sch]] . '" class="lang_' . $this->script2lang[$scriptblocks[$sch]] . '">' . $s . '</span>';
30120 } else {
30121 // Just output chars
30122 $o .= $s;
30123 }
30124 }
30125 // Identify Script block if not Basescript, and mark up as language
30126 elseif ($scriptblocks[$sch] > 0 && $scriptblocks[$sch] != $this->baseScript && isset($this->script2lang[$scriptblocks[$sch]])) {
30127 // Encase in <span>
30128 $o .= '<span lang="' . $this->script2lang[$scriptblocks[$sch]] . '" class="lang_' . $this->script2lang[$scriptblocks[$sch]] . '">';
30129 $o .= $s;
30130 $o .= '</span>';
30131 } else {
30132 // Just output chars
30133 $o .= $s;
30134 }
30135 }
30136 }
30137
30138 $a[$i] = $o;
30139 } else {
30140 $a[$i] = '<' . $e . '>';
30141 }
30142 }
30143 $n = implode('', $a);
30144
30145 return $n;
30146 }
30147
30148 //===========================
30149 // Functions
30150 // Call-back function Used for usort in fn _tableWrite
30151
30152 function _cmpdom($a, $b)
30153 {
30154 return ($a["dom"] < $b["dom"]) ? -1 : 1;
30155 }
30156
30157 function mb_strrev($str, $enc = 'utf-8')
30158 {
30159 $ch = array();
30160 $ch = preg_split('//u', $str);
30161 $revch = array_reverse($ch);
30162 return implode('', $revch);
30163 }
30164
30165 /* -- COLUMNS -- */
30166
30167 // Callback function from function printcolumnbuffer in mpdf
30168 function columnAdjustAdd($type, $k, $xadj, $yadj, $a, $b, $c = 0, $d = 0, $e = 0, $f = 0)
30169 {
30170 if ($type == 'Td') { // xpos,ypos
30171 $a += ($xadj * $k);
30172 $b -= ($yadj * $k);
30173 return 'BT ' . sprintf('%.3F %.3F', $a, $b) . ' Td';
30174 } elseif ($type == 're') { // xpos,ypos,width,height
30175 $a += ($xadj * $k);
30176 $b -= ($yadj * $k);
30177 return sprintf('%.3F %.3F %.3F %.3F', $a, $b, $c, $d) . ' re';
30178 } elseif ($type == 'l') { // xpos,ypos,x2pos,y2pos
30179 $a += ($xadj * $k);
30180 $b -= ($yadj * $k);
30181 return sprintf('%.3F %.3F l', $a, $b);
30182 } elseif ($type == 'img') { // width,height,xpos,ypos
30183 $c += ($xadj * $k);
30184 $d -= ($yadj * $k);
30185 return sprintf('q %.3F 0 0 %.3F %.3F %.3F', $a, $b, $c, $d) . ' cm /' . $e;
30186 } elseif ($type == 'draw') { // xpos,ypos
30187 $a += ($xadj * $k);
30188 $b -= ($yadj * $k);
30189 return sprintf('%.3F %.3F m', $a, $b);
30190 } elseif ($type == 'bezier') { // xpos,ypos,x2pos,y2pos,x3pos,y3pos
30191 $a += ($xadj * $k);
30192 $b -= ($yadj * $k);
30193 $c += ($xadj * $k);
30194 $d -= ($yadj * $k);
30195 $e += ($xadj * $k);
30196 $f -= ($yadj * $k);
30197 return sprintf('%.3F %.3F %.3F %.3F %.3F %.3F', $a, $b, $c, $d, $e, $f) . ' c';
30198 }
30199 }
30200
30201 /* -- END COLUMNS -- */
30202
30203 function ConvertColor($color = "#000000")
30204 {
30205 static $cache;
30206
30207 $color = trim(strtolower($color));
30208 $c = false;
30209 $cstr = '';
30210 if ($color == 'transparent') {
30211 return false;
30212 } elseif ($color == 'inherit') {
30213 return false;
30214 } elseif (isset($this->SVGcolors[$color]))
30215 $color = $this->SVGcolors[$color];
30216
30217 if (!isset($cache[$color])) {
30218 if (preg_match('/^[\d]+$/', $color)) {
30219 $c = (array(1, $color));
30220 } // i.e. integer only
30221 elseif ($color[0] == '#') { //case of #nnnnnn or #nnn
30222 $cor = preg_replace('/\s+.*/', '', $color); // in case of Background: #CCC url() x-repeat etc.
30223 if (strlen($cor) == 4) { // Turn #RGB into #RRGGBB
30224 $cor = "#" . $cor[1] . $cor[1] . $cor[2] . $cor[2] . $cor[3] . $cor[3];
30225 }
30226 $r = hexdec(substr($cor, 1, 2));
30227 $g = hexdec(substr($cor, 3, 2));
30228 $b = hexdec(substr($cor, 5, 2));
30229 $c = array(3, $r, $g, $b);
30230 } elseif (preg_match('/(rgba|rgb|device-cmyka|cmyka|device-cmyk|cmyk|hsla|hsl|spot)\((.*?)\)/', $color, $m)) {
30231 $type = $m[1];
30232 $cores = explode(",", $m[2]);
30233 $ncores = count($cores);
30234 if (stristr($cores[0], '%')) {
30235 $cores[0] += 0;
30236 if ($type == 'rgb' || $type == 'rgba') {
30237 $cores[0] = intval($cores[0] * 255 / 100);
30238 }
30239 }
30240 if ($ncores > 1 && stristr($cores[1], '%')) {
30241 $cores[1] += 0;
30242 if ($type == 'rgb' || $type == 'rgba') {
30243 $cores[1] = intval($cores[1] * 255 / 100);
30244 }
30245 if ($type == 'hsl' || $type == 'hsla') {
30246 $cores[1] = $cores[1] / 100;
30247 }
30248 }
30249 if ($ncores > 2 && stristr($cores[2], '%')) {
30250 $cores[2] += 0;
30251 if ($type == 'rgb' || $type == 'rgba') {
30252 $cores[2] = intval($cores[2] * 255 / 100);
30253 }
30254 if ($type == 'hsl' || $type == 'hsla') {
30255 $cores[2] = $cores[2] / 100;
30256 }
30257 }
30258 if ($ncores > 3 && stristr($cores[3], '%')) {
30259 $cores[3] += 0;
30260 }
30261
30262 if ($type == 'rgb') {
30263 $c = array(3, $cores[0], $cores[1], $cores[2]);
30264 } elseif ($type == 'rgba') {
30265 $c = array(5, $cores[0], $cores[1], $cores[2], $cores[3] * 100);
30266 } elseif ($type == 'cmyk' || $type == 'device-cmyk') {
30267 $c = array(4, $cores[0], $cores[1], $cores[2], $cores[3]);
30268 } elseif ($type == 'cmyka' || $type == 'device-cmyka') {
30269 $c = array(6, $cores[0], $cores[1], $cores[2], $cores[3], $cores[4] * 100);
30270 } elseif ($type == 'hsl' || $type == 'hsla') {
30271 $conv = $this->hsl2rgb($cores[0] / 360, $cores[1], $cores[2]);
30272 if ($type == 'hsl') {
30273 $c = array(3, $conv[0], $conv[1], $conv[2]);
30274 } elseif ($type == 'hsla') {
30275 $c = array(5, $conv[0], $conv[1], $conv[2], $cores[3] * 100);
30276 }
30277 } elseif ($type == 'spot') {
30278 $name = strtoupper(trim($cores[0]));
30279 if (!isset($this->spotColors[$name])) {
30280 if (isset($cores[5])) {
30281 $this->AddSpotColor($cores[0], $cores[2], $cores[3], $cores[4], $cores[5]);
30282 } else {
30283 throw new MpdfException('Undefined spot color: ' . $name);
30284 }
30285 }
30286 $c = array(2, $this->spotColors[$name]['i'], $cores[1]);
30287 }
30288 }
30289
30290
30291 // $this->restrictColorSpace
30292 // 1 - allow GRAYSCALE only [convert CMYK/RGB->gray]
30293 // 2 - allow RGB / SPOT COLOR / Grayscale [convert CMYK->RGB]
30294 // 3 - allow CMYK / SPOT COLOR / Grayscale [convert RGB->CMYK]
30295 if ($this->PDFA || $this->PDFX || $this->restrictColorSpace) {
30296 if ($c[0] == 1) { // GRAYSCALE
30297 } elseif ($c[0] == 2) { // SPOT COLOR
30298 if (!isset($this->spotColorIDs[$c[1]])) {
30299 throw new MpdfException('Error: Spot colour has not been defined - ' . $this->spotColorIDs[$c[1]]);
30300 }
30301 if ($this->PDFA) {
30302 if ($this->PDFA && !$this->PDFAauto) {
30303 $this->PDFAXwarnings[] = "Spot color specified '" . $this->spotColorIDs[$c[1]] . "' (converted to process color)";
30304 }
30305 if ($this->restrictColorSpace != 3) {
30306 $sp = $this->spotColors[$this->spotColorIDs[$c[1]]];
30307 $c = $this->cmyk2rgb(array(4, $sp['c'], $sp['m'], $sp['y'], $sp['k']));
30308 }
30309 } elseif ($this->restrictColorSpace == 1) {
30310 $sp = $this->spotColors[$this->spotColorIDs[$c[1]]];
30311 $c = $this->cmyk2gray(array(4, $sp['c'], $sp['m'], $sp['y'], $sp['k']));
30312 }
30313 }
30314 // RGB
30315 elseif ($c[0] == 3) {
30316 if ($this->PDFX || ($this->PDFA && $this->restrictColorSpace == 3)) {
30317 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
30318 $this->PDFAXwarnings[] = "RGB color specified '" . $color . "' (converted to CMYK)";
30319 }
30320 $c = $this->rgb2cmyk($c);
30321 } elseif ($this->restrictColorSpace == 1) {
30322 $c = $this->rgb2gray($c);
30323 } elseif ($this->restrictColorSpace == 3) {
30324 $c = $this->rgb2cmyk($c);
30325 }
30326 }
30327 // CMYK
30328 elseif ($c[0] == 4) {
30329 if ($this->PDFA && $this->restrictColorSpace != 3) {
30330 if ($this->PDFA && !$this->PDFAauto) {
30331 $this->PDFAXwarnings[] = "CMYK color specified '" . $color . "' (converted to RGB)";
30332 }
30333 $c = $this->cmyk2rgb($c);
30334 } elseif ($this->restrictColorSpace == 1) {
30335 $c = $this->cmyk2gray($c);
30336 } elseif ($this->restrictColorSpace == 2) {
30337 $c = $this->cmyk2rgb($c);
30338 }
30339 }
30340 // RGBa
30341 elseif ($c[0] == 5) {
30342 if ($this->PDFX || ($this->PDFA && $this->restrictColorSpace == 3)) {
30343 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
30344 $this->PDFAXwarnings[] = "RGB color with transparency specified '" . $color . "' (converted to CMYK without transparency)";
30345 }
30346 $c = $this->rgb2cmyk($c);
30347 $c = array(4, $c[1], $c[2], $c[3], $c[4]);
30348 } elseif ($this->PDFA && $this->restrictColorSpace != 3) {
30349 if (!$this->PDFAauto) {
30350 $this->PDFAXwarnings[] = "RGB color with transparency specified '" . $color . "' (converted to RGB without transparency)";
30351 }
30352 $c = $this->rgb2cmyk($c);
30353 $c = array(4, $c[1], $c[2], $c[3], $c[4]);
30354 } elseif ($this->restrictColorSpace == 1) {
30355 $c = $this->rgb2gray($c);
30356 } elseif ($this->restrictColorSpace == 3) {
30357 $c = $this->rgb2cmyk($c);
30358 }
30359 }
30360 // CMYKa
30361 elseif ($c[0] == 6) {
30362 if ($this->PDFA && $this->restrictColorSpace != 3) {
30363 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
30364 $this->PDFAXwarnings[] = "CMYK color with transparency specified '" . $color . "' (converted to RGB without transparency)";
30365 }
30366 $c = $this->cmyk2rgb($c);
30367 $c = array(3, $c[1], $c[2], $c[3]);
30368 } elseif ($this->PDFX || ($this->PDFA && $this->restrictColorSpace == 3)) {
30369 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
30370 $this->PDFAXwarnings[] = "CMYK color with transparency specified '" . $color . "' (converted to CMYK without transparency)";
30371 }
30372 $c = $this->cmyk2rgb($c);
30373 $c = array(3, $c[1], $c[2], $c[3]);
30374 } elseif ($this->restrictColorSpace == 1) {
30375 $c = $this->cmyk2gray($c);
30376 } elseif ($this->restrictColorSpace == 2) {
30377 $c = $this->cmyk2rgb($c);
30378 }
30379 }
30380 }
30381 if (is_array($c)) {
30382 $c = array_pad($c, 6, 0);
30383 $cstr = pack("a1ccccc", $c[0], ($c[1] & 0xFF), ($c[2] & 0xFF), ($c[3] & 0xFF), ($c[4] & 0xFF), ($c[5] & 0xFF));
30384 }
30385
30386 $cache[$color] = $cstr;
30387 }
30388
30389 return $cache[$color];
30390 }
30391
30392 function rgb2gray($c)
30393 {
30394 if (isset($c[4])) {
30395 return array(1, (($c[1] * .21) + ($c[2] * .71) + ($c[3] * .07)), ord(1), $c[4]);
30396 } else {
30397 return array(1, (($c[1] * .21) + ($c[2] * .71) + ($c[3] * .07)));
30398 }
30399 }
30400
30401 function cmyk2gray($c)
30402 {
30403 $rgb = $this->cmyk2rgb($c);
30404 return $this->rgb2gray($rgb);
30405 }
30406
30407 function rgb2cmyk($c)
30408 {
30409 $cyan = 1 - ($c[1] / 255);
30410 $magenta = 1 - ($c[2] / 255);
30411 $yellow = 1 - ($c[3] / 255);
30412 $min = min($cyan, $magenta, $yellow);
30413
30414 if ($min == 1) {
30415 if ($c[0] == 5) {
30416 return array(6, 100, 100, 100, 100, $c[4]);
30417 } else {
30418 return array(4, 100, 100, 100, 100);
30419 }
30420 // For K-Black
30421 //if ($c[0]==5) { return array (6,0,0,0,100, $c[4]); }
30422 //else { return array (4,0,0,0,100); }
30423 }
30424 $K = $min;
30425 $black = 1 - $K;
30426 if ($c[0] == 5) {
30427 return array(6, ($cyan - $K) * 100 / $black, ($magenta - $K) * 100 / $black, ($yellow - $K) * 100 / $black, $K * 100, $c[4]);
30428 } else {
30429 return array(4, ($cyan - $K) * 100 / $black, ($magenta - $K) * 100 / $black, ($yellow - $K) * 100 / $black, $K * 100);
30430 }
30431 }
30432
30433 function cmyk2rgb($c)
30434 {
30435 $rgb = array();
30436 $colors = 255 - ($c[4] * 2.55);
30437 $rgb[0] = intval($colors * (255 - ($c[1] * 2.55)) / 255);
30438 $rgb[1] = intval($colors * (255 - ($c[2] * 2.55)) / 255);
30439 $rgb[2] = intval($colors * (255 - ($c[3] * 2.55)) / 255);
30440 if ($c[0] == 6) {
30441 return array(5, $rgb[0], $rgb[1], $rgb[2], $c[5]);
30442 } else {
30443 return array(3, $rgb[0], $rgb[1], $rgb[2]);
30444 }
30445 }
30446
30447 function rgb2hsl($var_r, $var_g, $var_b)
30448 {
30449 $var_min = min($var_r, $var_g, $var_b);
30450 $var_max = max($var_r, $var_g, $var_b);
30451 $del_max = $var_max - $var_min;
30452 $l = ($var_max + $var_min) / 2;
30453 if ($del_max == 0) {
30454 $h = 0;
30455 $s = 0;
30456 } else {
30457 if ($l < 0.5) {
30458 $s = $del_max / ($var_max + $var_min);
30459 } else {
30460 $s = $del_max / (2 - $var_max - $var_min);
30461 }
30462 $del_r = ((($var_max - $var_r) / 6) + ($del_max / 2)) / $del_max;
30463 $del_g = ((($var_max - $var_g) / 6) + ($del_max / 2)) / $del_max;
30464 $del_b = ((($var_max - $var_b) / 6) + ($del_max / 2)) / $del_max;
30465 if ($var_r == $var_max) {
30466 $h = $del_b - $del_g;
30467 } elseif ($var_g == $var_max) {
30468 $h = (1 / 3) + $del_r - $del_b;
30469 } elseif ($var_b == $var_max) {
30470 $h = (2 / 3) + $del_g - $del_r;
30471 };
30472 if ($h < 0) {
30473 $h += 1;
30474 }
30475 if ($h > 1) {
30476 $h -= 1;
30477 }
30478 }
30479 return array($h, $s, $l);
30480 }
30481
30482 function hsl2rgb($h2, $s2, $l2)
30483 {
30484 // Input is HSL value of complementary colour, held in $h2, $s, $l as fractions of 1
30485 // Output is RGB in normal 255 255 255 format, held in $r, $g, $b
30486 // Hue is converted using function hue_2_rgb, shown at the end of this code
30487 if ($s2 == 0) {
30488 $r = $l2 * 255;
30489 $g = $l2 * 255;
30490 $b = $l2 * 255;
30491 } else {
30492 if ($l2 < 0.5) {
30493 $var_2 = $l2 * (1 + $s2);
30494 } else {
30495 $var_2 = ($l2 + $s2) - ($s2 * $l2);
30496 }
30497 $var_1 = 2 * $l2 - $var_2;
30498 $r = round(255 * $this->hue_2_rgb($var_1, $var_2, $h2 + (1 / 3)));
30499 $g = round(255 * $this->hue_2_rgb($var_1, $var_2, $h2));
30500 $b = round(255 * $this->hue_2_rgb($var_1, $var_2, $h2 - (1 / 3)));
30501 }
30502 return array($r, $g, $b);
30503 }
30504
30505 function hue_2_rgb($v1, $v2, $vh)
30506 {
30507 // Function to convert hue to RGB, called from above
30508 if ($vh < 0) {
30509 $vh += 1;
30510 };
30511 if ($vh > 1) {
30512 $vh -= 1;
30513 };
30514 if ((6 * $vh) < 1) {
30515 return ($v1 + ($v2 - $v1) * 6 * $vh);
30516 };
30517 if ((2 * $vh) < 1) {
30518 return ($v2);
30519 };
30520 if ((3 * $vh) < 2) {
30521 return ($v1 + ($v2 - $v1) * ((2 / 3 - $vh) * 6));
30522 };
30523 return ($v1);
30524 }
30525
30526 function _invertColor($cor)
30527 {
30528 if ($cor[0] == 3 || $cor[0] == 5) { // RGB
30529 return array(3, (255 - $cor[1]), (255 - $cor[2]), (255 - $cor[3]));
30530 } elseif ($cor[0] == 4 || $cor[0] == 6) { // CMYK
30531 return array(4, (100 - $cor[1]), (100 - $cor[2]), (100 - $cor[3]), (100 - $cor[4]));
30532 } elseif ($cor[0] == 1) { // Grayscale
30533 return array(1, (255 - $cor[1]));
30534 }
30535 // Cannot cope with non-RGB colors at present
30536 throw new MpdfException('Error in _invertColor - trying to invert non-RGB color');
30537 }
30538
30539 function _colAtoString($cor)
30540 {
30541 $s = '';
30542 if ($cor[0] == 1)
30543 $s = 'rgb(' . ord($cor[1]) . ',' . ord($cor[1]) . ',' . ord($cor[1]) . ')';
30544 elseif ($cor[0] == 2)
30545 $s = 'spot(' . ord($cor[1]) . ',' . ord($cor[2]) . ')'; // SPOT COLOR
30546 elseif ($cor[0] == 3)
30547 $s = 'rgb(' . ord($cor[1]) . ',' . ord($cor[2]) . ',' . ord($cor[3]) . ')';
30548 elseif ($cor[0] == 4)
30549 $s = 'cmyk(' . ord($cor[1]) . ',' . ord($cor[2]) . ',' . ord($cor[3]) . ',' . ord($cor[4]) . ')';
30550 elseif ($cor[0] == 5)
30551 $s = 'rgba(' . ord($cor[1]) . ',' . ord($cor[2]) . ',' . ord($cor[3]) . ',' . sprintf('%0.2F', ord($cor[4]) / 100) . ')';
30552 elseif ($cor[0] == 6)
30553 $s = 'cmyka(' . ord($cor[1]) . ',' . ord($cor[2]) . ',' . ord($cor[3]) . ',' . ord($cor[4]) . ',' . sprintf('%0.2F', ord($cor[5]) / 100) . ')';
30554 return $s;
30555 }
30556
30557 function ConvertSize($size = 5, $maxsize = 0, $fontsize = false, $usefontsize = true)
30558 {
30559 // usefontsize - set false for e.g. margins - will ignore fontsize for % values
30560 // Depends of maxsize value to make % work properly. Usually maxsize == pagewidth
30561 // For text $maxsize = Fontsize
30562 // Setting e.g. margin % will use maxsize (pagewidth) and em will use fontsize
30563 // Returns values using 'mm' units
30564 $size = trim(strtolower($size));
30565
30566 if ($size == 'thin')
30567 $size = 1 * (25.4 / $this->dpi); //1 pixel width for table borders
30568 elseif (stristr($size, 'px'))
30569 $size *= (25.4 / $this->dpi); //pixels
30570 elseif (stristr($size, 'cm'))
30571 $size *= 10; //centimeters
30572 elseif (stristr($size, 'mm'))
30573 $size += 0; //millimeters
30574 elseif (stristr($size, 'pt'))
30575 $size *= 25.4 / 72; //72 pts/inch
30576 elseif (stristr($size, 'rem')) {
30577 $size += 0; //make "0.83rem" become simply "0.83"
30578 $size *= ($this->default_font_size / _MPDFK);
30579 } elseif (stristr($size, 'em')) {
30580 $size += 0; //make "0.83em" become simply "0.83"
30581 if ($fontsize) {
30582 $size *= $fontsize;
30583 } else {
30584 $size *= $maxsize;
30585 }
30586 } elseif (stristr($size, '%')) {
30587 $size += 0; //make "90%" become simply "90"
30588 if ($fontsize && $usefontsize) {
30589 $size *= $fontsize / 100;
30590 } else {
30591 $size *= $maxsize / 100;
30592 }
30593 } elseif (stristr($size, 'in'))
30594 $size *= 25.4; //inches
30595 elseif (stristr($size, 'pc'))
30596 $size *= 38.1 / 9; //PostScript picas
30597 elseif (stristr($size, 'ex')) { // Approximates "ex" as half of font height
30598 $size += 0; //make "3.5ex" become simply "3.5"
30599 if ($fontsize) {
30600 $size *= $fontsize / 2;
30601 } else {
30602 $size *= $maxsize / 2;
30603 }
30604 } elseif ($size == 'medium')
30605 $size = 3 * (25.4 / $this->dpi); //3 pixel width for table borders
30606 elseif ($size == 'thick')
30607 $size = 5 * (25.4 / $this->dpi); //5 pixel width for table borders
30608 elseif ($size == 'xx-small') {
30609 if ($fontsize) {
30610 $size *= $fontsize * 0.7;
30611 } else {
30612 $size *= $maxsize * 0.7;
30613 }
30614 } elseif ($size == 'x-small') {
30615 if ($fontsize) {
30616 $size *= $fontsize * 0.77;
30617 } else {
30618 $size *= $maxsize * 0.77;
30619 }
30620 } elseif ($size == 'small') {
30621 if ($fontsize) {
30622 $size *= $fontsize * 0.86;
30623 } else {
30624 $size *= $maxsize * 0.86;
30625 }
30626 } elseif ($size == 'medium') {
30627 if ($fontsize) {
30628 $size *= $fontsize;
30629 } else {
30630 $size *= $maxsize;
30631 }
30632 } elseif ($size == 'large') {
30633 if ($fontsize) {
30634 $size *= $fontsize * 1.2;
30635 } else {
30636 $size *= $maxsize * 1.2;
30637 }
30638 } elseif ($size == 'x-large') {
30639 if ($fontsize) {
30640 $size *= $fontsize * 1.5;
30641 } else {
30642 $size *= $maxsize * 1.5;
30643 }
30644 } elseif ($size == 'xx-large') {
30645 if ($fontsize) {
30646 $size *= $fontsize * 2;
30647 } else {
30648 $size *= $maxsize * 2;
30649 }
30650 } else {
30651 @$size *= (25.4 / $this->dpi);
30652 }
30653
30654 return $size;
30655 }
30656
30657 // mPDF 5.7.3 TRANSFORMS
30658 function ConvertAngle($s, $makepositive = true)
30659 {
30660 if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i', $s, $m)) {
30661 $angle = $m[1] + 0;
30662 if (strtolower($m[2]) == 'deg') {
30663 $angle = $angle;
30664 } elseif (strtolower($m[2]) == 'grad') {
30665 $angle *= (360 / 400);
30666 } elseif (strtolower($m[2]) == 'rad') {
30667 $angle = rad2deg($angle);
30668 }
30669 while ($angle >= 360) {
30670 $angle -= 360;
30671 }
30672 while ($angle <= -360) {
30673 $angle += 360;
30674 }
30675 if ($makepositive) { // always returns an angle between 0 and 360deg
30676 if ($angle < 0) {
30677 $angle += 360;
30678 }
30679 }
30680 } else {
30681 $angle = $s + 0;
30682 }
30683 return $angle;
30684 }
30685
30686 function lesser_entity_decode($html)
30687 {
30688 //supports the most used entity codes (only does ascii safe characters)
30689 $html = str_replace("&lt;", "<", $html);
30690 $html = str_replace("&gt;", ">", $html);
30691
30692 $html = str_replace("&apos;", "'", $html);
30693 $html = str_replace("&quot;", '"', $html);
30694 $html = str_replace("&amp;", "&", $html);
30695 return $html;
30696 }
30697
30698 function AdjustHTML($html, $tabSpaces = 8)
30699 {
30700 //Try to make the html text more manageable (turning it into XHTML)
30701 if (PHP_VERSION_ID < 50307) {
30702 if (strlen($html) > 100000) {
30703 if (PHP_VERSION_ID < 50200)
30704 throw new MpdfException("The HTML code is more than 100,000 characters. You should use WriteHTML() with smaller string lengths.");
30705 else
30706 ini_set("pcre.backtrack_limit", "1000000");
30707 }
30708 }
30709
30710 /* -- ANNOTATIONS -- */
30711 preg_match_all("/(<annotation.*?>)/si", $html, $m);
30712 if (count($m[1])) {
30713 for ($i = 0; $i < count($m[1]); $i++) {
30714 $sub = preg_replace("/\n/si", "\xbb\xa4\xac", $m[1][$i]);
30715 $html = preg_replace('/' . preg_quote($m[1][$i], '/') . '/si', $sub, $html);
30716 }
30717 }
30718 /* -- END ANNOTATIONS -- */
30719
30720 preg_match_all("/(<svg.*?<\/svg>)/si", $html, $svgi);
30721 if (count($svgi[0])) {
30722 for ($i = 0; $i < count($svgi[0]); $i++) {
30723 $file = _MPDF_TEMP_PATH . '_tempSVG' . uniqid(rand(1, 100000), true) . '_' . $i . '.svg';
30724 //Save to local file
30725 file_put_contents($file, $svgi[0][$i]);
30726 $html = str_replace($svgi[0][$i], '<img src="' . $file . '" />', $html);
30727 }
30728 }
30729
30730 //Remove javascript code from HTML (should not appear in the PDF file)
30731 $html = preg_replace('/<script.*?<\/script>/is', '', $html);
30732
30733 //Remove special comments
30734 $html = preg_replace('/<!--mpdf/i', '', $html);
30735 $html = preg_replace('/mpdf-->/i', '', $html);
30736
30737 //Remove comments from HTML (should not appear in the PDF file)
30738 $html = preg_replace('/<!--.*?-->/s', '', $html);
30739
30740 $html = preg_replace('/\f/', '', $html); //replace formfeed by nothing
30741 $html = preg_replace('/\r/', '', $html); //replace carriage return by nothing
30742 // Well formed XHTML end tags
30743 $html = preg_replace('/<(br|hr)>/i', "<\\1 />", $html); // mPDF 6
30744 $html = preg_replace('/<(br|hr)\/>/i', "<\\1 />", $html);
30745 // Get rid of empty <thead></thead> etc
30746 $html = preg_replace('/<tr>\s*<\/tr>/i', '', $html);
30747 $html = preg_replace('/<thead>\s*<\/thead>/i', '', $html);
30748 $html = preg_replace('/<tfoot>\s*<\/tfoot>/i', '', $html);
30749 $html = preg_replace('/<table[^>]*>\s*<\/table>/i', '', $html);
30750
30751 // Remove spaces at end of table cells
30752 $html = preg_replace("/[ \n\r]+<\/t(d|h)/", '</t\\1', $html);
30753
30754 $html = preg_replace("/[ ]*<dottab\s*[\/]*>[ ]*/", '<dottab />', $html);
30755
30756 // Concatenates any Substitute characters from symbols/dingbats
30757 $html = str_replace('</tts><tts>', '|', $html);
30758 $html = str_replace('</ttz><ttz>', '|', $html);
30759 $html = str_replace('</tta><tta>', '|', $html);
30760
30761 $html = preg_replace('/<br \/>\s*/is', "<br />", $html);
30762
30763 $html = preg_replace('/<wbr[ \/]*>\s*/is', "&#173;", $html);
30764
30765 // Preserve '\n's in content between the tags <pre> and </pre>
30766 if (preg_match('/<pre/', $html)) {
30767 $html_a = preg_split('/(\<\/?pre[^\>]*\>)/', $html, -1, 2);
30768 $h = array();
30769 $c = 0;
30770 foreach ($html_a AS $s) {
30771 if ($c > 1 && preg_match('/^<\/pre/i', $s)) {
30772 $c--;
30773 $s = preg_replace('/<\/pre/i', '</innerpre', $s);
30774 } elseif ($c > 0 && preg_match('/^<pre/i', $s)) {
30775 $c++;
30776 $s = preg_replace('/<pre/i', '<innerpre', $s);
30777 } elseif (preg_match('/^<pre/i', $s)) {
30778 $c++;
30779 } elseif (preg_match('/^<\/pre/i', $s)) {
30780 $c--;
30781 }
30782 array_push($h, $s);
30783 }
30784 $html = implode("", $h);
30785 }
30786 $thereispre = preg_match_all('#<pre(.*?)>(.*?)</pre>#si', $html, $temp);
30787 // Preserve '\n's in content between the tags <textarea> and </textarea>
30788 $thereistextarea = preg_match_all('#<textarea(.*?)>(.*?)</textarea>#si', $html, $temp2);
30789 $html = preg_replace('/[\n]/', ' ', $html); //replace linefeed by spaces
30790 $html = preg_replace('/[\t]/', ' ', $html); //replace tabs by spaces
30791 // Converts < to &lt; when not a tag
30792 $html = preg_replace('/<([^!\/a-zA-Z_:])/i', '&lt;\\1', $html); // mPDF 5.7.3
30793 $html = preg_replace("/[ ]+/", ' ', $html);
30794
30795 $html = preg_replace('/\/li>\s+<\/(u|o)l/i', '/li></\\1l', $html);
30796 $html = preg_replace('/\/(u|o)l>\s+<\/li/i', '/\\1l></li', $html);
30797 $html = preg_replace('/\/li>\s+<\/(u|o)l/i', '/li></\\1l', $html);
30798 $html = preg_replace('/\/li>\s+<li/i', '/li><li', $html);
30799 $html = preg_replace('/<(u|o)l([^>]*)>[ ]+/i', '<\\1l\\2>', $html);
30800 $html = preg_replace('/[ ]+<(u|o)l/i', '<\\1l', $html);
30801
30802 // Make self closing tabs valid XHTML
30803 // Tags which are self-closing: 1) Replaceable and 2) Non-replaced items
30804 $selftabs = 'input|hr|img|br|jpgraph|barcode|dottab';
30805 $selftabs2 = 'indexentry|indexinsert|bookmark|watermarktext|watermarkimage|column_break|columnbreak|newcolumn|newpage|page_break|pagebreak|formfeed|columns|toc|tocpagebreak|setpageheader|setpagefooter|sethtmlpageheader|sethtmlpagefooter|annotation';
30806 $html = preg_replace('/(<(' . $selftabs . '|' . $selftabs2 . ')[^>\/]*)>/i', '\\1 />', $html);
30807
30808 $iterator = 0;
30809 while ($thereispre) { //Recover <pre attributes>content</pre>
30810 $temp[2][$iterator] = preg_replace('/<([^!\/a-zA-Z_:])/', '&lt;\\1', $temp[2][$iterator]); // mPDF 5.7.2 // mPDF 5.7.3
30811
30812 $temp[2][$iterator] = preg_replace_callback("/^([^\n\t]*?)\t/m", array($this, 'tabs2spaces_callback'), $temp[2][$iterator]); // mPDF 5.7+
30813 $temp[2][$iterator] = preg_replace('/\t/', str_repeat(" ", $tabSpaces), $temp[2][$iterator]);
30814
30815 $temp[2][$iterator] = preg_replace('/\n/', "<br />", $temp[2][$iterator]);
30816 $temp[2][$iterator] = str_replace('\\', "\\\\", $temp[2][$iterator]);
30817 //$html = preg_replace('#<pre(.*?)>(.*?)</pre>#si','<erp'.$temp[1][$iterator].'>'.$temp[2][$iterator].'</erp>',$html,1);
30818 $html = preg_replace('#<pre(.*?)>(.*?)</pre>#si', '<erp' . $temp[1][$iterator] . '>' . str_replace('$', '\$', $temp[2][$iterator]) . '</erp>', $html, 1); // mPDF 5.7+
30819 $thereispre--;
30820 $iterator++;
30821 }
30822 $iterator = 0;
30823 while ($thereistextarea) { //Recover <textarea attributes>content</textarea>
30824 $temp2[2][$iterator] = preg_replace('/\t/', str_repeat(" ", $tabSpaces), $temp2[2][$iterator]);
30825 $temp2[2][$iterator] = str_replace('\\', "\\\\", $temp2[2][$iterator]);
30826 $html = preg_replace('#<textarea(.*?)>(.*?)</textarea>#si', '<aeratxet' . $temp2[1][$iterator] . '>' . trim($temp2[2][$iterator]) . '</aeratxet>', $html, 1);
30827 $thereistextarea--;
30828 $iterator++;
30829 }
30830 //Restore original tag names
30831 $html = str_replace("<erp", "<pre", $html);
30832 $html = str_replace("</erp>", "</pre>", $html);
30833 $html = str_replace("<aeratxet", "<textarea", $html);
30834 $html = str_replace("</aeratxet>", "</textarea>", $html);
30835 $html = str_replace("</innerpre", "</pre", $html);
30836 $html = str_replace("<innerpre", "<pre", $html);
30837
30838 $html = preg_replace('/<textarea([^>]*)><\/textarea>/si', '<textarea\\1> </textarea>', $html);
30839 $html = preg_replace('/(<table[^>]*>)\s*(<caption)(.*?<\/caption>)(.*?<\/table>)/si', '\\2 position="top"\\3\\1\\4\\2 position="bottom"\\3', $html); // *TABLES*
30840 $html = preg_replace('/<(h[1-6])([^>]*)(>(?:(?!h[1-6]).)*?<\/\\1>\s*<table)/si', '<\\1\\2 keep-with-table="1"\\3', $html); // *TABLES*
30841 $html = preg_replace("/\xbb\xa4\xac/", "\n", $html);
30842
30843 // Fixes <p>&#8377</p> which browser copes with even though it is wrong!
30844 $html = preg_replace("/(&#[x]{0,1}[0-9a-f]{1,5})</i", "\\1;<", $html);
30845 return $html;
30846 }
30847
30848 // mPDF 5.7+
30849 function tabs2spaces_callback($matches)
30850 {
30851 return (stripslashes($matches[1]) . str_repeat(' ', $this->tabSpaces - (mb_strlen(stripslashes($matches[1])) % $this->tabSpaces)));
30852 }
30853
30854 // mPDF 5.7+
30855 function date_callback($matches)
30856 {
30857 return date($matches[1]);
30858 }
30859
30860 function dec2other($num, $cp, $check = true)
30861 {
30862 // From printlistbuffer: font is set, so check if character is available
30863 // From docPageNum: font is not set, so no check
30864 $nstr = (string) $num;
30865 $rnum = '';
30866 for ($i = 0; $i < strlen($nstr); $i++) {
30867 if (!$check || $this->_charDefined($this->CurrentFont['cw'], $cp + intval($nstr[$i]))) {
30868 $rnum .= code2utf($cp + intval($nstr[$i]));
30869 } else {
30870 $rnum .= $nstr[$i];
30871 }
30872 }
30873 return $rnum;
30874 }
30875
30876 function dec2cjk($num)
30877 {
30878 $nstr = (string) $num;
30879 $rnum = '';
30880 $glyphs = array(0x3007, 0x4E00, 0x4E8C, 0x4E09, 0x56DB, 0x4E94, 0x516D, 0x4E03, 0x516B, 0x4E5D);
30881 for ($i = 0; $i < strlen($nstr); $i++) {
30882 $rnum .= code2utf($glyphs[intval($nstr[$i])]);
30883 }
30884 return $rnum;
30885 }
30886
30887 function dec2alpha($valor, $toupper = "true")
30888 {
30889 // returns a string from A-Z to AA-ZZ to AAA-ZZZ
30890 // OBS: A = 65 ASCII TABLE VALUE
30891 if (($valor < 1) || ($valor > 18278))
30892 return "?"; //supports 'only' up to 18278
30893 $c1 = $c2 = $c3 = '';
30894 if ($valor > 702) { // 3 letters (up to 18278)
30895 $c1 = 65 + floor(($valor - 703) / 676);
30896 $c2 = 65 + floor((($valor - 703) % 676) / 26);
30897 $c3 = 65 + floor((($valor - 703) % 676) % 26);
30898 } elseif ($valor > 26) { // 2 letters (up to 702)
30899 $c1 = (64 + (int) (($valor - 1) / 26));
30900 $c2 = (64 + (int) ($valor % 26));
30901 if ($c2 == 64)
30902 $c2 += 26;
30903 }
30904 else { // 1 letter (up to 26)
30905 $c1 = (64 + $valor);
30906 }
30907 $alpha = chr($c1);
30908 if ($c2 != '')
30909 $alpha .= chr($c2);
30910 if ($c3 != '')
30911 $alpha .= chr($c3);
30912 if (!$toupper)
30913 $alpha = strtolower($alpha);
30914 return $alpha;
30915 }
30916
30917 // mPDF 6
30918 function dec2hebrew($in, $reverse = false)
30919 {
30920 // reverse is used when called from Lists, as these do not pass through bidi-algorithm
30921 $i = intval($in); // I initially be the counter value
30922 $s = ''; // S initially be the empty string
30923 //and glyph list initially be the list of additive tuples.
30924 $additive_nums = array(400, 300, 200, 100, 90, 80, 70, 60, 50, 40, 30, 20, 19, 18, 17, 16, 15, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1);
30925 $additive_glyphs = array(0x05EA, 0x05E9, 0x05E8, 0x05E7, 0x05E6, 0x05E4, 0x05E2, 0x05E1, 0x05E0, 0x05DE, 0x05DC, 0x05DB,
30926 array(0x05D9, 0x05D8), array(0x05D9, 0x05D7), array(0x05D9, 0x05D6), array(0x05D8, 0x05D6), array(0x05D8, 0x05D5), 0x05D9,
30927 0x05D8, 0x05D7, 0x05D6, 0x05D5, 0x05D4, 0x05D3, 0x05D2, 0x05D1, 0x05D0);
30928 /* NB This system manually specifies the values for 19-15 to force the correct display of 15 and 16, which are commonly
30929 rewritten to avoid a close resemblance to the Tetragrammaton. */
30930 // This function only works up to 1,000
30931 if ($i > 999) {
30932 return $in;
30933 } // return as initial numeric string
30934 // If I is initially 0, and there is an additive tuple with a weight of 0, append that tuple's counter glyph to S and return S.
30935 if ($i == 0) {
30936 return '0';
30937 }
30938
30939 // Otherwise, while I is greater than 0 and there are elements left in the glyph list:
30940 for ($t = 0; $t < count($additive_nums); $t++) {
30941
30942 // Pop the first additive tuple from the glyph list. This is the current tuple.
30943 $ct = $additive_nums[$t];
30944 // Append the current tuple's counter glyph to S x floor( I / current tuple's weight ) times (this may be 0).
30945 $n = floor($i / $ct);
30946 for ($j = 0; $j < $n; $j++) {
30947 if (is_array($additive_glyphs[$t])) {
30948 foreach ($additive_glyphs[$t] AS $ag) {
30949 if ($reverse) {
30950 $s = code2utf($ag) . $s;
30951 } else {
30952 $s .= code2utf($ag);
30953 }
30954 }
30955 } else {
30956 if ($reverse) {
30957 $s = code2utf($additive_glyphs[$t]) . $s;
30958 } else {
30959 $s .= code2utf($additive_glyphs[$t]);
30960 }
30961 }
30962 $i -= ($ct * $n);
30963 }
30964 if ($i == 0) {
30965 return $s;
30966 }
30967 }
30968 return $in; // return as initial string
30969 }
30970
30971 function dec2roman($valor, $toupper = true)
30972 {
30973 //returns a string as a roman numeral
30974 $r1 = $r2 = $r3 = $r4 = '';
30975 if (($valor >= 5000) || ($valor < 1))
30976 return "?"; //supports 'only' up to 4999
30977 $aux = (int) ($valor / 1000);
30978 if ($aux !== 0) {
30979 $valor %= 1000;
30980 while ($aux !== 0) {
30981 $r1 .= "M";
30982 $aux--;
30983 }
30984 }
30985 $aux = (int) ($valor / 100);
30986 if ($aux !== 0) {
30987 $valor %= 100;
30988 switch ($aux) {
30989 case 3: $r2 = "C";
30990 case 2: $r2.="C";
30991 case 1: $r2.="C";
30992 break;
30993 case 9: $r2 = "CM";
30994 break;
30995 case 8: $r2 = "C";
30996 case 7: $r2.="C";
30997 case 6: $r2.="C";
30998 case 5: $r2 = "D" . $r2;
30999 break;
31000 case 4: $r2 = "CD";
31001 break;
31002 default: break;
31003 }
31004 }
31005 $aux = (int) ($valor / 10);
31006 if ($aux !== 0) {
31007 $valor %= 10;
31008 switch ($aux) {
31009 case 3: $r3 = "X";
31010 case 2: $r3.="X";
31011 case 1: $r3.="X";
31012 break;
31013 case 9: $r3 = "XC";
31014 break;
31015 case 8: $r3 = "X";
31016 case 7: $r3.="X";
31017 case 6: $r3.="X";
31018 case 5: $r3 = "L" . $r3;
31019 break;
31020 case 4: $r3 = "XL";
31021 break;
31022 default: break;
31023 }
31024 }
31025 switch ($valor) {
31026 case 3: $r4 = "I";
31027 case 2: $r4.="I";
31028 case 1: $r4.="I";
31029 break;
31030 case 9: $r4 = "IX";
31031 break;
31032 case 8: $r4 = "I";
31033 case 7: $r4.="I";
31034 case 6: $r4.="I";
31035 case 5: $r4 = "V" . $r4;
31036 break;
31037 case 4: $r4 = "IV";
31038 break;
31039 default: break;
31040 }
31041 $roman = $r1 . $r2 . $r3 . $r4;
31042 if (!$toupper)
31043 $roman = strtolower($roman);
31044 return $roman;
31045 }
31046
31047 //===========================
31048 /* -- IMPORTS -- */
31049 function SetImportUse()
31050 {
31051 if (!class_exists('fpdi_pdf_parser')) {
31052 throw new MpdfException('Class fpdi_pdf_parser not found. Please run composer update or require setasign/fpdi 1.6.* manually');
31053 }
31054
31055 $this->enableImports = true;
31056 }
31057
31058 // from mPDFI
31059 function hex2str($hex)
31060 {
31061 return pack("H*", str_replace(array("\r", "\n", " "), "", $hex));
31062 }
31063
31064 function str2hex($str)
31065 {
31066 return current(unpack("H*", $str));
31067 }
31068
31069 function pdf_write_value(&$value)
31070 {
31071 switch ($value[0]) {
31072
31073 case pdf_parser::TYPE_TOKEN:
31074 $this->_out($value[1] . ' ', false);
31075 break;
31076
31077 case pdf_parser::TYPE_NUMERIC:
31078 case pdf_parser::TYPE_REAL:
31079 if (is_float($value[1]) && $value[1] != 0) {
31080 $this->_out(rtrim(rtrim(sprintf('%F', $value[1]), '0'), '.') . ' ', false);
31081 } else {
31082 $this->_out($value[1] . ' ', false);
31083 }
31084 break;
31085
31086 case pdf_parser::TYPE_ARRAY :
31087 // An array. Output the proper
31088 // structure and move on.
31089 $this->_out("[", false);
31090 for ($i = 0; $i < count($value[1]); $i++) {
31091 $this->pdf_write_value($value[1][$i]);
31092 }
31093 $this->_out("]");
31094 break;
31095
31096 case pdf_parser::TYPE_DICTIONARY :
31097 // A dictionary.
31098 $this->_out("<<", false);
31099 reset($value[1]);
31100 while (list($k, $v) = each($value[1])) {
31101 $this->_out($k . ' ',false);
31102 $this->pdf_write_value($v);
31103 }
31104 $this->_out(">>");
31105 break;
31106
31107 case pdf_parser::TYPE_OBJREF :
31108 // An indirect object reference
31109 // Fill the object stack if needed
31110 $cpfn = $this->current_parser->filename;
31111 if (!isset($this->_don_obj_stack[$cpfn][$value[1]])) {
31112 $this->_newobj(false, true);
31113 $this->_obj_stack[$cpfn][$value[1]] = array($this->n, $value);
31114 $this->_don_obj_stack[$cpfn][$value[1]] = array($this->n, $value);
31115 }
31116 $objid = $this->_don_obj_stack[$cpfn][$value[1]][0];
31117 $this->_out($objid . ' 0 R'); //{$value[2]}
31118 break;
31119
31120 case pdf_parser::TYPE_STRING :
31121 if ($this->encrypted) {
31122 $value[1] = $this->_RC4($this->_objectkey($this->_current_obj_id), $value[1]);
31123 $value[1] = $this->_escape($value[1]);
31124 }
31125 // A string.
31126 $this->_out('(' . $value[1] . ')');
31127 break;
31128
31129 case pdf_parser::TYPE_STREAM :
31130 // A stream. First, output the
31131 // stream dictionary, then the
31132 // stream data itself.
31133 $this->pdf_write_value($value[1]);
31134 if ($this->encrypted) {
31135 $value[2][1] = $this->_RC4($this->_objectkey($this->_current_obj_id), $value[2][1]);
31136 }
31137 $this->_out("stream");
31138 $this->_out($value[2][1]);
31139 $this->_out("endstream");
31140 break;
31141
31142 case pdf_parser::TYPE_HEX :
31143 if ($this->encrypted) {
31144 $value[1] = $this->hex2str($value[1]);
31145 $value[1] = $this->_RC4($this->_objectkey($this->_current_obj_id), $value[1]);
31146 // remake hexstring of encrypted string
31147 $value[1] = $this->str2hex($value[1]);
31148 }
31149 $this->_out("<" . $value[1] . ">");
31150 break;
31151
31152 case pdf_parser::TYPE_BOOLEAN :
31153 $this->_out($value[1] ? 'true' : 'false');
31154 break;
31155
31156 case pdf_parser::TYPE_NULL :
31157 // The null object.
31158 $this->_out("null");
31159 break;
31160
31161 }
31162 }
31163
31164 // ========== OVERWRITE SEARCH STRING IN A PDF FILE ================
31165 function OverWrite($file_in, $search, $replacement, $dest = "D", $file_out = "mpdf")
31166 {
31167 $pdf = file_get_contents($file_in);
31168
31169 if (!is_array($search)) {
31170 $x = $search;
31171 $search = array($x);
31172 }
31173 if (!is_array($replacement)) {
31174 $x = $replacement;
31175 $replacement = array($x); // mPDF 5.7.4
31176 }
31177
31178 if (!$this->onlyCoreFonts && !$this->usingCoreFont) {
31179 foreach ($search AS $k => $val) {
31180 $search[$k] = $this->UTF8ToUTF16BE($search[$k], false);
31181 $search[$k] = $this->_escape($search[$k]);
31182 $replacement[$k] = $this->UTF8ToUTF16BE($replacement[$k], false);
31183 $replacement[$k] = $this->_escape($replacement[$k]);
31184 }
31185 } else {
31186 foreach ($replacement AS $k => $val) {
31187 $replacement[$k] = mb_convert_encoding($replacement[$k], $this->mb_enc, 'utf-8');
31188 $replacement[$k] = $this->_escape($replacement[$k]);
31189 }
31190 }
31191
31192 // Get xref into array
31193 $xref = array();
31194 preg_match("/xref\n0 (\d+)\n(.*?)\ntrailer/s", $pdf, $m);
31195 $xref_objid = $m[1];
31196 preg_match_all('/(\d{10}) (\d{5}) (f|n)/', $m[2], $x);
31197 for ($i = 0; $i < count($x[0]); $i++) {
31198 $xref[] = array(intval($x[1][$i]), $x[2][$i], $x[3][$i]);
31199 }
31200
31201 $changes = array();
31202 preg_match("/<<\s*\/Type\s*\/Pages\s*\/Kids\s*\[(.*?)\]\s*\/Count/s", $pdf, $m);
31203 preg_match_all("/(\d+) 0 R /s", $m[1], $o);
31204 $objlist = $o[1];
31205 foreach ($objlist AS $obj) {
31206 if ($this->compress) {
31207 preg_match("/" . ($obj + 1) . " 0 obj\n<<\s*\/Filter\s*\/FlateDecode\s*\/Length (\d+)>>\nstream\n(.*?)\nendstream\n/s", $pdf, $m);
31208 } else {
31209 preg_match("/" . ($obj + 1) . " 0 obj\n<<\s*\/Length (\d+)>>\nstream\n(.*?)\nendstream\n/s", $pdf, $m);
31210 }
31211 $s = $m[2];
31212 if (!$s) {
31213 continue;
31214 }
31215 $oldlen = $m[1];
31216 if ($this->encrypted) {
31217 $s = $this->_RC4($this->_objectkey($obj + 1), $s);
31218 }
31219 if ($this->compress) {
31220 $s = gzuncompress($s);
31221 }
31222 foreach ($search AS $k => $val) {
31223 $s = str_replace($search[$k], $replacement[$k], $s);
31224 }
31225 if ($this->compress) {
31226 $s = gzcompress($s);
31227 }
31228 if ($this->encrypted) {
31229 $s = $this->_RC4($this->_objectkey($obj + 1), $s);
31230 }
31231 $newlen = strlen($s);
31232 $changes[($xref[$obj + 1][0])] = ($newlen - $oldlen) + (strlen($newlen) - strlen($oldlen));
31233 if ($this->compress) {
31234 $newstr = ($obj + 1) . " 0 obj\n<</Filter /FlateDecode /Length " . $newlen . ">>\nstream\n" . $s . "\nendstream\n";
31235 } else {
31236 $newstr = ($obj + 1) . " 0 obj\n<</Length " . $newlen . ">>\nstream\n" . $s . "\nendstream\n";
31237 }
31238 $pdf = str_replace($m[0], $newstr, $pdf);
31239 }
31240
31241 // Update xref in PDF
31242 krsort($changes);
31243 $newxref = "xref\n0 " . $xref_objid . "\n";
31244 foreach ($xref AS $v) {
31245 foreach ($changes AS $ck => $cv) {
31246 if ($v[0] > $ck) {
31247 $v[0] += $cv;
31248 }
31249 }
31250 $newxref .= sprintf('%010d', $v[0]) . ' ' . $v[1] . ' ' . $v[2] . " \n";
31251 }
31252 $newxref .= "trailer";
31253 $pdf = preg_replace("/xref\n0 \d+\n.*?\ntrailer/s", $newxref, $pdf);
31254
31255 // Update startxref in PDF
31256 preg_match("/startxref\n(\d+)\n%%EOF/s", $pdf, $m);
31257 $startxref = $m[1];
31258 $startxref += array_sum($changes);
31259 $pdf = preg_replace("/startxref\n(\d+)\n%%EOF/s", "startxref\n" . $startxref . "\n%%EOF", $pdf);
31260
31261 // OUTPUT
31262 switch ($dest) {
31263 case 'I':
31264 //Send to standard output
31265 if (isset($_SERVER['SERVER_NAME'])) {
31266 //We send to a browser
31267 Header('Content-Type: application/pdf');
31268 Header('Content-Length: ' . strlen($pdf));
31269 Header('Content-disposition: inline; filename=' . $file_out);
31270 }
31271 echo $pdf;
31272 break;
31273 case 'F':
31274 //Save to local file
31275 if (!$file_out) {
31276 $file_out = 'mpdf.pdf';
31277 }
31278 $f = fopen($file_out, 'wb');
31279 if (!$f)
31280 throw new MpdfException('Unable to create output file: ' . $file_out);
31281 fwrite($f, $pdf, strlen($pdf));
31282 fclose($f);
31283 break;
31284 case 'S':
31285 //Return as a string
31286 return $pdf;
31287 case 'D':
31288 default:
31289 //Download file
31290 if (isset($_SERVER['HTTP_USER_AGENT']) and strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE'))
31291 Header('Content-Type: application/force-download');
31292 else
31293 Header('Content-Type: application/octet-stream');
31294 Header('Content-Length: ' . strlen($pdf));
31295 Header('Content-disposition: attachment; filename=' . $file_out);
31296 echo $pdf;
31297 break;
31298 }
31299 }
31300
31301 function GetTemplateSize($tplidx, $_w = 0, $_h = 0)
31302 {
31303 if (!$this->tpls[$tplidx])
31304 return false;
31305 $w = $this->tpls[$tplidx]['box']['w'];
31306 $h = $this->tpls[$tplidx]['box']['h'];
31307 if ($_w == 0 and $_h == 0) {
31308 $_w = $w;
31309 $_h = $h;
31310 }
31311 if ($_w == 0)
31312 $_w = $_h * $w / $h;
31313 if ($_h == 0)
31314 $_h = $_w * $h / $w;
31315 return array("w" => $_w, "h" => $_h);
31316 }
31317
31318
31319 function Thumbnail($file, $npr = 3, $spacing = 10)
31320 {
31321 //$npr = number per row
31322 $w = (($this->pgwidth + $spacing) / $npr) - $spacing;
31323 $oldlinewidth = $this->LineWidth;
31324 $this->SetLineWidth(0.02);
31325 $this->SetDColor($this->ConvertColor(0));
31326 $h = 0;
31327 $maxh = 0;
31328 $x = $_x = $this->lMargin;
31329 $_y = $this->tMargin;
31330
31331 if ($this->y == 0) {
31332 $y = $_y;
31333 } else {
31334 $y = $this->y;
31335 }
31336
31337 $pagecount = $this->SetSourceFile($file);
31338
31339 for ($n = 1; $n <= $pagecount; $n++) {
31340 $tplidx = $this->ImportPage($n);
31341 $size = $this->useTemplate($tplidx, $x, $y, $w);
31342 $this->Rect($x, $y, $size['w'], $size['h']);
31343 $h = max($h, $size['h']);
31344 $maxh = max($h, $maxh);
31345
31346 if ($n % $npr == 0) {
31347 if (($y + $h + $spacing + $maxh) > $this->PageBreakTrigger && $n != $pagecount) {
31348 $this->AddPage();
31349 $x = $_x;
31350 $y = $_y;
31351 } else {
31352 $y += $h + $spacing;
31353 $x = $_x;
31354 $h = 0;
31355 }
31356 } else {
31357 $x += $w + $spacing;
31358 }
31359 }
31360 $this->SetLineWidth($oldlinewidth);
31361 }
31362
31363 function SetSourceFile($filename)
31364 {
31365 $this->current_filename = $filename;
31366 $fn = $this->current_filename;
31367 if (!isset($this->parsers[$fn])) {
31368 // $this->parsers[$fn] =& new fpdi_pdf_parser($fn,$this);
31369 try {
31370 $this->parsers[$fn] = new fpdi_pdf_parser($fn, $this);
31371 } catch (Exception $e) {
31372 throw new MpdfException($e->getMessage()); // Delete this line to return false on fail
31373 return false;
31374 }
31375 }
31376
31377 $this->current_parser = $this->parsers[$fn];
31378 return $this->parsers[$fn]->getPageCount();
31379 }
31380
31381 function ImportPage($pageno = 1, $crop_x = null, $crop_y = null, $crop_w = 0, $crop_h = 0, $boxName = '/CropBox')
31382 {
31383 $fn = $this->current_filename;
31384 $parser = $this->parsers[$fn];
31385 $parser->setPageno($pageno);
31386
31387 $this->tpl++;
31388 $this->tpls[$this->tpl] = array();
31389 $tpl = & $this->tpls[$this->tpl];
31390 $tpl['parser'] = $parser;
31391 $tpl['resources'] = $parser->getPageResources();
31392 $tpl['buffer'] = $parser->getContent();
31393
31394 if (!in_array($boxName, $parser->availableBoxes)) {
31395 throw new MpdfException(sprintf("Unknown box: %s", $boxName));
31396 }
31397
31398 $pageboxes = $parser->getPageBoxes($pageno, _MPDFK);
31399
31400 /**
31401 * MediaBox
31402 * CropBox: Default -> MediaBox
31403 * BleedBox: Default -> CropBox
31404 * TrimBox: Default -> CropBox
31405 * ArtBox: Default -> CropBox
31406 */
31407 if (!isset($pageboxes[$boxName]) && ($boxName == "/BleedBox" || $boxName == "/TrimBox" || $boxName == "/ArtBox")) {
31408 $boxName = "/CropBox";
31409 }
31410
31411 if (!isset($pageboxes[$boxName]) && $boxName == "/CropBox") {
31412 $boxName = "/MediaBox";
31413 }
31414
31415 if (!isset($pageboxes[$boxName])) {
31416 return false;
31417 }
31418
31419 $box = $pageboxes[$boxName];
31420
31421 $tpl['box'] = $box;
31422 // To build an array that can be used by useTemplate()
31423 $this->tpls[$this->tpl] = array_merge($this->tpls[$this->tpl], $box);
31424 // An imported page will start at 0,0 everytime. Translation will be set in _putformxobjects()
31425 $tpl['x'] = 0;
31426 $tpl['y'] = 0;
31427 $tpl['w'] = $tpl['box']['w'];
31428 $tpl['h'] = $tpl['box']['h'];
31429 if ($crop_w) {
31430 $tpl['box']['w'] = $crop_w;
31431 }
31432 if ($crop_h) {
31433 $tpl['box']['h'] = $crop_h;
31434 }
31435 if (isset($crop_x)) {
31436 $tpl['box']['x'] = $crop_x;
31437 }
31438 if (isset($crop_y)) {
31439 $tpl['box']['y'] = $tpl['h'] - $crop_y - $crop_h;
31440 }
31441
31442 // fix for rotated pages
31443 $rotation = $parser->getPageRotation($pageno);
31444
31445 if (isset($rotation[1]) && ($angle = $rotation[1] % 360) != 0 && $tpl['box']['w'] == $tpl['w']) {
31446 $steps = $angle / 90;
31447
31448 $_w = $tpl['w'];
31449 $_h = $tpl['h'];
31450 $tpl['w'] = $steps % 2 == 0 ? $_w : $_h;
31451 $tpl['h'] = $steps % 2 == 0 ? $_h : $_w;
31452 if ($steps % 2 != 0) {
31453 $x = $y = ($steps == 1 || $steps == -3) ? $tpl['h'] : $tpl['w'];
31454 } else {
31455 $x = $tpl['w'];
31456 $y = $tpl['h'];
31457 }
31458 $cx = ($x / 2 + $tpl['box']['x']) * _MPDFK;
31459 $cy = ($y / 2 + $tpl['box']['y']) * _MPDFK;
31460 $angle*=-1;
31461 $angle*=M_PI / 180;
31462 $c = cos($angle);
31463 $s = sin($angle);
31464 $tpl['box']['w'] = $tpl['w'];
31465 $tpl['box']['h'] = $tpl['h'];
31466 $tpl['buffer'] = sprintf('q %.5F %.5F %.5F %.5F %.2F %.2F cm 1 0 0 1 %.2F %.2F cm %s Q', $c, $s, -$s, $c, $cx, $cy, -$cx, -$cy, $tpl['buffer']);
31467 }
31468 return $this->tpl;
31469 }
31470
31471 function UseTemplate($tplidx, $_x = null, $_y = null, $_w = 0, $_h = 0)
31472 {
31473 if (!isset($this->tpls[$tplidx])) {
31474 throw new MpdfException("Template does not exist!");
31475 }
31476
31477 if ($this->state == 0) {
31478 $this->AddPage();
31479 }
31480
31481 $out = 'q 0 J 1 w 0 j 0 G' . "\n"; // reset standard values
31482 $x = $this->tpls[$tplidx]['x'];
31483 $y = $this->tpls[$tplidx]['y'];
31484 $w = $this->tpls[$tplidx]['w'];
31485 $h = $this->tpls[$tplidx]['h'];
31486
31487 if ($_x == null) {
31488 $_x = $x;
31489 }
31490
31491 if ($_y == null) {
31492 $_y = $y;
31493 }
31494
31495 if ($_x === -1) {
31496 $_x = $this->x;
31497 }
31498
31499 if ($_y === -1) {
31500 $_y = $this->y;
31501 }
31502
31503 $wh = $this->getTemplateSize($tplidx, $_w, $_h);
31504 $_w = $wh['w'];
31505 $_h = $wh['h'];
31506 $out .= sprintf("q %.4F 0 0 %.4F %.2F %.2F cm", ($_w / $this->tpls[$tplidx]['box']['w']), ($_h / $this->tpls[$tplidx]['box']['h']), $_x * _MPDFK, ($this->h - ($_y + $_h)) * _MPDFK) . "\n";
31507 $out .= $this->tplprefix . $tplidx . " Do Q\n";
31508
31509 $s = array("w" => $_w, "h" => $_h);
31510 $out .= "Q\n";
31511 $this->pages[$this->page] = $out . $this->pages[$this->page];
31512 return $s;
31513 }
31514
31515 function SetPageTemplate($tplidx = '')
31516 {
31517 if (!isset($this->tpls[$tplidx])) {
31518 $this->pageTemplate = '';
31519 return false;
31520 }
31521 $this->pageTemplate = $tplidx;
31522 }
31523
31524 function SetDocTemplate($file = '', $continue = 0)
31525 {
31526 $this->docTemplate = $file;
31527 $this->docTemplateContinue = $continue;
31528 }
31529
31530 /* -- END IMPORTS -- */
31531
31532
31533 /* ---------------------------------------------- */
31534 /* ---------------------------------------------- */
31535 /* ---------------------------------------------- */
31536 /* ---------------------------------------------- */
31537 /* ---------------------------------------------- */
31538
31539 // JAVASCRIPT
31540 function _set_object_javascript($string)
31541 {
31542 $this->_newobj();
31543 $this->_out('<<');
31544 $this->_out('/S /JavaScript ');
31545 $this->_out('/JS ' . $this->_textstring($string));
31546 $this->_out('>>');
31547 $this->_out('endobj');
31548 }
31549
31550 function SetJS($script)
31551 {
31552 $this->js = $script;
31553 }
31554
31555 }
31556