Skip to content

Commit e17a2dd

Browse files
committed
refactor: split structured layout helpers
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent ae0b4e1 commit e17a2dd

3 files changed

Lines changed: 963 additions & 722 deletions

File tree

src/Layout/LayoutStyleResolver.php

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<?php
2+
3+
// SPDX-FileCopyrightText: 2026 LibreSign
4+
// SPDX-License-Identifier: AGPL-3.0-or-later
5+
6+
declare(strict_types=1);
7+
8+
namespace LibreSign\XObjectTemplate\Layout;
9+
10+
use LibreSign\XObjectTemplate\Css\StyleMap;
11+
12+
final readonly class LayoutStyleResolver
13+
{
14+
public function styleValue(StyleMap $style, string $property, string $default): string
15+
{
16+
return $style->get($property, $default) ?? $default;
17+
}
18+
19+
public function toPoints(string $value): float
20+
{
21+
$normalized = strtolower($value);
22+
$number = (float) preg_replace('/[^0-9.\-]/', '', $normalized);
23+
if (str_ends_with($normalized, 'px')) {
24+
return $number * 0.75;
25+
}
26+
27+
return $number;
28+
}
29+
30+
public function resolveRelativeDimension(string $value, float $reference): float
31+
{
32+
$normalized = strtolower(trim($value));
33+
if ($normalized === '') {
34+
return 0.0;
35+
}
36+
37+
if (str_ends_with($normalized, '%')) {
38+
$number = (float) preg_replace('/[^0-9.\-]/', '', $normalized);
39+
40+
return $reference * ($number / 100.0);
41+
}
42+
43+
return $this->toPoints($normalized);
44+
}
45+
46+
public function resolveLineHeight(StyleMap $style, float $fontSize): float
47+
{
48+
$defaultLineHeight = $fontSize * 1.2;
49+
$configuredLineHeight = $this->styleValue($style, 'line-height', '');
50+
51+
if ($configuredLineHeight === '') {
52+
return $defaultLineHeight;
53+
}
54+
55+
return max($defaultLineHeight, $this->toPoints($configuredLineHeight));
56+
}
57+
58+
/**
59+
* @return array{top: float, right: float, bottom: float, left: float}
60+
*/
61+
public function parseBoxSpacing(string $value): array
62+
{
63+
preg_match_all('/\S+/', $value, $matches);
64+
$tokens = $matches[0];
65+
66+
if ($tokens === []) {
67+
return ['top' => 0.0, 'right' => 0.0, 'bottom' => 0.0, 'left' => 0.0];
68+
}
69+
70+
$points = array_map(fn (string $token): float => $this->toPoints($token), $tokens);
71+
$count = count($points);
72+
73+
return match ($count) {
74+
1 => ['top' => $points[0], 'right' => $points[0], 'bottom' => $points[0], 'left' => $points[0]],
75+
2 => ['top' => $points[0], 'right' => $points[1], 'bottom' => $points[0], 'left' => $points[1]],
76+
3 => ['top' => $points[0], 'right' => $points[1], 'bottom' => $points[2], 'left' => $points[1]],
77+
default => ['top' => $points[0], 'right' => $points[1], 'bottom' => $points[2], 'left' => $points[3]],
78+
};
79+
}
80+
81+
/**
82+
* @return array{top: float, right: float, bottom: float, left: float}
83+
*/
84+
public function parseBoxSpacingRelative(string $value, float $widthReference, float $heightReference): array
85+
{
86+
preg_match_all('/\S+/', $value, $matches);
87+
$tokens = $matches[0];
88+
89+
if ($tokens === []) {
90+
return ['top' => 0.0, 'right' => 0.0, 'bottom' => 0.0, 'left' => 0.0];
91+
}
92+
93+
[$top, $right, $bottom, $left] = $this->expandSpacingTokens($tokens);
94+
95+
return [
96+
'top' => $this->resolveRelativeDimension($top, $heightReference),
97+
'right' => $this->resolveRelativeDimension($right, $widthReference),
98+
'bottom' => $this->resolveRelativeDimension($bottom, $heightReference),
99+
'left' => $this->resolveRelativeDimension($left, $widthReference),
100+
];
101+
}
102+
103+
public function resolveFontAlias(string $fontFamily, string $fontWeight): string
104+
{
105+
$primary = strtolower(explode(',', $fontFamily)[0]);
106+
$isBold = $this->isBoldWeight($fontWeight);
107+
108+
if (str_contains($primary, 'times')) {
109+
return $isBold ? 'F4' : 'F3';
110+
}
111+
112+
if (str_contains($primary, 'courier')) {
113+
return $isBold ? 'F6' : 'F5';
114+
}
115+
116+
return $isBold ? 'F2' : 'F1';
117+
}
118+
119+
public function isAbsolutelyPositioned(StyleMap $style): bool
120+
{
121+
return strtolower(trim($this->styleValue($style, 'position', ''))) === 'absolute';
122+
}
123+
124+
/**
125+
* @param list<string> $tokens
126+
* @return array{0: string, 1: string, 2: string, 3: string}
127+
*/
128+
private function expandSpacingTokens(array $tokens): array
129+
{
130+
return match (count($tokens)) {
131+
1 => [$tokens[0], $tokens[0], $tokens[0], $tokens[0]],
132+
2 => [$tokens[0], $tokens[1], $tokens[0], $tokens[1]],
133+
3 => [$tokens[0], $tokens[1], $tokens[2], $tokens[1]],
134+
default => [$tokens[0], $tokens[1], $tokens[2], $tokens[3]],
135+
};
136+
}
137+
138+
private function isBoldWeight(string $fontWeight): bool
139+
{
140+
$normalized = strtolower($fontWeight);
141+
if ($normalized === 'bold' || $normalized === 'bolder') {
142+
return true;
143+
}
144+
145+
if (is_numeric($normalized)) {
146+
return $normalized >= 600;
147+
}
148+
149+
return false;
150+
}
151+
}

0 commit comments

Comments
 (0)