Skip to content

Commit

Permalink
Merge pull request #492 from Shopify/fix/rects
Browse files Browse the repository at this point in the history
Faster transform processing
  • Loading branch information
chrfalch authored May 20, 2022
2 parents 3a7097d + 5ffd45c commit d2599a0
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 108 deletions.
46 changes: 44 additions & 2 deletions package/cpp/api/JsiSkMatrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,51 @@ class JsiSkMatrix : public JsiSkWrappingSharedPtrHostObject<SkMatrix> {
: JsiSkWrappingSharedPtrHostObject<SkMatrix>(
context, std::make_shared<SkMatrix>(std::move(m))) {}


JSI_HOST_FUNCTION(preConcat) {
auto m3 = JsiSkMatrix::fromValue(runtime, arguments[0]);
getObject()->preConcat(*m3);
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION(preTranslate) {
auto x = arguments[0].asNumber();
auto y = arguments[1].asNumber();
getObject()->preTranslate(x, y);
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION(preScale) {
auto x = arguments[0].asNumber();
auto y = arguments[1].asNumber();
getObject()->preScale(x, y);
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION(preSkew) {
auto x = arguments[0].asNumber();
auto y = arguments[1].asNumber();
getObject()->preSkew(x, y);
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION(preRotate) {
auto a = arguments[0].asNumber();
getObject()->preRotate(a);
return jsi::Value::undefined();
}

JSI_EXPORT_FUNCTIONS(
JSI_EXPORT_FUNC(JsiSkMatrix, preConcat),
JSI_EXPORT_FUNC(JsiSkMatrix, preTranslate),
JSI_EXPORT_FUNC(JsiSkMatrix, preScale),
JSI_EXPORT_FUNC(JsiSkMatrix, preSkew),
JSI_EXPORT_FUNC(JsiSkMatrix, preRotate),
)

/**
Returns the underlying object from a host object of this type
*/
* Returns the underlying object from a host object of this type
*/
static std::shared_ptr<SkMatrix> fromValue(jsi::Runtime &runtime,
const jsi::Value &obj) {
const auto& object = obj.asObject(runtime);
Expand Down
129 changes: 24 additions & 105 deletions package/src/renderer/processors/math/Matrix3.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { exhaustiveCheck } from "../../typeddash";
import type { SkMatrix } from "../../../skia/Matrix";

export type Vec3 = readonly [number, number, number];

export type Matrix3 = readonly [Vec3, Vec3, Vec3];
import { Skia } from "../../../skia";

type Transform2dName =
| "translateX"
Expand Down Expand Up @@ -34,121 +30,44 @@ export type Transforms2d = readonly (
| Pick<Transformations, "rotate">
)[];

const identityMatrix: Matrix3 = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
];

const translateXMatrix = (x: number): Matrix3 => [
[1, 0, x],
[0, 1, 0],
[0, 0, 1],
];

const translateYMatrix = (y: number): Matrix3 => [
[1, 0, 0],
[0, 1, y],
[0, 0, 1],
];

const scaleMatrix = (s: number): Matrix3 => [
[s, 0, 0],
[0, s, 0],
[0, 0, 1],
];

const scaleXMatrix = (s: number): Matrix3 => [
[s, 0, 0],
[0, 1, 0],
[0, 0, 1],
];

const scaleYMatrix = (s: number): Matrix3 => [
[1, 0, 0],
[0, s, 0],
[0, 0, 1],
];

const skewXMatrix = (s: number): Matrix3 => [
[1, Math.tan(s), 0],
[0, 1, 0],
[0, 0, 1],
];

const skewYMatrix = (s: number): Matrix3 => [
[1, 0, 0],
[Math.tan(s), 1, 0],
[0, 0, 1],
];

const rotateZMatrix = (r: number): Matrix3 => [
[Math.cos(r), -1 * Math.sin(r), 0],
[Math.sin(r), Math.cos(r), 0],
[0, 0, 1],
];

const dot3 = (row: Vec3, col: Vec3) =>
row[0] * col[0] + row[1] * col[1] + row[2] * col[2];

const multiply3 = (m1: Matrix3, m2: Matrix3) => {
const col0 = [m2[0][0], m2[1][0], m2[2][0]] as const;
const col1 = [m2[0][1], m2[1][1], m2[2][1]] as const;
const col2 = [m2[0][2], m2[1][2], m2[2][2]] as const;
return [
[dot3(m1[0], col0), dot3(m1[0], col1), dot3(m1[0], col2)],
[dot3(m1[1], col0), dot3(m1[1], col1), dot3(m1[1], col2)],
[dot3(m1[2], col0), dot3(m1[2], col1), dot3(m1[2], col2)],
] as const;
};

export const matrixVecMul3 = (m: Matrix3, v: Vec3) =>
[dot3(m[0], v), dot3(m[1], v), dot3(m[2], v)] as const;

const skiaMatrix3 = (m: Matrix3): SkMatrix => {
return [
m[0][0],
m[0][1],
m[0][2],
m[1][0],
m[1][1],
m[1][2],
m[2][0],
m[2][1],
m[2][2],
];
};

export const processTransform2d = (transforms: Transforms2d) =>
skiaMatrix3(processTransform(transforms));

const processTransform = (transforms: Transforms2d) =>
transforms.reduce((acc, transform) => {
export const processTransform2d = (transforms: Transforms2d) => {
const m = Skia.Matrix();
for (const transform of transforms) {
const key = Object.keys(transform)[0] as Transform2dName;
const value = (transform as Pick<Transformations, typeof key>)[key];
if (key === "translateX") {
return multiply3(acc, translateXMatrix(value));
m.preTranslate(value, 0);
continue;
}
if (key === "translateY") {
return multiply3(acc, translateYMatrix(value));
m.preTranslate(0, value);
continue;
}
if (key === "scale") {
return multiply3(acc, scaleMatrix(value));
m.preScale(value, value);
continue;
}
if (key === "scaleX") {
return multiply3(acc, scaleXMatrix(value));
m.preScale(value, 0);
continue;
}
if (key === "scaleY") {
return multiply3(acc, scaleYMatrix(value));
m.preScale(0, value);
continue;
}
if (key === "skewX") {
return multiply3(acc, skewXMatrix(value));
m.preSkew(value, 0);
continue;
}
if (key === "skewY") {
return multiply3(acc, skewYMatrix(value));
m.preSkew(0, value);
continue;
}
if (key === "rotate" || key === "rotateZ") {
return multiply3(acc, rotateZMatrix(value));
m.preRotate((value * 180) / Math.PI);
continue;
}
return exhaustiveCheck(key);
}, identityMatrix);
exhaustiveCheck(key);
}
return m;
};
9 changes: 8 additions & 1 deletion package/src/skia/Matrix.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { SkJSIInstance } from "./JsiInstance";
export enum MatrixIndex {
ScaleX = 0,
SkewX = 1,
Expand All @@ -10,7 +11,7 @@ export enum MatrixIndex {
persp2 = 8,
}

export interface SkMatrix {
export interface SkMatrix extends SkJSIInstance<"Matrix"> {
0: number;
1: number;
2: number;
Expand All @@ -20,4 +21,10 @@ export interface SkMatrix {
6: number;
7: number;
8: number;

preConcat: (matrix: SkMatrix) => void;
preTranslate: (x: number, y: number) => void;
preScale: (x: number, y: number) => void;
preSkew: (x: number, y: number) => void;
preRotate: (theta: number) => void;
}

0 comments on commit d2599a0

Please sign in to comment.