From ba54b15799f696396f710a0da82c3bf71258e2cb Mon Sep 17 00:00:00 2001 From: Jakub Grzywacz Date: Tue, 15 Oct 2024 09:35:13 +0200 Subject: [PATCH] feat: FeFlood (#2487) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Summary Continuation of #2362 implementing `FeFlood` filter https://www.w3.org/TR/SVG11/filters.html#feFloodElement ## Test Plan Example app → Filters → `FeFlood` ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | macOS | ✅ _*_ | | Android | ✅ | | Web | ✅ | _* `canvasWidth/canvasHeight` is incorrect on macOS, so there might be some problems_ --- USAGE.md | 2 +- .../java/com/horcrux/svg/FeFloodView.java | 130 ++++++++++++++++ .../horcrux/svg/RenderableViewManager.java | 29 ++++ .../main/java/com/horcrux/svg/SvgPackage.java | 9 ++ .../RNSVGFeFloodManagerDelegate.java | 50 +++++++ .../RNSVGFeFloodManagerInterface.java | 24 +++ apple/Filters/RNSVGFeFlood.h | 9 ++ apple/Filters/RNSVGFeFlood.mm | 91 +++++++++++ apple/ViewManagers/RNSVGFeFloodManager.h | 5 + apple/ViewManagers/RNSVGFeFloodManager.mm | 16 ++ .../examples/src/examples/Filters/FeFlood.tsx | 141 ++++++++++++++++++ .../src/examples/Filters/examples.tsx | 2 + react-native.config.js | 1 + src/elements/filters/FeFlood.tsx | 18 ++- src/fabric/FeFloodNativeComponent.ts | 31 ++++ src/fabric/index.ts | 2 + src/lib/extract/extractFilter.ts | 27 ++++ 17 files changed, 581 insertions(+), 6 deletions(-) create mode 100644 android/src/main/java/com/horcrux/svg/FeFloodView.java create mode 100644 android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeFloodManagerDelegate.java create mode 100644 android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeFloodManagerInterface.java create mode 100644 apple/Filters/RNSVGFeFlood.h create mode 100644 apple/Filters/RNSVGFeFlood.mm create mode 100644 apple/ViewManagers/RNSVGFeFloodManager.h create mode 100644 apple/ViewManagers/RNSVGFeFloodManager.mm create mode 100644 apps/examples/src/examples/Filters/FeFlood.tsx create mode 100644 src/fabric/FeFloodNativeComponent.ts diff --git a/USAGE.md b/USAGE.md index 64cb9b2fa..a0d8fe0dc 100644 --- a/USAGE.md +++ b/USAGE.md @@ -1301,6 +1301,7 @@ Filter effects are a way of processing an element’s rendering before it is dis The following filters have been implemented: - FeColorMatrix +- FeFlood - FeGaussianBlur - FeMerge - FeOffset @@ -1314,7 +1315,6 @@ Not supported yet: - FeDiffuseLighting - FeDisplacementMap - FeDropShadow -- FeFlood - FeFuncA - FeFuncB - FeFuncG diff --git a/android/src/main/java/com/horcrux/svg/FeFloodView.java b/android/src/main/java/com/horcrux/svg/FeFloodView.java new file mode 100644 index 000000000..b6d0f6df8 --- /dev/null +++ b/android/src/main/java/com/horcrux/svg/FeFloodView.java @@ -0,0 +1,130 @@ +package com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import com.facebook.react.bridge.ColorPropConverter; +import com.facebook.react.bridge.Dynamic; +import com.facebook.react.bridge.JavaOnlyArray; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableType; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.annotation.Nullable; + +@SuppressLint("ViewConstructor") +class FeFloodView extends FilterPrimitiveView { + private static final Pattern regex = Pattern.compile("[0-9.-]+"); + + public @Nullable ReadableArray floodColor; + public float floodOpacity = 1; + + public FeFloodView(ReactContext reactContext) { + super(reactContext); + } + + public void setFloodColor(@Nullable Dynamic color) { + if (color == null || color.isNull()) { + floodColor = null; + invalidate(); + return; + } + + ReadableType strokeType = color.getType(); + if (strokeType.equals(ReadableType.Map)) { + ReadableMap colorMap = color.asMap(); + setFloodColor(colorMap); + return; + } + + // This code will probably never be reached with current changes + ReadableType type = color.getType(); + if (type.equals(ReadableType.Number)) { + floodColor = JavaOnlyArray.of(0, color.asInt()); + } else if (type.equals(ReadableType.Array)) { + floodColor = color.asArray(); + } else { + JavaOnlyArray arr = new JavaOnlyArray(); + arr.pushInt(0); + Matcher m = regex.matcher(color.asString()); + int i = 0; + while (m.find()) { + double parsed = Double.parseDouble(m.group()); + arr.pushDouble(i++ < 3 ? parsed / 255 : parsed); + } + floodColor = arr; + } + invalidate(); + } + + public void setFloodColor(@Nullable ReadableMap color) { + if (color == null) { + this.floodColor = null; + invalidate(); + return; + } + int type = color.getInt("type"); + if (type == 0) { + ReadableType payloadType = color.getType("payload"); + if (payloadType.equals(ReadableType.Number)) { + this.floodColor = JavaOnlyArray.of(0, color.getInt("payload")); + } else if (payloadType.equals(ReadableType.Map)) { + this.floodColor = JavaOnlyArray.of(0, color.getMap("payload")); + } + } else if (type == 1) { + this.floodColor = JavaOnlyArray.of(1, color.getString("brushRef")); + } else { + this.floodColor = JavaOnlyArray.of(type); + } + invalidate(); + } + + public void setFloodOpacity(float opacity) { + this.floodOpacity = opacity; + invalidate(); + } + + @Override + public Bitmap applyFilter(HashMap resultsMap, Bitmap prevResult) { + Bitmap floodBitmap = + Bitmap.createBitmap(prevResult.getWidth(), prevResult.getHeight(), Bitmap.Config.ARGB_8888); + Canvas floodCanvas = new Canvas(floodBitmap); + Paint paint = new Paint(); + paint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.SUBPIXEL_TEXT_FLAG); + paint.setStyle(Paint.Style.FILL); + this.setupPaint(paint, this.floodOpacity, this.floodColor); + floodCanvas.drawPaint(paint); + return floodBitmap; + } + + private void setupPaint(Paint paint, float opacity, @Nullable ReadableArray colors) { + int colorType = colors.getInt(0); + switch (colorType) { + case 0: + if (colors.size() == 2) { + int color; + if (colors.getType(1) == ReadableType.Map) { + color = ColorPropConverter.getColor(colors.getMap(1), getContext()); + } else { + color = colors.getInt(1); + } + int alpha = color >>> 24; + int combined = Math.round((float) alpha * opacity); + paint.setColor(combined << 24 | (color & 0x00ffffff)); + } else { + // solid color + paint.setARGB( + (int) (colors.size() > 4 ? colors.getDouble(4) * opacity * 255 : opacity * 255), + (int) (colors.getDouble(1) * 255), + (int) (colors.getDouble(2) * 255), + (int) (colors.getDouble(3) * 255)); + } + break; + // TODO: handle currentColor + } + } +} diff --git a/android/src/main/java/com/horcrux/svg/RenderableViewManager.java b/android/src/main/java/com/horcrux/svg/RenderableViewManager.java index 75e95b43d..9dd8838cc 100644 --- a/android/src/main/java/com/horcrux/svg/RenderableViewManager.java +++ b/android/src/main/java/com/horcrux/svg/RenderableViewManager.java @@ -105,6 +105,8 @@ import com.facebook.react.viewmanagers.RNSVGEllipseManagerInterface; import com.facebook.react.viewmanagers.RNSVGFeColorMatrixManagerDelegate; import com.facebook.react.viewmanagers.RNSVGFeColorMatrixManagerInterface; +import com.facebook.react.viewmanagers.RNSVGFeFloodManagerDelegate; +import com.facebook.react.viewmanagers.RNSVGFeFloodManagerInterface; import com.facebook.react.viewmanagers.RNSVGFeGaussianBlurManagerDelegate; import com.facebook.react.viewmanagers.RNSVGFeGaussianBlurManagerInterface; import com.facebook.react.viewmanagers.RNSVGFeMergeManagerDelegate; @@ -590,6 +592,7 @@ protected enum SVGClass { RNSVGMask, RNSVGFilter, RNSVGFeColorMatrix, + RNSVGFeFlood, RNSVGFeGaussianBlur, RNSVGFeMerge, RNSVGFeOffset, @@ -641,6 +644,8 @@ protected VirtualView createViewInstance(@Nonnull ThemedReactContext reactContex return new FilterView(reactContext); case RNSVGFeColorMatrix: return new FeColorMatrixView(reactContext); + case RNSVGFeFlood: + return new FeFloodView(reactContext); case RNSVGFeGaussianBlur: return new FeGaussianBlurView(reactContext); case RNSVGFeMerge: @@ -1605,6 +1610,30 @@ public void setValues(FeColorMatrixView node, @Nullable ReadableArray values) { } } + static class FeFloodManager extends FilterPrimitiveManager + implements RNSVGFeFloodManagerInterface { + FeFloodManager() { + super(SVGClass.RNSVGFeFlood); + mDelegate = new RNSVGFeFloodManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGFeFlood"; + + @ReactProp(name = "floodColor") + public void setFloodColor(FeFloodView node, @Nullable Dynamic strokeColors) { + node.setFloodColor(strokeColors); + } + + public void setFloodColor(FeFloodView view, @Nullable ReadableMap value) { + view.setFloodColor(value); + } + + @ReactProp(name = "floodOpacity", defaultFloat = 1f) + public void setFloodOpacity(FeFloodView node, float strokeOpacity) { + node.setFloodOpacity(strokeOpacity); + } + } + static class FeGaussianBlurManager extends FilterPrimitiveManager implements RNSVGFeGaussianBlurManagerInterface { FeGaussianBlurManager() { diff --git a/android/src/main/java/com/horcrux/svg/SvgPackage.java b/android/src/main/java/com/horcrux/svg/SvgPackage.java index 21cfa39eb..5d8edfc40 100644 --- a/android/src/main/java/com/horcrux/svg/SvgPackage.java +++ b/android/src/main/java/com/horcrux/svg/SvgPackage.java @@ -223,6 +223,15 @@ public NativeModule get() { return new FeColorMatrixManager(); } })); + specs.put( + FeFloodManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new FeFloodManager(); + } + })); specs.put( FeGaussianBlurManager.REACT_CLASS, ModuleSpec.viewManagerSpec( diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeFloodManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeFloodManagerDelegate.java new file mode 100644 index 000000000..9c57aa21c --- /dev/null +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeFloodManagerDelegate.java @@ -0,0 +1,50 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.DynamicFromObject; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGFeFloodManagerDelegate & RNSVGFeFloodManagerInterface> extends BaseViewManagerDelegate { + public RNSVGFeFloodManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "x": + mViewManager.setX(view, new DynamicFromObject(value)); + break; + case "y": + mViewManager.setY(view, new DynamicFromObject(value)); + break; + case "width": + mViewManager.setWidth(view, new DynamicFromObject(value)); + break; + case "height": + mViewManager.setHeight(view, new DynamicFromObject(value)); + break; + case "result": + mViewManager.setResult(view, value == null ? null : (String) value); + break; + case "floodColor": + mViewManager.setFloodColor(view, new DynamicFromObject(value)); + break; + case "floodOpacity": + mViewManager.setFloodOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeFloodManagerInterface.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeFloodManagerInterface.java new file mode 100644 index 000000000..0f9fc0f5e --- /dev/null +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeFloodManagerInterface.java @@ -0,0 +1,24 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.Dynamic; + +public interface RNSVGFeFloodManagerInterface { + void setX(T view, Dynamic value); + void setY(T view, Dynamic value); + void setWidth(T view, Dynamic value); + void setHeight(T view, Dynamic value); + void setResult(T view, @Nullable String value); + void setFloodColor(T view, Dynamic value); + void setFloodOpacity(T view, float value); +} diff --git a/apple/Filters/RNSVGFeFlood.h b/apple/Filters/RNSVGFeFlood.h new file mode 100644 index 000000000..27da9b1c7 --- /dev/null +++ b/apple/Filters/RNSVGFeFlood.h @@ -0,0 +1,9 @@ +#import "RNSVGBrush.h" +#import "RNSVGFilterPrimitive.h" + +@interface RNSVGFeFlood : RNSVGFilterPrimitive + +@property (nonatomic, strong) RNSVGBrush *floodColor; +@property (nonatomic, assign) CGFloat floodOpacity; + +@end diff --git a/apple/Filters/RNSVGFeFlood.mm b/apple/Filters/RNSVGFeFlood.mm new file mode 100644 index 000000000..75cff49f8 --- /dev/null +++ b/apple/Filters/RNSVGFeFlood.mm @@ -0,0 +1,91 @@ +#import "RNSVGFeFlood.h" + +#ifdef RCT_NEW_ARCH_ENABLED +#import +#import +#import +#import +#import "RNSVGConvert.h" +#import "RNSVGFabricConversions.h" +#endif // RCT_NEW_ARCH_ENABLED + +@implementation RNSVGFeFlood + +#ifdef RCT_NEW_ARCH_ENABLED +using namespace facebook::react; + +// Needed because of this: https://github.com/facebook/react-native/pull/37274 ++ (void)load +{ + [super load]; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + static const auto defaultProps = std::make_shared(); + _props = defaultProps; + } + return self; +} + +#pragma mark - RCTComponentViewProtocol + ++ (ComponentDescriptorProvider)componentDescriptorProvider +{ + return concreteComponentDescriptorProvider(); +} + +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps +{ + const auto &newProps = static_cast(*props); + + id floodColor = RNSVGConvertFollyDynamicToId(newProps.floodColor); + if (floodColor != nil) { + self.floodColor = [RCTConvert RNSVGBrush:floodColor]; + } + self.floodOpacity = newProps.floodOpacity; + + setCommonFilterProps(newProps, self); + _props = std::static_pointer_cast(props); +} + +- (void)prepareForRecycle +{ + [super prepareForRecycle]; + _floodColor = nil; + _floodOpacity = 1; +} +#endif // RCT_NEW_ARCH_ENABLED + +- (void)setFloodColor:(RNSVGBrush *)floodColor +{ + if (floodColor == _floodColor) { + return; + } + _floodColor = floodColor; + [self invalidate]; +} + +- (void)setFloodOpacity:(CGFloat)floodOpacity +{ + if (floodOpacity == _floodOpacity) { + return; + } + _floodOpacity = floodOpacity; + [self invalidate]; +} + +- (CIImage *)applyFilter:(NSMutableDictionary *)results previousFilterResult:(CIImage *)previous +{ + return [CIImage imageWithColor:[CIColor colorWithCGColor:[self.floodColor getColorWithOpacity:self.floodOpacity]]]; +} + +#ifdef RCT_NEW_ARCH_ENABLED +Class RNSVGFeFloodCls(void) +{ + return RNSVGFeFlood.class; +} +#endif // RCT_NEW_ARCH_ENABLED + +@end diff --git a/apple/ViewManagers/RNSVGFeFloodManager.h b/apple/ViewManagers/RNSVGFeFloodManager.h new file mode 100644 index 000000000..2f8be30a2 --- /dev/null +++ b/apple/ViewManagers/RNSVGFeFloodManager.h @@ -0,0 +1,5 @@ +#import "RNSVGFilterPrimitiveManager.h" + +@interface RNSVGFeFloodManager : RNSVGFilterPrimitiveManager + +@end diff --git a/apple/ViewManagers/RNSVGFeFloodManager.mm b/apple/ViewManagers/RNSVGFeFloodManager.mm new file mode 100644 index 000000000..9ee787331 --- /dev/null +++ b/apple/ViewManagers/RNSVGFeFloodManager.mm @@ -0,0 +1,16 @@ +#import "RNSVGFeFloodManager.h" +#import "RNSVGFeFlood.h" + +@implementation RNSVGFeFloodManager + +RCT_EXPORT_MODULE() + +- (RNSVGFeFlood *)node +{ + return [RNSVGFeFlood new]; +} + +RCT_EXPORT_VIEW_PROPERTY(floodColor, RNSVGBrush) +RCT_EXPORT_VIEW_PROPERTY(floodOpacity, CGFloat) + +@end diff --git a/apps/examples/src/examples/Filters/FeFlood.tsx b/apps/examples/src/examples/Filters/FeFlood.tsx new file mode 100644 index 000000000..be6446256 --- /dev/null +++ b/apps/examples/src/examples/Filters/FeFlood.tsx @@ -0,0 +1,141 @@ +import React, {Component} from 'react'; +import { + Circle, + FeFlood, + FeMerge, + FeMergeNode, + Filter, + G, + Line, + Rect, + Svg, + Use, +} from 'react-native-svg'; + +class BasicFlood extends Component { + static title = 'Basic MDN example with Use'; + render() { + return ( + + + + + + + ); + } +} + +class TestCase1 extends Component { + static title = 'Custom Test Case 1'; + render() { + return ( + + + + + + + + ); + } +} + +class TestCase2 extends Component { + static title = 'Custom Test Case 2'; + render() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + } +} + +const icon = ( + + + + + + + +); + +const samples = [BasicFlood, TestCase1, TestCase2]; +export {icon, samples}; diff --git a/apps/examples/src/examples/Filters/examples.tsx b/apps/examples/src/examples/Filters/examples.tsx index e71d053ec..9aed81701 100644 --- a/apps/examples/src/examples/Filters/examples.tsx +++ b/apps/examples/src/examples/Filters/examples.tsx @@ -1,10 +1,12 @@ import * as FeColorMatrix from './FeColorMatrix'; +import * as FeFlood from './FeFlood'; import * as FeGaussianBlur from './FeGaussianBlur'; import * as FeMerge from './FeMerge'; import * as FeOffset from './FeOffset'; import * as ReanimatedFeColorMatrix from './ReanimatedFeColorMatrix'; export { FeColorMatrix, + FeFlood, FeGaussianBlur, FeMerge, FeOffset, diff --git a/react-native.config.js b/react-native.config.js index 28470fcd2..bf02f021b 100644 --- a/react-native.config.js +++ b/react-native.config.js @@ -18,6 +18,7 @@ module.exports = { 'RNSVGClipPathComponentDescriptor', 'RNSVGDefsComponentDescriptor', 'RNSVGFeColorMatrixComponentDescriptor', + 'RNSVGFeFloodComponentDescriptor', 'RNSVGFeGaussianBlurComponentDescriptor', 'RNSVGFeMergeComponentDescriptor', 'RNSVGFeOffsetComponentDescriptor', diff --git a/src/elements/filters/FeFlood.tsx b/src/elements/filters/FeFlood.tsx index 8d530dfce..1aace13d1 100644 --- a/src/elements/filters/FeFlood.tsx +++ b/src/elements/filters/FeFlood.tsx @@ -1,6 +1,7 @@ -import { ColorValue } from 'react-native'; +import { ColorValue, NativeMethods } from 'react-native'; +import RNSVGFeFlood from '../../fabric/FeFloodNativeComponent'; +import extractFeFlood, { extractFilter } from '../../lib/extract/extractFilter'; import { NumberProp } from '../../lib/extract/types'; -import { warnUnimplementedFilter } from '../../lib/util'; import FilterPrimitive from './FilterPrimitive'; export interface FeFloodProps { @@ -12,12 +13,19 @@ export interface FeFloodProps { export default class FeFlood extends FilterPrimitive { static displayName = 'FeFlood'; - static defaultProps = { + static defaultProps: React.ComponentProps = { ...this.defaultPrimitiveProps, + floodColor: 'black', + floodOpacity: 1, }; render() { - warnUnimplementedFilter(); - return null; + return ( + this.refMethod(ref as (FeFlood & NativeMethods) | null)} + {...extractFilter(this.props)} + {...extractFeFlood(this.props)} + /> + ); } } diff --git a/src/fabric/FeFloodNativeComponent.ts b/src/fabric/FeFloodNativeComponent.ts new file mode 100644 index 000000000..82d2b68ee --- /dev/null +++ b/src/fabric/FeFloodNativeComponent.ts @@ -0,0 +1,31 @@ +import type { ColorValue } from 'react-native'; +import type { + Float, + Int32, + WithDefault, +} from 'react-native/Libraries/Types/CodegenTypes'; +import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; +import type { NumberProp } from '../lib/extract/types'; +import type { UnsafeMixed } from './codegenUtils'; +import type { ViewProps } from './utils'; + +interface FilterPrimitiveCommonProps { + x?: UnsafeMixed; + y?: UnsafeMixed; + width?: UnsafeMixed; + height?: UnsafeMixed; + result?: string; +} + +type ColorStruct = Readonly<{ + type?: WithDefault; + payload?: ColorValue; + brushRef?: string; +}>; + +export interface NativeProps extends ViewProps, FilterPrimitiveCommonProps { + floodColor?: UnsafeMixed; + floodOpacity?: WithDefault; +} + +export default codegenNativeComponent('RNSVGFeFlood'); diff --git a/src/fabric/index.ts b/src/fabric/index.ts index 8cdbb4f77..a89fbdee6 100644 --- a/src/fabric/index.ts +++ b/src/fabric/index.ts @@ -22,6 +22,7 @@ import RNSVGTSpan from './TSpanNativeComponent'; import RNSVGUse from './UseNativeComponent'; import RNSVGFilter from './FilterNativeComponent'; import RNSVGFeColorMatrix from './FeColorMatrixNativeComponent'; +import RNSVGFeFlood from './FeFloodNativeComponent'; import RNSVGFeGaussianBlur from './FeGaussianBlurNativeComponent'; import RNSVGFeMerge from './FeMergeNativeComponent'; import RNSVGFeOffset from './FeOffsetNativeComponent'; @@ -51,6 +52,7 @@ export { RNSVGUse, RNSVGFilter, RNSVGFeColorMatrix, + RNSVGFeFlood, RNSVGFeGaussianBlur, RNSVGFeMerge, RNSVGFeOffset, diff --git a/src/lib/extract/extractFilter.ts b/src/lib/extract/extractFilter.ts index 672194542..e198df22f 100644 --- a/src/lib/extract/extractFilter.ts +++ b/src/lib/extract/extractFilter.ts @@ -1,10 +1,15 @@ import React from 'react'; +import { ColorValue, processColor } from 'react-native'; import { FeColorMatrixProps as FeColorMatrixComponentProps } from '../../elements/filters/FeColorMatrix'; +import { FeFloodProps as FeFloodComponentProps } from '../../elements/filters/FeFlood'; import { FeGaussianBlurProps as FeGaussianBlurComponentProps } from '../../elements/filters/FeGaussianBlur'; import { FeMergeProps as FeMergeComponentProps } from '../../elements/filters/FeMerge'; import { NativeProps as FeColorMatrixNativeProps } from '../../fabric/FeColorMatrixNativeComponent'; +import { NativeProps as FeFloodNativeProps } from '../../fabric/FeFloodNativeComponent'; import { NativeProps as FeGaussianBlurNativeProps } from '../../fabric/FeGaussianBlurNativeComponent'; import { NativeProps as FeMergeNativeProps } from '../../fabric/FeMergeNativeComponent'; +import extractBrush from './extractBrush'; +import extractOpacity from './extractOpacity'; import { NumberProp } from './types'; const spaceReg = /\s+/; @@ -67,6 +72,28 @@ export const extractFeColorMatrix = ( return extracted; }; +const defaultFill = { type: 0, payload: processColor('black') as ColorValue }; +export default function extractFeFlood( + props: FeFloodComponentProps +): FeFloodNativeProps { + const extracted: FeFloodNativeProps = {}; + const { floodColor, floodOpacity } = props; + + if (floodColor != null) { + extracted.floodColor = + !floodColor && typeof floodColor !== 'number' + ? defaultFill + : (extractBrush(floodColor) as unknown as string); + } else { + // we want the default value of fill to be black to match the spec + extracted.floodColor = defaultFill; + } + if (floodOpacity != null) { + extracted.floodOpacity = extractOpacity(floodOpacity); + } + return extracted; +} + export const extractFeGaussianBlur = ( props: FeGaussianBlurComponentProps ): FeGaussianBlurNativeProps => {