Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
53 / 53
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
LengthContext
100.00% covered (success)
100.00%
53 / 53
100.00% covered (success)
100.00%
5 / 5
5
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
 withCurrentFontSize
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 withPercentageBasis
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 withFontMetrics
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 withContainerSize
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Phpdftk\Css\Cascade;
6
7/**
8 * Context needed to resolve relative lengths (em/rem/%/vw/vh/ex/ch/lh/rlh)
9 * to absolute pixels.
10 *
11 * - `parentFontSize` — used when resolving `em` on the `font-size` property
12 *   itself (parent's font-size is the reference).
13 * - `currentFontSize` — used for everything else; the resolved font-size of
14 *   the element being computed. Two-pass cascade: resolve font-size first
15 *   with `parentFontSize`, then resolve other lengths using the result.
16 * - `rootFontSize` — `rem` reference; the document root's font-size.
17 * - `viewportWidth` / `viewportHeight` — `vw` / `vh` references in CSS pixels.
18 * - `percentageBasis` — the basis a `%` length resolves against; depends on
19 *   the property (width: containing-block width; line-height: own font-size,
20 *   etc.). Callers pass per-property as needed.
21 */
22final readonly class LengthContext
23{
24    public function __construct(
25        public float $parentFontSize = 16.0,
26        public float $currentFontSize = 16.0,
27        public float $rootFontSize = 16.0,
28        public float $viewportWidth = 816.0,    // 8.5in × 96 DPI
29        public float $viewportHeight = 1056.0,  // 11in × 96 DPI
30        public float $percentageBasis = 0.0,
31        /**
32         * x-height as a fraction of the em-square. CSS Values 4 §6.1.1
33         * defines `ex` as the x-height of the element's first
34         * available font; without font metrics we approximate with
35         * `0.5em` (a sensible fallback for sans-serif designs).
36         * Layout code that has access to the resolved font passes
37         * `font.xHeight / font.unitsPerEm` here so `ex` for fonts
38         * like Ahem (xHeight = full em) resolves correctly.
39         */
40        public float $xHeightRatio = 0.5,
41        /**
42         * Width of the `0` (ZERO) glyph as a fraction of the em-square.
43         * CSS Values 4 §6.1.1 — `ch` is the advance of `0`. The same
44         * 0.5 fallback applies when font metrics aren't reachable.
45         */
46        public float $chWidthRatio = 0.5,
47        /**
48         * Cap-height as a fraction of the em-square. CSS Values 4 §6.1.1 —
49         * `cap` is the cap-height of the element's first available font.
50         * Without font metrics we approximate with `0.7em`; layout code with
51         * the resolved font passes `font.capHeight / font.unitsPerEm`.
52         */
53        public float $capHeightRatio = 0.7,
54        /**
55         * Inline / block size of the nearest size-query container
56         * (`container-type: size` for both; `inline-size` populates
57         * only the inline axis). CSS Containment 3 §6 — `cqw` / `cqi`
58         * resolve against `containerInlineSize`; `cqh` / `cqb` against
59         * `containerBlockSize`; `cqmin` / `cqmax` against the smaller
60         * / larger of the two. Zero by default so cq* units resolve
61         * to 0 outside any size container per §6.3.
62         */
63        public float $containerInlineSize = 0.0,
64        public float $containerBlockSize = 0.0,
65    ) {}
66
67    public function withCurrentFontSize(float $px): self
68    {
69        return new self(
70            $this->parentFontSize,
71            $px,
72            $this->rootFontSize,
73            $this->viewportWidth,
74            $this->viewportHeight,
75            $this->percentageBasis,
76            $this->xHeightRatio,
77            $this->chWidthRatio,
78            $this->capHeightRatio,
79            $this->containerInlineSize,
80            $this->containerBlockSize,
81        );
82    }
83
84    public function withPercentageBasis(float $px): self
85    {
86        return new self(
87            $this->parentFontSize,
88            $this->currentFontSize,
89            $this->rootFontSize,
90            $this->viewportWidth,
91            $this->viewportHeight,
92            $px,
93            $this->xHeightRatio,
94            $this->chWidthRatio,
95            $this->capHeightRatio,
96            $this->containerInlineSize,
97            $this->containerBlockSize,
98        );
99    }
100
101    public function withFontMetrics(float $xHeightRatio, float $chWidthRatio, float $capHeightRatio = 0.7): self
102    {
103        return new self(
104            $this->parentFontSize,
105            $this->currentFontSize,
106            $this->rootFontSize,
107            $this->viewportWidth,
108            $this->viewportHeight,
109            $this->percentageBasis,
110            $xHeightRatio,
111            $chWidthRatio,
112            $capHeightRatio,
113            $this->containerInlineSize,
114            $this->containerBlockSize,
115        );
116    }
117
118    public function withContainerSize(float $inlineSize, float $blockSize): self
119    {
120        return new self(
121            $this->parentFontSize,
122            $this->currentFontSize,
123            $this->rootFontSize,
124            $this->viewportWidth,
125            $this->viewportHeight,
126            $this->percentageBasis,
127            $this->xHeightRatio,
128            $this->chWidthRatio,
129            $this->capHeightRatio,
130            $inlineSize,
131            $blockSize,
132        );
133    }
134}