"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 }