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

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