"Fossies" - the Fresh Open Source Software Archive 
Member "icingaweb2-2.11.4/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/AbstractFrameDecorator.php" (26 Jan 2023, 22557 Bytes) of package /linux/www/icingaweb2-2.11.4.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 <?php
2 /**
3 * @package dompdf
4 * @link https://github.com/dompdf/dompdf
5 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
6 */
7 namespace Dompdf\FrameDecorator;
8
9 use DOMElement;
10 use DOMNode;
11 use Dompdf\Helpers;
12 use Dompdf\Dompdf;
13 use Dompdf\Exception;
14 use Dompdf\Frame;
15 use Dompdf\Frame\Factory;
16 use Dompdf\Frame\FrameListIterator;
17 use Dompdf\Frame\FrameTreeIterator;
18 use Dompdf\FrameReflower\AbstractFrameReflower;
19 use Dompdf\Css\Style;
20 use Dompdf\Positioner\AbstractPositioner;
21
22 /**
23 * Base AbstractFrameDecorator class
24 *
25 * @package dompdf
26 */
27 abstract class AbstractFrameDecorator extends Frame
28 {
29 const DEFAULT_COUNTER = "-dompdf-default-counter";
30
31 /**
32 * array([id] => counter_value) (for generated content)
33 *
34 * @var array
35 */
36 public $_counters = [];
37
38 /**
39 * The root node of the DOM tree
40 *
41 * @var Frame
42 */
43 protected $_root;
44
45 /**
46 * The decorated frame
47 *
48 * @var Frame
49 */
50 protected $_frame;
51
52 /**
53 * AbstractPositioner object used to position this frame (Strategy pattern)
54 *
55 * @var AbstractPositioner
56 */
57 protected $_positioner;
58
59 /**
60 * Reflower object used to calculate frame dimensions (Strategy pattern)
61 *
62 * @var AbstractFrameReflower
63 */
64 protected $_reflower;
65
66 /**
67 * Reference to the current dompdf instance
68 *
69 * @var Dompdf
70 */
71 protected $_dompdf;
72
73 /**
74 * First block parent
75 *
76 * @var Block
77 */
78 private $_block_parent;
79
80 /**
81 * First positioned parent (position: relative | absolute | fixed)
82 *
83 * @var AbstractFrameDecorator
84 */
85 private $_positioned_parent;
86
87 /**
88 * Cache for the get_parent while loop results
89 *
90 * @var Frame
91 */
92 private $_cached_parent;
93
94 /**
95 * Whether generated content and counters have been set.
96 *
97 * @var bool
98 */
99 public $content_set = false;
100
101 /**
102 * Whether the frame has been split
103 *
104 * @var bool
105 */
106 public $is_split = false;
107
108 /**
109 * Whether the frame is a split-off frame
110 *
111 * @var bool
112 */
113 public $is_split_off = false;
114
115 /**
116 * Class constructor
117 *
118 * @param Frame $frame The decoration target
119 * @param Dompdf $dompdf The Dompdf object
120 */
121 function __construct(Frame $frame, Dompdf $dompdf)
122 {
123 $this->_frame = $frame;
124 $this->_root = null;
125 $this->_dompdf = $dompdf;
126 $frame->set_decorator($this);
127 }
128
129 /**
130 * "Destructor": forcibly free all references held by this object
131 *
132 * @param bool $recursive if true, call dispose on all children
133 */
134 function dispose($recursive = false)
135 {
136 if ($recursive) {
137 while ($child = $this->get_first_child()) {
138 $child->dispose(true);
139 }
140 }
141
142 $this->_root = null;
143 unset($this->_root);
144
145 $this->_frame->dispose(true);
146 $this->_frame = null;
147 unset($this->_frame);
148
149 $this->_positioner = null;
150 unset($this->_positioner);
151
152 $this->_reflower = null;
153 unset($this->_reflower);
154 }
155
156 /**
157 * Return a copy of this frame with $node as its node
158 *
159 * @param DOMNode $node
160 *
161 * @return AbstractFrameDecorator
162 */
163 function copy(DOMNode $node)
164 {
165 $frame = new Frame($node);
166 $style = clone $this->_frame->get_style();
167
168 $style->reset();
169 $frame->set_style($style);
170
171 if ($node instanceof DOMElement && $node->hasAttribute("id")) {
172 $node->setAttribute("data-dompdf-original-id", $node->getAttribute("id"));
173 $node->removeAttribute("id");
174 }
175
176 return Factory::decorate_frame($frame, $this->_dompdf, $this->_root);
177 }
178
179 /**
180 * Create a deep copy: copy this node and all children
181 *
182 * @return AbstractFrameDecorator
183 */
184 function deep_copy()
185 {
186 $node = $this->_frame->get_node()->cloneNode();
187 $frame = new Frame($node);
188 $style = clone $this->_frame->get_style();
189
190 $style->reset();
191 $frame->set_style($style);
192
193 if ($node instanceof DOMElement && $node->hasAttribute("id")) {
194 $node->setAttribute("data-dompdf-original-id", $node->getAttribute("id"));
195 $node->removeAttribute("id");
196 }
197
198 $deco = Factory::decorate_frame($frame, $this->_dompdf, $this->_root);
199
200 foreach ($this->get_children() as $child) {
201 $deco->append_child($child->deep_copy());
202 }
203
204 return $deco;
205 }
206
207 /**
208 * Create an anonymous child frame, inheriting styles from this frame.
209 *
210 * @param string $node_name
211 * @param string $display
212 *
213 * @return AbstractFrameDecorator
214 */
215 public function create_anonymous_child(string $node_name, string $display): AbstractFrameDecorator
216 {
217 $style = $this->get_style();
218 $child_style = $style->get_stylesheet()->create_style();
219 $child_style->set_prop("display", $display);
220 $child_style->inherit($style);
221
222 $node = $this->get_node()->ownerDocument->createElement($node_name);
223 $frame = new Frame($node);
224 $frame->set_style($child_style);
225
226 return Factory::decorate_frame($frame, $this->_dompdf, $this->_root);
227 }
228
229 function reset()
230 {
231 $this->_frame->reset();
232 $this->_reflower->reset();
233 $this->reset_generated_content();
234 $this->revert_counter_increment();
235
236 $this->content_set = false;
237 $this->_counters = [];
238
239 // clear parent lookup caches
240 $this->_cached_parent = null;
241 $this->_block_parent = null;
242 $this->_positioned_parent = null;
243
244 // Reset all children
245 foreach ($this->get_children() as $child) {
246 $child->reset();
247 }
248 }
249
250 /**
251 * If this represents a generated node then child nodes represent generated
252 * content. Remove the children since the content will be generated next
253 * time this frame is reflowed.
254 */
255 protected function reset_generated_content(): void
256 {
257 if ($this->content_set
258 && $this->get_node()->nodeName === "dompdf_generated"
259 ) {
260 $content = $this->get_style()->content;
261
262 if ($content !== "normal" && $content !== "none") {
263 foreach ($this->get_children() as $child) {
264 $this->remove_child($child);
265 }
266 }
267 }
268 }
269
270 /**
271 * Decrement any counters that were incremented on the current node, unless
272 * that node is the body.
273 */
274 protected function revert_counter_increment(): void
275 {
276 if ($this->content_set
277 && $this->get_node()->nodeName !== "body"
278 && ($decrement = $this->get_style()->counter_increment) !== "none"
279 ) {
280 $this->decrement_counters($decrement);
281 }
282 }
283
284 // Getters -----------
285
286 function get_id()
287 {
288 return $this->_frame->get_id();
289 }
290
291 /**
292 * @return Frame
293 */
294 function get_frame()
295 {
296 return $this->_frame;
297 }
298
299 function get_node()
300 {
301 return $this->_frame->get_node();
302 }
303
304 function get_style()
305 {
306 return $this->_frame->get_style();
307 }
308
309 /**
310 * @deprecated
311 */
312 function get_original_style()
313 {
314 return $this->_frame->get_style();
315 }
316
317 function get_containing_block($i = null)
318 {
319 return $this->_frame->get_containing_block($i);
320 }
321
322 function get_position($i = null)
323 {
324 return $this->_frame->get_position($i);
325 }
326
327 /**
328 * @return Dompdf
329 */
330 function get_dompdf()
331 {
332 return $this->_dompdf;
333 }
334
335 public function get_margin_width(): float
336 {
337 return $this->_frame->get_margin_width();
338 }
339
340 public function get_margin_height(): float
341 {
342 return $this->_frame->get_margin_height();
343 }
344
345 public function get_content_box(): array
346 {
347 return $this->_frame->get_content_box();
348 }
349
350 public function get_padding_box(): array
351 {
352 return $this->_frame->get_padding_box();
353 }
354
355 public function get_border_box(): array
356 {
357 return $this->_frame->get_border_box();
358 }
359
360 function set_id($id)
361 {
362 $this->_frame->set_id($id);
363 }
364
365 public function set_style(Style $style): void
366 {
367 $this->_frame->set_style($style);
368 }
369
370 function set_containing_block($x = null, $y = null, $w = null, $h = null)
371 {
372 $this->_frame->set_containing_block($x, $y, $w, $h);
373 }
374
375 function set_position($x = null, $y = null)
376 {
377 $this->_frame->set_position($x, $y);
378 }
379
380 function is_auto_height()
381 {
382 return $this->_frame->is_auto_height();
383 }
384
385 function is_auto_width()
386 {
387 return $this->_frame->is_auto_width();
388 }
389
390 function __toString()
391 {
392 return $this->_frame->__toString();
393 }
394
395 function prepend_child(Frame $child, $update_node = true)
396 {
397 while ($child instanceof AbstractFrameDecorator) {
398 $child = $child->_frame;
399 }
400
401 $this->_frame->prepend_child($child, $update_node);
402 }
403
404 function append_child(Frame $child, $update_node = true)
405 {
406 while ($child instanceof AbstractFrameDecorator) {
407 $child = $child->_frame;
408 }
409
410 $this->_frame->append_child($child, $update_node);
411 }
412
413 function insert_child_before(Frame $new_child, Frame $ref, $update_node = true)
414 {
415 while ($new_child instanceof AbstractFrameDecorator) {
416 $new_child = $new_child->_frame;
417 }
418
419 if ($ref instanceof AbstractFrameDecorator) {
420 $ref = $ref->_frame;
421 }
422
423 $this->_frame->insert_child_before($new_child, $ref, $update_node);
424 }
425
426 function insert_child_after(Frame $new_child, Frame $ref, $update_node = true)
427 {
428 $insert_frame = $new_child;
429 while ($insert_frame instanceof AbstractFrameDecorator) {
430 $insert_frame = $insert_frame->_frame;
431 }
432
433 $reference_frame = $ref;
434 while ($reference_frame instanceof AbstractFrameDecorator) {
435 $reference_frame = $reference_frame->_frame;
436 }
437
438 $this->_frame->insert_child_after($insert_frame, $reference_frame, $update_node);
439 }
440
441 function remove_child(Frame $child, $update_node = true)
442 {
443 while ($child instanceof AbstractFrameDecorator) {
444 $child = $child->_frame;
445 }
446
447 return $this->_frame->remove_child($child, $update_node);
448 }
449
450 /**
451 * @param bool $use_cache
452 * @return AbstractFrameDecorator
453 */
454 function get_parent($use_cache = true)
455 {
456 if ($use_cache && $this->_cached_parent) {
457 return $this->_cached_parent;
458 }
459 $p = $this->_frame->get_parent();
460 if ($p && $deco = $p->get_decorator()) {
461 while ($tmp = $deco->get_decorator()) {
462 $deco = $tmp;
463 }
464
465 return $this->_cached_parent = $deco;
466 } else {
467 return $this->_cached_parent = $p;
468 }
469 }
470
471 /**
472 * @return AbstractFrameDecorator
473 */
474 function get_first_child()
475 {
476 $c = $this->_frame->get_first_child();
477 if ($c && $deco = $c->get_decorator()) {
478 while ($tmp = $deco->get_decorator()) {
479 $deco = $tmp;
480 }
481
482 return $deco;
483 } else {
484 if ($c) {
485 return $c;
486 }
487 }
488
489 return null;
490 }
491
492 /**
493 * @return AbstractFrameDecorator
494 */
495 function get_last_child()
496 {
497 $c = $this->_frame->get_last_child();
498 if ($c && $deco = $c->get_decorator()) {
499 while ($tmp = $deco->get_decorator()) {
500 $deco = $tmp;
501 }
502
503 return $deco;
504 } else {
505 if ($c) {
506 return $c;
507 }
508 }
509
510 return null;
511 }
512
513 /**
514 * @return AbstractFrameDecorator
515 */
516 function get_prev_sibling()
517 {
518 $s = $this->_frame->get_prev_sibling();
519 if ($s && $deco = $s->get_decorator()) {
520 while ($tmp = $deco->get_decorator()) {
521 $deco = $tmp;
522 }
523
524 return $deco;
525 } else {
526 if ($s) {
527 return $s;
528 }
529 }
530
531 return null;
532 }
533
534 /**
535 * @return AbstractFrameDecorator
536 */
537 function get_next_sibling()
538 {
539 $s = $this->_frame->get_next_sibling();
540 if ($s && $deco = $s->get_decorator()) {
541 while ($tmp = $deco->get_decorator()) {
542 $deco = $tmp;
543 }
544
545 return $deco;
546 } else {
547 if ($s) {
548 return $s;
549 }
550 }
551
552 return null;
553 }
554
555 /**
556 * @return FrameListIterator<AbstractFrameDecorator>
557 */
558 public function get_children(): FrameListIterator
559 {
560 return new FrameListIterator($this);
561 }
562
563 /**
564 * @return FrameTreeIterator<AbstractFrameDecorator>
565 */
566 function get_subtree(): FrameTreeIterator
567 {
568 return new FrameTreeIterator($this);
569 }
570
571 function set_positioner(AbstractPositioner $posn)
572 {
573 $this->_positioner = $posn;
574 if ($this->_frame instanceof AbstractFrameDecorator) {
575 $this->_frame->set_positioner($posn);
576 }
577 }
578
579 function set_reflower(AbstractFrameReflower $reflower)
580 {
581 $this->_reflower = $reflower;
582 if ($this->_frame instanceof AbstractFrameDecorator) {
583 $this->_frame->set_reflower($reflower);
584 }
585 }
586
587 /**
588 * @return AbstractPositioner
589 */
590 function get_positioner()
591 {
592 return $this->_positioner;
593 }
594
595 /**
596 * @return AbstractFrameReflower
597 */
598 function get_reflower()
599 {
600 return $this->_reflower;
601 }
602
603 /**
604 * @param Frame $root
605 */
606 function set_root(Frame $root)
607 {
608 $this->_root = $root;
609
610 if ($this->_frame instanceof AbstractFrameDecorator) {
611 $this->_frame->set_root($root);
612 }
613 }
614
615 /**
616 * @return Page
617 */
618 function get_root()
619 {
620 return $this->_root;
621 }
622
623 /**
624 * @return Block
625 */
626 function find_block_parent()
627 {
628 // Find our nearest block level parent
629 if (isset($this->_block_parent)) {
630 return $this->_block_parent;
631 }
632
633 $p = $this->get_parent();
634
635 while ($p) {
636 if ($p->is_block()) {
637 break;
638 }
639
640 $p = $p->get_parent();
641 }
642
643 return $this->_block_parent = $p;
644 }
645
646 /**
647 * @return AbstractFrameDecorator
648 */
649 function find_positioned_parent()
650 {
651 // Find our nearest relative positioned parent
652 if (isset($this->_positioned_parent)) {
653 return $this->_positioned_parent;
654 }
655
656 $p = $this->get_parent();
657 while ($p) {
658 if ($p->is_positioned()) {
659 break;
660 }
661
662 $p = $p->get_parent();
663 }
664
665 if (!$p) {
666 $p = $this->_root;
667 }
668
669 return $this->_positioned_parent = $p;
670 }
671
672 /**
673 * Split this frame at $child.
674 * The current frame is cloned and $child and all children following
675 * $child are added to the clone. The clone is then passed to the
676 * current frame's parent->split() method.
677 *
678 * @param Frame|null $child
679 * @param bool $page_break
680 * @param bool $forced Whether the page break is forced.
681 *
682 * @throws Exception
683 */
684 public function split(?Frame $child = null, bool $page_break = false, bool $forced = false): void
685 {
686 if (is_null($child)) {
687 $this->get_parent()->split($this, $page_break, $forced);
688 return;
689 }
690
691 if ($child->get_parent() !== $this) {
692 throw new Exception("Unable to split: frame is not a child of this one.");
693 }
694
695 $this->revert_counter_increment();
696
697 $node = $this->_frame->get_node();
698 $split = $this->copy($node->cloneNode());
699
700 $style = $this->_frame->get_style();
701 $split_style = $split->get_style();
702
703 // Truncate the box decoration at the split, except for the body
704 if ($node->nodeName !== "body") {
705 // Clear bottom decoration of original frame
706 $style->margin_bottom = 0.0;
707 $style->padding_bottom = 0.0;
708 $style->border_bottom_width = 0.0;
709 $style->border_bottom_left_radius = 0.0;
710 $style->border_bottom_right_radius = 0.0;
711
712 // Clear top decoration of split frame
713 $split_style->margin_top = 0.0;
714 $split_style->padding_top = 0.0;
715 $split_style->border_top_width = 0.0;
716 $split_style->border_top_left_radius = 0.0;
717 $split_style->border_top_right_radius = 0.0;
718 $split_style->page_break_before = "auto";
719 }
720
721 $split_style->text_indent = 0.0;
722 $split_style->counter_reset = "none";
723
724 $this->is_split = true;
725 $split->is_split_off = true;
726 $split->_already_pushed = true;
727
728 $this->get_parent()->insert_child_after($split, $this);
729
730 if ($this instanceof Block) {
731 // Remove the frames that will be moved to the new split node from
732 // the line boxes
733 $this->remove_frames_from_line($child);
734
735 // recalculate the float offsets after paging
736 foreach ($this->get_line_boxes() as $line_box) {
737 $line_box->get_float_offsets();
738 }
739 }
740
741 if (!$forced) {
742 // Reset top margin in case of an unforced page break
743 // https://www.w3.org/TR/CSS21/page.html#allowed-page-breaks
744 $child->get_style()->margin_top = 0.0;
745 }
746
747 // Add $child and all following siblings to the new split node
748 $iter = $child;
749 while ($iter) {
750 $frame = $iter;
751 $iter = $iter->get_next_sibling();
752 $frame->reset();
753 $split->append_child($frame);
754 }
755
756 $this->get_parent()->split($split, $page_break, $forced);
757
758 // Preserve the current counter values. This must be done after the
759 // parent split, as counters get reset on frame reset
760 $split->_counters = $this->_counters;
761 }
762
763 /**
764 * @param array $counters
765 */
766 public function reset_counters(array $counters): void
767 {
768 foreach ($counters as $id => $value) {
769 $this->reset_counter($id, $value);
770 }
771 }
772
773 /**
774 * @param string $id
775 * @param int $value
776 */
777 public function reset_counter(string $id = self::DEFAULT_COUNTER, int $value = 0): void
778 {
779 $this->get_parent()->_counters[$id] = $value;
780 }
781
782 /**
783 * @param array $counters
784 */
785 public function decrement_counters(array $counters): void
786 {
787 foreach ($counters as $id => $increment) {
788 $this->increment_counter($id, $increment * -1);
789 }
790 }
791
792 /**
793 * @param array $counters
794 */
795 public function increment_counters(array $counters): void
796 {
797 foreach ($counters as $id => $increment) {
798 $this->increment_counter($id, $increment);
799 }
800 }
801
802 /**
803 * @param string $id
804 * @param int $increment
805 */
806 public function increment_counter(string $id = self::DEFAULT_COUNTER, int $increment = 1): void
807 {
808 $counter_frame = $this->lookup_counter_frame($id);
809
810 if ($counter_frame) {
811 if (!isset($counter_frame->_counters[$id])) {
812 $counter_frame->_counters[$id] = 0;
813 }
814
815 $counter_frame->_counters[$id] += $increment;
816 }
817 }
818
819 /**
820 * @param string $id
821 * @return AbstractFrameDecorator|null
822 */
823 function lookup_counter_frame($id = self::DEFAULT_COUNTER)
824 {
825 $f = $this->get_parent();
826
827 while ($f) {
828 if (isset($f->_counters[$id])) {
829 return $f;
830 }
831 $fp = $f->get_parent();
832
833 if (!$fp) {
834 return $f;
835 }
836
837 $f = $fp;
838 }
839
840 return null;
841 }
842
843 /**
844 * @param string $id
845 * @param string $type
846 * @return bool|string
847 *
848 * TODO: What version is the best : this one or the one in ListBullet ?
849 */
850 function counter_value(string $id = self::DEFAULT_COUNTER, string $type = "decimal")
851 {
852 $type = mb_strtolower($type);
853
854 if (!isset($this->_counters[$id])) {
855 $this->_counters[$id] = 0;
856 }
857
858 $value = $this->_counters[$id];
859
860 switch ($type) {
861 default:
862 case "decimal":
863 return $value;
864
865 case "decimal-leading-zero":
866 return str_pad($value, 2, "0", STR_PAD_LEFT);
867
868 case "lower-roman":
869 return Helpers::dec2roman($value);
870
871 case "upper-roman":
872 return mb_strtoupper(Helpers::dec2roman($value));
873
874 case "lower-latin":
875 case "lower-alpha":
876 return chr((($value - 1) % 26) + ord('a'));
877
878 case "upper-latin":
879 case "upper-alpha":
880 return chr((($value - 1) % 26) + ord('A'));
881
882 case "lower-greek":
883 return Helpers::unichr($value + 944);
884
885 case "upper-greek":
886 return Helpers::unichr($value + 912);
887 }
888 }
889
890 final function position()
891 {
892 $this->_positioner->position($this);
893 }
894
895 /**
896 * @param float $offset_x
897 * @param float $offset_y
898 * @param bool $ignore_self
899 */
900 final function move(float $offset_x, float $offset_y, bool $ignore_self = false): void
901 {
902 $this->_positioner->move($this, $offset_x, $offset_y, $ignore_self);
903 }
904
905 /**
906 * @param Block|null $block
907 */
908 final function reflow(Block $block = null)
909 {
910 // Uncomment this to see the frames before they're laid out, instead of
911 // during rendering.
912 //echo $this->_frame; flush();
913 $this->_reflower->reflow($block);
914 }
915
916 /**
917 * @return array
918 */
919 final public function get_min_max_width(): array
920 {
921 return $this->_reflower->get_min_max_width();
922 }
923 }