Skip to content

Commit 0d978c8

Browse files
ssddanbrownbsweeney
authored andcommitted
Added support for additional relative length units
Implements tag-aware reference size handling to supply a sensible reference size depending on unit and tag context.
1 parent 79a523f commit 0d978c8

File tree

9 files changed

+134
-30
lines changed

9 files changed

+134
-30
lines changed

src/Svg/Style.php

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,12 @@ static function convertSize($size, $referenceSize = 11.0, $dpi = 96.0) {
404404
return $size;
405405
}
406406

407+
// Has to be before 'in' to not be mis-identified
408+
if ($pos = strpos($size, "vmin")) {
409+
$val = floatval(substr($size, 0, $pos));
410+
return $referenceSize * ($val / 100);
411+
}
412+
407413
if ($pos = strpos($size, "px")) {
408414
return floatval(substr($size, 0, $pos));
409415
}
@@ -447,13 +453,35 @@ static function convertSize($size, $referenceSize = 11.0, $dpi = 96.0) {
447453
return $referenceSize * $val;
448454
}
449455

450-
// TODO - vmin
451-
// TODO - vmax
452-
// TODO - vh
453-
// TODO - vw
454-
// TODO - rem
455-
// TODO - ch
456-
// TODO - ex
456+
if ($pos = strpos($size, "rem")) {
457+
$val = floatval(substr($size, 0, $pos));
458+
return $referenceSize * $val;
459+
}
460+
461+
if ($pos = strpos($size, "ex")) {
462+
$val = floatval(substr($size, 0, $pos));
463+
return $referenceSize * $val;
464+
}
465+
466+
if ($pos = strpos($size, "ch")) {
467+
$val = floatval(substr($size, 0, $pos));
468+
return $referenceSize * $val;
469+
}
470+
471+
if ($pos = strpos($size, "vw")) {
472+
$val = floatval(substr($size, 0, $pos));
473+
return $referenceSize * ($val / 100);
474+
}
475+
476+
if ($pos = strpos($size, "vh")) {
477+
$val = floatval(substr($size, 0, $pos));
478+
return $referenceSize * ($val / 100);
479+
}
480+
481+
if ($pos = strpos($size, "vmax")) {
482+
$val = floatval(substr($size, 0, $pos));
483+
return $referenceSize * ($val / 100);
484+
}
457485

458486
return null;
459487
}

src/Svg/Tag/AbstractTag.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,4 +187,64 @@ protected function applyTransform($attributes)
187187
}
188188
}
189189
}
190+
191+
/**
192+
* Convert the given size for the context of this current tag.
193+
* Takes a pixel-based reference, which is usually specific to the context of the size,
194+
* but the actual reference size will be decided based upon the unit used.
195+
*
196+
* @param string $size
197+
* @param float $pxReference
198+
*
199+
* @return float
200+
*/
201+
protected function convertSize(string $size, float $pxReference): float
202+
{
203+
$reference = $pxReference;
204+
$defaultFontSize = 12;
205+
206+
if (strpos($size, "em")) {
207+
$reference = $this->style->fontSize ?? $defaultFontSize;
208+
return Style::convertSize($size, $reference);
209+
}
210+
211+
if (strpos($size, "rem")) {
212+
$reference = $this->document->style->fontSize ?? $defaultFontSize;
213+
return Style::convertSize($size, $reference);
214+
}
215+
216+
if (strpos($size, "ex")) {
217+
$emRef = $this->style->fontSize ?? $defaultFontSize;
218+
$reference = $emRef * 0.5;
219+
return Style::convertSize($size, $reference);
220+
}
221+
222+
if (strpos($size, "ch")) {
223+
$emRef = $this->style->fontSize ?? $defaultFontSize;
224+
$reference = $emRef * 0.5;
225+
return Style::convertSize($size, $reference);
226+
}
227+
228+
if (strpos($size, "vw")) {
229+
$reference = $this->getDocument()->getWidth();
230+
return Style::convertSize($size, $reference);
231+
}
232+
233+
if (strpos($size, "vh")) {
234+
$reference = $this->getDocument()->getHeight();
235+
return Style::convertSize($size, $reference);
236+
}
237+
238+
if (strpos($size, "vmin")) {
239+
$reference = min($this->getDocument()->getHeight(), $this->getDocument()->getWidth());
240+
return Style::convertSize($size, $reference);
241+
}
242+
243+
if (strpos($size, "vmax")) {
244+
$reference = max($this->getDocument()->getHeight(), $this->getDocument()->getWidth());
245+
return Style::convertSize($size, $reference);
246+
}
247+
248+
return Style::convertSize($size, $reference);
249+
}
190250
}

