mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-10 02:54:54 +03: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
Notes:
sideshowbarker
2024-07-17 06:35:16 +09:00
Author: https://github.com/MacDue Commit: https://github.com/SerenityOS/serenity/commit/71938550fa Pull-request: https://github.com/SerenityOS/serenity/pull/18473 Reviewed-by: https://github.com/nico
@ -495,6 +495,7 @@ set(SOURCES
|
||||
SVG/SVGGElement.cpp
|
||||
SVG/SVGGeometryElement.cpp
|
||||
SVG/SVGGraphicsElement.cpp
|
||||
SVG/SVGGradientElement.cpp
|
||||
SVG/SVGPathElement.cpp
|
||||
SVG/SVGCircleElement.cpp
|
||||
SVG/SVGEllipseElement.cpp
|
||||
|
@ -494,6 +494,19 @@ Optional<PreserveAspectRatio> AttributeParser::parse_preserve_aspect_ratio(Strin
|
||||
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
|
||||
Optional<Vector<Transform>> AttributeParser::parse_transform()
|
||||
{
|
||||
|
@ -88,6 +88,11 @@ struct PreserveAspectRatio {
|
||||
MeetOrSlice meet_or_slice { MeetOrSlice::Meet };
|
||||
};
|
||||
|
||||
enum class GradientUnits {
|
||||
ObjectBoundingBox,
|
||||
UserSpaceOnUse
|
||||
};
|
||||
|
||||
class NumberPercentage {
|
||||
public:
|
||||
NumberPercentage(float value, bool is_percentage)
|
||||
@ -127,6 +132,7 @@ public:
|
||||
static Vector<PathInstruction> parse_path_data(StringView input);
|
||||
static Optional<Vector<Transform>> parse_transform(StringView input);
|
||||
static Optional<PreserveAspectRatio> parse_preserve_aspect_ratio(StringView input);
|
||||
static Optional<GradientUnits> parse_gradient_units(StringView input);
|
||||
|
||||
private:
|
||||
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/SVGElement)
|
||||
libweb_js_bindings(SVG/SVGGeometryElement)
|
||||
libweb_js_bindings(SVG/SVGGradientElement)
|
||||
libweb_js_bindings(SVG/SVGGraphicsElement)
|
||||
libweb_js_bindings(SVG/SVGCircleElement)
|
||||
libweb_js_bindings(SVG/SVGEllipseElement)
|
||||
|
Loading…
Reference in New Issue
Block a user