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