/src/serenity/Userland/Libraries/LibWeb/SVG/SVGEllipseElement.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <LibWeb/Bindings/SVGEllipseElementPrototype.h> |
8 | | #include <LibWeb/HTML/Window.h> |
9 | | #include <LibWeb/SVG/AttributeNames.h> |
10 | | #include <LibWeb/SVG/AttributeParser.h> |
11 | | #include <LibWeb/SVG/SVGEllipseElement.h> |
12 | | |
13 | | namespace Web::SVG { |
14 | | |
15 | | JS_DEFINE_ALLOCATOR(SVGEllipseElement); |
16 | | |
17 | | SVGEllipseElement::SVGEllipseElement(DOM::Document& document, DOM::QualifiedName qualified_name) |
18 | 0 | : SVGGeometryElement(document, qualified_name) |
19 | 0 | { |
20 | 0 | } |
21 | | |
22 | | void SVGEllipseElement::initialize(JS::Realm& realm) |
23 | 0 | { |
24 | 0 | Base::initialize(realm); |
25 | 0 | WEB_SET_PROTOTYPE_FOR_INTERFACE(SVGEllipseElement); |
26 | 0 | } |
27 | | |
28 | | void SVGEllipseElement::attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value) |
29 | 0 | { |
30 | 0 | SVGGeometryElement::attribute_changed(name, old_value, value); |
31 | |
|
32 | 0 | if (name == SVG::AttributeNames::cx) { |
33 | 0 | m_center_x = AttributeParser::parse_coordinate(value.value_or(String {})); |
34 | 0 | } else if (name == SVG::AttributeNames::cy) { |
35 | 0 | m_center_y = AttributeParser::parse_coordinate(value.value_or(String {})); |
36 | 0 | } else if (name == SVG::AttributeNames::rx) { |
37 | 0 | m_radius_x = AttributeParser::parse_positive_length(value.value_or(String {})); |
38 | 0 | } else if (name == SVG::AttributeNames::ry) { |
39 | 0 | m_radius_y = AttributeParser::parse_positive_length(value.value_or(String {})); |
40 | 0 | } |
41 | 0 | } |
42 | | |
43 | | Gfx::Path SVGEllipseElement::get_path(CSSPixelSize) |
44 | 0 | { |
45 | 0 | float rx = m_radius_x.value_or(0); |
46 | 0 | float ry = m_radius_y.value_or(0); |
47 | 0 | float cx = m_center_x.value_or(0); |
48 | 0 | float cy = m_center_y.value_or(0); |
49 | 0 | Gfx::Path path; |
50 | | |
51 | | // A computed value of zero for either dimension, or a computed value of auto for both dimensions, disables rendering of the element. |
52 | 0 | if (rx == 0 || ry == 0) |
53 | 0 | return path; |
54 | | |
55 | 0 | Gfx::FloatSize radii = { rx, ry }; |
56 | 0 | double x_axis_rotation = 0; |
57 | 0 | bool large_arc = false; |
58 | 0 | bool sweep = true; // Note: Spec says it should be false, but it's wrong. https://github.com/w3c/svgwg/issues/765 |
59 | | |
60 | | // 1. A move-to command to the point cx+rx,cy; |
61 | 0 | path.move_to({ cx + rx, cy }); |
62 | | |
63 | | // 2. arc to cx,cy+ry; |
64 | 0 | path.elliptical_arc_to({ cx, cy + ry }, radii, x_axis_rotation, large_arc, sweep); |
65 | | |
66 | | // 3. arc to cx-rx,cy; |
67 | 0 | path.elliptical_arc_to({ cx - rx, cy }, radii, x_axis_rotation, large_arc, sweep); |
68 | | |
69 | | // 4. arc to cx,cy-ry; |
70 | 0 | path.elliptical_arc_to({ cx, cy - ry }, radii, x_axis_rotation, large_arc, sweep); |
71 | | |
72 | | // 5. arc with a segment-completing close path operation. |
73 | 0 | path.elliptical_arc_to({ cx + rx, cy }, radii, x_axis_rotation, large_arc, sweep); |
74 | |
|
75 | 0 | return path; |
76 | 0 | } |
77 | | |
78 | | // https://www.w3.org/TR/SVG11/shapes.html#EllipseElementCXAttribute |
79 | | JS::NonnullGCPtr<SVGAnimatedLength> SVGEllipseElement::cx() const |
80 | 0 | { |
81 | | // FIXME: Populate the unit type when it is parsed (0 here is "unknown"). |
82 | | // FIXME: Create a proper animated value when animations are supported. |
83 | 0 | auto base_length = SVGLength::create(realm(), 0, m_center_x.value_or(0)); |
84 | 0 | auto anim_length = SVGLength::create(realm(), 0, m_center_x.value_or(0)); |
85 | 0 | return SVGAnimatedLength::create(realm(), move(base_length), move(anim_length)); |
86 | 0 | } |
87 | | |
88 | | // https://www.w3.org/TR/SVG11/shapes.html#EllipseElementCYAttribute |
89 | | JS::NonnullGCPtr<SVGAnimatedLength> SVGEllipseElement::cy() const |
90 | 0 | { |
91 | | // FIXME: Populate the unit type when it is parsed (0 here is "unknown"). |
92 | | // FIXME: Create a proper animated value when animations are supported. |
93 | 0 | auto base_length = SVGLength::create(realm(), 0, m_center_y.value_or(0)); |
94 | 0 | auto anim_length = SVGLength::create(realm(), 0, m_center_y.value_or(0)); |
95 | 0 | return SVGAnimatedLength::create(realm(), move(base_length), move(anim_length)); |
96 | 0 | } |
97 | | |
98 | | // https://www.w3.org/TR/SVG11/shapes.html#EllipseElementRXAttribute |
99 | | JS::NonnullGCPtr<SVGAnimatedLength> SVGEllipseElement::rx() const |
100 | 0 | { |
101 | | // FIXME: Populate the unit type when it is parsed (0 here is "unknown"). |
102 | | // FIXME: Create a proper animated value when animations are supported. |
103 | 0 | auto base_length = SVGLength::create(realm(), 0, m_radius_x.value_or(0)); |
104 | 0 | auto anim_length = SVGLength::create(realm(), 0, m_radius_x.value_or(0)); |
105 | 0 | return SVGAnimatedLength::create(realm(), move(base_length), move(anim_length)); |
106 | 0 | } |
107 | | |
108 | | // https://www.w3.org/TR/SVG11/shapes.html#EllipseElementRYAttribute |
109 | | JS::NonnullGCPtr<SVGAnimatedLength> SVGEllipseElement::ry() const |
110 | 0 | { |
111 | | // FIXME: Populate the unit type when it is parsed (0 here is "unknown"). |
112 | | // FIXME: Create a proper animated value when animations are supported. |
113 | 0 | auto base_length = SVGLength::create(realm(), 0, m_radius_y.value_or(0)); |
114 | 0 | auto anim_length = SVGLength::create(realm(), 0, m_radius_y.value_or(0)); |
115 | 0 | return SVGAnimatedLength::create(realm(), move(base_length), move(anim_length)); |
116 | 0 | } |
117 | | |
118 | | } |