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

LineBox.php in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.4.3, at vendor/dompdf/dompdf/src/LineBox.php

426 lines 10.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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;
8
9 use Dompdf\FrameDecorator\AbstractFrameDecorator;
10 use Dompdf\FrameDecorator\Block;
11 use Dompdf\FrameDecorator\ListBullet;
12 use Dompdf\FrameDecorator\Page;
13 use Dompdf\FrameReflower\Text as TextFrameReflower;
14 use Dompdf\Positioner\Inline as InlinePositioner;
15 use Iterator;
16
17 /**
18 * The line box class
19 *
20 * This class represents a line box
21 * http://www.w3.org/TR/CSS2/visuren.html#line-box
22 *
23 * @package dompdf
24 */
25 class LineBox
26 {
27 /**
28 * @var Block
29 */
30 protected $_block_frame;
31
32 /**
33 * @var AbstractFrameDecorator[]
34 */
35 protected $_frames = [];
36
37 /**
38 * @var ListBullet[]
39 */
40 protected $list_markers = [];
41
42 /**
43 * @var int
44 */
45 public $wc = 0;
46
47 /**
48 * @var float
49 */
50 public $y = 0.0;
51
52 /**
53 * @var float
54 */
55 public $w = 0.0;
56
57 /**
58 * @var float
59 */
60 public $h = 0.0;
61
62 /**
63 * @var float
64 */
65 public $left = 0.0;
66
67 /**
68 * @var float
69 */
70 public $right = 0.0;
71
72 /**
73 * @var AbstractFrameDecorator
74 */
75 public $tallest_frame = null;
76
77 /**
78 * @var bool[]
79 */
80 public $floating_blocks = [];
81
82 /**
83 * @var bool
84 */
85 public $br = false;
86
87 /**
88 * Whether the line box contains any inline-positioned frames.
89 *
90 * @var bool
91 */
92 public $inline = false;
93
94 /**
95 * @var int
96 */
97 public static $max_float_reflows = 10000;
98
99 /**
100 * FIXME smelly hack, used by the get_float_offsets method.
101 *
102 * @var int
103 */
104 private static $float_offset_anti_infinite_loop = 10000;
105
106 /**
107 * @param Block $frame the Block containing this line
108 * @param float $y
109 */
110 public function __construct(Block $frame, float $y = 0.0)
111 {
112 $this->_block_frame = $frame;
113 $this->_frames = [];
114 $this->y = $y;
115
116 $this->get_float_offsets();
117 }
118
119 /**
120 * Returns the floating elements inside the first floating parent
121 *
122 * @param Page $root
123 *
124 * @return Frame[]
125 */
126 public function get_floats_inside(Page $root): array
127 {
128 $floating_frames = $root->get_floating_frames();
129
130 if (count($floating_frames) == 0) {
131 return $floating_frames;
132 }
133
134 // Find nearest floating element
135 $p = $this->_block_frame;
136 while ($p->get_style()->float === "none") {
137 $parent = $p->get_parent();
138
139 if (!$parent) {
140 break;
141 }
142
143 $p = $parent;
144 }
145
146 if ($p == $root) {
147 return $floating_frames;
148 }
149
150 $parent = $p;
151
152 $childs = [];
153
154 foreach ($floating_frames as $_floating) {
155 $p = $_floating->get_parent();
156
157 while (($p = $p->get_parent()) && $p !== $parent);
158
159 if ($p) {
160 $childs[] = $p;
161 }
162 }
163
164 return $childs;
165 }
166
167 /**
168 * Resets the anti-infinite-loop counter for the get_float_offsets method.
169 */
170 public static function reset_float_reflow_limit(): void
171 {
172 self::$float_offset_anti_infinite_loop = self::$max_float_reflows;
173 }
174
175 public function get_float_offsets(): void
176 {
177 $reflower = $this->_block_frame->get_reflower();
178
179 if (!$reflower) {
180 return;
181 }
182
183 $cb_w = null;
184
185 $block = $this->_block_frame;
186 $root = $block->get_root();
187
188 if (!$root) {
189 return;
190 }
191
192 $style = $this->_block_frame->get_style();
193 $floating_frames = $this->get_floats_inside($root);
194 $inside_left_floating_width = 0;
195 $inside_right_floating_width = 0;
196 $outside_left_floating_width = 0;
197 $outside_right_floating_width = 0;
198
199 foreach ($floating_frames as $child_key => $floating_frame) {
200 $floating_frame_parent = $floating_frame->get_parent();
201 $id = $floating_frame->get_id();
202
203 if (isset($this->floating_blocks[$id])) {
204 continue;
205 }
206
207 $float = $floating_frame->get_style()->float;
208 $floating_width = $floating_frame->get_margin_width();
209
210 if (!$cb_w) {
211 $cb_w = $floating_frame->get_containing_block("w");
212 }
213
214 $line_w = $this->get_width();
215
216 if (!$floating_frame->_float_next_line && ($cb_w <= $line_w + $floating_width) && ($cb_w > $line_w)) {
217 $floating_frame->_float_next_line = true;
218 continue;
219 }
220
221 // If the child is still shifted by the floating element
222 if (self::$float_offset_anti_infinite_loop-- > 0 &&
223 $floating_frame->get_position("y") + $floating_frame->get_margin_height() >= $this->y &&
224 $block->get_position("x") + $block->get_margin_width() >= $floating_frame->get_position("x")
225 ) {
226 if ($float === "left") {
227 if ($floating_frame_parent === $this->_block_frame) {
228 $inside_left_floating_width += $floating_width;
229 } else {
230 $outside_left_floating_width += $floating_width;
231 }
232 } elseif ($float === "right") {
233 if ($floating_frame_parent === $this->_block_frame) {
234 $inside_right_floating_width += $floating_width;
235 } else {
236 $outside_right_floating_width += $floating_width;
237 }
238 }
239
240 $this->floating_blocks[$id] = true;
241 } // else, the floating element won't shift anymore
242 else {
243 $root->remove_floating_frame($child_key);
244 }
245 }
246
247 $this->left += $inside_left_floating_width;
248 if ($outside_left_floating_width > 0 && $outside_left_floating_width > ((float)$style->length_in_pt($style->margin_left) + (float)$style->length_in_pt($style->padding_left))) {
249 $this->left += $outside_left_floating_width - (float)$style->length_in_pt($style->margin_left) - (float)$style->length_in_pt($style->padding_left);
250 }
251 $this->right += $inside_right_floating_width;
252 if ($outside_right_floating_width > 0 && $outside_right_floating_width > ((float)$style->length_in_pt($style->margin_left) + (float)$style->length_in_pt($style->padding_right))) {
253 $this->right += $outside_right_floating_width - (float)$style->length_in_pt($style->margin_right) - (float)$style->length_in_pt($style->padding_right);
254 }
255 }
256
257 /**
258 * @return float
259 */
260 public function get_width(): float
261 {
262 return $this->left + $this->w + $this->right;
263 }
264
265 /**
266 * @return Block
267 */
268 public function get_block_frame(): Block
269 {
270 return $this->_block_frame;
271 }
272
273 /**
274 * @return AbstractFrameDecorator[]
275 */
276 public function &get_frames(): array
277 {
278 return $this->_frames;
279 }
280
281 /**
282 * @return bool
283 */
284 public function is_empty(): bool
285 {
286 return $this->_frames === [];
287 }
288
289 /**
290 * @param AbstractFrameDecorator $frame
291 */
292 public function add_frame(Frame $frame): void
293 {
294 $this->_frames[] = $frame;
295
296 if ($frame->get_positioner() instanceof InlinePositioner) {
297 $this->inline = true;
298 }
299 }
300
301 /**
302 * Remove the frame at the given index and all following frames from the
303 * line.
304 *
305 * @param int $index
306 */
307 public function remove_frames(int $index): void
308 {
309 $lastIndex = count($this->_frames) - 1;
310
311 if ($index < 0 || $index > $lastIndex) {
312 return;
313 }
314
315 for ($i = $lastIndex; $i >= $index; $i--) {
316 $f = $this->_frames[$i];
317 unset($this->_frames[$i]);
318 $this->w -= $f->get_margin_width();
319 }
320
321 // Reset array indices
322 $this->_frames = array_values($this->_frames);
323
324 // Recalculate the height of the line
325 $h = 0.0;
326 $this->inline = false;
327
328 foreach ($this->_frames as $f) {
329 $h = max($h, $f->get_margin_height());
330
331 if ($f->get_positioner() instanceof InlinePositioner) {
332 $this->inline = true;
333 }
334 }
335
336 $this->h = $h;
337 }
338
339 /**
340 * Get the `outside` positioned list markers to be vertically aligned with
341 * the line box.
342 *
343 * @return ListBullet[]
344 */
345 public function get_list_markers(): array
346 {
347 return $this->list_markers;
348 }
349
350 /**
351 * Add a list marker to the line box.
352 *
353 * The list marker is only added for the purpose of vertical alignment, it
354 * is not actually added to the list of frames of the line box.
355 */
356 public function add_list_marker(ListBullet $marker): void
357 {
358 $this->list_markers[] = $marker;
359 }
360
361 /**
362 * An iterator of all list markers and inline positioned frames of the line
363 * box.
364 *
365 * @return Iterator<AbstractFrameDecorator>
366 */
367 public function frames_to_align(): Iterator
368 {
369 yield from $this->list_markers;
370
371 foreach ($this->_frames as $frame) {
372 if ($frame->get_positioner() instanceof InlinePositioner) {
373 yield $frame;
374 }
375 }
376 }
377
378 /**
379 * Trim trailing whitespace from the line.
380 */
381 public function trim_trailing_ws(): void
382 {
383 $lastIndex = count($this->_frames) - 1;
384
385 if ($lastIndex < 0) {
386 return;
387 }
388
389 $lastFrame = $this->_frames[$lastIndex];
390 $reflower = $lastFrame->get_reflower();
391
392 if ($reflower instanceof TextFrameReflower && !$lastFrame->is_pre()) {
393 $reflower->trim_trailing_ws();
394 $this->recalculate_width();
395 }
396 }
397
398 /**
399 * Recalculate LineBox width based on the contained frames total width.
400 *
401 * @return float
402 */
403 public function recalculate_width(): float
404 {
405 $width = 0.0;
406
407 foreach ($this->_frames as $frame) {
408 $width += $frame->get_margin_width();
409 }
410
411 return $this->w = $width;
412 }
413
414 public function __toString(): string
415 {
416 $props = ["wc", "y", "w", "h", "left", "right", "br"];
417 $s = "";
418 foreach ($props as $prop) {
419 $s .= "$prop: " . $this->$prop . "\n";
420 }
421 $s .= count($this->_frames) . " frames\n";
422
423 return $s;
424 }
425 }
426