PluginProbe
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin / 1.8.4
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin v1.8.4
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 1.8.4, at mpdf/classes/cssmgr.php

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