LibWeb/SVG: Implement the feTurbulence filter
This commit is contained in:
parent
a89b02e5c3
commit
e9f5df2131
20 changed files with 314 additions and 0 deletions
|
|
@ -13,6 +13,7 @@
|
|||
#include <core/SkScalar.h>
|
||||
#include <effects/SkColorMatrix.h>
|
||||
#include <effects/SkImageFilters.h>
|
||||
#include <effects/SkPerlinNoiseShader.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
|
|
@ -296,4 +297,20 @@ Filter Filter::offset(float dx, float dy, Optional<Filter const&> input)
|
|||
return Filter(Impl::create(SkImageFilters::Offset(dx, dy, input_skia)));
|
||||
}
|
||||
|
||||
Filter Filter::turbulence(TurbulenceType turbulence_type, float base_frequency_x, float base_frequency_y, i32 num_octaves, float seed, Gfx::IntSize const& tile_stitch_size)
|
||||
{
|
||||
sk_sp<SkShader> turbulence_shader = [&] {
|
||||
auto skia_size = SkISize::Make(tile_stitch_size.width(), tile_stitch_size.height());
|
||||
switch (turbulence_type) {
|
||||
case TurbulenceType::Turbulence:
|
||||
return SkShaders::MakeTurbulence(base_frequency_x, base_frequency_y, num_octaves, seed, &skia_size);
|
||||
case TurbulenceType::FractalNoise:
|
||||
return SkShaders::MakeFractalNoise(base_frequency_x, base_frequency_y, num_octaves, seed, &skia_size);
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}();
|
||||
|
||||
return Filter(Impl::create(SkImageFilters::Shader(move(turbulence_shader))));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,11 @@ enum class ColorFilterType {
|
|||
Sepia
|
||||
};
|
||||
|
||||
enum class TurbulenceType {
|
||||
FractalNoise,
|
||||
Turbulence,
|
||||
};
|
||||
|
||||
struct FilterImpl;
|
||||
|
||||
class Filter {
|
||||
|
|
@ -50,6 +55,7 @@ public:
|
|||
static Filter offset(float dx, float dy, Optional<Filter const&> input = {});
|
||||
static Filter erode(float radius_x, float radius_y, Optional<Filter> const& input = {});
|
||||
static Filter dilate(float radius_x, float radius_y, Optional<Filter> const& input = {});
|
||||
static Filter turbulence(TurbulenceType turbulence_type, float base_frequency_x, float base_frequency_y, i32 num_octaves, float seed, Gfx::IntSize const& tile_stitch_size);
|
||||
|
||||
FilterImpl const& impl() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -964,6 +964,7 @@ set(SOURCES
|
|||
SVG/SVGFEMergeNodeElement.cpp
|
||||
SVG/SVGFEMorphologyElement.cpp
|
||||
SVG/SVGFEOffsetElement.cpp
|
||||
SVG/SVGFETurbulenceElement.cpp
|
||||
SVG/SVGFilterElement.cpp
|
||||
SVG/SVGFilterPrimitiveStandardAttributes.cpp
|
||||
SVG/SVGFitToViewBox.cpp
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@
|
|||
#include <LibWeb/SVG/SVGFEMergeNodeElement.h>
|
||||
#include <LibWeb/SVG/SVGFEMorphologyElement.h>
|
||||
#include <LibWeb/SVG/SVGFEOffsetElement.h>
|
||||
#include <LibWeb/SVG/SVGFETurbulenceElement.h>
|
||||
#include <LibWeb/SVG/SVGFilterElement.h>
|
||||
#include <LibWeb/SVG/SVGForeignObjectElement.h>
|
||||
#include <LibWeb/SVG/SVGGElement.h>
|
||||
|
|
@ -517,6 +518,8 @@ static GC::Ref<SVG::SVGElement> create_svg_element(JS::Realm& realm, Document& d
|
|||
return realm.create<SVG::SVGFEMorphologyElement>(document, move(qualified_name));
|
||||
if (local_name == SVG::TagNames::feOffset)
|
||||
return realm.create<SVG::SVGFEOffsetElement>(document, move(qualified_name));
|
||||
if (local_name == SVG::TagNames::feTurbulence)
|
||||
return realm.create<SVG::SVGFETurbulenceElement>(document, move(qualified_name));
|
||||
if (local_name == SVG::TagNames::filter)
|
||||
return realm.create<SVG::SVGFilterElement>(document, move(qualified_name));
|
||||
if (local_name.equals_ignoring_ascii_case(SVG::TagNames::foreignObject))
|
||||
|
|
|
|||
|
|
@ -1152,6 +1152,7 @@ class SVGFEFuncRElement;
|
|||
class SVGFEGaussianBlurElement;
|
||||
class SVGFEImageElement;
|
||||
class SVGFEMorphologyElement;
|
||||
class SVGFETurbulenceElement;
|
||||
class SVGFilterElement;
|
||||
class SVGFitToViewBox;
|
||||
class SVGForeignObjectElement;
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ namespace Web::SVG::AttributeNames {
|
|||
__ENUMERATE_SVG_ATTRIBUTE(rotate, "rotate") \
|
||||
__ENUMERATE_SVG_ATTRIBUTE(rx, "rx") \
|
||||
__ENUMERATE_SVG_ATTRIBUTE(ry, "ry") \
|
||||
__ENUMERATE_SVG_ATTRIBUTE(seed, "seed") \
|
||||
__ENUMERATE_SVG_ATTRIBUTE(slope, "slope") \
|
||||
__ENUMERATE_SVG_ATTRIBUTE(specularConstant, "specularConstant") \
|
||||
__ENUMERATE_SVG_ATTRIBUTE(specularExponent, "specularExponent") \
|
||||
|
|
|
|||
116
Libraries/LibWeb/SVG/SVGFETurbulenceElement.cpp
Normal file
116
Libraries/LibWeb/SVG/SVGFETurbulenceElement.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/Bindings/SVGFETurbulenceElementPrototype.h>
|
||||
#include <LibWeb/SVG/AttributeNames.h>
|
||||
#include <LibWeb/SVG/SVGFETurbulenceElement.h>
|
||||
|
||||
namespace Web::SVG {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(SVGFETurbulenceElement);
|
||||
|
||||
SVGFETurbulenceElement::SVGFETurbulenceElement(DOM::Document& document, DOM::QualifiedName qualified_name)
|
||||
: SVGElement(document, move(qualified_name))
|
||||
{
|
||||
}
|
||||
|
||||
void SVGFETurbulenceElement::initialize(JS::Realm& realm)
|
||||
{
|
||||
WEB_SET_PROTOTYPE_FOR_INTERFACE(SVGFETurbulenceElement);
|
||||
Base::initialize(realm);
|
||||
}
|
||||
|
||||
void SVGFETurbulenceElement::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
SVGFilterPrimitiveStandardAttributes::visit_edges(visitor);
|
||||
visitor.visit(m_base_frequency_x);
|
||||
visitor.visit(m_base_frequency_y);
|
||||
visitor.visit(m_num_octaves);
|
||||
visitor.visit(m_seed);
|
||||
visitor.visit(m_stitch_tiles);
|
||||
visitor.visit(m_type);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/filter-effects/#dom-svgfeturbulenceelement-basefrequencyx
|
||||
GC::Ref<SVGAnimatedNumber> SVGFETurbulenceElement::base_frequency_x()
|
||||
{
|
||||
if (!m_base_frequency_x) {
|
||||
m_base_frequency_x = SVGAnimatedNumber::create(realm(), *this, DOM::QualifiedName { AttributeNames::baseFrequency, OptionalNone {}, OptionalNone {} }, 0.f,
|
||||
SVGAnimatedNumber::SupportsSecondValue::Yes, SVGAnimatedNumber::ValueRepresented::First);
|
||||
}
|
||||
return *m_base_frequency_x;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/filter-effects/#dom-svgfeturbulenceelement-basefrequencyy
|
||||
GC::Ref<SVGAnimatedNumber> SVGFETurbulenceElement::base_frequency_y()
|
||||
{
|
||||
if (!m_base_frequency_y) {
|
||||
m_base_frequency_y = SVGAnimatedNumber::create(realm(), *this, DOM::QualifiedName { AttributeNames::baseFrequency, OptionalNone {}, OptionalNone {} }, 0.f,
|
||||
SVGAnimatedNumber::SupportsSecondValue::Yes, SVGAnimatedNumber::ValueRepresented::Second);
|
||||
}
|
||||
return *m_base_frequency_y;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/filter-effects/#dom-svgfeturbulenceelement-numoctaves
|
||||
GC::Ref<SVGAnimatedInteger> SVGFETurbulenceElement::num_octaves()
|
||||
{
|
||||
if (!m_num_octaves)
|
||||
m_num_octaves = SVGAnimatedInteger::create(realm(), *this, DOM::QualifiedName { AttributeNames::numOctaves, OptionalNone {}, OptionalNone {} }, 1);
|
||||
|
||||
return *m_num_octaves;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/filter-effects/#dom-svgfeturbulenceelement-seed
|
||||
GC::Ref<SVGAnimatedNumber> SVGFETurbulenceElement::seed()
|
||||
{
|
||||
if (!m_seed)
|
||||
m_seed = SVGAnimatedNumber::create(realm(), *this, DOM::QualifiedName { AttributeNames::seed, OptionalNone {}, OptionalNone {} }, 0);
|
||||
|
||||
return *m_seed;
|
||||
}
|
||||
|
||||
// // https://drafts.csswg.org/filter-effects/#element-attrdef-feturbulence-stitchtiles
|
||||
static SVGFETurbulenceElement::StitchType parse_stitch_tiles(String const& value)
|
||||
{
|
||||
if (value == "stitch"sv)
|
||||
return SVGFETurbulenceElement::StitchType::Stitch;
|
||||
|
||||
if (value == "noStitch"sv)
|
||||
return SVGFETurbulenceElement::StitchType::NoStitch;
|
||||
|
||||
return SVGFETurbulenceElement::StitchType::NoStitch;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/filter-effects/#element-attrdef-feturbulence-stitchtiles
|
||||
GC::Ref<SVGAnimatedEnumeration> SVGFETurbulenceElement::stitch_tiles()
|
||||
{
|
||||
// FIXME: Support reflection, don't return a new object every time.
|
||||
auto stitch_tiles = parse_stitch_tiles(get_attribute_value(AttributeNames::stitchTiles));
|
||||
return SVGAnimatedEnumeration::create(realm(), to_underlying(stitch_tiles));
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/filter-effects/#element-attrdef-feturbulence-type
|
||||
static SVGFETurbulenceElement::TurbulenceType parse_turbulence_type(String const& value)
|
||||
{
|
||||
if (value == "turbulence"sv)
|
||||
return SVGFETurbulenceElement::TurbulenceType::Turbulence;
|
||||
|
||||
if (value == "fractalNoise"sv)
|
||||
return SVGFETurbulenceElement::TurbulenceType::FractalNoise;
|
||||
|
||||
return SVGFETurbulenceElement::TurbulenceType::Turbulence;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/filter-effects/#dom-svgfeturbulenceelement-type
|
||||
GC::Ref<SVGAnimatedEnumeration> SVGFETurbulenceElement::type()
|
||||
{
|
||||
// FIXME: Support reflection, don't return a new object every time.
|
||||
auto turbulence_type = parse_turbulence_type(get_attribute_value(AttributeNames::type));
|
||||
return SVGAnimatedEnumeration::create(realm(), to_underlying(turbulence_type));
|
||||
}
|
||||
|
||||
}
|
||||
62
Libraries/LibWeb/SVG/SVGFETurbulenceElement.h
Normal file
62
Libraries/LibWeb/SVG/SVGFETurbulenceElement.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/SVG/SVGAnimatedEnumeration.h>
|
||||
#include <LibWeb/SVG/SVGAnimatedInteger.h>
|
||||
#include <LibWeb/SVG/SVGAnimatedNumber.h>
|
||||
#include <LibWeb/SVG/SVGAnimatedString.h>
|
||||
#include <LibWeb/SVG/SVGElement.h>
|
||||
#include <LibWeb/SVG/SVGFilterPrimitiveStandardAttributes.h>
|
||||
|
||||
namespace Web::SVG {
|
||||
|
||||
class SVGFETurbulenceElement final
|
||||
: public SVGElement
|
||||
, public SVGFilterPrimitiveStandardAttributes<SVGFETurbulenceElement> {
|
||||
WEB_PLATFORM_OBJECT(SVGFETurbulenceElement, SVGElement);
|
||||
GC_DECLARE_ALLOCATOR(SVGFETurbulenceElement);
|
||||
|
||||
public:
|
||||
enum class TurbulenceType {
|
||||
Unknown = 0,
|
||||
FractalNoise = 1,
|
||||
Turbulence = 2,
|
||||
};
|
||||
|
||||
enum class StitchType {
|
||||
Unknown = 0,
|
||||
Stitch = 1,
|
||||
NoStitch = 2,
|
||||
};
|
||||
|
||||
virtual ~SVGFETurbulenceElement() override = default;
|
||||
|
||||
GC::Ref<SVGAnimatedNumber> base_frequency_x();
|
||||
GC::Ref<SVGAnimatedNumber> base_frequency_y();
|
||||
GC::Ref<SVGAnimatedInteger> num_octaves();
|
||||
GC::Ref<SVGAnimatedNumber> seed();
|
||||
GC::Ref<SVGAnimatedEnumeration> stitch_tiles();
|
||||
GC::Ref<SVGAnimatedEnumeration> type();
|
||||
|
||||
protected:
|
||||
SVGFETurbulenceElement(DOM::Document&, DOM::QualifiedName);
|
||||
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
|
||||
private:
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
GC::Ptr<SVGAnimatedNumber> m_base_frequency_x;
|
||||
GC::Ptr<SVGAnimatedNumber> m_base_frequency_y;
|
||||
GC::Ptr<SVGAnimatedInteger> m_num_octaves;
|
||||
GC::Ptr<SVGAnimatedNumber> m_seed;
|
||||
GC::Ptr<SVGAnimatedEnumeration> m_stitch_tiles;
|
||||
GC::Ptr<SVGAnimatedEnumeration> m_type;
|
||||
};
|
||||
|
||||
}
|
||||
28
Libraries/LibWeb/SVG/SVGFETurbulenceElement.idl
Normal file
28
Libraries/LibWeb/SVG/SVGFETurbulenceElement.idl
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#import <SVG/SVGAnimatedEnumeration.idl>
|
||||
#import <SVG/SVGAnimatedInteger.idl>
|
||||
#import <SVG/SVGAnimatedNumber.idl>
|
||||
#import <SVG/SVGAnimatedString.idl>
|
||||
#import <SVG/SVGFilterPrimitiveStandardAttributes.idl>
|
||||
|
||||
// https://drafts.csswg.org/filter-effects/#svgfeturbulenceelement
|
||||
[Exposed=Window]
|
||||
interface SVGFETurbulenceElement : SVGElement {
|
||||
// Turbulence Types
|
||||
const unsigned short SVG_TURBULENCE_TYPE_UNKNOWN = 0;
|
||||
const unsigned short SVG_TURBULENCE_TYPE_FRACTALNOISE = 1;
|
||||
const unsigned short SVG_TURBULENCE_TYPE_TURBULENCE = 2;
|
||||
|
||||
// Stitch Options
|
||||
const unsigned short SVG_STITCHTYPE_UNKNOWN = 0;
|
||||
const unsigned short SVG_STITCHTYPE_STITCH = 1;
|
||||
const unsigned short SVG_STITCHTYPE_NOSTITCH = 2;
|
||||
|
||||
readonly attribute SVGAnimatedNumber baseFrequencyX;
|
||||
readonly attribute SVGAnimatedNumber baseFrequencyY;
|
||||
readonly attribute SVGAnimatedInteger numOctaves;
|
||||
readonly attribute SVGAnimatedNumber seed;
|
||||
readonly attribute SVGAnimatedEnumeration stitchTiles;
|
||||
readonly attribute SVGAnimatedEnumeration type;
|
||||
};
|
||||
|
||||
SVGFETurbulenceElement includes SVGFilterPrimitiveStandardAttributes;
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
#include <LibWeb/SVG/SVGFEMergeNodeElement.h>
|
||||
#include <LibWeb/SVG/SVGFEMorphologyElement.h>
|
||||
#include <LibWeb/SVG/SVGFEOffsetElement.h>
|
||||
#include <LibWeb/SVG/SVGFETurbulenceElement.h>
|
||||
#include <LibWeb/SVG/SVGFilterElement.h>
|
||||
|
||||
namespace Web::SVG {
|
||||
|
|
@ -359,6 +360,39 @@ Optional<Gfx::Filter> SVGFilterElement::gfx_filter(Layout::NodeWithStyle const&
|
|||
// </feMerge>
|
||||
root_filter = Gfx::Filter::merge({ colored_shadow, input });
|
||||
update_result_map(*drop_shadow);
|
||||
} else if (auto* turbulence = as_if<SVGFETurbulenceElement>(node)) {
|
||||
auto base_frequency_x = turbulence->base_frequency_x()->base_val();
|
||||
auto base_frequency_y = turbulence->base_frequency_y()->base_val();
|
||||
auto num_octaves = turbulence->num_octaves()->base_val();
|
||||
auto seed = turbulence->seed()->base_val();
|
||||
|
||||
auto type = [turbulence] {
|
||||
auto turbulence_type = turbulence->type()->base_val();
|
||||
switch (turbulence_type) {
|
||||
case to_underlying(SVGFETurbulenceElement::TurbulenceType::Turbulence):
|
||||
return Gfx::TurbulenceType::Turbulence;
|
||||
case to_underlying(SVGFETurbulenceElement::TurbulenceType::FractalNoise):
|
||||
return Gfx::TurbulenceType::FractalNoise;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}();
|
||||
|
||||
auto tile_stitch_size = [turbulence] {
|
||||
auto stitch_tiles = turbulence->stitch_tiles()->base_val();
|
||||
switch (stitch_tiles) {
|
||||
case to_underlying(SVGFETurbulenceElement::StitchType::Stitch):
|
||||
// FIXME: Are these the correct width and height?
|
||||
return Gfx::IntSize { turbulence->width()->base_val()->value(), turbulence->height()->base_val()->value() };
|
||||
case to_underlying(SVGFETurbulenceElement::StitchType::NoStitch):
|
||||
return Gfx::IntSize {};
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}();
|
||||
|
||||
root_filter = Gfx::Filter::turbulence(type, base_frequency_x, base_frequency_y, num_octaves, seed, tile_stitch_size);
|
||||
update_result_map(*turbulence);
|
||||
} else {
|
||||
dbgln("SVGFilterElement::gfx_filter(): Unknown or unsupported filter element '{}'", node.debug_description());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <LibWeb/SVG/SVGFEMergeElement.h>
|
||||
#include <LibWeb/SVG/SVGFEMorphologyElement.h>
|
||||
#include <LibWeb/SVG/SVGFEOffsetElement.h>
|
||||
#include <LibWeb/SVG/SVGFETurbulenceElement.h>
|
||||
#include <LibWeb/SVG/SVGFilterPrimitiveStandardAttributes.h>
|
||||
|
||||
namespace Web::SVG {
|
||||
|
|
@ -65,5 +66,6 @@ template class SVGFilterPrimitiveStandardAttributes<SVGFEImageElement>;
|
|||
template class SVGFilterPrimitiveStandardAttributes<SVGFEMergeElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFEMorphologyElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFEOffsetElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFETurbulenceElement>;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ namespace Web::SVG::TagNames {
|
|||
__ENUMERATE_SVG_TAG(feMergeNode) \
|
||||
__ENUMERATE_SVG_TAG(feMorphology) \
|
||||
__ENUMERATE_SVG_TAG(feOffset) \
|
||||
__ENUMERATE_SVG_TAG(feTurbulence) \
|
||||
__ENUMERATE_SVG_TAG(filter) \
|
||||
__ENUMERATE_SVG_TAG(foreignObject) \
|
||||
__ENUMERATE_SVG_TAG(g) \
|
||||
|
|
|
|||
|
|
@ -423,6 +423,7 @@ libweb_js_bindings(SVG/SVGFEMergeElement)
|
|||
libweb_js_bindings(SVG/SVGFEMergeNodeElement)
|
||||
libweb_js_bindings(SVG/SVGFEMorphologyElement)
|
||||
libweb_js_bindings(SVG/SVGFEOffsetElement)
|
||||
libweb_js_bindings(SVG/SVGFETurbulenceElement)
|
||||
libweb_js_bindings(SVG/SVGFilterElement)
|
||||
libweb_js_bindings(SVG/SVGForeignObjectElement)
|
||||
libweb_js_bindings(SVG/SVGLength)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
* { margin: 0; }
|
||||
body { background-color: white; }
|
||||
</style>
|
||||
<img src="../images/svg-feTurbulence-fractalNoise-ref.png">
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
* { margin: 0; }
|
||||
body { background-color: white; }
|
||||
</style>
|
||||
<img src="../images/svg-feTurbulence-ref.png">
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
BIN
Tests/LibWeb/Screenshot/images/svg-feTurbulence-ref.png
Normal file
BIN
Tests/LibWeb/Screenshot/images/svg-feTurbulence-ref.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="match" href="../expected/svg-feTurbulence-fractalNoise-ref.html" />
|
||||
<style>
|
||||
* { margin: 0; }
|
||||
body { background-color: white; }
|
||||
</style>
|
||||
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<filter id="turbulence">
|
||||
<feTurbulence type="fractalNoise" baseFrequency="0.05" numOctaves="3" seed="5" />
|
||||
</filter>
|
||||
</defs>
|
||||
<rect width="200" height="200" filter="url(#turbulence)" />
|
||||
</svg>
|
||||
14
Tests/LibWeb/Screenshot/input/svg-feTurbulence.html
Normal file
14
Tests/LibWeb/Screenshot/input/svg-feTurbulence.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="match" href="../expected/svg-feTurbulence-ref.html" />
|
||||
<style>
|
||||
* { margin: 0; }
|
||||
body { background-color: white; }
|
||||
</style>
|
||||
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<filter id="turbulence">
|
||||
<feTurbulence baseFrequency="0.05" numOctaves="2" />
|
||||
</filter>
|
||||
</defs>
|
||||
<rect width="200" height="200" filter="url(#turbulence)" />
|
||||
</svg>
|
||||
|
|
@ -401,6 +401,7 @@ SVGFEMergeElement
|
|||
SVGFEMergeNodeElement
|
||||
SVGFEMorphologyElement
|
||||
SVGFEOffsetElement
|
||||
SVGFETurbulenceElement
|
||||
SVGFilterElement
|
||||
SVGForeignObjectElement
|
||||
SVGGElement
|
||||
|
|
|
|||
Loading…
Reference in a new issue