diff --git a/docs/docs/assets/group/rasterize.png b/docs/docs/assets/group/rasterize.png deleted file mode 100644 index 13509a00ce..0000000000 Binary files a/docs/docs/assets/group/rasterize.png and /dev/null differ diff --git a/docs/docs/getting-started/web.mdx b/docs/docs/getting-started/web.mdx index 24e46906ad..0fe9cee7c6 100644 --- a/docs/docs/getting-started/web.mdx +++ b/docs/docs/getting-started/web.mdx @@ -164,11 +164,13 @@ LoadSkiaWeb({ ## Unsupported Features Below are the React Native Skia APIs which are not yet supported on React Native Web. -Some of these features are a work in progress, and some others will come later. +If you are interested to use one of these features, please make [a feature request on GitHub](https://github.com/Shopify/react-native-skia/issues/new/choose). -**Coming soon** +**Unsupported** -* `Font::GetPath` +* `PathEffectFactory.MakeSum()` +* `PathEffectFactory.MakeCompose()` +* `Font.GetPath()` * `ShaderFilter` **Unplanned** diff --git a/docs/docs/group.md b/docs/docs/group.md index f245ed8880..90b0a21e91 100644 --- a/docs/docs/group.md +++ b/docs/docs/group.md @@ -268,7 +268,7 @@ const Clip = () => { }; ``` -![Rasterize](assets/group/rasterize.png) +Rasterize ## Fitbox @@ -301,12 +301,18 @@ const Hello = () => { return ( - + ); } ``` -![Hello Skia](assets/fitbox/hello.png) + diff --git a/docs/docs/paint/assets/assignment.png b/docs/docs/paint/assets/assignment.png deleted file mode 100644 index c04ebcdf93..0000000000 Binary files a/docs/docs/paint/assets/assignment.png and /dev/null differ diff --git a/docs/docs/paint/assets/blend-mode.png b/docs/docs/paint/assets/blend-mode.png deleted file mode 100644 index 4ce44232e0..0000000000 Binary files a/docs/docs/paint/assets/blend-mode.png and /dev/null differ diff --git a/docs/docs/paint/assets/inheritance.png b/docs/docs/paint/assets/inheritance.png deleted file mode 100644 index 5d2cfce5ff..0000000000 Binary files a/docs/docs/paint/assets/inheritance.png and /dev/null differ diff --git a/docs/docs/paint/assets/opacity.png b/docs/docs/paint/assets/opacity.png deleted file mode 100644 index da17d725b6..0000000000 Binary files a/docs/docs/paint/assets/opacity.png and /dev/null differ diff --git a/docs/docs/paint/assets/strokes.png b/docs/docs/paint/assets/strokes.png deleted file mode 100644 index 7d83bfd7cc..0000000000 Binary files a/docs/docs/paint/assets/strokes.png and /dev/null differ diff --git a/docs/docs/paint/overview.md b/docs/docs/paint/overview.md index 561fe15a1b..d1f03fb347 100644 --- a/docs/docs/paint/overview.md +++ b/docs/docs/paint/overview.md @@ -35,14 +35,18 @@ When drawing something, you can pass Paint components as children to add strokes In the example below, the circle has one light blue fill and two stroke paints. ```tsx twoslash -import {Canvas, Circle, Paint} from "@shopify/react-native-skia"; +import {Canvas, Circle, Paint, vec} from "@shopify/react-native-skia"; + +const width = 256; +const height = 256; export const PaintDemo = () => { const strokeWidth = 10; - const r = 128 - strokeWidth / 2; + const c = vec(width / 2, height / 2); + const r = (width - strokeWidth) / 2; return ( - - + + @@ -52,7 +56,7 @@ export const PaintDemo = () => { }; ``` -![Paint Fill and strokes](assets/strokes.png) +Paint Fill and strokes ## Inheritance @@ -62,10 +66,13 @@ In the example below, the first circle will be filled with a light blue color, a ```tsx twoslash import {Canvas, Circle, Paint, Group} from "@shopify/react-native-skia"; +const width = 256; +const height = 256; + export const PaintDemo = () => { - const r = 128; + const r = width / 6; return ( - + @@ -77,17 +84,21 @@ export const PaintDemo = () => { }; ``` -![Paint Inheritance](assets/inheritance.png) +Paint Inheritance + Complex painting attributes like a shader or an image filter can be passed as children to a group or a drawing. ```tsx twoslash import {Canvas, Circle, Group, LinearGradient, vec} from "@shopify/react-native-skia"; +const width = 256; +const height = 256; + export const PaintDemo = () => { - const r = 128; + const r = width/2; return ( - + { const paint = usePaintRef(); return ( {/* We can assign the ref to any shape. This will be handy in advanced use-case */} - + ); }; ``` + + + diff --git a/docs/docs/paint/properties.md b/docs/docs/paint/properties.md index 682c0563c5..e1a56c649e 100644 --- a/docs/docs/paint/properties.md +++ b/docs/docs/paint/properties.md @@ -34,26 +34,40 @@ Replaces alpha, leaving RGBA unchanged. 0 means fully transparent, 1.0 means opa When setting opacity in a Group component, the alpha component of all descending colors will inherit that value. ```tsx twoslash -import {Canvas, Circle, Group, Paint} from "@shopify/react-native-skia"; +import {Canvas, Circle, Group, Paint, vec} from "@shopify/react-native-skia"; + +const width = 256; +const height = 256; +const strokeWidth = 30; +const r = width / 2 - strokeWidth / 2; +const c = vec(width / 2, height / 2); export const OpacityDemo = () => { - const strokeWidth = 10; - const r = 128 - strokeWidth / 2; return ( - + - - - - - + + + - ) + ); }; ``` -![Opacity](./assets/opacity.png) +Paint Opacity ## blendMode diff --git a/docs/static/img/group/rasterize.png b/docs/static/img/group/rasterize.png new file mode 100644 index 0000000000..d972c6a43e Binary files /dev/null and b/docs/static/img/group/rasterize.png differ diff --git a/docs/static/img/group/scale-path.png b/docs/static/img/group/scale-path.png new file mode 100644 index 0000000000..82cfcdebc3 Binary files /dev/null and b/docs/static/img/group/scale-path.png differ diff --git a/docs/static/img/paint/assignement.png b/docs/static/img/paint/assignement.png new file mode 100644 index 0000000000..cd8ebf150d Binary files /dev/null and b/docs/static/img/paint/assignement.png differ diff --git a/docs/static/img/paint/inheritance.png b/docs/static/img/paint/inheritance.png new file mode 100644 index 0000000000..4b478a0a64 Binary files /dev/null and b/docs/static/img/paint/inheritance.png differ diff --git a/docs/static/img/paint/opacity.png b/docs/static/img/paint/opacity.png new file mode 100644 index 0000000000..904204259e Binary files /dev/null and b/docs/static/img/paint/opacity.png differ diff --git a/docs/static/img/paint/stroke.png b/docs/static/img/paint/stroke.png new file mode 100644 index 0000000000..dbaff689a2 Binary files /dev/null and b/docs/static/img/paint/stroke.png differ diff --git a/package/src/renderer/__tests__/documentation/Group.spec.tsx b/package/src/renderer/__tests__/documentation/Group.spec.tsx index 13cd265e4b..1591d4b95a 100644 --- a/package/src/renderer/__tests__/documentation/Group.spec.tsx +++ b/package/src/renderer/__tests__/documentation/Group.spec.tsx @@ -1,13 +1,54 @@ import React from "react"; import { docPath, processResult } from "../../../__tests__/setup"; -import { Image, Group, Fill } from "../../components"; -import { drawOnNode, width, loadImage, importSkia } from "../setup"; +import { + Image, + Group, + Fill, + FitBox, + Path, + Paint, + ColorMatrix, + Blur, + Circle, +} from "../../components"; +import { + drawOnNode, + width, + loadImage, + importSkia, + height, + PIXEL_RATIO, +} from "../setup"; const size = width; const padding = 48; const r = 24; +const TestRasterization = () => { + const { usePaintRef, vec } = importSkia(); + const paint = usePaintRef(); + const c = vec(width / 2, height / 2); + const radius = c.x * 0.95; + return ( + <> + + + + + + + + + + + ); +}; + describe("Group", () => { it("Should use a rectangle as a clip", () => { const image = loadImage("skia/__tests__/assets/oslo.jpg"); @@ -100,4 +141,30 @@ describe("Group", () => { ); processResult(surface, docPath("group/invert-clip.png")); }); + it("Should scale an SVG Path properly", () => { + const { rect, Skia } = importSkia(); + const svgPath = + // eslint-disable-next-line max-len + "M481.586 193.457C470.446 176.319 382.871 101.323 313.771 101.323C244.671 101.323 207.195 126.054 193.668 142.763C149.967 196.747 134.971 249.875 148.681 302.146C166.676 365.556 216.376 423.397 297.781 475.668C391.183 528.795 451.166 589.207 477.73 656.902C487.156 686.893 488.441 716.456 481.586 745.591C474.731 774.725 461.021 801.289 440.455 825.282C423.317 848.419 400.609 865.128 372.332 875.411C344.054 884.837 309.778 892.12 269.504 897.262C172.674 904.974 93.8398 890.407 33 853.56M559.992 689.035C667.105 531.366 746.796 399.832 799.067 294.434C811.92 264.442 821.346 241.735 827.344 226.31C833.343 210.029 839.341 188.607 845.339 162.043C851.338 135.479 853.48 111.058 851.766 88.7783C849.195 66.4989 838.056 51.0748 818.347 39.9351C798.638 28.7954 784.212 31.7989 761.792 43.7911C724.945 63.4998 700.095 97.3473 687.242 145.334C679.53 165.899 671.817 189.892 664.105 217.313C657.25 244.734 652.109 265.728 648.681 280.295C646.111 294.862 641.398 321.426 634.542 359.987C627.687 397.69 623.403 419.969 621.689 426.825C604.551 533.937 583.985 689.464 559.992 893.406C586.556 800.861 616.976 727.167 651.252 672.326C663.248 648.333 673.531 629.481 682.1 615.771C690.669 602.06 703.094 587.065 719.375 570.784C736.513 554.502 754.508 542.506 773.36 534.794C837.627 510.801 883.9 512.943 912.177 541.221C929.315 559.215 937.884 581.066 937.884 606.773C938.741 632.48 928.887 652.617 908.321 667.185C868.047 689.464 806.779 696.748 724.517 689.035C738.227 693.32 748.51 697.176 755.365 700.604C763.077 703.174 772.503 707.459 783.643 713.457C795.639 719.455 804.637 726.739 810.635 735.308C817.49 743.877 821.775 753.731 823.488 764.871C824.345 769.155 825.631 777.296 827.344 789.293C829.915 801.289 832.057 810.287 833.771 816.285C835.485 822.283 837.627 829.995 840.198 839.421C843.626 848.847 847.482 856.987 851.766 863.843C856.907 869.841 862.906 875.839 869.761 881.838C891.183 902.403 926.745 899.832 976.445 874.125C991.012 867.27 1004.29 858.701 1016.29 848.418C1029.14 838.136 1041.14 825.711 1052.28 811.143C1064.28 795.719 1073.7 783.294 1080.56 773.868C1087.41 763.586 1096.84 748.59 1108.84 728.881C1120.83 709.173 1129.4 695.891 1134.54 689.035C1161.96 634.194 1189.38 579.352 1216.8 524.511C1174.82 629.909 1147.82 710.458 1135.83 766.156C1130.69 782.437 1128.54 801.289 1129.4 822.712C1130.26 844.134 1136.68 861.272 1148.68 874.125C1157.25 884.408 1167.96 891.263 1180.81 894.691C1194.53 898.119 1207.38 897.69 1219.38 893.406C1271.65 877.981 1314.06 847.99 1346.62 803.431C1365.48 777.724 1390.75 739.592 1422.46 689.035M1275.93 367.699C1263.93 367.699 1256.65 362.129 1254.08 350.989C1252.37 338.993 1253.65 328.71 1257.94 320.141C1261.37 313.272 1272.5 314.999 1283.64 314.999C1294.78 314.999 1303.74 321.228 1304.21 329.138M1804.21 655.616C1782.79 595.634 1756.65 558.358 1725.8 543.791C1696.67 526.653 1664.11 518.513 1628.12 519.37C1592.13 519.37 1559.99 528.796 1531.71 547.647C1505.15 563.071 1482.44 583.637 1463.59 609.344C1444.74 634.194 1431.89 661.615 1425.03 691.606C1419.03 720.741 1419.89 750.304 1427.6 780.295C1436.17 809.43 1450.74 834.28 1471.3 854.845C1503.87 882.266 1543.28 895.976 1589.56 895.976C1635.83 895.976 1675.67 882.266 1709.09 854.845C1722.8 841.135 1732.66 831.281 1738.66 825.282C1744.65 819.284 1751.51 810.715 1759.22 799.575C1767.79 788.436 1774.65 776.868 1779.79 764.871M1835.06 523.226C1811.92 618.341 1796.5 701.032 1788.78 771.298C1781.07 825.282 1791.35 862.557 1819.63 883.123C1841.05 900.261 1874.47 897.69 1919.89 875.411C1959.31 856.559 1997.01 819.712 2033 764.871"; + const path = Skia.Path.MakeFromSVGString(svgPath)!; + expect(path).toBeTruthy(); + const src = path.computeTightBounds(); + const strokeWidth = 30 * PIXEL_RATIO; + const surface = drawOnNode( + + + + ); + processResult(surface, docPath("group/scale-path.png")); + }); + it("Should use saveLayer() properly", () => { + const surface = drawOnNode(); + processResult(surface, docPath("group/rasterize.png")); + }); }); diff --git a/package/src/renderer/__tests__/documentation/paint/Overview.spec.tsx b/package/src/renderer/__tests__/documentation/paint/Overview.spec.tsx new file mode 100644 index 0000000000..caf81238b2 --- /dev/null +++ b/package/src/renderer/__tests__/documentation/paint/Overview.spec.tsx @@ -0,0 +1,89 @@ +import React from "react"; + +import { + drawOnNode, + PIXEL_RATIO, + width, + height, + importSkia, +} from "../../setup"; +import { Circle, Group, Paint } from "../../../components"; +import { docPath, processResult } from "../../../../__tests__/setup"; + +const TestPaintAssignment = () => { + const { usePaintRef } = importSkia(); + const r = width / 2; + const paint = usePaintRef(); + return ( + <> + + {/* We can assign the ref to any shape. This will be handy in advanced use-case */} + + + ); +}; + +describe("Paint", () => { + it("should draw the color fill and strokes properly", () => { + const { vec } = importSkia(); + const strokeWidth = 10 * PIXEL_RATIO; + const c = vec(width / 2, height / 2); + const r = (width - strokeWidth) / 2; + const surface = drawOnNode( + <> + + + + + + + ); + processResult(surface, docPath("paint/stroke.png")); + }); + + it("should use paint inheritance properly", () => { + const r = width / 6; + const strokeWidth = 10 * PIXEL_RATIO; + const surface = drawOnNode( + + + + + + + ); + processResult(surface, docPath("paint/inheritance.png")); + }); + + it("should use paint assignement properly", () => { + const surface = drawOnNode(); + processResult(surface, docPath("paint/assignement.png")); + }); + + it("should use the opacity property properly", () => { + const { vec } = importSkia(); + const strokeWidth = 30 * PIXEL_RATIO; + const r = width / 2 - strokeWidth / 2; + const c = vec(width / 2, height / 2); + const surface = drawOnNode( + + + + + + ); + processResult(surface, docPath("paint/opacity.png"), true); + }); +});