| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  | /*
 | 
					
						
							|  |  |  |  |  * Copyright (c) 2023, MacDue <macdue@dueutil.tech> | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include <LibWeb/Bindings/Intrinsics.h>
 | 
					
						
							|  |  |  |  | #include <LibWeb/DOM/Document.h>
 | 
					
						
							|  |  |  |  | #include <LibWeb/SVG/AttributeNames.h>
 | 
					
						
							|  |  |  |  | #include <LibWeb/SVG/AttributeParser.h>
 | 
					
						
							|  |  |  |  | #include <LibWeb/SVG/SVGLinearGradientElement.h>
 | 
					
						
							|  |  |  |  | #include <LibWeb/SVG/SVGStopElement.h>
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | namespace Web::SVG { | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | SVGLinearGradientElement::SVGLinearGradientElement(DOM::Document& document, DOM::QualifiedName qualified_name) | 
					
						
							|  |  |  |  |     : SVGGradientElement(document, qualified_name) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-07 08:41:28 +02:00
										 |  |  |  | void SVGLinearGradientElement::initialize(JS::Realm& realm) | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-08-07 08:41:28 +02:00
										 |  |  |  |     Base::initialize(realm); | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  |     set_prototype(&Bindings::ensure_web_prototype<Bindings::SVGLinearGradientElementPrototype>(realm, "SVGLinearGradientElement")); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-10 15:00:58 +03:30
										 |  |  |  | void SVGLinearGradientElement::attribute_changed(FlyString const& name, Optional<DeprecatedString> const& value) | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-03 17:08:37 +02:00
										 |  |  |  |     SVGGradientElement::attribute_changed(name, value); | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     // FIXME: Should allow for `<number-percentage> | <length>` for x1, x2, y1, y2
 | 
					
						
							|  |  |  |  |     if (name == SVG::AttributeNames::x1) { | 
					
						
							| 
									
										
										
										
											2023-10-10 15:00:58 +03:30
										 |  |  |  |         m_x1 = AttributeParser::parse_number_percentage(value.value_or("")); | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  |         m_paint_style = nullptr; | 
					
						
							|  |  |  |  |     } else if (name == SVG::AttributeNames::y1) { | 
					
						
							| 
									
										
										
										
											2023-10-10 15:00:58 +03:30
										 |  |  |  |         m_y1 = AttributeParser::parse_number_percentage(value.value_or("")); | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  |         m_paint_style = nullptr; | 
					
						
							|  |  |  |  |     } else if (name == SVG::AttributeNames::x2) { | 
					
						
							| 
									
										
										
										
											2023-10-10 15:00:58 +03:30
										 |  |  |  |         m_x2 = AttributeParser::parse_number_percentage(value.value_or("")); | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  |         m_paint_style = nullptr; | 
					
						
							|  |  |  |  |     } else if (name == SVG::AttributeNames::y2) { | 
					
						
							| 
									
										
										
										
											2023-10-10 15:00:58 +03:30
										 |  |  |  |         m_y2 = AttributeParser::parse_number_percentage(value.value_or("")); | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  |         m_paint_style = nullptr; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementX1Attribute
 | 
					
						
							|  |  |  |  | NumberPercentage SVGLinearGradientElement::start_x() const | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     if (m_x1.has_value()) | 
					
						
							|  |  |  |  |         return *m_x1; | 
					
						
							| 
									
										
										
										
											2023-07-30 13:50:16 +01:00
										 |  |  |  |     if (auto gradient = linked_linear_gradient()) | 
					
						
							|  |  |  |  |         return gradient->start_x(); | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  |     // If the attribute is not specified, the effect is as if a value of '0%' were specified.
 | 
					
						
							|  |  |  |  |     return NumberPercentage::create_percentage(0); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementY1Attribute
 | 
					
						
							|  |  |  |  | NumberPercentage SVGLinearGradientElement::start_y() const | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     if (m_y1.has_value()) | 
					
						
							|  |  |  |  |         return *m_y1; | 
					
						
							| 
									
										
										
										
											2023-07-30 13:50:16 +01:00
										 |  |  |  |     if (auto gradient = linked_linear_gradient()) | 
					
						
							|  |  |  |  |         return gradient->start_x(); | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  |     // If the attribute is not specified, the effect is as if a value of '0%' were specified.
 | 
					
						
							|  |  |  |  |     return NumberPercentage::create_percentage(0); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementX2Attribute
 | 
					
						
							|  |  |  |  | NumberPercentage SVGLinearGradientElement::end_x() const | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     if (m_x2.has_value()) | 
					
						
							|  |  |  |  |         return *m_x2; | 
					
						
							| 
									
										
										
										
											2023-07-30 13:50:16 +01:00
										 |  |  |  |     if (auto gradient = linked_linear_gradient()) | 
					
						
							|  |  |  |  |         return gradient->start_x(); | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  |     // If the attribute is not specified, the effect is as if a value of '100%' were specified.
 | 
					
						
							|  |  |  |  |     return NumberPercentage::create_percentage(100); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementY2Attribute
 | 
					
						
							|  |  |  |  | NumberPercentage SVGLinearGradientElement::end_y() const | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     if (m_y2.has_value()) | 
					
						
							|  |  |  |  |         return *m_y2; | 
					
						
							| 
									
										
										
										
											2023-07-30 13:50:16 +01:00
										 |  |  |  |     if (auto gradient = linked_linear_gradient()) | 
					
						
							|  |  |  |  |         return gradient->start_x(); | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  |     // If the attribute is not specified, the effect is as if a value of '0%' were specified.
 | 
					
						
							|  |  |  |  |     return NumberPercentage::create_percentage(0); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | Optional<Gfx::PaintStyle const&> SVGLinearGradientElement::to_gfx_paint_style(SVGPaintContext const& paint_context) const | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     auto units = gradient_units(); | 
					
						
							|  |  |  |  |     // FIXME: Resolve percentages properly
 | 
					
						
							|  |  |  |  |     Gfx::FloatPoint start_point {}; | 
					
						
							|  |  |  |  |     Gfx::FloatPoint end_point {}; | 
					
						
							|  |  |  |  |     // https://svgwg.org/svg2-draft/pservers.html#LinearGradientElementGradientUnitsAttribute
 | 
					
						
							|  |  |  |  |     if (units == GradientUnits::ObjectBoundingBox) { | 
					
						
							|  |  |  |  |         // If gradientUnits="objectBoundingBox", the user coordinate system for attributes ‘x1’, ‘y1’, ‘x2’ and ‘y2’
 | 
					
						
							|  |  |  |  |         // is established using the bounding box of the element to which the gradient is applied (see Object bounding
 | 
					
						
							|  |  |  |  |         // box units) and then applying the transform specified by attribute ‘gradientTransform’. Percentages represent
 | 
					
						
							|  |  |  |  |         // values relative to the bounding box for the object.
 | 
					
						
							|  |  |  |  |         // Note: For gradientUnits="objectBoundingBox" both "100%" and "1" are treated the same.
 | 
					
						
							| 
									
										
										
										
											2023-05-02 23:05:47 +01:00
										 |  |  |  |         start_point = { start_x().value(), start_y().value() }; | 
					
						
							|  |  |  |  |         end_point = { end_x().value(), end_y().value() }; | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  |     } else { | 
					
						
							|  |  |  |  |         // GradientUnits::UserSpaceOnUse
 | 
					
						
							|  |  |  |  |         // If gradientUnits="userSpaceOnUse", ‘x1’, ‘y1’, ‘x2’, and ‘y2’ represent values in the coordinate system
 | 
					
						
							|  |  |  |  |         // that results from taking the current user coordinate system in place at the time when the gradient element
 | 
					
						
							|  |  |  |  |         // is referenced (i.e., the user coordinate system for the element referencing the gradient element via a
 | 
					
						
							|  |  |  |  |         // fill or stroke property) and then applying the transform specified by attribute ‘gradientTransform’.
 | 
					
						
							|  |  |  |  |         // Percentages represent values relative to the current SVG viewport.
 | 
					
						
							|  |  |  |  |         start_point = Gfx::FloatPoint { | 
					
						
							|  |  |  |  |             start_x().resolve_relative_to(paint_context.viewport.width()), | 
					
						
							|  |  |  |  |             start_y().resolve_relative_to(paint_context.viewport.height()), | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  |         end_point = Gfx::FloatPoint { | 
					
						
							|  |  |  |  |             end_x().resolve_relative_to(paint_context.viewport.width()), | 
					
						
							|  |  |  |  |             end_y().resolve_relative_to(paint_context.viewport.height()), | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (!m_paint_style) { | 
					
						
							|  |  |  |  |         m_paint_style = Gfx::SVGLinearGradientPaintStyle::create(start_point, end_point) | 
					
						
							|  |  |  |  |                             .release_value_but_fixme_should_propagate_errors(); | 
					
						
							| 
									
										
										
										
											2023-05-02 23:05:47 +01:00
										 |  |  |  |         // FIXME: Update stops in DOM changes:
 | 
					
						
							|  |  |  |  |         add_color_stops(*m_paint_style); | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  |     } else { | 
					
						
							|  |  |  |  |         m_paint_style->set_start_point(start_point); | 
					
						
							|  |  |  |  |         m_paint_style->set_end_point(end_point); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-02 23:05:47 +01:00
										 |  |  |  |     m_paint_style->set_gradient_transform(gradient_paint_transform(paint_context)); | 
					
						
							| 
									
										
										
										
											2023-08-20 15:45:02 +01:00
										 |  |  |  |     m_paint_style->set_spread_method(to_gfx_spread_method(spread_method())); | 
					
						
							| 
									
										
										
										
											2023-04-22 18:51:00 +01:00
										 |  |  |  |     return *m_paint_style; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | JS::NonnullGCPtr<SVGAnimatedLength> SVGLinearGradientElement::x1() const | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     TODO(); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | JS::NonnullGCPtr<SVGAnimatedLength> SVGLinearGradientElement::y1() const | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     TODO(); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | JS::NonnullGCPtr<SVGAnimatedLength> SVGLinearGradientElement::x2() const | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     TODO(); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | JS::NonnullGCPtr<SVGAnimatedLength> SVGLinearGradientElement::y2() const | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     TODO(); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | } |