Completed
Push — master ( 7cd6f2...7b7591 )
by
unknown
04:24
created

PDFLib::page_line()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 7
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 34 and the first side effect is on line 1408.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * @package dompdf
4
 * @link    http://dompdf.github.com/
5
 * @author  Benj Carson <[email protected]>
6
 * @author  Helmut Tischer <[email protected]>
7
 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
 */
9
10
namespace Dompdf\Adapter;
11
12
use Dompdf\Canvas;
13
use Dompdf\Dompdf;
14
use Dompdf\Helpers;
15
use Dompdf\Exception;
16
use Dompdf\Image\Cache;
17
use Dompdf\PhpEvaluator;
18
19
/**
20
 * PDF rendering interface
21
 *
22
 * Dompdf\Adapter\PDFLib provides a simple, stateless interface to the one
23
 * provided by PDFLib.
24
 *
25
 * Unless otherwise mentioned, all dimensions are in points (1/72 in).
26
 * The coordinate origin is in the top left corner and y values
27
 * increase downwards.
28
 *
29
 * See {@link http://www.pdflib.com/} for more complete documentation
30
 * on the underlying PDFlib functions.
31
 *
32
 * @package dompdf
33
 */
34
class PDFLib implements Canvas
35
{
36
37
    /**
38
     * Dimensions of paper sizes in points
39
     *
40
     * @var array;
41
     */
42
    static public $PAPER_SIZES = array(); // Set to Dompdf\Adapter\CPDF::$PAPER_SIZES below.
43
44
    /**
45
     * Whether to create PDFs in memory or on disk
46
     *
47
     * @var bool
48
     */
49
    static $IN_MEMORY = true;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $IN_MEMORY.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
50
51
    /**
52
     * @var Dompdf
53
     */
54
    private $_dompdf;
55
56
    /**
57
     * Instance of PDFLib class
58
     *
59
     * @var \PDFlib
60
     */
61
    private $_pdf;
62
63
    /**
64
     * Name of temporary file used for PDFs created on disk
65
     *
66
     * @var string
67
     */
68
    private $_file;
69
70
    /**
71
     * PDF width, in points
72
     *
73
     * @var float
74
     */
75
    private $_width;
76
77
    /**
78
     * PDF height, in points
79
     *
80
     * @var float
81
     */
82
    private $_height;
83
84
    /**
85
     * Last fill color used
86
     *
87
     * @var array
88
     */
89
    private $_last_fill_color;
90
91
    /**
92
     * Last stroke color used
93
     *
94
     * @var array
95
     */
96
    private $_last_stroke_color;
97
98
    /**
99
     * The current opacity level
100
     *
101
     * @var array
102
     */
103
    private $_current_opacity;
104
105
    /**
106
     * Cache of image handles
107
     *
108
     * @var array
109
     */
110
    private $_imgs;
111
112
    /**
113
     * Cache of font handles
114
     *
115
     * @var array
116
     */
117
    private $_fonts;
118
119
    /**
120
     * List of objects (templates) to add to multiple pages
121
     *
122
     * @var array
123
     */
124
    private $_objs;
125
126
    /**
127
     * List of gstate objects created for this PDF (for reuse)
128
     *
129
     * @var array
130
     */
131
    private $_gstates = array();
132
133
    /**
134
     * Current page number
135
     *
136
     * @var int
137
     */
138
    private $_page_number;
139
140
    /**
141
     * Total number of pages
142
     *
143
     * @var int
144
     */
145
    private $_page_count;
146
147
    /**
148
     * Text to display on every page
149
     *
150
     * @var array
151
     */
152
    private $_page_text;
153
154
    /**
155
     * Array of pages for accesing after rendering is initially complete
156
     *
157
     * @var array
158
     */
159
    private $_pages;
0 ignored issues
show
Unused Code introduced by
The property $_pages is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
160
161
    /**
162
     * Class constructor
163
     *
164
     * @param mixed $paper The size of paper to use either a string (see {@link Dompdf\Adapter\CPDF::$PAPER_SIZES}) or
165
     *                            an array(xmin,ymin,xmax,ymax)
166
     * @param string $orientation The orientation of the document (either 'landscape' or 'portrait')
167
     * @param Dompdf $dompdf
168
     */
169
    public function __construct($paper = "letter", $orientation = "portrait", Dompdf $dompdf)
170
    {
171 View Code Duplication
        if (is_array($paper)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
172
            $size = $paper;
173
        } else if (isset(self::$PAPER_SIZES[mb_strtolower($paper)])) {
174
            $size = self::$PAPER_SIZES[mb_strtolower($paper)];
175
        } else {
176
            $size = self::$PAPER_SIZES["letter"];
177
        }
178
179 View Code Duplication
        if (mb_strtolower($orientation) === "landscape") {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
            list($size[2], $size[3]) = array($size[3], $size[2]);
181
        }
182
183
        $this->_width = $size[2] - $size[0];
0 ignored issues
show
Documentation Bug introduced by
It seems like $size[2] - $size[0] can also be of type integer. However, the property $_width is declared as type double. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
184
        $this->_height = $size[3] - $size[1];
0 ignored issues
show
Documentation Bug introduced by
It seems like $size[3] - $size[1] can also be of type integer. However, the property $_height is declared as type double. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
185
186
        $this->_dompdf = $dompdf;
187
188
        $this->_pdf = new \PDFLib();
189
190
        $license = $dompdf->getOptions()->getPdflibLicense();
191
        if (strlen($license) > 0) {
192
            $this->_pdf->set_parameter("license", $license);
193
        }
194
195
        $this->_pdf->set_parameter("textformat", "utf8");
196
        $this->_pdf->set_parameter("fontwarning", "false");
197
198
        // TODO: fetch PDFLib version information for the producer field
199
        $this->_pdf->set_info("Producer Addendum", sprintf("%s + PDFLib", $dompdf->version));
0 ignored issues
show
Documentation introduced by
The property $version is declared private in Dompdf\Dompdf. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
200
201
        // Silence pedantic warnings about missing TZ settings
202
        $tz = @date_default_timezone_get();
203
        date_default_timezone_set("UTC");
204
        $this->_pdf->set_info("Date", date("Y-m-d"));
205
        date_default_timezone_set($tz);
206
207
        if (self::$IN_MEMORY) {
208
            $this->_pdf->begin_document("", "");
209
        } else {
210
            $tmp_dir = $this->_dompdf->getOptions()->getTempDir();
211
            $tmp_name = tempnam($tmp_dir, "libdompdf_pdf_");
212
            @unlink($tmp_name);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
213
            $this->_file = "$tmp_name.pdf";
214
            $this->_pdf->begin_document($this->_file, "");
215
        }
216
217
        $this->_pdf->begin_page_ext($this->_width, $this->_height, "");
218
219
        $this->_page_number = $this->_page_count = 1;
220
        $this->_page_text = array();
221
222
        $this->_imgs = array();
223
        $this->_fonts = array();
224
        $this->_objs = array();
225
    }
226
227
    /**
228
     * @return Dompdf
229
     */
230
    function get_dompdf()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
231
    {
232
        return $this->_dompdf;
233
    }
234
235
    /**
236
     * Close the pdf
237
     */
238
    protected function _close()
239
    {
240
        $this->_place_objects();
241
242
        // Close all pages
243
        $this->_pdf->suspend_page("");
244
        for ($p = 1; $p <= $this->_page_count; $p++) {
245
            $this->_pdf->resume_page("pagenumber=$p");
246
            $this->_pdf->end_page_ext("");
247
        }
248
249
        $this->_pdf->end_document("");
250
    }
251
252
253
    /**
254
     * Returns the PDFLib instance
255
     *
256
     * @return PDFLib
257
     */
258
    public function get_pdflib()
259
    {
260
        return $this->_pdf;
261
    }
262
263
    /**
264
     * Add meta information to the PDF
265
     *
266
     * @param string $label label of the value (Creator, Producter, etc.)
267
     * @param string $value the text to set
268
     */
269
    public function add_info($label, $value)
270
    {
271
        $this->_pdf->set_info($label, $value);
272
    }
273
274
    /**
275
     * Opens a new 'object' (template in PDFLib-speak)
276
     *
277
     * While an object is open, all drawing actions are recorded to the
278
     * object instead of being drawn on the current page.  Objects can
279
     * be added later to a specific page or to several pages.
280
     *
281
     * The return value is an integer ID for the new object.
282
     *
283
     * @see PDFLib::close_object()
284
     * @see PDFLib::add_object()
285
     *
286
     * @return int
287
     */
288
    public function open_object()
289
    {
290
        $this->_pdf->suspend_page("");
291
        $ret = $this->_pdf->begin_template($this->_width, $this->_height);
292
        $this->_pdf->save();
293
        $this->_objs[$ret] = array("start_page" => $this->_page_number);
294
        return $ret;
295
    }
296
297
    /**
298
     * Reopen an existing object (NOT IMPLEMENTED)
299
     * PDFLib does not seem to support reopening templates.
300
     *
301
     * @param int $object the ID of a previously opened object
302
     *
303
     * @throws Exception
304
     * @return void
305
     */
306
    public function reopen_object($object)
0 ignored issues
show
Unused Code introduced by
The parameter $object is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
307
    {
308
        throw new Exception("PDFLib does not support reopening objects.");
309
    }
310
311
    /**
312
     * Close the current template
313
     *
314
     * @see PDFLib::open_object()
315
     */
316
    public function close_object()
317
    {
318
        $this->_pdf->restore();
319
        $this->_pdf->end_template();
320
        $this->_pdf->resume_page("pagenumber=" . $this->_page_number);
321
    }
322
323
    /**
324
     * Adds the specified object to the document
325
     *
326
     * $where can be one of:
327
     * - 'add' add to current page only
328
     * - 'all' add to every page from the current one onwards
329
     * - 'odd' add to all odd numbered pages from now on
330
     * - 'even' add to all even numbered pages from now on
331
     * - 'next' add the object to the next page only
332
     * - 'nextodd' add to all odd numbered pages from the next one
333
     * - 'nexteven' add to all even numbered pages from the next one
334
     *
335
     * @param int $object the object handle returned by open_object()
336
     * @param string $where
337
     */
338
    public function add_object($object, $where = 'all')
339
    {
340
341
        if (mb_strpos($where, "next") !== false) {
342
            $this->_objs[$object]["start_page"]++;
343
            $where = str_replace("next", "", $where);
344
            if ($where == "") {
345
                $where = "add";
346
            }
347
        }
348
349
        $this->_objs[$object]["where"] = $where;
350
    }
351
352
    /**
353
     * Stops the specified template from appearing in the document.
354
     *
355
     * The object will stop being displayed on the page following the
356
     * current one.
357
     *
358
     * @param int $object
359
     */
360
    public function stop_object($object)
361
    {
362
363
        if (!isset($this->_objs[$object])) {
364
            return;
365
        }
366
367
        $start = $this->_objs[$object]["start_page"];
368
        $where = $this->_objs[$object]["where"];
369
370
        // Place the object on this page if required
371 View Code Duplication
        if ($this->_page_number >= $start &&
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
372
            (($this->_page_number % 2 == 0 && $where === "even") ||
373
                ($this->_page_number % 2 == 1 && $where === "odd") ||
374
                ($where === "all"))
375
        ) {
376
            $this->_pdf->fit_image($object, 0, 0, "");
377
        }
378
379
        $this->_objs[$object] = null;
380
        unset($this->_objs[$object]);
381
    }
382
383
    /**
384
     * Add all active objects to the current page
385
     */
386
    protected function _place_objects()
387
    {
388
389
        foreach ($this->_objs as $obj => $props) {
390
            $start = $props["start_page"];
391
            $where = $props["where"];
392
393
            // Place the object on this page if required
394 View Code Duplication
            if ($this->_page_number >= $start &&
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
395
                (($this->_page_number % 2 == 0 && $where === "even") ||
396
                    ($this->_page_number % 2 == 1 && $where === "odd") ||
397
                    ($where === "all"))
398
            ) {
399
                $this->_pdf->fit_image($obj, 0, 0, "");
400
            }
401
        }
402
403
    }
404
405
    /**
406
     * @return float|mixed
407
     */
408
    public function get_width()
409
    {
410
        return $this->_width;
411
    }
412
413
    /**
414
     * @return float|mixed
415
     */
416
    public function get_height()
417
    {
418
        return $this->_height;
419
    }
420
421
    /**
422
     * @return int
423
     */
424
    public function get_page_number()
425
    {
426
        return $this->_page_number;
427
    }
428
429
    /**
430
     * @return int
431
     */
432
    public function get_page_count()
433
    {
434
        return $this->_page_count;
435
    }
436
437
    /**
438
     * @param $num
439
     */
440
    public function set_page_number($num)
441
    {
442
        $this->_page_number = (int)$num;
443
    }
444
445
    /**
446
     * @param int $count
447
     */
448
    public function set_page_count($count)
449
    {
450
        $this->_page_count = (int)$count;
451
    }
452
453
    /**
454
     * Sets the line style
455
     *
456
     * @param float $width
457
     * @param        $cap
458
     * @param string $join
459
     * @param array $dash
460
     *
461
     * @return void
462
     */
463
    protected function _set_line_style($width, $cap, $join, $dash)
464
    {
465
        if (count($dash) == 1) {
466
            $dash[] = $dash[0];
467
        }
468
469
        if (count($dash) > 1) {
470
            $this->_pdf->setdashpattern("dasharray={" . implode(" ", $dash) . "}");
471
        } else {
472
            $this->_pdf->setdash(0, 0);
473
        }
474
475
        switch ($join) {
476
            case "miter":
477
                $this->_pdf->setlinejoin(0);
478
                break;
479
480
            case "round":
481
                $this->_pdf->setlinejoin(1);
482
                break;
483
484
            case "bevel":
485
                $this->_pdf->setlinejoin(2);
486
                break;
487
488
            default:
489
                break;
490
        }
491
492
        switch ($cap) {
493
            case "butt":
494
                $this->_pdf->setlinecap(0);
495
                break;
496
497
            case "round":
498
                $this->_pdf->setlinecap(1);
499
                break;
500
501
            case "square":
502
                $this->_pdf->setlinecap(2);
503
                break;
504
505
            default:
506
                break;
507
        }
508
509
        $this->_pdf->setlinewidth($width);
510
    }
511
512
    /**
513
     * Sets the line color
514
     *
515
     * @param array $color array(r,g,b)
516
     */
517 View Code Duplication
    protected function _set_stroke_color($color)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
518
    {
519
        if ($this->_last_stroke_color == $color) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
520
            //return;
521
        }
522
523
        $alpha = isset($color["alpha"]) ? $color["alpha"] : 1;
524
        if (isset($this->_current_opacity)) {
525
            $alpha *= $this->_current_opacity;
526
        }
527
528
        $this->_last_stroke_color = $color;
529
530
        if (isset($color[3])) {
531
            $type = "cmyk";
532
            list($c1, $c2, $c3, $c4) = array($color[0], $color[1], $color[2], $color[3]);
533
        } elseif (isset($color[2])) {
534
            $type = "rgb";
535
            list($c1, $c2, $c3, $c4) = array($color[0], $color[1], $color[2], null);
536
        } else {
537
            $type = "gray";
538
            list($c1, $c2, $c3, $c4) = array($color[0], $color[1], null, null);
539
        }
540
541
        $this->_set_stroke_opacity($alpha);
542
        $this->_pdf->setcolor("stroke", $type, $c1, $c2, $c3, $c4);
543
    }
