mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:47:34 +00:00
LibWeb: Implement SVGGradientElement
This is the base class for all SVG gradient types. This supports: - The `gradientUnits` attribute - The `gradientTransform` attribute - And following `xlink:hrefs` for inheriting <stops>/attributes
This commit is contained in:
parent
a5fa5e55ef
commit
71938550fa
7 changed files with 175 additions and 0 deletions
|
@ -495,6 +495,7 @@ set(SOURCES
|
||||||
SVG/SVGGElement.cpp
|
SVG/SVGGElement.cpp
|
||||||
SVG/SVGGeometryElement.cpp
|
SVG/SVGGeometryElement.cpp
|
||||||
SVG/SVGGraphicsElement.cpp
|
SVG/SVGGraphicsElement.cpp
|
||||||
|
SVG/SVGGradientElement.cpp
|
||||||
SVG/SVGPathElement.cpp
|
SVG/SVGPathElement.cpp
|
||||||
SVG/SVGCircleElement.cpp
|
SVG/SVGCircleElement.cpp
|
||||||
SVG/SVGEllipseElement.cpp
|
SVG/SVGEllipseElement.cpp
|
||||||
|
|
|
@ -494,6 +494,19 @@ Optional<PreserveAspectRatio> AttributeParser::parse_preserve_aspect_ratio(Strin
|
||||||
return PreserveAspectRatio { *align, *meet_or_slice };
|
return PreserveAspectRatio { *align, *meet_or_slice };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://svgwg.org/svg2-draft/pservers.html#LinearGradientElementGradientUnitsAttribute
|
||||||
|
Optional<GradientUnits> AttributeParser::parse_gradient_units(StringView input)
|
||||||
|
{
|
||||||
|
GenericLexer lexer { input };
|
||||||
|
lexer.ignore_while(whitespace);
|
||||||
|
auto gradient_units_string = lexer.consume_until(whitespace);
|
||||||
|
if (gradient_units_string == "userSpaceOnUse"sv)
|
||||||
|
return GradientUnits::UserSpaceOnUse;
|
||||||
|
if (gradient_units_string == "objectBoundingBox"sv)
|
||||||
|
return GradientUnits::ObjectBoundingBox;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-transforms/#svg-syntax
|
// https://drafts.csswg.org/css-transforms/#svg-syntax
|
||||||
Optional<Vector<Transform>> AttributeParser::parse_transform()
|
Optional<Vector<Transform>> AttributeParser::parse_transform()
|
||||||
{
|
{
|
||||||
|
|
|
@ -88,6 +88,11 @@ struct PreserveAspectRatio {
|
||||||
MeetOrSlice meet_or_slice { MeetOrSlice::Meet };
|
MeetOrSlice meet_or_slice { MeetOrSlice::Meet };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GradientUnits {
|
||||||
|
ObjectBoundingBox,
|
||||||
|
UserSpaceOnUse
|
||||||
|
};
|
||||||
|
|
||||||
class NumberPercentage {
|
class NumberPercentage {
|
||||||
public:
|
public:
|
||||||
NumberPercentage(float value, bool is_percentage)
|
NumberPercentage(float value, bool is_percentage)
|
||||||
|
@ -127,6 +132,7 @@ public:
|
||||||
static Vector<PathInstruction> parse_path_data(StringView input);
|
static Vector<PathInstruction> parse_path_data(StringView input);
|
||||||
static Optional<Vector<Transform>> parse_transform(StringView input);
|
static Optional<Vector<Transform>> parse_transform(StringView input);
|
||||||
static Optional<PreserveAspectRatio> parse_preserve_aspect_ratio(StringView input);
|
static Optional<PreserveAspectRatio> parse_preserve_aspect_ratio(StringView input);
|
||||||
|
static Optional<GradientUnits> parse_gradient_units(StringView input);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AttributeParser(StringView source);
|
AttributeParser(StringView source);
|
||||||
|
|
78
Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp
Normal file
78
Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* 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/SVGGradientElement.h>
|
||||||
|
#include <LibWeb/SVG/SVGGraphicsElement.h>
|
||||||
|
|
||||||
|
namespace Web::SVG {
|
||||||
|
|
||||||
|
SVGGradientElement::SVGGradientElement(DOM::Document& document, DOM::QualifiedName qualified_name)
|
||||||
|
: SVGElement(document, move(qualified_name))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SVGGradientElement::parse_attribute(DeprecatedFlyString const& name, DeprecatedString const& value)
|
||||||
|
{
|
||||||
|
SVGElement::parse_attribute(name, value);
|
||||||
|
if (name == AttributeNames::gradientUnits) {
|
||||||
|
m_gradient_units = AttributeParser::parse_gradient_units(value);
|
||||||
|
} else if (name == AttributeNames::gradientTransform) {
|
||||||
|
if (auto transform_list = AttributeParser::parse_transform(value); transform_list.has_value()) {
|
||||||
|
m_gradient_transform = transform_from_transform_list(*transform_list);
|
||||||
|
} else {
|
||||||
|
m_gradient_transform = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientUnits SVGGradientElement::gradient_units() const
|
||||||
|
{
|
||||||
|
if (m_gradient_units.has_value())
|
||||||
|
return *m_gradient_units;
|
||||||
|
if (auto href = xlink_href())
|
||||||
|
return href->gradient_units();
|
||||||
|
return GradientUnits::ObjectBoundingBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Gfx::AffineTransform> SVGGradientElement::gradient_transform() const
|
||||||
|
{
|
||||||
|
if (m_gradient_transform.has_value())
|
||||||
|
return m_gradient_transform;
|
||||||
|
if (auto href = xlink_href())
|
||||||
|
return href->gradient_transform();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::GCPtr<SVGGradientElement const> SVGGradientElement::xlink_href() const
|
||||||
|
{
|
||||||
|
// FIXME: This entire function is an ad-hoc hack!
|
||||||
|
// It can only resolve #<ids> in the same document.
|
||||||
|
if (auto href = get_attribute("href"); !href.is_empty()) {
|
||||||
|
auto url = document().parse_url(href);
|
||||||
|
auto id = url.fragment();
|
||||||
|
if (id.is_empty())
|
||||||
|
return {};
|
||||||
|
auto element = document().get_element_by_id(id);
|
||||||
|
if (!element)
|
||||||
|
return {};
|
||||||
|
if (!is<SVGGradientElement>(*element))
|
||||||
|
return {};
|
||||||
|
return &verify_cast<SVGGradientElement>(*element);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::ThrowCompletionOr<void> SVGGradientElement::initialize(JS::Realm& realm)
|
||||||
|
{
|
||||||
|
MUST_OR_THROW_OOM(Base::initialize(realm));
|
||||||
|
set_prototype(&Bindings::ensure_web_prototype<Bindings::SVGGradientElementPrototype>(realm, "SVGGradientElement"));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
59
Userland/Libraries/LibWeb/SVG/SVGGradientElement.h
Normal file
59
Userland/Libraries/LibWeb/SVG/SVGGradientElement.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, MacDue <macdue@dueutil.tech>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/IterationDecision.h>
|
||||||
|
#include <LibGfx/PaintStyle.h>
|
||||||
|
#include <LibWeb/SVG/AttributeParser.h>
|
||||||
|
#include <LibWeb/SVG/SVGElement.h>
|
||||||
|
#include <LibWeb/SVG/SVGStopElement.h>
|
||||||
|
|
||||||
|
namespace Web::SVG {
|
||||||
|
|
||||||
|
struct SVGPaintContext {
|
||||||
|
Gfx::FloatRect viewport;
|
||||||
|
Gfx::FloatRect path_bounding_box;
|
||||||
|
Gfx::AffineTransform transform;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SVGGradientElement : public SVGElement {
|
||||||
|
WEB_PLATFORM_OBJECT(SVGGradientElement, SVGElement);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~SVGGradientElement() override = default;
|
||||||
|
|
||||||
|
virtual void parse_attribute(DeprecatedFlyString const& name, DeprecatedString const& value) override;
|
||||||
|
|
||||||
|
virtual Optional<Gfx::PaintStyle const&> to_gfx_paint_style(SVGPaintContext const&) const = 0;
|
||||||
|
|
||||||
|
GradientUnits gradient_units() const;
|
||||||
|
|
||||||
|
Optional<Gfx::AffineTransform> gradient_transform() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SVGGradientElement(DOM::Document&, DOM::QualifiedName);
|
||||||
|
|
||||||
|
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
|
||||||
|
|
||||||
|
JS::GCPtr<SVGGradientElement const> xlink_href() const;
|
||||||
|
|
||||||
|
template<VoidFunction<SVGStopElement> Callback>
|
||||||
|
void for_each_color_stop(Callback const& callback) const
|
||||||
|
{
|
||||||
|
for_each_child_of_type<SVG::SVGStopElement>([&](auto& stop) {
|
||||||
|
callback(stop);
|
||||||
|
});
|
||||||
|
if (auto href = xlink_href())
|
||||||
|
href->for_each_color_stop(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Optional<GradientUnits> m_gradient_units = {};
|
||||||
|
Optional<Gfx::AffineTransform> m_gradient_transform = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
17
Userland/Libraries/LibWeb/SVG/SVGGradientElement.idl
Normal file
17
Userland/Libraries/LibWeb/SVG/SVGGradientElement.idl
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#import <SVG/SVGElement.idl>
|
||||||
|
|
||||||
|
[Exposed=Window]
|
||||||
|
interface SVGGradientElement : SVGElement {
|
||||||
|
|
||||||
|
// Spread Method Types
|
||||||
|
const unsigned short SVG_SPREADMETHOD_UNKNOWN = 0;
|
||||||
|
const unsigned short SVG_SPREADMETHOD_PAD = 1;
|
||||||
|
const unsigned short SVG_SPREADMETHOD_REFLECT = 2;
|
||||||
|
const unsigned short SVG_SPREADMETHOD_REPEAT = 3;
|
||||||
|
|
||||||
|
// FIXME: [SameObject] readonly attribute SVGAnimatedEnumeration gradientUnits;
|
||||||
|
// FIXME: [SameObject] readonly attribute SVGAnimatedTransformList gradientTransform;
|
||||||
|
// FIXME: [SameObject] readonly attribute SVGAnimatedEnumeration spreadMethod;
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: SVGGradientElement includes SVGURIReference;
|
|
@ -196,6 +196,7 @@ libweb_js_bindings(SVG/SVGClipPathElement)
|
||||||
libweb_js_bindings(SVG/SVGDefsElement)
|
libweb_js_bindings(SVG/SVGDefsElement)
|
||||||
libweb_js_bindings(SVG/SVGElement)
|
libweb_js_bindings(SVG/SVGElement)
|
||||||
libweb_js_bindings(SVG/SVGGeometryElement)
|
libweb_js_bindings(SVG/SVGGeometryElement)
|
||||||
|
libweb_js_bindings(SVG/SVGGradientElement)
|
||||||
libweb_js_bindings(SVG/SVGGraphicsElement)
|
libweb_js_bindings(SVG/SVGGraphicsElement)
|
||||||
libweb_js_bindings(SVG/SVGCircleElement)
|
libweb_js_bindings(SVG/SVGCircleElement)
|
||||||
libweb_js_bindings(SVG/SVGEllipseElement)
|
libweb_js_bindings(SVG/SVGEllipseElement)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue