1<?php
2
3namespace Mpdf;
4
5use Mpdf\Utils\Arrays;
6use DeepCopy\DeepCopy;
7
8class TableOfContents
9{
10
11	private $mpdf;
12
13	private $sizeConverter;
14
15	var $_toc;
16
17	var $TOCmark;
18
19	var $TOCoutdent; // mPDF 5.6.31
20
21	var $TOCpreHTML;
22
23	var $TOCpostHTML;
24
25	var $TOCbookmarkText;
26
27	var $TOCusePaging;
28
29	var $TOCuseLinking;
30
31	var $TOCorientation;
32
33	var $TOC_margin_left;
34
35	var $TOC_margin_right;
36
37	var $TOC_margin_top;
38
39	var $TOC_margin_bottom;
40
41	var $TOC_margin_header;
42
43	var $TOC_margin_footer;
44
45	var $TOC_odd_header_name;
46
47	var $TOC_even_header_name;
48
49	var $TOC_odd_footer_name;
50
51	var $TOC_even_footer_name;
52
53	var $TOC_odd_header_value;
54
55	var $TOC_even_header_value;
56
57	var $TOC_odd_footer_value;
58
59	var $TOC_even_footer_value;
60
61	var $TOC_page_selector;
62
63	var $TOC_resetpagenum; // mPDF 6
64
65	var $TOC_pagenumstyle; // mPDF 6
66
67	var $TOC_suppress; // mPDF 6
68
69	var $TOCsheetsize;
70
71	var $m_TOC;
72
73	/**
74	 * @var bool Determine if the TOC should be cloned to calculate the correct page numbers
75	 */
76	protected $tocTocPaintBegun = false;
77
78	public function __construct(Mpdf $mpdf, SizeConverter $sizeConverter)
79	{
80		$this->mpdf = $mpdf;
81		$this->sizeConverter = $sizeConverter;
82
83		$this->_toc = [];
84		$this->TOCmark = 0;
85		$this->m_TOC = [];
86	}
87
88	/**
89	 * Mark the TOC Paint as having begun
90	 */
91	public function beginTocPaint()
92	{
93		$this->tocTocPaintBegun = true;
94	}
95
96	public function TOCpagebreak(
97		$tocfont = '',
98		$tocfontsize = '',
99		$tocindent = '',
100		$TOCusePaging = true,
101		$TOCuseLinking = '',
102		$toc_orientation = '',
103		$toc_mgl = '',
104		$toc_mgr = '',
105		$toc_mgt = '',
106		$toc_mgb = '',
107		$toc_mgh = '',
108		$toc_mgf = '',
109		$toc_ohname = '',
110		$toc_ehname = '',
111		$toc_ofname = '',
112		$toc_efname = '',
113		$toc_ohvalue = 0,
114		$toc_ehvalue = 0,
115		$toc_ofvalue = 0,
116		$toc_efvalue = 0,
117		$toc_preHTML = '',
118		$toc_postHTML = '',
119		$toc_bookmarkText = '',
120		$resetpagenum = '',
121		$pagenumstyle = '',
122		$suppress = '',
123		$orientation = '',
124		$mgl = '',
125		$mgr = '',
126		$mgt = '',
127		$mgb = '',
128		$mgh = '',
129		$mgf = '',
130		$ohname = '',
131		$ehname = '',
132		$ofname = '',
133		$efname = '',
134		$ohvalue = 0,
135		$ehvalue = 0,
136		$ofvalue = 0,
137		$efvalue = 0,
138		$toc_id = 0,
139		$pagesel = '',
140		$toc_pagesel = '',
141		$sheetsize = '',
142		$toc_sheetsize = '',
143		$tocoutdent = '',
144		$toc_resetpagenum = '',
145		$toc_pagenumstyle = '',
146		$toc_suppress = ''
147	) {
148
149		if (strtoupper($toc_id) == 'ALL') {
150			$toc_id = '_mpdf_all';
151		} elseif (!$toc_id) {
152			$toc_id = 0;
153		} else {
154			$toc_id = strtolower($toc_id);
155		}
156
157		if ($TOCusePaging === false || strtolower($TOCusePaging) == "off" || $TOCusePaging === 0 || $TOCusePaging === "0" || $TOCusePaging === "") {
158			$TOCusePaging = false;
159		} else {
160			$TOCusePaging = true;
161		}
162		if (!$TOCuseLinking) {
163			$TOCuseLinking = false;
164		}
165		if ($toc_id) {
166			$this->m_TOC[$toc_id]['TOCmark'] = $this->mpdf->page;
167			$this->m_TOC[$toc_id]['TOCoutdent'] = $tocoutdent;
168			$this->m_TOC[$toc_id]['TOCorientation'] = $toc_orientation;
169			$this->m_TOC[$toc_id]['TOCuseLinking'] = $TOCuseLinking;
170			$this->m_TOC[$toc_id]['TOCusePaging'] = $TOCusePaging;
171
172			if ($toc_preHTML) {
173				$this->m_TOC[$toc_id]['TOCpreHTML'] = $toc_preHTML;
174			}
175			if ($toc_postHTML) {
176				$this->m_TOC[$toc_id]['TOCpostHTML'] = $toc_postHTML;
177			}
178			if ($toc_bookmarkText) {
179				$this->m_TOC[$toc_id]['TOCbookmarkText'] = $toc_bookmarkText;
180			}
181
182			$this->m_TOC[$toc_id]['TOC_margin_left'] = $toc_mgl;
183			$this->m_TOC[$toc_id]['TOC_margin_right'] = $toc_mgr;
184			$this->m_TOC[$toc_id]['TOC_margin_top'] = $toc_mgt;
185			$this->m_TOC[$toc_id]['TOC_margin_bottom'] = $toc_mgb;
186			$this->m_TOC[$toc_id]['TOC_margin_header'] = $toc_mgh;
187			$this->m_TOC[$toc_id]['TOC_margin_footer'] = $toc_mgf;
188			$this->m_TOC[$toc_id]['TOC_odd_header_name'] = $toc_ohname;
189			$this->m_TOC[$toc_id]['TOC_even_header_name'] = $toc_ehname;
190			$this->m_TOC[$toc_id]['TOC_odd_footer_name'] = $toc_ofname;
191			$this->m_TOC[$toc_id]['TOC_even_footer_name'] = $toc_efname;
192			$this->m_TOC[$toc_id]['TOC_odd_header_value'] = $toc_ohvalue;
193			$this->m_TOC[$toc_id]['TOC_even_header_value'] = $toc_ehvalue;
194			$this->m_TOC[$toc_id]['TOC_odd_footer_value'] = $toc_ofvalue;
195			$this->m_TOC[$toc_id]['TOC_even_footer_value'] = $toc_efvalue;
196			$this->m_TOC[$toc_id]['TOC_page_selector'] = $toc_pagesel;
197			$this->m_TOC[$toc_id]['TOC_resetpagenum'] = $toc_resetpagenum; // mPDF 6
198			$this->m_TOC[$toc_id]['TOC_pagenumstyle'] = $toc_pagenumstyle; // mPDF 6
199			$this->m_TOC[$toc_id]['TOC_suppress'] = $toc_suppress; // mPDF 6
200			$this->m_TOC[$toc_id]['TOCsheetsize'] = $toc_sheetsize;
201		} else {
202			$this->TOCmark = $this->mpdf->page;
203			$this->TOCoutdent = $tocoutdent;
204			$this->TOCorientation = $toc_orientation;
205			$this->TOCuseLinking = $TOCuseLinking;
206			$this->TOCusePaging = $TOCusePaging;
207
208			if ($toc_preHTML) {
209				$this->TOCpreHTML = $toc_preHTML;
210			}
211			if ($toc_postHTML) {
212				$this->TOCpostHTML = $toc_postHTML;
213			}
214			if ($toc_bookmarkText) {
215				$this->TOCbookmarkText = $toc_bookmarkText;
216			}
217
218			$this->TOC_margin_left = $toc_mgl;
219			$this->TOC_margin_right = $toc_mgr;
220			$this->TOC_margin_top = $toc_mgt;
221			$this->TOC_margin_bottom = $toc_mgb;
222			$this->TOC_margin_header = $toc_mgh;
223			$this->TOC_margin_footer = $toc_mgf;
224			$this->TOC_odd_header_name = $toc_ohname;
225			$this->TOC_even_header_name = $toc_ehname;
226			$this->TOC_odd_footer_name = $toc_ofname;
227			$this->TOC_even_footer_name = $toc_efname;
228			$this->TOC_odd_header_value = $toc_ohvalue;
229			$this->TOC_even_header_value = $toc_ehvalue;
230			$this->TOC_odd_footer_value = $toc_ofvalue;
231			$this->TOC_even_footer_value = $toc_efvalue;
232			$this->TOC_page_selector = $toc_pagesel;
233			$this->TOC_resetpagenum = $toc_resetpagenum; // mPDF 6
234			$this->TOC_pagenumstyle = $toc_pagenumstyle; // mPDF 6
235			$this->TOC_suppress = $toc_suppress; // mPDF 6
236			$this->TOCsheetsize = $toc_sheetsize;
237		}
238	}
239
240	/**
241	 * Initiate, and Mark a place for the Table of Contents to be inserted
242	 */
243	public function TOC(
244		$tocfont = '',
245		$tocfontsize = 0,
246		$tocindent = 0,
247		$resetpagenum = '',
248		$pagenumstyle = '',
249		$suppress = '',
250		$toc_orientation = '',
251		$TOCusePaging = true,
252		$TOCuseLinking = false,
253		$toc_id = 0,
254		$tocoutdent = '',
255		$toc_resetpagenum = '',
256		$toc_pagenumstyle = '',
257		$toc_suppress = ''
258	) {
259
260		if (strtoupper($toc_id) == 'ALL') {
261			$toc_id = '_mpdf_all';
262		} elseif (!$toc_id) {
263			$toc_id = 0;
264		} else {
265			$toc_id = strtolower($toc_id);
266		}
267		// To use odd and even pages
268		// Cannot start table of contents on an even page
269		if (($this->mpdf->mirrorMargins) && (($this->mpdf->page) % 2 == 0)) { // EVEN
270			if ($this->mpdf->ColActive) {
271				if (count($this->mpdf->columnbuffer)) {
272					$this->mpdf->printcolumnbuffer();
273				}
274			}
275			$this->mpdf->AddPage($this->mpdf->CurOrientation, '', $resetpagenum, $pagenumstyle, $suppress);
276		} else {
277			$this->mpdf->PageNumSubstitutions[] = ['from' => $this->mpdf->page, 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress];
278		}
279		if ($toc_id) {
280			$this->m_TOC[$toc_id]['TOCmark'] = $this->mpdf->page;
281			$this->m_TOC[$toc_id]['TOCoutdent'] = $tocoutdent;
282			$this->m_TOC[$toc_id]['TOCorientation'] = $toc_orientation;
283			$this->m_TOC[$toc_id]['TOCuseLinking'] = $TOCuseLinking;
284			$this->m_TOC[$toc_id]['TOCusePaging'] = $TOCusePaging;
285			$this->m_TOC[$toc_id]['TOC_resetpagenum'] = $toc_resetpagenum; // mPDF 6
286			$this->m_TOC[$toc_id]['TOC_pagenumstyle'] = $toc_pagenumstyle; // mPDF 6
287			$this->m_TOC[$toc_id]['TOC_suppress'] = $toc_suppress; // mPDF 6
288		} else {
289			$this->TOCmark = $this->mpdf->page;
290			$this->TOCoutdent = $tocoutdent;
291			$this->TOCorientation = $toc_orientation;
292			$this->TOCuseLinking = $TOCuseLinking;
293			$this->TOCusePaging = $TOCusePaging;
294			$this->TOC_resetpagenum = $toc_resetpagenum; // mPDF 6
295			$this->TOC_pagenumstyle = $toc_pagenumstyle; // mPDF 6
296			$this->TOC_suppress = $toc_suppress; // mPDF 6
297		}
298	}
299
300	public function insertTOC()
301	{
302		/*
303		 * Fix the TOC page numbering problem
304		 *
305		 * To do this, the current class is deep cloned and then the TOC functionality run. The correct page
306		 * numbers are calculated when the TOC pages are moved into position in the cloned object (see Mpdf::MovePages).
307		 * It's then a matter of copying the correct page numbers to the original object and letting the TOC functionality
308		 * run as per normal.
309		 *
310		 * See https://github.com/mpdf/mpdf/issues/642
311		 */
312		if (!$this->tocTocPaintBegun) {
313			$copier = new DeepCopy(true);
314			$tocClassClone = $copier->copy($this);
315			$tocClassClone->beginTocPaint();
316			$tocClassClone->insertTOC();
317			$this->_toc = $tocClassClone->_toc;
318		}
319
320		$notocs = 0;
321		if ($this->TOCmark) {
322			$notocs = 1;
323		}
324		$notocs += count($this->m_TOC);
325
326		if ($notocs == 0) {
327			return;
328		}
329
330		if (count($this->m_TOC)) {
331			reset($this->m_TOC);
332		}
333		$added_toc_pages = 0;
334
335		if ($this->mpdf->ColActive) {
336			$this->mpdf->SetColumns(0);
337		}
338		if (($this->mpdf->mirrorMargins) && (($this->mpdf->page) % 2 == 1)) { // ODD
339			$this->mpdf->AddPage($this->mpdf->CurOrientation);
340			$extrapage = true;
341		} else {
342			$extrapage = false;
343		}
344
345		for ($toci = 0; $toci < $notocs; $toci++) {
346			if ($toci == 0 && $this->TOCmark) {
347				$toc_id = 0;
348				$toc_page = $this->TOCmark;
349				$tocoutdent = $this->TOCoutdent;
350				$toc_orientation = $this->TOCorientation;
351				$TOCuseLinking = $this->TOCuseLinking;
352				$TOCusePaging = $this->TOCusePaging;
353				$toc_preHTML = $this->TOCpreHTML;
354				$toc_postHTML = $this->TOCpostHTML;
355				$toc_bookmarkText = $this->TOCbookmarkText;
356				$toc_mgl = $this->TOC_margin_left;
357				$toc_mgr = $this->TOC_margin_right;
358				$toc_mgt = $this->TOC_margin_top;
359				$toc_mgb = $this->TOC_margin_bottom;
360				$toc_mgh = $this->TOC_margin_header;
361				$toc_mgf = $this->TOC_margin_footer;
362				$toc_ohname = $this->TOC_odd_header_name;
363				$toc_ehname = $this->TOC_even_header_name;
364				$toc_ofname = $this->TOC_odd_footer_name;
365				$toc_efname = $this->TOC_even_footer_name;
366				$toc_ohvalue = $this->TOC_odd_header_value;
367				$toc_ehvalue = $this->TOC_even_header_value;
368				$toc_ofvalue = $this->TOC_odd_footer_value;
369				$toc_efvalue = $this->TOC_even_footer_value;
370				$toc_page_selector = $this->TOC_page_selector;
371				$toc_resetpagenum = $this->TOC_resetpagenum; // mPDF 6
372				$toc_pagenumstyle = $this->TOC_pagenumstyle; // mPDF 6
373				$toc_suppress = $this->TOC_suppress; // mPDF 6
374				$toc_sheet_size = (isset($this->TOCsheetsize) ? $this->TOCsheetsize : '');
375			} else {
376				$arr = current($this->m_TOC);
377
378				$toc_id = key($this->m_TOC);
379				$toc_page = $this->m_TOC[$toc_id]['TOCmark'];
380				$tocoutdent = $this->m_TOC[$toc_id]['TOCoutdent'];
381				$toc_orientation = $this->m_TOC[$toc_id]['TOCorientation'];
382				$TOCuseLinking = $this->m_TOC[$toc_id]['TOCuseLinking'];
383				$TOCusePaging = $this->m_TOC[$toc_id]['TOCusePaging'];
384				if (isset($this->m_TOC[$toc_id]['TOCpreHTML'])) {
385					$toc_preHTML = $this->m_TOC[$toc_id]['TOCpreHTML'];
386				} else {
387					$toc_preHTML = '';
388				}
389				if (isset($this->m_TOC[$toc_id]['TOCpostHTML'])) {
390					$toc_postHTML = $this->m_TOC[$toc_id]['TOCpostHTML'];
391				} else {
392					$toc_postHTML = '';
393				}
394				if (isset($this->m_TOC[$toc_id]['TOCbookmarkText'])) {
395					$toc_bookmarkText = $this->m_TOC[$toc_id]['TOCbookmarkText'];
396				} else {
397					$toc_bookmarkText = '';
398				} // *BOOKMARKS*
399				$toc_mgl = $this->m_TOC[$toc_id]['TOC_margin_left'];
400				$toc_mgr = $this->m_TOC[$toc_id]['TOC_margin_right'];
401				$toc_mgt = $this->m_TOC[$toc_id]['TOC_margin_top'];
402				$toc_mgb = $this->m_TOC[$toc_id]['TOC_margin_bottom'];
403				$toc_mgh = $this->m_TOC[$toc_id]['TOC_margin_header'];
404				$toc_mgf = $this->m_TOC[$toc_id]['TOC_margin_footer'];
405				$toc_ohname = $this->m_TOC[$toc_id]['TOC_odd_header_name'];
406				$toc_ehname = $this->m_TOC[$toc_id]['TOC_even_header_name'];
407				$toc_ofname = $this->m_TOC[$toc_id]['TOC_odd_footer_name'];
408				$toc_efname = $this->m_TOC[$toc_id]['TOC_even_footer_name'];
409				$toc_ohvalue = $this->m_TOC[$toc_id]['TOC_odd_header_value'];
410				$toc_ehvalue = $this->m_TOC[$toc_id]['TOC_even_header_value'];
411				$toc_ofvalue = $this->m_TOC[$toc_id]['TOC_odd_footer_value'];
412				$toc_efvalue = $this->m_TOC[$toc_id]['TOC_even_footer_value'];
413				$toc_page_selector = $this->m_TOC[$toc_id]['TOC_page_selector'];
414				$toc_resetpagenum = $this->m_TOC[$toc_id]['TOC_resetpagenum']; // mPDF 6
415				$toc_pagenumstyle = $this->m_TOC[$toc_id]['TOC_pagenumstyle']; // mPDF 6
416				$toc_suppress = $this->m_TOC[$toc_id]['TOC_suppress']; // mPDF 6
417				$toc_sheet_size = (isset($this->m_TOC[$toc_id]['TOCsheetsize']) ? $this->m_TOC[$toc_id]['TOCsheetsize'] : '');
418				next($this->m_TOC);
419			}
420
421			// mPDF 5.6.31
422			if (!$toc_orientation) {
423				$toc_orientation = $this->mpdf->DefOrientation;
424			}
425
426			//  mPDF 6 number style and suppress now picked up from section preceding ToC
427			list($tp_pagenumstyle, $tp_suppress, $tp_reset) = $this->mpdf->docPageSettings($toc_page - 1);
428
429			if ($toc_resetpagenum) {
430				$tp_reset = $toc_resetpagenum; // mPDF 6
431			}
432			if ($toc_pagenumstyle) {
433				$tp_pagenumstyle = $toc_pagenumstyle; // mPDF 6
434			}
435			if ($toc_suppress || $toc_suppress === '0') {
436				$tp_suppress = $toc_suppress; // mPDF 6
437			}
438
439			$this->mpdf->AddPage($toc_orientation, '', $tp_reset, $tp_pagenumstyle, $tp_suppress, $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_page_selector, $toc_sheet_size); // mPDF 6
440
441			$this->mpdf->writingToC = true; // mPDF 5.6.38
442
443			/*
444			 * Ensure the TOC Page Number Style doesn't effect the TOC Numbering (added automatically in `AddPage()` above)
445			 * Ensure the page numbers show in the TOC when the 'suppress' setting is enabled
446			 * @see https://github.com/mpdf/mpdf/issues/792
447			 * @see https://github.com/mpdf/mpdf/issues/777
448			 */
449			if (isset($tocClassClone)) {
450				$this->mpdf->PageNumSubstitutions = array_map(function ($sub) {
451					$sub['suppress'] = '';
452					return $sub;
453				}, $tocClassClone->mpdf->PageNumSubstitutions);
454			}
455
456			// mPDF 5.6.31
457			$tocstart = count($this->mpdf->pages);
458			if (isset($toc_preHTML) && $toc_preHTML) {
459				$this->mpdf->WriteHTML($toc_preHTML);
460			}
461
462			// mPDF 5.6.19
463			$html = '<div class="mpdf_toc" id="mpdf_toc_' . $toc_id . '">';
464			foreach ($this->_toc as $t) {
465				if ($t['toc_id'] === '_mpdf_all' || $t['toc_id'] === $toc_id) {
466					$html .= '<div class="mpdf_toc_level_' . $t['l'] . '">';
467					if ($TOCuseLinking) {
468						$html .= '<a class="mpdf_toc_a" href="#__mpdfinternallink_' . $t['link'] . '">';
469					}
470					$html .= '<span class="mpdf_toc_t_level_' . $t['l'] . '">' . $t['t'] . '</span>';
471					if ($TOCuseLinking) {
472						$html .= '</a>';
473					}
474					if (!$tocoutdent) {
475						$tocoutdent = '0';
476					}
477					if ($TOCusePaging) {
478						$html .= ' <dottab outdent="' . $tocoutdent . '" /> ';
479						if ($TOCuseLinking) {
480							$html .= '<a class="mpdf_toc_a" href="#__mpdfinternallink_' . $t['link'] . '">';
481						}
482						$html .= '<span class="mpdf_toc_p_level_' . $t['l'] . '">' . $this->mpdf->docPageNum($t['p']) . '</span>';
483						if ($TOCuseLinking) {
484							$html .= '</a>';
485						}
486					}
487					$html .= '</div>';
488				}
489			}
490			$html .= '</div>';
491			$this->mpdf->WriteHTML($html);
492
493			if (isset($toc_postHTML) && $toc_postHTML) {
494				$this->mpdf->WriteHTML($toc_postHTML);
495			}
496			$this->mpdf->writingToC = false; // mPDF 5.6.38
497			$this->mpdf->AddPage($toc_orientation, 'E');
498
499			$n_toc = $this->mpdf->page - $tocstart + 1;
500
501			if ($toci == 0 && $this->TOCmark) {
502				$TOC_start = $tocstart;
503				$TOC_end = $this->mpdf->page;
504				$TOC_npages = $n_toc;
505			} else {
506				$this->m_TOC[$toc_id]['start'] = $tocstart;
507				$this->m_TOC[$toc_id]['end'] = $this->mpdf->page;
508				$this->m_TOC[$toc_id]['npages'] = $n_toc;
509			}
510		}
511
512		$s = '';
513
514		$s .= $this->mpdf->PrintBodyBackgrounds();
515
516		$s .= $this->mpdf->PrintPageBackgrounds();
517		$this->mpdf->pages[$this->mpdf->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->mpdf->uniqstr . ')/', "\n" . $s . "\n" . '\\1', $this->mpdf->pages[$this->mpdf->page]);
518		$this->mpdf->pageBackgrounds = [];
519
520		//Page footer
521		$this->mpdf->InFooter = true;
522		$this->mpdf->Footer();
523		$this->mpdf->InFooter = false;
524
525		// 2nd time through to move pages etc.
526		$added_toc_pages = 0;
527		if (count($this->m_TOC)) {
528			reset($this->m_TOC);
529		}
530
531		for ($toci = 0; $toci < $notocs; $toci++) {
532			if ($toci == 0 && $this->TOCmark) {
533				$toc_id = 0;
534				$toc_page = $this->TOCmark + $added_toc_pages;
535				$toc_orientation = $this->TOCorientation;
536				$TOCuseLinking = $this->TOCuseLinking;
537				$TOCusePaging = $this->TOCusePaging;
538				$toc_bookmarkText = $this->TOCbookmarkText; // *BOOKMARKS*
539
540				$tocstart = $TOC_start;
541				$tocend = $n = $TOC_end;
542				$n_toc = $TOC_npages;
543			} else {
544				$arr = current($this->m_TOC);
545
546				$toc_id = key($this->m_TOC);
547				$toc_page = $this->m_TOC[$toc_id]['TOCmark'] + $added_toc_pages;
548				$toc_orientation = $this->m_TOC[$toc_id]['TOCorientation'];
549				$TOCuseLinking = $this->m_TOC[$toc_id]['TOCuseLinking'];
550				$TOCusePaging = $this->m_TOC[$toc_id]['TOCusePaging'];
551				$toc_bookmarkText = Arrays::get($this->m_TOC[$toc_id], 'TOCbookmarkText', null); // *BOOKMARKS*
552
553				$tocstart = $this->m_TOC[$toc_id]['start'];
554				$tocend = $n = $this->m_TOC[$toc_id]['end'];
555				$n_toc = $this->m_TOC[$toc_id]['npages'];
556
557				next($this->m_TOC);
558			}
559
560			// Now pages moved
561			$added_toc_pages += $n_toc;
562
563			$this->mpdf->MovePages($toc_page, $tocstart, $tocend);
564			$this->mpdf->pgsIns[$toc_page] = $tocend - $tocstart + 1;
565
566			/* -- BOOKMARKS -- */
567			// Insert new Bookmark for Bookmark
568			if ($toc_bookmarkText) {
569				$insert = -1;
570				foreach ($this->mpdf->BMoutlines as $i => $o) {
571					if ($o['p'] < $toc_page) { // i.e. before point of insertion
572						$insert = $i;
573					}
574				}
575				$txt = $this->mpdf->purify_utf8_text($toc_bookmarkText);
576				if ($this->mpdf->text_input_as_HTML) {
577					$txt = $this->mpdf->all_entities_to_utf8($txt);
578				}
579				$newBookmark[0] = ['t' => $txt, 'l' => 0, 'y' => 0, 'p' => $toc_page];
580				array_splice($this->mpdf->BMoutlines, ($insert + 1), 0, $newBookmark);
581			}
582			/* -- END BOOKMARKS -- */
583		}
584
585		// Delete empty page that was inserted earlier
586		if ($extrapage) {
587			unset($this->mpdf->pages[count($this->mpdf->pages)]);
588			$this->mpdf->page--; // Reset page pointer
589		}
590
591		/* Fix the over adjustment of the TOC and Page Substitutions values */
592		if (isset($tocClassClone)) {
593			$this->_toc = $tocClassClone->_toc;
594			$this->mpdf->PageNumSubstitutions = $tocClassClone->mpdf->PageNumSubstitutions;
595			unset($tocClassClone);
596		}
597	}
598
599	public function openTagTOC($attr)
600	{
601		if (isset($attr['OUTDENT']) && $attr['OUTDENT']) {
602			$tocoutdent = $attr['OUTDENT'];
603		} else {
604			$tocoutdent = '';
605		} // mPDF 5.6.19
606		if (isset($attr['RESETPAGENUM']) && $attr['RESETPAGENUM']) {
607			$resetpagenum = $attr['RESETPAGENUM'];
608		} else {
609			$resetpagenum = '';
610		}
611		if (isset($attr['PAGENUMSTYLE']) && $attr['PAGENUMSTYLE']) {
612			$pagenumstyle = $attr['PAGENUMSTYLE'];
613		} else {
614			$pagenumstyle = '';
615		}
616		if (isset($attr['SUPPRESS']) && $attr['SUPPRESS']) {
617			$suppress = $attr['SUPPRESS'];
618		} else {
619			$suppress = '';
620		}
621		if (isset($attr['TOC-ORIENTATION']) && $attr['TOC-ORIENTATION']) {
622			$toc_orientation = $attr['TOC-ORIENTATION'];
623		} else {
624			$toc_orientation = '';
625		}
626		if (isset($attr['PAGING']) && (strtoupper($attr['PAGING']) == 'OFF' || $attr['PAGING'] === '0')) {
627			$paging = false;
628		} else {
629			$paging = true;
630		}
631		if (isset($attr['LINKS']) && (strtoupper($attr['LINKS']) == 'ON' || $attr['LINKS'] == 1)) {
632			$links = true;
633		} else {
634			$links = false;
635		}
636		if (isset($attr['NAME']) && $attr['NAME']) {
637			$toc_id = strtolower($attr['NAME']);
638		} else {
639			$toc_id = 0;
640		}
641		$this->TOC('', 0, 0, $resetpagenum, $pagenumstyle, $suppress, $toc_orientation, $paging, $links, $toc_id, $tocoutdent);  // mPDF 5.6.19 5.6.31
642	}
643
644	public function openTagTOCPAGEBREAK($attr)
645	{
646		if (isset($attr['NAME']) && $attr['NAME']) {
647			$toc_id = strtolower($attr['NAME']);
648		} else {
649			$toc_id = 0;
650		}
651		if ($toc_id) {
652			if (isset($attr['OUTDENT']) && $attr['OUTDENT']) {
653				$this->m_TOC[$toc_id]['TOCoutdent'] = $attr['OUTDENT'];
654			} else {
655				$this->m_TOC[$toc_id]['TOCoutdent'] = '';
656			} // mPDF 5.6.19
657			if (isset($attr['TOC-ORIENTATION']) && $attr['TOC-ORIENTATION']) {
658				$this->m_TOC[$toc_id]['TOCorientation'] = $attr['TOC-ORIENTATION'];
659			} else {
660				$this->m_TOC[$toc_id]['TOCorientation'] = '';
661			}
662			if (isset($attr['PAGING']) && (strtoupper($attr['PAGING']) == 'OFF' || $attr['PAGING'] === '0')) {
663				$this->m_TOC[$toc_id]['TOCusePaging'] = false;
664			} else {
665				$this->m_TOC[$toc_id]['TOCusePaging'] = true;
666			}
667			if (isset($attr['LINKS']) && (strtoupper($attr['LINKS']) == 'ON' || $attr['LINKS'] == 1)) {
668				$this->m_TOC[$toc_id]['TOCuseLinking'] = true;
669			} else {
670				$this->m_TOC[$toc_id]['TOCuseLinking'] = false;
671			}
672
673			$this->m_TOC[$toc_id]['TOC_margin_left'] = $this->m_TOC[$toc_id]['TOC_margin_right'] = $this->m_TOC[$toc_id]['TOC_margin_top'] = $this->m_TOC[$toc_id]['TOC_margin_bottom'] = $this->m_TOC[$toc_id]['TOC_margin_header'] = $this->m_TOC[$toc_id]['TOC_margin_footer'] = '';
674			if (isset($attr['TOC-MARGIN-RIGHT'])) {
675				$this->m_TOC[$toc_id]['TOC_margin_right'] = $this->sizeConverter->convert($attr['TOC-MARGIN-RIGHT'], $this->mpdf->w, $this->mpdf->FontSize, false);
676			}
677			if (isset($attr['TOC-MARGIN-LEFT'])) {
678				$this->m_TOC[$toc_id]['TOC_margin_left'] = $this->sizeConverter->convert($attr['TOC-MARGIN-LEFT'], $this->mpdf->w, $this->mpdf->FontSize, false);
679			}
680			if (isset($attr['TOC-MARGIN-TOP'])) {
681				$this->m_TOC[$toc_id]['TOC_margin_top'] = $this->sizeConverter->convert($attr['TOC-MARGIN-TOP'], $this->mpdf->w, $this->mpdf->FontSize, false);
682			}
683			if (isset($attr['TOC-MARGIN-BOTTOM'])) {
684				$this->m_TOC[$toc_id]['TOC_margin_bottom'] = $this->sizeConverter->convert($attr['TOC-MARGIN-BOTTOM'], $this->mpdf->w, $this->mpdf->FontSize, false);
685			}
686			if (isset($attr['TOC-MARGIN-HEADER'])) {
687				$this->m_TOC[$toc_id]['TOC_margin_header'] = $this->sizeConverter->convert($attr['TOC-MARGIN-HEADER'], $this->mpdf->w, $this->mpdf->FontSize, false);
688			}
689			if (isset($attr['TOC-MARGIN-FOOTER'])) {
690				$this->m_TOC[$toc_id]['TOC_margin_footer'] = $this->sizeConverter->convert($attr['TOC-MARGIN-FOOTER'], $this->mpdf->w, $this->mpdf->FontSize, false);
691			}
692			$this->m_TOC[$toc_id]['TOC_odd_header_name'] = $this->m_TOC[$toc_id]['TOC_even_header_name'] = $this->m_TOC[$toc_id]['TOC_odd_footer_name'] = $this->m_TOC[$toc_id]['TOC_even_footer_name'] = '';
693			if (isset($attr['TOC-ODD-HEADER-NAME']) && $attr['TOC-ODD-HEADER-NAME']) {
694				$this->m_TOC[$toc_id]['TOC_odd_header_name'] = $attr['TOC-ODD-HEADER-NAME'];
695			}
696			if (isset($attr['TOC-EVEN-HEADER-NAME']) && $attr['TOC-EVEN-HEADER-NAME']) {
697				$this->m_TOC[$toc_id]['TOC_even_header_name'] = $attr['TOC-EVEN-HEADER-NAME'];
698			}
699			if (isset($attr['TOC-ODD-FOOTER-NAME']) && $attr['TOC-ODD-FOOTER-NAME']) {
700				$this->m_TOC[$toc_id]['TOC_odd_footer_name'] = $attr['TOC-ODD-FOOTER-NAME'];
701			}
702			if (isset($attr['TOC-EVEN-FOOTER-NAME']) && $attr['TOC-EVEN-FOOTER-NAME']) {
703				$this->m_TOC[$toc_id]['TOC_even_footer_name'] = $attr['TOC-EVEN-FOOTER-NAME'];
704			}
705			$this->m_TOC[$toc_id]['TOC_odd_header_value'] = $this->m_TOC[$toc_id]['TOC_even_header_value'] = $this->m_TOC[$toc_id]['TOC_odd_footer_value'] = $this->m_TOC[$toc_id]['TOC_even_footer_value'] = 0;
706			if (isset($attr['TOC-ODD-HEADER-VALUE']) && ($attr['TOC-ODD-HEADER-VALUE'] == '1' || strtoupper($attr['TOC-ODD-HEADER-VALUE']) == 'ON')) {
707				$this->m_TOC[$toc_id]['TOC_odd_header_value'] = 1;
708			} elseif (isset($attr['TOC-ODD-HEADER-VALUE']) && ($attr['TOC-ODD-HEADER-VALUE'] == '-1' || strtoupper($attr['TOC-ODD-HEADER-VALUE']) == 'OFF')) {
709				$this->m_TOC[$toc_id]['TOC_odd_header_value'] = -1;
710			}
711			if (isset($attr['TOC-EVEN-HEADER-VALUE']) && ($attr['TOC-EVEN-HEADER-VALUE'] == '1' || strtoupper($attr['TOC-EVEN-HEADER-VALUE']) == 'ON')) {
712				$this->m_TOC[$toc_id]['TOC_even_header_value'] = 1;
713			} elseif (isset($attr['TOC-EVEN-HEADER-VALUE']) && ($attr['TOC-EVEN-HEADER-VALUE'] == '-1' || strtoupper($attr['TOC-EVEN-HEADER-VALUE']) == 'OFF')) {
714				$this->m_TOC[$toc_id]['TOC_even_header_value'] = -1;
715			}
716			if (isset($attr['TOC-ODD-FOOTER-VALUE']) && ($attr['TOC-ODD-FOOTER-VALUE'] == '1' || strtoupper($attr['TOC-ODD-FOOTER-VALUE']) == 'ON')) {
717				$this->m_TOC[$toc_id]['TOC_odd_footer_value'] = 1;
718			} elseif (isset($attr['TOC-ODD-FOOTER-VALUE']) && ($attr['TOC-ODD-FOOTER-VALUE'] == '-1' || strtoupper($attr['TOC-ODD-FOOTER-VALUE']) == 'OFF')) {
719				$this->m_TOC[$toc_id]['TOC_odd_footer_value'] = -1;
720			}
721			if (isset($attr['TOC-EVEN-FOOTER-VALUE']) && ($attr['TOC-EVEN-FOOTER-VALUE'] == '1' || strtoupper($attr['TOC-EVEN-FOOTER-VALUE']) == 'ON')) {
722				$this->m_TOC[$toc_id]['TOC_even_footer_value'] = 1;
723			} elseif (isset($attr['TOC-EVEN-FOOTER-VALUE']) && ($attr['TOC-EVEN-FOOTER-VALUE'] == '-1' || strtoupper($attr['TOC-EVEN-FOOTER-VALUE']) == 'OFF')) {
724				$this->m_TOC[$toc_id]['TOC_even_footer_value'] = -1;
725			}
726			if (isset($attr['TOC-RESETPAGENUM']) && $attr['TOC-RESETPAGENUM']) {
727				$this->m_TOC[$toc_id]['TOC_resetpagenum'] = $attr['TOC-RESETPAGENUM'];
728			} else {
729				$this->m_TOC[$toc_id]['TOC_resetpagenum'] = '';
730			} // mPDF 6
731			if (isset($attr['TOC-PAGENUMSTYLE']) && $attr['TOC-PAGENUMSTYLE']) {
732				$this->m_TOC[$toc_id]['TOC_pagenumstyle'] = $attr['TOC-PAGENUMSTYLE'];
733			} else {
734				$this->m_TOC[$toc_id]['TOC_pagenumstyle'] = '';
735			} // mPDF 6
736			if (isset($attr['TOC-SUPPRESS']) && ($attr['TOC-SUPPRESS'] || $attr['TOC-SUPPRESS'] === '0')) {
737				$this->m_TOC[$toc_id]['TOC_suppress'] = $attr['TOC-SUPPRESS'];
738			} else {
739				$this->m_TOC[$toc_id]['TOC_suppress'] = '';
740			} // mPDF 6
741			if (isset($attr['TOC-PAGE-SELECTOR']) && $attr['TOC-PAGE-SELECTOR']) {
742				$this->m_TOC[$toc_id]['TOC_page_selector'] = $attr['TOC-PAGE-SELECTOR'];
743			} else {
744				$this->m_TOC[$toc_id]['TOC_page_selector'] = '';
745			}
746			if (isset($attr['TOC-SHEET-SIZE']) && $attr['TOC-SHEET-SIZE']) {
747				$this->m_TOC[$toc_id]['TOCsheetsize'] = $attr['TOC-SHEET-SIZE'];
748			} else {
749				$this->m_TOC[$toc_id]['TOCsheetsize'] = '';
750			}
751
752
753			if (isset($attr['TOC-PREHTML']) && $attr['TOC-PREHTML']) {
754				$this->m_TOC[$toc_id]['TOCpreHTML'] = htmlspecialchars_decode($attr['TOC-PREHTML'], ENT_QUOTES);
755			}
756			if (isset($attr['TOC-POSTHTML']) && $attr['TOC-POSTHTML']) {
757				$this->m_TOC[$toc_id]['TOCpostHTML'] = htmlspecialchars_decode($attr['TOC-POSTHTML'], ENT_QUOTES);
758			}
759
760			if (isset($attr['TOC-BOOKMARKTEXT']) && $attr['TOC-BOOKMARKTEXT']) {
761				$this->m_TOC[$toc_id]['TOCbookmarkText'] = htmlspecialchars_decode($attr['TOC-BOOKMARKTEXT'], ENT_QUOTES);
762			} // *BOOKMARKS*
763		} else {
764			if (isset($attr['OUTDENT']) && $attr['OUTDENT']) {
765				$this->TOCoutdent = $attr['OUTDENT'];
766			} else {
767				$this->TOCoutdent = '';
768			} // mPDF 5.6.19
769			if (isset($attr['TOC-ORIENTATION']) && $attr['TOC-ORIENTATION']) {
770				$this->TOCorientation = $attr['TOC-ORIENTATION'];
771			} else {
772				$this->TOCorientation = '';
773			}
774			if (isset($attr['PAGING']) && (strtoupper($attr['PAGING']) == 'OFF' || $attr['PAGING'] === '0')) {
775				$this->TOCusePaging = false;
776			} else {
777				$this->TOCusePaging = true;
778			}
779			if (isset($attr['LINKS']) && (strtoupper($attr['LINKS']) == 'ON' || $attr['LINKS'] == 1)) {
780				$this->TOCuseLinking = true;
781			} else {
782				$this->TOCuseLinking = false;
783			}
784
785			$this->TOC_margin_left = $this->TOC_margin_right = $this->TOC_margin_top = $this->TOC_margin_bottom = $this->TOC_margin_header = $this->TOC_margin_footer = '';
786			if (isset($attr['TOC-MARGIN-RIGHT'])) {
787				$this->TOC_margin_right = $this->sizeConverter->convert($attr['TOC-MARGIN-RIGHT'], $this->mpdf->w, $this->mpdf->FontSize, false);
788			}
789			if (isset($attr['TOC-MARGIN-LEFT'])) {
790				$this->TOC_margin_left = $this->sizeConverter->convert($attr['TOC-MARGIN-LEFT'], $this->mpdf->w, $this->mpdf->FontSize, false);
791			}
792			if (isset($attr['TOC-MARGIN-TOP'])) {
793				$this->TOC_margin_top = $this->sizeConverter->convert($attr['TOC-MARGIN-TOP'], $this->mpdf->w, $this->mpdf->FontSize, false);
794			}
795			if (isset($attr['TOC-MARGIN-BOTTOM'])) {
796				$this->TOC_margin_bottom = $this->sizeConverter->convert($attr['TOC-MARGIN-BOTTOM'], $this->mpdf->w, $this->mpdf->FontSize, false);
797			}
798			if (isset($attr['TOC-MARGIN-HEADER'])) {
799				$this->TOC_margin_header = $this->sizeConverter->convert($attr['TOC-MARGIN-HEADER'], $this->mpdf->w, $this->mpdf->FontSize, false);
800			}
801			if (isset($attr['TOC-MARGIN-FOOTER'])) {
802				$this->TOC_margin_footer = $this->sizeConverter->convert($attr['TOC-MARGIN-FOOTER'], $this->mpdf->w, $this->mpdf->FontSize, false);
803			}
804			$this->TOC_odd_header_name = $this->TOC_even_header_name = $this->TOC_odd_footer_name = $this->TOC_even_footer_name = '';
805			if (isset($attr['TOC-ODD-HEADER-NAME']) && $attr['TOC-ODD-HEADER-NAME']) {
806				$this->TOC_odd_header_name = $attr['TOC-ODD-HEADER-NAME'];
807			}
808			if (isset($attr['TOC-EVEN-HEADER-NAME']) && $attr['TOC-EVEN-HEADER-NAME']) {
809				$this->TOC_even_header_name = $attr['TOC-EVEN-HEADER-NAME'];
810			}
811			if (isset($attr['TOC-ODD-FOOTER-NAME']) && $attr['TOC-ODD-FOOTER-NAME']) {
812				$this->TOC_odd_footer_name = $attr['TOC-ODD-FOOTER-NAME'];
813			}
814			if (isset($attr['TOC-EVEN-FOOTER-NAME']) && $attr['TOC-EVEN-FOOTER-NAME']) {
815				$this->TOC_even_footer_name = $attr['TOC-EVEN-FOOTER-NAME'];
816			}
817			$this->TOC_odd_header_value = $this->TOC_even_header_value = $this->TOC_odd_footer_value = $this->TOC_even_footer_value = 0;
818			if (isset($attr['TOC-ODD-HEADER-VALUE']) && ($attr['TOC-ODD-HEADER-VALUE'] == '1' || strtoupper($attr['TOC-ODD-HEADER-VALUE']) == 'ON')) {
819				$this->TOC_odd_header_value = 1;
820			} elseif (isset($attr['TOC-ODD-HEADER-VALUE']) && ($attr['TOC-ODD-HEADER-VALUE'] == '-1' || strtoupper($attr['TOC-ODD-HEADER-VALUE']) == 'OFF')) {
821				$this->TOC_odd_header_value = -1;
822			}
823			if (isset($attr['TOC-EVEN-HEADER-VALUE']) && ($attr['TOC-EVEN-HEADER-VALUE'] == '1' || strtoupper($attr['TOC-EVEN-HEADER-VALUE']) == 'ON')) {
824				$this->TOC_even_header_value = 1;
825			} elseif (isset($attr['TOC-EVEN-HEADER-VALUE']) && ($attr['TOC-EVEN-HEADER-VALUE'] == '-1' || strtoupper($attr['TOC-EVEN-HEADER-VALUE']) == 'OFF')) {
826				$this->TOC_even_header_value = -1;
827			}
828
829			if (isset($attr['TOC-ODD-FOOTER-VALUE']) && ($attr['TOC-ODD-FOOTER-VALUE'] == '1' || strtoupper($attr['TOC-ODD-FOOTER-VALUE']) == 'ON')) {
830				$this->TOC_odd_footer_value = 1;
831			} elseif (isset($attr['TOC-ODD-FOOTER-VALUE']) && ($attr['TOC-ODD-FOOTER-VALUE'] == '-1' || strtoupper($attr['TOC-ODD-FOOTER-VALUE']) == 'OFF')) {
832				$this->TOC_odd_footer_value = -1;
833			}
834			if (isset($attr['TOC-EVEN-FOOTER-VALUE']) && ($attr['TOC-EVEN-FOOTER-VALUE'] == '1' || strtoupper($attr['TOC-EVEN-FOOTER-VALUE']) == 'ON')) {
835				$this->TOC_even_footer_value = 1;
836			} elseif (isset($attr['TOC-EVEN-FOOTER-VALUE']) && ($attr['TOC-EVEN-FOOTER-VALUE'] == '-1' || strtoupper($attr['TOC-EVEN-FOOTER-VALUE']) == 'OFF')) {
837				$this->TOC_even_footer_value = -1;
838			}
839			if (isset($attr['TOC-PAGE-SELECTOR']) && $attr['TOC-PAGE-SELECTOR']) {
840				$this->TOC_page_selector = $attr['TOC-PAGE-SELECTOR'];
841			} else {
842				$this->TOC_page_selector = '';
843			}
844			if (isset($attr['TOC-RESETPAGENUM']) && $attr['TOC-RESETPAGENUM']) {
845				$this->TOC_resetpagenum = $attr['TOC-RESETPAGENUM'];
846			} else {
847				$this->TOC_resetpagenum = '';
848			} // mPDF 6
849			if (isset($attr['TOC-PAGENUMSTYLE']) && $attr['TOC-PAGENUMSTYLE']) {
850				$this->TOC_pagenumstyle = $attr['TOC-PAGENUMSTYLE'];
851			} else {
852				$this->TOC_pagenumstyle = '';
853			} // mPDF 6
854			if (isset($attr['TOC-SUPPRESS']) && ($attr['TOC-SUPPRESS'] || $attr['TOC-SUPPRESS'] === '0')) {
855				$this->TOC_suppress = $attr['TOC-SUPPRESS'];
856			} else {
857				$this->TOC_suppress = '';
858			} // mPDF 6
859			if (isset($attr['TOC-SHEET-SIZE']) && $attr['TOC-SHEET-SIZE']) {
860				$this->TOCsheetsize = $attr['TOC-SHEET-SIZE'];
861			} else {
862				$this->TOCsheetsize = '';
863			}
864
865			if (isset($attr['TOC-PREHTML']) && $attr['TOC-PREHTML']) {
866				$this->TOCpreHTML = htmlspecialchars_decode($attr['TOC-PREHTML'], ENT_QUOTES);
867			}
868			if (isset($attr['TOC-POSTHTML']) && $attr['TOC-POSTHTML']) {
869				$this->TOCpostHTML = htmlspecialchars_decode($attr['TOC-POSTHTML'], ENT_QUOTES);
870			}
871			if (isset($attr['TOC-BOOKMARKTEXT']) && $attr['TOC-BOOKMARKTEXT']) {
872				$this->TOCbookmarkText = htmlspecialchars_decode($attr['TOC-BOOKMARKTEXT'], ENT_QUOTES);
873			}
874		}
875
876		if ($this->mpdf->y == $this->mpdf->tMargin && (!$this->mpdf->mirrorMargins || ($this->mpdf->mirrorMargins && $this->mpdf->page % 2 == 1))) {
877			if ($toc_id) {
878				$this->m_TOC[$toc_id]['TOCmark'] = $this->mpdf->page;
879			} else {
880				$this->TOCmark = $this->mpdf->page;
881			}
882			// Don't add a page
883			if ($this->mpdf->page == 1 && count($this->mpdf->PageNumSubstitutions) == 0) {
884				$resetpagenum = '';
885				$pagenumstyle = '';
886				$suppress = '';
887				if (isset($attr['RESETPAGENUM'])) {
888					$resetpagenum = $attr['RESETPAGENUM'];
889				}
890				if (isset($attr['PAGENUMSTYLE'])) {
891					$pagenumstyle = $attr['PAGENUMSTYLE'];
892				}
893				if (isset($attr['SUPPRESS'])) {
894					$suppress = $attr['SUPPRESS'];
895				}
896				if (!$suppress) {
897					$suppress = 'off';
898				}
899				$this->mpdf->PageNumSubstitutions[] = ['from' => 1, 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress];
900			}
901			return [true, $toc_id];
902		}
903
904		// No break - continues as PAGEBREAK...
905		return [false, $toc_id];
906	}
907
908}
909