544
545
    /**
546
     * Sets the fill color
547
     *
548
     * @param array $color array(r,g,b)
549
     */
550 View Code Duplication
    protected function _set_fill_color($color)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
551
    {
552
        if ($this->_last_fill_color == $color) {
553
            return;
554
        }
555
556
        $alpha = isset($color["alpha"]) ? $color["alpha"] : 1;
557
        if (isset($this->_current_opacity)) {
558
            $alpha *= $this->_current_opacity;
559
        }
560
561
        $this->_last_fill_color = $color;
562
563
        if (isset($color[3])) {
564
            $type = "cmyk";
565
            list($c1, $c2, $c3, $c4) = array($color[0], $color[1], $color[2], $color[3]);
566
        } elseif (isset($color[2])) {
567
            $type = "rgb";
568
            list($c1, $c2, $c3, $c4) = array($color[0], $color[1], $color[2], null);
569
        } else {
570
            $type = "gray";
571
            list($c1, $c2, $c3, $c4) = array($color[0], $color[1], null, null);
572
        }
573
574
        $this->_set_fill_opacity($alpha);
575
        $this->_pdf->setcolor("fill", $type, $c1, $c2, $c3, $c4);
576
    }
577
578
    /**
579
     * Sets the fill opacity
580
     *
581
     * @param $opacity
582
     * @param $mode
583
     */
