From 28af2d4ab72996a21b91ca3694143b90bdd0168f Mon Sep 17 00:00:00 2001 From: William Candillon Date: Fri, 28 Jun 2024 20:02:09 +0200 Subject: [PATCH 01/12] :one: --- package/src/dom/nodes/datatypes/Circle.ts | 7 +- package/src/dom/nodes/datatypes/Enum.ts | 6 +- package/src/dom/nodes/datatypes/Path.ts | 7 +- package/src/dom/nodes/datatypes/Rect.ts | 15 +- package/src/sg/ColorFilters.ts | 0 package/src/sg/Common.ts | 7 + package/src/sg/Drawing.ts | 241 ++++++++++++++++++++++ package/src/sg/ImageFilters.ts | 0 package/src/sg/MaskFilters.ts | 0 package/src/sg/Mixed.ts | 0 package/src/sg/Paragraph.ts | 0 package/src/sg/PathEffects.ts | 0 package/src/sg/SceneGraph.ts | 96 +++++++++ package/src/sg/Shaders.ts | 0 package/src/sg/Text.ts | 23 +++ 15 files changed, 392 insertions(+), 10 deletions(-) create mode 100644 package/src/sg/ColorFilters.ts create mode 100644 package/src/sg/Common.ts create mode 100644 package/src/sg/Drawing.ts create mode 100644 package/src/sg/ImageFilters.ts create mode 100644 package/src/sg/MaskFilters.ts create mode 100644 package/src/sg/Mixed.ts create mode 100644 package/src/sg/Paragraph.ts create mode 100644 package/src/sg/PathEffects.ts create mode 100644 package/src/sg/SceneGraph.ts create mode 100644 package/src/sg/Shaders.ts create mode 100644 package/src/sg/Text.ts diff --git a/package/src/dom/nodes/datatypes/Circle.ts b/package/src/dom/nodes/datatypes/Circle.ts index 6fc473b19a..18db2da3eb 100644 --- a/package/src/dom/nodes/datatypes/Circle.ts +++ b/package/src/dom/nodes/datatypes/Circle.ts @@ -1,12 +1,15 @@ import type { Skia } from "../../../skia/types"; import type { CircleDef, ScalarCircleDef } from "../../types"; -export const isCircleScalarDef = (def: CircleDef): def is ScalarCircleDef => +export const isCircleScalarDef = (def: CircleDef): def is ScalarCircleDef => { + "worklet"; // We have an issue to check property existence on JSI backed instances // eslint-disable-next-line @typescript-eslint/no-explicit-any - (def as any).cx !== undefined; + return (def as any).cx !== undefined; +}; export const processCircle = (Skia: Skia, def: CircleDef) => { + "worklet"; if (isCircleScalarDef(def)) { return { c: Skia.Point(def.cx, def.cy), r: def.r }; } diff --git a/package/src/dom/nodes/datatypes/Enum.ts b/package/src/dom/nodes/datatypes/Enum.ts index 361c589fa8..1184e523d1 100644 --- a/package/src/dom/nodes/datatypes/Enum.ts +++ b/package/src/dom/nodes/datatypes/Enum.ts @@ -1,2 +1,4 @@ -export const enumKey = (k: K) => - (k.charAt(0).toUpperCase() + k.slice(1)) as Capitalize; +export const enumKey = (k: K) => { + "worklet"; + return (k.charAt(0).toUpperCase() + k.slice(1)) as Capitalize; +}; diff --git a/package/src/dom/nodes/datatypes/Path.ts b/package/src/dom/nodes/datatypes/Path.ts index 547839efec..da2fbe6b9d 100644 --- a/package/src/dom/nodes/datatypes/Path.ts +++ b/package/src/dom/nodes/datatypes/Path.ts @@ -3,6 +3,7 @@ import { isPath } from "../../../skia/types"; import type { PathDef } from "../../types"; export const processPath = (Skia: Skia, rawPath: PathDef) => { + "worklet"; const path = typeof rawPath === "string" ? Skia.Path.MakeFromSVGString(rawPath) @@ -14,5 +15,7 @@ export const processPath = (Skia: Skia, rawPath: PathDef) => { }; // eslint-disable-next-line @typescript-eslint/no-explicit-any -export const isPathDef = (def: any): def is PathDef => - typeof def === "string" || isPath(def); +export const isPathDef = (def: any): def is PathDef => { + "worklet"; + return typeof def === "string" || isPath(def); +}; diff --git a/package/src/dom/nodes/datatypes/Rect.ts b/package/src/dom/nodes/datatypes/Rect.ts index a93c97d4c9..eee892680b 100644 --- a/package/src/dom/nodes/datatypes/Rect.ts +++ b/package/src/dom/nodes/datatypes/Rect.ts @@ -12,13 +12,19 @@ export const isEdge = (pos: Vector, b: SkRect) => { }; // We have an issue to check property existence on JSI backed instances -const isRRectCtor = (def: RRectDef): def is RRectCtor => - (def as any).rect === undefined; +const isRRectCtor = (def: RRectDef): def is RRectCtor => { + "worklet"; + return (def as any).rect === undefined; +}; + // We have an issue to check property existence on JSI backed instances -const isRectCtor = (def: RectDef): def is RectCtor => - (def as any).rect === undefined; +const isRectCtor = (def: RectDef): def is RectCtor => { + "worklet"; + return (def as any).rect === undefined; +}; export const processRect = (Skia: Skia, def: RectDef) => { + "worklet"; if (isRectCtor(def)) { return Skia.XYWHRect(def.x ?? 0, def.y ?? 0, def.width, def.height); } else { @@ -27,6 +33,7 @@ export const processRect = (Skia: Skia, def: RectDef) => { }; export const processRRect = (Skia: Skia, def: RRectDef) => { + "worklet"; if (isRRectCtor(def)) { const r = processRadius(Skia, def.r ?? 0); return Skia.RRectXY( diff --git a/package/src/sg/ColorFilters.ts b/package/src/sg/ColorFilters.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/package/src/sg/Common.ts b/package/src/sg/Common.ts new file mode 100644 index 0000000000..916ddf8f98 --- /dev/null +++ b/package/src/sg/Common.ts @@ -0,0 +1,7 @@ +import type { SkCanvas, SkPaint, Skia } from "../skia/types"; + +export interface DrawingContext { + Skia: Skia; + canvas: SkCanvas; + paint: SkPaint; +} diff --git a/package/src/sg/Drawing.ts b/package/src/sg/Drawing.ts new file mode 100644 index 0000000000..70999f3689 --- /dev/null +++ b/package/src/sg/Drawing.ts @@ -0,0 +1,241 @@ +import type { + AtlasProps, + CircleProps, + DiffRectProps, + ImageProps, + ImageSVGProps, + LineProps, + OvalProps, + PatchProps, + PathProps, + PictureProps, + PointsProps, + RectProps, + RoundedRectProps, + VerticesProps, +} from "../dom/nodes"; +import { + enumKey, + fitRects, + processCircle, + processPath, + processRRect, + processRect, +} from "../dom/nodes"; +import { saturate } from "../renderer"; +import { BlendMode, FillType, PointMode, VertexMode } from "../skia"; +import type { Skia } from "../skia/types"; + +import type { DrawingContext } from "./Common"; + +export const renderCircle = (ctx: DrawingContext, props: CircleProps) => { + "worklet"; + const { c, r } = processCircle(ctx.Skia, props); + ctx.canvas.drawCircle(c.x, c.y, r, ctx.paint); +}; + +export const renderFill = (ctx: DrawingContext) => { + "worklet"; + ctx.canvas.drawPaint(ctx.paint); +}; + +export const renderPoints = (ctx: DrawingContext, props: PointsProps) => { + "worklet"; + const { points, mode } = props; + ctx.canvas.drawPoints(PointMode[enumKey(mode)], points, ctx.paint); +}; + +const computePath = (ctx: DrawingContext, props: PathProps) => { + "worklet"; + const { + start: trimStart, + end: trimEnd, + fillType, + stroke, + ...pathProps + } = props; + const start = saturate(trimStart); + const end = saturate(trimEnd); + const hasStartOffset = start !== 0; + const hasEndOffset = end !== 1; + const hasStrokeOptions = stroke !== undefined; + const hasFillType = !!fillType; + const willMutatePath = + hasStartOffset || hasEndOffset || hasStrokeOptions || hasFillType; + const pristinePath = processPath(ctx.Skia, pathProps.path); + const path = willMutatePath ? pristinePath.copy() : pristinePath; + if (hasFillType) { + path.setFillType(FillType[enumKey(fillType)]); + } + if (hasStrokeOptions) { + path.stroke(stroke); + } + if (hasStartOffset || hasEndOffset) { + path.trim(start, end, false); + } + return path; +}; + +export const renderPath = (ctx: DrawingContext, props: PathProps) => { + "worklet"; + const path = computePath(ctx, props); + ctx.canvas.drawPath(path, ctx.paint); +}; + +export const renderRect = (ctx: DrawingContext, props: RectProps) => { + "worklet"; + const rect = processRect(ctx.Skia, props); + ctx.canvas.drawRect(rect, ctx.paint); +}; + +export const renderRRect = (ctx: DrawingContext, props: RoundedRectProps) => { + "worklet"; + const rrect = processRRect(ctx.Skia, props); + ctx.canvas.drawRRect(rrect, ctx.paint); +}; + +export const renderOval = (ctx: DrawingContext, props: OvalProps) => { + "worklet"; + const oval = processRect(ctx.Skia, props); + ctx.canvas.drawOval(oval, ctx.paint); +}; + +const processImage = (Skia: Skia, props: ImageProps) => { + "worklet"; + const { image } = props; + if (!image) { + return { + src: { x: 0, y: 0, width: 0, height: 0 }, + dst: { x: 0, y: 0, width: 0, height: 0 }, + }; + } + const fit = props.fit ?? "contain"; + const rect = processRect(Skia, props); + const { src, dst } = fitRects( + fit, + { + x: 0, + y: 0, + width: image.width(), + height: image.height(), + }, + rect + ); + return { src, dst }; +}; + +export const renderImage = (ctx: DrawingContext, props: ImageProps) => { + "worklet"; + const { image } = props; + const { src, dst } = processImage(ctx.Skia, props); + if (!image) { + return; + } + ctx.canvas.drawImageRect(image, src, dst, ctx.paint); +}; + +export const renderLine = (ctx: DrawingContext, props: LineProps) => { + "worklet"; + const { p1, p2 } = props; + ctx.canvas.drawLine(p1.x, p1.y, p2.x, p2.y, ctx.paint); +}; + +const processPatch = (Skia: Skia, props: PatchProps) => { + "worklet"; + const { colors, blendMode, patch } = props; + const defaultBlendMode = colors ? BlendMode.DstOver : BlendMode.SrcOver; + const mode = blendMode ? BlendMode[enumKey(blendMode)] : defaultBlendMode; + // Patch requires a path with the following constraints: + // M tl + // C c1 c2 br + // C c1 c2 bl + // C c1 c2 tl (the redundant point in the last command is removed) + return { + mode, + points: [ + patch[0].pos, + patch[0].c2, + patch[1].c1, + patch[1].pos, + patch[1].c2, + patch[2].c1, + patch[2].pos, + patch[2].c2, + patch[3].c1, + patch[3].pos, + patch[3].c2, + patch[0].c1, + ], + colors: colors ? colors.map((c) => Skia.Color(c)) : undefined, + }; +}; + +export const renderPatch = (ctx: DrawingContext, props: PatchProps) => { + "worklet"; + const { texture } = props; + const { colors, points, mode } = processPatch(ctx.Skia, props); + ctx.canvas.drawPatch(points, colors, texture, mode, ctx.paint); +}; + +export const renderVertices = (ctx: DrawingContext, props: VerticesProps) => { + "worklet"; + const { colors, blendMode } = props; + const defaultBlendMode = colors ? BlendMode.DstOver : BlendMode.SrcOver; + const blend = blendMode ? BlendMode[enumKey(blendMode)] : defaultBlendMode; + const { mode, vertices, textures, indices } = props; + const vertexMode = mode ? VertexMode[enumKey(mode)] : VertexMode.Triangles; + const vert = ctx.Skia.MakeVertices( + vertexMode, + vertices, + textures, + colors ? colors.map((c) => ctx.Skia.Color(c)) : undefined, + indices + ); + ctx.canvas.drawVertices(vert, blend, ctx.paint); +}; + +export const renderDiffRect = (ctx: DrawingContext, props: DiffRectProps) => { + "worklet"; + const { outer, inner } = props; + ctx.canvas.drawDRRect(outer, inner, ctx.paint); +}; + +export const renderPicture = (ctx: DrawingContext, props: PictureProps) => { + "worklet"; + const { picture } = props; + ctx.canvas.drawPicture(picture); +}; + +const processImageSVG = (props: ImageSVGProps) => { + "worklet"; + if (props.rect) { + return props.rect; + } + const { x, y, width, height } = props; + return { x, y, width, height }; +}; + +export const renderImageSVG = (ctx: DrawingContext, props: ImageSVGProps) => { + "worklet"; + const { svg } = props; + + const { x, y, width, height } = processImageSVG(props); + if (svg === null) { + return; + } + ctx.canvas.save(); + if (x && y) { + ctx.canvas.translate(x, y); + } + ctx.canvas.drawSvg(svg, width, height); + ctx.canvas.restore(); +}; + +export const renderAtlas = (ctx: DrawingContext, props: AtlasProps) => { + "worklet"; + const { image, sprites, transforms, colors, blendMode } = props; + const blend = blendMode ? BlendMode[enumKey(blendMode)] : undefined; + if (image) { + ctx.canvas.drawAtlas(image, sprites, transforms, ctx.paint, blend, colors); + } +}; diff --git a/package/src/sg/ImageFilters.ts b/package/src/sg/ImageFilters.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/package/src/sg/MaskFilters.ts b/package/src/sg/MaskFilters.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/package/src/sg/Mixed.ts b/package/src/sg/Mixed.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/package/src/sg/Paragraph.ts b/package/src/sg/Paragraph.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/package/src/sg/PathEffects.ts b/package/src/sg/PathEffects.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/package/src/sg/SceneGraph.ts b/package/src/sg/SceneGraph.ts new file mode 100644 index 0000000000..10f13d8976 --- /dev/null +++ b/package/src/sg/SceneGraph.ts @@ -0,0 +1,96 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { NodeType } from "../dom/types"; +import type { AnimatedProps } from "../renderer"; +import Rea from "../external/reanimated/ReanimatedProxy"; +import { exhaustiveCheck } from "../renderer/typeddash"; + +import type { DrawingContext } from "./Common"; +import { + renderAtlas, + renderCircle, + renderDiffRect, + renderFill, + renderImageSVG, + renderLine, + renderOval, + renderPatch, + renderPath, + renderPicture, + renderPoints, + renderRRect, + renderRect, + renderVertices, +} from "./Drawing"; + +type UnknownProps = Record; + +interface SGNode

{ + type: NodeType; + props: AnimatedProps

; + children: SGNode[]; +} + +const materialize =

(props: AnimatedProps

) => { + "worklet"; + const materializedProps: Record = {}; + for (const key in props) { + const value = props[key]; + if (Rea.isSharedValue(value)) { + materializedProps[key] = value.value; + } else { + materializedProps[key] = value; + } + } + return materializedProps as any; +}; + +export const renderNode = (ctx: DrawingContext, node: SGNode) => { + "worklet"; + const materializedProps = materialize(node.props); + switch (node.type) { + case NodeType.Circle: + return renderCircle(ctx, materializedProps); + case NodeType.Fill: + return renderFill(ctx); + case NodeType.Points: + return renderPoints(ctx, materializedProps); + case NodeType.Path: + return renderPath(ctx, materializedProps); + case NodeType.Rect: + return renderRect(ctx, materializedProps); + case NodeType.RRect: + return renderRRect(ctx, materializedProps); + case NodeType.Oval: + return renderOval(ctx, materializedProps); + // case NodeType.Group: + // return renderGroup(ctx, materializedProps); + // case NodeType.Paint: + // return renderPaint(ctx, materializedProps); + // case NodeType.Image: + // return renderImage(ctx, materializedProps); + case NodeType.Line: + return renderLine(ctx, materializedProps); + case NodeType.Patch: + return renderPatch(ctx, materializedProps); + case NodeType.Vertices: + return renderVertices(ctx, materializedProps); + case NodeType.DiffRect: + return renderDiffRect(ctx, materializedProps); + // case NodeType.Text: + // return renderText(ctx, materializedProps); + // case NodeType.TextPath: + // return renderTextPath(ctx, materializedProps); + // case NodeType.TextBlob: + // return renderTextBlob(ctx, materializedProps); + // case NodeType.Glyphs: + // return renderGlyphs(ctx, materializedProps); + case NodeType.Picture: + return renderPicture(ctx, materializedProps); + case NodeType.ImageSVG: + return renderImageSVG(ctx, materializedProps); + case NodeType.Atlas: + return renderAtlas(ctx, materializedProps); + default: + return exhaustiveCheck(node.type); + } +}; diff --git a/package/src/sg/Shaders.ts b/package/src/sg/Shaders.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/package/src/sg/Text.ts b/package/src/sg/Text.ts new file mode 100644 index 0000000000..17de95f1ce --- /dev/null +++ b/package/src/sg/Text.ts @@ -0,0 +1,23 @@ +export const renderText = (ctx: DrawingContext, props: TextProps) => { + "worklet"; + const { text, x, y, font } = processText(ctx.Skia, props); + ctx.canvas.drawText(text, x, y, font, ctx.paint); +}; + +export const renderTextPath = (ctx: DrawingContext, props: TextPathProps) => { + "worklet"; + const { text, path, font } = processTextPath(ctx.Skia, props); + ctx.canvas.drawTextOnPath(text, path, font, ctx.paint); +}; + +export const renderTextBlob = (ctx: DrawingContext, props: TextBlobProps) => { + "worklet"; + const { textBlob, x, y } = processTextBlob(ctx.Skia, props); + ctx.canvas.drawTextBlob(textBlob, x, y, ctx.paint); +}; + +export const renderGlyphs = (ctx: DrawingContext, props: GlyphsProps) => { + "worklet"; + const { glyphs, positions, font } = processGlyphs(ctx.Skia, props); + ctx.canvas.drawGlyphs(glyphs, positions, font, ctx.paint); +}; From b1de84385b0937b6bd5770c919b76f944dd08435 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Fri, 28 Jun 2024 20:25:18 +0200 Subject: [PATCH 02/12] :wrench: --- package/src/sg/Common.ts | 7 ------- package/src/sg/Context.ts | 16 ++++++++++++++++ package/src/sg/Drawing.ts | 2 +- package/src/sg/SceneGraph.ts | 11 ++++++++++- 4 files changed, 27 insertions(+), 9 deletions(-) delete mode 100644 package/src/sg/Common.ts create mode 100644 package/src/sg/Context.ts diff --git a/package/src/sg/Common.ts b/package/src/sg/Common.ts deleted file mode 100644 index 916ddf8f98..0000000000 --- a/package/src/sg/Common.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { SkCanvas, SkPaint, Skia } from "../skia/types"; - -export interface DrawingContext { - Skia: Skia; - canvas: SkCanvas; - paint: SkPaint; -} diff --git a/package/src/sg/Context.ts b/package/src/sg/Context.ts new file mode 100644 index 0000000000..e08d354165 --- /dev/null +++ b/package/src/sg/Context.ts @@ -0,0 +1,16 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import type { SkCanvas, SkPaint, Skia } from "../skia/types"; + +export interface DrawingContext { + Skia: Skia; + canvas: SkCanvas; + paint: SkPaint; +} + +export const processContext = ( + ctx: DrawingContext, + props: Record +) => { + "worklet"; + return { restore: false, restorePaint: false }; +}; diff --git a/package/src/sg/Drawing.ts b/package/src/sg/Drawing.ts index 70999f3689..61c191e3ba 100644 --- a/package/src/sg/Drawing.ts +++ b/package/src/sg/Drawing.ts @@ -26,7 +26,7 @@ import { saturate } from "../renderer"; import { BlendMode, FillType, PointMode, VertexMode } from "../skia"; import type { Skia } from "../skia/types"; -import type { DrawingContext } from "./Common"; +import type { DrawingContext } from "./Context"; export const renderCircle = (ctx: DrawingContext, props: CircleProps) => { "worklet"; diff --git a/package/src/sg/SceneGraph.ts b/package/src/sg/SceneGraph.ts index 10f13d8976..ec7adc5489 100644 --- a/package/src/sg/SceneGraph.ts +++ b/package/src/sg/SceneGraph.ts @@ -4,7 +4,7 @@ import type { AnimatedProps } from "../renderer"; import Rea from "../external/reanimated/ReanimatedProxy"; import { exhaustiveCheck } from "../renderer/typeddash"; -import type { DrawingContext } from "./Common"; +import { processContext, type DrawingContext } from "./Context"; import { renderAtlas, renderCircle, @@ -47,6 +47,9 @@ const materialize =

(props: AnimatedProps

) => { export const renderNode = (ctx: DrawingContext, node: SGNode) => { "worklet"; const materializedProps = materialize(node.props); + const { restore, restorePaint } = processContext(ctx, materializedProps); + //const { invertClip, layer, matrix, transform } = materializedProps; + switch (node.type) { case NodeType.Circle: return renderCircle(ctx, materializedProps); @@ -93,4 +96,10 @@ export const renderNode = (ctx: DrawingContext, node: SGNode) => { default: return exhaustiveCheck(node.type); } + if (restore) { + ctx.canvas.restore(); + } + if (restorePaint) { + //ctx.paint.restore(); + } }; From dc74e46088aea8165ebcf76cdc8b98bf318e34dd Mon Sep 17 00:00:00 2001 From: William Candillon Date: Mon, 1 Jul 2024 08:31:59 +0200 Subject: [PATCH 03/12] :wrench: --- package/src/sg/Context.ts | 20 ++++++++++++- package/src/sg/Drawing.ts | 3 ++ package/src/sg/Node.ts | 24 ++++++++++++++++ package/src/sg/SceneGraph.ts | 54 ++++++++++++++++++++---------------- 4 files changed, 76 insertions(+), 25 deletions(-) create mode 100644 package/src/sg/Node.ts diff --git a/package/src/sg/Context.ts b/package/src/sg/Context.ts index e08d354165..9720a06be7 100644 --- a/package/src/sg/Context.ts +++ b/package/src/sg/Context.ts @@ -1,5 +1,14 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { SkCanvas, SkPaint, Skia } from "../skia/types"; +import type { + SkCanvas, + SkColorFilter, + SkImageFilter, + SkMaskFilter, + SkPaint, + SkPathEffect, + SkShader, + Skia, +} from "../skia/types"; export interface DrawingContext { Skia: Skia; @@ -7,6 +16,15 @@ export interface DrawingContext { paint: SkPaint; } +export interface PaintingContext { + paints: SkPaint[]; + maskFilters: SkMaskFilter[]; + shaders: SkShader[]; + pathEffects: SkPathEffect[]; + imageFilters: SkImageFilter[]; + colorFilters: SkColorFilter[]; +} + export const processContext = ( ctx: DrawingContext, props: Record diff --git a/package/src/sg/Drawing.ts b/package/src/sg/Drawing.ts index 61c191e3ba..5c5ed88d8d 100644 --- a/package/src/sg/Drawing.ts +++ b/package/src/sg/Drawing.ts @@ -1,3 +1,5 @@ +import type { AnimatedProps } from "react-native-reanimated"; + import type { AtlasProps, CircleProps, @@ -13,6 +15,7 @@ import type { RectProps, RoundedRectProps, VerticesProps, + NodeType, } from "../dom/nodes"; import { enumKey, diff --git a/package/src/sg/Node.ts b/package/src/sg/Node.ts new file mode 100644 index 0000000000..870f643af1 --- /dev/null +++ b/package/src/sg/Node.ts @@ -0,0 +1,24 @@ +import type { CircleProps, NodeType } from "../dom/types"; +import type { AnimatedProps } from "../renderer"; + +export interface PropMap { + [NodeType.Circle]: CircleProps; + [name: string]: object; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type UnknownProps = Record; + +export interface SGNode

{ + type: NodeType; + props: AnimatedProps

; + // children?: SGNode[]; +} + +export const createNode = ( + type: T, + props: AnimatedProps +): SGNode => { + "worklet"; + return { type, props }; +}; diff --git a/package/src/sg/SceneGraph.ts b/package/src/sg/SceneGraph.ts index ec7adc5489..ba90f6d2f7 100644 --- a/package/src/sg/SceneGraph.ts +++ b/package/src/sg/SceneGraph.ts @@ -2,7 +2,6 @@ import { NodeType } from "../dom/types"; import type { AnimatedProps } from "../renderer"; import Rea from "../external/reanimated/ReanimatedProxy"; -import { exhaustiveCheck } from "../renderer/typeddash"; import { processContext, type DrawingContext } from "./Context"; import { @@ -22,14 +21,6 @@ import { renderVertices, } from "./Drawing"; -type UnknownProps = Record; - -interface SGNode

{ - type: NodeType; - props: AnimatedProps

; - children: SGNode[]; -} - const materialize =

(props: AnimatedProps

) => { "worklet"; const materializedProps: Record = {}; @@ -52,19 +43,26 @@ export const renderNode = (ctx: DrawingContext, node: SGNode) => { switch (node.type) { case NodeType.Circle: - return renderCircle(ctx, materializedProps); + renderCircle(ctx, materializedProps); + break; case NodeType.Fill: - return renderFill(ctx); + renderFill(ctx); + break; case NodeType.Points: - return renderPoints(ctx, materializedProps); + renderPoints(ctx, materializedProps); + break; case NodeType.Path: - return renderPath(ctx, materializedProps); + renderPath(ctx, materializedProps); + break; case NodeType.Rect: - return renderRect(ctx, materializedProps); + renderRect(ctx, materializedProps); + break; case NodeType.RRect: - return renderRRect(ctx, materializedProps); + renderRRect(ctx, materializedProps); + break; case NodeType.Oval: - return renderOval(ctx, materializedProps); + renderOval(ctx, materializedProps); + break; // case NodeType.Group: // return renderGroup(ctx, materializedProps); // case NodeType.Paint: @@ -72,13 +70,17 @@ export const renderNode = (ctx: DrawingContext, node: SGNode) => { // case NodeType.Image: // return renderImage(ctx, materializedProps); case NodeType.Line: - return renderLine(ctx, materializedProps); + renderLine(ctx, materializedProps); + break; case NodeType.Patch: - return renderPatch(ctx, materializedProps); + renderPatch(ctx, materializedProps); + break; case NodeType.Vertices: - return renderVertices(ctx, materializedProps); + renderVertices(ctx, materializedProps); + break; case NodeType.DiffRect: - return renderDiffRect(ctx, materializedProps); + renderDiffRect(ctx, materializedProps); + break; // case NodeType.Text: // return renderText(ctx, materializedProps); // case NodeType.TextPath: @@ -88,13 +90,17 @@ export const renderNode = (ctx: DrawingContext, node: SGNode) => { // case NodeType.Glyphs: // return renderGlyphs(ctx, materializedProps); case NodeType.Picture: - return renderPicture(ctx, materializedProps); + renderPicture(ctx, materializedProps); + break; case NodeType.ImageSVG: - return renderImageSVG(ctx, materializedProps); + renderImageSVG(ctx, materializedProps); + break; case NodeType.Atlas: - return renderAtlas(ctx, materializedProps); + renderAtlas(ctx, materializedProps); + break; default: - return exhaustiveCheck(node.type); + throw new Error(`Unsupported node type: ${node.type}`); + //return exhaustiveCheck(node.type); } if (restore) { ctx.canvas.restore(); From 92fc38e5acc6a5e6091ec2dba542c8344683df26 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Mon, 1 Jul 2024 09:14:12 +0200 Subject: [PATCH 04/12] :wrench: --- package.json | 4 +- package/src/sg/Node.ts | 113 ++++++++++++++++- package/src/sg/Renderer.ts | 227 +++++++++++++++++++++++++++++++++++ package/src/sg/SceneGraph.ts | 111 ----------------- scripts/codegen.ts | 38 ++++++ yarn.lock | 166 +++++++++++++++++++++++++ 6 files changed, 545 insertions(+), 114 deletions(-) create mode 100644 package/src/sg/Renderer.ts delete mode 100644 package/src/sg/SceneGraph.ts create mode 100644 scripts/codegen.ts diff --git a/package.json b/package.json index 07de86c0d2..ab191652fc 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "@types/node": "16.11.7", "clang-format": "1.6.0", "rimraf": "3.0.2", + "ts-morph": "^23.0.0", "ts-node": "10.4.0", "typescript": "5.3.3" }, @@ -29,7 +30,8 @@ "clang-format-common": "find package/cpp/ -iname *.h -o -iname *.m -o -iname *.cpp | xargs clang-format -i", "workflow-copy-libs": "yarn ts-node ./scripts/workflow-copy-libs.ts", "bootstrap": "yarn && cd ./package && yarn && cd .. && cd ./example && yarn && cd .. && cd ./fabricexample && yarn && cd ..", - "cpplint": "cpplint --linelength=230 --filter=-legal/copyright,-whitespace/indent,-whitespace/comments,-whitespace/ending_newline,-build/include_order,-runtime/references,-readability/todo,-whitespace/blank_line,-whitespace/todo,-runtime/int,-build/c++11,-whitespace/parens --exclude=package/cpp/skia --exclude=package/ios --exclude=package/android/build --exclude=package/node_modules --recursive package" + "cpplint": "cpplint --linelength=230 --filter=-legal/copyright,-whitespace/indent,-whitespace/comments,-whitespace/ending_newline,-build/include_order,-runtime/references,-readability/todo,-whitespace/blank_line,-whitespace/todo,-runtime/int,-build/c++11,-whitespace/parens --exclude=package/cpp/skia --exclude=package/ios --exclude=package/android/build --exclude=package/node_modules --recursive package", + "codegen": "yarn ts-node ./scripts/codegen.ts" }, "license": "MIT", "licenseFilename": "LICENSE.md", diff --git a/package/src/sg/Node.ts b/package/src/sg/Node.ts index 870f643af1..524ff40002 100644 --- a/package/src/sg/Node.ts +++ b/package/src/sg/Node.ts @@ -1,9 +1,118 @@ -import type { CircleProps, NodeType } from "../dom/types"; +import type { + ChildrenProps, + DrawingNodeProps, + GroupProps, + PaintProps, + ImageProps, + CircleProps, + PathProps, + LineProps, + OvalProps, + PatchProps, + PointsProps, + RectProps, + RoundedRectProps, + AtlasProps, + VerticesProps, + TextProps, + TextPathProps, + TextBlobProps, + GlyphsProps, + DiffRectProps, + PictureProps, + ImageSVGProps, + BlurMaskFilterProps, + BlendImageFilterProps, + BlurImageFilterProps, + OffsetImageFilterProps, + DropShadowImageFilterProps, + DisplacementMapImageFilterProps, + RuntimeShaderImageFilterProps, + MorphologyImageFilterProps, + MatrixColorFilterProps, + BlendColorFilterProps, + LerpColorFilterProps, + ShaderProps, + ImageShaderProps, + TurbulenceProps, + FractalNoiseProps, + LinearGradientProps, + RadialGradientProps, + SweepGradientProps, + TwoPointConicalGradientProps, + DiscretePathEffectProps, + DashPathEffectProps, + Path1DPathEffectProps, + Path2DPathEffectProps, + CornerPathEffectProps, + Line2DPathEffectProps, + BlendProps, + BoxProps, + BoxShadowProps, + ParagraphProps, + ColorProps, + NodeType, +} from "../dom/types"; import type { AnimatedProps } from "../renderer"; export interface PropMap { + [NodeType.Group]: GroupProps; + [NodeType.Layer]: ChildrenProps; + [NodeType.Paint]: PaintProps; + [NodeType.Fill]: DrawingNodeProps; + [NodeType.Image]: ImageProps; [NodeType.Circle]: CircleProps; - [name: string]: object; + [NodeType.Path]: PathProps; + [NodeType.Line]: LineProps; + [NodeType.Oval]: OvalProps; + [NodeType.Patch]: PatchProps; + [NodeType.Points]: PointsProps; + [NodeType.Rect]: RectProps; + [NodeType.RRect]: RoundedRectProps; + [NodeType.Atlas]: AtlasProps; + [NodeType.Vertices]: VerticesProps; + [NodeType.Text]: TextProps; + [NodeType.TextPath]: TextPathProps; + [NodeType.TextBlob]: TextBlobProps; + [NodeType.Glyphs]: GlyphsProps; + [NodeType.DiffRect]: DiffRectProps; + [NodeType.Picture]: PictureProps; + [NodeType.ImageSVG]: ImageSVGProps; + [NodeType.BlurMaskFilter]: BlurMaskFilterProps; + [NodeType.BlendImageFilter]: BlendImageFilterProps; + [NodeType.BlurImageFilter]: BlurImageFilterProps; + [NodeType.OffsetImageFilter]: OffsetImageFilterProps; + [NodeType.DropShadowImageFilter]: DropShadowImageFilterProps; + [NodeType.DisplacementMapImageFilter]: DisplacementMapImageFilterProps; + [NodeType.RuntimeShaderImageFilter]: RuntimeShaderImageFilterProps; + [NodeType.MorphologyImageFilter]: MorphologyImageFilterProps; + [NodeType.MatrixColorFilter]: MatrixColorFilterProps; + [NodeType.BlendColorFilter]: BlendColorFilterProps; + [NodeType.LinearToSRGBGammaColorFilter]: ChildrenProps; + [NodeType.SRGBToLinearGammaColorFilter]: ChildrenProps; + [NodeType.LumaColorFilter]: ChildrenProps; + [NodeType.LerpColorFilter]: LerpColorFilterProps; + [NodeType.Shader]: ShaderProps; + [NodeType.ImageShader]: ImageShaderProps; + [NodeType.ColorShader]: ColorProps; + [NodeType.Turbulence]: TurbulenceProps; + [NodeType.FractalNoise]: FractalNoiseProps; + [NodeType.LinearGradient]: LinearGradientProps; + [NodeType.RadialGradient]: RadialGradientProps; + [NodeType.SweepGradient]: SweepGradientProps; + [NodeType.TwoPointConicalGradient]: TwoPointConicalGradientProps; + [NodeType.DiscretePathEffect]: DiscretePathEffectProps; + [NodeType.DashPathEffect]: DashPathEffectProps; + [NodeType.Path1DPathEffect]: Path1DPathEffectProps; + [NodeType.Path2DPathEffect]: Path2DPathEffectProps; + [NodeType.CornerPathEffect]: CornerPathEffectProps; + [NodeType.SumPathEffect]: ChildrenProps; + [NodeType.Line2DPathEffect]: Line2DPathEffectProps; + [NodeType.Blend]: BlendProps; + [NodeType.BackdropFilter]: ChildrenProps; + [NodeType.Box]: BoxProps; + [NodeType.BoxShadow]: BoxShadowProps; + [NodeType.Paragraph]: ParagraphProps; } // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/package/src/sg/Renderer.ts b/package/src/sg/Renderer.ts new file mode 100644 index 0000000000..e551fec1d7 --- /dev/null +++ b/package/src/sg/Renderer.ts @@ -0,0 +1,227 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { NodeType } from "../dom/types"; +import type { AnimatedProps } from "../renderer"; +import Rea from "../external/reanimated/ReanimatedProxy"; +import { exhaustiveCheck } from "../renderer/typeddash"; + +import { processContext, type DrawingContext } from "./Context"; +import { + renderAtlas, + renderCircle, + renderDiffRect, + renderFill, + renderImageSVG, + renderLine, + renderOval, + renderPatch, + renderPath, + renderPicture, + renderPoints, + renderRRect, + renderRect, + renderVertices, +} from "./Drawing"; +import type { SGNode } from "./Node"; + +const materialize =

(props: AnimatedProps

) => { + "worklet"; + const materializedProps: Record = {}; + for (const key in props) { + const value = props[key]; + if (Rea.isSharedValue(value)) { + materializedProps[key] = value.value; + } else { + materializedProps[key] = value; + } + } + return materializedProps as any; +}; + +export const renderNode = (ctx: DrawingContext, node: SGNode) => { + "worklet"; + const materializedProps = materialize(node.props); + const { restore, restorePaint } = processContext(ctx, materializedProps); + //const { invertClip, layer, matrix, transform } = materializedProps; + + switch (node.type) { + case NodeType.Group: + renderGroup(ctx, materializedProps); + break; + case NodeType.Layer: + renderLayer(ctx, materializedProps); + break; + case NodeType.Paint: + renderPaint(ctx, materializedProps); + break; + case NodeType.Fill: + renderFill(ctx, materializedProps); + break; + case NodeType.Image: + renderImage(ctx, materializedProps); + break; + case NodeType.Circle: + renderCircle(ctx, materializedProps); + break; + case NodeType.Path: + renderPath(ctx, materializedProps); + break; + case NodeType.Line: + renderLine(ctx, materializedProps); + break; + case NodeType.Oval: + renderOval(ctx, materializedProps); + break; + case NodeType.Patch: + renderPatch(ctx, materializedProps); + break; + case NodeType.Points: + renderPoints(ctx, materializedProps); + break; + case NodeType.Rect: + renderRect(ctx, materializedProps); + break; + case NodeType.RRect: + renderRRect(ctx, materializedProps); + break; + case NodeType.Atlas: + renderAtlas(ctx, materializedProps); + break; + case NodeType.Vertices: + renderVertices(ctx, materializedProps); + break; + case NodeType.Text: + renderText(ctx, materializedProps); + break; + case NodeType.TextPath: + renderTextPath(ctx, materializedProps); + break; + case NodeType.TextBlob: + renderTextBlob(ctx, materializedProps); + break; + case NodeType.Glyphs: + renderGlyphs(ctx, materializedProps); + break; + case NodeType.DiffRect: + renderDiffRect(ctx, materializedProps); + break; + case NodeType.Picture: + renderPicture(ctx, materializedProps); + break; + case NodeType.ImageSVG: + renderImageSVG(ctx, materializedProps); + break; + case NodeType.BlurMaskFilter: + renderBlurMaskFilter(ctx, materializedProps); + break; + case NodeType.BlendImageFilter: + renderBlendImageFilter(ctx, materializedProps); + break; + case NodeType.BlurImageFilter: + renderBlurImageFilter(ctx, materializedProps); + break; + case NodeType.OffsetImageFilter: + renderOffsetImageFilter(ctx, materializedProps); + break; + case NodeType.DropShadowImageFilter: + renderDropShadowImageFilter(ctx, materializedProps); + break; + case NodeType.DisplacementMapImageFilter: + renderDisplacementMapImageFilter(ctx, materializedProps); + break; + case NodeType.RuntimeShaderImageFilter: + renderRuntimeShaderImageFilter(ctx, materializedProps); + break; + case NodeType.MorphologyImageFilter: + renderMorphologyImageFilter(ctx, materializedProps); + break; + case NodeType.MatrixColorFilter: + renderMatrixColorFilter(ctx, materializedProps); + break; + case NodeType.BlendColorFilter: + renderBlendColorFilter(ctx, materializedProps); + break; + case NodeType.LinearToSRGBGammaColorFilter: + renderLinearToSRGBGammaColorFilter(ctx, materializedProps); + break; + case NodeType.SRGBToLinearGammaColorFilter: + renderSRGBToLinearGammaColorFilter(ctx, materializedProps); + break; + case NodeType.LumaColorFilter: + renderLumaColorFilter(ctx, materializedProps); + break; + case NodeType.LerpColorFilter: + renderLerpColorFilter(ctx, materializedProps); + break; + case NodeType.Shader: + renderShader(ctx, materializedProps); + break; + case NodeType.ImageShader: + renderImageShader(ctx, materializedProps); + break; + case NodeType.ColorShader: + renderColorShader(ctx, materializedProps); + break; + case NodeType.Turbulence: + renderTurbulence(ctx, materializedProps); + break; + case NodeType.FractalNoise: + renderFractalNoise(ctx, materializedProps); + break; + case NodeType.LinearGradient: + renderLinearGradient(ctx, materializedProps); + break; + case NodeType.RadialGradient: + renderRadialGradient(ctx, materializedProps); + break; + case NodeType.SweepGradient: + renderSweepGradient(ctx, materializedProps); + break; + case NodeType.TwoPointConicalGradient: + renderTwoPointConicalGradient(ctx, materializedProps); + break; + case NodeType.DiscretePathEffect: + renderDiscretePathEffect(ctx, materializedProps); + break; + case NodeType.DashPathEffect: + renderDashPathEffect(ctx, materializedProps); + break; + case NodeType.Path1DPathEffect: + renderPath1DPathEffect(ctx, materializedProps); + break; + case NodeType.Path2DPathEffect: + renderPath2DPathEffect(ctx, materializedProps); + break; + case NodeType.CornerPathEffect: + renderCornerPathEffect(ctx, materializedProps); + break; + case NodeType.SumPathEffect: + renderSumPathEffect(ctx, materializedProps); + break; + case NodeType.Line2DPathEffect: + renderLine2DPathEffect(ctx, materializedProps); + break; + case NodeType.Blend: + renderBlend(ctx, materializedProps); + break; + case NodeType.BackdropFilter: + renderBackdropFilter(ctx, materializedProps); + break; + case NodeType.Box: + renderBox(ctx, materializedProps); + break; + case NodeType.BoxShadow: + renderBoxShadow(ctx, materializedProps); + break; + case NodeType.Paragraph: + renderParagraph(ctx, materializedProps); + break; + default: + return exhaustiveCheck(node.type); + } + if (restore) { + ctx.canvas.restore(); + } + if (restorePaint) { + //ctx.paint.restore(); + } +}; diff --git a/package/src/sg/SceneGraph.ts b/package/src/sg/SceneGraph.ts deleted file mode 100644 index ba90f6d2f7..0000000000 --- a/package/src/sg/SceneGraph.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { NodeType } from "../dom/types"; -import type { AnimatedProps } from "../renderer"; -import Rea from "../external/reanimated/ReanimatedProxy"; - -import { processContext, type DrawingContext } from "./Context"; -import { - renderAtlas, - renderCircle, - renderDiffRect, - renderFill, - renderImageSVG, - renderLine, - renderOval, - renderPatch, - renderPath, - renderPicture, - renderPoints, - renderRRect, - renderRect, - renderVertices, -} from "./Drawing"; - -const materialize =

(props: AnimatedProps

) => { - "worklet"; - const materializedProps: Record = {}; - for (const key in props) { - const value = props[key]; - if (Rea.isSharedValue(value)) { - materializedProps[key] = value.value; - } else { - materializedProps[key] = value; - } - } - return materializedProps as any; -}; - -export const renderNode = (ctx: DrawingContext, node: SGNode) => { - "worklet"; - const materializedProps = materialize(node.props); - const { restore, restorePaint } = processContext(ctx, materializedProps); - //const { invertClip, layer, matrix, transform } = materializedProps; - - switch (node.type) { - case NodeType.Circle: - renderCircle(ctx, materializedProps); - break; - case NodeType.Fill: - renderFill(ctx); - break; - case NodeType.Points: - renderPoints(ctx, materializedProps); - break; - case NodeType.Path: - renderPath(ctx, materializedProps); - break; - case NodeType.Rect: - renderRect(ctx, materializedProps); - break; - case NodeType.RRect: - renderRRect(ctx, materializedProps); - break; - case NodeType.Oval: - renderOval(ctx, materializedProps); - break; - // case NodeType.Group: - // return renderGroup(ctx, materializedProps); - // case NodeType.Paint: - // return renderPaint(ctx, materializedProps); - // case NodeType.Image: - // return renderImage(ctx, materializedProps); - case NodeType.Line: - renderLine(ctx, materializedProps); - break; - case NodeType.Patch: - renderPatch(ctx, materializedProps); - break; - case NodeType.Vertices: - renderVertices(ctx, materializedProps); - break; - case NodeType.DiffRect: - renderDiffRect(ctx, materializedProps); - break; - // case NodeType.Text: - // return renderText(ctx, materializedProps); - // case NodeType.TextPath: - // return renderTextPath(ctx, materializedProps); - // case NodeType.TextBlob: - // return renderTextBlob(ctx, materializedProps); - // case NodeType.Glyphs: - // return renderGlyphs(ctx, materializedProps); - case NodeType.Picture: - renderPicture(ctx, materializedProps); - break; - case NodeType.ImageSVG: - renderImageSVG(ctx, materializedProps); - break; - case NodeType.Atlas: - renderAtlas(ctx, materializedProps); - break; - default: - throw new Error(`Unsupported node type: ${node.type}`); - //return exhaustiveCheck(node.type); - } - if (restore) { - ctx.canvas.restore(); - } - if (restorePaint) { - //ctx.paint.restore(); - } -}; diff --git a/scripts/codegen.ts b/scripts/codegen.ts new file mode 100644 index 0000000000..57d01a0f88 --- /dev/null +++ b/scripts/codegen.ts @@ -0,0 +1,38 @@ +import * as path from "path"; + +import { Node, Project, SyntaxKind } from "ts-morph"; + +// Define the path to the WebGPU type declaration file +const tsConfigFilePath = path.resolve(__dirname, "../package/tsconfig.json"); +const filePath = path.resolve( + __dirname, + "../package/src/renderer/HostComponents.ts", +); +const project = new Project({ + tsConfigFilePath, +}); + +const sourceFile = project.addSourceFileAtPath(filePath); + +const decl = sourceFile.getDescendantsOfKind(SyntaxKind.InterfaceDeclaration).filter(node => node.getName() === "IntrinsicElements")[0]; +decl.getProperties().forEach(prop => { + const nodeType = prop.getName().substring(2); + console.log(`${nodeType}Props,`); +}); +// decl.getProperties().forEach(prop => { +// const nodeType = prop.getName().substring(2); +// console.log(`[NodeType.${nodeType}]: ${nodeType}Props;`); +// }); +// decl.getProperties().forEach(prop => { +// const nodeType = prop.getName().substring(2); +// console.log(`case NodeType.${nodeType}: +// render${nodeType}(ctx, materializedProps); +// break;`); +// }); + +// console.log(sourceFile.getDescendantsOfKind(SyntaxKind.InterfaceDeclaration).map(node => { +// // node.getName() +// return node.getText(); +// })); +//console.log(sourceFile.getInterface("IntrinsicElements")!.getText()); +//console.log(sourceFile.getModule("global")!.getText()); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 2d9f2a24eb..69dfae9689 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14,6 +14,37 @@ dependencies: "@cspotcode/source-map-consumer" "0.8.0" +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@ts-morph/common@~0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.24.0.tgz#9125b3d5ef9e2633cd6a54296b420b89366599c1" + integrity sha512-c1xMmNHWpNselmpIqursHeOHHBTIsJLbB+NuovbTTRCNiTLEr/U9dbJ8qy0jd/O2x5pc3seWuOUN5R2IoOTp8A== + dependencies: + fast-glob "^3.3.2" + minimatch "^9.0.4" + mkdirp "^3.0.1" + path-browserify "^1.0.1" + "@tsconfig/node10@^1.0.7": version "1.0.9" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" @@ -72,6 +103,20 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + clang-format@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/clang-format/-/clang-format-1.6.0.tgz#48fac4387712aeeae0f47b5d72f639f3fd95f4b6" @@ -81,6 +126,11 @@ clang-format@1.6.0: glob "^7.0.0" resolve "^1.1.6" +code-block-writer@^13.0.1: + version "13.0.1" + resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-13.0.1.tgz#52ac60ca6076d8700b88a45bd71e06a577158405" + integrity sha512-c5or4P6erEA69TxaxTNcHUNcIn+oyxSRTOWV+pSYF+z4epXqNvwvJ70XPGjPNgue83oAFAPBRQYwpAJ/Hpe/Sg== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -96,6 +146,31 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -106,6 +181,13 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + glob@^7.0.0, glob@^7.1.3: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -145,11 +227,41 @@ is-core-module@^2.13.0: dependencies: hasown "^2.0.0" +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.7" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" + integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + minimatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -157,6 +269,18 @@ minimatch@^3.1.1: dependencies: brace-expansion "^1.1.7" +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +mkdirp@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -164,6 +288,11 @@ once@^1.3.0: dependencies: wrappy "1" +path-browserify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -174,6 +303,16 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + resolve@^1.1.6: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" @@ -183,6 +322,11 @@ resolve@^1.1.6: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + rimraf@3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -190,11 +334,33 @@ rimraf@3.0.2: dependencies: glob "^7.1.3" +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-morph@^23.0.0: + version "23.0.0" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-23.0.0.tgz#601d74edd1d24247e312b9fa5d147bdc659bff15" + integrity sha512-FcvFx7a9E8TUe6T3ShihXJLiJOiqyafzFKUO4aqIHDUCIvADdGNShcbc2W5PMr3LerXRv7mafvFZ9lRENxJmug== + dependencies: + "@ts-morph/common" "~0.24.0" + code-block-writer "^13.0.1" + ts-node@10.4.0: version "10.4.0" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7" From 2376408f660f7d4ef9f1744290f7bd15c54844a4 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Mon, 1 Jul 2024 09:41:24 +0200 Subject: [PATCH 05/12] :wrench: --- package/src/sg/ColorFilters.ts | 48 ++++++++ package/src/sg/Drawing.ts | 16 ++- package/src/sg/ImageFilters.ts | 76 ++++++++++++ package/src/sg/MaskFilters.ts | 11 ++ package/src/sg/Renderer.ts | 219 +++++++++++++++++++++++---------- package/src/sg/Text.ts | 37 ++++-- 6 files changed, 326 insertions(+), 81 deletions(-) diff --git a/package/src/sg/ColorFilters.ts b/package/src/sg/ColorFilters.ts index e69de29bb2..9fedc245c5 100644 --- a/package/src/sg/ColorFilters.ts +++ b/package/src/sg/ColorFilters.ts @@ -0,0 +1,48 @@ +import type { + BlendColorFilterProps, + ChildrenProps, + LerpColorFilterProps, + MatrixColorFilterProps, +} from "../dom/types"; + +import type { DrawingContext } from "./Context"; + +export const renderMatrixColorFilter = ( + _ctx: DrawingContext, + _props: MatrixColorFilterProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderBlendColorFilter = ( + _ctx: DrawingContext, + _props: BlendColorFilterProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderLinearToSRGBGammaColorFilter = ( + _ctx: DrawingContext, + _props: ChildrenProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderSRGBToLinearGammaColorFilter = ( + _ctx: DrawingContext, + _props: ChildrenProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderLerpColorFilter = ( + _ctx: DrawingContext, + _props: LerpColorFilterProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; diff --git a/package/src/sg/Drawing.ts b/package/src/sg/Drawing.ts index 5c5ed88d8d..64a3e2bf50 100644 --- a/package/src/sg/Drawing.ts +++ b/package/src/sg/Drawing.ts @@ -15,7 +15,9 @@ import type { RectProps, RoundedRectProps, VerticesProps, - NodeType, + ChildrenProps, + PaintProps, + DrawingNodeProps, } from "../dom/nodes"; import { enumKey, @@ -37,7 +39,7 @@ export const renderCircle = (ctx: DrawingContext, props: CircleProps) => { ctx.canvas.drawCircle(c.x, c.y, r, ctx.paint); }; -export const renderFill = (ctx: DrawingContext) => { +export const renderFill = (ctx: DrawingContext, _props: DrawingNodeProps) => { "worklet"; ctx.canvas.drawPaint(ctx.paint); }; @@ -242,3 +244,13 @@ export const renderAtlas = (ctx: DrawingContext, props: AtlasProps) => { ctx.canvas.drawAtlas(image, sprites, transforms, ctx.paint, blend, colors); } }; + +export const renderLayer = (_ctx: DrawingContext, _props: ChildrenProps) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderPaint = (_ctx: DrawingContext, _props: PaintProps) => { + "worklet"; + throw new Error("Not implemented"); +}; diff --git a/package/src/sg/ImageFilters.ts b/package/src/sg/ImageFilters.ts index e69de29bb2..6e53673886 100644 --- a/package/src/sg/ImageFilters.ts +++ b/package/src/sg/ImageFilters.ts @@ -0,0 +1,76 @@ +import type { + BlendImageFilterProps, + BlurImageFilterProps, + ChildrenProps, + DisplacementMapImageFilterProps, + DropShadowImageFilterProps, + MorphologyImageFilterProps, + OffsetImageFilterProps, + RuntimeShaderImageFilterProps, +} from "../dom/types"; + +import type { DrawingContext } from "./Context"; + +export const renderBlendImageFilter = ( + _ctx: DrawingContext, + _props: BlendImageFilterProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderBlurImageFilter = ( + _ctx: DrawingContext, + _props: BlurImageFilterProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderOffsetImageFilter = ( + _ctx: DrawingContext, + _props: OffsetImageFilterProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderDropShadowImageFilter = ( + _ctx: DrawingContext, + _props: DropShadowImageFilterProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderDisplacementMapImageFilter = ( + _ctx: DrawingContext, + _props: DisplacementMapImageFilterProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderRuntimeShaderImageFilter = ( + _ctx: DrawingContext, + _props: RuntimeShaderImageFilterProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderMorphologyImageFilter = ( + _ctx: DrawingContext, + _props: MorphologyImageFilterProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderLumaColorFilter = ( + _ctx: DrawingContext, + _props: ChildrenProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; diff --git a/package/src/sg/MaskFilters.ts b/package/src/sg/MaskFilters.ts index e69de29bb2..87da5f9357 100644 --- a/package/src/sg/MaskFilters.ts +++ b/package/src/sg/MaskFilters.ts @@ -0,0 +1,11 @@ +import type { BlurMaskFilterProps } from "../dom/types"; + +import type { DrawingContext } from "./Context"; + +export const renderBlurMaskFilter = ( + _ctx: DrawingContext, + _props: BlurMaskFilterProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; diff --git a/package/src/sg/Renderer.ts b/package/src/sg/Renderer.ts index e551fec1d7..a659306b8f 100644 --- a/package/src/sg/Renderer.ts +++ b/package/src/sg/Renderer.ts @@ -4,15 +4,18 @@ import type { AnimatedProps } from "../renderer"; import Rea from "../external/reanimated/ReanimatedProxy"; import { exhaustiveCheck } from "../renderer/typeddash"; -import { processContext, type DrawingContext } from "./Context"; +import { type DrawingContext } from "./Context"; import { renderAtlas, renderCircle, renderDiffRect, renderFill, + renderImage, renderImageSVG, + renderLayer, renderLine, renderOval, + renderPaint, renderPatch, renderPath, renderPicture, @@ -21,7 +24,31 @@ import { renderRect, renderVertices, } from "./Drawing"; -import type { SGNode } from "./Node"; +import type { PropMap, SGNode } from "./Node"; +import { + renderGlyphs, + renderText, + renderTextBlob, + renderTextPath, +} from "./Text"; +import { renderBlurMaskFilter } from "./MaskFilters"; +import { + renderBlendImageFilter, + renderBlurImageFilter, + renderDisplacementMapImageFilter, + renderDropShadowImageFilter, + renderLumaColorFilter, + renderMorphologyImageFilter, + renderOffsetImageFilter, + renderRuntimeShaderImageFilter, +} from "./ImageFilters"; +import { + renderBlendColorFilter, + renderLerpColorFilter, + renderLinearToSRGBGammaColorFilter, + renderMatrixColorFilter, + renderSRGBToLinearGammaColorFilter, +} from "./ColorFilters"; const materialize =

(props: AnimatedProps

) => { "worklet"; @@ -39,189 +66,247 @@ const materialize =

(props: AnimatedProps

) => { export const renderNode = (ctx: DrawingContext, node: SGNode) => { "worklet"; - const materializedProps = materialize(node.props); - const { restore, restorePaint } = processContext(ctx, materializedProps); + const materializedProps = materialize(node.props) as unknown; + //const { restore, restorePaint } = processContext(ctx, materializedProps as PropMap[typeof node.type]); //const { invertClip, layer, matrix, transform } = materializedProps; switch (node.type) { case NodeType.Group: - renderGroup(ctx, materializedProps); + // nothing to do here + //renderGroup(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Layer: - renderLayer(ctx, materializedProps); + renderLayer(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Paint: - renderPaint(ctx, materializedProps); + renderPaint(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Fill: - renderFill(ctx, materializedProps); + renderFill(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Image: - renderImage(ctx, materializedProps); + renderImage(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Circle: - renderCircle(ctx, materializedProps); + renderCircle(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Path: - renderPath(ctx, materializedProps); + renderPath(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Line: - renderLine(ctx, materializedProps); + renderLine(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Oval: - renderOval(ctx, materializedProps); + renderOval(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Patch: - renderPatch(ctx, materializedProps); + renderPatch(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Points: - renderPoints(ctx, materializedProps); + renderPoints(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Rect: - renderRect(ctx, materializedProps); + renderRect(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.RRect: - renderRRect(ctx, materializedProps); + renderRRect(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Atlas: - renderAtlas(ctx, materializedProps); + renderAtlas(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Vertices: - renderVertices(ctx, materializedProps); + renderVertices(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Text: - renderText(ctx, materializedProps); + renderText(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.TextPath: - renderTextPath(ctx, materializedProps); + renderTextPath(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.TextBlob: - renderTextBlob(ctx, materializedProps); + renderTextBlob(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Glyphs: - renderGlyphs(ctx, materializedProps); + renderGlyphs(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.DiffRect: - renderDiffRect(ctx, materializedProps); + renderDiffRect(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Picture: - renderPicture(ctx, materializedProps); + renderPicture(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.ImageSVG: - renderImageSVG(ctx, materializedProps); + renderImageSVG(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.BlurMaskFilter: - renderBlurMaskFilter(ctx, materializedProps); + renderBlurMaskFilter(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.BlendImageFilter: - renderBlendImageFilter(ctx, materializedProps); + renderBlendImageFilter( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.BlurImageFilter: - renderBlurImageFilter(ctx, materializedProps); + renderBlurImageFilter( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.OffsetImageFilter: - renderOffsetImageFilter(ctx, materializedProps); + renderOffsetImageFilter( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.DropShadowImageFilter: - renderDropShadowImageFilter(ctx, materializedProps); + renderDropShadowImageFilter( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.DisplacementMapImageFilter: - renderDisplacementMapImageFilter(ctx, materializedProps); + renderDisplacementMapImageFilter( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.RuntimeShaderImageFilter: - renderRuntimeShaderImageFilter(ctx, materializedProps); + renderRuntimeShaderImageFilter( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.MorphologyImageFilter: - renderMorphologyImageFilter(ctx, materializedProps); + renderMorphologyImageFilter( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.MatrixColorFilter: - renderMatrixColorFilter(ctx, materializedProps); + renderMatrixColorFilter( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.BlendColorFilter: - renderBlendColorFilter(ctx, materializedProps); + renderBlendColorFilter( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.LinearToSRGBGammaColorFilter: - renderLinearToSRGBGammaColorFilter(ctx, materializedProps); + renderLinearToSRGBGammaColorFilter( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.SRGBToLinearGammaColorFilter: - renderSRGBToLinearGammaColorFilter(ctx, materializedProps); + renderSRGBToLinearGammaColorFilter( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.LumaColorFilter: - renderLumaColorFilter(ctx, materializedProps); + renderLumaColorFilter( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.LerpColorFilter: - renderLerpColorFilter(ctx, materializedProps); + renderLerpColorFilter( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.Shader: - renderShader(ctx, materializedProps); + renderShader(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.ImageShader: - renderImageShader(ctx, materializedProps); + renderImageShader(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.ColorShader: - renderColorShader(ctx, materializedProps); + renderColorShader(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Turbulence: - renderTurbulence(ctx, materializedProps); + renderTurbulence(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.FractalNoise: - renderFractalNoise(ctx, materializedProps); + renderFractalNoise(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.LinearGradient: - renderLinearGradient(ctx, materializedProps); + renderLinearGradient(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.RadialGradient: - renderRadialGradient(ctx, materializedProps); + renderRadialGradient(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.SweepGradient: - renderSweepGradient(ctx, materializedProps); + renderSweepGradient(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.TwoPointConicalGradient: - renderTwoPointConicalGradient(ctx, materializedProps); + renderTwoPointConicalGradient( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.DiscretePathEffect: - renderDiscretePathEffect(ctx, materializedProps); + renderDiscretePathEffect( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.DashPathEffect: - renderDashPathEffect(ctx, materializedProps); + renderDashPathEffect(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Path1DPathEffect: - renderPath1DPathEffect(ctx, materializedProps); + renderPath1DPathEffect( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.Path2DPathEffect: - renderPath2DPathEffect(ctx, materializedProps); + renderPath2DPathEffect( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.CornerPathEffect: - renderCornerPathEffect(ctx, materializedProps); + renderCornerPathEffect( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.SumPathEffect: - renderSumPathEffect(ctx, materializedProps); + renderSumPathEffect(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Line2DPathEffect: - renderLine2DPathEffect(ctx, materializedProps); + renderLine2DPathEffect( + ctx, + materializedProps as PropMap[typeof node.type] + ); break; case NodeType.Blend: - renderBlend(ctx, materializedProps); + renderBlend(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.BackdropFilter: - renderBackdropFilter(ctx, materializedProps); + renderBackdropFilter(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Box: - renderBox(ctx, materializedProps); + renderBox(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.BoxShadow: - renderBoxShadow(ctx, materializedProps); + renderBoxShadow(ctx, materializedProps as PropMap[typeof node.type]); break; case NodeType.Paragraph: - renderParagraph(ctx, materializedProps); + renderParagraph(ctx, materializedProps as PropMap[typeof node.type]); break; default: return exhaustiveCheck(node.type); } - if (restore) { - ctx.canvas.restore(); - } - if (restorePaint) { - //ctx.paint.restore(); - } + // if (restore) { + // ctx.canvas.restore(); + // } + // if (restorePaint) { + // //ctx.paint.restore(); + // } }; diff --git a/package/src/sg/Text.ts b/package/src/sg/Text.ts index 17de95f1ce..abf8dedf5f 100644 --- a/package/src/sg/Text.ts +++ b/package/src/sg/Text.ts @@ -1,23 +1,36 @@ -export const renderText = (ctx: DrawingContext, props: TextProps) => { +import type { + GlyphsProps, + TextBlobProps, + TextPathProps, + TextProps, +} from "../dom/types"; + +import type { DrawingContext } from "./Context"; + +export const renderText = (_ctx: DrawingContext, _props: TextProps) => { "worklet"; - const { text, x, y, font } = processText(ctx.Skia, props); - ctx.canvas.drawText(text, x, y, font, ctx.paint); + // const { text, x, y, font } = processText(ctx.Skia, props); + // ctx.canvas.drawText(text, x, y, font, ctx.paint); + throw new Error("Not implemented"); }; -export const renderTextPath = (ctx: DrawingContext, props: TextPathProps) => { +export const renderTextPath = (_ctx: DrawingContext, _props: TextPathProps) => { "worklet"; - const { text, path, font } = processTextPath(ctx.Skia, props); - ctx.canvas.drawTextOnPath(text, path, font, ctx.paint); + // const { text, path, font } = processTextPath(ctx.Skia, props); + // ctx.canvas.drawTextOnPath(text, path, font, ctx.paint); + throw new Error("Not implemented"); }; -export const renderTextBlob = (ctx: DrawingContext, props: TextBlobProps) => { +export const renderTextBlob = (_ctx: DrawingContext, _props: TextBlobProps) => { "worklet"; - const { textBlob, x, y } = processTextBlob(ctx.Skia, props); - ctx.canvas.drawTextBlob(textBlob, x, y, ctx.paint); + // const { textBlob, x, y } = processTextBlob(ctx.Skia, props); + // ctx.canvas.drawTextBlob(textBlob, x, y, ctx.paint); + throw new Error("Not implemented"); }; -export const renderGlyphs = (ctx: DrawingContext, props: GlyphsProps) => { +export const renderGlyphs = (_ctx: DrawingContext, _props: GlyphsProps) => { "worklet"; - const { glyphs, positions, font } = processGlyphs(ctx.Skia, props); - ctx.canvas.drawGlyphs(glyphs, positions, font, ctx.paint); + // const { glyphs, positions, font } = processGlyphs(ctx.Skia, props); + // ctx.canvas.drawGlyphs(glyphs, positions, font, ctx.paint); + throw new Error("Not implemented"); }; From 25e74f3253bd36afb6b5514483aae160f50aefb2 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Mon, 1 Jul 2024 09:51:37 +0200 Subject: [PATCH 06/12] :wrench: --- package/src/sg/PathEffects.ts | 49 ++++++++++++++++++++++ package/src/sg/Renderer.ts | 18 ++++++++ package/src/sg/Shaders.ts | 79 +++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) diff --git a/package/src/sg/PathEffects.ts b/package/src/sg/PathEffects.ts index e69de29bb2..cb5e581240 100644 --- a/package/src/sg/PathEffects.ts +++ b/package/src/sg/PathEffects.ts @@ -0,0 +1,49 @@ +import type { + CornerPathEffectProps, + DashPathEffectProps, + DiscretePathEffectProps, + Path1DPathEffectProps, + Path2DPathEffectProps, +} from "../dom/types"; + +import type { DrawingContext } from "./Context"; + +export const renderDiscretePathEffect = ( + _ctx: DrawingContext, + _props: DiscretePathEffectProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderDashPathEffect = ( + _ctx: DrawingContext, + _props: DashPathEffectProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderPath1DPathEffect = ( + _ctx: DrawingContext, + _props: Path1DPathEffectProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderPath2DPathEffect = ( + _ctx: DrawingContext, + _props: Path2DPathEffectProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderCornerPathEffect = ( + _ctx: DrawingContext, + _props: CornerPathEffectProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; diff --git a/package/src/sg/Renderer.ts b/package/src/sg/Renderer.ts index a659306b8f..cdadc2051a 100644 --- a/package/src/sg/Renderer.ts +++ b/package/src/sg/Renderer.ts @@ -49,6 +49,24 @@ import { renderMatrixColorFilter, renderSRGBToLinearGammaColorFilter, } from "./ColorFilters"; +import { + renderColorShader, + renderFractalNoise, + renderImageShader, + renderLinearGradient, + renderRadialGradient, + renderShader, + renderSweepGradient, + renderTurbulence, + renderTwoPointConicalGradient, +} from "./Shaders"; +import { + renderCornerPathEffect, + renderDashPathEffect, + renderDiscretePathEffect, + renderPath1DPathEffect, + renderPath2DPathEffect, +} from "./PathEffects"; const materialize =

(props: AnimatedProps

) => { "worklet"; diff --git a/package/src/sg/Shaders.ts b/package/src/sg/Shaders.ts index e69de29bb2..0d34077c31 100644 --- a/package/src/sg/Shaders.ts +++ b/package/src/sg/Shaders.ts @@ -0,0 +1,79 @@ +import type { + ColorProps, + DiscretePathEffectProps, + ImageShaderProps, + LinearGradientProps, + RadialGradientProps, + ShaderProps, + SweepGradientProps, + TurbulenceProps, + TwoPointConicalGradientProps, +} from "../dom/types"; + +import type { DrawingContext } from "./Context"; + +export const renderShader = (_ctx: DrawingContext, _props: ShaderProps) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderImageShader = ( + _ctx: DrawingContext, + _props: ImageShaderProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderColorShader = (_ctx: DrawingContext, _props: ColorProps) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderTurbulence = ( + _ctx: DrawingContext, + _props: TurbulenceProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderFractalNoise = ( + _ctx: DrawingContext, + _props: TurbulenceProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderLinearGradient = ( + _ctx: DrawingContext, + _props: LinearGradientProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderRadialGradient = ( + _ctx: DrawingContext, + _props: RadialGradientProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderSweepGradient = ( + _ctx: DrawingContext, + _props: SweepGradientProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderTwoPointConicalGradient = ( + _ctx: DrawingContext, + _props: TwoPointConicalGradientProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; From 9011cb415db274d218755d201333744433c59262 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Mon, 1 Jul 2024 09:59:05 +0200 Subject: [PATCH 07/12] :wrench: --- package/src/sg/Context.ts | 15 +++++++-------- package/src/sg/Drawing.ts | 2 -- package/src/sg/Mixed.ts | 30 ++++++++++++++++++++++++++++++ package/src/sg/Node.ts | 4 ++-- package/src/sg/PathEffects.ts | 18 ++++++++++++++++++ package/src/sg/Renderer.ts | 9 +++++++++ package/src/sg/Shaders.ts | 1 - package/src/sg/Text.ts | 9 +++++++++ 8 files changed, 75 insertions(+), 13 deletions(-) diff --git a/package/src/sg/Context.ts b/package/src/sg/Context.ts index 9720a06be7..94b359a2f0 100644 --- a/package/src/sg/Context.ts +++ b/package/src/sg/Context.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ import type { SkCanvas, SkColorFilter, @@ -25,10 +24,10 @@ export interface PaintingContext { colorFilters: SkColorFilter[]; } -export const processContext = ( - ctx: DrawingContext, - props: Record -) => { - "worklet"; - return { restore: false, restorePaint: false }; -}; +// export const processContext = ( +// ctx: DrawingContext, +// props: Record +// ) => { +// "worklet"; +// return { restore: false, restorePaint: false }; +// }; diff --git a/package/src/sg/Drawing.ts b/package/src/sg/Drawing.ts index 64a3e2bf50..515581813a 100644 --- a/package/src/sg/Drawing.ts +++ b/package/src/sg/Drawing.ts @@ -1,5 +1,3 @@ -import type { AnimatedProps } from "react-native-reanimated"; - import type { AtlasProps, CircleProps, diff --git a/package/src/sg/Mixed.ts b/package/src/sg/Mixed.ts index e69de29bb2..dddccc55c1 100644 --- a/package/src/sg/Mixed.ts +++ b/package/src/sg/Mixed.ts @@ -0,0 +1,30 @@ +import type { BlendProps, BoxProps, BoxShadowProps } from "../dom/types"; +import type { BackdropFilterProps } from "../renderer"; + +import type { DrawingContext } from "./Context"; + +export const renderBlend = (_ctx: DrawingContext, _props: BlendProps) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderBackdropFilter = ( + _ctx: DrawingContext, + _props: BackdropFilterProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderBox = (_ctx: DrawingContext, _props: BoxProps) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderBoxShadow = ( + _ctx: DrawingContext, + _props: BoxShadowProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; diff --git a/package/src/sg/Node.ts b/package/src/sg/Node.ts index 524ff40002..9bc6174c32 100644 --- a/package/src/sg/Node.ts +++ b/package/src/sg/Node.ts @@ -53,7 +53,7 @@ import type { ColorProps, NodeType, } from "../dom/types"; -import type { AnimatedProps } from "../renderer"; +import type { AnimatedProps, BackdropFilterProps } from "../renderer"; export interface PropMap { [NodeType.Group]: GroupProps; @@ -109,7 +109,7 @@ export interface PropMap { [NodeType.SumPathEffect]: ChildrenProps; [NodeType.Line2DPathEffect]: Line2DPathEffectProps; [NodeType.Blend]: BlendProps; - [NodeType.BackdropFilter]: ChildrenProps; + [NodeType.BackdropFilter]: BackdropFilterProps; [NodeType.Box]: BoxProps; [NodeType.BoxShadow]: BoxShadowProps; [NodeType.Paragraph]: ParagraphProps; diff --git a/package/src/sg/PathEffects.ts b/package/src/sg/PathEffects.ts index cb5e581240..48865c8fca 100644 --- a/package/src/sg/PathEffects.ts +++ b/package/src/sg/PathEffects.ts @@ -1,7 +1,9 @@ import type { + ChildrenProps, CornerPathEffectProps, DashPathEffectProps, DiscretePathEffectProps, + Line2DPathEffectProps, Path1DPathEffectProps, Path2DPathEffectProps, } from "../dom/types"; @@ -47,3 +49,19 @@ export const renderCornerPathEffect = ( "worklet"; throw new Error("Not implemented"); }; + +export const renderSumPathEffect = ( + _ctx: DrawingContext, + _props: ChildrenProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; + +export const renderLine2DPathEffect = ( + _ctx: DrawingContext, + _props: Line2DPathEffectProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; diff --git a/package/src/sg/Renderer.ts b/package/src/sg/Renderer.ts index cdadc2051a..e4e7dfbd7e 100644 --- a/package/src/sg/Renderer.ts +++ b/package/src/sg/Renderer.ts @@ -27,6 +27,7 @@ import { import type { PropMap, SGNode } from "./Node"; import { renderGlyphs, + renderParagraph, renderText, renderTextBlob, renderTextPath, @@ -64,9 +65,17 @@ import { renderCornerPathEffect, renderDashPathEffect, renderDiscretePathEffect, + renderLine2DPathEffect, renderPath1DPathEffect, renderPath2DPathEffect, + renderSumPathEffect, } from "./PathEffects"; +import { + renderBackdropFilter, + renderBlend, + renderBox, + renderBoxShadow, +} from "./Mixed"; const materialize =

(props: AnimatedProps

) => { "worklet"; diff --git a/package/src/sg/Shaders.ts b/package/src/sg/Shaders.ts index 0d34077c31..fe2ace6273 100644 --- a/package/src/sg/Shaders.ts +++ b/package/src/sg/Shaders.ts @@ -1,6 +1,5 @@ import type { ColorProps, - DiscretePathEffectProps, ImageShaderProps, LinearGradientProps, RadialGradientProps, diff --git a/package/src/sg/Text.ts b/package/src/sg/Text.ts index abf8dedf5f..215998253e 100644 --- a/package/src/sg/Text.ts +++ b/package/src/sg/Text.ts @@ -1,5 +1,6 @@ import type { GlyphsProps, + ParagraphProps, TextBlobProps, TextPathProps, TextProps, @@ -34,3 +35,11 @@ export const renderGlyphs = (_ctx: DrawingContext, _props: GlyphsProps) => { // ctx.canvas.drawGlyphs(glyphs, positions, font, ctx.paint); throw new Error("Not implemented"); }; + +export const renderParagraph = ( + _ctx: DrawingContext, + _props: ParagraphProps +) => { + "worklet"; + throw new Error("Not implemented"); +}; From 14a22ea1c21393292b312acde035f03299e4cf13 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Mon, 1 Jul 2024 14:32:02 +0200 Subject: [PATCH 08/12] :wrench: --- package/src/sg/Context.ts | 35 +++-- package/src/sg/Drawing.ts | 41 ++++-- package/src/sg/Node.ts | 7 +- package/src/sg/__tests__/Breathe.spec.tsx | 156 ++++++++++++++++++++++ 4 files changed, 202 insertions(+), 37 deletions(-) create mode 100644 package/src/sg/__tests__/Breathe.spec.tsx diff --git a/package/src/sg/Context.ts b/package/src/sg/Context.ts index 94b359a2f0..bf8d37aebd 100644 --- a/package/src/sg/Context.ts +++ b/package/src/sg/Context.ts @@ -1,28 +1,23 @@ -import type { - SkCanvas, - SkColorFilter, - SkImageFilter, - SkMaskFilter, - SkPaint, - SkPathEffect, - SkShader, - Skia, -} from "../skia/types"; +import type { SkCanvas, SkPaint, Skia } from "../skia/types"; -export interface DrawingContext { +export interface PaintingContext { + paints: SkPaint[]; + // maskFilters: SkMaskFilter[]; + // shaders: SkShader[]; + // pathEffects: SkPathEffect[]; + // imageFilters: SkImageFilter[]; + // colorFilters: SkColorFilter[]; +} + +export interface DrawingContext extends PaintingContext { Skia: Skia; canvas: SkCanvas; - paint: SkPaint; } -export interface PaintingContext { - paints: SkPaint[]; - maskFilters: SkMaskFilter[]; - shaders: SkShader[]; - pathEffects: SkPathEffect[]; - imageFilters: SkImageFilter[]; - colorFilters: SkColorFilter[]; -} +export const getPaint = (ctx: DrawingContext) => { + "worklet"; + return ctx.paints[ctx.paints.length - 1]; +}; // export const processContext = ( // ctx: DrawingContext, diff --git a/package/src/sg/Drawing.ts b/package/src/sg/Drawing.ts index 515581813a..16abe68f2d 100644 --- a/package/src/sg/Drawing.ts +++ b/package/src/sg/Drawing.ts @@ -29,23 +29,26 @@ import { saturate } from "../renderer"; import { BlendMode, FillType, PointMode, VertexMode } from "../skia"; import type { Skia } from "../skia/types"; -import type { DrawingContext } from "./Context"; +import { getPaint, type DrawingContext } from "./Context"; export const renderCircle = (ctx: DrawingContext, props: CircleProps) => { "worklet"; const { c, r } = processCircle(ctx.Skia, props); - ctx.canvas.drawCircle(c.x, c.y, r, ctx.paint); + const paint = getPaint(ctx); + ctx.canvas.drawCircle(c.x, c.y, r, paint); }; export const renderFill = (ctx: DrawingContext, _props: DrawingNodeProps) => { "worklet"; - ctx.canvas.drawPaint(ctx.paint); + const paint = getPaint(ctx); + ctx.canvas.drawPaint(paint); }; export const renderPoints = (ctx: DrawingContext, props: PointsProps) => { "worklet"; const { points, mode } = props; - ctx.canvas.drawPoints(PointMode[enumKey(mode)], points, ctx.paint); + const paint = getPaint(ctx); + ctx.canvas.drawPoints(PointMode[enumKey(mode)], points, paint); }; const computePath = (ctx: DrawingContext, props: PathProps) => { @@ -82,25 +85,29 @@ const computePath = (ctx: DrawingContext, props: PathProps) => { export const renderPath = (ctx: DrawingContext, props: PathProps) => { "worklet"; const path = computePath(ctx, props); - ctx.canvas.drawPath(path, ctx.paint); + const paint = getPaint(ctx); + ctx.canvas.drawPath(path, paint); }; export const renderRect = (ctx: DrawingContext, props: RectProps) => { "worklet"; const rect = processRect(ctx.Skia, props); - ctx.canvas.drawRect(rect, ctx.paint); + const paint = getPaint(ctx); + ctx.canvas.drawRect(rect, paint); }; export const renderRRect = (ctx: DrawingContext, props: RoundedRectProps) => { "worklet"; const rrect = processRRect(ctx.Skia, props); - ctx.canvas.drawRRect(rrect, ctx.paint); + const paint = getPaint(ctx); + ctx.canvas.drawRRect(rrect, paint); }; export const renderOval = (ctx: DrawingContext, props: OvalProps) => { "worklet"; const oval = processRect(ctx.Skia, props); - ctx.canvas.drawOval(oval, ctx.paint); + const paint = getPaint(ctx); + ctx.canvas.drawOval(oval, paint); }; const processImage = (Skia: Skia, props: ImageProps) => { @@ -134,13 +141,15 @@ export const renderImage = (ctx: DrawingContext, props: ImageProps) => { if (!image) { return; } - ctx.canvas.drawImageRect(image, src, dst, ctx.paint); + const paint = getPaint(ctx); + ctx.canvas.drawImageRect(image, src, dst, paint); }; export const renderLine = (ctx: DrawingContext, props: LineProps) => { "worklet"; const { p1, p2 } = props; - ctx.canvas.drawLine(p1.x, p1.y, p2.x, p2.y, ctx.paint); + const paint = getPaint(ctx); + ctx.canvas.drawLine(p1.x, p1.y, p2.x, p2.y, paint); }; const processPatch = (Skia: Skia, props: PatchProps) => { @@ -177,7 +186,8 @@ export const renderPatch = (ctx: DrawingContext, props: PatchProps) => { "worklet"; const { texture } = props; const { colors, points, mode } = processPatch(ctx.Skia, props); - ctx.canvas.drawPatch(points, colors, texture, mode, ctx.paint); + const paint = getPaint(ctx); + ctx.canvas.drawPatch(points, colors, texture, mode, paint); }; export const renderVertices = (ctx: DrawingContext, props: VerticesProps) => { @@ -194,13 +204,15 @@ export const renderVertices = (ctx: DrawingContext, props: VerticesProps) => { colors ? colors.map((c) => ctx.Skia.Color(c)) : undefined, indices ); - ctx.canvas.drawVertices(vert, blend, ctx.paint); + const paint = getPaint(ctx); + ctx.canvas.drawVertices(vert, blend, paint); }; export const renderDiffRect = (ctx: DrawingContext, props: DiffRectProps) => { "worklet"; const { outer, inner } = props; - ctx.canvas.drawDRRect(outer, inner, ctx.paint); + const paint = getPaint(ctx); + ctx.canvas.drawDRRect(outer, inner, paint); }; export const renderPicture = (ctx: DrawingContext, props: PictureProps) => { @@ -239,7 +251,8 @@ export const renderAtlas = (ctx: DrawingContext, props: AtlasProps) => { const { image, sprites, transforms, colors, blendMode } = props; const blend = blendMode ? BlendMode[enumKey(blendMode)] : undefined; if (image) { - ctx.canvas.drawAtlas(image, sprites, transforms, ctx.paint, blend, colors); + const paint = getPaint(ctx); + ctx.canvas.drawAtlas(image, sprites, transforms, paint, blend, colors); } }; diff --git a/package/src/sg/Node.ts b/package/src/sg/Node.ts index 9bc6174c32..d44856ae47 100644 --- a/package/src/sg/Node.ts +++ b/package/src/sg/Node.ts @@ -121,13 +121,14 @@ type UnknownProps = Record; export interface SGNode

{ type: NodeType; props: AnimatedProps

; - // children?: SGNode[]; + children?: SGNode[]; } export const createNode = ( type: T, - props: AnimatedProps + props: AnimatedProps, + children?: SGNode[] ): SGNode => { "worklet"; - return { type, props }; + return { type, props, children }; }; diff --git a/package/src/sg/__tests__/Breathe.spec.tsx b/package/src/sg/__tests__/Breathe.spec.tsx new file mode 100644 index 0000000000..30a01f6e34 --- /dev/null +++ b/package/src/sg/__tests__/Breathe.spec.tsx @@ -0,0 +1,156 @@ +import { importSkia, width, height } from "../../renderer/__tests__/setup"; +import { setupSkia } from "../../skia/__tests__/setup"; +import { processResult } from "../../__tests__/setup"; +import { createNode } from "../Node"; +import { NodeType } from "../../dom/types"; +import { renderNode } from "../Renderer"; + +describe("Breathe", () => { + it("Apple Breathe Demo", () => { + const { surface, canvas } = setupSkia(width, height); + const { Skia, vec, polar2Canvas } = importSkia(); + const c = vec(width / 2, height / 2); + const c1 = Skia.Color("#61bea2"); + const c2 = Skia.Color("#529ca0"); + const R = width / 4; + const color = Skia.Color("rgb(36,43,56)"); + const fill = createNode(NodeType.Fill, {}); + + const blur = createNode(NodeType.BlurMaskFilter, { + blur: 10, + style: "solid", + respectCTM: true, + }); + + const ringChildren = []; + for (let i = 0; i < 6; i++) { + const theta = (i * (2 * Math.PI)) / 6; + const matrix = Skia.Matrix(); + const { x, y } = polar2Canvas({ theta, radius: R }, { x: 0, y: 0 }); + matrix.translate(x, y); + const ring = createNode( + NodeType.Group, + { + matrix, + color: i % 2 ? c1 : c2, + }, + [createNode(NodeType.Circle, { c, r: R })] + ); + ringChildren.push(ring); + } + const rings = createNode(NodeType.Group, { blendMode: "screen" }, [ + blur, + ...ringChildren, + ]); + const root = createNode( + NodeType.Group, + { + color, + }, + [fill, rings] + ); + const ctx = { + Skia, + canvas, + paints: [Skia.Paint()], + }; + renderNode(ctx, root); + processResult(surface, "snapshots/demos/breathe.png"); + }); + // it("1Demo", () => { + + // }); + // it("Apple Breathe Demo with the new API", () => { + // const { surface, canvas } = setupSkia(width, height); + // const { Skia, vec, polar2Canvas } = importSkia(); + // const Sk = getSkDOM(); + // const c = vec(width / 2, height / 2); + // const c1 = Skia.Color("#61bea2"); + // const c2 = Skia.Color("#529ca0"); + // const R = width / 4; + // const color = Skia.Color("rgb(36,43,56)"); + // const root = Sk.Group({ color }); + // root.addChild(Sk.Fill()); + // const rings = Sk.Group({ + // blendMode: "screen", + // }); + // const blur = Sk.BlurMaskFilter({ + // blur: 10, + // style: "solid", + // respectCTM: true, + // }); + // rings.addChild(blur); + // for (let i = 0; i < 6; i++) { + // const theta = (i * (2 * Math.PI)) / 6; + // const matrix = Skia.Matrix(); + // const { x, y } = polar2Canvas({ theta, radius: R }, { x: 0, y: 0 }); + // matrix.translate(x, y); + // rings.addChild(Sk.Circle({ c, r: R, matrix, color: i % 2 ? c1 : c2 })); + // } + // root.addChild(rings); + // const ctx = new JsiDrawingContext(Skia, canvas); + // root.render(ctx); + // processResult(surface, "snapshots/demos/breathe.png"); + // }); + // it("Apple Breathe Demo with animations", () => { + // const { surface, canvas } = setupSkia(width, height); + // const { Skia, vec, polar2Canvas } = importSkia(); + // const Sk = getSkDOM(); + // const c = vec(width / 2, height / 2); + // const c1 = Skia.Color("#61bea2"); + // const c2 = Skia.Color("#529ca0"); + // const R = width / 4; + // const color = Skia.Color("rgb(36,43,56)"); + // const root = Sk.Group({ color }); + // root.addChild(Sk.Fill()); + // const rings = Sk.Group({ + // blendMode: "screen", + // }); + // const blur = Sk.BlurMaskFilter({ + // blur: 10, + // style: "solid", + // respectCTM: true, + // }); + // rings.addChild(blur); + // for (let i = 0; i < 6; i++) { + // const theta = (i * (2 * Math.PI)) / 6; + // const matrix = Skia.Matrix(); + // const { x, y } = polar2Canvas({ theta, radius: R }, { x: 0, y: 0 }); + // matrix.translate(x, y); + // rings.addChild(Sk.Circle({ c, r: R, matrix, color: i % 2 ? c1 : c2 })); + // } + // root.addChild(rings); + // const ctx = new JsiDrawingContext(Skia, canvas); + // root.render(ctx); + // processResult(surface, "snapshots/demos/breathe.png"); + // blur.setProp("blur", 0); + // root.setProp("transform", [ + // { translateX: c.x }, + // { translateY: c.y }, + // { rotate: Math.PI / 4 }, + // { translateX: -c.x }, + // { translateY: -c.y }, + // ]); + // for (let i = 0; i < 6; i++) { + // const theta = (i * (2 * Math.PI)) / 6; + // const matrix = Skia.Matrix(); + // const scale = 0.5; + // const { x, y } = polar2Canvas({ theta, radius: 0.5 * R }, { x: 0, y: 0 }); + // matrix.translate(x, y); + // // eslint-disable-next-line @typescript-eslint/no-explicit-any + // const ring = rings.children()[i + 1] as any; + // ring.setProp("matrix", undefined); + // ring.setProp("transform", [ + // { translateX: c.x }, + // { translateY: c.y }, + // { translateX: x }, + // { translateY: y }, + // { scale }, + // { translateX: -c.x }, + // { translateY: -c.y }, + // ]); + // } + // root.render(ctx); + // processResult(surface, "snapshots/demos/breathe2.png"); + // }); +}); From 561f86964d694c30e84771a307f9fd5ee0229ca2 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Mon, 1 Jul 2024 14:58:57 +0200 Subject: [PATCH 09/12] :wrench: --- package/src/sg/Drawing.ts | 2 +- package/src/sg/Renderer.ts | 7 +++++-- package/src/sg/__tests__/Breathe.spec.tsx | 5 +++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/package/src/sg/Drawing.ts b/package/src/sg/Drawing.ts index 16abe68f2d..ecf2e2e53f 100644 --- a/package/src/sg/Drawing.ts +++ b/package/src/sg/Drawing.ts @@ -26,7 +26,7 @@ import { processRect, } from "../dom/nodes"; import { saturate } from "../renderer"; -import { BlendMode, FillType, PointMode, VertexMode } from "../skia"; +import { BlendMode, FillType, PointMode, VertexMode } from "../skia/types"; import type { Skia } from "../skia/types"; import { getPaint, type DrawingContext } from "./Context"; diff --git a/package/src/sg/Renderer.ts b/package/src/sg/Renderer.ts index e4e7dfbd7e..f815662a87 100644 --- a/package/src/sg/Renderer.ts +++ b/package/src/sg/Renderer.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { NodeType } from "../dom/types"; import type { AnimatedProps } from "../renderer"; -import Rea from "../external/reanimated/ReanimatedProxy"; import { exhaustiveCheck } from "../renderer/typeddash"; import { type DrawingContext } from "./Context"; @@ -77,12 +76,16 @@ import { renderBoxShadow, } from "./Mixed"; +const isSharedValueKind = (value: unknown): value is { value: unknown } => { + return typeof value === "object" && value !== null && "value" in value; +}; + const materialize =

(props: AnimatedProps

) => { "worklet"; const materializedProps: Record = {}; for (const key in props) { const value = props[key]; - if (Rea.isSharedValue(value)) { + if (isSharedValueKind(value)) { materializedProps[key] = value.value; } else { materializedProps[key] = value; diff --git a/package/src/sg/__tests__/Breathe.spec.tsx b/package/src/sg/__tests__/Breathe.spec.tsx index 30a01f6e34..ae9f1e6ac3 100644 --- a/package/src/sg/__tests__/Breathe.spec.tsx +++ b/package/src/sg/__tests__/Breathe.spec.tsx @@ -1,9 +1,10 @@ import { importSkia, width, height } from "../../renderer/__tests__/setup"; -import { setupSkia } from "../../skia/__tests__/setup"; import { processResult } from "../../__tests__/setup"; +import type { SGNode } from "../Node"; import { createNode } from "../Node"; import { NodeType } from "../../dom/types"; import { renderNode } from "../Renderer"; +import { setupSkia } from "../../skia/__tests__/setup"; describe("Breathe", () => { it("Apple Breathe Demo", () => { @@ -22,7 +23,7 @@ describe("Breathe", () => { respectCTM: true, }); - const ringChildren = []; + const ringChildren: SGNode[] = []; for (let i = 0; i < 6; i++) { const theta = (i * (2 * Math.PI)) / 6; const matrix = Skia.Matrix(); From 212032c954bd532896b3f1d3d20d73438f625465 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Mon, 1 Jul 2024 15:10:45 +0200 Subject: [PATCH 10/12] :wrench: --- package/src/sg/Renderer.ts | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/package/src/sg/Renderer.ts b/package/src/sg/Renderer.ts index f815662a87..a2dddf19eb 100644 --- a/package/src/sg/Renderer.ts +++ b/package/src/sg/Renderer.ts @@ -1,7 +1,9 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import type { GroupProps } from "../dom/types"; import { NodeType } from "../dom/types"; import type { AnimatedProps } from "../renderer"; import { exhaustiveCheck } from "../renderer/typeddash"; +import { processTransform3d } from "../skia/types"; import { type DrawingContext } from "./Context"; import { @@ -77,6 +79,7 @@ import { } from "./Mixed"; const isSharedValueKind = (value: unknown): value is { value: unknown } => { + "worklet"; return typeof value === "object" && value !== null && "value" in value; }; @@ -94,16 +97,35 @@ const materialize =

(props: AnimatedProps

) => { return materializedProps as any; }; +const processContext = (ctx: DrawingContext, props: GroupProps) => { + "worklet"; + let restore = false; + if (props.matrix) { + ctx.canvas.save(); + ctx.canvas.concat(props.matrix); + restore = true; + } else if (props.transform) { + ctx.canvas.save(); + ctx.canvas.concat(processTransform3d(props.transform)); + restore = true; + } + + return { restore }; +}; + export const renderNode = (ctx: DrawingContext, node: SGNode) => { "worklet"; const materializedProps = materialize(node.props) as unknown; - //const { restore, restorePaint } = processContext(ctx, materializedProps as PropMap[typeof node.type]); - //const { invertClip, layer, matrix, transform } = materializedProps; - + let restore = false; switch (node.type) { case NodeType.Group: - // nothing to do here - //renderGroup(ctx, materializedProps as PropMap[typeof node.type]); + const result = processContext( + ctx, + materializedProps as PropMap[typeof node.type] + ); + // eslint-disable-next-line prefer-destructuring + restore = result.restore; + node.children?.forEach((child) => renderNode(ctx, child)); break; case NodeType.Layer: renderLayer(ctx, materializedProps as PropMap[typeof node.type]); @@ -333,9 +355,9 @@ export const renderNode = (ctx: DrawingContext, node: SGNode) => { default: return exhaustiveCheck(node.type); } - // if (restore) { - // ctx.canvas.restore(); - // } + if (restore) { + ctx.canvas.restore(); + } // if (restorePaint) { // //ctx.paint.restore(); // } From 8bc0e49e90d612dcc6a093352c796037474638a5 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Mon, 1 Jul 2024 15:13:42 +0200 Subject: [PATCH 11/12] :wrench: --- package/src/sg/MaskFilters.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/src/sg/MaskFilters.ts b/package/src/sg/MaskFilters.ts index 87da5f9357..ffcc230d8d 100644 --- a/package/src/sg/MaskFilters.ts +++ b/package/src/sg/MaskFilters.ts @@ -7,5 +7,5 @@ export const renderBlurMaskFilter = ( _props: BlurMaskFilterProps ) => { "worklet"; - throw new Error("Not implemented"); + console.warn("Not implemented"); }; From a30cd486c989cc8c712353d3305bdf60f0e80091 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Thu, 4 Jul 2024 07:54:34 +0200 Subject: [PATCH 12/12] :wrench: --- package/src/sg/Context.ts | 33 ++++++++++++++++++------ package/src/sg/Renderer.ts | 20 +------------- package/src/sg/__tests__/Simple.spec.tsx | 21 +++++++++++++++ 3 files changed, 47 insertions(+), 27 deletions(-) create mode 100644 package/src/sg/__tests__/Simple.spec.tsx diff --git a/package/src/sg/Context.ts b/package/src/sg/Context.ts index bf8d37aebd..8668f8c655 100644 --- a/package/src/sg/Context.ts +++ b/package/src/sg/Context.ts @@ -1,4 +1,10 @@ -import type { SkCanvas, SkPaint, Skia } from "../skia/types"; +import type { GroupProps } from "../dom/types"; +import { + processTransform3d, + type SkCanvas, + type SkPaint, + type Skia, +} from "../skia/types"; export interface PaintingContext { paints: SkPaint[]; @@ -19,10 +25,21 @@ export const getPaint = (ctx: DrawingContext) => { return ctx.paints[ctx.paints.length - 1]; }; -// export const processContext = ( -// ctx: DrawingContext, -// props: Record -// ) => { -// "worklet"; -// return { restore: false, restorePaint: false }; -// }; +export const processContext = (ctx: DrawingContext, props: GroupProps) => { + "worklet"; + let restore = false; + if (props.matrix) { + ctx.canvas.save(); + ctx.canvas.concat(props.matrix); + restore = true; + } else if (props.transform) { + ctx.canvas.save(); + ctx.canvas.concat(processTransform3d(props.transform)); + restore = true; + } + if (props.color) { + const paint = getPaint(ctx); + paint.setColor(ctx.Skia.Color(props.color)); + } + return { restore }; +}; diff --git a/package/src/sg/Renderer.ts b/package/src/sg/Renderer.ts index a2dddf19eb..bd4f208187 100644 --- a/package/src/sg/Renderer.ts +++ b/package/src/sg/Renderer.ts @@ -1,11 +1,9 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { GroupProps } from "../dom/types"; import { NodeType } from "../dom/types"; import type { AnimatedProps } from "../renderer"; import { exhaustiveCheck } from "../renderer/typeddash"; -import { processTransform3d } from "../skia/types"; -import { type DrawingContext } from "./Context"; +import { processContext, type DrawingContext } from "./Context"; import { renderAtlas, renderCircle, @@ -97,22 +95,6 @@ const materialize =

(props: AnimatedProps

) => { return materializedProps as any; }; -const processContext = (ctx: DrawingContext, props: GroupProps) => { - "worklet"; - let restore = false; - if (props.matrix) { - ctx.canvas.save(); - ctx.canvas.concat(props.matrix); - restore = true; - } else if (props.transform) { - ctx.canvas.save(); - ctx.canvas.concat(processTransform3d(props.transform)); - restore = true; - } - - return { restore }; -}; - export const renderNode = (ctx: DrawingContext, node: SGNode) => { "worklet"; const materializedProps = materialize(node.props) as unknown; diff --git a/package/src/sg/__tests__/Simple.spec.tsx b/package/src/sg/__tests__/Simple.spec.tsx new file mode 100644 index 0000000000..ad323070db --- /dev/null +++ b/package/src/sg/__tests__/Simple.spec.tsx @@ -0,0 +1,21 @@ +import { importSkia, width, height } from "../../renderer/__tests__/setup"; +import { processResult } from "../../__tests__/setup"; +import { createNode } from "../Node"; +import { NodeType } from "../../dom/types"; +import { renderNode } from "../Renderer"; +import { setupSkia } from "../../skia/__tests__/setup"; + +describe("Simple", () => { + it("Fill", () => { + const { surface, canvas } = setupSkia(width, height); + const { Skia } = importSkia(); + const root = createNode(NodeType.Fill, { color: "red" }); + const ctx = { + Skia, + canvas, + paints: [Skia.Paint()], + }; + renderNode(ctx, root); + processResult(surface, "snapshots/demos/simple1.png"); + }); +});