blob: 682842d4d7da05c13ebe8a671a8c7ce23f245d66 [file] [log] [blame]
Copybara botbe50d492023-11-30 00:16:42 +01001<?php
2 /**********************************************************************
3 * formateString *
4 * *
5 * Version: 1.2 *
6 * Date: 04-10-2017 *
7 * Author: Dan Machado *
8 * Use within exfpdf class *
9 **********************************************************************/
10 class formatedString{
11 public $parced_str;
12 public $style_map;
13 public $positions;
14 private $np;
15 public $iterator;
16 public $width;
17 public $lines;
18 public $linesmap;
19 public $used_fonts;
20
21 private function get_style($str){
22 $style=array('font-family'=>false, 'font-weight'=>false, 'font-style'=>false,
23 'font-size'=>false, 'font-color'=>false, 'href'=>'');
24 $tmp=explode(';', trim($str, '",\', '));
25 foreach($tmp as $x){
26 if($x && strpos($x,':')>0){
27 $r=explode(':',$x);
28 $r[0]=trim($r[0]);
29 $r[1]=trim($r[1]);
30 if(isset($style[$r[0]]) || $r[0]=='style'){
31 if($r[0]=='style' || $r[0]=='font-style'){
32 $r[1]=strtoupper($r[1]);
33 if(strpos($r[1], 'B')!==false){
34 $style['font-weight']='B';
35 }
36 if(strpos($r[1], 'I')!==false){
37 $style['font-style']='I';
38 }
39 if(strpos($r[1], 'U')!==false){
40 $style['font-style'].='U';
41 }
42 }
43 elseif($r[1]){
44 if($r[0]=='href'){
45 $style[$r[0]]=implode(':', array_slice($r,1));
46 }
47 else{
48 $style[$r[0]]=$r[1];
49 }
50 }
51 }
52 }
53 }
54 return $style;
55 }
56
57
58 private function style_merge($style1, $style2){
59 $result=$style1;
60 foreach($style2 as $k=>$v){
61 if($v){
62 $result[$k]=$v;
63 }
64 }
65 return $result;
66 }
67
68 private function style_parcer($text, &$font_data){
69 $str=trim(strtr($text, array("\r"=>'', "\t"=>'')));
70 $rep=array('[bB]{1}'=>'B', '[iI]{1}'=>'I', '[iI]{1}[ ]*[bB]{1}'=>'BI', '[bB]{1}[ ]*[iI]{1}'=>'BI' );
71 foreach($rep as $a=>$v){
72 $str=preg_replace('/<[ ]*'.$a.'[ ]*>/', "<$v>", $str);
73 $str=preg_replace('/<[ ]*\/+[ ]*'.$a.'[ ]*>/', "</$v>", $str);
74 }
75 $str=preg_replace('/<BI>/', '<s "font-weight:B;font-style:I">', $str);
76 $str=preg_replace('/<\/BI>/', "</s>", $str);
77 $str=preg_replace('/<B>/', '<s "font-weight:B;">', $str);
78 $str=preg_replace('/<\/B>/', "</s>", $str);
79 $str=preg_replace('/<I>/', '<s "font-style:I;">', $str);
80 $str=preg_replace('/<\/I>/', "</s>", $str);
81 $open=array();
82 $total=array();
83 $lt="<s";
84 $rt="</s>";
85 $j=strpos($str, $lt, 0);
86 while($j!==false){
87 if($j>0 && ord($str[$j-1])==92){
88 $j=strpos($str, $lt, $j+1);
89 continue;
90 }
91 $k=strpos($str, '>',$j+1);
92 $open[$j]=substr($str, $j+2, $k-($j+2));
93 $total[]=$j;
94 $j=strpos($str, $lt, $j+1);
95 }
96 $j=strpos($str, $rt, 0);
97 while($j!==false){
98 $total[]=$j;
99 $j=strpos($str, $rt, $j+1);
100 }
101 sort($total);
102
103 $cs='';
104 foreach($font_data as $k=>$v){
105 $cs.=$k . ':'. $v . '; ';
106 }
107 $cs=$this->get_style($cs);
108 $tmp=array($cs);
109 $blocks=array();
110 $blockstyle=array();
111 $n=count($total);
112 $k=0;
113 for($i=0; $i<$n; $i++){
114 $blocks[]=substr($str, $k, $total[$i]-$k);
115 $blockstyle[]=$cs;
116 if(isset($open[$total[$i]])){
117 $cs=$this->style_merge($cs, $this->get_style($open[$total[$i]]));
118 array_push($tmp, $cs);
119 $k=strpos($str, '>',$total[$i]+1)+1;
120 }
121 else{
122 $k=$total[$i]+4;
123 array_pop($tmp);
124 $l=count($tmp)-1;
125 $cs=$tmp[$l];
126 }
127 }
128 if($k<strlen($str)){
129 $blocks[]=substr($str, $k);
130 $blockstyle[]=$cs;
131 }
132 $n=count($blocks);
133 for($i=0; $i<$n; $i++){
134 $this->parced_str.=strtr($blocks[$i], array('\<s'=>'<s'));
135 if(strlen($blocks[$i])>0){
136 $blockstyle[$i]['style']=$blockstyle[$i]['font-weight'] . $blockstyle[$i]['font-style'];
137 unset($blockstyle[$i]['font-weight']);
138 unset($blockstyle[$i]['font-style']);
139 $this->style_map[strlen($this->parced_str)-1]=$blockstyle[$i];
140 }
141 }
142 }
143
144 public function __construct($text, $width, &$font_data){
145 $this->iterator=0;
146 $this->parced_str='';
147 $this->style_map=array();
148 $this->style_parcer($text, $font_data);
149 $this->positions=array_keys($this->style_map);
150 $this->np=(bool)count($this->positions);
151 $this->width=$width;
152 $this->lines=array('');
153 $this->linesmap[0]=array(0, 0, 0);
154 $this->used_fonts=array();
155 }
156
157 public function get_str(){
158 return $this->parced_str;
159 }
160
161 public function get_current_style($i){
162 if(!$this->np){
163 return '';
164 }
165 while($this->positions[$this->iterator]<$i){
166 $this->iterator++;
167 }
168 return $this->style_map[$this->positions[$this->iterator]];
169 }
170
171
172 public function break_by_style($t){
173 $i=$this->linesmap[$t][0];
174 $j=$this->linesmap[$t][1];
175 $this->iterator=0;
176 $result=array('chunks'=>array(), 'style'=>array(), 'height'=>0, 'width'=>$this->linesmap[$t][2]);
177 if(strlen($this->parced_str)==0){
178 return $result;
179 }
180 $cs=$this->get_current_style($i);
181 $result['height']=$cs['font-size'];
182 $r=0;
183 $result['chunks'][$r]='';
184 $result['style'][$r]=$cs;
185 while($this->parced_str[$j]==' '){
186 $j--;
187 }
188 $tmp=$i;
189 for($k=$i; $k<=$j; $k++){
190 if($this->parced_str[$tmp]==' ' && $this->parced_str[$k]==' '){
191 $tmp=$k;
192 continue;
193 }
194 if($cs!=$this->get_current_style($k)) {
195 $r++;
196 $cs=$this->get_current_style($k);
197 $result['chunks'][$r]='';
198 $result['style'][$r]=$cs;
199 if($result['height']<$cs['font-size']){
200 $result['height']=$cs['font-size'];
201 }
202 }
203 $result['chunks'][$r].=$this->parced_str[$k];
204 $tmp=$k;
205 }
206 return $result;
207 }
208}
209?>