584
    public function _set_fill_opacity($opacity, $mode = "Normal")
585
    {
586
        if ($mode === "Normal") {
587
            $this->_set_gstate("opacityfill=$opacity");
588
        }
589
    }
590
591
    /**
592
     * Sets the stroke opacity
593
     *
594
     * @param $opacity
595
     * @param $mode
596
     */
597
    public function _set_stroke_opacity($opacity, $mode = "Normal")
598
    {
599
        if ($mode === "Normal") {
600
            $this->_set_gstate("opacitystroke=$opacity");
601
        }
602
    }
603
604
    /**
605
     * Sets the opacity
606
     *
607
     * @param $opacity
608
     * @param $mode
609
     */
610
    public function set_opacity($opacity, $mode = "Normal")
611
    {
612
        if ($mode === "Normal") {
613
            $this->_set_gstate("opacityfill=$opacity opacitystroke=$opacity");
614
            $this->_current_opacity = $opacity;
0 ignored issues
show
Documentation Bug introduced by
It seems like $opacity of type double is incompatible with the declared type array of property $_current_opacity.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
615
        }
616
    }
617
618
    /**
619
     * Sets the gstate
620
     *
621
     * @param $gstate_options
622
     * @return int
623
     */
624
    public function _set_gstate($gstate_options)