src/Svg/Tag/Circle.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ public function start($attributes)
2020
{
2121
if (isset($attributes['cx'])) {
2222
$width = $this->document->getWidth();
23-
$this->cx = Style::convertSize($attributes['cx'], $width);
23+
$this->cx = $this->convertSize($attributes['cx'], $width);
2424
}
2525
if (isset($attributes['cy'])) {
2626
$height = $this->document->getHeight();
27-
$this->cy = Style::convertSize($attributes['cy'], $height);
27+
$this->cy = $this->convertSize($attributes['cy'], $height);
2828
}
2929
if (isset($attributes['r'])) {
3030
$diagonal = $this->document->getDiagonal();
31-
$this->r = Style::convertSize($attributes['r'], $diagonal);
31+
$this->r = $this->convertSize($attributes['r'], $diagonal);
3232
}
3333

3434
$this->document->getSurface()->circle($this->cx, $this->cy, $this->r);

src/Svg/Tag/Ellipse.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,16 @@ public function start($attributes)
2525
$height = $this->document->getHeight();
2626

2727
if (isset($attributes['cx'])) {
28-
$this->cx = Style::convertSize($attributes['cx'], $width);
28+
$this->cx = $this->convertSize($attributes['cx'], $width);
2929
}
3030
if (isset($attributes['cy'])) {
31-
$this->cy = Style::convertSize($attributes['cy'], $height);
31+
$this->cy = $this->convertSize($attributes['cy'], $height);
3232
}
3333
if (isset($attributes['rx'])) {
34-
$this->rx = Style::convertSize($attributes['rx'], $width);
34+
$this->rx = $this->convertSize($attributes['rx'], $width);
3535
}
3636
if (isset($attributes['ry'])) {
37-
$this->ry = Style::convertSize($attributes['ry'], $height);
37+
$this->ry = $this->convertSize($attributes['ry'], $height);
3838
}
3939

4040
$this->document->getSurface()->ellipse($this->cx, $this->cy, $this->rx, $this->ry, 0, 0, 360, false);

src/Svg/Tag/Image.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,17 @@ public function start($attributes)
3535
$this->y = $height;
3636

3737
if (isset($attributes['x'])) {
38-
$this->x = Style::convertSize($attributes['x'], $width);
38+
$this->x = $this->convertSize($attributes['x'], $width);
3939
}
4040
if (isset($attributes['y'])) {
41-
$this->y = $height - Style::convertSize($attributes['y'], $height);
41+
$this->y = $height - $this->convertSize($attributes['y'], $height);
4242
}
4343

4444
if (isset($attributes['width'])) {
45-
$this->width = Style::convertSize($attributes['width'], $width);
45+
$this->width = $this->convertSize($attributes['width'], $width);
4646
}
4747
if (isset($attributes['height'])) {
48-
$this->height = Style::convertSize($attributes['height'], $height);
48+
$this->height = $this->convertSize($attributes['height'], $height);
4949
}
5050

5151
if (isset($attributes['xlink:href'])) {

src/Svg/Tag/Line.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@ public function start($attributes)
2424
$width = $this->document->getWidth();
2525

2626
if (isset($attributes['x1'])) {
27-
$this->x1 = Style::convertSize($attributes['x1'], $width);
27+
$this->x1 = $this->convertSize($attributes['x1'], $width);
2828
}
2929
if (isset($attributes['y1'])) {
30-
$this->y1 = Style::convertSize($attributes['y1'], $height);
30+
$this->y1 = $this->convertSize($attributes['y1'], $height);
3131
}
3232
if (isset($attributes['x2'])) {
33-
$this->x2 = Style::convertSize($attributes['x2'], $width);
33+
$this->x2 = $this->convertSize($attributes['x2'], $width);
3434
}
3535
if (isset($attributes['y2'])) {
36-
$this->y2 = Style::convertSize($attributes['y2'], $height);
36+
$this->y2 = $this->convertSize($attributes['y2'], $height);
3737
}
3838

3939
$surface = $this->document->getSurface();

src/Svg/Tag/Rect.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ public function start($attributes)
2525
$height = $this->document->getHeight();
2626

2727
if (isset($attributes['x'])) {
28-
$this->x = Style::convertSize($attributes['x'], $width);
28+
$this->x = $this->convertSize($attributes['x'], $width);
2929
}
3030
if (isset($attributes['y'])) {
31-
$this->y = Style::convertSize($attributes['y'], $height);
31+
$this->y = $this->convertSize($attributes['y'], $height);
3232
}
3333

3434
if (isset($attributes['width'])) {
35-
$this->width = Style::convertSize($attributes['width'], $width);
35+
$this->width = $this->convertSize($attributes['width'], $width);
3636
}
3737
if (isset($attributes['height'])) {
38-
$this->height = Style::convertSize($attributes['height'], $width);
38+
$this->height = $this->convertSize($attributes['height'], $width);
3939
}
4040

4141
if (isset($attributes['rx'])) {

src/Svg/Tag/Text.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ public function start($attributes)
2323

2424
if (isset($attributes['x'])) {
2525
$width = $this->document->getWidth();
26-
$this->x = Style::convertSize($attributes['x'], $width);
26+
$this->x = $this->convertSize($attributes['x'], $width);
2727
}
2828
if (isset($attributes['y'])) {
29-
$this->y = $height - Style::convertSize($attributes['y'], $height);
29+
$this->y = $height - $this->convertSize($attributes['y'], $height);
3030
}
3131

3232
$this->document->getSurface()->transform(1, 0, 0, -1, 0, $height);

tests/Svg/StyleTest.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,26 @@ public function test_fromAttributes()
5858

5959
public function test_convertSize()
6060
{
61+
// Absolute lengths
6162
$this->assertEquals(1, Style::convertSize(1));
62-
$this->assertEquals(10, Style::convertSize("10px")); // FIXME
63-
$this->assertEquals(10, Style::convertSize("10pt"));
63+
$this->assertEquals(10, Style::convertSize("10px"));
64+
$this->assertEquals((10 * 96) / 72 , Style::convertSize("10pt"));
65+
$this->assertEquals((10 * 72) / 72 , Style::convertSize("10pt", 11, 72));
6466
$this->assertEquals(8, Style::convertSize("80%", 10, 72));
67+
$this->assertEquals((10 * 96) / 2.54, Style::convertSize("10cm"));
68+
$this->assertEquals((10 * 96) / 25.4, Style::convertSize("10mm"));
69+
$this->assertEquals(10 * 96, Style::convertSize("10in"));
70+
$this->assertEquals((10 * 96) / 6, Style::convertSize("10pc"));
71+
72+
// Relative lengths
73+
$this->assertEquals(200, Style::convertSize("10em", 20));
74+
$this->assertEquals(200, Style::convertSize("10ex", 20));
75+
$this->assertEquals(200, Style::convertSize("10ch", 20));
76+
$this->assertEquals(200, Style::convertSize("10rem", 20));
77+
$this->assertEquals(2, Style::convertSize("10vw", 20));
78+
$this->assertEquals(2, Style::convertSize("10vh", 20));
79+
$this->assertEquals(2, Style::convertSize("10vmin", 20));
80+
$this->assertEquals(2, Style::convertSize("10vmax", 20));
6581
}
6682

6783
}

0 commit comments

Comments
 (0)