PluginProbe
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin / trunk
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin vtrunk
trunk 1.5 1.6 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 All 71 releases
pdf-print / mpdf / classes / cssmgr.php

cssmgr.php in PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin trunk, at mpdf/classes/cssmgr.php

2,045 lines 74.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class cssmgr
4 {
5
6 var $mpdf = null;
7
8 var $tablecascadeCSS;
9
10 var $cascadeCSS;
11
12 var $CSS;
13
14 var $tbCSSlvl;
15
16 public function __construct(mPDF $mpdf)
17 {
18 $this->mpdf = $mpdf;
19 $this->tablecascadeCSS = array();
20 $this->CSS = array();
21 $this->cascadeCSS = array();
22 $this->tbCSSlvl = 0;
23 }
24
25 function ReadCSS($html)
26 {
27 preg_match_all('/<style[^>]*media=["\']([^"\'>]*)["\'].*?<\/style>/is', $html, $m);
28 for ($i = 0; $i < count($m[0]); $i++) {
29 if ($this->mpdf->CSSselectMedia && !preg_match('/(' . trim($this->mpdf->CSSselectMedia) . '|all)/i', $m[1][$i])) {
30 $html = preg_replace('/' . preg_quote($m[0][$i], '/') . '/', '', $html);
31 }
32 }
33 preg_match_all('/<link[^>]*media=["\']([^"\'>]*)["\'].*?>/is', $html, $m);
34 for ($i = 0; $i < count($m[0]); $i++) {
35 if ($this->mpdf->CSSselectMedia && !preg_match('/(' . trim($this->mpdf->CSSselectMedia) . '|all)/i', $m[1][$i])) {
36 $html = preg_replace('/' . preg_quote($m[0][$i], '/') . '/', '', $html);
37 }
38 }
39
40 // mPDF 5.5.02
41 // Remove Comment tags <!-- ... --> inside CSS as <style> in HTML document
42 // Remove Comment tags /* ... */ inside CSS as <style> in HTML document
43 // But first, we replace upper and mixed case closing style tag with lower
44 // case so we can use str_replace later.
45 preg_match_all('/<style.*?>(.*?)<\/style>/si',$html,$m);
46 if (count($m[1])) {
47 for ($i = 0; $i < count($m[1]); $i++) {
48 // Remove comment tags
49 $sub = preg_replace('/(<\!\-\-|\-\->)/s',' ',$m[1][$i]);
50 $sub = '>'.preg_replace('|/\*.*?\*/|s',' ',$sub).'</style>';
51 $html = str_replace('>'.$m[1][$i].'</style>', $sub, $html);
52
53 }
54 }
55
56 $html = preg_replace('/<!--mpdf/i', '', $html);
57 $html = preg_replace('/mpdf-->/i', '', $html);
58 $html = preg_replace('/<\!\-\-.*?\-\->/s', ' ', $html);
59
60 $match = 0; // no match for instance
61 $regexp = ''; // This helps debugging: showing what is the REAL string being processed
62 $CSSext = array();
63
64 //CSS inside external files
65 $regexp = '/<link[^>]*rel=["\']stylesheet["\'][^>]*href=["\']([^>"\']*)["\'].*?>/si';
66 $x = preg_match_all($regexp, $html, $cxt);
67 if ($x) {
68 $match += $x;
69 $CSSext = $cxt[1];
70 }
71 $regexp = '/<link[^>]*href=["\']([^>"\']*)["\'][^>]*?rel=["\']stylesheet["\'].*?>/si';
72 $x = preg_match_all($regexp, $html, $cxt);
73 if ($x) {
74 $match += $x;
75 $CSSext = array_merge($CSSext, $cxt[1]);
76 }
77
78 // look for @import stylesheets
79 //$regexp = '/@import url\([\'\"]{0,1}([^\)]*?\.css)[\'\"]{0,1}\)/si';
80 $regexp = '/@import url\([\'\"]{0,1}([^\)]*?\.css(\?\S+)?)[\'\"]{0,1}\)/si';
81 $x = preg_match_all($regexp, $html, $cxt);
82 if ($x) {
83 $match += $x;
84 $CSSext = array_merge($CSSext, $cxt[1]);
85 }
86
87 // look for @import without the url()
88 //$regexp = '/@import [\'\"]{0,1}([^;]*?\.css)[\'\"]{0,1}/si';
89 $regexp = '/@import [\'\"]{0,1}([^;]*?\.css(\?\S+)?)[\'\"]{0,1}/si';
90 $x = preg_match_all($regexp, $html, $cxt);
91 if ($x) {
92 $match += $x;
93 $CSSext = array_merge($CSSext, $cxt[1]);
94 }
95
96 $ind = 0;
97 $CSSstr = '';
98
99 if (!is_array($this->cascadeCSS))
100 $this->cascadeCSS = array();
101
102 while ($match) {
103 $path = $CSSext[$ind];
104
105 $path = htmlspecialchars_decode($path); // mPDF 6
106
107 $this->mpdf->GetFullPath($path);
108 $CSSextblock = $this->mpdf->_get_file($path);
109 if ($CSSextblock) {
110 // look for embedded @import stylesheets in other stylesheets
111 // and fix url paths (including background-images) relative to stylesheet
112 //$regexpem = '/@import url\([\'\"]{0,1}(.*?\.css)[\'\"]{0,1}\)/si';
113 $regexpem = '/@import url\([\'\"]{0,1}(.*?\.css(\?\S+)?)[\'\"]{0,1}\)/si';
114 $xem = preg_match_all($regexpem, $CSSextblock, $cxtem);
115 $cssBasePath = preg_replace('/\/[^\/]*$/', '', $path) . '/';
116 if ($xem) {
117 foreach ($cxtem[1] AS $cxtembedded) {
118 // path is relative to original stlyesheet!!
119 $this->mpdf->GetFullPath($cxtembedded, $cssBasePath);
120 $match++;
121 $CSSext[] = $cxtembedded;
122 }
123 }
124 $regexpem = '/(background[^;]*url\s*\(\s*[\'\"]{0,1})([^\)\'\"]*)([\'\"]{0,1}\s*\))/si';
125 $xem = preg_match_all($regexpem, $CSSextblock, $cxtem);
126 if ($xem) {
127 for ($i = 0; $i < count($cxtem[0]); $i++) {
128 // path is relative to original stlyesheet!!
129 $embedded = $cxtem[2][$i];
130 if (!preg_match('/^data:image/i', $embedded)) { // mPDF 5.5.13
131 $this->mpdf->GetFullPath($embedded, $cssBasePath);
132 $CSSextblock = preg_replace('/' . preg_quote($cxtem[0][$i], '/') . '/', ($cxtem[1][$i] . $embedded . $cxtem[3][$i]), $CSSextblock);
133 }
134 }
135 }
136 $CSSstr .= ' ' . $CSSextblock;
137 }
138 $match--;
139 $ind++;
140 } //end of match
141
142 $match = 0; // reset value, if needed
143 // CSS as <style> in HTML document
144 $regexp = '/<style.*?>(.*?)<\/style>/si';
145 $match = preg_match_all($regexp, $html, $CSSblock);
146 if ($match) {
147 $tmpCSSstr = implode(' ', $CSSblock[1]);
148 $regexpem = '/(background[^;]*url\s*\(\s*[\'\"]{0,1})([^\)\'\"]*)([\'\"]{0,1}\s*\))/si';
149 $xem = preg_match_all($regexpem, $tmpCSSstr, $cxtem);
150 if ($xem) {
151 for ($i = 0; $i < count($cxtem[0]); $i++) {
152 $embedded = $cxtem[2][$i];
153 if (!preg_match('/^data:image/i', $embedded)) { // mPDF 5.5.13
154 $this->mpdf->GetFullPath($embedded);
155 $tmpCSSstr = preg_replace('/' . preg_quote($cxtem[0][$i], '/') . '/', ($cxtem[1][$i] . $embedded . $cxtem[3][$i]), $tmpCSSstr);
156 }
157 }
158 }
159 $CSSstr .= ' ' . $tmpCSSstr;
160 }
161 // Remove comments
162 $CSSstr = preg_replace('|/\*.*?\*/|s', ' ', $CSSstr);
163 $CSSstr = preg_replace('/[\s\n\r\t\f]/s', ' ', $CSSstr);
164
165 if (preg_match('/@media/', $CSSstr)) {
166 preg_match_all('/@media(.*?)\{(([^\{\}]*\{[^\{\}]*\})+)\s*\}/is', $CSSstr, $m);
167 for ($i = 0; $i < count($m[0]); $i++) {
168 if ($this->mpdf->CSSselectMedia && !preg_match('/(' . trim($this->mpdf->CSSselectMedia) . '|all)/i', $m[1][$i])) {
169 $CSSstr = preg_replace('/' . preg_quote($m[0][$i], '/') . '/', '', $CSSstr);
170 } else {
171 $CSSstr = preg_replace('/' . preg_quote($m[0][$i], '/') . '/', ' ' . $m[2][$i] . ' ', $CSSstr);
172 }
173 }
174 }
175
176 // Replace any background: url(data:image... with temporary image file reference
177 preg_match_all("/(url\(data:image\/(jpeg|gif|png);base64,(.*?)\))/si", $CSSstr, $idata); // mPDF 5.7.2
178 if (count($idata[0])) {
179 for ($i = 0; $i < count($idata[0]); $i++) {
180 $file = _MPDF_TEMP_PATH . '_tempCSSidata' . RAND(1, 10000) . '_' . $i . '.' . $idata[2][$i];
181 //Save to local file
182 file_put_contents($file, base64_decode($idata[3][$i]));
183 // $this->mpdf->GetFullPath($file); // ? is this needed - NO mPDF 5.6.03
184 $CSSstr = str_replace($idata[0][$i], 'url("' . $file . '")', $CSSstr); // mPDF 5.5.17
185 }
186 }
187
188 $CSSstr = preg_replace('/(<\!\-\-|\-\->)/s', ' ', $CSSstr);
189
190 // mPDF 5.7.4 URLs
191 // Characters "(" ")" and ";" in url() e.g. background-image, cause problems parsing the CSS string
192 // URLencode ( and ), but change ";" to a code which can be converted back after parsing (so as not to confuse ;
193 // with a segment delimiter in the URI)
194 $tempmarker = '%ZZ';
195 if (strpos($CSSstr, 'url(') !== false) {
196 preg_match_all('/url\(\"(.*?)\"\)/', $CSSstr, $m);
197 for ($i = 0; $i < count($m[1]); $i++) {
198 $tmp = str_replace(array('(', ')', ';'), array('%28', '%29', $tempmarker), $m[1][$i]);
199 $CSSstr = preg_replace('/' . preg_quote($m[0][$i], '/') . '/', 'url(\'' . $tmp . '\')', $CSSstr);
200 }
201 preg_match_all('/url\(\'(.*?)\'\)/', $CSSstr, $m);
202 for ($i = 0; $i < count($m[1]); $i++) {
203 $tmp = str_replace(array('(', ')', ';'), array('%28', '%29', $tempmarker), $m[1][$i]);
204 $CSSstr = preg_replace('/' . preg_quote($m[0][$i], '/') . '/', 'url(\'' . $tmp . '\')', $CSSstr);
205 }
206 preg_match_all('/url\(([^\'\"].*?[^\'\"])\)/', $CSSstr, $m);
207 for ($i = 0; $i < count($m[1]); $i++) {
208 $tmp = str_replace(array('(', ')', ';'), array('%28', '%29', $tempmarker), $m[1][$i]);
209 $CSSstr = preg_replace('/' . preg_quote($m[0][$i], '/') . '/', 'url(\'' . $tmp . '\')', $CSSstr);
210 }
211 }
212
213
214
215 if ($CSSstr) {
216 $classproperties = array(); // mPDF 6
217 preg_match_all('/(.*?)\{(.*?)\}/', $CSSstr, $styles);
218 for ($i = 0; $i < count($styles[1]); $i++) {
219 // SET array e.g. $classproperties['COLOR'] = '#ffffff';
220 $stylestr = trim($styles[2][$i]);
221 $stylearr = explode(';', $stylestr);
222 foreach ($stylearr AS $sta) {
223 if (trim($sta)) {
224 // Changed to allow style="background: url('http://www.bpm1.com/bg.jpg')"
225 $tmp = explode(':', $sta, 2);
226 $property = $tmp[0];
227 if (isset($tmp[1])) {
228 $value = $tmp[1];
229 } else {
230 $value = '';
231 }
232 $value = str_replace($tempmarker, ';', $value); // mPDF 5.7.4 URLs
233 $property = trim($property);
234 $value = preg_replace('/\s*!important/i', '', $value);
235 $value = trim($value);
236 if ($property && ($value || $value === '0')) {
237 // Ignores -webkit-gradient so doesn't override -moz-
238 if ((strtoupper($property) == 'BACKGROUND-IMAGE' || strtoupper($property) == 'BACKGROUND') && preg_match('/-webkit-gradient/i', $value)) {
239 continue;
240 }
241 $classproperties[strtoupper($property)] = $value;
242 }
243 }
244 }
245 $classproperties = $this->fixCSS($classproperties);
246 $tagstr = strtoupper(trim($styles[1][$i]));
247 $tagarr = explode(',', $tagstr);
248 $pageselectors = false; // used to turn on $this->mpdf->mirrorMargins
249 foreach ($tagarr AS $tg) {
250 // mPDF 5.7.4
251 if (preg_match('/NTH-CHILD\((\s*(([\-+]?\d*)N(\s*[\-+]\s*\d+)?|[\-+]?\d+|ODD|EVEN)\s*)\)/', $tg, $m)) {
252 $tg = preg_replace('/NTH-CHILD\(.*\)/', 'NTH-CHILD(' . str_replace(' ', '', $m[1]) . ')', $tg);
253 }
254 $tags = preg_split('/\s+/', trim($tg));
255 $level = count($tags);
256 $t = '';
257 $t2 = '';
258 $t3 = '';
259 if (trim($tags[0]) == '@PAGE') {
260 if (isset($tags[0])) {
261 $t = trim($tags[0]);
262 }
263 if (isset($tags[1])) {
264 $t2 = trim($tags[1]);
265 }
266 if (isset($tags[2])) {
267 $t3 = trim($tags[2]);
268 }
269 $tag = '';
270 if ($level == 1) {
271 $tag = $t;
272 } else if ($level == 2 && preg_match('/^[:](.*)$/', $t2, $m)) {
273 $tag = $t . '>>PSEUDO>>' . $m[1];
274 if ($m[1] == 'LEFT' || $m[1] == 'RIGHT') {
275 $pageselectors = true;
276 } // used to turn on $this->mpdf->mirrorMargins
277 } else if ($level == 2) {
278 $tag = $t . '>>NAMED>>' . $t2;
279 } else if ($level == 3 && preg_match('/^[:](.*)$/', $t3, $m)) {
280 $tag = $t . '>>NAMED>>' . $t2 . '>>PSEUDO>>' . $m[1];
281 if ($m[1] == 'LEFT' || $m[1] == 'RIGHT') {
282 $pageselectors = true;
283 } // used to turn on $this->mpdf->mirrorMargins
284 }
285 if (isset($this->CSS[$tag]) && $tag) {
286 $this->CSS[$tag] = $this->array_merge_recursive_unique($this->CSS[$tag], $classproperties);
287 } else if ($tag) {
288 $this->CSS[$tag] = $classproperties;
289 }
290 } else if ($level == 1) { // e.g. p or .class or #id or p.class or p#id
291 if (isset($tags[0])) {
292 $t = trim($tags[0]);
293 }
294 if ($t) {
295 $tag = '';
296 if (preg_match('/^[.](.*)$/', $t, $m)) {
297 $tag = 'CLASS>>' . $m[1];
298 } else if (preg_match('/^[#](.*)$/', $t, $m)) {
299 $tag = 'ID>>' . $m[1];
300 } else if (preg_match('/^\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/', $t, $m)) {
301 $tag = 'LANG>>' . strtolower($m[1]);
302 } // mPDF 6 Special case for lang as attribute selector
303 else if (preg_match('/^:LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/', $t, $m)) {
304 $tag = 'LANG>>' . strtolower($m[1]);
305 } // mPDF 6 Special case for lang as attribute selector
306 else if (preg_match('/^(' . $this->mpdf->allowedCSStags . ')[.](.*)$/', $t, $m)) {
307 $tag = $m[1] . '>>CLASS>>' . $m[2];
308 } else if (preg_match('/^(' . $this->mpdf->allowedCSStags . ')\s*:NTH-CHILD\((.*)\)$/', $t, $m)) {
309 $tag = $m[1] . '>>SELECTORNTHCHILD>>' . $m[2];
310 } else if (preg_match('/^(' . $this->mpdf->allowedCSStags . ')[#](.*)$/', $t, $m)) {
311 $tag = $m[1] . '>>ID>>' . $m[2];
312 } else if (preg_match('/^(' . $this->mpdf->allowedCSStags . ')\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/', $t, $m)) {
313 $tag = $m[1] . '>>LANG>>' . strtolower($m[2]);
314 } // mPDF 6 Special case for lang as attribute selector
315 else if (preg_match('/^(' . $this->mpdf->allowedCSStags . '):LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/', $t, $m)) {
316 $tag = $m[1] . '>>LANG>>' . strtolower($m[2]);
317 } // mPDF 6 Special case for lang as attribute selector
318 else if (preg_match('/^(' . $this->mpdf->allowedCSStags . ')$/', $t)) {
319 $tag = $t;
320 }
321 if (isset($this->CSS[$tag]) && $tag) {
322 $this->CSS[$tag] = $this->array_merge_recursive_unique($this->CSS[$tag], $classproperties);
323 } else if ($tag) {
324 $this->CSS[$tag] = $classproperties;
325 }
326 }
327 } else {
328 $tmp = array();
329 for ($n = 0; $n < $level; $n++) {
330 if (isset($tags[$n])) {
331 $t = trim($tags[$n]);
332 } else {
333 $t = '';
334 }
335 if ($t) {
336 $tag = '';
337 if (preg_match('/^[.](.*)$/', $t, $m)) {
338 $tag = 'CLASS>>' . $m[1];
339 } else if (preg_match('/^[#](.*)$/', $t, $m)) {
340 $tag = 'ID>>' . $m[1];
341 } else if (preg_match('/^\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/', $t, $m)) {
342 $tag = 'LANG>>' . strtolower($m[1]);
343 } // mPDF 6 Special case for lang as attribute selector
344 else if (preg_match('/^:LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/', $t, $m)) {
345 $tag = 'LANG>>' . strtolower($m[1]);
346 } // mPDF 6 Special case for lang as attribute selector
347 else if (preg_match('/^(' . $this->mpdf->allowedCSStags . ')[.](.*)$/', $t, $m)) {
348 $tag = $m[1] . '>>CLASS>>' . $m[2];
349 } else if (preg_match('/^(' . $this->mpdf->allowedCSStags . ')\s*:NTH-CHILD\((.*)\)$/', $t, $m)) {
350 $tag = $m[1] . '>>SELECTORNTHCHILD>>' . $m[2];
351 } else if (preg_match('/^(' . $this->mpdf->allowedCSStags . ')[#](.*)$/', $t, $m)) {
352 $tag = $m[1] . '>>ID>>' . $m[2];
353 } else if (preg_match('/^(' . $this->mpdf->allowedCSStags . ')\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/', $t, $m)) {
354 $tag = $m[1] . '>>LANG>>' . strtolower($m[2]);
355 } // mPDF 6 Special case for lang as attribute selector
356 else if (preg_match('/^(' . $this->mpdf->allowedCSStags . '):LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/', $t, $m)) {
357 $tag = $m[1] . '>>LANG>>' . strtolower($m[2]);
358 } // mPDF 6 Special case for lang as attribute selector
359 else if (preg_match('/^(' . $this->mpdf->allowedCSStags . ')$/', $t)) {
360 $tag = $t;
361 }
362
363 if ($tag)
364 $tmp[] = $tag;
365 else {
366 break;
367 }
368 }
369 }
370
371 if ($tag) {
372 $x = &$this->cascadeCSS;
373 foreach ($tmp AS $tp) {
374 $x = &$x[$tp];
375 }
376 $x = $this->array_merge_recursive_unique($x, $classproperties);
377 $x['depth'] = $level;
378 }
379 }
380 }
381 if ($pageselectors) {
382 $this->mpdf->mirrorMargins = true;
383 }
384 $properties = array();
385 $values = array();
386 $classproperties = array();
387 }
388 } // end of if
389 //Remove CSS (tags and content), if any
390 $regexp = '/<style.*?>(.*?)<\/style>/si'; // it can be <style> or <style type="txt/css">
391 $html = preg_replace($regexp, '', $html);
392 //print_r($this->CSS); exit;
393 //print_r($this->cascadeCSS); exit;
394 return $html;
395 }
396
397 function readInlineCSS($html)
398 {
399 $html = htmlspecialchars_decode($html); // mPDF 5.7.4 URLs
400 // mPDF 5.7.4 URLs
401 // Characters "(" ")" and ";" in url() e.g. background-image, cause probems parsing the CSS string
402 // URLencode ( and ), but change ";" to a code which can be converted back after parsing (so as not to confuse ;
403 // with a segment delimiter in the URI)
404 $tempmarker = '%ZZ';
405 if (strpos($html, 'url(') !== false) {
406 preg_match_all('/url\(\"(.*?)\"\)/', $html, $m);
407 for ($i = 0; $i < count($m[1]); $i++) {
408 $tmp = str_replace(array('(', ')', ';'), array('%28', '%29', $tempmarker), $m[1][$i]);
409 $html = preg_replace('/' . preg_quote($m[0][$i], '/') . '/', 'url(\'' . $tmp . '\')', $html);
410 }
411 preg_match_all('/url\(\'(.*?)\'\)/', $html, $m);
412 for ($i = 0; $i < count($m[1]); $i++) {
413 $tmp = str_replace(array('(', ')', ';'), array('%28', '%29', $tempmarker), $m[1][$i]);
414 $html = preg_replace('/' . preg_quote($m[0][$i], '/') . '/', 'url(\'' . $tmp . '\')', $html);
415 }
416 preg_match_all('/url\(([^\'\"].*?[^\'\"])\)/', $html, $m);
417 for ($i = 0; $i < count($m[1]); $i++) {
418 $tmp = str_replace(array('(', ')', ';'), array('%28', '%29', $tempmarker), $m[1][$i]);
419 $html = preg_replace('/' . preg_quote($m[0][$i], '/') . '/', 'url(\'' . $tmp . '\')', $html);
420 }
421 }
422 //Fix incomplete CSS code
423 $size = strlen($html) - 1;
424 if (substr($html, $size, 1) != ';')
425 $html .= ';';
426 //Make CSS[Name-of-the-class] = array(key => value)
427 $regexp = '|\\s*?(\\S+?):(.+?);|i';
428 preg_match_all($regexp, $html, $styleinfo);
429 $properties = $styleinfo[1];
430 $values = $styleinfo[2];
431 //Array-properties and Array-values must have the SAME SIZE!
432 $classproperties = array();
433 for ($i = 0; $i < count($properties); $i++) {
434 // Ignores -webkit-gradient so doesn't override -moz-
435 if ((strtoupper($properties[$i]) == 'BACKGROUND-IMAGE' || strtoupper($properties[$i]) == 'BACKGROUND') && preg_match('/-webkit-gradient/i', $values[$i])) {
436 continue;
437 }
438 $values[$i] = str_replace($tempmarker, ';', $values[$i]); // mPDF 5.7.4 URLs
439 $classproperties[strtoupper($properties[$i])] = trim($values[$i]);
440 }
441 return $this->fixCSS($classproperties);
442 }
443
444 function _fix_borderStr($bd)
445 {
446 preg_match_all("/\((.*?)\)/", $bd, $m);
447 if (count($m[1])) {
448 for ($i = 0; $i < count($m[1]); $i++) {
449 $sub = preg_replace("/ /", "", $m[1][$i]);
450 $bd = preg_replace('/' . preg_quote($m[1][$i], '/') . '/si', $sub, $bd);
451 }
452 }
453
454 $prop = preg_split('/\s+/', trim($bd));
455 $w = 'medium';
456 $c = '#000000';
457 $s = 'none';
458
459 if (count($prop) == 1) {
460 // solid
461 if (in_array($prop[0], $this->mpdf->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden') {
462 $s = $prop[0];
463 }
464 // #000000
465 else if (is_array($this->mpdf->ConvertColor($prop[0]))) {
466 $c = $prop[0];
467 }
468 // 1px
469 else {
470 $w = $prop[0];
471 }
472 } else if (count($prop) == 2) {
473 // 1px solid
474 if (in_array($prop[1], $this->mpdf->borderstyles) || $prop[1] == 'none' || $prop[1] == 'hidden') {
475 $w = $prop[0];
476 $s = $prop[1];
477 }
478 // solid #000000
479 else if (in_array($prop[0], $this->mpdf->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden') {
480 $s = $prop[0];
481 $c = $prop[1];
482 }
483 // 1px #000000
484 else {
485 $w = $prop[0];
486 $c = $prop[1];
487 }
488 } else if (count($prop) == 3) {
489 // Change #000000 1px solid to 1px solid #000000 (proper)
490 if (substr($prop[0], 0, 1) == '#') {
491 $c = $prop[0];
492 $w = $prop[1];
493 $s = $prop[2];
494 }
495 // Change solid #000000 1px to 1px solid #000000 (proper)
496 else if (substr($prop[0], 1, 1) == '#') {
497 $s = $prop[0];
498 $c = $prop[1];
499 $w = $prop[2];
500 }
501 // Change solid 1px #000000 to 1px solid #000000 (proper)
502 else if (in_array($prop[0], $this->mpdf->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden') {
503 $s = $prop[0];
504 $w = $prop[1];
505 $c = $prop[2];
506 } else {
507 $w = $prop[0];
508 $s = $prop[1];
509 $c = $prop[2];
510 }
511 } else {
512 return '';
513 }
514 $s = strtolower($s);
515 return $w . ' ' . $s . ' ' . $c;
516 }
517
518 function fixCSS($prop)
519 {
520 if (!is_array($prop) || (count($prop) == 0))
521 return array();
522 $newprop = array();
523 foreach ($prop AS $k => $v) {
524 if ($k != 'BACKGROUND-IMAGE' && $k != 'BACKGROUND' && $k != 'ODD-HEADER-NAME' && $k != 'EVEN-HEADER-NAME' && $k != 'ODD-FOOTER-NAME' && $k != 'EVEN-FOOTER-NAME' && $k != 'HEADER' && $k != 'FOOTER') {
525 $v = strtolower($v);
526 }
527
528 if ($k == 'FONT') {
529 $s = trim($v);
530 preg_match_all('/\"(.*?)\"/', $s, $ff);
531 if (count($ff[1])) {
532 foreach ($ff[1] AS $ffp) {
533 $w = preg_split('/\s+/', $ffp);
534 $s = preg_replace('/\"' . $ffp . '\"/', $w[0], $s);
535 }
536 }
537 preg_match_all('/\'(.*?)\'/', $s, $ff);
538 if (count($ff[1])) {
539 foreach ($ff[1] AS $ffp) {
540 $w = preg_split('/\s+/', $ffp);
541 $s = preg_replace('/\'' . $ffp . '\'/', $w[0], $s);
542 }
543 }
544 $s = preg_replace('/\s*,\s*/', ',', $s);
545 $bits = preg_split('/\s+/', $s);
546 if (count($bits) > 1) {
547 $k = 'FONT-FAMILY';
548 $v = $bits[(count($bits) - 1)];
549 $fs = $bits[(count($bits) - 2)];
550 if (preg_match('/(.*?)\/(.*)/', $fs, $fsp)) {
551 $newprop['FONT-SIZE'] = $fsp[1];
552 $newprop['LINE-HEIGHT'] = $fsp[2];
553 } else {
554 $newprop['FONT-SIZE'] = $fs;
555 }
556 if (preg_match('/(italic|oblique)/i', $s)) {
557 $newprop['FONT-STYLE'] = 'italic';
558 } else {
559 $newprop['FONT-STYLE'] = 'normal';
560 }
561 if (preg_match('/bold/i', $s)) {
562 $newprop['FONT-WEIGHT'] = 'bold';
563 } else {
564 $newprop['FONT-WEIGHT'] = 'normal';
565 }
566 if (preg_match('/small-caps/i', $s)) {
567 $newprop['TEXT-TRANSFORM'] = 'uppercase';
568 }
569 }
570 } else if ($k == 'FONT-FAMILY') {
571 $aux_fontlist = explode(",", $v);
572 $found = 0;
573 foreach ($aux_fontlist AS $f) {
574 $fonttype = trim($f);
575 $fonttype = preg_replace('/["\']*(.*?)["\']*/', '\\1', $fonttype);
576 $fonttype = preg_replace('/ /', '', $fonttype);
577 $v = strtolower(trim($fonttype));
578 if (isset($this->mpdf->fonttrans[$v]) && $this->mpdf->fonttrans[$v]) {
579 $v = $this->mpdf->fonttrans[$v];
580 }
581 if ((!$this->mpdf->onlyCoreFonts && in_array($v, $this->mpdf->available_unifonts)) ||
582 in_array($v, array('ccourier', 'ctimes', 'chelvetica')) ||
583 ($this->mpdf->onlyCoreFonts && in_array($v, array('courier', 'times', 'helvetica', 'arial'))) ||
584 in_array($v, array('sjis', 'uhc', 'big5', 'gb'))) {
585 $newprop[$k] = $v;
586 $found = 1;
587 break;
588 }
589 }
590 if (!$found) {
591 foreach ($aux_fontlist AS $f) {
592 $fonttype = trim($f);
593 $fonttype = preg_replace('/["\']*(.*?)["\']*/', '\\1', $fonttype);
594 $fonttype = preg_replace('/ /', '', $fonttype);
595 $v = strtolower(trim($fonttype));
596 if (isset($this->mpdf->fonttrans[$v]) && $this->mpdf->fonttrans[$v]) {
597 $v = $this->mpdf->fonttrans[$v];
598 }
599 if (in_array($v, $this->mpdf->sans_fonts) || in_array($v, $this->mpdf->serif_fonts) || in_array($v, $this->mpdf->mono_fonts)) {
600 $newprop[$k] = $v;
601 break;
602 }
603 }
604 }
605 }
606 // mPDF 5.7.1
607 else if ($k == 'FONT-VARIANT') {
608 if (preg_match('/(normal|none)/', $v, $m)) { // mPDF 6
609 $newprop['FONT-VARIANT-LIGATURES'] = $m[1];
610 $newprop['FONT-VARIANT-CAPS'] = $m[1];
611 $newprop['FONT-VARIANT-NUMERIC'] = $m[1];
612 $newprop['FONT-VARIANT-ALTERNATES'] = $m[1];
613 } else {
614 if (preg_match_all('/(no-common-ligatures|\bcommon-ligatures|no-discretionary-ligatures|\bdiscretionary-ligatures|no-historical-ligatures|\bhistorical-ligatures|no-contextual|\bcontextual)/i', $v, $m)) {
615 $newprop['FONT-VARIANT-LIGATURES'] = implode(' ', $m[1]);
616 }
617 if (preg_match('/(all-small-caps|\bsmall-caps|all-petite-caps|\bpetite-caps|unicase|titling-caps)/i', $v, $m)) {
618 $newprop['FONT-VARIANT-CAPS'] = $m[1];
619 }
620 if (preg_match_all('/(lining-nums|oldstyle-nums|proportional-nums|tabular-nums|diagonal-fractions|stacked-fractions)/i', $v, $m)) {
621 $newprop['FONT-VARIANT-NUMERIC'] = implode(' ', $m[1]);
622 }
623 if (preg_match('/(historical-forms)/i', $v, $m)) {
624 $newprop['FONT-VARIANT-ALTERNATES'] = $m[1];
625 }
626 }
627 } else if ($k == 'MARGIN') {
628 $tmp = $this->expand24($v);
629 $newprop['MARGIN-TOP'] = $tmp['T'];
630 $newprop['MARGIN-RIGHT'] = $tmp['R'];
631 $newprop['MARGIN-BOTTOM'] = $tmp['B'];
632 $newprop['MARGIN-LEFT'] = $tmp['L'];
633 }
634 /* -- BORDER-RADIUS -- */ else if ($k == 'BORDER-RADIUS' || $k == 'BORDER-TOP-LEFT-RADIUS' || $k == 'BORDER-TOP-RIGHT-RADIUS' || $k == 'BORDER-BOTTOM-LEFT-RADIUS' || $k == 'BORDER-BOTTOM-RIGHT-RADIUS') {
635 $tmp = $this->border_radius_expand($v, $k);
636 if (isset($tmp['TL-H']))
637 $newprop['BORDER-TOP-LEFT-RADIUS-H'] = $tmp['TL-H'];
638 if (isset($tmp['TL-V']))
639 $newprop['BORDER-TOP-LEFT-RADIUS-V'] = $tmp['TL-V'];
640 if (isset($tmp['TR-H']))
641 $newprop['BORDER-TOP-RIGHT-RADIUS-H'] = $tmp['TR-H'];
642 if (isset($tmp['TR-V']))
643 $newprop['BORDER-TOP-RIGHT-RADIUS-V'] = $tmp['TR-V'];
644 if (isset($tmp['BL-H']))
645 $newprop['BORDER-BOTTOM-LEFT-RADIUS-H'] = $tmp['BL-H'];
646 if (isset($tmp['BL-V']))
647 $newprop['BORDER-BOTTOM-LEFT-RADIUS-V'] = $tmp['BL-V'];
648 if (isset($tmp['BR-H']))
649 $newprop['BORDER-BOTTOM-RIGHT-RADIUS-H'] = $tmp['BR-H'];
650 if (isset($tmp['BR-V']))
651 $newprop['BORDER-BOTTOM-RIGHT-RADIUS-V'] = $tmp['BR-V'];
652 }
653 /* -- END BORDER-RADIUS -- */
654 else if ($k == 'PADDING') {
655 $tmp = $this->expand24($v);
656 $newprop['PADDING-TOP'] = $tmp['T'];
657 $newprop['PADDING-RIGHT'] = $tmp['R'];
658 $newprop['PADDING-BOTTOM'] = $tmp['B'];
659 $newprop['PADDING-LEFT'] = $tmp['L'];
660 } else if ($k == 'BORDER') {
661 if ($v == '1') {
662 $v = '1px solid #000000';
663 } else {
664 $v = $this->_fix_borderStr($v);
665 }
666 $newprop['BORDER-TOP'] = $v;
667 $newprop['BORDER-RIGHT'] = $v;
668 $newprop['BORDER-BOTTOM'] = $v;
669 $newprop['BORDER-LEFT'] = $v;
670 } else if ($k == 'BORDER-TOP') {
671 $newprop['BORDER-TOP'] = $this->_fix_borderStr($v);
672 } else if ($k == 'BORDER-RIGHT') {
673 $newprop['BORDER-RIGHT'] = $this->_fix_borderStr($v);
674 } else if ($k == 'BORDER-BOTTOM') {
675 $newprop['BORDER-BOTTOM'] = $this->_fix_borderStr($v);
676 } else if ($k == 'BORDER-LEFT') {
677 $newprop['BORDER-LEFT'] = $this->_fix_borderStr($v);
678 } else if ($k == 'BORDER-STYLE') {
679 $e = $this->expand24($v);
680 if (!empty($e)) {
681 $newprop['BORDER-TOP-STYLE'] = $e['T'];
682 $newprop['BORDER-RIGHT-STYLE'] = $e['R'];
683 $newprop['BORDER-BOTTOM-STYLE'] = $e['B'];
684 $newprop['BORDER-LEFT-STYLE'] = $e['L'];
685 }
686 } else if ($k == 'BORDER-WIDTH') {
687 $e = $this->expand24($v);
688 if (!empty($e)) {
689 $newprop['BORDER-TOP-WIDTH'] = $e['T'];
690 $newprop['BORDER-RIGHT-WIDTH'] = $e['R'];
691 $newprop['BORDER-BOTTOM-WIDTH'] = $e['B'];
692 $newprop['BORDER-LEFT-WIDTH'] = $e['L'];
693 }
694 } else if ($k == 'BORDER-COLOR') {
695 $e = $this->expand24($v);
696 if (!empty($e)) {
697 $newprop['BORDER-TOP-COLOR'] = $e['T'];
698 $newprop['BORDER-RIGHT-COLOR'] = $e['R'];
699 $newprop['BORDER-BOTTOM-COLOR'] = $e['B'];
700 $newprop['BORDER-LEFT-COLOR'] = $e['L'];
701 }
702 } else if ($k == 'BORDER-SPACING') {
703 $prop = preg_split('/\s+/', trim($v));
704 if (count($prop) == 1) {
705 $newprop['BORDER-SPACING-H'] = $prop[0];
706 $newprop['BORDER-SPACING-V'] = $prop[0];
707 } else if (count($prop) == 2) {
708 $newprop['BORDER-SPACING-H'] = $prop[0];
709 $newprop['BORDER-SPACING-V'] = $prop[1];
710 }
711 } else if ($k == 'TEXT-OUTLINE') { // mPDF 5.6.07
712 $prop = preg_split('/\s+/', trim($v));
713 if (trim(strtolower($v)) == 'none') {
714 $newprop['TEXT-OUTLINE'] = 'none';
715 } else if (count($prop) == 2) {
716 $newprop['TEXT-OUTLINE-WIDTH'] = $prop[0];
717 $newprop['TEXT-OUTLINE-COLOR'] = $prop[1];
718 } else if (count($prop) == 3) {
719 $newprop['TEXT-OUTLINE-WIDTH'] = $prop[0];
720 $newprop['TEXT-OUTLINE-COLOR'] = $prop[2];
721 }
722 } else if ($k == 'SIZE') {
723 $prop = preg_split('/\s+/', trim($v));
724 if (preg_match('/(auto|portrait|landscape)/', $prop[0])) {
725 $newprop['SIZE'] = strtoupper($prop[0]);
726 } else if (count($prop) == 1) {
727 $newprop['SIZE']['W'] = $this->mpdf->ConvertSize($prop[0]);
728 $newprop['SIZE']['H'] = $this->mpdf->ConvertSize($prop[0]);
729 } else if (count($prop) == 2) {
730 $newprop['SIZE']['W'] = $this->mpdf->ConvertSize($prop[0]);
731 $newprop['SIZE']['H'] = $this->mpdf->ConvertSize($prop[1]);
732 }
733 } else if ($k == 'SHEET-SIZE') {
734 $prop = preg_split('/\s+/', trim($v));
735 if (count($prop) == 2) {
736 $newprop['SHEET-SIZE'] = array($this->mpdf->ConvertSize($prop[0]), $this->mpdf->ConvertSize($prop[1]));
737 } else {
738 if (preg_match('/([0-9a-zA-Z]*)-L/i', $v, $m)) { // e.g. A4-L = A$ landscape
739 $ft = $this->mpdf->_getPageFormat($m[1]);
740 $format = array($ft[1], $ft[0]);
741 } else {
742 $format = $this->mpdf->_getPageFormat($v);
743 }
744 if ($format) {
745 $newprop['SHEET-SIZE'] = array($format[0] / _MPDFK, $format[1] / _MPDFK);
746 }
747 }
748 } else if ($k == 'BACKGROUND') {
749 $bg = $this->parseCSSbackground($v);
750 if ($bg['c']) {
751 $newprop['BACKGROUND-COLOR'] = $bg['c'];
752 } else {
753 $newprop['BACKGROUND-COLOR'] = 'transparent';
754 }
755 /* -- BACKGROUNDS -- */
756 if ($bg['i']) {
757 $newprop['BACKGROUND-IMAGE'] = $bg['i'];
758 if ($bg['r']) {
759 $newprop['BACKGROUND-REPEAT'] = $bg['r'];
760 }
761 if ($bg['p']) {
762 $newprop['BACKGROUND-POSITION'] = $bg['p'];
763 }
764 } else {
765 $newprop['BACKGROUND-IMAGE'] = '';
766 }
767 /* -- END BACKGROUNDS -- */
768 }
769 /* -- BACKGROUNDS -- */ else if ($k == 'BACKGROUND-IMAGE') {
770 if (preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient\(.*\)/i', $v, $m)) {
771 $newprop['BACKGROUND-IMAGE'] = $m[0];
772 continue;
773 }
774 if (preg_match('/url\([\'\"]{0,1}(.*?)[\'\"]{0,1}\)/i', $v, $m)) {
775 $newprop['BACKGROUND-IMAGE'] = $m[1];
776 } else if (strtolower($v) == 'none') {
777 $newprop['BACKGROUND-IMAGE'] = '';
778 }
779 } else if ($k == 'BACKGROUND-REPEAT') {
780 if (preg_match('/(repeat-x|repeat-y|no-repeat|repeat)/i', $v, $m)) {
781 $newprop['BACKGROUND-REPEAT'] = strtolower($m[1]);
782 }
783 } else if ($k == 'BACKGROUND-POSITION') {
784 $s = $v;
785 $bits = preg_split('/\s+/', trim($s));
786 // These should be Position x1 or x2
787 if (count($bits) == 1) {
788 if (preg_match('/bottom/', $bits[0])) {
789 $bg['p'] = '50% 100%';
790 } else if (preg_match('/top/', $bits[0])) {
791 $bg['p'] = '50% 0%';
792 } else {
793 $bg['p'] = $bits[0] . ' 50%';
794 }
795 } else if (count($bits) == 2) {
796 // Can be either right center or center right
797 if (preg_match('/(top|bottom)/', $bits[0]) || preg_match('/(left|right)/', $bits[1])) {
798 $bg['p'] = $bits[1] . ' ' . $bits[0];
799 } else {
800 $bg['p'] = $bits[0] . ' ' . $bits[1];
801 }
802 }
803 if ($bg['p']) {
804 $bg['p'] = preg_replace('/(left|top)/', '0%', $bg['p']);
805 $bg['p'] = preg_replace('/(right|bottom)/', '100%', $bg['p']);
806 $bg['p'] = preg_replace('/(center)/', '50%', $bg['p']);
807 if (!preg_match('/[\-]{0,1}\d+(in|cm|mm|pt|pc|em|ex|px|%)* [\-]{0,1}\d+(in|cm|mm|pt|pc|em|ex|px|%)*/', $bg['p'])) {
808 $bg['p'] = false;
809 }
810 }
811 if ($bg['p']) {
812 $newprop['BACKGROUND-POSITION'] = $bg['p'];
813 }
814 }
815 /* -- END BACKGROUNDS -- */ else if ($k == 'IMAGE-ORIENTATION') {
816 if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i', $v, $m)) {
817 $angle = $m[1] + 0;
818 if (strtolower($m[2]) == 'deg') {
819 $angle = $angle;
820 } else if (strtolower($m[2]) == 'grad') {
821 $angle *= (360 / 400);
822 } else if (strtolower($m[2]) == 'rad') {
823 $angle = rad2deg($angle);
824 }
825 while ($angle < 0) {
826 $angle += 360;
827 }
828 $angle = ($angle % 360);
829 $angle /= 90;
830 $angle = round($angle) * 90;
831 $newprop['IMAGE-ORIENTATION'] = $angle;
832 }
833 } else if ($k == 'TEXT-ALIGN') {
834 if (preg_match('/["\'](.){1}["\']/i', $v, $m)) {
835 $d = array_search($m[1], $this->mpdf->decimal_align);
836 if ($d !== false) {
837 $newprop['TEXT-ALIGN'] = $d;
838 }
839 if (preg_match('/(center|left|right)/i', $v, $m)) {
840 $newprop['TEXT-ALIGN'] .= strtoupper(substr($m[1], 0, 1));
841 } else {
842 $newprop['TEXT-ALIGN'] .= 'R';
843 } // default = R
844 } else if (preg_match('/["\'](\\\[a-fA-F0-9]{1,6})["\']/i', $v, $m)) {
845 $utf8 = codeHex2utf(substr($m[1], 1, 6));
846 $d = array_search($utf8, $this->mpdf->decimal_align);
847 if ($d !== false) {
848 $newprop['TEXT-ALIGN'] = $d;
849 }
850 if (preg_match('/(center|left|right)/i', $v, $m)) {
851 $newprop['TEXT-ALIGN'] .= strtoupper(substr($m[1], 0, 1));
852 } else {
853 $newprop['TEXT-ALIGN'] .= 'R';
854 } // default = R
855 } else {
856 $newprop[$k] = $v;
857 }
858 }
859 // mpDF 6 Lists
860 else if ($k == 'LIST-STYLE') {
861 if (preg_match('/none/i', $v, $m)) {
862 $newprop['LIST-STYLE-TYPE'] = 'none';
863 $newprop['LIST-STYLE-IMAGE'] = 'none';
864 }
865 if (preg_match('/(lower-roman|upper-roman|lower-latin|lower-alpha|upper-latin|upper-alpha|decimal|disc|circle|square|arabic-indic|bengali|devanagari|gujarati|gurmukhi|kannada|malayalam|oriya|persian|tamil|telugu|thai|urdu|cambodian|khmer|lao|cjk-decimal|hebrew)/i', $v, $m)) {
866 $newprop['LIST-STYLE-TYPE'] = strtolower(trim($m[1]));
867 } else if (preg_match('/U\+([a-fA-F0-9]+)/i', $v, $m)) {
868 $newprop['LIST-STYLE-TYPE'] = strtolower(trim($m[1]));
869 }
870 if (preg_match('/url\([\'\"]{0,1}(.*?)[\'\"]{0,1}\)/i', $v, $m)) {
871 $newprop['LIST-STYLE-IMAGE'] = strtolower(trim($m[1]));
872 }
873 if (preg_match('/(inside|outside)/i', $v, $m)) {
874 $newprop['LIST-STYLE-POSITION'] = strtolower(trim($m[1]));
875 }
876 } else {
877 $newprop[$k] = $v;
878 }
879 }
880
881 return $newprop;
882 }
883
884 function setCSSboxshadow($v)
885 {
886 $sh = array();
887 $c = preg_match_all('/(rgba|rgb|device-cmyka|cmyka|device-cmyk|cmyk|hsla|hsl)\(.*?\)/', $v, $x); // mPDF 5.6.05
888 for ($i = 0; $i < $c; $i++) {
889 $col = preg_replace('/,/', '*', $x[0][$i]);
890 $v = preg_replace('/' . preg_quote($x[0][$i], '/') . '/', $col, $v);
891 }
892 $ss = explode(',', $v);
893 foreach ($ss AS $s) {
894 $new = array('inset' => false, 'blur' => 0, 'spread' => 0);
895 if (preg_match('/inset/i', $s)) {
896 $new['inset'] = true;
897 $s = preg_replace('/\s*inset\s*/', '', $s);
898 }
899 $p = explode(' ', trim($s));
900 if (isset($p[0])) {
901 $new['x'] = $this->mpdf->ConvertSize(trim($p[0]), $this->mpdf->blk[$this->mpdf->blklvl - 1]['inner_width'], $this->mpdf->FontSize, false);
902 }
903 if (isset($p[1])) {
904 $new['y'] = $this->mpdf->ConvertSize(trim($p[1]), $this->mpdf->blk[$this->mpdf->blklvl - 1]['inner_width'], $this->mpdf->FontSize, false);
905 }
906 if (isset($p[2])) {
907 if (preg_match('/^\s*[\.\-0-9]/', $p[2])) {
908 $new['blur'] = $this->mpdf->ConvertSize(trim($p[2]), $this->mpdf->blk[$this->mpdf->blklvl - 1]['inner_width'], $this->mpdf->FontSize, false);
909 } else {
910 $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/', ',', $p[2]));
911 }
912 if (isset($p[3])) {
913 if (preg_match('/^\s*[\.\-0-9]/', $p[3])) {
914 $new['spread'] = $this->mpdf->ConvertSize(trim($p[3]), $this->mpdf->blk[$this->mpdf->blklvl - 1]['inner_width'], $this->mpdf->FontSize, false);
915 } else {
916 $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/', ',', $p[3]));
917 }
918 if (isset($p[4])) {
919 $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/', ',', $p[4]));
920 }
921 }
922 }
923 if (!$new['col']) {
924 $new['col'] = $this->mpdf->ConvertColor('#888888');
925 }
926 if (isset($new['y'])) {
927 array_unshift($sh, $new);
928 }
929 }
930 return $sh;
931 }
932
933 function setCSStextshadow($v)
934 {
935 $sh = array();
936 $c = preg_match_all('/(rgba|rgb|device-cmyka|cmyka|device-cmyk|cmyk|hsla|hsl)\(.*?\)/', $v, $x); // mPDF 5.6.05
937 for ($i = 0; $i < $c; $i++) {
938 $col = preg_replace('/,/', '*', $x[0][$i]);
939 $v = preg_replace('/' . preg_quote($x[0][$i], '/') . '/', $col, $v);
940 }
941 $ss = explode(',', $v);
942 foreach ($ss AS $s) {
943 $new = array('blur' => 0);
944 $p = explode(' ', trim($s));
945 if (isset($p[0])) {
946 $new['x'] = $this->mpdf->ConvertSize(trim($p[0]), $this->mpdf->FontSize, $this->mpdf->FontSize, false);
947 }
948 if (isset($p[1])) {
949 $new['y'] = $this->mpdf->ConvertSize(trim($p[1]), $this->mpdf->FontSize, $this->mpdf->FontSize, false);
950 }
951 if (isset($p[2])) {
952 if (preg_match('/^\s*[\.\-0-9]/', $p[2])) {
953 $new['blur'] = $this->mpdf->ConvertSize(trim($p[2]), $this->mpdf->blk[$this->mpdf->blklvl]['inner_width'], $this->mpdf->FontSize, false);
954 } else {
955 $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/', ',', $p[2]));
956 }
957 if (isset($p[3])) {
958 $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/', ',', $p[3]));
959 }
960 }
961 if (!isset($new['col']) || !$new['col']) {
962 $new['col'] = $this->mpdf->ConvertColor('#888888');
963 }
964 if (isset($new['y'])) {
965 array_unshift($sh, $new);
966 }
967 }
968 return $sh;
969 }
970
971 function parseCSSbackground($s)
972 {
973 $bg = array('c' => false, 'i' => false, 'r' => false, 'p' => false,);
974 /* -- BACKGROUNDS -- */
975 if (preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient\(.*\)/i', $s, $m)) {
976 $bg['i'] = $m[0];
977 } else
978 /* -- END BACKGROUNDS -- */
979 if (preg_match('/url\(/i', $s)) {
980 // If color, set and strip it off
981 // mPDF 5.6.05
982 if (preg_match('/^\s*(#[0-9a-fA-F]{3,6}|(rgba|rgb|device-cmyka|cmyka|device-cmyk|cmyk|hsla|hsl|spot)\(.*?\)|[a-zA-Z]{3,})\s+(url\(.*)/i', $s, $m)) {
983 $bg['c'] = strtolower($m[1]);
984 $s = $m[3];
985 }
986 /* -- BACKGROUNDS -- */
987 if (preg_match('/url\([\'\"]{0,1}(.*?)[\'\"]{0,1}\)\s*(.*)/i', $s, $m)) {
988 $bg['i'] = $m[1];
989 $s = strtolower($m[2]);
990 if (preg_match('/(repeat-x|repeat-y|no-repeat|repeat)/', $s, $m)) {
991 $bg['r'] = $m[1];
992 }
993 // Remove repeat, attachment (discarded) and also any inherit
994 $s = preg_replace('/(repeat-x|repeat-y|no-repeat|repeat|scroll|fixed|inherit)/', '', $s);
995 $bits = preg_split('/\s+/', trim($s));
996 // These should be Position x1 or x2
997 if (count($bits) == 1) {
998 if (preg_match('/bottom/', $bits[0])) {
999 $bg['p'] = '50% 100%';
1000 } else if (preg_match('/top/', $bits[0])) {
1001 $bg['p'] = '50% 0%';
1002 } else {
1003 $bg['p'] = $bits[0] . ' 50%';
1004 }
1005 } else if (count($bits) == 2) {
1006 // Can be either right center or center right
1007 if (preg_match('/(top|bottom)/', $bits[0]) || preg_match('/(left|right)/', $bits[1])) {
1008 $bg['p'] = $bits[1] . ' ' . $bits[0];
1009 } else {
1010 $bg['p'] = $bits[0] . ' ' . $bits[1];
1011 }
1012 }
1013 if ($bg['p']) {
1014 $bg['p'] = preg_replace('/(left|top)/', '0%', $bg['p']);
1015 $bg['p'] = preg_replace('/(right|bottom)/', '100%', $bg['p']);
1016 $bg['p'] = preg_replace('/(center)/', '50%', $bg['p']);
1017 if (!preg_match('/[\-]{0,1}\d+(in|cm|mm|pt|pc|em|ex|px|%)* [\-]{0,1}\d+(in|cm|mm|pt|pc|em|ex|px|%)*/', $bg['p'])) {
1018 $bg['p'] = false;
1019 }
1020 }
1021 }
1022 /* -- END BACKGROUNDS -- */
1023 } else if (preg_match('/^\s*(#[0-9a-fA-F]{3,6}|(rgba|rgb|device-cmyka|cmyka|device-cmyk|cmyk|hsla|hsl|spot)\(.*?\)|[a-zA-Z]{3,})/i', $s, $m)) {
1024 $bg['c'] = strtolower($m[1]);
1025 } // mPDF 5.6.05
1026 return ($bg);
1027 }
1028
1029 function expand24($mp)
1030 {
1031 $prop = preg_split('/\s+/', trim($mp));
1032 if (count($prop) == 1) {
1033 return array('T' => $prop[0], 'R' => $prop[0], 'B' => $prop[0], 'L' => $prop[0]);
1034 }
1035 if (count($prop) == 2) {
1036 return array('T' => $prop[0], 'R' => $prop[1], 'B' => $prop[0], 'L' => $prop[1]);
1037 }
1038
1039 if (count($prop) == 3) {
1040 return array('T' => $prop[0], 'R' => $prop[1], 'B' => $prop[2], 'L' => $prop[1]);
1041 }
1042 if (count($prop) == 4) {
1043 return array('T' => $prop[0], 'R' => $prop[1], 'B' => $prop[2], 'L' => $prop[3]);
1044 }
1045 return array();
1046 }
1047
1048 /* -- BORDER-RADIUS -- */
1049
1050 function border_radius_expand($val, $k)
1051 {
1052 $b = array();
1053 if ($k == 'BORDER-RADIUS') {
1054 $hv = explode('/', trim($val));
1055 $prop = preg_split('/\s+/', trim($hv[0]));
1056 if (count($prop) == 1) {
1057 $b['TL-H'] = $b['TR-H'] = $b['BR-H'] = $b['BL-H'] = $prop[0];
1058 } else if (count($prop) == 2) {
1059 $b['TL-H'] = $b['BR-H'] = $prop[0];
1060 $b['TR-H'] = $b['BL-H'] = $prop[1];
1061 } else if (count($prop) == 3) {
1062 $b['TL-H'] = $prop[0];
1063 $b['TR-H'] = $b['BL-H'] = $prop[1];
1064 $b['BR-H'] = $prop[2];
1065 } else if (count($prop) == 4) {
1066 $b['TL-H'] = $prop[0];
1067 $b['TR-H'] = $prop[1];
1068 $b['BR-H'] = $prop[2];
1069 $b['BL-H'] = $prop[3];
1070 }
1071 if (count($hv) == 2) {
1072 $prop = preg_split('/\s+/', trim($hv[1]));
1073 if (count($prop) == 1) {
1074 $b['TL-V'] = $b['TR-V'] = $b['BR-V'] = $b['BL-V'] = $prop[0];
1075 } else if (count($prop) == 2) {
1076 $b['TL-V'] = $b['BR-V'] = $prop[0];
1077 $b['TR-V'] = $b['BL-V'] = $prop[1];
1078 } else if (count($prop) == 3) {
1079 $b['TL-V'] = $prop[0];
1080 $b['TR-V'] = $b['BL-V'] = $prop[1];
1081 $b['BR-V'] = $prop[2];
1082 } else if (count($prop) == 4) {
1083 $b['TL-V'] = $prop[0];
1084 $b['TR-V'] = $prop[1];
1085 $b['BR-V'] = $prop[2];
1086 $b['BL-V'] = $prop[3];
1087 }
1088 } else {
1089 $b['TL-V'] = $b['TL-H'];
1090 $b['TR-V'] = $b['TR-H'];
1091 $b['BL-V'] = $b['BL-H'];
1092 $b['BR-V'] = $b['BR-H'];
1093 }
1094 return $b;
1095 }
1096
1097 // Parse 2
1098 $h = 0;
1099 $v = 0;
1100 $prop = preg_split('/\s+/', trim($val));
1101 if (count($prop) == 1) {
1102 $h = $v = $val;
1103 } else {
1104 $h = $prop[0];
1105 $v = $prop[1];
1106 }
1107 if ($h == 0 || $v == 0) {
1108 $h = $v = 0;
1109 }
1110 if ($k == 'BORDER-TOP-LEFT-RADIUS') {
1111 $b['TL-H'] = $h;
1112 $b['TL-V'] = $v;
1113 } else if ($k == 'BORDER-TOP-RIGHT-RADIUS') {
1114 $b['TR-H'] = $h;
1115 $b['TR-V'] = $v;
1116 } else if ($k == 'BORDER-BOTTOM-LEFT-RADIUS') {
1117 $b['BL-H'] = $h;
1118 $b['BL-V'] = $v;
1119 } else if ($k == 'BORDER-BOTTOM-RIGHT-RADIUS') {
1120 $b['BR-H'] = $h;
1121 $b['BR-V'] = $v;
1122 }
1123 return $b;
1124 }
1125
1126 /* -- END BORDER-RADIUS -- */
1127
1128 function _mergeCSS($p, &$t)
1129 {
1130 // Save Cascading CSS e.g. "div.topic p" at this block level
1131 if (isset($p) && $p) {
1132 if ($t) {
1133 $t = $this->array_merge_recursive_unique($t, $p);
1134 } else {
1135 $t = $p;
1136 }
1137 }
1138 }
1139
1140 // for CSS handling
1141 function array_merge_recursive_unique($array1, $array2)
1142 {
1143 $arrays = func_get_args();
1144 $narrays = count($arrays);
1145 $ret = $arrays[0];
1146 for ($i = 1; $i < $narrays; $i ++) {
1147 foreach ($arrays[$i] as $key => $value) {
1148 if (((string) $key) === ((string) intval($key))) { // integer or string as integer key - append
1149 $ret[] = $value;
1150 } else { // string key - merge
1151 if (is_array($value) && isset($ret[$key])) {
1152 $ret[$key] = $this->array_merge_recursive_unique($ret[$key], $value);
1153 } else {
1154 $ret[$key] = $value;
1155 }
1156 }
1157 }
1158 }
1159 return $ret;
1160 }
1161
1162 function _mergeFullCSS($p, &$t, $tag, $classes, $id, $lang)
1163 { // mPDF 6
1164 if (isset($p[$tag])) {
1165 $this->_mergeCSS($p[$tag], $t);
1166 }
1167 // STYLESHEET CLASS e.g. .smallone{} .redletter{}
1168 foreach ($classes AS $class) {
1169 if (isset($p['CLASS>>' . $class])) {
1170 $this->_mergeCSS($p['CLASS>>' . $class], $t);
1171 }
1172 }
1173 // STYLESHEET nth-child SELECTOR e.g. tr:nth-child(odd) td:nth-child(2n+1)
1174 if ($tag == 'TR' && isset($p) && $p) {
1175 foreach ($p AS $k => $val) {
1176 if (preg_match('/' . $tag . '>>SELECTORNTHCHILD>>(.*)/', $k, $m)) {
1177 $select = false;
1178 if ($tag == 'TR') {
1179 $row = $this->mpdf->row;
1180 $thnr = (isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_thead']) ? count($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_thead']) : 0);
1181 $tfnr = (isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_tfoot']) ? count($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_tfoot']) : 0);
1182 if ($this->mpdf->tabletfoot) {
1183 $row -= $thnr;
1184 } else if (!$this->mpdf->tablethead) {
1185 $row -= ($thnr + $tfnr);
1186 }
1187 if (preg_match('/(([\-+]?\d*)?N([\-+]\d+)?|[\-+]?\d+|ODD|EVEN)/', $m[1], $a)) { // mPDF 5.7.4
1188 $select = $this->_nthchild($a, $row);
1189 }
1190 } else if ($tag == 'TD' || $tag == 'TH') {
1191 if (preg_match('/(([\-+]?\d*)?N([\-+]\d+)?|[\-+]?\d+|ODD|EVEN)/', $m[1], $a)) { // mPDF 5.7.4
1192 $select = $this->_nthchild($a, $this->mpdf->col);
1193 }
1194 }
1195 if ($select) {
1196 $this->_mergeCSS($p[$tag . '>>SELECTORNTHCHILD>>' . $m[1]], $t);
1197 }
1198 }
1199 }
1200 }
1201 // STYLESHEET CLASS e.g. [lang=fr]{} or :lang(fr)
1202 if (isset($lang) && isset($p['LANG>>' . $lang])) {
1203 $this->_mergeCSS($p['LANG>>' . $lang], $t);
1204 }
1205 // STYLESHEET CLASS e.g. #smallone{} #redletter{}
1206 if (isset($id) && isset($p['ID>>' . $id])) {
1207 $this->_mergeCSS($p['ID>>' . $id], $t);
1208 }
1209
1210 // STYLESHEET CLASS e.g. .smallone{} .redletter{}
1211 foreach ($classes AS $class) {
1212 if (isset($p[$tag . '>>CLASS>>' . $class])) {
1213 $this->_mergeCSS($p[$tag . '>>CLASS>>' . $class], $t);
1214 }
1215 }
1216 // STYLESHEET CLASS e.g. [lang=fr]{} or :lang(fr)
1217 if (isset($lang) && isset($p[$tag . '>>LANG>>' . $lang])) {
1218 $this->_mergeCSS($p[$tag . '>>LANG>>' . $lang], $t);
1219 }
1220 // STYLESHEET CLASS e.g. #smallone{} #redletter{}
1221 if (isset($id) && isset($p[$tag . '>>ID>>' . $id])) {
1222 $this->_mergeCSS($p[$tag . '>>ID>>' . $id], $t);
1223 }
1224 }
1225
1226 function setBorderDominance($prop, $val)
1227 {
1228 if (isset($prop['BORDER-LEFT']) && $prop['BORDER-LEFT']) {
1229 $this->cell_border_dominance_L = $val;
1230 }
1231 if (isset($prop['BORDER-RIGHT']) && $prop['BORDER-RIGHT']) {
1232 $this->cell_border_dominance_R = $val;
1233 }
1234 if (isset($prop['BORDER-TOP']) && $prop['BORDER-TOP']) {
1235 $this->cell_border_dominance_T = $val;
1236 }
1237 if (isset($prop['BORDER-BOTTOM']) && $prop['BORDER-BOTTOM']) {
1238 $this->cell_border_dominance_B = $val;
1239 }
1240 }
1241
1242 function _set_mergedCSS(&$m, &$p, $d = true, $bd = false)
1243 {
1244 if (isset($m)) {
1245 if ((isset($m['depth']) && $m['depth'] > 1) || $d == false) { // include check for 'depth'
1246 if ($bd) {
1247 $this->setBorderDominance($m, $bd);
1248 } // *TABLES*
1249 if (is_array($m)) {
1250 $p = array_merge($p, $m);
1251 $this->_mergeBorders($p, $m);
1252 }
1253 }
1254 }
1255 }
1256
1257 function _mergeBorders(&$b, &$a)
1258 { // Merges $a['BORDER-TOP-STYLE'] to $b['BORDER-TOP'] etc.
1259 foreach (array('TOP', 'RIGHT', 'BOTTOM', 'LEFT') AS $side) {
1260 foreach (array('STYLE', 'WIDTH', 'COLOR') AS $el) {
1261 if (isset($a['BORDER-' . $side . '-' . $el])) { // e.g. $b['BORDER-TOP-STYLE']
1262 $s = trim($a['BORDER-' . $side . '-' . $el]);
1263 if (isset($b['BORDER-' . $side])) { // e.g. $b['BORDER-TOP']
1264 $p = trim($b['BORDER-' . $side]);
1265 } else {
1266 $p = '';
1267 }
1268 if ($el == 'STYLE') {
1269 if ($p) {
1270 $b['BORDER-' . $side] = preg_replace('/(\S+)\s+(\S+)\s+(\S+)/', '\\1 ' . $s . ' \\3', $p);
1271 } else {
1272 $b['BORDER-' . $side] = '0px ' . $s . ' #000000';
1273 }
1274 } else if ($el == 'WIDTH') {
1275 if ($p) {
1276 $b['BORDER-' . $side] = preg_replace('/(\S+)\s+(\S+)\s+(\S+)/', $s . ' \\2 \\3', $p);
1277 } else {
1278 $b['BORDER-' . $side] = $s . ' none #000000';
1279 }
1280 } else if ($el == 'COLOR') {
1281 if ($p) {
1282 $b['BORDER-' . $side] = preg_replace('/(\S+)\s+(\S+)\s+(\S+)/', '\\1 \\2 ' . $s, $p);
1283 } else {
1284 $b['BORDER-' . $side] = '0px none ' . $s;
1285 }
1286 }
1287 }
1288 }
1289 }
1290 }
1291
1292 function MergeCSS($inherit, $tag, $attr)
1293 {
1294 $p = array();
1295 $zp = array();
1296
1297 $classes = array();
1298 $attr = $attr === '' ? [] : $attr;
1299 if (isset($attr['CLASS'])) {
1300 $classes = preg_split('/\s+/', $attr['CLASS']);
1301 }
1302 if (!isset($attr['ID'])) {
1303 $attr['ID'] = '';
1304 }
1305 // mPDF 6
1306 $shortlang = '';
1307 if (!isset($attr['LANG'])) {
1308 $attr['LANG'] = '';
1309 } else {
1310 $attr['LANG'] = strtolower($attr['LANG']);
1311 if (strlen($attr['LANG']) == 5) {
1312 $shortlang = substr($attr['LANG'], 0, 2);
1313 }
1314 }
1315 //===============================================
1316 /* -- TABLES -- */
1317 // Set Inherited properties
1318 if ($inherit == 'TOPTABLE') { // $tag = TABLE
1319 //===============================================
1320 // Save Cascading CSS e.g. "div.topic p" at this block level
1321 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'])) {
1322 $this->tablecascadeCSS[0] = $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'];
1323 } else {
1324 $this->tablecascadeCSS[0] = $this->cascadeCSS;
1325 }
1326 }
1327 //===============================================
1328 // Set Inherited properties
1329 if ($inherit == 'TOPTABLE' || $inherit == 'TABLE') {
1330 //Cascade everything from last level that is not an actual property, or defined by current tag/attributes
1331 if (isset($this->tablecascadeCSS[$this->tbCSSlvl - 1]) && is_array($this->tablecascadeCSS[$this->tbCSSlvl - 1])) {
1332 foreach ($this->tablecascadeCSS[$this->tbCSSlvl - 1] AS $k => $v) {
1333 $this->tablecascadeCSS[$this->tbCSSlvl][$k] = $v;
1334 }
1335 }
1336 $this->_mergeFullCSS($this->cascadeCSS, $this->tablecascadeCSS[$this->tbCSSlvl], $tag, $classes, $attr['ID'], $attr['LANG']);
1337 //===============================================
1338 // Cascading forward CSS e.g. "table.topic td" for this table in $this->tablecascadeCSS
1339 //===============================================
1340 // STYLESHEET TAG e.g. table
1341 $this->_mergeFullCSS($this->tablecascadeCSS[$this->tbCSSlvl - 1], $this->tablecascadeCSS[$this->tbCSSlvl], $tag, $classes, $attr['ID'], $attr['LANG']);
1342 //===============================================
1343 }
1344 /* -- END TABLES -- */
1345 //===============================================
1346 // Set Inherited properties
1347 if ($inherit == 'BLOCK') {
1348 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['cascadeCSS']) && is_array($this->mpdf->blk[$this->mpdf->blklvl - 1]['cascadeCSS'])) {
1349 foreach ($this->mpdf->blk[$this->mpdf->blklvl - 1]['cascadeCSS'] AS $k => $v) {
1350 $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'][$k] = $v;
1351 }
1352 }
1353
1354 //===============================================
1355 // Save Cascading CSS e.g. "div.topic p" at this block level
1356 $this->_mergeFullCSS($this->cascadeCSS, $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'], $tag, $classes, $attr['ID'], $attr['LANG']);
1357 //===============================================
1358 // Cascading forward CSS
1359 //===============================================
1360 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1])) {
1361 $this->_mergeFullCSS($this->mpdf->blk[$this->mpdf->blklvl - 1]['cascadeCSS'], $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'], $tag, $classes, $attr['ID'], $attr['LANG']);
1362 }
1363 //===============================================
1364 // Block properties which are inherited
1365 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['margin_collapse']) && $this->mpdf->blk[$this->mpdf->blklvl - 1]['margin_collapse']) {
1366 $p['MARGIN-COLLAPSE'] = 'COLLAPSE';
1367 } // custom tag, but follows CSS principle that border-collapse is inherited
1368 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['line_height']) && $this->mpdf->blk[$this->mpdf->blklvl - 1]['line_height']) {
1369 $p['LINE-HEIGHT'] = $this->mpdf->blk[$this->mpdf->blklvl - 1]['line_height'];
1370 }
1371 // mPDF 6
1372 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['line_stacking_strategy']) && $this->mpdf->blk[$this->mpdf->blklvl - 1]['line_stacking_strategy']) {
1373 $p['LINE-STACKING-STRATEGY'] = $this->mpdf->blk[$this->mpdf->blklvl - 1]['line_stacking_strategy'];
1374 }
1375 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['line_stacking_shift']) && $this->mpdf->blk[$this->mpdf->blklvl - 1]['line_stacking_shift']) {
1376 $p['LINE-STACKING-SHIFT'] = $this->mpdf->blk[$this->mpdf->blklvl - 1]['line_stacking_shift'];
1377 }
1378
1379 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['direction']) && $this->mpdf->blk[$this->mpdf->blklvl - 1]['direction']) {
1380 $p['DIRECTION'] = $this->mpdf->blk[$this->mpdf->blklvl - 1]['direction'];
1381 }
1382 // mPDF 6 Lists
1383 if ($tag == 'LI') {
1384 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['list_style_type']) && $this->mpdf->blk[$this->mpdf->blklvl - 1]['list_style_type']) {
1385 $p['LIST-STYLE-TYPE'] = $this->mpdf->blk[$this->mpdf->blklvl - 1]['list_style_type'];
1386 }
1387 }
1388 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['list_style_image']) && $this->mpdf->blk[$this->mpdf->blklvl - 1]['list_style_image']) {
1389 $p['LIST-STYLE-IMAGE'] = $this->mpdf->blk[$this->mpdf->blklvl - 1]['list_style_image'];
1390 }
1391 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['list_style_position']) && $this->mpdf->blk[$this->mpdf->blklvl - 1]['list_style_position']) {
1392 $p['LIST-STYLE-POSITION'] = $this->mpdf->blk[$this->mpdf->blklvl - 1]['list_style_position'];
1393 }
1394
1395 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['align']) && $this->mpdf->blk[$this->mpdf->blklvl - 1]['align']) {
1396 if ($this->mpdf->blk[$this->mpdf->blklvl - 1]['align'] == 'L') {
1397 $p['TEXT-ALIGN'] = 'left';
1398 } else if ($this->mpdf->blk[$this->mpdf->blklvl - 1]['align'] == 'J') {
1399 $p['TEXT-ALIGN'] = 'justify';
1400 } else if ($this->mpdf->blk[$this->mpdf->blklvl - 1]['align'] == 'R') {
1401 $p['TEXT-ALIGN'] = 'right';
1402 } else if ($this->mpdf->blk[$this->mpdf->blklvl - 1]['align'] == 'C') {
1403 $p['TEXT-ALIGN'] = 'center';
1404 }
1405 }
1406 if ($this->mpdf->ColActive || $this->mpdf->keep_block_together) {
1407 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['bgcolor']) && $this->mpdf->blk[$this->mpdf->blklvl - 1]['bgcolor']) { // Doesn't officially inherit, but default value is transparent (?=inherited)
1408 $cor = $this->mpdf->blk[$this->mpdf->blklvl - 1]['bgcolorarray'];
1409 $p['BACKGROUND-COLOR'] = $this->mpdf->_colAtoString($cor);
1410 }
1411 }
1412
1413 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['text_indent']) && ($this->mpdf->blk[$this->mpdf->blklvl - 1]['text_indent'] || $this->mpdf->blk[$this->mpdf->blklvl - 1]['text_indent'] === 0)) {
1414 $p['TEXT-INDENT'] = $this->mpdf->blk[$this->mpdf->blklvl - 1]['text_indent'];
1415 }
1416 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['InlineProperties'])) {
1417 $biilp = $this->mpdf->blk[$this->mpdf->blklvl - 1]['InlineProperties'];
1418 $this->inlinePropsToCSS($biilp, $p); // mPDF 5.7.1
1419 } else {
1420 $biilp = null;
1421 }
1422 }
1423 //===============================================
1424 //===============================================
1425 // INLINE HTML ATTRIBUTES e.g. .. ALIGN="CENTER">
1426 // mPDF 6 (added)
1427 if (isset($attr['DIR']) and $attr['DIR'] != '') {
1428 $p['DIRECTION'] = $attr['DIR'];
1429 }
1430 // mPDF 6 (moved)
1431 if (isset($attr['LANG']) and $attr['LANG'] != '') {
1432 $p['LANG'] = $attr['LANG'];
1433 }
1434 if (isset($attr['COLOR']) and $attr['COLOR'] != '') {
1435 $p['COLOR'] = $attr['COLOR'];
1436 }
1437
1438 if ($tag != 'INPUT') {
1439 if (isset($attr['WIDTH']) and $attr['WIDTH'] != '') {
1440 $p['WIDTH'] = $attr['WIDTH'];
1441 }
1442 if (isset($attr['HEIGHT']) and $attr['HEIGHT'] != '') {
1443 $p['HEIGHT'] = $attr['HEIGHT'];
1444 }
1445 }
1446 if ($tag == 'FONT') {
1447 if (isset($attr['FACE'])) {
1448 $p['FONT-FAMILY'] = $attr['FACE'];
1449 }
1450 if (isset($attr['SIZE']) and $attr['SIZE'] != '') {
1451 $s = '';
1452 if ($attr['SIZE'] === '+1') {
1453 $s = '120%';
1454 } else if ($attr['SIZE'] === '-1') {
1455 $s = '86%';
1456 } else if ($attr['SIZE'] === '1') {
1457 $s = 'XX-SMALL';
1458 } else if ($attr['SIZE'] == '2') {
1459 $s = 'X-SMALL';
1460 } else if ($attr['SIZE'] == '3') {
1461 $s = 'SMALL';
1462 } else if ($attr['SIZE'] == '4') {
1463 $s = 'MEDIUM';
1464 } else if ($attr['SIZE'] == '5') {
1465 $s = 'LARGE';
1466 } else if ($attr['SIZE'] == '6') {
1467 $s = 'X-LARGE';
1468 } else if ($attr['SIZE'] == '7') {
1469 $s = 'XX-LARGE';
1470 }
1471 if ($s)
1472 $p['FONT-SIZE'] = $s;
1473 }
1474 }
1475 if (isset($attr['VALIGN']) and $attr['VALIGN'] != '') {
1476 $p['VERTICAL-ALIGN'] = $attr['VALIGN'];
1477 }
1478 if (isset($attr['VSPACE']) and $attr['VSPACE'] != '') {
1479 $p['MARGIN-TOP'] = $attr['VSPACE'];
1480 $p['MARGIN-BOTTOM'] = $attr['VSPACE'];
1481 }
1482 if (isset($attr['HSPACE']) and $attr['HSPACE'] != '') {
1483 $p['MARGIN-LEFT'] = $attr['HSPACE'];
1484 $p['MARGIN-RIGHT'] = $attr['HSPACE'];
1485 }
1486 //===============================================
1487 //===============================================
1488 // DEFAULT for this TAG set in DefaultCSS
1489 if (isset($this->mpdf->defaultCSS[$tag])) {
1490 $zp = $this->fixCSS($this->mpdf->defaultCSS[$tag]);
1491 if (is_array($zp)) { // Default overwrites Inherited
1492 $p = array_merge($p, $zp); // !! Note other way round !!
1493 $this->_mergeBorders($p, $zp);
1494 }
1495 }
1496 //===============================================
1497 /* -- TABLES -- */
1498 // mPDF 5.7.3
1499 // cellSpacing overwrites TABLE default but not specific CSS set on table
1500 if ($tag == 'TABLE' && isset($attr['CELLSPACING'])) {
1501 $p['BORDER-SPACING-H'] = $p['BORDER-SPACING-V'] = $attr['CELLSPACING'];
1502 }
1503 // cellPadding overwrites TD/TH default but not specific CSS set on cell
1504 if (($tag == 'TD' || $tag == 'TH') && isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding']) && ($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding'] || $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding'] === '0')) { // mPDF 5.7.3
1505 $p['PADDING-LEFT'] = $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding'];
1506 $p['PADDING-RIGHT'] = $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding'];
1507 $p['PADDING-TOP'] = $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding'];
1508 $p['PADDING-BOTTOM'] = $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding'];
1509 }
1510 /* -- END TABLES -- */
1511 //===============================================
1512 // STYLESHEET TAG e.g. h1 p div table
1513 if (isset($this->CSS[$tag]) && $this->CSS[$tag]) {
1514 $zp = $this->CSS[$tag];
1515 if ($tag == 'TD' || $tag == 'TH') {
1516 $this->setBorderDominance($zp, 9);
1517 } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1518 if (is_array($zp)) {
1519 $p = array_merge($p, $zp);
1520 $this->_mergeBorders($p, $zp);
1521 }
1522 }
1523 //===============================================
1524 // STYLESHEET CLASS e.g. .smallone{} .redletter{}
1525 foreach ($classes AS $class) {
1526 $zp = array();
1527 if (isset($this->CSS['CLASS>>' . $class]) && $this->CSS['CLASS>>' . $class]) {
1528 $zp = $this->CSS['CLASS>>' . $class];
1529 }
1530 if ($tag == 'TD' || $tag == 'TH') {
1531 $this->setBorderDominance($zp, 9);
1532 } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1533 if (is_array($zp)) {
1534 $p = array_merge($p, $zp);
1535 $this->_mergeBorders($p, $zp);
1536 }
1537 }
1538 //===============================================
1539 /* -- TABLES -- */
1540 // STYLESHEET nth-child SELECTOR e.g. tr:nth-child(odd) td:nth-child(2n+1)
1541 if ($tag == 'TR' || $tag == 'TD' || $tag == 'TH') {
1542 foreach ($this->CSS AS $k => $val) {
1543 if (preg_match('/' . $tag . '>>SELECTORNTHCHILD>>(.*)/', $k, $m)) {
1544 $select = false;
1545 if ($tag == 'TR') {
1546 $row = $this->mpdf->row;
1547 $thnr = (isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_thead']) ? count($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_thead']) : 0);
1548 $tfnr = (isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_tfoot']) ? count($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_tfoot']) : 0);
1549 if ($this->mpdf->tabletfoot) {
1550 $row -= $thnr;
1551 } else if (!$this->mpdf->tablethead) {
1552 $row -= ($thnr + $tfnr);
1553 }
1554 if (preg_match('/(([\-+]?\d*)?N([\-+]\d+)?|[\-+]?\d+|ODD|EVEN)/', $m[1], $a)) { // mPDF 5.7.4
1555 $select = $this->_nthchild($a, $row);
1556 }
1557 } else if ($tag == 'TD' || $tag == 'TH') {
1558 if (preg_match('/(([\-+]?\d*)?N([\-+]\d+)?|[\-+]?\d+|ODD|EVEN)/', $m[1], $a)) { // mPDF 5.7.4
1559 $select = $this->_nthchild($a, $this->mpdf->col);
1560 }
1561 }
1562 if ($select) {
1563 $zp = $this->CSS[$tag . '>>SELECTORNTHCHILD>>' . $m[1]];
1564 if ($tag == 'TD' || $tag == 'TH') {
1565 $this->setBorderDominance($zp, 9);
1566 }
1567 if (is_array($zp)) {
1568 $p = array_merge($p, $zp);
1569 $this->_mergeBorders($p, $zp);
1570 }
1571 }
1572 }
1573 }
1574 }
1575 /* -- END TABLES -- */
1576 //===============================================
1577 // STYLESHEET LANG e.g. [lang=fr]{} or :lang(fr)
1578 if (isset($attr['LANG'])) {
1579 if (isset($this->CSS['LANG>>' . $attr['LANG']]) && $this->CSS['LANG>>' . $attr['LANG']]) {
1580 $zp = $this->CSS['LANG>>' . $attr['LANG']];
1581 if ($tag == 'TD' || $tag == 'TH') {
1582 $this->setBorderDominance($zp, 9);
1583 } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1584 if (is_array($zp)) {
1585 $p = array_merge($p, $zp);
1586 $this->_mergeBorders($p, $zp);
1587 }
1588 } else if (isset($this->CSS['LANG>>' . $shortlang]) && $this->CSS['LANG>>' . $shortlang]) {
1589 $zp = $this->CSS['LANG>>' . $shortlang];
1590 if ($tag == 'TD' || $tag == 'TH') {
1591 $this->setBorderDominance($zp, 9);
1592 } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1593 if (is_array($zp)) {
1594 $p = array_merge($p, $zp);
1595 $this->_mergeBorders($p, $zp);
1596 }
1597 }
1598 }
1599 //===============================================
1600 // STYLESHEET ID e.g. #smallone{} #redletter{}
1601 if (isset($attr['ID']) && isset($this->CSS['ID>>' . $attr['ID']]) && $this->CSS['ID>>' . $attr['ID']]) {
1602 $zp = $this->CSS['ID>>' . $attr['ID']];
1603 if ($tag == 'TD' || $tag == 'TH') {
1604 $this->setBorderDominance($zp, 9);
1605 } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1606 if (is_array($zp)) {
1607 $p = array_merge($p, $zp);
1608 $this->_mergeBorders($p, $zp);
1609 }
1610 }
1611
1612 //===============================================
1613 // STYLESHEET CLASS e.g. p.smallone{} div.redletter{}
1614 foreach ($classes AS $class) {
1615 $zp = array();
1616 if (isset($this->CSS[$tag . '>>CLASS>>' . $class]) && $this->CSS[$tag . '>>CLASS>>' . $class]) {
1617 $zp = $this->CSS[$tag . '>>CLASS>>' . $class];
1618 }
1619 if ($tag == 'TD' || $tag == 'TH') {
1620 $this->setBorderDominance($zp, 9);
1621 } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1622 if (is_array($zp)) {
1623 $p = array_merge($p, $zp);
1624 $this->_mergeBorders($p, $zp);
1625 }
1626 }
1627 //===============================================
1628 // STYLESHEET LANG e.g. [lang=fr]{} or :lang(fr)
1629 if (isset($attr['LANG'])) {
1630 if (isset($this->CSS[$tag . '>>LANG>>' . $attr['LANG']]) && $this->CSS[$tag . '>>LANG>>' . $attr['LANG']]) {
1631 $zp = $this->CSS[$tag . '>>LANG>>' . $attr['LANG']];
1632 if ($tag == 'TD' || $tag == 'TH') {
1633 $this->setBorderDominance($zp, 9);
1634 } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1635 if (is_array($zp)) {
1636 $p = array_merge($p, $zp);
1637 $this->_mergeBorders($p, $zp);
1638 }
1639 } else if (isset($this->CSS[$tag . '>>LANG>>' . $shortlang]) && $this->CSS[$tag . '>>LANG>>' . $shortlang]) {
1640 $zp = $this->CSS[$tag . '>>LANG>>' . $shortlang];
1641 if ($tag == 'TD' || $tag == 'TH') {
1642 $this->setBorderDominance($zp, 9);
1643 } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1644 if (is_array($zp)) {
1645 $p = array_merge($p, $zp);
1646 $this->_mergeBorders($p, $zp);
1647 }
1648 }
1649 }
1650 //===============================================
1651 // STYLESHEET CLASS e.g. p#smallone{} div#redletter{}
1652 if (isset($attr['ID']) && isset($this->CSS[$tag . '>>ID>>' . $attr['ID']]) && $this->CSS[$tag . '>>ID>>' . $attr['ID']]) {
1653 $zp = $this->CSS[$tag . '>>ID>>' . $attr['ID']];
1654 if ($tag == 'TD' || $tag == 'TH') {
1655 $this->setBorderDominance($zp, 9);
1656 } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1657 if (is_array($zp)) {
1658 $p = array_merge($p, $zp);
1659 $this->_mergeBorders($p, $zp);
1660 }
1661 }
1662 //===============================================
1663 // Cascaded e.g. div.class p only works for block level
1664 if ($inherit == 'BLOCK') {
1665 if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1])) { // mPDF 6
1666 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl - 1]['cascadeCSS'][$tag], $p);
1667 foreach ($classes AS $class) {
1668 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl - 1]['cascadeCSS']['CLASS>>' . $class], $p);
1669 }
1670 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl - 1]['cascadeCSS']['ID>>' . $attr['ID']], $p);
1671 foreach ($classes AS $class) {
1672 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl - 1]['cascadeCSS'][$tag . '>>CLASS>>' . $class], $p);
1673 }
1674 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl - 1]['cascadeCSS'][$tag . '>>ID>>' . $attr['ID']], $p);
1675 }
1676 } else if ($inherit == 'INLINE') {
1677 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'][$tag], $p);
1678 foreach ($classes AS $class) {
1679 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS']['CLASS>>' . $class], $p);
1680 }
1681 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS']['ID>>' . $attr['ID']], $p);
1682 foreach ($classes AS $class) {
1683 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'][$tag . '>>CLASS>>' . $class], $p);
1684 }
1685 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'][$tag . '>>ID>>' . $attr['ID']], $p);
1686 }
1687 /* -- TABLES -- */ else if ($inherit == 'TOPTABLE' || $inherit == 'TABLE') { // NB looks at $this->tablecascadeCSS-1 for cascading CSS
1688 if (isset($this->tablecascadeCSS[$this->tbCSSlvl - 1])) { // mPDF 6
1689 // false, 9 = don't check for 'depth' and do set border dominance
1690 $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl - 1][$tag], $p, false, 9);
1691 foreach ($classes AS $class) {
1692 $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl - 1]['CLASS>>' . $class], $p, false, 9);
1693 }
1694 // STYLESHEET nth-child SELECTOR e.g. tr:nth-child(odd) td:nth-child(2n+1)
1695 if ($tag == 'TR' || $tag == 'TD' || $tag == 'TH') {
1696 foreach ($this->tablecascadeCSS[$this->tbCSSlvl - 1] AS $k => $val) {
1697 if (preg_match('/' . $tag . '>>SELECTORNTHCHILD>>(.*)/', $k, $m)) {
1698 $select = false;
1699 if ($tag == 'TR') {
1700 $row = $this->mpdf->row;
1701 $thnr = (isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_thead']) ? count($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_thead']) : 0);
1702 $tfnr = (isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_tfoot']) ? count($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_tfoot']) : 0);
1703 if ($this->mpdf->tabletfoot) {
1704 $row -= $thnr;
1705 } else if (!$this->mpdf->tablethead) {
1706 $row -= ($thnr + $tfnr);
1707 }
1708 if (preg_match('/(([\-+]?\d*)?N([\-+]\d+)?|[\-+]?\d+|ODD|EVEN)/', $m[1], $a)) { // mPDF 5.7.4
1709 $select = $this->_nthchild($a, $row);
1710 }
1711 } else if ($tag == 'TD' || $tag == 'TH') {
1712 if (preg_match('/(([\-+]?\d*)?N([\-+]\d+)?|[\-+]?\d+|ODD|EVEN)/', $m[1], $a)) { // mPDF 5.7.4
1713 $select = $this->_nthchild($a, $this->mpdf->col);
1714 }
1715 }
1716 if ($select) {
1717 $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl - 1][$tag . '>>SELECTORNTHCHILD>>' . $m[1]], $p, false, 9);
1718 }
1719 }
1720 }
1721 }
1722 }
1723 $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl - 1]['ID>>' . $attr['ID']], $p, false, 9);
1724 foreach ($classes AS $class) {
1725 $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl - 1][$tag . '>>CLASS>>' . $class], $p, false, 9);
1726 }
1727 $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl - 1][$tag . '>>ID>>' . $attr['ID']], $p, false, 9);
1728 }
1729 /* -- END TABLES -- */
1730 //===============================================
1731 //===============================================
1732 // INLINE STYLE e.g. style="CSS:property"
1733 if (isset($attr['STYLE'])) {
1734 $zp = $this->readInlineCSS($attr['STYLE']);
1735 if ($tag == 'TD' || $tag == 'TH') {
1736 $this->setBorderDominance($zp, 9);
1737 } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1738 if (is_array($zp)) {
1739 $p = array_merge($p, $zp);
1740 $this->_mergeBorders($p, $zp);
1741 }
1742 }
1743 //===============================================
1744 //===============================================
1745 return $p;
1746 }
1747
1748 // Convert inline Properties back to CSS
1749 function inlinePropsToCSS($bilp, &$p)
1750 {
1751 if (isset($bilp['family']) && $bilp['family']) {
1752 $p['FONT-FAMILY'] = $bilp['family'];
1753 }
1754 if (isset($bilp['I']) && $bilp['I']) {
1755 $p['FONT-STYLE'] = 'italic';
1756 }
1757 if (isset($bilp['sizePt']) && $bilp['sizePt']) {
1758 $p['FONT-SIZE'] = $bilp['sizePt'] . 'pt';
1759 }
1760 if (isset($bilp['B']) && $bilp['B']) {
1761 $p['FONT-WEIGHT'] = 'bold';
1762 }
1763 if (isset($bilp['colorarray']) && $bilp['colorarray']) {
1764 $cor = $bilp['colorarray'];
1765 $p['COLOR'] = $this->mpdf->_colAtoString($cor);
1766 }
1767 if (isset($bilp['lSpacingCSS']) && $bilp['lSpacingCSS']) {
1768 $p['LETTER-SPACING'] = $bilp['lSpacingCSS'];
1769 }
1770 if (isset($bilp['wSpacingCSS']) && $bilp['wSpacingCSS']) {
1771 $p['WORD-SPACING'] = $bilp['wSpacingCSS'];
1772 }
1773
1774 if (isset($bilp['textparam']) && $bilp['textparam']) {
1775 if (isset($bilp['textparam']['hyphens'])) {
1776 if ($bilp['textparam']['hyphens'] == 2) {
1777 $p['HYPHENS'] = 'none';
1778 }
1779 if ($bilp['textparam']['hyphens'] == 1) {
1780 $p['HYPHENS'] = 'auto';
1781 }
1782 if ($bilp['textparam']['hyphens'] == 0) {
1783 $p['HYPHENS'] = 'manual';
1784 }
1785 }
1786 if (isset($bilp['textparam']['outline-s']) && !$bilp['textparam']['outline-s']) {
1787 $p['TEXT-OUTLINE'] = 'none';
1788 }
1789 if (isset($bilp['textparam']['outline-COLOR']) && $bilp['textparam']['outline-COLOR']) {
1790 $p['TEXT-OUTLINE-COLOR'] = $this->mpdf->_colAtoString($bilp['textparam']['outline-COLOR']);
1791 }
1792 if (isset($bilp['textparam']['outline-WIDTH']) && $bilp['textparam']['outline-WIDTH']) {
1793 $p['TEXT-OUTLINE-WIDTH'] = $bilp['textparam']['outline-WIDTH'] . 'mm';
1794 }
1795 }
1796
1797 if (isset($bilp['textvar']) && $bilp['textvar']) {
1798 // CSS says text-decoration is not inherited, but IE7 does??
1799 if ($bilp['textvar'] & FD_LINETHROUGH) {
1800 if ($bilp['textvar'] & FD_UNDERLINE) {
1801 $p['TEXT-DECORATION'] = 'underline line-through';
1802 } else {
1803 $p['TEXT-DECORATION'] = 'line-through';
1804 }
1805 } else if ($bilp['textvar'] & FD_UNDERLINE) {
1806 $p['TEXT-DECORATION'] = 'underline';
1807 } else {
1808 $p['TEXT-DECORATION'] = 'none';
1809 }
1810
1811 if ($bilp['textvar'] & FA_SUPERSCRIPT) {
1812 $p['VERTICAL-ALIGN'] = 'super';
1813 } else if ($bilp['textvar'] & FA_SUBSCRIPT) {
1814 $p['VERTICAL-ALIGN'] = 'sub';
1815 } else {
1816 $p['VERTICAL-ALIGN'] = 'baseline';
1817 }
1818
1819 if ($bilp['textvar'] & FT_CAPITALIZE) {
1820 $p['TEXT-TRANSFORM'] = 'capitalize';
1821 } else if ($bilp['textvar'] & FT_UPPERCASE) {
1822 $p['TEXT-TRANSFORM'] = 'uppercase';
1823 } else if ($bilp['textvar'] & FT_LOWERCASE) {
1824 $p['TEXT-TRANSFORM'] = 'lowercase';
1825 } else {
1826 $p['TEXT-TRANSFORM'] = 'none';
1827 }
1828
1829 if ($bilp['textvar'] & FC_KERNING) {
1830 $p['FONT-KERNING'] = 'normal';
1831 } // ignore 'auto' as default already applied
1832 //if (isset($bilp[ 'OTLtags' ]) && $bilp[ 'OTLtags' ]['Plus'] contains 'kern'
1833 else {
1834 $p['FONT-KERNING'] = 'none';
1835 }
1836
1837 if ($bilp['textvar'] & FA_SUPERSCRIPT) {
1838 $p['FONT-VARIANT-POSITION'] = 'super';
1839 }
1840 //if (isset($bilp[ 'OTLtags' ]) && $bilp[ 'OTLtags' ]['Plus'] contains 'sups' / 'subs'
1841 else if ($bilp['textvar'] & FA_SUBSCRIPT) {
1842 $p['FONT-VARIANT-POSITION'] = 'sub';
1843 } else {
1844 $p['FONT-VARIANT-POSITION'] = 'normal';
1845 }
1846
1847 if ($bilp['textvar'] & FC_SMALLCAPS) {
1848 $p['FONT-VARIANT-CAPS'] = 'small-caps';
1849 }
1850 }
1851 if (isset($bilp['fontLanguageOverride'])) {
1852 if ($bilp['fontLanguageOverride']) {
1853 $p['FONT-LANGUAGE-OVERRIDE'] = $bilp['fontLanguageOverride'];
1854 } else {
1855 $p['FONT-LANGUAGE-OVERRIDE'] = 'normal';
1856 }
1857 }
1858 // All the variations of font-variant-* we are going to set as font-feature-settings...
1859 if (isset($bilp['OTLtags']) && $bilp['OTLtags']) {
1860 $ffs = array();
1861 if (isset($bilp['OTLtags']['Minus']) && $bilp['OTLtags']['Minus']) {
1862 $f = preg_split('/\s+/', trim($bilp['OTLtags']['Minus']));
1863 foreach ($f AS $ff) {
1864 $ffs[] = "'" . $ff . "' 0";
1865 }
1866 }
1867 if (isset($bilp['OTLtags']['FFMinus']) && $bilp['OTLtags']['FFMinus']) {
1868 $f = preg_split('/\s+/', trim($bilp['OTLtags']['FFMinus']));
1869 foreach ($f AS $ff) {
1870 $ffs[] = "'" . $ff . "' 0";
1871 }
1872 }
1873 if (isset($bilp['OTLtags']['Plus']) && $bilp['OTLtags']['Plus']) {
1874 $f = preg_split('/\s+/', trim($bilp['OTLtags']['Plus']));
1875 foreach ($f AS $ff) {
1876 $ffs[] = "'" . $ff . "' 1";
1877 }
1878 }
1879 if (isset($bilp['OTLtags']['FFPlus']) && $bilp['OTLtags']['FFPlus']) { // May contain numeric value e.g. salt4
1880 $f = preg_split('/\s+/', trim($bilp['OTLtags']['FFPlus']));
1881 foreach ($f AS $ff) {
1882 if (strlen($ff) > 4) {
1883 $ffs[] = "'" . substr($ff, 0, 4) . "' " . substr($ff, 4);
1884 } else {
1885 $ffs[] = "'" . $ff . "' 1";
1886 }
1887 }
1888 }
1889 $p['FONT-FEATURE-SETTINGS'] = implode(', ', $ffs);
1890 }
1891 }
1892
1893 function PreviewBlockCSS($tag, $attr)
1894 {
1895 // Looks ahead from current block level to a new level
1896 $p = array();
1897 $zp = array();
1898 $oldcascadeCSS = $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'];
1899 $classes = array();
1900 if (isset($attr['CLASS'])) {
1901 $classes = preg_split('/\s+/', $attr['CLASS']);
1902 }
1903 //===============================================
1904 // DEFAULT for this TAG set in DefaultCSS
1905 if (isset($this->mpdf->defaultCSS[$tag])) {
1906 $zp = $this->fixCSS($this->mpdf->defaultCSS[$tag]);
1907 if (is_array($zp)) {
1908 $p = array_merge($zp, $p);
1909 } // Inherited overwrites default
1910 }
1911 // STYLESHEET TAG e.g. h1 p div table
1912 if (isset($this->CSS[$tag])) {
1913 $zp = $this->CSS[$tag];
1914 if (is_array($zp)) {
1915 $p = array_merge($p, $zp);
1916 }
1917 }
1918 // STYLESHEET CLASS e.g. .smallone{} .redletter{}
1919 foreach ($classes AS $class) {
1920 $zp = array();
1921 if (isset($this->CSS['CLASS>>' . $class])) {
1922 $zp = $this->CSS['CLASS>>' . $class];
1923 }
1924 if (is_array($zp)) {
1925 $p = array_merge($p, $zp);
1926 }
1927 }
1928 // STYLESHEET ID e.g. #smallone{} #redletter{}
1929 if (isset($attr['ID']) && isset($this->CSS['ID>>' . $attr['ID']])) {
1930 $zp = $this->CSS['ID>>' . $attr['ID']];
1931 if (is_array($zp)) {
1932 $p = array_merge($p, $zp);
1933 }
1934 }
1935 // STYLESHEET CLASS e.g. p.smallone{} div.redletter{}
1936 foreach ($classes AS $class) {
1937 $zp = array();
1938 if (isset($this->CSS[$tag . '>>CLASS>>' . $class])) {
1939 $zp = $this->CSS[$tag . '>>CLASS>>' . $class];
1940 }
1941 if (is_array($zp)) {
1942 $p = array_merge($p, $zp);
1943 }
1944 }
1945 // STYLESHEET CLASS e.g. p#smallone{} div#redletter{}
1946 if (isset($attr['ID']) && isset($this->CSS[$tag . '>>ID>>' . $attr['ID']])) {
1947 $zp = $this->CSS[$tag . '>>ID>>' . $attr['ID']];
1948 if (is_array($zp)) {
1949 $p = array_merge($p, $zp);
1950 }
1951 }
1952 //===============================================
1953 // STYLESHEET TAG e.g. div h1 div p
1954
1955 $this->_set_mergedCSS($oldcascadeCSS[$tag], $p);
1956 // STYLESHEET CLASS e.g. .smallone{} .redletter{}
1957 foreach ($classes AS $class) {
1958
1959 $this->_set_mergedCSS($oldcascadeCSS['CLASS>>' . $class], $p);
1960 }
1961 // STYLESHEET CLASS e.g. #smallone{} #redletter{}
1962 if (isset($attr['ID'])) {
1963
1964 $this->_set_mergedCSS($oldcascadeCSS['ID>>' . $attr['ID']], $p);
1965 }
1966 // STYLESHEET CLASS e.g. div.smallone{} p.redletter{}
1967 foreach ($classes AS $class) {
1968
1969 $this->_set_mergedCSS($oldcascadeCSS[$tag . '>>CLASS>>' . $class], $p);
1970 }
1971 // STYLESHEET CLASS e.g. div#smallone{} p#redletter{}
1972 if (isset($attr['ID'])) {
1973
1974 $this->_set_mergedCSS($oldcascadeCSS[$tag . '>>ID>>' . $attr['ID']], $p);
1975 }
1976 //===============================================
1977 // INLINE STYLE e.g. style="CSS:property"
1978 if (isset($attr['STYLE'])) {
1979 $zp = $this->readInlineCSS($attr['STYLE']);
1980 if (is_array($zp)) {
1981 $p = array_merge($p, $zp);
1982 }
1983 }
1984 //===============================================
1985 return $p;
1986 }
1987
1988 // mPDF 5.7.4 nth-child
1989 function _nthchild($f, $c)
1990 {
1991 // $f is formual e.g. 2N+1 spilt into a preg_match array
1992 // $c is the comparator value e.g row or column number
1993 $c += 1;
1994 $select = false;
1995 $a = 1;
1996 $b = 1;
1997 if ($f[0] == 'ODD') {
1998 $a = 2;
1999 $b = 1;
2000 } else if ($f[0] == 'EVEN') {
2001 $a = 2;
2002 $b = 0;
2003 } else if (count($f) == 2) {
2004 $a = 0;
2005 $b = $f[1] + 0;
2006 } // e.g. (+6)
2007 else if (count($f) == 3) { // e.g. (2N)
2008 if ($f[2] == '') {
2009 $a = 1;
2010 } else if ($f[2] == '-') {
2011 $a = -1;
2012 } else {
2013 $a = $f[2] + 0;
2014 }
2015 $b = 0;
2016 } else if (count($f) == 4) { // e.g. (2N+6)
2017 if ($f[2] == '') {
2018 $a = 1;
2019 } else if ($f[2] == '-') {
2020 $a = -1;
2021 } else {
2022 $a = $f[2] + 0;
2023 }
2024 $b = $f[3] + 0;
2025 } else {
2026 return false;
2027 }
2028 if ($a > 0) {
2029 if (((($c % $a) - $b) % $a) == 0 && $c >= $b) {
2030 $select = true;
2031 }
2032 } else if ($a == 0) {
2033 if ($c == $b) {
2034 $select = true;
2035 }
2036 } else { // if ($a<0)
2037 if (((($c % $a) - $b) % $a) == 0 && $c <= $b) {
2038 $select = true;
2039 }
2040 }
2041 return $select;
2042 }
2043
2044 }
2045