PluginProbe
MBE eShip / trunk
MBE eShip vtrunk
2.8.1 trunk 1.0.0 1.1.0 1.1.3 1.2.1 1.2.2 1.3.0 1.4.0 1.4.1 1.5.0 1.5.1 1.5.2 1.6.0 1.7.0 1.7.1 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.1.0 2.1.1 2.1.2 2.2.1 All 37 releases
mail-boxes-etc / lib / dompdf / src / LineBox.php

LineBox.php in MBE eShip trunk, at lib/dompdf/src/LineBox.php

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