mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-07 21:59:54 +00:00
LibWeb+LibGfx: Implement SVGFEMorphologyElement
This filter primitive is used to erode or dilate an image.
This commit is contained in:
parent
837d5fb7ea
commit
36c6079dbc
Notes:
github-actions[bot]
2025-11-15 15:09:46 +00:00
Author: https://github.com/tcl3
Commit: 36c6079dbc
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6831
17 changed files with 235 additions and 0 deletions
|
|
@ -76,6 +76,7 @@ namespace Web::SVG::AttributeNames {
|
|||
__ENUMERATE_SVG_ATTRIBUTE(preserveAspectRatio, "preserveAspectRatio") \
|
||||
__ENUMERATE_SVG_ATTRIBUTE(primitiveUnits, "primitiveUnits") \
|
||||
__ENUMERATE_SVG_ATTRIBUTE(r, "r") \
|
||||
__ENUMERATE_SVG_ATTRIBUTE(radius, "radius") \
|
||||
__ENUMERATE_SVG_ATTRIBUTE(refX, "refX") \
|
||||
__ENUMERATE_SVG_ATTRIBUTE(refY, "refY") \
|
||||
__ENUMERATE_SVG_ATTRIBUTE(repeatCount, "repeatCount") \
|
||||
|
|
|
|||
85
Libraries/LibWeb/SVG/SVGFEMorphologyElement.cpp
Normal file
85
Libraries/LibWeb/SVG/SVGFEMorphologyElement.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Tim Ledbetter <tim.ledbetter@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/Bindings/SVGFEMorphologyElementPrototype.h>
|
||||
#include <LibWeb/SVG/AttributeNames.h>
|
||||
#include <LibWeb/SVG/SVGFEMorphologyElement.h>
|
||||
|
||||
namespace Web::SVG {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(SVGFEMorphologyElement);
|
||||
|
||||
SVGFEMorphologyElement::SVGFEMorphologyElement(DOM::Document& document, DOM::QualifiedName qualified_name)
|
||||
: SVGElement(document, qualified_name)
|
||||
{
|
||||
}
|
||||
|
||||
void SVGFEMorphologyElement::initialize(JS::Realm& realm)
|
||||
{
|
||||
WEB_SET_PROTOTYPE_FOR_INTERFACE(SVGFEMorphologyElement);
|
||||
Base::initialize(realm);
|
||||
}
|
||||
|
||||
void SVGFEMorphologyElement::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
SVGFilterPrimitiveStandardAttributes::visit_edges(visitor);
|
||||
visitor.visit(m_in1);
|
||||
visitor.visit(m_radius_x);
|
||||
visitor.visit(m_radius_y);
|
||||
}
|
||||
|
||||
void SVGFEMorphologyElement::attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& new_value, Optional<FlyString> const& namespace_)
|
||||
{
|
||||
Base::attribute_changed(name, old_value, new_value, namespace_);
|
||||
|
||||
if (name == SVG::AttributeNames::operator_) {
|
||||
if (!new_value.has_value()) {
|
||||
m_morphology_operator = Gfx::MorphologyOperator::Dilate;
|
||||
return;
|
||||
}
|
||||
if (new_value->equals_ignoring_ascii_case("erode"sv)) {
|
||||
m_morphology_operator = Gfx::MorphologyOperator::Erode;
|
||||
} else if (new_value->equals_ignoring_ascii_case("dilate"sv)) {
|
||||
m_morphology_operator = Gfx::MorphologyOperator::Dilate;
|
||||
} else {
|
||||
m_morphology_operator = Gfx::MorphologyOperator::Dilate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GC::Ref<SVGAnimatedString> SVGFEMorphologyElement::in1()
|
||||
{
|
||||
if (!m_in1)
|
||||
m_in1 = SVGAnimatedString::create(realm(), *this, DOM::QualifiedName { AttributeNames::in, OptionalNone {}, OptionalNone {} });
|
||||
|
||||
return *m_in1;
|
||||
}
|
||||
|
||||
GC::Ref<SVGAnimatedEnumeration> SVGFEMorphologyElement::operator_for_bindings()
|
||||
{
|
||||
return SVGAnimatedEnumeration::create(realm(), to_underlying(m_morphology_operator));
|
||||
}
|
||||
|
||||
GC::Ref<SVGAnimatedNumber> SVGFEMorphologyElement::radius_x()
|
||||
{
|
||||
if (!m_radius_x)
|
||||
m_radius_x = SVGAnimatedNumber::create(realm(), *this, DOM::QualifiedName { SVG::AttributeNames::radius, OptionalNone {}, OptionalNone {} }, 0.0,
|
||||
SVGAnimatedNumber::SupportsSecondValue::Yes, SVGAnimatedNumber::ValueRepresented::First);
|
||||
|
||||
return *m_radius_x;
|
||||
}
|
||||
|
||||
GC::Ref<SVGAnimatedNumber> SVGFEMorphologyElement::radius_y()
|
||||
{
|
||||
if (!m_radius_y)
|
||||
m_radius_y = SVGAnimatedNumber::create(realm(), *this, DOM::QualifiedName { SVG::AttributeNames::radius, OptionalNone {}, OptionalNone {} }, 0.0,
|
||||
SVGAnimatedNumber::SupportsSecondValue::Yes, SVGAnimatedNumber::ValueRepresented::Second);
|
||||
|
||||
return *m_radius_y;
|
||||
}
|
||||
|
||||
}
|
||||
50
Libraries/LibWeb/SVG/SVGFEMorphologyElement.h
Normal file
50
Libraries/LibWeb/SVG/SVGFEMorphologyElement.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Tim Ledbetter <tim.ledbetter@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibGfx/MorphologyOperator.h>
|
||||
#include <LibWeb/SVG/SVGAnimatedEnumeration.h>
|
||||
#include <LibWeb/SVG/SVGAnimatedNumber.h>
|
||||
#include <LibWeb/SVG/SVGAnimatedString.h>
|
||||
#include <LibWeb/SVG/SVGElement.h>
|
||||
#include <LibWeb/SVG/SVGFilterPrimitiveStandardAttributes.h>
|
||||
|
||||
namespace Web::SVG {
|
||||
|
||||
// https://www.w3.org/TR/filter-effects-1/#svgfemorphologyelement
|
||||
class SVGFEMorphologyElement final
|
||||
: public SVGElement
|
||||
, public SVGFilterPrimitiveStandardAttributes<SVGFEMorphologyElement> {
|
||||
WEB_PLATFORM_OBJECT(SVGFEMorphologyElement, SVGElement);
|
||||
GC_DECLARE_ALLOCATOR(SVGFEMorphologyElement);
|
||||
|
||||
public:
|
||||
virtual ~SVGFEMorphologyElement() override = default;
|
||||
|
||||
GC::Ref<SVGAnimatedString> in1();
|
||||
|
||||
GC::Ref<SVGAnimatedEnumeration> operator_for_bindings();
|
||||
Gfx::MorphologyOperator morphology_operator() { return m_morphology_operator; }
|
||||
|
||||
GC::Ref<SVGAnimatedNumber> radius_x();
|
||||
GC::Ref<SVGAnimatedNumber> radius_y();
|
||||
|
||||
private:
|
||||
SVGFEMorphologyElement(DOM::Document&, DOM::QualifiedName);
|
||||
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& new_value, Optional<FlyString> const& namespace_) override;
|
||||
|
||||
GC::Ptr<SVGAnimatedString> m_in1;
|
||||
Gfx::MorphologyOperator m_morphology_operator { Gfx::MorphologyOperator::Erode };
|
||||
GC::Ptr<SVGAnimatedNumber> m_radius_x;
|
||||
GC::Ptr<SVGAnimatedNumber> m_radius_y;
|
||||
};
|
||||
|
||||
}
|
||||
22
Libraries/LibWeb/SVG/SVGFEMorphologyElement.idl
Normal file
22
Libraries/LibWeb/SVG/SVGFEMorphologyElement.idl
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#import <SVG/SVGAnimatedEnumeration.idl>
|
||||
#import <SVG/SVGAnimatedNumber.idl>
|
||||
#import <SVG/SVGAnimatedString.idl>
|
||||
#import <SVG/SVGElement.idl>
|
||||
#import <SVG/SVGFilterPrimitiveStandardAttributes.idl>
|
||||
|
||||
// https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEMorphologyElement
|
||||
[Exposed=Window]
|
||||
interface SVGFEMorphologyElement : SVGElement {
|
||||
|
||||
// Morphology Operators
|
||||
const unsigned short SVG_MORPHOLOGY_OPERATOR_UNKNOWN = 0;
|
||||
const unsigned short SVG_MORPHOLOGY_OPERATOR_ERODE = 1;
|
||||
const unsigned short SVG_MORPHOLOGY_OPERATOR_DILATE = 2;
|
||||
|
||||
readonly attribute SVGAnimatedString in1;
|
||||
[ImplementedAs=operator_for_bindings] readonly attribute SVGAnimatedEnumeration operator;
|
||||
readonly attribute SVGAnimatedNumber radiusX;
|
||||
readonly attribute SVGAnimatedNumber radiusY;
|
||||
};
|
||||
|
||||
SVGFEMorphologyElement includes SVGFilterPrimitiveStandardAttributes;
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
#include <LibWeb/SVG/SVGFEImageElement.h>
|
||||
#include <LibWeb/SVG/SVGFEMergeElement.h>
|
||||
#include <LibWeb/SVG/SVGFEMergeNodeElement.h>
|
||||
#include <LibWeb/SVG/SVGFEMorphologyElement.h>
|
||||
#include <LibWeb/SVG/SVGFEOffsetElement.h>
|
||||
#include <LibWeb/SVG/SVGFilterElement.h>
|
||||
|
||||
|
|
@ -284,6 +285,24 @@ Optional<Gfx::Filter> SVGFilterElement::gfx_filter(Layout::NodeWithStyle const&
|
|||
|
||||
root_filter = Gfx::Filter::merge(merge_inputs);
|
||||
update_result_map(*merge_primitive);
|
||||
} else if (auto* morphology_primitive = as_if<SVGFEMorphologyElement>(node)) {
|
||||
auto input = resolve_input_filter(morphology_primitive->in1()->base_val());
|
||||
|
||||
auto radius_x = morphology_primitive->radius_x()->base_val();
|
||||
auto radius_y = morphology_primitive->radius_y()->base_val();
|
||||
auto morphology_operator = morphology_primitive->morphology_operator();
|
||||
switch (morphology_operator) {
|
||||
case Gfx::MorphologyOperator::Erode:
|
||||
root_filter = Gfx::Filter::erode(radius_x, radius_y, input);
|
||||
break;
|
||||
case Gfx::MorphologyOperator::Dilate:
|
||||
root_filter = Gfx::Filter::dilate(radius_x, radius_y, input);
|
||||
break;
|
||||
case Gfx::MorphologyOperator::Unknown:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
update_result_map(*morphology_primitive);
|
||||
} else if (auto* offset_primitive = as_if<SVGFEOffsetElement>(node)) {
|
||||
auto input = resolve_input_filter(offset_primitive->in1()->base_val());
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include <LibWeb/SVG/SVGFEGaussianBlurElement.h>
|
||||
#include <LibWeb/SVG/SVGFEImageElement.h>
|
||||
#include <LibWeb/SVG/SVGFEMergeElement.h>
|
||||
#include <LibWeb/SVG/SVGFEMorphologyElement.h>
|
||||
#include <LibWeb/SVG/SVGFEOffsetElement.h>
|
||||
|
||||
namespace Web::SVG {
|
||||
|
|
@ -60,6 +61,7 @@ template class SVGFilterPrimitiveStandardAttributes<SVGFEFloodElement>;
|
|||
template class SVGFilterPrimitiveStandardAttributes<SVGFEGaussianBlurElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFEImageElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFEMergeElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFEMorphologyElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFEOffsetElement>;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ namespace Web::SVG::TagNames {
|
|||
__ENUMERATE_SVG_TAG(feImage) \
|
||||
__ENUMERATE_SVG_TAG(feMerge) \
|
||||
__ENUMERATE_SVG_TAG(feMergeNode) \
|
||||
__ENUMERATE_SVG_TAG(feMorphology) \
|
||||
__ENUMERATE_SVG_TAG(feOffset) \
|
||||
__ENUMERATE_SVG_TAG(filter) \
|
||||
__ENUMERATE_SVG_TAG(foreignObject) \
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue