PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.4.4
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.4.4
2.4.3 2.4.4 2.4.2 2.4.0 2.4.1 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.2.0 2.1.21 2.1.20 2.1.19 2.1.18 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 All 60 releases
easy-invoice / vendor / dompdf / php-svg-lib / src / Svg / Document.php

Document.php in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.4.4, at vendor/dompdf/php-svg-lib/src/Svg/Document.php

449 lines 10.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package php-svg-lib
4 * @link http://github.com/dompdf/php-svg-lib
5 * @license GNU LGPLv3+ http://www.gnu.org/copyleft/lesser.html
6 */
7
8 namespace Svg;
9
10 use Svg\Surface\SurfaceInterface;
11 use Svg\Tag\AbstractTag;
12 use Svg\Tag\Anchor;
13 use Svg\Tag\Circle;
14 use Svg\Tag\Ellipse;
15 use Svg\Tag\Group;
16 use Svg\Tag\ClipPath;
17 use Svg\Tag\Image;
18 use Svg\Tag\Line;
19 use Svg\Tag\LinearGradient;
20 use Svg\Tag\Path;
21 use Svg\Tag\Polygon;
22 use Svg\Tag\Polyline;
23 use Svg\Tag\Rect;
24 use Svg\Tag\Stop;
25 use Svg\Tag\Symbol;
26 use Svg\Tag\Text;
27 use Svg\Tag\StyleTag;
28 use Svg\Tag\UseTag;
29
30 class Document extends AbstractTag
31 {
32 protected $filename;
33 protected $_defs_depth = 0;
34 public $inDefs = false;
35
36 protected $x;
37 protected $y;
38 protected $width;
39 protected $height;
40
41 protected $subPathInit;
42 protected $pathBBox;
43 protected $viewBox;
44
45 /** @var SurfaceInterface */
46 protected $surface;
47
48 /** @var AbstractTag[] */
49 protected $stack = array();
50
51 /** @var AbstractTag[] */
52 protected $defs = array();
53
54 /** @var \Sabberworm\CSS\CSSList\Document[] */
55 protected $styleSheets = array();
56
57 public $allowExternalReferences = true;
58
59 public function loadFile($filename)
60 {
61 $this->filename = $filename;
62 }
63
64 protected function initParser() {
65 $parser = xml_parser_create("utf-8");
66 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);
67 xml_set_element_handler(
68 $parser,
69 array($this, "_tagStart"),
70 array($this, "_tagEnd")
71 );
72 xml_set_character_data_handler(
73 $parser,
74 array($this, "_charData")
75 );
76
77 return $parser;
78 }
79
80 public function __construct() {
81
82 }
83
84 /**
85 * Increase the nesting level for defs-like elements
86 *
87 * @return int
88 */
89 public function enterDefs () {
90 $this->_defs_depth++;
91 $this->inDefs = true;
92 return $this->_defs_depth;
93 }
94
95 /**
96 * Decrease the nesting level for defs-like elements
97 *
98 * @return int
99 */
100 public function exitDefs () {
101 $this->_defs_depth--;
102 if ($this->_defs_depth < 0) {
103 $this->_defs_depth = 0;
104 }
105 $this->inDefs = ($this->_defs_depth > 0 ? true : false);
106 return $this->_defs_depth;
107 }
108
109 /**
110 * @return SurfaceInterface
111 */
112 public function getSurface()
113 {
114 return $this->surface;
115 }
116
117 public function getStack()
118 {
119 return $this->stack;
120 }
121
122 public function getWidth()
123 {
124 return $this->width;
125 }
126
127 public function getHeight()
128 {
129 return $this->height;
130 }
131
132 public function getDiagonal()
133 {
134 return sqrt(($this->width)**2 + ($this->height)**2) / sqrt(2);
135 }
136
137 public function getDimensions() {
138 $rootAttributes = null;
139
140 $parser = xml_parser_create("utf-8");
141 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);
142 xml_set_element_handler(
143 $parser,
144 function ($parser, $name, $attributes) use (&$rootAttributes) {
145 if ($name === "svg" && $rootAttributes === null) {
146 $attributes = array_change_key_case($attributes, CASE_LOWER);
147
148 $rootAttributes = $attributes;
149 }
150 },
151 function ($parser, $name) {}
152 );
153
154 $fp = fopen($this->filename, "r");
155 while ($line = fread($fp, 8192)) {
156 xml_parse($parser, $line, false);
157
158 if ($rootAttributes !== null) {
159 break;
160 }
161 }
162 xml_parse($parser, "", true);
163
164 if (PHP_MAJOR_VERSION < 8) {
165 xml_parser_free($parser);
166 }
167
168 return $this->handleSizeAttributes($rootAttributes);
169 }
170
171 public function handleSizeAttributes($attributes){
172 if ($this->width === null) {
173 if (isset($attributes["width"])) {
174 $width = $this->convertSize($attributes["width"], 400);
175 $this->width = $width;
176 }
177
178 if (isset($attributes["height"])) {
179 $height = $this->convertSize($attributes["height"], 300);
180 $this->height = $height;
181 }
182
183 if (isset($attributes['viewbox'])) {
184 $viewBox = preg_split('/[\s,]+/is', trim($attributes['viewbox']));
185 if (count($viewBox) == 4) {
186 $this->x = $viewBox[0];
187 $this->y = $viewBox[1];
188
189 if (!$this->width) {
190 $this->width = $viewBox[2];
191 }
192 if (!$this->height) {
193 $this->height = $viewBox[3];
194 }
195 }
196 }
197 }
198
199 return array(
200 0 => $this->width,
201 1 => $this->height,
202
203 "width" => $this->width,
204 "height" => $this->height,
205 );
206 }
207
208 public function getDocument(){
209 return $this;
210 }
211
212 /**
213 * Append a style sheet
214 *
215 * @param \Sabberworm\CSS\CSSList\Document $stylesheet
216 */
217 public function appendStyleSheet($stylesheet) {
218 $this->styleSheets[] = $stylesheet;
219 }
220
221 /**
222 * Get the document style sheets
223 *
224 * @return \Sabberworm\CSS\CSSList\Document[]
225 */
226 public function getStyleSheets() {
227 return $this->styleSheets;
228 }
229
230 protected function before($attributes)
231 {
232 $surface = $this->getSurface();
233
234 $style = new DefaultStyle($this);
235 $style->inherit($this);
236 $style->fromAttributes($attributes);
237
238 $this->setStyle($style);
239
240 $surface->setStyle($style);
241 }
242
243 public function render(SurfaceInterface $surface)
244 {
245 $this->_defs_depth = 0;
246 $this->inDefs = false;
247 $this->surface = $surface;
248
249 $parser = $this->initParser();
250
251 if ($this->x || $this->y) {
252 $surface->translate(-$this->x, -$this->y);
253 }
254
255 $fp = fopen($this->filename, "r");
256 while ($line = fread($fp, 8192)) {
257 xml_parse($parser, $line, false);
258 }
259
260 xml_parse($parser, "", true);
261
262 if (PHP_MAJOR_VERSION < 8) {
263 xml_parser_free($parser);
264 }
265 }
266
267 protected function svgOffset($attributes)
268 {
269 $this->attributes = $attributes;
270
271 $this->handleSizeAttributes($attributes);
272 }
273
274 public function getDef($id) {
275 $id = ltrim($id, "#");
276
277 return isset($this->defs[$id]) ? $this->defs[$id] : null;
278 }
279
280 private function _tagStart($parser, $name, $attributes)
281 {
282 $this->x = 0;
283 $this->y = 0;
284
285 $tag = null;
286
287 $attributes = array_change_key_case($attributes, CASE_LOWER);
288
289 switch (strtolower($name)) {
290 case 'defs':
291 $this->enterDefs();
292 return;
293
294 case 'svg':
295 if (count($this->attributes)) {
296 $tag = new Group($this, $name);
297 }
298 else {
299 $tag = $this;
300 $this->svgOffset($attributes);
301 }
302 break;
303
304 case 'path':
305 $tag = new Path($this, $name);
306 break;
307
308 case 'rect':
309 $tag = new Rect($this, $name);
310 break;
311
312 case 'circle':
313 $tag = new Circle($this, $name);
314 break;
315
316 case 'ellipse':
317 $tag = new Ellipse($this, $name);
318 break;
319
320 case 'image':
321 $tag = new Image($this, $name);
322 break;
323
324 case 'line':
325 $tag = new Line($this, $name);
326 break;
327
328 case 'polyline':
329 $tag = new Polyline($this, $name);
330 break;
331
332 case 'polygon':
333 $tag = new Polygon($this, $name);
334 break;
335
336 case 'lineargradient':
337 $tag = new LinearGradient($this, $name);
338 break;
339
340 case 'radialgradient':
341 $tag = new LinearGradient($this, $name);
342 break;
343
344 case 'stop':
345 $tag = new Stop($this, $name);
346 break;
347
348 case 'style':
349 $tag = new StyleTag($this, $name);
350 break;
351
352 case 'a':
353 $tag = new Anchor($this, $name);
354 break;
355
356 case 'g':
357 $tag = new Group($this, $name);
358 break;
359
360 case 'symbol':
361 $this->enterDefs();
362 $tag = new Symbol($this, $name);
363 break;
364
365 case 'clippath':
366 $tag = new ClipPath($this, $name);
367 break;
368
369 case 'use':
370 $tag = new UseTag($this, $name);
371 break;
372
373 case 'text':
374 $tag = new Text($this, $name);
375 break;
376
377 case 'desc':
378 return;
379 }
380
381 if ($tag) {
382 if (isset($attributes["id"])) {
383 $this->defs[$attributes["id"]] = $tag;
384 }
385 else {
386 /** @var AbstractTag $top */
387 $top = end($this->stack);
388 if ($top && $top != $tag) {
389 $top->children[] = $tag;
390 }
391 }
392
393 $this->stack[] = $tag;
394
395 $tag->handle($attributes);
396 }
397 }
398
399 function _charData($parser, $data)
400 {
401 $stack_top = end($this->stack);
402
403 if ($stack_top instanceof Text || $stack_top instanceof StyleTag) {
404 $stack_top->appendText($data);
405 }
406 }
407
408 function _tagEnd($parser, $name)
409 {
410 /** @var AbstractTag $tag */
411 $tag = null;
412 switch (strtolower($name)) {
413 case 'defs':
414 $this->exitDefs();
415 return;
416
417 case 'symbol':
418 $this->exitDefs();
419 $tag = array_pop($this->stack);
420 break;
421
422 case 'svg':
423 case 'path':
424 case 'rect':
425 case 'circle':
426 case 'ellipse':
427 case 'image':
428 case 'line':
429 case 'polyline':
430 case 'polygon':
431 case 'radialgradient':
432 case 'lineargradient':
433 case 'stop':
434 case 'style':
435 case 'text':
436 case 'g':
437 case 'clippath':
438 case 'use':
439 case 'a':
440 $tag = array_pop($this->stack);
441 break;
442 }
443
444 if ((!$this->inDefs && $tag) || $tag instanceof StyleTag) {
445 $tag->handleEnd();
446 }
447 }
448 }
449