625
    {
626
        if (($gstate = array_search($gstate_options, $this->_gstates)) === false) {
627
            $gstate = $this->_pdf->create_gstate($gstate_options);
628
            $this->_gstates[$gstate] = $gstate_options;
629
        }
630
        return $this->_pdf->set_gstate($gstate);
631
    }
632
633
    public function set_default_view($view, $options = array())
634
    {
635
        // TODO
636
        // http://www.pdflib.com/fileadmin/pdflib/pdf/manuals/PDFlib-8.0.2-API-reference.pdf
637
        /**
638
         * fitheight Fit the page height to the window, with the x coordinate left at the left edge of the window.
639
         * fitrect Fit the rectangle specified by left, bottom, right, and top to the window.
640
         * fitvisible Fit the visible contents of the page (the ArtBox) to the window.
641
         * fitvisibleheight Fit the visible contents of the page to the window with the x coordinate left at the left edge of the window.
642
         * fitvisiblewidth Fit the visible contents of the page to the window with the y coordinate top at the top edge of the window.
643
         * fitwidth Fit the page width to the window, with the y coordinate top at the top edge of the window.
644
         * fitwindow Fit the complete page to the window.
645
         * fixed
646
         */
647
        //$this->_pdf->set_parameter("openaction", $view);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
648
    }
649
650
    /**
651
     * Loads a specific font and stores the corresponding descriptor.
652
     *
653
     * @param string $font
654
     * @param string $encoding
655
     * @param string $options
656
     *
657
     * @return int the font descriptor for the font
658
     */
659
    protected function _load_font($font, $encoding = null, $options = "")
660
    {
661
        // Set up font paths
662
        if ($this->_pdf->get_parameter("FontOutline", 1) === "") {
663
            $families = $this->_dompdf->getFontMetrics()->getFontFamilies();
664
            foreach ($families as $files) {
665
                foreach ($files as $file) {
666
                    $face = basename($file);
667
                    $afm = null;
668
669
                    // Prefer ttfs to afms
670
                    if (file_exists("$file.ttf")) {
671
                        $outline = "$file.ttf";
672
673
                    } else if (file_exists("$file.TTF")) {
674
                        $outline = "$file.TTF";
675
676
                    } else if (file_exists("$file.pfb")) {
677
                        $outline = "$file.pfb";
678
                        if (file_exists("$file.afm")) {
679
                            $afm = "$file.afm";
680
                        }
681
682
                    } else if (file_exists("$file.PFB")) {
683
                        $outline = "$file.PFB";
684
                        if (file_exists("$file.AFM")) {
685
                            $afm = "$file.AFM";
686
                        }
687
                    } else {
688
                        continue;
689
                    }
690
691
                    $this->_pdf->set_parameter("FontOutline", "\{$face\}=\{$outline\}");
692
693
                    if (!is_null($afm)) {
694
                        $this->_pdf->set_parameter("FontAFM", "\{$face\}=\{$afm\}");
695
                    }
696
                }
697
            }
698
        }
699
700
        // Check if the font is a native PDF font
701
        // Embed non-native fonts
702
        $test = strtolower(basename($font));
703
        if (in_array($test, DOMPDF::$nativeFonts)) {
704
            $font = basename($font);
705
        } else {
706
            // Embed non-native fonts
707
            $options .= " embedding=true";
708
        }
709
710
        if (is_null($encoding)) {
711
            // Unicode encoding is only available for the commerical
712
            // version of PDFlib and not PDFlib-Lite
713
            if (strlen($this->_dompdf->getOptions()->getPdflibLicense()) > 0) {
714
                $encoding = "unicode";
715
            } else {
716
                $encoding = "auto";
717
            }
718
        }
719
720
        $key = "$font:$encoding:$options";
721
722
        if (isset($this->_fonts[$key])) {
723
            return $this->_fonts[$key];
724
        } else {
725
            $this->_fonts[$key] = $this->_pdf->load_font($font, $encoding, $options);
726
            return $this->_fonts[$key];
727
        }
728
    }
729
730
    /**
731
     * Remaps y coords from 4th to 1st quadrant
732
     *
733
     * @param float $y
734
     * @return float
735
     */
736
    protected function y($y)
737
    {
738
        return $this->_height - $y;
739
    }
740
741
    /**
742
     * @param float $x1
743
     * @param float $y1
744
     * @param float $x2
745
     * @param float $y2
746
     * @param array $color
747
     * @param float $width
748
     * @param array $style
749
     */
750
    public function line($x1, $y1, $x2, $y2, $color, $width, $style = null)
751
    {
752
        $this->_set_line_style($width, "butt", "", $style);
0 ignored issues
show
Bug introduced by
It seems like $style defined by parameter $style on line 750 can also be of type null; however, Dompdf\Adapter\PDFLib::_set_line_style() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
753
        $this->_set_stroke_color($color);
754
755
        $y1 = $this->y($y1);
756
        $y2 = $this->y($y2);
757
758
        $this->_pdf->moveto($x1, $y1);
759
        $this->_pdf->lineto($x2, $y2);
760
        $this->_pdf->stroke();
761
762
        $this->_set_line_transparency("Normal", $this->_current_opacity);
0 ignored issues
show
Bug introduced by
The method _set_line_transparency() does not seem to exist on object<Dompdf\Adapter\PDFLib>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
763
    }
