Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
MultiColumnLayout
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
2 / 2
2
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 withRun
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Phpdftk\HtmlToPdf\Layout;
6
7use Phpdftk\Css\Value\Color;
8
9/**
10 * Resolved multi-column container layout — populated by
11 * {@see BlockLayout::layoutMultiColumn()} when a box's cascade declares
12 * `column-count` and/or `column-width` non-`auto`.
13 *
14 * The painter reads this to draw `column-rule` strokes between adjacent
15 * columns (CSS Multi-column 1 §3). The geometry is recorded relative to
16 * the container's content edge: column 0 starts at `box.geometry.x`, each
17 * subsequent column at `x + i * (columnWidth + columnGap)`.
18 */
19final readonly class MultiColumnLayout
20{
21    public function __construct(
22        public int $columnCount,
23        public float $columnWidth,
24        public float $columnGap,
25        public float $ruleWidth,
26        public string $ruleStyle,
27        public ?Color $ruleColor,
28        /**
29         * CSS Multi-column 1 §3.3 — `column-fill: auto` fragmentation. When
30         * true the container's content was laid out in a SINGLE tall column
31         * (children keep their column-0 positions) and the painter must
32         * SLICE it into `columnCount` bands of `columnHeight`, translating
33         * band `i` to column `i`. `contentOffset` is band 0's origin as a
34         * distance BELOW the container's own content origin — relative
35         * because block layout can still move the container after this is
36         * recorded, and the children move with it. False (the default) = the
37         * classic balance path, where children were already moved to their
38         * columns and paint once.
39         */
40        public bool $fragmented = false,
41        public float $columnHeight = 0.0,
42        public float $contentOffset = 0.0,
43        /**
44         * CSS Multi-column 2 §3 — `column-wrap: wrap`. When true the tall
45         * content is sliced into bands of `columnHeight` and wrapped into a
46         * `columnCount × rowCount` grid (filling a row of columns left→right,
47         * then the next row down), rather than a single row of `columnCount`
48         * columns. `contentHeight` is the tall content's total block size (to
49         * derive the band/row count); `rowGap` separates the rows.
50         */
51        public bool $columnWrap = false,
52        public float $contentHeight = 0.0,
53        public float $rowGap = 0.0,
54        /**
55         * CSS Multi-column 1 §3.3 + §6.2 — the container's FRAGMENTED
56         * columnar runs, in document order. `$fragmented` above can only
57         * describe ONE tall column; a container carved up by
58         * `column-span: all` has several independent runs, each with its
59         * own column height, its own top and its own band count, so those
60         * are recorded here instead. Empty on every container that does
61         * not need slicing (the classic balance path) — the painter falls
62         * back to painting children once.
63         *
64         * @var list<ColumnRun>
65         */
66        public array $runs = [],
67    ) {}
68
69    /**
70     * Append one fragmented columnar run. `MultiColumnLayout` is readonly
71     * and is built before the runs are known, so layout rebuilds it as
72     * each run resolves.
73     */
74    public function withRun(ColumnRun $run): self
75    {
76        return new self(
77            $this->columnCount,
78            $this->columnWidth,
79            $this->columnGap,
80            $this->ruleWidth,
81            $this->ruleStyle,
82            $this->ruleColor,
83            $this->fragmented,
84            $this->columnHeight,
85            $this->contentOffset,
86            $this->columnWrap,
87            $this->contentHeight,
88            $this->rowGap,
89            [...$this->runs, $run],
90        );
91    }
92}