UNPKG

@shopify/react-native-skia

Version:

High-performance React Native Graphics using Skia

171 lines (157 loc) 5.01 kB
import { enumKey, processPath } from "../../../dom/nodes"; import { NodeType } from "../../../dom/types"; import type { CornerPathEffectProps, DashPathEffectProps, DiscretePathEffectProps, Line2DPathEffectProps, Path1DPathEffectProps, Path2DPathEffectProps, } from "../../../dom/types"; import { Path1DEffectStyle } from "../../../skia/types"; import { composeDeclarations } from "../../utils"; import type { Command } from "../Core"; import { CommandType } from "../Core"; import type { DrawingContext } from "../DrawingContext"; const declareDiscretePathEffect = ( ctx: DrawingContext, props: DiscretePathEffectProps ) => { "worklet"; const { length, deviation, seed } = props; const pe = ctx.Skia.PathEffect.MakeDiscrete(length, deviation, seed); ctx.pathEffects.push(pe); }; const declarePath2DPathEffect = ( ctx: DrawingContext, props: Path2DPathEffectProps ) => { "worklet"; const { matrix } = props; const path = processPath(ctx.Skia, props.path); const pe = ctx.Skia.PathEffect.MakePath2D(matrix, path); if (pe === null) { throw new Error("Path2DPathEffect: invalid path"); } ctx.pathEffects.push(pe); }; const declareDashPathEffect = ( ctx: DrawingContext, props: DashPathEffectProps ) => { "worklet"; const { intervals, phase } = props; const pe = ctx.Skia.PathEffect.MakeDash(intervals, phase); ctx.pathEffects.push(pe); }; const declareCornerPathEffect = ( ctx: DrawingContext, props: CornerPathEffectProps ) => { "worklet"; const { r } = props; const pe = ctx.Skia.PathEffect.MakeCorner(r); if (pe === null) { throw new Error("CornerPathEffect: couldn't create path effect"); } ctx.pathEffects.push(pe); }; const declareSumPathEffect = (ctx: DrawingContext) => { "worklet"; // Note: decorateChildren functionality needs to be handled differently const pes = ctx.pathEffects.splice(0, ctx.pathEffects.length); const pe = composeDeclarations( pes, ctx.Skia.PathEffect.MakeSum.bind(ctx.Skia.PathEffect) ); ctx.pathEffects.push(pe); }; const declareLine2DPathEffect = ( ctx: DrawingContext, props: Line2DPathEffectProps ) => { "worklet"; const { width, matrix } = props; const pe = ctx.Skia.PathEffect.MakeLine2D(width, matrix); if (pe === null) { throw new Error("Line2DPathEffect: could not create path effect"); } ctx.pathEffects.push(pe); }; const declarePath1DPathEffect = ( ctx: DrawingContext, props: Path1DPathEffectProps ) => { "worklet"; const { advance, phase, style } = props; const path = processPath(ctx.Skia, props.path); const pe = ctx.Skia.PathEffect.MakePath1D( path, advance, phase, Path1DEffectStyle[enumKey(style)] ); if (pe === null) { throw new Error("Path1DPathEffect: could not create path effect"); } ctx.pathEffects.push(pe); }; export const isPushPathEffect = ( command: Command ): command is Command<CommandType.PushPathEffect> => { "worklet"; return command.type === CommandType.PushPathEffect; }; type Props = { [NodeType.DiscretePathEffect]: DiscretePathEffectProps; [NodeType.DashPathEffect]: DashPathEffectProps; [NodeType.Path1DPathEffect]: Path1DPathEffectProps; [NodeType.Path2DPathEffect]: Path2DPathEffectProps; [NodeType.CornerPathEffect]: CornerPathEffectProps; [NodeType.SumPathEffect]: Record<string, never>; [NodeType.Line2DPathEffect]: Line2DPathEffectProps; }; interface PushPathEffect< T extends keyof Props, > extends Command<CommandType.PushPathEffect> { pathEffectType: T; props: Props[T]; } const isPathEffect = <T extends keyof Props>( command: Command<CommandType.PushPathEffect>, type: T ): command is PushPathEffect<T> => { "worklet"; return command.pathEffectType === type; }; export const composePathEffects = (ctx: DrawingContext) => { "worklet"; if (ctx.pathEffects.length > 1) { const outer = ctx.pathEffects.pop()!; const inner = ctx.pathEffects.pop()!; ctx.pathEffects.push(ctx.Skia.PathEffect.MakeCompose(outer, inner)); } }; export const pushPathEffect = ( ctx: DrawingContext, command: Command<CommandType.PushPathEffect> ) => { "worklet"; if (isPathEffect(command, NodeType.DiscretePathEffect)) { declareDiscretePathEffect(ctx, command.props); } else if (isPathEffect(command, NodeType.DashPathEffect)) { declareDashPathEffect(ctx, command.props); } else if (isPathEffect(command, NodeType.Path1DPathEffect)) { declarePath1DPathEffect(ctx, command.props); } else if (isPathEffect(command, NodeType.Path2DPathEffect)) { declarePath2DPathEffect(ctx, command.props); } else if (isPathEffect(command, NodeType.CornerPathEffect)) { declareCornerPathEffect(ctx, command.props); } else if (isPathEffect(command, NodeType.SumPathEffect)) { declareSumPathEffect(ctx); } else if (isPathEffect(command, NodeType.Line2DPathEffect)) { declareLine2DPathEffect(ctx, command.props); } else { throw new Error("Invalid image filter type: " + command.imageFilterType); } };