764
765
    /**
766
     * Draw line at the specified coordinates on every page.
767
     *
768
     * See {@link Style::munge_color()} for the format of the colour array.
769
     *
770
     * @param float $x1
771
     * @param float $y1
772
     * @param float $x2
773
     * @param float $y2
774
     * @param array $color
775
     * @param float $width
776
     * @param array $style optional
777
     */
778
    public function page_line($x1, $y1, $x2, $y2, $color, $width, $style = array())
779
    {
780
        $_t = 'line';
781
        $this->_page_text[] = compact('_t', 'x1', 'y1', 'x2', 'y2', 'color', 'width', 'style');
782
    }
783
784
    /**
785
     * @param float $x1
786
     * @param float $y1
787
     * @param float $r1
788
     * @param float $r2
789
     * @param float $astart
790
     * @param float $aend
791
     * @param array $color
792
     * @param float $width
793
     * @param array $style
794
     */
795 View Code Duplication
    public function arc($x1, $y1, $r1, $r2, $astart, $aend, $color, $width, $style = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
796
    {
797
        $this->_set_line_style($width, "butt", "", $style);
798
        $this->_set_stroke_color($color);
799
800
        $y1 = $this->y($y1);
801
802
        $this->_pdf->arc($x1, $y1, $r1, $astart, $aend);
803
        $this->_pdf->stroke();
804
805
        $this->_set_line_transparency("Normal", $this->_current_opacity);
0 ignored issues
show
Bug introduced by
The method _set_line_transparency() does not seem to exist on object<Dompdf\Adapter\PDFLib>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
806
    }
807
808
    /**
809
     * @param float $x1
810
     * @param float $y1
811
     * @param float $w
812
     * @param float $h
813
     * @param array $color
814
     * @param float $width
815
     * @param null $style
816
     */
817 View Code Duplication
    public function rectangle($x1, $y1, $w, $h, $color, $width, $style = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
818
    {
819
        $this->_set_stroke_color($color);
820
        $this->_set_line_style($width, "butt", "", $style);
0 ignored issues
show
Documentation introduced by
$style is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
821
822
        $y1 = $this->y($y1) - $h;
823
824
        $this->_pdf->rect($x1, $y1, $w, $h);
825
        $this->_pdf->stroke();
826
827
        $this->_set_line_transparency("Normal", $this->_current_opacity);
0 ignored issues
show
Bug introduced by
The method _set_line_transparency() does not seem to exist on object<Dompdf\Adapter\PDFLib>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
828
    }
829
830
    /**
831
     * @param float $x1
832
     * @param float $y1
833
     * @param float $w
834
     * @param float $h
835
     * @param array $color
836
     */
837
    public function filled_rectangle($x1, $y1, $w, $h, $color)
838
    {
839
        $this->_set_fill_color($color);
840
841
        $y1 = $this->y($y1) - $h;
842
843
        $this->_pdf->rect(floatval($x1), floatval($y1), floatval($w), floatval($h));
844
        $this->_pdf->fill();
845
846
        $this->_set_fill_transparency("Normal", $this->_current_opacity);
0 ignored issues
show
Bug introduced by
The method _set_fill_transparency() does not seem to exist on object<Dompdf\Adapter\PDFLib>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
847
    }
848
849
    /**
850
     * @param float $x1
851
     * @param float $y1
852
     * @param float $w
853
     * @param float $h
854
     */
855
    public function clipping_rectangle($x1, $y1, $w, $h)
856
    {
857
        $this->_pdf->save();
858
859
        $y1 = $this->y($y1) - $h;
860
861
        $this->_pdf->rect(floatval($x1), floatval($y1), floatval($w), floatval($h));
862
        $this->_pdf->clip();
863
    }
864
865
    /**
866
     * @param float $x1
867
     * @param float $y1
868
     * @param float $w
869
     * @param float $h
870
     * @param float $rTL
871
     * @param float $rTR
872
     * @param float $rBR
873
     * @param float $rBL
874
     */
875
    public function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL)
876
    {
877
        // @todo
878
        $this->clipping_rectangle($x1, $y1, $w, $h);
879
    }
880
881
    /**
882
     *
883
     */
884
    public function clipping_end()
885
    {
886
        $this->_pdf->restore();
887
    }
888
889
    /**
890
     *
891
     */
892
    public function save()
893
    {
894
        $this->_pdf->save();
895
    }
896
897
    function restore()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
898
    {
899
        $this->_pdf->restore();
900
    }
901
902
    /**
903
     * @param $angle
904
     * @param $x
905
     * @param $y
906
     */
907 View Code Duplication
    public function rotate($angle, $x, $y)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
908
    {
909
        $pdf = $this->_pdf;
910
        $pdf->translate($x, $this->_height - $y);
911
        $pdf->rotate(-$angle);
912
        $pdf->translate(-$x, -$this->_height + $y);
913
    }
914
915
    /**
916
     * @param $angle_x
917
     * @param $angle_y
918
     * @param $x
919
     * @param $y
920
     */
921 View Code Duplication
    public function skew($angle_x, $angle_y, $x, $y)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
922
    {
923
        $pdf = $this->_pdf;
924
        $pdf->translate($x, $this->_height - $y);
925
        $pdf->skew($angle_y, $angle_x); // Needs to be inverted
926
        $pdf->translate(-$x, -$this->_height + $y);
927
    }
928
929
    /**
930
     * @param $s_x
931
     * @param $s_y
932
     * @param $x
933
     * @param $y
934
     */
935 View Code Duplication
    public function scale($s_x, $s_y, $x, $y)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
936
    {
937
        $pdf = $this->_pdf;
938
        $pdf->translate($x, $this->_height - $y);
939
        $pdf->scale($s_x, $s_y);
940
        $pdf->translate(-$x, -$this->_height + $y);
941
    }
942
943
    /**
944
     * @param $t_x
945
     * @param $t_y
946
     */
947
    public function translate($t_x, $t_y)
948
    {
949
        $this->_pdf->translate($t_x, -$t_y);
950
    }
951
952
    /**
953
     * @param $a
954
     * @param $b
955
     * @param $c
956
     * @param $d
957
     * @param $e
958
     * @param $f
959
     */
960
    public function transform($a, $b, $c, $d, $e, $f)
961
    {
962
        $this->_pdf->concat($a, $b, $c, $d, $e, $f);
963
    }
964
965
    /**
966
     * @param array $points
967
     * @param array $color
968
     * @param null $width
969
     * @param null $style
970
     * @param bool $fill
971
     */
972
    public function polygon($points, $color, $width = null, $style = null, $fill = false)
973
    {
974
        $this->_set_fill_color($color);
975
        $this->_set_stroke_color($color);
976
977
        if (!$fill && isset($width)) {
978
            $this->_set_line_style($width, "square", "miter", $style);
0 ignored issues
show
Documentation introduced by
$style is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
979
        }
980
981
        $y = $this->y(array_pop($points));
982
        $x = array_pop($points);
983
        $this->_pdf->moveto($x, $y);
984
985
        while (count($points) > 1) {
986
            $y = $this->y(array_pop($points));
987
            $x = array_pop($points);
988
            $this->_pdf->lineto($x, $y);
989
        }
990
991
        if ($fill) {
992
            $this->_pdf->fill();
993
        } else {
994
            $this->_pdf->closepath_stroke();
995
        }
996
997
        $this->_set_fill_transparency("Normal", $this->_current_opacity);
0 ignored issues
show
Bug introduced by
The method _set_fill_transparency() does not seem to exist on object<Dompdf\Adapter\PDFLib>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
998
        $this->_set_line_transparency("Normal", $this->_current_opacity);
0 ignored issues
show
Bug introduced by
The method _set_line_transparency() does not seem to exist on object<Dompdf\Adapter\PDFLib>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
999
    }
1000
1001
    /**
1002
     * @param float $x
1003
     * @param float $y
1004
     * @param float $r
1005
     * @param array $color
1006
     * @param null $width
1007
     * @param null $style
1008
     * @param bool $fill
1009
     */
1010
    public function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false)
