1<?php
2
3namespace Mpdf;
4
5use Mpdf\Strict;
6
7use Mpdf\Color\ColorConverter;
8
9use \dokuwiki\plugin\dw2pdf\DokuImageProcessorDecorator as ImageProcessor;
10
11use Mpdf\Language\LanguageToFontInterface;
12
13class Tag
14{
15
16	use Strict;
17
18	/**
19	 * @var \Mpdf\Mpdf
20	 */
21	private $mpdf;
22
23	/**
24	 * @var \Mpdf\Cache
25	 */
26	private $cache;
27
28	/**
29	 * @var \Mpdf\CssManager
30	 */
31	private $cssManager;
32
33	/**
34	 * @var \Mpdf\Form
35	 */
36	private $form;
37
38	/**
39	 * @var \Mpdf\Otl
40	 */
41	private $otl;
42
43	/**
44	 * @var \Mpdf\TableOfContents
45	 */
46	private $tableOfContents;
47
48	/**
49	 * @var \Mpdf\SizeConverter
50	 */
51	private $sizeConverter;
52
53	/**
54	 * @var \Mpdf\Color\ColorConverter
55	 */
56	private $colorConverter;
57
58	/**
59	 * @var \Mpdf\Image\ImageProcessor
60	 */
61	private $imageProcessor;
62
63	/**
64	 * @var \Mpdf\Language\LanguageToFontInterface
65	 */
66	private $languageToFont;
67
68	/**
69	 * @param \Mpdf\Mpdf $mpdf
70	 * @param \Mpdf\Cache $cache
71	 * @param \Mpdf\CssManager $cssManager
72	 * @param \Mpdf\Form $form
73	 * @param \Mpdf\Otl $otl
74	 * @param \Mpdf\TableOfContents $tableOfContents
75	 * @param \Mpdf\SizeConverter $sizeConverter
76	 * @param \Mpdf\Color\ColorConverter $colorConverter
77	 * @param \Mpdf\Image\ImageProcessor $imageProcessor
78	 * @param \Mpdf\Language\LanguageToFontInterface $languageToFont
79	 */
80	public function __construct(
81		Mpdf $mpdf,
82		Cache $cache,
83		CssManager $cssManager,
84		Form $form,
85		Otl $otl,
86		TableOfContents $tableOfContents,
87		SizeConverter $sizeConverter,
88		ColorConverter $colorConverter,
89		ImageProcessor $imageProcessor,
90		LanguageToFontInterface $languageToFont
91	) {
92
93		$this->mpdf = $mpdf;
94		$this->cache = $cache;
95		$this->cssManager = $cssManager;
96		$this->form = $form;
97		$this->otl = $otl;
98		$this->tableOfContents = $tableOfContents;
99		$this->sizeConverter = $sizeConverter;
100		$this->colorConverter = $colorConverter;
101		$this->imageProcessor = $imageProcessor;
102		$this->languageToFont = $languageToFont;
103	}
104
105	/**
106	 * @param string $tag The tag name
107	 * @return \Mpdf\Tag\Tag
108	 */
109	private function getTagInstance($tag)
110	{
111		$className = self::getTagClassName($tag);
112		if (class_exists($className)) {
113			return new $className(
114				$this->mpdf,
115				$this->cache,
116				$this->cssManager,
117				$this->form,
118				$this->otl,
119				$this->tableOfContents,
120				$this->sizeConverter,
121				$this->colorConverter,
122				$this->imageProcessor,
123				$this->languageToFont
124			);
125		}
126	}
127
128	/**
129	 * Returns the fully qualified name of the class handling the rendering of the given tag
130	 *
131	 * @param string $tag The tag name
132	 * @return string The fully qualified name
133	 */
134	public static function getTagClassName($tag)
135	{
136		static $map = [
137			'BARCODE' => 'BarCode',
138			'BLOCKQUOTE' => 'BlockQuote',
139			'COLUMN_BREAK' => 'ColumnBreak',
140			'COLUMNBREAK' => 'ColumnBreak',
141			'DOTTAB' => 'DotTab',
142			'FIELDSET' => 'FieldSet',
143			'FIGCAPTION' => 'FigCaption',
144			'FORMFEED' => 'FormFeed',
145			'HGROUP' => 'HGroup',
146			'INDEXENTRY' => 'IndexEntry',
147			'INDEXINSERT' => 'IndexInsert',
148			'NEWCOLUMN' => 'NewColumn',
149			'NEWPAGE' => 'NewPage',
150			'PAGEFOOTER' => 'PageFooter',
151			'PAGEHEADER' => 'PageHeader',
152			'PAGE_BREAK' => 'PageBreak',
153			'PAGEBREAK' => 'PageBreak',
154			'SETHTMLPAGEFOOTER' => 'SetHtmlPageFooter',
155			'SETHTMLPAGEHEADER' => 'SetHtmlPageHeader',
156			'SETPAGEFOOTER' => 'SetPageFooter',
157			'SETPAGEHEADER' => 'SetPageHeader',
158			'TBODY' => 'TBody',
159			'TFOOT' => 'TFoot',
160			'THEAD' => 'THead',
161			'TEXTAREA' => 'TextArea',
162			'TEXTCIRCLE' => 'TextCircle',
163			'TOCENTRY' => 'TocEntry',
164			'TOCPAGEBREAK' => 'TocPageBreak',
165			'VAR' => 'VarTag',
166			'WATERMARKIMAGE' => 'WatermarkImage',
167			'WATERMARKTEXT' => 'WatermarkText',
168		];
169
170		$className = 'Mpdf\Tag\\';
171		$className .= isset($map[$tag]) ? $map[$tag] : ucfirst(strtolower($tag));
172
173		return $className;
174	}
175
176	public function OpenTag($tag, $attr, &$ahtml, &$ihtml)
177	{
178		// Correct for tags where HTML5 specifies optional end tags excluding table elements (cf WriteHTML() )
179		if ($this->mpdf->allow_html_optional_endtags) {
180			if (isset($this->mpdf->blk[$this->mpdf->blklvl]['tag'])) {
181				$closed = false;
182				// li end tag may be omitted if immediately followed by another li element
183				if (!$closed && $this->mpdf->blk[$this->mpdf->blklvl]['tag'] == 'LI' && $tag == 'LI') {
184					$this->CloseTag('LI', $ahtml, $ihtml);
185					$closed = true;
186				}
187				// dt end tag may be omitted if immediately followed by another dt element or a dd element
188				if (!$closed && $this->mpdf->blk[$this->mpdf->blklvl]['tag'] == 'DT' && ($tag == 'DT' || $tag == 'DD')) {
189					$this->CloseTag('DT', $ahtml, $ihtml);
190					$closed = true;
191				}
192				// dd end tag may be omitted if immediately followed by another dd element or a dt element
193				if (!$closed && $this->mpdf->blk[$this->mpdf->blklvl]['tag'] == 'DD' && ($tag == 'DT' || $tag == 'DD')) {
194					$this->CloseTag('DD', $ahtml, $ihtml);
195					$closed = true;
196				}
197				// p end tag may be omitted if immediately followed by an address, article, aside, blockquote, div, dl,
198				// fieldset, form, h1, h2, h3, h4, h5, h6, hgroup, hr, main, nav, ol, p, pre, section, table, ul
199				if (!$closed && $this->mpdf->blk[$this->mpdf->blklvl]['tag'] == 'P'
200						&& ($tag == 'P' || $tag == 'DIV' || $tag == 'H1' || $tag == 'H2' || $tag == 'H3'
201							|| $tag == 'H4' || $tag == 'H5' || $tag == 'H6' || $tag == 'UL' || $tag == 'OL'
202							|| $tag == 'TABLE' || $tag == 'PRE' || $tag == 'FORM' || $tag == 'ADDRESS' || $tag == 'BLOCKQUOTE'
203							|| $tag == 'CENTER' || $tag == 'DL' || $tag == 'HR' || $tag == 'ARTICLE' || $tag == 'ASIDE'
204							|| $tag == 'FIELDSET' || $tag == 'HGROUP' || $tag == 'MAIN' || $tag == 'NAV' || $tag == 'SECTION')) {
205					$this->CloseTag('P', $ahtml, $ihtml);
206					$closed = true;
207				}
208				// option end tag may be omitted if immediately followed by another option element
209				// (or if it is immediately followed by an optgroup element)
210				if (!$closed && $this->mpdf->blk[$this->mpdf->blklvl]['tag'] == 'OPTION' && $tag == 'OPTION') {
211					$this->CloseTag('OPTION', $ahtml, $ihtml);
212					$closed = true;
213				}
214				// Table elements - see also WriteHTML()
215				if (!$closed && ($tag == 'TD' || $tag == 'TH') && $this->mpdf->lastoptionaltag == 'TD') {
216					$this->CloseTag($this->mpdf->lastoptionaltag, $ahtml, $ihtml);
217					$closed = true;
218				} // *TABLES*
219				if (!$closed && ($tag == 'TD' || $tag == 'TH') && $this->mpdf->lastoptionaltag == 'TH') {
220					$this->CloseTag($this->mpdf->lastoptionaltag, $ahtml, $ihtml);
221					$closed = true;
222				} // *TABLES*
223				if (!$closed && $tag == 'TR' && $this->mpdf->lastoptionaltag == 'TR') {
224					$this->CloseTag($this->mpdf->lastoptionaltag, $ahtml, $ihtml);
225					$closed = true;
226				} // *TABLES*
227				if (!$closed && $tag == 'TR' && $this->mpdf->lastoptionaltag == 'TD') {
228					$this->CloseTag($this->mpdf->lastoptionaltag, $ahtml, $ihtml);
229					$this->CloseTag('TR', $ahtml, $ihtml);
230					$this->CloseTag('THEAD', $ahtml, $ihtml);
231					$closed = true;
232				} // *TABLES*
233				if (!$closed && $tag == 'TR' && $this->mpdf->lastoptionaltag == 'TH') {
234					$this->CloseTag($this->mpdf->lastoptionaltag, $ahtml, $ihtml);
235					$this->CloseTag('TR', $ahtml, $ihtml);
236					$this->CloseTag('THEAD', $ahtml, $ihtml);
237					$closed = true;
238				} // *TABLES*
239			}
240		}
241
242		if ($object = $this->getTagInstance($tag)) {
243			return $object->open($attr, $ahtml, $ihtml);
244		}
245	}
246
247	public function CloseTag($tag, &$ahtml, &$ihtml)
248	{
249		if ($object = $this->getTagInstance($tag)) {
250			return $object->close($ahtml, $ihtml);
251		}
252	}
253}
254