Serenity Operating System
1/*
2 * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <LibWeb/Bindings/Intrinsics.h>
8#include <LibWeb/SVG/AttributeNames.h>
9#include <LibWeb/SVG/AttributeParser.h>
10#include <LibWeb/SVG/SVGCircleElement.h>
11
12namespace Web::SVG {
13
14SVGCircleElement::SVGCircleElement(DOM::Document& document, DOM::QualifiedName qualified_name)
15 : SVGGeometryElement(document, qualified_name)
16{
17}
18
19JS::ThrowCompletionOr<void> SVGCircleElement::initialize(JS::Realm& realm)
20{
21 MUST_OR_THROW_OOM(Base::initialize(realm));
22 set_prototype(&Bindings::ensure_web_prototype<Bindings::SVGCircleElementPrototype>(realm, "SVGCircleElement"));
23
24 return {};
25}
26
27void SVGCircleElement::parse_attribute(DeprecatedFlyString const& name, DeprecatedString const& value)
28{
29 SVGGeometryElement::parse_attribute(name, value);
30
31 if (name == SVG::AttributeNames::cx) {
32 m_center_x = AttributeParser::parse_coordinate(value);
33 m_path.clear();
34 } else if (name == SVG::AttributeNames::cy) {
35 m_center_y = AttributeParser::parse_coordinate(value);
36 m_path.clear();
37 } else if (name == SVG::AttributeNames::r) {
38 m_radius = AttributeParser::parse_positive_length(value);
39 m_path.clear();
40 }
41}
42
43Gfx::Path& SVGCircleElement::get_path()
44{
45 if (m_path.has_value())
46 return m_path.value();
47
48 float cx = m_center_x.value_or(0);
49 float cy = m_center_y.value_or(0);
50 float r = m_radius.value_or(0);
51
52 Gfx::Path path;
53
54 // A zero radius disables rendering.
55 if (r == 0) {
56 m_path = move(path);
57 return m_path.value();
58 }
59
60 bool large_arc = false;
61 bool sweep = true;
62
63 // 1. A move-to command to the point cx+r,cy;
64 path.move_to({ cx + r, cy });
65
66 // 2. arc to cx,cy+r;
67 path.arc_to({ cx, cy + r }, r, large_arc, sweep);
68
69 // 3. arc to cx-r,cy;
70 path.arc_to({ cx - r, cy }, r, large_arc, sweep);
71
72 // 4. arc to cx,cy-r;
73 path.arc_to({ cx, cy - r }, r, large_arc, sweep);
74
75 // 5. arc with a segment-completing close path operation.
76 path.arc_to({ cx + r, cy }, r, large_arc, sweep);
77
78 m_path = move(path);
79 return m_path.value();
80}
81
82// https://www.w3.org/TR/SVG11/shapes.html#CircleElementCXAttribute
83JS::NonnullGCPtr<SVGAnimatedLength> SVGCircleElement::cx() const
84{
85 // FIXME: Populate the unit type when it is parsed (0 here is "unknown").
86 // FIXME: Create a proper animated value when animations are supported.
87 auto base_length = SVGLength::create(realm(), 0, m_center_x.value_or(0)).release_value_but_fixme_should_propagate_errors();
88 auto anim_length = SVGLength::create(realm(), 0, m_center_x.value_or(0)).release_value_but_fixme_should_propagate_errors();
89 return SVGAnimatedLength::create(realm(), move(base_length), move(anim_length)).release_value_but_fixme_should_propagate_errors();
90}
91
92// https://www.w3.org/TR/SVG11/shapes.html#CircleElementCYAttribute
93JS::NonnullGCPtr<SVGAnimatedLength> SVGCircleElement::cy() const
94{
95 // FIXME: Populate the unit type when it is parsed (0 here is "unknown").
96 // FIXME: Create a proper animated value when animations are supported.
97 auto base_length = SVGLength::create(realm(), 0, m_center_y.value_or(0)).release_value_but_fixme_should_propagate_errors();
98 auto anim_length = SVGLength::create(realm(), 0, m_center_y.value_or(0)).release_value_but_fixme_should_propagate_errors();
99 return SVGAnimatedLength::create(realm(), move(base_length), move(anim_length)).release_value_but_fixme_should_propagate_errors();
100}
101
102// https://www.w3.org/TR/SVG11/shapes.html#CircleElementRAttribute
103JS::NonnullGCPtr<SVGAnimatedLength> SVGCircleElement::r() const
104{
105 // FIXME: Populate the unit type when it is parsed (0 here is "unknown").
106 // FIXME: Create a proper animated value when animations are supported.
107 auto base_length = SVGLength::create(realm(), 0, m_radius.value_or(0)).release_value_but_fixme_should_propagate_errors();
108 auto anim_length = SVGLength::create(realm(), 0, m_radius.value_or(0)).release_value_but_fixme_should_propagate_errors();
109 return SVGAnimatedLength::create(realm(), move(base_length), move(anim_length)).release_value_but_fixme_should_propagate_errors();
110}
111
112}