1011
    {
1012
        $this->_set_fill_color($color);
1013
        $this->_set_stroke_color($color);
1014
1015
        if (!$fill && isset($width)) {
1016
            $this->_set_line_style($width, "round", "round", $style);
0 ignored issues
show
Documentation introduced by
$style is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1017
        }
1018
1019
        $y = $this->y($y);
1020
1021
        $this->_pdf->circle($x, $y, $r);
1022
1023
        if ($fill) {
1024
            $this->_pdf->fill();
1025
        } else {
1026
            $this->_pdf->stroke();
1027
        }
1028
1029
        $this->_set_fill_transparency("Normal", $this->_current_opacity);
0 ignored issues
show
Bug introduced by
The method _set_fill_transparency() does not seem to exist on object<Dompdf\Adapter\PDFLib>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1030
        $this->_set_line_transparency("Normal", $this->_current_opacity);
0 ignored issues
show
Bug introduced by
The method _set_line_transparency() does not seem to exist on object<Dompdf\Adapter\PDFLib>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1031
    }
1032
1033
    /**
1034
     * @param string $img_url
1035
     * @param float $x
1036
     * @param float $y
1037
     * @param int $w
1038
     * @param int $h
1039
     * @param string $resolution
1040
     */
1041
    public function image($img_url, $x, $y, $w, $h, $resolution = "normal")
1042
    {
1043
        $w = (int)$w;
1044
        $h = (int)$h;
1045
1046
        $img_type = Cache::detect_type($img_url, $this->get_dompdf()->getHttpContext());
1047
1048
        if (!isset($this->_imgs[$img_url])) {
1049
            $this->_imgs[$img_url] = $this->_pdf->load_image($img_type, $img_url, "");
1050
        }
1051
1052
        $img = $this->_imgs[$img_url];
1053
1054
        $y = $this->y($y) - $h;
1055
        $this->_pdf->fit_image($img, $x, $y, 'boxsize={' . "$w $h" . '} fitmethod=entire');
1056
    }
1057
1058
    /**
1059
     * @param float $x
1060
     * @param float $y
1061
     * @param string $text
1062
     * @param string $font
1063
     * @param float $size
1064
     * @param array $color
1065
     * @param int $word_spacing
1066
     * @param int $char_spacing
1067
     * @param int $angle
1068
     */
1069
    public function text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_spacing = 0, $char_spacing = 0, $angle = 0)
1070
    {
1071
        $fh = $this->_load_font($font);
1072
1073
        $this->_pdf->setfont($fh, $size);
1074
        $this->_set_fill_color($color);
1075
1076
        $y = $this->y($y) - $this->get_font_height($font, $size);
1077
1078
        $word_spacing = (float)$word_spacing;
1079
        $char_spacing = (float)$char_spacing;
1080
        $angle = -(float)$angle;
1081
1082
        $this->_pdf->fit_textline($text, $x, $y, "rotate=$angle wordspacing=$word_spacing charspacing=$char_spacing ");
1083
1084
        $this->_set_fill_transparency("Normal", $this->_current_opacity);
0 ignored issues
show
Bug introduced by
The method _set_fill_transparency() does not seem to exist on object<Dompdf\Adapter\PDFLib>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1085
    }
