7 use Mpdf\Utils\UtfString
;
12 public function open($attr, &$ahtml, &$ihtml)
14 $tag = $this->getTagName();
15 $this->mpdf
->ignorefollowingspaces
= true;
16 $this->mpdf
->lastoptionaltag
= $tag; // Save current HTML specified optional endtag
17 $this->cssManager
->tbCSSlvl++
;
18 $this->mpdf
->InlineProperties
= [];
19 $this->mpdf
->InlineBDF
= []; // mPDF 6
20 $this->mpdf
->InlineBDFctr
= 0; // mPDF 6
21 $this->mpdf
->tdbegin
= true;
23 while (isset($this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
])) {
27 //Update number column
28 if ($this->mpdf
->table
[$this->mpdf
->tableLevel
][$this->mpdf
->tbctr
[$this->mpdf
->tableLevel
]]['nc'] < $this->mpdf
->col +
1) {
29 $this->mpdf
->table
[$this->mpdf
->tableLevel
][$this->mpdf
->tbctr
[$this->mpdf
->tableLevel
]]['nc'] = $this->mpdf
->col +
1;
32 $table = &$this->mpdf
->table
[$this->mpdf
->tableLevel
][$this->mpdf
->tbctr
[$this->mpdf
->tableLevel
]];
38 'padding' => ['L' => false,
45 if ($this->mpdf
->simpleTables
&& $this->mpdf
->row
== 0 && $this->mpdf
->col
== 0) {
46 $table['simple']['border'] = false;
47 $table['simple']['border_details']['R']['w'] = 0;
48 $table['simple']['border_details']['L']['w'] = 0;
49 $table['simple']['border_details']['T']['w'] = 0;
50 $table['simple']['border_details']['B']['w'] = 0;
51 $table['simple']['border_details']['R']['style'] = '';
52 $table['simple']['border_details']['L']['style'] = '';
53 $table['simple']['border_details']['T']['style'] = '';
54 $table['simple']['border_details']['B']['style'] = '';
55 } elseif (!$this->mpdf
->simpleTables
) {
57 $c['border_details']['R']['w'] = 0;
58 $c['border_details']['L']['w'] = 0;
59 $c['border_details']['T']['w'] = 0;
60 $c['border_details']['B']['w'] = 0;
61 $c['border_details']['mbw']['BL'] = 0;
62 $c['border_details']['mbw']['BR'] = 0;
63 $c['border_details']['mbw']['RT'] = 0;
64 $c['border_details']['mbw']['RB'] = 0;
65 $c['border_details']['mbw']['TL'] = 0;
66 $c['border_details']['mbw']['TR'] = 0;
67 $c['border_details']['mbw']['LT'] = 0;
68 $c['border_details']['mbw']['LB'] = 0;
69 $c['border_details']['R']['style'] = '';
70 $c['border_details']['L']['style'] = '';
71 $c['border_details']['T']['style'] = '';
72 $c['border_details']['B']['style'] = '';
73 $c['border_details']['R']['s'] = 0;
74 $c['border_details']['L']['s'] = 0;
75 $c['border_details']['T']['s'] = 0;
76 $c['border_details']['B']['s'] = 0;
77 $c['border_details']['R']['c'] = $this->colorConverter
->convert(0, $this->mpdf
->PDFAXwarnings
);
78 $c['border_details']['L']['c'] = $this->colorConverter
->convert(0, $this->mpdf
->PDFAXwarnings
);
79 $c['border_details']['T']['c'] = $this->colorConverter
->convert(0, $this->mpdf
->PDFAXwarnings
);
80 $c['border_details']['B']['c'] = $this->colorConverter
->convert(0, $this->mpdf
->PDFAXwarnings
);
81 $c['border_details']['R']['dom'] = 0;
82 $c['border_details']['L']['dom'] = 0;
83 $c['border_details']['T']['dom'] = 0;
84 $c['border_details']['B']['dom'] = 0;
85 $c['border_details']['cellposdom'] = 0;
90 $c['va'] = $table['va'];
93 $c['a'] = $table['txta'];
95 if ($this->mpdf
->table_border_attr_set
&& $table['border_details']) {
96 if (!$this->mpdf
->simpleTables
) {
97 $c['border_details']['R'] = $table['border_details']['R'];
98 $c['border_details']['L'] = $table['border_details']['L'];
99 $c['border_details']['T'] = $table['border_details']['T'];
100 $c['border_details']['B'] = $table['border_details']['B'];
101 $c['border'] = $table['border'];
102 $c['border_details']['L']['dom'] = 1;
103 $c['border_details']['R']['dom'] = 1;
104 $c['border_details']['T']['dom'] = 1;
105 $c['border_details']['B']['dom'] = 1;
106 } elseif ($this->mpdf
->simpleTables
&& $this->mpdf
->row
== 0 && $this->mpdf
->col
== 0) {
107 $table['simple']['border_details']['R'] = $table['border_details']['R'];
108 $table['simple']['border_details']['L'] = $table['border_details']['L'];
109 $table['simple']['border_details']['T'] = $table['border_details']['T'];
110 $table['simple']['border_details']['B'] = $table['border_details']['B'];
111 $table['simple']['border'] = $table['border'];
114 // INHERITED THEAD CSS Properties
115 if ($this->mpdf
->tablethead
) {
116 if ($this->mpdf
->thead_valign_default
) {
117 $c['va'] = self
::ALIGN
[strtolower($this->mpdf
->thead_valign_default
)];
119 if ($this->mpdf
->thead_textalign_default
) {
120 $c['a'] = self
::ALIGN
[strtolower($this->mpdf
->thead_textalign_default
)];
122 if ($this->mpdf
->thead_font_weight
=== 'B') {
123 $this->mpdf
->SetStyle('B', true);
125 if ($this->mpdf
->thead_font_style
=== 'I') {
126 $this->mpdf
->SetStyle('I', true);
128 if ($this->mpdf
->thead_font_smCaps
=== 'S') {
129 $this->mpdf
->textvar |
= TextVars
::FC_SMALLCAPS
;
133 // INHERITED TFOOT CSS Properties
134 if ($this->mpdf
->tabletfoot
) {
135 if ($this->mpdf
->tfoot_valign_default
) {
136 $c['va'] = self
::ALIGN
[strtolower($this->mpdf
->tfoot_valign_default
)];
138 if ($this->mpdf
->tfoot_textalign_default
) {
139 $c['a'] = self
::ALIGN
[strtolower($this->mpdf
->tfoot_textalign_default
)];
141 if ($this->mpdf
->tfoot_font_weight
=== 'B') {
142 $this->mpdf
->SetStyle('B', true);
144 if ($this->mpdf
->tfoot_font_style
=== 'I') {
145 $this->mpdf
->SetStyle('I', true);
147 if ($this->mpdf
->tfoot_font_style
=== 'S') {
148 $this->mpdf
->textvar |
= TextVars
::FC_SMALLCAPS
;
153 if ($this->mpdf
->trow_text_rotate
) {
154 $c['R'] = $this->mpdf
->trow_text_rotate
;
157 $this->mpdf
->cell_border_dominance_L
= 0;
158 $this->mpdf
->cell_border_dominance_R
= 0;
159 $this->mpdf
->cell_border_dominance_T
= 0;
160 $this->mpdf
->cell_border_dominance_B
= 0;
162 $properties = $this->cssManager
->MergeCSS('TABLE', $tag, $attr);
164 $properties = $this->cssManager
->array_merge_recursive_unique($this->mpdf
->base_table_properties
, $properties);
166 $this->mpdf
->Reset(); // mPDF 6 ?????????????????????
168 $this->mpdf
->setCSS($properties, 'TABLECELL', $tag);
170 $c['dfs'] = $this->mpdf
->FontSize
; // Default Font size
173 if (isset($properties['BACKGROUND-COLOR'])) {
174 $c['bgcolor'] = $properties['BACKGROUND-COLOR'];
175 } elseif (isset($properties['BACKGROUND'])) {
176 $c['bgcolor'] = $properties['BACKGROUND'];
177 } elseif (isset($attr['BGCOLOR'])) {
178 $c['bgcolor'] = $attr['BGCOLOR'];
183 /* -- BACKGROUNDS -- */
184 if (isset($properties['BACKGROUND-GRADIENT'])) {
185 $c['gradient'] = $properties['BACKGROUND-GRADIENT'];
187 $c['gradient'] = false;
190 if (!empty($properties['BACKGROUND-IMAGE']) && !$this->mpdf
->keep_block_together
) {
191 $ret = $this->mpdf
->SetBackground($properties, $this->mpdf
->blk
[$this->mpdf
->blklvl
]['inner_width']);
193 $c['background-image'] = $ret;
196 /* -- END BACKGROUNDS -- */
197 if (isset($properties['VERTICAL-ALIGN'])) {
198 $c['va'] = self
::ALIGN
[strtolower($properties['VERTICAL-ALIGN'])];
199 } elseif (isset($attr['VALIGN'])) {
200 $c['va'] = self
::ALIGN
[strtolower($attr['VALIGN'])];
204 if (!empty($properties['TEXT-ALIGN'])) {
205 if (0 === strpos($properties['TEXT-ALIGN'], 'D')) {
206 $c['a'] = $properties['TEXT-ALIGN'];
208 $c['a'] = self
::ALIGN
[strtolower($properties['TEXT-ALIGN'])];
211 if (!empty($attr['ALIGN'])) {
212 if (strtolower($attr['ALIGN']) === 'char') {
213 if (!empty($attr['CHAR'])) {
214 $char = html_entity_decode($attr['CHAR']);
215 $char = UtfString
::strcode2utf($char);
216 $d = array_search($char, $this->mpdf
->decimal_align
);
224 $c['a'] = self
::ALIGN
[strtolower($attr['ALIGN'])];
229 $c['direction'] = $table['direction'];
230 if (isset($attr['DIR']) && $attr['DIR'] != '') {
231 $c['direction'] = strtolower($attr['DIR']);
233 if (isset($properties['DIRECTION'])) {
234 $c['direction'] = strtolower($properties['DIRECTION']);
238 if (isset($c['direction']) && $c['direction'] === 'rtl') {
245 $c['cellLineHeight'] = $table['cellLineHeight'];
246 if (isset($properties['LINE-HEIGHT'])) {
247 $c['cellLineHeight'] = $this->mpdf
->fixLineheight($properties['LINE-HEIGHT']);
250 $c['cellLineStackingStrategy'] = $table['cellLineStackingStrategy'];
251 if (isset($properties['LINE-STACKING-STRATEGY'])) {
252 $c['cellLineStackingStrategy'] = strtolower($properties['LINE-STACKING-STRATEGY']);
255 $c['cellLineStackingShift'] = $table['cellLineStackingShift'];
256 if (isset($properties['LINE-STACKING-SHIFT'])) {
257 $c['cellLineStackingShift'] = strtolower($properties['LINE-STACKING-SHIFT']);
260 if (isset($properties['TEXT-ROTATE']) && ($properties['TEXT-ROTATE'] ||
$properties['TEXT-ROTATE'] === '0')) {
261 $c['R'] = $properties['TEXT-ROTATE'];
263 if (isset($properties['BORDER'])) {
264 $bord = $this->mpdf
->border_details($properties['BORDER']);
266 if (!$this->mpdf
->simpleTables
) {
267 $c['border'] = Border
::ALL
;
268 $c['border_details']['R'] = $bord;
269 $c['border_details']['L'] = $bord;
270 $c['border_details']['T'] = $bord;
271 $c['border_details']['B'] = $bord;
272 $c['border_details']['L']['dom'] = $this->mpdf
->cell_border_dominance_L
;
273 $c['border_details']['R']['dom'] = $this->mpdf
->cell_border_dominance_R
;
274 $c['border_details']['T']['dom'] = $this->mpdf
->cell_border_dominance_T
;
275 $c['border_details']['B']['dom'] = $this->mpdf
->cell_border_dominance_B
;
276 } elseif ($this->mpdf
->simpleTables
&& $this->mpdf
->row
== 0 && $this->mpdf
->col
== 0) {
277 $table['simple']['border'] = Border
::ALL
;
278 $table['simple']['border_details']['R'] = $bord;
279 $table['simple']['border_details']['L'] = $bord;
280 $table['simple']['border_details']['T'] = $bord;
281 $table['simple']['border_details']['B'] = $bord;
285 if (!$this->mpdf
->simpleTables
) {
286 if (!empty($properties['BORDER-RIGHT'])) {
287 $c['border_details']['R'] = $this->mpdf
->border_details($properties['BORDER-RIGHT']);
288 $this->mpdf
->setBorder($c['border'], Border
::RIGHT
, $c['border_details']['R']['s']);
289 $c['border_details']['R']['dom'] = $this->mpdf
->cell_border_dominance_R
;
291 if (!empty($properties['BORDER-LEFT'])) {
292 $c['border_details']['L'] = $this->mpdf
->border_details($properties['BORDER-LEFT']);
293 $this->mpdf
->setBorder($c['border'], Border
::LEFT
, $c['border_details']['L']['s']);
294 $c['border_details']['L']['dom'] = $this->mpdf
->cell_border_dominance_L
;
296 if (!empty($properties['BORDER-BOTTOM'])) {
297 $c['border_details']['B'] = $this->mpdf
->border_details($properties['BORDER-BOTTOM']);
298 $this->mpdf
->setBorder($c['border'], Border
::BOTTOM
, $c['border_details']['B']['s']);
299 $c['border_details']['B']['dom'] = $this->mpdf
->cell_border_dominance_B
;
301 if (!empty($properties['BORDER-TOP'])) {
302 $c['border_details']['T'] = $this->mpdf
->border_details($properties['BORDER-TOP']);
303 $this->mpdf
->setBorder($c['border'], Border
::TOP
, $c['border_details']['T']['s']);
304 $c['border_details']['T']['dom'] = $this->mpdf
->cell_border_dominance_T
;
306 } elseif ($this->mpdf
->simpleTables
&& $this->mpdf
->row
== 0 && $this->mpdf
->col
== 0) {
307 if (!empty($properties['BORDER-LEFT'])) {
308 $bord = $this->mpdf
->border_details($properties['BORDER-LEFT']);
310 $table['simple']['border'] = Border
::ALL
;
312 $table['simple']['border'] = 0;
314 $table['simple']['border_details']['R'] = $bord;
315 $table['simple']['border_details']['L'] = $bord;
316 $table['simple']['border_details']['T'] = $bord;
317 $table['simple']['border_details']['B'] = $bord;
321 if ($this->mpdf
->simpleTables
&& $this->mpdf
->row
== 0 && $this->mpdf
->col
== 0 && !$table['borders_separate'] && $table['simple']['border']) {
322 $table['border_details'] = $table['simple']['border_details'];
323 $table['border'] = $table['simple']['border'];
326 // Border set on TR (if collapsed only)
327 if (!$table['borders_separate'] && !$this->mpdf
->simpleTables
&& isset($table['trborder-left'][$this->mpdf
->row
])) {
328 if ($this->mpdf
->col
== 0) {
329 $left = $this->mpdf
->border_details($table['trborder-left'][$this->mpdf
->row
]);
330 $c['border_details']['L'] = $left;
331 $this->mpdf
->setBorder($c['border'], Border
::LEFT
, $c['border_details']['L']['s']);
333 $c['border_details']['B'] = $this->mpdf
->border_details($table['trborder-bottom'][$this->mpdf
->row
]);
334 $this->mpdf
->setBorder($c['border'], Border
::BOTTOM
, $c['border_details']['B']['s']);
335 $c['border_details']['T'] = $this->mpdf
->border_details($table['trborder-top'][$this->mpdf
->row
]);
336 $this->mpdf
->setBorder($c['border'], Border
::TOP
, $c['border_details']['T']['s']);
339 if ($this->mpdf
->packTableData
&& !$this->mpdf
->simpleTables
) {
340 $c['borderbin'] = $this->mpdf
->_packCellBorder($c);
341 unset($c['border'], $c['border_details']);
344 if (isset($properties['PADDING-LEFT'])) {
345 $c['padding']['L'] = $this->sizeConverter
->convert($properties['PADDING-LEFT'], $this->mpdf
->blk
[$this->mpdf
->blklvl
]['inner_width'], $this->mpdf
->FontSize
, false);
347 if (isset($properties['PADDING-RIGHT'])) {
348 $c['padding']['R'] = $this->sizeConverter
->convert($properties['PADDING-RIGHT'], $this->mpdf
->blk
[$this->mpdf
->blklvl
]['inner_width'], $this->mpdf
->FontSize
, false);
350 if (isset($properties['PADDING-BOTTOM'])) {
351 $c['padding']['B'] = $this->sizeConverter
->convert($properties['PADDING-BOTTOM'], $this->mpdf
->blk
[$this->mpdf
->blklvl
]['inner_width'], $this->mpdf
->FontSize
, false);
353 if (isset($properties['PADDING-TOP'])) {
354 $c['padding']['T'] = $this->sizeConverter
->convert($properties['PADDING-TOP'], $this->mpdf
->blk
[$this->mpdf
->blklvl
]['inner_width'], $this->mpdf
->FontSize
, false);
358 if (isset($properties['WIDTH'])) {
359 $w = $properties['WIDTH'];
360 } elseif (isset($attr['WIDTH'])) {
364 if (strpos($w, '%') && !$this->mpdf
->ignore_table_percents
) {
365 $c['wpercent'] = (float) $w;
367 elseif (!strpos($w, '%') && !$this->mpdf
->ignore_table_widths
) {
368 $c['w'] = $this->sizeConverter
->convert($w, $this->mpdf
->blk
[$this->mpdf
->blklvl
]['inner_width'], $this->mpdf
->FontSize
, false);
372 if (isset($properties['HEIGHT']) && !strpos($properties['HEIGHT'], '%')) {
373 $c['h'] = $this->sizeConverter
->convert($properties['HEIGHT'], $this->mpdf
->blk
[$this->mpdf
->blklvl
]['inner_width'], $this->mpdf
->FontSize
, false);
374 } elseif (isset($attr['HEIGHT']) && !strpos($attr['HEIGHT'], '%')) {
375 $c['h'] = $this->sizeConverter
->convert($attr['HEIGHT'], $this->mpdf
->blk
[$this->mpdf
->blklvl
]['inner_width'], $this->mpdf
->FontSize
, false);
378 if (isset($properties['WHITE-SPACE'])) {
379 if (strtoupper($properties['WHITE-SPACE']) === 'NOWRAP') {
384 if (isset($attr['TEXT-ROTATE'])) {
385 $c['R'] = $attr['TEXT-ROTATE'];
387 if (!empty($attr['NOWRAP'])) {
391 $this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
] = $c;
393 $this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['s'] = 0;
396 if (isset($attr['COLSPAN']) && $attr['COLSPAN'] > 1) {
397 $cs = $this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['colspan'] = $attr['COLSPAN'];
399 if ($this->mpdf
->table
[$this->mpdf
->tableLevel
][$this->mpdf
->tbctr
[$this->mpdf
->tableLevel
]]['nc'] < $this->mpdf
->col +
$cs) {
400 $this->mpdf
->table
[$this->mpdf
->tableLevel
][$this->mpdf
->tbctr
[$this->mpdf
->tableLevel
]]['nc'] = $this->mpdf
->col +
$cs;
401 } // following code moved outside if...
402 for ($l = $this->mpdf
->col
; $l < $this->mpdf
->col +
$cs; $l++
) {
403 if ($l - $this->mpdf
->col
) {
404 $this->mpdf
->cell
[$this->mpdf
->row
][$l] = 0;
407 if (isset($attr['ROWSPAN']) && $attr['ROWSPAN'] > 1) {
408 $rs = $this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['rowspan'] = $attr['ROWSPAN'];
410 for ($k = $this->mpdf
->row
; $k < $this->mpdf
->row +
$rs; $k++
) {
411 for ($l = $this->mpdf
->col
; $l < $this->mpdf
->col +
$cs; $l++
) {
412 if ($k - $this->mpdf
->row ||
$l - $this->mpdf
->col
) {
413 $this->mpdf
->cell
[$k][$l] = 0;
420 public function close(&$ahtml, &$ihtml)
422 if ($this->mpdf
->tableLevel
) {
423 $this->mpdf
->lastoptionaltag
= 'TR';
424 unset($this->cssManager
->tablecascadeCSS
[$this->cssManager
->tbCSSlvl
]);
425 $this->cssManager
->tbCSSlvl
--;
426 if (!$this->mpdf
->tdbegin
) {
429 $this->mpdf
->tdbegin
= false;
430 // Added for correct calculation of cell column width - otherwise misses the last line if not end </p> etc.
431 if (!isset($this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['maxs'])) {
432 if (!is_array($this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
])) {
433 throw new \Mpdf\
MpdfException('You may have an error in your HTML code e.g. </td></td>');
435 $this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['maxs'] = $this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['s'];
436 } elseif ($this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['maxs'] < $this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['s']) {
437 $this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['maxs'] = $this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['s'];
440 // Remove last <br> if at end of cell
442 if (isset($this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['textbuffer'])) {
443 $ntb = count($this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['textbuffer']);
445 if ($ntb > 1 && $this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['textbuffer'][$ntb - 1][0] === "\n") {
446 unset($this->mpdf
->cell
[$this->mpdf
->row
][$this->mpdf
->col
]['textbuffer'][$ntb - 1]);
449 if ($this->mpdf
->tablethead
) {
450 $this->mpdf
->table
[$this->mpdf
->tableLevel
][$this->mpdf
->tbctr
[$this->mpdf
->tableLevel
]]['is_thead'][$this->mpdf
->row
] = true;
451 if ($this->mpdf
->tableLevel
== 1) {
452 $this->mpdf
->table
[$this->mpdf
->tableLevel
][$this->mpdf
->tbctr
[$this->mpdf
->tableLevel
]]['headernrows']
453 = max($this->mpdf
->table
[$this->mpdf
->tableLevel
][$this->mpdf
->tbctr
[$this->mpdf
->tableLevel
]]['headernrows'], $this->mpdf
->row +
1);
456 if ($this->mpdf
->tabletfoot
) {
457 $this->mpdf
->table
[$this->mpdf
->tableLevel
][$this->mpdf
->tbctr
[$this->mpdf
->tableLevel
]]['is_tfoot'][$this->mpdf
->row
] = true;
458 if ($this->mpdf
->tableLevel
== 1) {
459 $this->mpdf
->table
[$this->mpdf
->tableLevel
][$this->mpdf
->tbctr
[$this->mpdf
->tableLevel
]]['footernrows']
461 $this->mpdf
->table
[$this->mpdf
->tableLevel
][$this->mpdf
->tbctr
[$this->mpdf
->tableLevel
]]['footernrows'],
462 $this->mpdf
->row +
1 - $this->mpdf
->table
[$this->mpdf
->tableLevel
][$this->mpdf
->tbctr
[$this->mpdf
->tableLevel
]]['headernrows']
466 $this->mpdf
->Reset();