Browse Source

LibWeb: Support percentage values in SVG text positioning element

Edwin Hoksberg 1 year ago
parent
commit
356bddbdbb

+ 29 - 0
Tests/LibWeb/Layout/expected/svg-text-with-percentage-values.txt

@@ -0,0 +1,29 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+  BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
+    BlockContainer <body> at (8,8) content-size 784x261.328125 children: inline
+      frag 0 from SVGSVGBox start: 0, length: 0, rect: [8,8 784x261.328125] baseline: 261.328125
+      SVGSVGBox <svg> at (8,8) content-size 784x261.328125 [SVG] children: inline
+        TextNode <#text>
+        TextNode <#text>
+        SVGTextBox <text.small> at (86.40625,65.5) content-size 48.109375x37.484375 children: inline
+          TextNode <#text>
+        TextNode <#text>
+        SVGTextBox <text.heavy> at (141.28125,21.078125) content-size 148.234375x79.71875 children: inline
+          TextNode <#text>
+        TextNode <#text>
+        SVGTextBox <text.small> at (204,117.765625) content-size 34.59375x34.703125 children: inline
+          TextNode <#text>
+        TextNode <#text>
+        SVGTextBox <text.Rrrrr> at (243.1875,47.21875) content-size 519.34375x115.359375 children: inline
+          TextNode <#text>
+        TextNode <#text>
+      TextNode <#text>
+
+ViewportPaintable (Viewport<#document>) [0,0 800x600]
+  PaintableWithLines (BlockContainer<HTML>) [0,0 800x600]
+    PaintableWithLines (BlockContainer<BODY>) [8,8 784x261.328125]
+      SVGSVGPaintable (SVGSVGBox<svg>) [8,8 784x261.328125]
+        SVGPathPaintable (SVGTextBox<text>.small) [86.40625,65.5 48.109375x37.484375]
+        SVGPathPaintable (SVGTextBox<text>.heavy) [141.28125,21.078125 148.234375x79.71875]
+        SVGPathPaintable (SVGTextBox<text>.small) [204,117.765625 34.59375x34.703125]
+        SVGPathPaintable (SVGTextBox<text>.Rrrrr) [243.1875,47.21875 519.34375x115.359375]

+ 20 - 0
Tests/LibWeb/Layout/input/svg-text-with-percentage-values.html

@@ -0,0 +1,20 @@
+<svg viewBox="0 0 240 80" xmlns="http://www.w3.org/2000/svg">
+  <style>
+    .small {
+      font: italic 13px sans-serif;
+    }
+    .heavy {
+      font: bold 30px sans-serif;
+    }
+
+    .Rrrrr {
+      font: italic 40px serif;
+      fill: red;
+    }
+  </style>
+
+  <text x="10%" y="35%" class="small">My</text>
+  <text x="17%" y="35%" class="heavy">cat</text>
+  <text x="25%" y="55%" class="small">is</text>
+  <text x="30%" y="55%" class="Rrrrr">Grumpy!</text>
+</svg>

+ 1 - 1
Userland/Libraries/LibWeb/Layout/SVGFormattingContext.cpp

@@ -308,7 +308,7 @@ Gfx::Path SVGFormattingContext::compute_path_for_text(SVGTextBox const& text_box
     auto text_contents = text_element.text_contents();
     auto text_contents = text_element.text_contents();
     Utf8View text_utf8 { text_contents };
     Utf8View text_utf8 { text_contents };
     auto text_width = font.width(text_utf8);
     auto text_width = font.width(text_utf8);
-    auto text_offset = text_element.get_offset();
+    auto text_offset = text_element.get_offset(m_viewport_size);
 
 
     // https://svgwg.org/svg2-draft/text.html#TextAnchoringProperties
     // https://svgwg.org/svg2-draft/text.html#TextAnchoringProperties
     switch (text_element.text_anchor().value_or(SVG::TextAnchor::Start)) {
     switch (text_element.text_anchor().value_or(SVG::TextAnchor::Start)) {

+ 14 - 6
Userland/Libraries/LibWeb/SVG/SVGTextPositioningElement.cpp

@@ -34,19 +34,27 @@ void SVGTextPositioningElement::attribute_changed(FlyString const& name, Optiona
     SVGGraphicsElement::attribute_changed(name, old_value, value);
     SVGGraphicsElement::attribute_changed(name, old_value, value);
 
 
     if (name == SVG::AttributeNames::x) {
     if (name == SVG::AttributeNames::x) {
-        m_x = AttributeParser::parse_coordinate(value.value_or(String {})).value_or(m_x);
+        m_x = AttributeParser::parse_number_percentage(value.value_or(String {}));
     } else if (name == SVG::AttributeNames::y) {
     } else if (name == SVG::AttributeNames::y) {
-        m_y = AttributeParser::parse_coordinate(value.value_or(String {})).value_or(m_y);
+        m_y = AttributeParser::parse_number_percentage(value.value_or(String {}));
     } else if (name == SVG::AttributeNames::dx) {
     } else if (name == SVG::AttributeNames::dx) {
-        m_dx = AttributeParser::parse_coordinate(value.value_or(String {})).value_or(m_dx);
+        m_dx = AttributeParser::parse_number_percentage(value.value_or(String {}));
     } else if (name == SVG::AttributeNames::dy) {
     } else if (name == SVG::AttributeNames::dy) {
-        m_dy = AttributeParser::parse_coordinate(value.value_or(String {})).value_or(m_dy);
+        m_dy = AttributeParser::parse_number_percentage(value.value_or(String {}));
     }
     }
 }
 }
 
 
-Gfx::FloatPoint SVGTextPositioningElement::get_offset() const
+Gfx::FloatPoint SVGTextPositioningElement::get_offset(CSSPixelSize const& viewport_size) const
 {
 {
-    return { m_x + m_dx, m_y + m_dy };
+    auto const viewport_width = viewport_size.width().to_float();
+    auto const viewport_height = viewport_size.height().to_float();
+
+    float const x = m_x.value_or({ 0, false }).resolve_relative_to(viewport_width);
+    float const y = m_y.value_or({ 0, false }).resolve_relative_to(viewport_height);
+    float const dx = m_dx.value_or({ 0, false }).resolve_relative_to(viewport_width);
+    float const dy = m_dy.value_or({ 0, false }).resolve_relative_to(viewport_height);
+
+    return { x + dx, y + dy };
 }
 }
 
 
 }
 }

+ 5 - 5
Userland/Libraries/LibWeb/SVG/SVGTextPositioningElement.h

@@ -18,7 +18,7 @@ class SVGTextPositioningElement : public SVGTextContentElement {
 public:
 public:
     virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value) override;
     virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value) override;
 
 
-    Gfx::FloatPoint get_offset() const;
+    Gfx::FloatPoint get_offset(CSSPixelSize const& viewport_size) const;
 
 
     JS::NonnullGCPtr<SVGAnimatedLength> x() const;
     JS::NonnullGCPtr<SVGAnimatedLength> x() const;
     JS::NonnullGCPtr<SVGAnimatedLength> y() const;
     JS::NonnullGCPtr<SVGAnimatedLength> y() const;
@@ -31,10 +31,10 @@ protected:
     virtual void initialize(JS::Realm&) override;
     virtual void initialize(JS::Realm&) override;
 
 
 private:
 private:
-    float m_x { 0 };
-    float m_y { 0 };
-    float m_dx { 0 };
-    float m_dy { 0 };
+    Optional<NumberPercentage> m_x;
+    Optional<NumberPercentage> m_y;
+    Optional<NumberPercentage> m_dx;
+    Optional<NumberPercentage> m_dy;
 };
 };
 
 
 }
 }