1086
1087
    /**
1088
     * @param string $code
1089
     */
1090
    public function javascript($code)
1091
    {
1092
        if (strlen($this->_dompdf->getOptions()->getPdflibLicense()) > 0) {
1093
            $this->_pdf->create_action("JavaScript", $code);
1094
        }
1095
    }
1096
1097
    /**
1098
     * Add a named destination (similar to <a name="foo">...</a> in html)
1099
     *
1100
     * @param string $anchorname The name of the named destination
1101
     */
1102
    public function add_named_dest($anchorname)
1103
    {
1104
        $this->_pdf->add_nameddest($anchorname, "");
1105
    }
1106
1107
    /**
1108
     * Add a link to the pdf
1109
     *
1110
     * @param string $url The url to link to
1111
     * @param float $x The x position of the link
1112
     * @param float $y The y position of the link
1113
     * @param float $width The width of the link
1114
     * @param float $height The height of the link
1115
     */
1116
    public function add_link($url, $x, $y, $width, $height)
1117
    {
1118
        $y = $this->y($y) - $height;
1119
        if (strpos($url, '#') === 0) {
1120
            // Local link
1121
            $name = substr($url, 1);
1122
            if ($name) {
1123
                $this->_pdf->create_annotation($x, $y, $x + $width, $y + $height, 'Link',
1124
                    "contents={$url} destname=" . substr($url, 1) . " linewidth=0");
1125
            }
1126
        } else {
1127
            list($proto, $host, $path, $file) = Helpers::explode_url($url);
1128
1129
            if ($proto == "" || $proto === "file://") {
1130
                return; // Local links are not allowed
1131
            }
1132
            $url = Helpers::build_url($proto, $host, $path, $file);
1133
            $url = '{' . rawurldecode($url) . '}';
1134
1135
            $action = $this->_pdf->create_action("URI", "url=" . $url);
1136
            $this->_pdf->create_annotation($x, $y, $x + $width, $y + $height, 'Link', "contents={$url} action={activate=$action} linewidth=0");
1137
        }
1138
    }
1139
1140
    /**
1141
     * @param string $text
1142
     * @param string $font
1143
     * @param float $size
1144
     * @param int $word_spacing
1145
     * @param int $letter_spacing
1146
     * @return mixed
1147
     */
1148
    public function get_text_width($text, $font, $size, $word_spacing = 0, $letter_spacing = 0)
1149
    {
1150
        $fh = $this->_load_font($font);
1151
1152
        // Determine the additional width due to extra spacing
1153
        $num_spaces = mb_substr_count($text, " ");
1154
        $delta = $word_spacing * $num_spaces;
1155
1156
        if ($letter_spacing) {
1157
            $num_chars = mb_strlen($text);
1158
            $delta += ($num_chars - $num_spaces) * $letter_spacing;
1159
        }
1160
1161
        return $this->_pdf->stringwidth($text, $fh, $size) + $delta;
1162
    }
1163
1164
    /**
1165
     * @param string $font
1166
     * @param float $size
1167
     * @return float
1168
     */
1169
    public function get_font_height($font, $size)
1170
    {
1171
        $fh = $this->_load_font($font);
1172
1173
        $this->_pdf->setfont($fh, $size);
1174
1175
        $asc = $this->_pdf->get_value("ascender", $fh);
1176
        $desc = $this->_pdf->get_value("descender", $fh);
1177
1178
        // $desc is usually < 0,
1179
        $ratio = $this->_dompdf->getOptions()->getFontHeightRatio();
1180
        return $size * ($asc - $desc) * $ratio;
1181
    }
1182
1183
    /**
1184
     * @param string $font
1185
     * @param float $size
1186
     * @return float
1187
     */
1188
    public function get_font_baseline($font, $size)
1189
    {
1190
        $ratio = $this->_dompdf->getOptions()->getFontHeightRatio();
1191
        return $this->get_font_height($font, $size) / $ratio * 1.1;
1192
    }
1193
1194
    /**
1195
     * Writes text at the specified x and y coordinates on every page
1196
     *
1197
     * The strings '{PAGE_NUM}' and '{PAGE_COUNT}' are automatically replaced
1198
     * with their current values.
1199
     *
1200
     * See {@link Style::munge_color()} for the format of the color array.
1201
     *
1202
     * @param float $x
1203
     * @param float $y
1204
     * @param string $text the text to write
1205
     * @param string $font the font file to use
1206
     * @param float $size the font size, in points
1207
     * @param array $color
1208
     * @param float $word_space word spacing adjustment
1209
     * @param float $char_space char spacing adjustment
1210
     * @param float $angle angle to write the text at, measured CW starting from the x-axis
1211
     */
1212
    public function page_text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0)
1213
    {
1214
        $_t = "text";
1215
        $this->_page_text[] = compact("_t", "x", "y", "text", "font", "size", "color", "word_space", "char_space", "angle");
1216
    }
1217
1218
    //........................................................................
0 ignored issues
show
Unused Code Comprehensibility introduced by
100% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1219
1220
    /**
1221
     * Processes a script on every page
1222
     *
1223
     * The variables $pdf, $PAGE_NUM, and $PAGE_COUNT are available.
1224
     *
1225
     * This function can be used to add page numbers to all pages
1226
     * after the first one, for example.
1227
     *
1228
     * @param string $code the script code
1229
     * @param string $type the language type for script
1230
     */
1231
    public function page_script($code, $type = "text/php")
1232
    {
1233
        $_t = "script";
1234
        $this->_page_text[] = compact("_t", "code", "type");
1235
    }
1236
1237
    /**
1238
     *
1239
     */
1240
    public function new_page()
1241
    {
1242
        // Add objects to the current page
1243
        $this->_place_objects();
1244
1245
        $this->_pdf->suspend_page("");
1246
        $this->_pdf->begin_page_ext($this->_width, $this->_height, "");
1247
        $this->_page_number = ++$this->_page_count;
1248
    }
