1<?php
2
3namespace Mpdf;
4
5use Mpdf\Strict;
6use Mpdf\Color\ColorConverter;
7use Mpdf\Writer\BaseWriter;
8use Mpdf\Writer\FormWriter;
9
10class Form
11{
12
13	use Strict;
14
15	// Input flags
16	const FLAG_READONLY = 1;
17	const FLAG_REQUIRED = 2;
18	const FLAG_NO_EXPORT = 3;
19	const FLAG_TEXTAREA = 13;
20	const FLAG_PASSWORD = 14;
21	const FLAG_RADIO = 15;
22	const FLAG_NOTOGGLEOFF = 16;
23	const FLAG_COMBOBOX = 18;
24	const FLAG_EDITABLE = 19;
25	const FLAG_MULTISELECT = 22;
26	const FLAG_NO_SPELLCHECK = 23;
27	const FLAG_NO_SCROLL = 24;
28
29	/**
30	 * @var \Mpdf\Mpdf
31	 */
32	private $mpdf;
33
34	/**
35	 * @var \Mpdf\Otl
36	 */
37	private $otl;
38
39	/**
40	 * @var \Mpdf\Color\ColorConverter
41	 */
42	private $colorConverter;
43
44	/**
45	 * @var \Mpdf\Writer\BaseWriter
46	 */
47	private $writer;
48
49	/**
50	 * @var \Mpdf\Writer\FormWriter
51	 */
52	private $formWriter;
53
54	/**
55	 * @var array
56	 */
57	public $forms;
58
59	/**
60	 * @var int
61	 */
62	private $formCount;
63
64	// Active Forms
65	var $formSubmitNoValueFields;
66	var $formExportType;
67	var $formSelectDefaultOption;
68	var $formUseZapD;
69
70	// Form Styles
71	var $form_border_color;
72	var $form_background_color;
73	var $form_border_width;
74	var $form_border_style;
75	var $form_button_border_color;
76	var $form_button_background_color;
77	var $form_button_border_width;
78	var $form_button_border_style;
79	var $form_radio_color;
80	var $form_radio_background_color;
81	var $form_element_spacing;
82
83	// Active forms
84	var $formMethod;
85	var $formAction;
86	var $form_fonts;
87	var $form_radio_groups;
88	var $form_checkboxes;
89	var $pdf_acro_array;
90	var $pdf_array_co;
91	var $array_form_button_js;
92	var $array_form_choice_js;
93	var $array_form_text_js;
94
95	// Button Text
96	var $form_button_text;
97	var $form_button_text_over;
98	var $form_button_text_click;
99	var $form_button_icon;
100
101	// FORMS
102	var $textarea_lineheight;
103
104	public function __construct(Mpdf $mpdf, Otl $otl, ColorConverter $colorConverter, BaseWriter $writer, FormWriter $formWriter)
105	{
106		$this->mpdf = $mpdf;
107		$this->otl = $otl;
108		$this->colorConverter = $colorConverter;
109		$this->writer = $writer;
110		$this->formWriter = $formWriter;
111
112		// ACTIVE FORMS
113		$this->formExportType = 'xfdf'; // 'xfdf' or 'html'
114		$this->formSubmitNoValueFields = true; // Whether to include blank fields when submitting data
115		$this->formSelectDefaultOption = true; // for Select drop down box; if no option is explicitly maked as selected,
116		// this determines whether to select 1st option (as per browser)
117		// - affects whether "required" attribute is relevant
118		$this->formUseZapD = true;  // Determine whether to use ZapfDingbat icons for radio/checkboxes
119		// FORM STYLES
120		// These can alternatively use a 4 number string to represent CMYK colours
121		$this->form_border_color = '0.6 0.6 0.72';   // RGB
122		$this->form_background_color = '0.975 0.975 0.975';  // RGB
123		$this->form_border_width = '1';  // 0 doesn't seem to work as it should
124		$this->form_border_style = 'S';  // B - Bevelled; D - Double
125		$this->form_button_border_color = '0.2 0.2 0.55';
126		$this->form_button_background_color = '0.941 0.941 0.941';
127		$this->form_button_border_width = '1';
128		$this->form_button_border_style = 'S';
129		$this->form_radio_color = '0.0 0.0 0.4';  // radio and checkbox
130		$this->form_radio_background_color = '0.9 0.9 0.9';
131
132		// FORMS
133		$this->textarea_lineheight = 1.25;
134
135		// FORM ELEMENT SPACING
136		$this->form_element_spacing['select']['outer']['h'] = 0.5; // Horizontal spacing around SELECT
137		$this->form_element_spacing['select']['outer']['v'] = 0.5; // Vertical spacing around SELECT
138		$this->form_element_spacing['select']['inner']['h'] = 0.7; // Horizontal padding around SELECT
139		$this->form_element_spacing['select']['inner']['v'] = 0.7; // Vertical padding around SELECT
140		$this->form_element_spacing['input']['outer']['h'] = 0.5;
141		$this->form_element_spacing['input']['outer']['v'] = 0.5;
142		$this->form_element_spacing['input']['inner']['h'] = 0.7;
143		$this->form_element_spacing['input']['inner']['v'] = 0.7;
144		$this->form_element_spacing['textarea']['outer']['h'] = 0.5;
145		$this->form_element_spacing['textarea']['outer']['v'] = 0.5;
146		$this->form_element_spacing['textarea']['inner']['h'] = 1;
147		$this->form_element_spacing['textarea']['inner']['v'] = 0.5;
148		$this->form_element_spacing['button']['outer']['h'] = 0.5;
149		$this->form_element_spacing['button']['outer']['v'] = 0.5;
150		$this->form_element_spacing['button']['inner']['h'] = 2;
151		$this->form_element_spacing['button']['inner']['v'] = 1;
152
153		// INITIALISE non-configurable
154		$this->formMethod = 'POST';
155		$this->formAction = '';
156		$this->form_fonts = [];
157		$this->form_radio_groups = [];
158		$this->form_checkboxes = false;
159		$this->forms = [];
160		$this->pdf_array_co = '';
161	}
162
163	function print_ob_text($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir)
164	{
165		// TEXT/PASSWORD INPUT
166		if ($this->mpdf->useActiveForms) {
167
168			$flags = [];
169
170			if (!empty($objattr['disabled']) || !empty($objattr['readonly'])) {
171				$flags[] = self::FLAG_READONLY;
172			}
173
174			if (!empty($objattr['disabled'])) {
175				$flags[] = self::FLAG_NO_EXPORT;
176				$objattr['color'] = [3, 128, 128, 128];  // gray out disabled
177			}
178
179			if (!empty($objattr['required'])) {
180				$flags[] = self::FLAG_REQUIRED;
181			}
182
183			if (!isset($objattr['spellcheck']) || !$objattr['spellcheck']) {
184				$flags[] = self::FLAG_NO_SPELLCHECK;
185			}
186
187			if (isset($objattr['subtype']) && $objattr['subtype'] === 'PASSWORD') {
188				$flags[] = self::FLAG_PASSWORD;
189			}
190
191			if (isset($objattr['color'])) {
192				$this->mpdf->SetTColor($objattr['color']);
193			} else {
194				$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
195			}
196
197			$fieldalign = $rtlalign;
198
199			if (!empty($objattr['text_align'])) {
200				$fieldalign = $objattr['text_align'];
201				$val = $objattr['text'];
202			} else {
203				$val = $objattr['text'];
204			}
205
206			// mPDF 5.3.25
207			$js = [];
208			if (!empty($objattr['onCalculate'])) {
209				$js[] = ['C', $objattr['onCalculate']];
210			}
211			if (!empty($objattr['onValidate'])) {
212				$js[] = ['V', $objattr['onValidate']];
213			}
214			if (!empty($objattr['onFormat'])) {
215				$js[] = ['F', $objattr['onFormat']];
216			}
217			if (!empty($objattr['onKeystroke'])) {
218				$js[] = ['K', $objattr['onKeystroke']];
219			}
220
221			$this->SetFormText($w, $h, $objattr['fieldname'], $val, $val, $objattr['title'], $flags, $fieldalign, false, (isset($objattr['maxlength']) ? $objattr['maxlength'] : false), $js, (isset($objattr['background-col']) ? $objattr['background-col'] : false), (isset($objattr['border-col']) ? $objattr['border-col'] : false));
222			$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
223
224		} else {
225
226			$w -= $this->form_element_spacing['input']['outer']['h'] * 2 / $k;
227			$h -= $this->form_element_spacing['input']['outer']['v'] * 2 / $k;
228			$this->mpdf->x += $this->form_element_spacing['input']['outer']['h'] / $k;
229			$this->mpdf->y += $this->form_element_spacing['input']['outer']['v'] / $k;
230			// Chop texto to max length $w-inner-padding
231			while ($this->mpdf->GetStringWidth($texto) > $w - ($this->form_element_spacing['input']['inner']['h'] * 2)) {
232				$texto = mb_substr($texto, 0, mb_strlen($texto, $this->mpdf->mb_enc) - 1, $this->mpdf->mb_enc);
233			}
234
235			// DIRECTIONALITY
236			if (preg_match('/([' . $this->mpdf->pregRTLchars . '])/u', $texto)) {
237				$this->mpdf->biDirectional = true;
238			} // *RTL*
239			// Use OTL OpenType Table Layout - GSUB & GPOS
240			if (!empty($this->mpdf->CurrentFont['useOTL'])) {
241				$texto = $this->otl->applyOTL($texto, $this->mpdf->CurrentFont['useOTL']);
242				$OTLdata = $this->otl->OTLdata;
243			}
244
245			$this->mpdf->magic_reverse_dir($texto, $this->mpdf->directionality, $OTLdata);
246
247			$this->mpdf->SetLineWidth(0.2 / $k);
248			if (!empty($objattr['disabled'])) {
249				$this->mpdf->SetFColor($this->colorConverter->convert(225, $this->mpdf->PDFAXwarnings));
250				$this->mpdf->SetTColor($this->colorConverter->convert(127, $this->mpdf->PDFAXwarnings));
251			} elseif (!empty($objattr['readonly'])) {
252				$this->mpdf->SetFColor($this->colorConverter->convert(225, $this->mpdf->PDFAXwarnings));
253				$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
254			} else {
255				$this->mpdf->SetFColor($this->colorConverter->convert(250, $this->mpdf->PDFAXwarnings));
256				$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
257			}
258			$this->mpdf->Cell($w, $h, $texto, 1, 0, $rtlalign, 1, '', 0, $this->form_element_spacing['input']['inner']['h'] / $k, $this->form_element_spacing['input']['inner']['h'] / $k, 'M', 0, false, $OTLdata);
259			$this->mpdf->SetFColor($this->colorConverter->convert(255, $this->mpdf->PDFAXwarnings));
260			$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
261		}
262	}
263
264	function print_ob_textarea($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir)
265	{
266		// TEXTAREA
267		if ($this->mpdf->useActiveForms) {
268
269			$flags = [self::FLAG_TEXTAREA];
270			if (!empty($objattr['disabled']) || !empty($objattr['readonly'])) {
271				$flags[] = self::FLAG_READONLY;
272			}
273			if (!empty($objattr['disabled'])) {
274				$flags[] = self::FLAG_NO_EXPORT;
275				$objattr['color'] = [3, 128, 128, 128];   // gray out disabled
276			}
277			if (!empty($objattr['required'])) {
278				$flags[] = self::FLAG_REQUIRED;
279			}
280			if (!isset($objattr['spellcheck']) || !$objattr['spellcheck']) {
281				$flags[] = self::FLAG_NO_SPELLCHECK;
282			}
283			if (!empty($objattr['donotscroll'])) {
284				$flags[] = self::FLAG_NO_SCROLL;
285			}
286			if (isset($objattr['color'])) {
287				$this->mpdf->SetTColor($objattr['color']);
288			} else {
289				$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
290			}
291			$fieldalign = $rtlalign;
292			if ($texto === ' ') {
293				$texto = '';
294			} // mPDF 5.3.24
295			if (!empty($objattr['text_align'])) {
296				$fieldalign = $objattr['text_align'];
297			}
298			// mPDF 5.3.25
299			$js = [];
300			if (!empty($objattr['onCalculate'])) {
301				$js[] = ['C', $objattr['onCalculate']];
302			}
303			if (!empty($objattr['onValidate'])) {
304				$js[] = ['V', $objattr['onValidate']];
305			}
306			if (!empty($objattr['onFormat'])) {
307				$js[] = ['F', $objattr['onFormat']];
308			}
309			if (!empty($objattr['onKeystroke'])) {
310				$js[] = ['K', $objattr['onKeystroke']];
311			}
312			$this->SetFormText($w, $h, $objattr['fieldname'], $texto, $texto, (isset($objattr['title']) ? $objattr['title'] : ''), $flags, $fieldalign, false, -1, $js, (isset($objattr['background-col']) ? $objattr['background-col'] : false), (isset($objattr['border-col']) ? $objattr['border-col'] : false));
313			$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
314		} else {
315			$w -= $this->form_element_spacing['textarea']['outer']['h'] * 2 / $k;
316			$h -= $this->form_element_spacing['textarea']['outer']['v'] * 2 / $k;
317			$this->mpdf->x += $this->form_element_spacing['textarea']['outer']['h'] / $k;
318			$this->mpdf->y += $this->form_element_spacing['textarea']['outer']['v'] / $k;
319			$this->mpdf->SetLineWidth(0.2 / $k);
320			if (!empty($objattr['disabled'])) {
321				$this->mpdf->SetFColor($this->colorConverter->convert(225, $this->mpdf->PDFAXwarnings));
322				$this->mpdf->SetTColor($this->colorConverter->convert(127, $this->mpdf->PDFAXwarnings));
323			} elseif (!empty($objattr['readonly'])) {
324				$this->mpdf->SetFColor($this->colorConverter->convert(225, $this->mpdf->PDFAXwarnings));
325				$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
326			} else {
327				$this->mpdf->SetFColor($this->colorConverter->convert(250, $this->mpdf->PDFAXwarnings));
328				$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
329			}
330			$this->mpdf->Rect($this->mpdf->x, $this->mpdf->y, $w, $h, 'DF');
331			$ClipPath = sprintf('q %.3F %.3F %.3F %.3F re W n ', $this->mpdf->x * Mpdf::SCALE, ($this->mpdf->h - $this->mpdf->y) * Mpdf::SCALE, $w * Mpdf::SCALE, -$h * Mpdf::SCALE);
332			$this->writer->write($ClipPath);
333
334			$w -= $this->form_element_spacing['textarea']['inner']['h'] * 2 / $k;
335			$this->mpdf->x += $this->form_element_spacing['textarea']['inner']['h'] / $k;
336			$this->mpdf->y += $this->form_element_spacing['textarea']['inner']['v'] / $k;
337
338			if ($texto != '') {
339				$this->mpdf->MultiCell($w, $this->mpdf->FontSize * $this->textarea_lineheight, $texto, 0, '', 0, '', $blockdir, true, $objattr['OTLdata'], $objattr['rows']);
340			}
341			$this->writer->write('Q');
342			$this->mpdf->SetFColor($this->colorConverter->convert(255, $this->mpdf->PDFAXwarnings));
343			$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
344		}
345	}
346
347	function print_ob_select($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir)
348	{
349		// SELECT
350		if ($this->mpdf->useActiveForms) {
351			$flags = [];
352			if (!empty($objattr['disabled'])) {
353				$flags[] = self::FLAG_READONLY;
354				$flags[] = self::FLAG_NO_EXPORT;
355				$objattr['color'] = [3, 128, 128, 128]; // gray out disabled
356			}
357			if (!empty($objattr['required'])) {
358				$flags[] = self::FLAG_REQUIRED;
359			}
360			if (!empty($objattr['multiple']) && isset($objattr['size']) && $objattr['size'] > 1) {
361				$flags[] = self::FLAG_MULTISELECT;
362			}
363			if (isset($objattr['size']) && $objattr['size'] < 2) {
364				$flags[] = self::FLAG_COMBOBOX;
365				if (!empty($objattr['editable'])) {
366					$flags[] = self::FLAG_EDITABLE;
367				}
368			}
369			// only allow spellcheck if combo and editable
370			if ((!isset($objattr['spellcheck']) || !$objattr['spellcheck']) || (isset($objattr['size']) && $objattr['size'] > 1) || (!isset($objattr['editable']) || !$objattr['editable'])) {
371				$flags[] = self::FLAG_NO_SPELLCHECK;
372			}
373			if (isset($objattr['subtype']) && $objattr['subtype'] === 'PASSWORD') {
374				$flags[] = self::FLAG_PASSWORD;
375			}
376			if (!empty($objattr['onChange'])) {
377				$js = $objattr['onChange'];
378			} else {
379				$js = '';
380			} // mPDF 5.3.37
381			$data = ['VAL' => [], 'OPT' => [], 'SEL' => [],];
382			if (isset($objattr['items'])) {
383				for ($i = 0; $i < count($objattr['items']); $i++) {
384					$item = $objattr['items'][$i];
385					$data['VAL'][] = (isset($item['exportValue']) ? $item['exportValue'] : '');
386					$data['OPT'][] = (isset($item['content']) ? $item['content'] : '');
387					if (!empty($item['selected'])) {
388						$data['SEL'][] = $i;
389					}
390				}
391			}
392			if (count($data['SEL']) === 0 && $this->formSelectDefaultOption) {
393				$data['SEL'][] = 0;
394			}
395			if (isset($objattr['color'])) {
396				$this->mpdf->SetTColor($objattr['color']);
397			} else {
398				$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
399			}
400			$this->SetFormChoice($w, $h, $objattr['fieldname'], $flags, $data, $rtlalign, $js);
401			$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
402		} else {
403			$this->mpdf->SetLineWidth(0.2 / $k);
404			if (!empty($objattr['disabled'])) {
405				$this->mpdf->SetFColor($this->colorConverter->convert(225, $this->mpdf->PDFAXwarnings));
406				$this->mpdf->SetTColor($this->colorConverter->convert(127, $this->mpdf->PDFAXwarnings));
407			} else {
408				$this->mpdf->SetFColor($this->colorConverter->convert(250, $this->mpdf->PDFAXwarnings));
409				$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
410			}
411			$w -= $this->form_element_spacing['select']['outer']['h'] * 2 / $k;
412			$h -= $this->form_element_spacing['select']['outer']['v'] * 2 / $k;
413			$this->mpdf->x += $this->form_element_spacing['select']['outer']['h'] / $k;
414			$this->mpdf->y += $this->form_element_spacing['select']['outer']['v'] / $k;
415
416			// DIRECTIONALITY
417			if (preg_match('/([' . $this->mpdf->pregRTLchars . '])/u', $texto)) {
418				$this->mpdf->biDirectional = true;
419			} // *RTL*
420
421			$this->mpdf->magic_reverse_dir($texto, $this->mpdf->directionality, $objattr['OTLdata']);
422
423			$this->mpdf->Cell($w - ($this->mpdf->FontSize * 1.4), $h, $texto, 1, 0, $rtlalign, 1, '', 0, $this->form_element_spacing['select']['inner']['h'] / $k, $this->form_element_spacing['select']['inner']['h'] / $k, 'M', 0, false, $objattr['OTLdata']);
424			$this->mpdf->SetFColor($this->colorConverter->convert(190, $this->mpdf->PDFAXwarnings));
425			$save_font = $this->mpdf->FontFamily;
426			$save_currentfont = $this->mpdf->currentfontfamily;
427			if ($this->mpdf->PDFA || $this->mpdf->PDFX) {
428				if (($this->mpdf->PDFA && !$this->mpdf->PDFAauto) || ($this->mpdf->PDFX && !$this->mpdf->PDFXauto)) {
429					$this->mpdf->PDFAXwarnings[] = 'Core Adobe font Zapfdingbats cannot be embedded in mPDF - used in Form element: Select - which is required for PDFA1-b or PDFX/1-a. (Different character/font will be substituted.)';
430				}
431				$this->mpdf->SetFont('sans');
432				if ($this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 9660)) {
433					$down = "\xe2\x96\xbc";
434				} else {
435					$down = '=';
436				}
437				$this->mpdf->Cell($this->mpdf->FontSize * 1.4, $h, $down, 1, 0, 'C', 1);
438			} else {
439				$this->mpdf->SetFont('czapfdingbats');
440				$this->mpdf->Cell($this->mpdf->FontSize * 1.4, $h, chr(116), 1, 0, 'C', 1);
441			}
442			$this->mpdf->SetFont($save_font);
443			$this->mpdf->currentfontfamily = $save_currentfont;
444			$this->mpdf->SetFColor($this->colorConverter->convert(255, $this->mpdf->PDFAXwarnings));
445			$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
446		}
447	}
448
449	function print_ob_imageinput($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $is_table)
450	{
451		// INPUT/BUTTON as IMAGE
452		if ($this->mpdf->useActiveForms) {
453			$flags = [];
454			if (!empty($objattr['disabled'])) {
455				$flags[] = self::FLAG_READONLY;
456				$flags[] = self::FLAG_NO_EXPORT;
457			}
458			if (!empty($objattr['onClick'])) {
459				$js = $objattr['onClick'];
460			} else {
461				$js = '';
462			}
463			$this->SetJSButton($w, $h, $objattr['fieldname'], (isset($objattr['value']) ? $objattr['value'] : ''), $js, $objattr['ID'], $objattr['title'], $flags, (isset($objattr['Indexed']) ? $objattr['Indexed'] : false));
464		} else {
465			$this->mpdf->y = $objattr['INNER-Y'];
466			$this->writer->write(sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q', $objattr['INNER-WIDTH'] * Mpdf::SCALE, $objattr['INNER-HEIGHT'] * Mpdf::SCALE, $objattr['INNER-X'] * Mpdf::SCALE, ($this->mpdf->h - ($objattr['INNER-Y'] + $objattr['INNER-HEIGHT'] )) * Mpdf::SCALE, $objattr['ID']));
467			if (!empty($objattr['BORDER-WIDTH'])) {
468				$this->mpdf->PaintImgBorder($objattr, $is_table);
469			}
470		}
471	}
472
473	function print_ob_button($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir)
474	{
475		// BUTTON
476		if ($this->mpdf->useActiveForms) {
477			$flags = [];
478			if (!empty($objattr['disabled'])) {
479				$flags[] = self::FLAG_READONLY;
480				$flags[] = self::FLAG_NO_EXPORT;
481				$objattr['color'] = [3, 128, 128, 128];
482			}
483			if (isset($objattr['color'])) {
484				$this->mpdf->SetTColor($objattr['color']);
485			} else {
486				$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
487			}
488			if (isset($objattr['subtype'])) {
489				if ($objattr['subtype'] === 'RESET') {
490					$this->SetFormButtonText($objattr['value']);
491					$this->SetFormReset($w, $h, $objattr['fieldname'], $objattr['value'], $objattr['title'], $flags, (isset($objattr['background-col']) ? $objattr['background-col'] : false), (isset($objattr['border-col']) ? $objattr['border-col'] : false), (isset($objattr['noprint']) ? $objattr['noprint'] : false));
492				} elseif ($objattr['subtype'] === 'SUBMIT') {
493					$url = $this->formAction;
494					$type = $this->formExportType;
495					$method = $this->formMethod;
496					$this->SetFormButtonText($objattr['value']);
497					$this->SetFormSubmit($w, $h, $objattr['fieldname'], $objattr['value'], $url, $objattr['title'], $type, $method, $flags, (isset($objattr['background-col']) ? $objattr['background-col'] : false), (isset($objattr['border-col']) ? $objattr['border-col'] : false), (isset($objattr['noprint']) ? $objattr['noprint'] : false));
498				} elseif ($objattr['subtype'] === 'BUTTON') {
499					$this->SetFormButtonText($objattr['value']);
500					if (isset($objattr['onClick']) && $objattr['onClick']) {
501						$js = $objattr['onClick'];
502					} else {
503						$js = '';
504					}
505					$this->SetJSButton($w, $h, $objattr['fieldname'], $objattr['value'], $js, 0, $objattr['title'], $flags, false, (isset($objattr['background-col']) ? $objattr['background-col'] : false), (isset($objattr['border-col']) ? $objattr['border-col'] : false), (isset($objattr['noprint']) ? $objattr['noprint'] : false));
506				}
507			}
508			$this->mpdf->SetTColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
509		} else {
510			$this->mpdf->SetLineWidth(0.2 / $k);
511			$this->mpdf->SetFColor($this->colorConverter->convert(190, $this->mpdf->PDFAXwarnings));
512			$w -= $this->form_element_spacing['button']['outer']['h'] * 2 / $k;
513			$h -= $this->form_element_spacing['button']['outer']['v'] * 2 / $k;
514			$this->mpdf->x += $this->form_element_spacing['button']['outer']['h'] / $k;
515			$this->mpdf->y += $this->form_element_spacing['button']['outer']['v'] / $k;
516			$this->mpdf->RoundedRect($this->mpdf->x, $this->mpdf->y, $w, $h, 0.5 / $k, 'DF');
517			$w -= $this->form_element_spacing['button']['inner']['h'] * 2 / $k;
518			$h -= $this->form_element_spacing['button']['inner']['v'] * 2 / $k;
519			$this->mpdf->x += $this->form_element_spacing['button']['inner']['h'] / $k;
520			$this->mpdf->y += $this->form_element_spacing['button']['inner']['v'] / $k;
521
522			// DIRECTIONALITY
523			if (preg_match('/([' . $this->mpdf->pregRTLchars . '])/u', $texto)) {
524				$this->mpdf->biDirectional = true;
525			} // *RTL*
526			// Use OTL OpenType Table Layout - GSUB & GPOS
527			if (!empty($this->mpdf->CurrentFont['useOTL'])) {
528				$texto = $this->otl->applyOTL($texto, $this->mpdf->CurrentFont['useOTL']);
529				$OTLdata = $this->otl->OTLdata;
530			}
531
532			$this->mpdf->magic_reverse_dir($texto, $this->mpdf->directionality, $OTLdata);
533
534			$this->mpdf->Cell($w, $h, $texto, '', 0, 'C', 0, '', 0, 0, 0, 'M', 0, false, $OTLdata);
535			$this->mpdf->SetFColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
536		}
537	}
538
539	function print_ob_checkbox($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $x, $y)
540	{
541		// CHECKBOX
542		if ($this->mpdf->useActiveForms) {
543			$flags = [];
544			if (!empty($objattr['disabled'])) {
545				$flags[] = self::FLAG_READONLY;
546				$flags[] = self::FLAG_NO_EXPORT;
547			}
548			$checked = false;
549			if (!empty($objattr['checked'])) {
550				$checked = true;
551			}
552			if ($this->formUseZapD) {
553				$save_font = $this->mpdf->FontFamily;
554				$save_currentfont = $this->mpdf->currentfontfamily;
555				$this->mpdf->SetFont('czapfdingbats');
556			}
557			$this->SetCheckBox($w, $h, $objattr['fieldname'], $objattr['value'], $objattr['title'], $checked, $flags, (isset($objattr['disabled']) ? $objattr['disabled'] : false));
558			if ($this->formUseZapD) {
559				$this->mpdf->SetFont($save_font);
560				$this->mpdf->currentfontfamily = $save_currentfont;
561			}
562		} else {
563			$iw = $w * 0.7;
564			$ih = $h * 0.7;
565			$lx = $x + (($w - $iw) / 2);
566			$ty = $y + (($h - $ih) / 2);
567			$rx = $lx + $iw;
568			$by = $ty + $ih;
569			$this->mpdf->SetLineWidth(0.2 / $k);
570			if (!empty($objattr['disabled'])) {
571				$this->mpdf->SetFColor($this->colorConverter->convert(225, $this->mpdf->PDFAXwarnings));
572				$this->mpdf->SetDColor($this->colorConverter->convert(127, $this->mpdf->PDFAXwarnings));
573			} else {
574				$this->mpdf->SetFColor($this->colorConverter->convert(250, $this->mpdf->PDFAXwarnings));
575				$this->mpdf->SetDColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
576			}
577			$this->mpdf->Rect($lx, $ty, $iw, $ih, 'DF');
578			if (!empty($objattr['checked'])) {
579				//Round join and cap
580				$this->mpdf->SetLineCap(1);
581				$this->mpdf->Line($lx, $ty, $rx, $by);
582				$this->mpdf->Line($lx, $by, $rx, $ty);
583				//Set line cap style back to square
584				$this->mpdf->SetLineCap();
585			}
586			$this->mpdf->SetFColor($this->colorConverter->convert(255, $this->mpdf->PDFAXwarnings));
587			$this->mpdf->SetDColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
588		}
589	}
590
591	function print_ob_radio($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $x, $y)
592	{
593		// RADIO
594		if ($this->mpdf->useActiveForms) {
595			$flags = [];
596			if (!empty($objattr['disabled'])) {
597				$flags[] = self::FLAG_READONLY;
598				$flags[] = self::FLAG_NO_EXPORT;
599			}
600			$checked = false;
601			if (!empty($objattr['checked'])) {
602				$checked = true;
603			}
604			if ($this->formUseZapD) {
605				$save_font = $this->mpdf->FontFamily;
606				$save_currentfont = $this->mpdf->currentfontfamily;
607				$this->mpdf->SetFont('czapfdingbats');
608			}
609			$this->SetRadio($w, $h, $objattr['fieldname'], $objattr['value'], (isset($objattr['title']) ? $objattr['title'] : ''), $checked, $flags, (isset($objattr['disabled']) ? $objattr['disabled'] : false));
610			if ($this->formUseZapD) {
611				$this->mpdf->SetFont($save_font);
612				$this->mpdf->currentfontfamily = $save_currentfont;
613			}
614		} else {
615			$this->mpdf->SetLineWidth(0.2 / $k);
616			$radius = $this->mpdf->FontSize * 0.35;
617			$cx = $x + ($w / 2);
618			$cy = $y + ($h / 2);
619			$color = $this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings);
620			if (isset($objattr['color']) && $objattr['color']) {
621				$color = $objattr['color'];
622			}
623			if (!empty($objattr['disabled'])) {
624				$this->mpdf->SetFColor($this->colorConverter->convert(127, $this->mpdf->PDFAXwarnings));
625				$this->mpdf->SetDColor($this->colorConverter->convert(127, $this->mpdf->PDFAXwarnings));
626			} else {
627				$this->mpdf->SetFColor($color);
628				$this->mpdf->SetDColor($color);
629			}
630			$this->mpdf->Circle($cx, $cy, $radius, 'D');
631			if (!empty($objattr['checked'])) {
632				$this->mpdf->Circle($cx, $cy, $radius * 0.4, 'DF');
633			}
634			$this->mpdf->SetFColor($this->colorConverter->convert(255, $this->mpdf->PDFAXwarnings));
635			$this->mpdf->SetDColor($this->colorConverter->convert(0, $this->mpdf->PDFAXwarnings));
636		}
637	}
638
639	private function getCountItems($form)
640	{
641		$total = 1;
642		if ($form['typ'] === 'Tx') {
643			if (isset($this->array_form_text_js[$form['T']])) {
644				if (isset($this->array_form_text_js[$form['T']]['F'])) {
645					$total++;
646				}
647				if (isset($this->array_form_text_js[$form['T']]['K'])) {
648					$total++;
649				}
650				if (isset($this->array_form_text_js[$form['T']]['V'])) {
651					$total++;
652				}
653				if (isset($this->array_form_text_js[$form['T']]['C'])) {
654					$total++;
655				}
656			}
657		}
658
659		if ($form['typ'] === 'Bt') {
660			if (isset($this->array_form_button_js[$form['T']])) {
661				$total++;
662			}
663			if (isset($this->form_button_icon[$form['T']])) {
664				$total++;
665				if ($this->form_button_icon[$form['T']]['Indexed']) {
666					$total++;
667				}
668			}
669			if ($form['subtype'] === 'radio') {
670				$total+=2;
671			} elseif ($form['subtype'] === 'checkbox') {
672				$total++;
673				if (!$this->formUseZapD) {
674					$total++;
675				}
676			}
677		}
678		if ($form['typ'] === 'Ch') {
679			if (isset($this->array_form_choice_js[$form['T']])) {
680				$total++;
681			}
682		}
683		return $total;
684	}
685
686	// In _putpages
687	function countPageForms($n, &$totaladdnum)
688	{
689		foreach ($this->forms as $form) {
690			if ($form['page'] == $n) {
691				$totaladdnum += $this->getCountItems($form);
692			}
693		}
694	}
695
696	// In _putpages
697	function addFormIds($n, &$s, &$annotid)
698	{
699		foreach ($this->forms as $form) {
700			if ($form['page'] == $n) {
701				$s .= $annotid . ' 0 R ';
702				$annotid += $this->getCountItems($form);
703			}
704		}
705	}
706
707	// In _putannots
708	function _putFormItems($n, $hPt)
709	{
710		foreach ($this->forms as $val) {
711			if ($val['page'] == $n) {
712				if ($val['typ'] === 'Tx') {
713					$this->_putform_tx($val, $hPt);
714				}
715				if ($val['typ'] === 'Ch') {
716					$this->_putform_ch($val, $hPt);
717				}
718				if ($val['typ'] === 'Bt') {
719					$this->_putform_bt($val, $hPt);
720				}
721			}
722		}
723	}
724
725	// In _putannots
726	function _putRadioItems($n)
727	{
728		// Output Radio Groups
729		$key = 1;
730		foreach ($this->form_radio_groups as $name => $frg) {
731			$this->writer->object();
732			$this->pdf_acro_array .= $this->mpdf->n . ' 0 R ';
733			$this->writer->write('<<');
734			$this->writer->write('/Type /Annot ');
735			$this->writer->write('/Subtype /Widget');
736			$this->writer->write('/NM ' . $this->writer->string(sprintf('%04u-%04u', $n, 3000 + $key++)));
737			$this->writer->write('/M ' . $this->writer->string('D:' . date('YmdHis')));
738			$this->writer->write('/Rect [0 0 0 0] ');
739			$this->writer->write('/FT /Btn ');
740			if (!empty($frg['disabled'])) {
741				$flags = [self::FLAG_READONLY, self::FLAG_NO_EXPORT, self::FLAG_RADIO, self::FLAG_NOTOGGLEOFF];
742			} else {
743				$flags = [self::FLAG_RADIO, self::FLAG_NOTOGGLEOFF];
744			}
745			$this->writer->write('/Ff ' . $this->_setflag($flags));
746			$kstr = '';
747			// $optstr = '';
748			foreach ($frg['kids'] as $kid) {
749				$kstr .= $this->forms[$kid['n']]['obj'] . ' 0 R ';
750				//		$optstr .= ' '.$this->writer->string($kid['OPT']).' ';
751			}
752			$this->writer->write('/Kids [ ' . $kstr . ' ] '); // 11 0 R 12 0 R etc.
753			//	$this->writer->write('/Opt [ '.$optstr.' ] ');
754			//V entry holds index corresponding to the appearance state of
755			//whichever child field is currently in the on state = or Off
756			if (isset($frg['on'])) {
757				$state = $frg['on'];
758			} else {
759				$state = 'Off';
760			}
761			$this->writer->write('/V /' . $state . ' ');
762			$this->writer->write('/DV /' . $state . ' ');
763			$this->writer->write('/T ' . $this->writer->string($name) . ' ');
764			$this->writer->write('>>');
765			$this->writer->write('endobj');
766		}
767	}
768
769	function _putFormsCatalog()
770	{
771		if (isset($this->pdf_acro_array)) {
772			$this->writer->write('/AcroForm << /DA (/F1 0 Tf 0 g )');
773			$this->writer->write('/Q 0');
774			$this->writer->write('/Fields [' . $this->pdf_acro_array . ']');
775			$f = '';
776			foreach ($this->form_fonts as $fn) {
777				if (is_array($this->mpdf->fonts[$fn]['n'])) {
778					throw new \Mpdf\MpdfException('Cannot use fonts with SMP or SIP characters for interactive Form elements');
779				}
780				$f .= '/F' . $this->mpdf->fonts[$fn]['i'] . ' ' . $this->mpdf->fonts[$fn]['n'] . ' 0 R ';
781			}
782			$this->writer->write('/DR << /Font << ' . $f . ' >> >>');
783			// CO Calculation Order
784			if ($this->pdf_array_co) {
785				$this->writer->write('/CO [' . $this->pdf_array_co . ']');
786			}
787			$this->writer->write('/NeedAppearances true');
788			$this->writer->write('>>');
789		}
790	}
791
792	function SetFormButtonJS($name, $js)
793	{
794		$js = str_replace("\t", ' ', trim($js));
795		if (isset($name) && isset($js)) {
796			$this->array_form_button_js[$this->writer->escape($name)] = [
797				'js' => $js
798			];
799		}
800	}
801
802	function SetFormChoiceJS($name, $js)
803	{
804		$js = str_replace("\t", ' ', trim($js));
805		if (isset($name) && isset($js)) {
806			$this->array_form_choice_js[$this->writer->escape($name)] = [
807				'js' => $js
808			];
809		}
810	}
811
812	function SetFormTextJS($name, $js)
813	{
814		for ($i = 0; $i < count($js); $i++) {
815			$j = str_replace("\t", ' ', trim($js[$i][1]));
816			$format = $js[$i][0];
817			if ($name) {
818				$this->array_form_text_js[$this->writer->escape($name)][$format] = ['js' => $j];
819			}
820		}
821	}
822
823	function Win1252ToPDFDocEncoding($txt)
824	{
825		$Win1252ToPDFDocEncoding = [
826			chr(0200) => chr(0240), chr(0214) => chr(0226), chr(0212) => chr(0227), chr(0237) => chr(0230),
827			chr(0225) => chr(0200), chr(0210) => chr(0032), chr(0206) => chr(0201), chr(0207) => chr(0202),
828			chr(0205) => chr(0203), chr(0227) => chr(0204), chr(0226) => chr(0205), chr(0203) => chr(0206),
829			chr(0213) => chr(0210), chr(0233) => chr(0211), chr(0211) => chr(0213), chr(0204) => chr(0214),
830			chr(0223) => chr(0215), chr(0224) => chr(0216), chr(0221) => chr(0217), chr(0222) => chr(0220),
831			chr(0202) => chr(0221), chr(0232) => chr(0235), chr(0230) => chr(0037), chr(0231) => chr(0222),
832			chr(0216) => chr(0231), chr(0240) => chr(0040)
833		]; // mPDF 5.3.46
834		return strtr($txt, $Win1252ToPDFDocEncoding);
835	}
836
837	function SetFormText($w, $h, $name, $value = '', $default = '', $title = '', $flags = [], $align = 'L', $hidden = false, $maxlen = -1, $js = '', $background_col = false, $border_col = false)
838	{
839		$this->formCount++;
840		if ($align === 'C') {
841			$align = '1';
842		} elseif ($align === 'R') {
843			$align = '2';
844		} else {
845			$align = '0';
846		}
847		if ($maxlen < 1) {
848			$maxlen = false;
849		}
850		if (!preg_match('/^[a-zA-Z0-9_:\-]+$/', $name)) {
851			throw new \Mpdf\MpdfException('Field [' . $name . '] must have a name attribute, which can only contain letters, numbers, colon(:), undersore(_) or hyphen(-)');
852		}
853		if ($this->mpdf->onlyCoreFonts) {
854			$value = $this->Win1252ToPDFDocEncoding($value);
855			$default = $this->Win1252ToPDFDocEncoding($default);
856			$title = $this->Win1252ToPDFDocEncoding($title);
857		} else {
858			if (isset($this->mpdf->CurrentFont['subset'])) {
859				$this->mpdf->UTF8StringToArray($value); // Add characters to font subset
860				$this->mpdf->UTF8StringToArray($default); // Add characters to font subset
861				$this->mpdf->UTF8StringToArray($title); // Add characters to font subset
862			}
863			if ($value) {
864				$value = $this->writer->utf8ToUtf16BigEndian($value);
865			}
866			if ($default) {
867				$default = $this->writer->utf8ToUtf16BigEndian($default);
868			}
869			$title = $this->writer->utf8ToUtf16BigEndian($title);
870		}
871		if ($background_col) {
872			$bg_c = $this->mpdf->SetColor($background_col, 'CodeOnly');
873		} else {
874			$bg_c = $this->form_background_color;
875		}
876		if ($border_col) {
877			$bc_c = $this->mpdf->SetColor($border_col, 'CodeOnly');
878		} else {
879			$bc_c = $this->form_border_color;
880		}
881
882		$f = [
883			'n' => $this->formCount,
884			'typ' => 'Tx',
885			'page' => $this->mpdf->page,
886			'x' => $this->mpdf->x,
887			'y' => $this->mpdf->y,
888			'w' => $w,
889			'h' => $h,
890			'T' => $name,
891			'FF' => $flags,
892			'V' => $value,
893			'DV' => $default,
894			'TU' => $title,
895			'hidden' => $hidden,
896			'Q' => $align,
897			'maxlen' => $maxlen,
898			'BS_W' => $this->form_border_width,
899			'BS_S' => $this->form_border_style,
900			'BC_C' => $bc_c,
901			'BG_C' => $bg_c,
902			'style' => [
903				'font' => $this->mpdf->FontFamily,
904				'fontsize' => $this->mpdf->FontSizePt,
905				'fontcolor' => $this->mpdf->TextColor,
906			]
907		];
908
909		if (is_array($js) && count($js) > 0) {
910			$this->SetFormTextJS($name, $js);
911		} // mPDF 5.3.25
912		if ($this->mpdf->keep_block_together) {
913			$this->mpdf->ktForms[] = $f;
914		} elseif ($this->mpdf->writingHTMLheader || $this->mpdf->writingHTMLfooter) {
915			$this->mpdf->HTMLheaderPageForms[] = $f;
916		} else {
917			if ($this->mpdf->ColActive) {
918				$this->mpdf->columnbuffer[] = [
919					's' => 'ACROFORM',
920					'col' => $this->mpdf->CurrCol,
921					'x' => $this->mpdf->x,
922					'y' => $this->mpdf->y,
923					'h' => $h
924				];
925				$this->mpdf->columnForms[$this->mpdf->CurrCol][(int) $this->mpdf->x][(int) $this->mpdf->y] = $this->formCount;
926			}
927			$this->forms[$this->formCount] = $f;
928		}
929		if (!in_array($this->mpdf->FontFamily, $this->form_fonts)) {
930			$this->form_fonts[] = $this->mpdf->FontFamily;
931			$this->mpdf->fonts[$this->mpdf->FontFamily]['used'] = true;
932		}
933		if (!$hidden) {
934			$this->mpdf->x += $w;
935		}
936	}
937
938	function SetFormChoice($w, $h, $name, $flags, $array, $align = 'L', $js = '')
939	{
940		$this->formCount++;
941		if ($this->mpdf->blk[$this->mpdf->blklvl]['direction'] === 'rtl') {
942			$align = '2';
943		} else {
944			$align = '0';
945		}
946		if (!preg_match('/^[a-zA-Z0-9_:\-]+$/', $name)) {
947			throw new \Mpdf\MpdfException('Field [' . $name . '] must have a name attribute, which can only contain letters, numbers, colon(:), undersore(_) or hyphen(-)');
948		}
949		if ($this->mpdf->onlyCoreFonts) {
950			for ($i = 0; $i < count($array['VAL']); $i++) {
951				$array['VAL'][$i] = $this->Win1252ToPDFDocEncoding($array['VAL'][$i]);
952				$array['OPT'][$i] = $this->Win1252ToPDFDocEncoding($array['OPT'][$i]);
953			}
954		} else {
955			for ($i = 0; $i < count($array['VAL']); $i++) {
956				if (isset($this->mpdf->CurrentFont['subset'])) {
957					$this->mpdf->UTF8StringToArray($array['VAL'][$i]); // Add characters to font subset
958					$this->mpdf->UTF8StringToArray($array['OPT'][$i]); // Add characters to font subset
959				}
960				if ($array['VAL'][$i]) {
961					$array['VAL'][$i] = $this->writer->utf8ToUtf16BigEndian($array['VAL'][$i]);
962				}
963				if ($array['OPT'][$i]) {
964					$array['OPT'][$i] = $this->writer->utf8ToUtf16BigEndian($array['OPT'][$i]);
965				}
966			}
967		}
968		$f = ['n' => $this->formCount,
969			'typ' => 'Ch',
970			'page' => $this->mpdf->page,
971			'x' => $this->mpdf->x,
972			'y' => $this->mpdf->y,
973			'w' => $w,
974			'h' => $h,
975			'T' => $name,
976			'OPT' => $array,
977			'FF' => $flags,
978			'Q' => $align,
979			'BS_W' => $this->form_border_width,
980			'BS_S' => $this->form_border_style,
981			'BC_C' => $this->form_border_color,
982			'BG_C' => $this->form_background_color,
983			'style' => [
984				'font' => $this->mpdf->FontFamily,
985				'fontsize' => $this->mpdf->FontSizePt,
986				'fontcolor' => $this->mpdf->TextColor,
987			]
988		];
989		if ($js) {
990			$this->SetFormChoiceJS($name, $js);
991		}
992		if ($this->mpdf->keep_block_together) {
993			$this->mpdf->ktForms[] = $f;
994		} elseif ($this->mpdf->writingHTMLheader || $this->mpdf->writingHTMLfooter) {
995			$this->mpdf->HTMLheaderPageForms[] = $f;
996		} else {
997			if ($this->mpdf->ColActive) {
998				$this->mpdf->columnbuffer[] = ['s' => 'ACROFORM', 'col' => $this->mpdf->CurrCol, 'x' => $this->mpdf->x, 'y' => $this->mpdf->y,
999					'h' => $h];
1000				$this->mpdf->columnForms[$this->mpdf->CurrCol][(int) $this->mpdf->x][(int) $this->mpdf->y] = $this->formCount;
1001			}
1002			$this->forms[$this->formCount] = $f;
1003		}
1004		if (!in_array($this->mpdf->FontFamily, $this->form_fonts)) {
1005			$this->form_fonts[] = $this->mpdf->FontFamily;
1006			$this->mpdf->fonts[$this->mpdf->FontFamily]['used'] = true;
1007		}
1008		$this->mpdf->x += $w;
1009	}
1010
1011	// CHECKBOX
1012	function SetCheckBox($w, $h, $name, $value, $title = '', $checked = false, $flags = [], $disabled = false)
1013	{
1014		$this->SetFormButton($w, $h, $name, $value, 'checkbox', $title, $flags, $checked, $disabled);
1015		$this->mpdf->x += $w;
1016	}
1017
1018	// RADIO
1019	function SetRadio($w, $h, $name, $value, $title = '', $checked = false, $flags = [], $disabled = false)
1020	{
1021		$this->SetFormButton($w, $h, $name, $value, 'radio', $title, $flags, $checked, $disabled);
1022		$this->mpdf->x += $w;
1023	}
1024
1025	function SetFormReset($w, $h, $name, $value = 'Reset', $title = '', $flags = [], $background_col = false, $border_col = false, $noprint = false)
1026	{
1027		if (!$name) {
1028			$name = 'Reset';
1029		}
1030		$this->SetFormButton($w, $h, $name, $value, 'reset', $title, $flags, false, false, $background_col, $border_col, $noprint);
1031		$this->mpdf->x += $w;
1032	}
1033
1034	function SetJSButton($w, $h, $name, $value, $js, $image_id = 0, $title = '', $flags = [], $indexed = false, $background_col = false, $border_col = false, $noprint = false)
1035	{
1036		$this->SetFormButton($w, $h, $name, $value, 'js_button', $title, $flags, false, false, $background_col, $border_col, $noprint);
1037		// pos => 1 = no caption, icon only; 0 = caption only
1038		if ($image_id) {
1039			$this->form_button_icon[$this->writer->escape($name)] = [
1040				'pos' => 1,
1041				'image_id' => $image_id,
1042				'Indexed' => $indexed,
1043			];
1044		}
1045		if ($js) {
1046			$this->SetFormButtonJS($name, $js);
1047		}
1048		$this->mpdf->x += $w;
1049	}
1050
1051	function SetFormSubmit($w, $h, $name, $value = 'Submit', $url = '', $title = '', $typ = 'html', $method = 'POST', $flags = [], $background_col = false, $border_col = false, $noprint = false)
1052	{
1053		if (!$name) {
1054			$name = 'Submit';
1055		}
1056
1057		$this->SetFormButton($w, $h, $name, $value, 'submit', $title, $flags, false, false, $background_col, $border_col, $noprint);
1058		$this->forms[$this->formCount]['URL'] = $url;
1059		$this->forms[$this->formCount]['method'] = $method;
1060		$this->forms[$this->formCount]['exporttype'] = $typ;
1061		$this->mpdf->x += $w;
1062	}
1063
1064	function SetFormButtonText($ca, $rc = '', $ac = '')
1065	{
1066		if ($this->mpdf->onlyCoreFonts) {
1067			$ca = $this->Win1252ToPDFDocEncoding($ca);
1068			if ($rc) {
1069				$rc = $this->Win1252ToPDFDocEncoding($rc);
1070			}
1071			if ($ac) {
1072				$ac = $this->Win1252ToPDFDocEncoding($ac);
1073			}
1074		} else {
1075			if (isset($this->mpdf->CurrentFont['subset'])) {
1076				$this->mpdf->UTF8StringToArray($ca); // Add characters to font subset
1077			}
1078			$ca = $this->writer->utf8ToUtf16BigEndian($ca);
1079			if ($rc) {
1080				if (isset($this->mpdf->CurrentFont['subset'])) {
1081					$this->mpdf->UTF8StringToArray($rc);
1082				}
1083				$rc = $this->writer->utf8ToUtf16BigEndian($rc);
1084			}
1085			if ($ac) {
1086				if (isset($this->mpdf->CurrentFont['subset'])) {
1087					$this->mpdf->UTF8StringToArray($ac);
1088				}
1089				$ac = $this->writer->utf8ToUtf16BigEndian($ac);
1090			}
1091		}
1092		$this->form_button_text = $ca;
1093		$this->form_button_text_over = $rc ?: $ca;
1094		$this->form_button_text_click = $ac ?: $ca;
1095	}
1096
1097	function SetFormButton($bb, $hh, $name, $value, $type, $title = '', $flags = [], $checked = false, $disabled = false, $background_col = false, $border_col = false, $noprint = false)
1098	{
1099		$this->formCount++;
1100		if (!preg_match('/^[a-zA-Z0-9_:\-]+$/', $name)) {
1101			throw new \Mpdf\MpdfException('Field [' . $name . '] must have a name attribute, which can only contain letters, numbers, colon(:), undersore(_) or hyphen(-)');
1102		}
1103		if (!$this->mpdf->onlyCoreFonts) {
1104			if (isset($this->mpdf->CurrentFont['subset'])) {
1105				$this->mpdf->UTF8StringToArray($title); // Add characters to font subset
1106				$this->mpdf->UTF8StringToArray($value); // Add characters to font subset
1107			}
1108			$title = $this->writer->utf8ToUtf16BigEndian($title);
1109			if ($type === 'checkbox') {
1110				$uvalue = $this->writer->utf8ToUtf16BigEndian($value);
1111			} elseif ($type === 'radio') {
1112				$uvalue = $this->writer->utf8ToUtf16BigEndian($value);
1113				$value = mb_convert_encoding($value, 'Windows-1252', 'UTF-8');
1114			} else {
1115				$value = $this->writer->utf8ToUtf16BigEndian($value);
1116				$uvalue = $value;
1117			}
1118		} else {
1119			$title = $this->Win1252ToPDFDocEncoding($title);
1120			$value = $this->Win1252ToPDFDocEncoding($value);     //// ??? not needed
1121			$uvalue = mb_convert_encoding($value, 'UTF-8', 'Windows-1252');
1122			$uvalue = $this->writer->utf8ToUtf16BigEndian($uvalue);
1123		}
1124		if ($type === 'radio' || $type === 'checkbox') {
1125			if (!preg_match('/^[a-zA-Z0-9_:\-\.]+$/', $value)) {
1126				throw new \Mpdf\MpdfException("Field '" . $name . "' must have a value, which can only contain letters, numbers, colon(:), underscore(_), hyphen(-) or period(.)");
1127			}
1128		}
1129		if ($type === 'radio') {
1130			if (!isset($this->form_radio_groups[$name])) {
1131				$this->form_radio_groups[$name] = [
1132					'page' => $this->mpdf->page,
1133					'kids' => [],
1134				];
1135			}
1136			$this->form_radio_groups[$name]['kids'][] = [
1137				'n' => $this->formCount, 'V' => $value, 'OPT' => $uvalue, 'disabled' => $disabled
1138			];
1139			if ($checked) {
1140				$this->form_radio_groups[$name]['on'] = $value;
1141			}
1142			// Disable the whole radio group if one is disabled, because of inconsistency in PDF readers
1143			if ($disabled) {
1144				$this->form_radio_groups[$name]['disabled'] = true;
1145			}
1146		}
1147		if ($type === 'checkbox') {
1148			$this->form_checkboxes = true;
1149		}
1150		if ($checked) {
1151			$activ = 1;
1152		} else {
1153			$activ = 0;
1154		}
1155		if ($background_col) {
1156			$bg_c = $this->mpdf->SetColor($background_col, 'CodeOnly');
1157		} else {
1158			$bg_c = $this->form_button_background_color;
1159		}
1160		if ($border_col) {
1161			$bc_c = $this->mpdf->SetColor($border_col, 'CodeOnly');
1162		} else {
1163			$bc_c = $this->form_button_border_color;
1164		}
1165		$f = ['n' => $this->formCount,
1166			'typ' => 'Bt',
1167			'page' => $this->mpdf->page,
1168			'subtype' => $type,
1169			'x' => $this->mpdf->x,
1170			'y' => $this->mpdf->y,
1171			'w' => $bb,
1172			'h' => $hh,
1173			'T' => $name,
1174			'V' => $value,
1175			'OPT' => $uvalue,
1176			'TU' => $title,
1177			'FF' => $flags,
1178			'CA' => $this->form_button_text,
1179			'RC' => $this->form_button_text_over,
1180			'AC' => $this->form_button_text_click,
1181			'BS_W' => $this->form_button_border_width,
1182			'BS_S' => $this->form_button_border_style,
1183			'BC_C' => $bc_c,
1184			'BG_C' => $bg_c,
1185			'activ' => $activ,
1186			'disabled' => $disabled,
1187			'noprint' => $noprint,
1188			'style' => [
1189				'font' => $this->mpdf->FontFamily,
1190				'fontsize' => $this->mpdf->FontSizePt,
1191				'fontcolor' => $this->mpdf->TextColor,
1192			]
1193		];
1194		if ($this->mpdf->keep_block_together) {
1195			$this->mpdf->ktForms[] = $f;
1196		} elseif ($this->mpdf->writingHTMLheader || $this->mpdf->writingHTMLfooter) {
1197			$this->mpdf->HTMLheaderPageForms[] = $f;
1198		} else {
1199			if ($this->mpdf->ColActive) {
1200				$this->mpdf->columnbuffer[] = ['s' => 'ACROFORM', 'col' => $this->mpdf->CurrCol, 'x' => $this->mpdf->x, 'y' => $this->mpdf->y,
1201					'h' => $hh];
1202				$this->mpdf->columnForms[$this->mpdf->CurrCol][(int) $this->mpdf->x][(int) $this->mpdf->y] = $this->formCount;
1203			}
1204			$this->forms[$this->formCount] = $f;
1205		}
1206		if (!in_array($this->mpdf->FontFamily, $this->form_fonts)) {
1207			$this->form_fonts[] = $this->mpdf->FontFamily;
1208			$this->mpdf->fonts[$this->mpdf->FontFamily]['used'] = true;
1209		}
1210
1211		$this->form_button_text = null;
1212		$this->form_button_text_over = null;
1213		$this->form_button_text_click = null;
1214	}
1215
1216	function SetFormBorderWidth($string)
1217	{
1218		switch ($string) {
1219			case 'S':
1220				$this->form_border_width = '1';
1221				break;
1222			case 'M':
1223				$this->form_border_width = '2';
1224				break;
1225			case 'B':
1226				$this->form_border_width = '3';
1227				break;
1228			case '0':
1229				$this->form_border_width = '0';
1230				break;
1231			default:
1232				$this->form_border_width = '0';
1233				break;
1234		}
1235	}
1236
1237	function SetFormBorderStyle($string)
1238	{
1239		switch ($string) {
1240			case 'S':
1241				$this->form_border_style = 'S';
1242				break;
1243			case 'D':
1244				$this->form_border_style = 'D /D [3]';
1245				break;
1246			case 'B':
1247				$this->form_border_style = 'B';
1248				break;
1249			case 'I':
1250				$this->form_border_style = 'I';
1251				break;
1252			case 'U':
1253				$this->form_border_style = 'U';
1254				break;
1255			default:
1256				$this->form_border_style = 'B';
1257				break;
1258		}
1259	}
1260
1261	function SetFormBorderColor($r, $g = -1, $b = -1)
1262	{
1263		$this->form_border_color = $this->getColor($r, $g, $b);
1264	}
1265
1266	function SetFormBackgroundColor($r, $g = -1, $b = -1)
1267	{
1268		$this->form_background_color = $this->getColor($r, $g, $b);
1269	}
1270
1271	private function getColor($r, $g = -1, $b = -1)
1272	{
1273		if (($r == 0 && $g == 0 && $b == 0) || $g == -1) {
1274			return sprintf('%.3F', $r / 255);
1275		}
1276		return sprintf('%.3F %.3F %.3F', $r / 255, $g / 255, $b / 255);
1277	}
1278
1279	function SetFormD($W, $S, $BC, $BG)
1280	{
1281		$this->SetFormBorderWidth($W);
1282		$this->SetFormBorderStyle($S);
1283		$this->SetFormBorderColor($BC);
1284		$this->SetFormBackgroundColor($BG);
1285	}
1286
1287	function _setflag($array)
1288	{
1289		$flag = 0;
1290		foreach ($array as $val) {
1291			$flag += 1 << ($val - 1);
1292		}
1293		return $flag;
1294	}
1295
1296	function _form_rect($x, $y, $w, $h, $hPt)
1297	{
1298		$x *= Mpdf::SCALE;
1299		$y = $hPt - ($y * Mpdf::SCALE);
1300		$x2 = $x + ($w * Mpdf::SCALE);
1301		$y2 = $y - ($h * Mpdf::SCALE);
1302
1303		return sprintf('%.3F %.3F %.3F %.3F', $x, $y2, $x2, $y);
1304	}
1305
1306	function _put_button_icon($array, $w, $h)
1307	{
1308		$info = true;
1309
1310		if (isset($array['image_id'])) {
1311			$info = false;
1312			foreach ($this->mpdf->images as $iid => $img) {
1313				if ($img['i'] == $array['image_id']) {
1314					$info = $this->mpdf->images[$iid];
1315					break;
1316				}
1317			}
1318		}
1319
1320		if (!$info) {
1321			throw new \Mpdf\MpdfException('Cannot find Button image');
1322		}
1323
1324		$this->writer->object();
1325		$this->writer->write('<<');
1326		$this->writer->write('/Type /XObject');
1327		$this->writer->write('/Subtype /Image');
1328		$this->writer->write('/BBox [0 0 1 1]');
1329		$this->writer->write('/Length ' . strlen($info['data']));
1330		$this->writer->write('/BitsPerComponent ' . $info['bpc']);
1331
1332		if ($info['cs'] === 'Indexed') {
1333			$this->writer->write('/ColorSpace [/Indexed /DeviceRGB ' . (strlen($info['pal']) / 3 - 1) . ' ' . ($this->mpdf->n + 1) . ' 0 R]');
1334		} else {
1335			$this->writer->write('/ColorSpace /' . $info['cs']);
1336			if ($info['cs'] === 'DeviceCMYK') {
1337				if ($info['type'] === 'jpg') {
1338					$this->writer->write('/Decode [1 0 1 0 1 0 1 0]');
1339				}
1340			}
1341		}
1342
1343		if (isset($info['f'])) {
1344			$this->writer->write('/Filter /' . $info['f']);
1345		}
1346
1347		if (isset($info['parms'])) {
1348			$this->writer->write($info['parms']);
1349		}
1350
1351		$this->writer->write('/Width ' . $info['w']);
1352		$this->writer->write('/Height ' . $info['h']);
1353		$this->writer->write('>>');
1354		$this->writer->stream($info['data']);
1355		$this->writer->write('endobj');
1356
1357		//Palette
1358		if ($info['cs'] === 'Indexed') {
1359			$filter = $this->mpdf->compress ? '/Filter /FlateDecode ' : '';
1360			$this->writer->object();
1361			$pal = $this->mpdf->compress ? gzcompress($info['pal']) : $info['pal'];
1362			$this->writer->write('<<' . $filter . '/Length ' . strlen($pal) . '>>');
1363			$this->writer->stream($pal);
1364			$this->writer->write('endobj');
1365		}
1366	}
1367
1368	function _putform_bt($form, $hPt)
1369	{
1370		$cc = 0;
1371		$put_js = 0;
1372		$put_icon = 0;
1373		$this->writer->object();
1374		$n = $this->mpdf->n;
1375
1376		if ($form['subtype'] !== 'radio') {
1377			$this->pdf_acro_array .= $n . ' 0 R '; // Add to /Field element
1378		}
1379
1380		$this->forms[$form['n']]['obj'] = $n;
1381		$this->writer->write('<<');
1382		$this->writer->write('/Type /Annot ');
1383		$this->writer->write('/Subtype /Widget');
1384		$this->writer->write('/NM ' . $this->writer->string(sprintf('%04u-%04u', $n, 7000 + $form['n'])));
1385		$this->writer->write('/M ' . $this->writer->string('D:' . date('YmdHis')));
1386		$this->writer->write('/Rect [ ' . $this->_form_rect($form['x'], $form['y'], $form['w'], $form['h'], $hPt) . ' ]');
1387
1388		$form['noprint'] ? $this->writer->write('/F 0 ') : $this->writer->write('/F 4 ');
1389
1390		$this->writer->write('/FT /Btn ');
1391		$this->writer->write('/H /P ');
1392
1393		if ($form['subtype'] !== 'radio') {  // mPDF 5.3.23
1394			$this->writer->write('/T ' . $this->writer->string($form['T']));
1395		}
1396
1397		$this->writer->write('/TU ' . $this->writer->string($form['TU']));
1398
1399		if (isset($this->form_button_icon[$form['T']])) {
1400			$form['BS_W'] = 0;
1401		}
1402
1403		if ($form['BS_W'] == 0) {
1404			$form['BC_C'] = $form['BG_C'];
1405		}
1406
1407		$bstemp = '';
1408		$bstemp .= '/W ' . $form['BS_W'] . ' ';
1409		$bstemp .= '/S /' . $form['BS_S'] . ' ';
1410		$temp = '';
1411		$temp .= '/BC [ ' . $form['BC_C'] . ' ] ';
1412		$temp .= '/BG [ ' . $form['BG_C'] . ' ] ';
1413
1414		if ($form['subtype'] === 'checkbox') {
1415
1416			if ($form['disabled']) {
1417				$radio_color = '0.5 0.5 0.5';
1418				$radio_background_color = '0.9 0.9 0.9';
1419			} else {
1420				$radio_color = $this->form_radio_color;
1421				$radio_background_color = $this->form_radio_background_color;
1422			}
1423
1424			$temp = '';
1425			$temp .= '/BC [ ' . $radio_color . ' ] ';
1426			$temp .= '/BG [ ' . $radio_background_color . ' ] ';
1427			$this->writer->write('/BS << /W 1 /S /S >>');
1428			$this->writer->write("/MK << $temp >>");
1429			$this->writer->write('/Ff ' . $this->_setflag($form['FF']));
1430
1431			if ($form['activ']) {
1432				$this->writer->write('/V /' . $this->writer->escape($form['V']) . ' ');
1433				$this->writer->write('/DV /' . $this->writer->escape($form['V']) . ' ');
1434				$this->writer->write('/AS /' . $this->writer->escape($form['V']) . ' ');
1435			} else {
1436				$this->writer->write('/AS /Off ');
1437			}
1438
1439			if ($this->formUseZapD) {
1440				$this->writer->write('/DA (/F' . $this->mpdf->fonts['czapfdingbats']['i'] . ' 0 Tf ' . $radio_color . ' rg)');
1441				$this->writer->write('/AP << /N << /' . $this->writer->escape($form['V']) . ' ' . ($this->mpdf->n + 1) . ' 0 R /Off /Off >> >>');
1442			} else {
1443				$this->writer->write('/DA (/F' . $this->mpdf->fonts[$this->mpdf->CurrentFont['fontkey']]['i'] . ' 0 Tf ' . $radio_color . ' rg)');
1444				$this->writer->write('/AP << /N << /' . $this->writer->escape($form['V']) . ' ' . ($this->mpdf->n + 1) . ' 0 R /Off ' . ($this->mpdf->n + 2) . ' 0 R >> >>');
1445			}
1446
1447			$this->writer->write('/Opt [ ' . $this->writer->string($form['OPT']) . ' ' . $this->writer->string($form['OPT']) . ' ]');
1448		}
1449
1450		if ($form['subtype'] === 'radio') {
1451
1452			if ((isset($form['disabled']) && $form['disabled']) || (isset($this->form_radio_groups[$form['T']]['disabled']) && $this->form_radio_groups[$form['T']]['disabled'])) {
1453				$radio_color = '0.5 0.5 0.5';
1454				$radio_background_color = '0.9 0.9 0.9';
1455			} else {
1456				$radio_color = $this->form_radio_color;
1457				$radio_background_color = $this->form_radio_background_color;
1458			}
1459
1460			$this->writer->write('/Parent ' . $this->form_radio_groups[$form['T']]['obj_id'] . ' 0 R ');
1461
1462			$temp = '';
1463			$temp .= '/BC [ ' . $radio_color . ' ] ';
1464			$temp .= '/BG [ ' . $radio_background_color . ' ] ';
1465
1466			$this->writer->write('/BS << /W 1 /S /S >>');
1467			$this->writer->write('/MK << ' . $temp . ' >> ');
1468
1469			$form['FF'][] = self::FLAG_NOTOGGLEOFF;
1470			$form['FF'][] = self::FLAG_RADIO; // must be same as radio button group setting?
1471			$this->writer->write('/Ff ' . $this->_setflag($form['FF']));
1472
1473			if ($this->formUseZapD) {
1474				$this->writer->write('/DA (/F' . $this->mpdf->fonts['czapfdingbats']['i'] . ' 0 Tf ' . $radio_color . ' rg)');
1475			} else {
1476				$this->writer->write('/DA (/F' . $this->mpdf->fonts[$this->mpdf->CurrentFont['fontkey']]['i'] . ' 0 Tf ' . $radio_color . ' rg)');
1477			}
1478
1479			$this->writer->write('/AP << /N << /' . $this->writer->escape($form['V']) . ' ' . ($this->mpdf->n + 1) . ' 0 R /Off ' . ($this->mpdf->n + 2) . ' 0 R >> >>');
1480
1481			if ($form['activ']) {
1482				$this->writer->write('/V /' . $this->writer->escape($form['V']) . ' ');
1483				$this->writer->write('/DV /' . $this->writer->escape($form['V']) . ' ');
1484				$this->writer->write('/AS /' . $this->writer->escape($form['V']) . ' ');
1485			} else {
1486				$this->writer->write('/AS /Off ');
1487			}
1488			$this->writer->write('/AP << /N << /' . $this->writer->escape($form['V']) . ' ' . ($this->mpdf->n + 1) . ' 0 R /Off ' . ($this->mpdf->n + 2) . ' 0 R >> >>');
1489			// $this->writer->write('/Opt [ '.$this->writer->string($form['OPT']).' '.$this->writer->string($form['OPT']).' ]');
1490		}
1491
1492		if ($form['subtype'] === 'reset') {
1493			$temp .= $form['CA'] ? '/CA ' . $this->writer->string($form['CA']) . ' ' : '/CA ' . $this->writer->string($form['T']) . ' ';
1494			$temp .= $form['RC'] ? '/RC ' . $this->writer->string($form['RC']) . ' ' : '/RC ' . $this->writer->string($form['T']) . ' ';
1495			$temp .= $form['AC'] ? '/AC ' . $this->writer->string($form['AC']) . ' ' : '/AC ' . $this->writer->string($form['T']) . ' ';
1496			$this->writer->write("/BS << $bstemp >>");
1497			$this->writer->write('/MK << ' . $temp . ' >>');
1498			$this->writer->write('/DA (/F' . $this->mpdf->fonts[$form['style']['font']]['i'] . ' ' . $form['style']['fontsize'] . ' Tf ' . $form['style']['fontcolor'] . ')');
1499			$this->writer->write('/AA << /D << /S /ResetForm /Flags 1 >> >>');
1500			$form['FF'][] = 17;
1501			$this->writer->write('/Ff ' . $this->_setflag($form['FF']));
1502		}
1503
1504		if ($form['subtype'] === 'submit') {
1505
1506			$temp .= $form['CA'] ? '/CA ' . $this->writer->string($form['CA']) . ' ' : '/CA ' . $this->writer->string($form['T']) . ' ';
1507			$temp .= $form['RC'] ? '/RC ' . $this->writer->string($form['RC']) . ' ' : '/RC ' . $this->writer->string($form['T']) . ' ';
1508			$temp .= $form['AC'] ? '/AC ' . $this->writer->string($form['AC']) . ' ' : '/AC ' . $this->writer->string($form['T']) . ' ';
1509			$this->writer->write("/BS << $bstemp >>");
1510			$this->writer->write("/MK << $temp >>");
1511			$this->writer->write('/DA (/F' . $this->mpdf->fonts[$form['style']['font']]['i'] . ' ' . $form['style']['fontsize'] . ' Tf ' . $form['style']['fontcolor'] . ')');
1512
1513			// Bit 4 (8) = useGETmethod else use POST
1514			// Bit 3 (4) = HTML export format (charset chosen by Adobe)--- OR ---
1515			// Bit 6 (32) = XFDF export format (form of XML in UTF-8)
1516			if ($form['exporttype'] === 'xfdf') {
1517				$flag = 32;
1518			} elseif ($form['method'] === 'GET') { // 'xfdf' or 'html'
1519				$flag = 12;
1520			} else {
1521				$flag = 4;
1522			}
1523			// Bit 2 (2) = IncludeNoValueFields
1524			if ($this->formSubmitNoValueFields) {
1525				$flag += 2;
1526			}
1527			// To submit a value, needs to be in /AP dictionary, AND this object must contain a /Fields entry
1528			// listing all fields to output
1529			$this->writer->write('/AA << /D << /S /SubmitForm /F (' . $form['URL'] . ') /Flags ' . $flag . ' >> >>');
1530			$form['FF'][] = 17;
1531			$this->writer->write('/Ff ' . $this->_setflag($form['FF']));
1532		}
1533
1534		if ($form['subtype'] === 'js_button') {
1535			// Icon / image
1536			if (isset($this->form_button_icon[$form['T']])) {
1537				$cc++;
1538				$temp .= '/TP ' . $this->form_button_icon[$form['T']]['pos'] . ' ';
1539				$temp .= '/I ' . ($cc + $this->mpdf->n) . ' 0 R ';  // Normal icon
1540				$temp .= '/RI ' . ($cc + $this->mpdf->n) . ' 0 R ';  // onMouseOver
1541				$temp .= '/IX ' . ($cc + $this->mpdf->n) . ' 0 R ';  // onClick / onMouseDown
1542				$temp .= '/IF << /SW /A /S /A /A [0.0 0.0] >> '; // Icon fit dictionary
1543				if ($this->form_button_icon[$form['T']]['Indexed']) {
1544					$cc++;
1545				}
1546				$put_icon = 1;
1547			}
1548			$temp .= $form['CA'] ? '/CA ' . $this->writer->string($form['CA']) . ' ' : '/CA ' . $this->writer->string($form['T']) . ' ';
1549			$temp .= $form['RC'] ? '/RC ' . $this->writer->string($form['RC']) . ' ' : '/RC ' . $this->writer->string($form['T']) . ' ';
1550			$temp .= $form['AC'] ? '/AC ' . $this->writer->string($form['AC']) . ' ' : '/AC ' . $this->writer->string($form['T']) . ' ';
1551			$this->writer->write("/BS << $bstemp >>");
1552			$this->writer->write("/MK << $temp >>");
1553			$this->writer->write('/DA (/F' . $this->mpdf->fonts[$form['style']['font']]['i'] . ' ' . $form['style']['fontsize'] . ' Tf ' . $form['style']['fontcolor'] . ')');
1554			$form['FF'][] = 17;
1555			$this->writer->write('/Ff ' . $this->_setflag($form['FF']));
1556			// Javascript
1557			if (isset($this->array_form_button_js[$form['T']])) {
1558				$cc++;
1559				$this->writer->write('/AA << /D ' . ($cc + $this->mpdf->n) . ' 0 R >>');
1560				$put_js = 1;
1561			}
1562		}
1563
1564		$this->writer->write('>>');
1565		$this->writer->write('endobj');
1566
1567		// additional objects
1568		// obj icon
1569		if ($put_icon === 1) {
1570			$this->_put_button_icon($this->form_button_icon[$form['T']], $form['w'], $form['h']);
1571			$put_icon = null;
1572		}
1573		// obj + 1
1574		if ($put_js === 1) {
1575			$this->mpdf->_set_object_javascript($this->array_form_button_js[$form['T']]['js']);
1576			unset($this->array_form_button_js[$form['T']]);
1577			$put_js = null;
1578		}
1579
1580		// RADIO and CHECK BOX appearance streams
1581		$filter = $this->mpdf->compress ? '/Filter /FlateDecode ' : '';
1582		if ($form['subtype'] === 'radio') {
1583			// output 2 appearance streams for radio buttons on/off
1584			if ($this->formUseZapD) {
1585				$fs = sprintf('%.3F', $form['style']['fontsize'] * 1.25);
1586				$fi = 'czapfdingbats';
1587				$r_on = 'q ' . $radio_color . ' rg BT /F' . $this->mpdf->fonts[$fi]['i'] . ' ' . $fs . ' Tf 0 0 Td (4) Tj ET Q';
1588				$r_off = 'q ' . $radio_color . ' rg BT /F' . $this->mpdf->fonts[$fi]['i'] . ' ' . $fs . ' Tf 0 0 Td (8) Tj ET Q';
1589			} else {
1590				$matrix = sprintf('%.3F 0 0 %.3F 0 %.3F', $form['style']['fontsize'] * 1.33 / 10, $form['style']['fontsize'] * 1.25 / 10, $form['style']['fontsize']);
1591				$fill = $radio_background_color . ' rg 3.778 -7.410 m 2.800 -7.410 1.947 -7.047 1.225 -6.322 c 0.500 -5.600 0.138 -4.747 0.138 -3.769 c 0.138 -2.788 0.500 -1.938 1.225 -1.213 c 1.947 -0.491 2.800 -0.128 3.778 -0.128 c 4.757 -0.128 5.610 -0.491 6.334 -1.213 c 7.056 -1.938 7.419 -2.788 7.419 -3.769 c 7.419 -4.747 7.056 -5.600 6.334 -6.322 c 5.610 -7.047 4.757 -7.410 3.778 -7.410 c h f ';
1592				$circle = '3.778 -6.963 m 4.631 -6.963 5.375 -6.641 6.013 -6.004 c 6.653 -5.366 6.972 -4.619 6.972 -3.769 c 6.972 -2.916 6.653 -2.172 6.013 -1.532 c 5.375 -0.894 4.631 -0.576 3.778 -0.576 c 2.928 -0.576 2.182 -0.894 1.544 -1.532 c 0.904 -2.172 0.585 -2.916 0.585 -3.769 c 0.585 -4.619 0.904 -5.366 1.544 -6.004 c 2.182 -6.641 2.928 -6.963 3.778 -6.963 c h 3.778 -7.410 m 2.800 -7.410 1.947 -7.047 1.225 -6.322 c 0.500 -5.600 0.138 -4.747 0.138 -3.769 c 0.138 -2.788 0.500 -1.938 1.225 -1.213 c 1.947 -0.491 2.800 -0.128 3.778 -0.128 c 4.757 -0.128 5.610 -0.491 6.334 -1.213 c 7.056 -1.938 7.419 -2.788 7.419 -3.769 c 7.419 -4.747 7.056 -5.600 6.334 -6.322 c 5.610 -7.047 4.757 -7.410 3.778 -7.410 c h f ';
1593				$r_on = 'q ' . $matrix . ' cm ' . $fill . $radio_color . ' rg ' . $circle . '  ' . $radio_color . ' rg
15945.184 -5.110 m 4.800 -5.494 4.354 -5.685 3.841 -5.685 c 3.331 -5.685 2.885 -5.494 2.501 -5.110 c 2.119 -4.725 1.925 -4.279 1.925 -3.769 c 1.925 -3.257 2.119 -2.810 2.501 -2.429 c 2.885 -2.044 3.331 -1.853 3.841 -1.853 c 4.354 -1.853 4.800 -2.044 5.184 -2.429 c 5.566 -2.810 5.760 -3.257 5.760 -3.769 c 5.760 -4.279 5.566 -4.725 5.184 -5.110 c h
1595f Q ';
1596				$r_off = 'q ' . $matrix . ' cm ' . $fill . $radio_color . ' rg ' . $circle . '  Q ';
1597			}
1598
1599			$this->writer->object();
1600			$p = $this->mpdf->compress ? gzcompress($r_on) : $r_on;
1601			$this->writer->write('<<' . $filter . '/Length ' . strlen($p) . ' /Resources 2 0 R>>');
1602			$this->writer->stream($p);
1603			$this->writer->write('endobj');
1604
1605			$this->writer->object();
1606			$p = $this->mpdf->compress ? gzcompress($r_off) : $r_off;
1607			$this->writer->write('<<' . $filter . '/Length ' . strlen($p) . ' /Resources 2 0 R>>');
1608			$this->writer->stream($p);
1609			$this->writer->write('endobj');
1610		}
1611
1612		if ($form['subtype'] === 'checkbox') {
1613			// First output appearance stream for check box on
1614			if ($this->formUseZapD) {
1615				$fs = sprintf('%.3F', $form['style']['fontsize'] * 1.25);
1616				$fi = 'czapfdingbats';
1617				$cb_on = 'q ' . $radio_color . ' rg BT /F' . $this->mpdf->fonts[$fi]['i'] . ' ' . $fs . ' Tf 0 0 Td (4) Tj ET Q';
1618				$cb_off = 'q ' . $radio_color . ' rg BT /F' . $this->mpdf->fonts[$fi]['i'] . ' ' . $fs . ' Tf 0 0 Td (8) Tj ET Q';
1619			} else {
1620				$matrix = sprintf('%.3F 0 0 %.3F 0 %.3F', $form['style']['fontsize'] * 1.33 / 10, $form['style']['fontsize'] * 1.25 / 10, $form['style']['fontsize']);
1621				$fill = $radio_background_color . ' rg 7.395 -0.070 m 7.395 -7.344 l 0.121 -7.344 l 0.121 -0.070 l 7.395 -0.070 l h  f ';
1622				$square = '0.508 -6.880 m 6.969 -6.880 l 6.969 -0.534 l 0.508 -0.534 l 0.508 -6.880 l h 7.395 -0.070 m 7.395 -7.344 l 0.121 -7.344 l 0.121 -0.070 l 7.395 -0.070 l h ';
1623				$cb_on = 'q ' . $matrix . ' cm ' . $fill . $radio_color . ' rg ' . $square . ' f ' . $radio_color . ' rg
16246.321 -1.352 m 5.669 -2.075 5.070 -2.801 4.525 -3.532 c 3.979 -4.262 3.508 -4.967 3.112 -5.649 c 3.080 -5.706 3.039 -5.779 2.993 -5.868 c 2.858 -6.118 2.638 -6.243 2.334 -6.243 c 2.194 -6.243 2.100 -6.231 2.052 -6.205 c 2.003 -6.180 1.954 -6.118 1.904 -6.020 c 1.787 -5.788 1.688 -5.523 1.604 -5.226 c 1.521 -4.930 1.480 -4.721 1.480 -4.600 c 1.480 -4.535 1.491 -4.484 1.512 -4.447 c 1.535 -4.410 1.579 -4.367 1.647 -4.319 c 1.733 -4.259 1.828 -4.210 1.935 -4.172 c 2.040 -4.134 2.131 -4.115 2.205 -4.115 c 2.267 -4.115 2.341 -4.232 2.429 -4.469 c 2.437 -4.494 2.444 -4.511 2.448 -4.522 c 2.451 -4.531 2.456 -4.546 2.465 -4.568 c 2.546 -4.795 2.614 -4.910 2.668 -4.910 c 2.714 -4.910 2.898 -4.652 3.219 -4.136 c 3.539 -3.620 3.866 -3.136 4.197 -2.683 c 4.426 -2.367 4.633 -2.103 4.816 -1.889 c 4.998 -1.676 5.131 -1.544 5.211 -1.493 c 5.329 -1.426 5.483 -1.368 5.670 -1.319 c 5.856 -1.271 6.066 -1.238 6.296 -1.217 c 6.321 -1.352 l h  f  Q ';
1625				$cb_off = 'q ' . $matrix . ' cm ' . $fill . $radio_color . ' rg ' . $square . ' f Q ';
1626			}
1627			$this->writer->object();
1628			$p = $this->mpdf->compress ? gzcompress($cb_on) : $cb_on;
1629			$this->writer->write('<<' . $filter . '/Length ' . strlen($p) . ' /Resources 2 0 R>>');
1630			$this->writer->stream($p);
1631			$this->writer->write('endobj');
1632
1633			// output appearance stream for check box off (only if not using ZapfDingbats)
1634			if (!$this->formUseZapD) {
1635				$this->writer->object();
1636				$p = $this->mpdf->compress ? gzcompress($cb_off) : $cb_off;
1637				$this->writer->write('<<' . $filter . '/Length ' . strlen($p) . ' /Resources 2 0 R>>');
1638				$this->writer->stream($p);
1639				$this->writer->write('endobj');
1640			}
1641		}
1642		return $n;
1643	}
1644
1645	function _putform_ch($form, $hPt)
1646	{
1647		$put_js = 0;
1648		$this->writer->object();
1649		$n = $this->mpdf->n;
1650		$this->pdf_acro_array .= $n . ' 0 R ';
1651		$this->forms[$form['n']]['obj'] = $n;
1652
1653		$this->writer->write('<<');
1654		$this->writer->write('/Type /Annot ');
1655		$this->writer->write('/Subtype /Widget');
1656		$this->writer->write('/Rect [ ' . $this->_form_rect($form['x'], $form['y'], $form['w'], $form['h'], $hPt) . ' ]');
1657		$this->writer->write('/F 4');
1658		$this->writer->write('/FT /Ch');
1659		if ($form['Q']) {
1660			$this->writer->write('/Q ' . $form['Q'] . '');
1661		}
1662		$temp = '';
1663		$temp .= '/W ' . $form['BS_W'] . ' ';
1664		$temp .= '/S /' . $form['BS_S'] . ' ';
1665		$this->writer->write("/BS << $temp >>");
1666
1667		$temp = '';
1668		$temp .= '/BC [ ' . $form['BC_C'] . ' ] ';
1669		$temp .= '/BG [ ' . $form['BG_C'] . ' ] ';
1670		$this->writer->write('/MK << ' . $temp . ' >>');
1671
1672		$this->writer->write('/NM ' . $this->writer->string(sprintf('%04u-%04u', $n, 6000 + $form['n'])));
1673		$this->writer->write('/M ' . $this->writer->string('D:' . date('YmdHis')));
1674
1675		$this->writer->write('/T ' . $this->writer->string($form['T']));
1676		$this->writer->write('/DA (/F' . $this->mpdf->fonts[$form['style']['font']]['i'] . ' ' . $form['style']['fontsize'] . ' Tf ' . $form['style']['fontcolor'] . ')');
1677
1678		$opt = '';
1679		$count = count($form['OPT']['VAL']);
1680		for ($i = 0; $i < $count; $i++) {
1681			$opt .= '[ ' . $this->writer->string($form['OPT']['VAL'][$i]) . ' ' . $this->writer->string($form['OPT']['OPT'][$i]) . ' ] ';
1682		}
1683		$this->writer->write('/Opt [ ' . $opt . ']');
1684
1685		// selected
1686		$selectItem = false;
1687		$selectIndex = false;
1688		foreach ($form['OPT']['SEL'] as $selectKey => $selectVal) {
1689			$selectName = $this->writer->string($form['OPT']['VAL'][$selectVal]);
1690			$selectItem .= ' ' . $selectName . ' ';
1691			$selectIndex .= ' ' . $selectVal . ' ';
1692		}
1693		if ($selectItem) {
1694			if (count($form['OPT']['SEL']) < 2) {
1695				$this->writer->write('/V ' . $selectItem . ' ');
1696				$this->writer->write('/DV ' . $selectItem . ' ');
1697			} else {
1698				$this->writer->write('/V [' . $selectItem . '] ');
1699				$this->writer->write('/DV [' . $selectItem . '] ');
1700			}
1701			$this->writer->write('/I [' . $selectIndex . '] ');
1702		}
1703
1704		if (is_array($form['FF']) && count($form['FF']) > 0) {
1705			$this->writer->write('/Ff ' . $this->_setflag($form['FF']) . ' ');
1706		}
1707
1708		// Javascript
1709		if (isset($this->array_form_choice_js[$form['T']])) {
1710			$this->writer->write('/AA << /V ' . ($this->mpdf->n + 1) . ' 0 R >>');
1711			$put_js = 1;
1712		}
1713
1714		$this->writer->write('>>');
1715		$this->writer->write('endobj');
1716
1717		// obj + 1
1718		if ($put_js === 1) {
1719			$this->mpdf->_set_object_javascript($this->array_form_choice_js[$form['T']]['js']);
1720			unset($this->array_form_choice_js[$form['T']]);
1721			$put_js = null;
1722		}
1723
1724		return $n;
1725	}
1726
1727	function _putform_tx($form, $hPt)
1728	{
1729		$put_js = 0;
1730		$this->writer->object();
1731		$n = $this->mpdf->n;
1732		$this->pdf_acro_array .= $n . ' 0 R ';
1733		$this->forms[$form['n']]['obj'] = $n;
1734
1735		$this->writer->write('<<');
1736		$this->writer->write('/Type /Annot ');
1737		$this->writer->write('/Subtype /Widget ');
1738
1739		$this->writer->write('/Rect [ ' . $this->_form_rect($form['x'], $form['y'], $form['w'], $form['h'], $hPt) . ' ] ');
1740		$form['hidden'] ? $this->writer->write('/F 2 ') : $this->writer->write('/F 4 ');
1741		$this->writer->write('/FT /Tx ');
1742
1743		$this->writer->write('/H /N ');
1744		$this->writer->write('/R 0 ');
1745
1746		if (is_array($form['FF']) && count($form['FF']) > 0) {
1747			$this->writer->write('/Ff ' . $this->_setflag($form['FF']) . ' ');
1748		}
1749		if (isset($form['maxlen']) && $form['maxlen'] > 0) {
1750			$this->writer->write('/MaxLen ' . $form['maxlen']);
1751		}
1752
1753		$temp = '';
1754		$temp .= '/W ' . $form['BS_W'] . ' ';
1755		$temp .= '/S /' . $form['BS_S'] . ' ';
1756		$this->writer->write("/BS << $temp >>");
1757
1758		$temp = '';
1759		$temp .= '/BC [ ' . $form['BC_C'] . ' ] ';
1760		$temp .= '/BG [ ' . $form['BG_C'] . ' ] ';
1761		$this->writer->write('/MK <<' . $temp . ' >>');
1762
1763		$this->writer->write('/T ' . $this->writer->string($form['T']));
1764		$this->writer->write('/TU ' . $this->writer->string($form['TU']));
1765		if ($form['V'] || $form['V'] === '0') {
1766			$this->writer->write('/V ' . $this->writer->string($form['V']));
1767		}
1768		$this->writer->write('/DV ' . $this->writer->string($form['DV']));
1769		$this->writer->write('/DA (/F' . $this->mpdf->fonts[$form['style']['font']]['i'] . ' ' . $form['style']['fontsize'] . ' Tf ' . $form['style']['fontcolor'] . ')');
1770		if ($form['Q']) {
1771			$this->writer->write('/Q ' . $form['Q'] . '');
1772		}
1773
1774		$this->writer->write('/NM ' . $this->writer->string(sprintf('%04u-%04u', $n, 5000 + $form['n'])));
1775		$this->writer->write('/M ' . $this->writer->string('D:' . date('YmdHis')));
1776
1777
1778		if (isset($this->array_form_text_js[$form['T']])) {
1779			$put_js = 1;
1780			$cc = 0;
1781			$js_str = '';
1782
1783			if (isset($this->array_form_text_js[$form['T']]['F'])) {
1784				$cc++;
1785				$js_str .= '/F ' . ($cc + $this->mpdf->n) . ' 0 R ';
1786			}
1787			if (isset($this->array_form_text_js[$form['T']]['K'])) {
1788				$cc++;
1789				$js_str .= '/K ' . ($cc + $this->mpdf->n) . ' 0 R ';
1790			}
1791			if (isset($this->array_form_text_js[$form['T']]['V'])) {
1792				$cc++;
1793				$js_str .= '/V ' . ($cc + $this->mpdf->n) . ' 0 R ';
1794			}
1795			if (isset($this->array_form_text_js[$form['T']]['C'])) {
1796				$cc++;
1797				$js_str .= '/C ' . ($cc + $this->mpdf->n) . ' 0 R ';
1798				$this->pdf_array_co .= $this->mpdf->n . ' 0 R ';
1799			}
1800			$this->writer->write('/AA << ' . $js_str . ' >>');
1801		}
1802
1803		$this->writer->write('>>');
1804		$this->writer->write('endobj');
1805
1806		if ($put_js == 1) {
1807			if (isset($this->array_form_text_js[$form['T']]['F'])) {
1808				$this->mpdf->_set_object_javascript($this->array_form_text_js[$form['T']]['F']['js']);
1809				unset($this->array_form_text_js[$form['T']]['F']);
1810			}
1811			if (isset($this->array_form_text_js[$form['T']]['K'])) {
1812				$this->mpdf->_set_object_javascript($this->array_form_text_js[$form['T']]['K']['js']);
1813				unset($this->array_form_text_js[$form['T']]['K']);
1814			}
1815			if (isset($this->array_form_text_js[$form['T']]['V'])) {
1816				$this->mpdf->_set_object_javascript($this->array_form_text_js[$form['T']]['V']['js']);
1817				unset($this->array_form_text_js[$form['T']]['V']);
1818			}
1819			if (isset($this->array_form_text_js[$form['T']]['C'])) {
1820				$this->mpdf->_set_object_javascript($this->array_form_text_js[$form['T']]['C']['js']);
1821				unset($this->array_form_text_js[$form['T']]['C']);
1822			}
1823		}
1824		return $n;
1825	}
1826}
1827