1249
1250
    /**
1251
     * Add text to each page after rendering is complete
1252
     */
1253
    protected function _add_page_text()
1254
    {
1255
        if (!count($this->_page_text)) {
1256
            return;
1257
        }
1258
1259
        $eval = null;
1260
        $this->_pdf->suspend_page("");
1261
1262
        for ($p = 1; $p <= $this->_page_count; $p++) {
1263
            $this->_pdf->resume_page("pagenumber=$p");
1264
1265 View Code Duplication
            foreach ($this->_page_text as $pt) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1266
                extract($pt);
1267
1268
                switch ($_t) {
1269
                    case "text":
1270
                        $text = str_replace(array("{PAGE_NUM}", "{PAGE_COUNT}"),
1271
                            array($p, $this->_page_count), $text);
1272
                        $this->text($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle);
1273
                        break;
1274
1275
                    case "script":
1276
                        if (!$eval) {
1277
                            $eval = new PHPEvaluator($this);
1278
                        }
1279
                        $eval->evaluate($code, array('PAGE_NUM' => $p, 'PAGE_COUNT' => $this->_page_count));
1280
                        break;
1281
1282
                    case 'line':
1283
                        $this->line( $x1, $y1, $x2, $y2, $color, $width, $style );
1284
                        break;
1285
1286
                }
1287
            }
1288
1289
            $this->_pdf->suspend_page("");
1290
        }
1291
1292
        $this->_pdf->resume_page("pagenumber=" . $this->_page_number);
1293
    }
1294
1295
    /**
1296
     * Streams the PDF to the client.
1297
     *
1298
     * @param string $filename The filename to present to the client.
1299
     * @param array $options Associative array: 'compress' => 1 or 0 (default 1); 'Attachment' => 1 or 0 (default 1).
1300
     * @throws Exception
1301
     */
1302
    public function stream($filename = "document.pdf", $options = array())
1303
    {
1304
        if (headers_sent()) {
1305
            die("Unable to stream pdf: headers already sent");
0 ignored issues
show
Coding Style Compatibility introduced by
The method stream() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1306
        }
1307
1308
        if (!isset($options["compress"])) $options["compress"] = true;
1309
        if (!isset($options["Attachment"])) $options["Attachment"] = true;
1310
1311
        $this->_add_page_text();
1312
1313
        if ($options["compress"]) {
1314
            $this->_pdf->set_value("compress", 6);
1315
        } else {
1316
            $this->_pdf->set_value("compress", 0);
1317
        }
1318
1319
        $this->_close();
1320
1321
        $data = "";
1322
1323
        if (self::$IN_MEMORY) {
1324
            $data = $this->_pdf->get_buffer();
1325
            $size = mb_strlen($data, "8bit");
1326
        } else {
1327
            $size = filesize($this->_file);
1328
        }
1329
1330
        header("Cache-Control: private");
1331
        header("Content-Type: application/pdf");
1332
        header("Content-Length: " . $size);
1333
1334
        $filename = str_replace(array("\n", "'"), "", basename($filename, ".pdf")) . ".pdf";
1335
        $attachment = $options["Attachment"] ? "attachment" : "inline";
1336
        header(Helpers::buildContentDispositionHeader($attachment, $filename));
1337
1338
        if (self::$IN_MEMORY) {
1339
            echo $data;
1340
        } else {
1341
            // Chunked readfile()
1342
            $chunk = (1 << 21); // 2 MB
1343
            $fh = fopen($this->_file, "rb");
1344
            if (!$fh) {
1345
                throw new Exception("Unable to load temporary PDF file: " . $this->_file);
1346
            }
1347
1348
            while (!feof($fh)) {
1349
                echo fread($fh, $chunk);
1350
            }
1351
            fclose($fh);
1352
1353
            //debugpng
1354
            if ($this->_dompdf->getOptions()->getDebugPng()) {
1355
                print '[pdflib stream unlink ' . $this->_file . ']';
1356
            }
1357
            if (!$this->_dompdf->getOptions()->getDebugKeepTemp()) {
1358
                unlink($this->_file);
1359
            }
1360
            $this->_file = null;
1361
            unset($this->_file);
1362
        }
1363
1364
        flush();
1365
    }
1366
1367
    /**
1368
     * Returns the PDF as a string.
1369
     *
1370
     * @param array $options Associative array: 'compress' => 1 or 0 (default 1).
1371
     * @return string
1372
     */
1373
    public function output($options = array())
1374
    {
1375
        if (!isset($options["compress"])) $options["compress"] = true;
1376
1377
        $this->_add_page_text();
1378
1379
        if ($options["compress"]) {
1380
            $this->_pdf->set_value("compress", 6);
1381
        } else {
1382
            $this->_pdf->set_value("compress", 0);
1383
        }
1384
1385
        $this->_close();
1386
1387
        if (self::$IN_MEMORY) {
1388
            $data = $this->_pdf->get_buffer();
1389
        } else {
1390
            $data = file_get_contents($this->_file);
1391
1392
            //debugpng
1393
            if ($this->_dompdf->getOptions()->getDebugPng()) {
1394
                print '[pdflib output unlink ' . $this->_file . ']';
1395
            }
1396
            if (!$this->_dompdf->getOptions()->getDebugKeepTemp()) {
1397
                unlink($this->_file);
1398
            }
1399
            $this->_file = null;
1400
            unset($this->_file);
1401
        }
1402
1403
        return $data;
1404
    }
1405
}
1406
1407
// Workaround for idiotic limitation on statics...
1408
PDFLib::$PAPER_SIZES = CPDF::$PAPER_SIZES;
0 ignored issues
show
Bug introduced by
The property PAPER_SIZES cannot be accessed from this context as it is declared private in class Dompdf\Adapter\CPDF.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1409