[canvaskit] Handle passing matrix values into CK ourselves.
This means we take DOMMatrix everywhere now. This reduced the *_makeShader benchmark by ~25% (4 us -> 3 us) and cleaned up several callsites. Trimming this down saves ~3kb in uncompressed code size. Change-Id: Ie677c7ebb7bc97ed8cd4d4851a039b78b6f8079d Reviewed-on: https://skia-review.googlesource.com/c/skia/+/281018 Reviewed-by: Mike Reed <reed@google.com>
This commit is contained in:
parent
5384f4036f
commit
6bffe39c98
@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- Support for DOMMatrix in addition to the SkMatrix currently supported by some APIs. [WIP]
|
||||
- Support for DOMMatrix on all APIs that take SkMatrix (i.e. arrays or Float32Arrays of length 9).
|
||||
|
||||
### Removed
|
||||
- Previously deprecated functions MakeSkDashPathEffect, MakeLinearGradientShader,
|
||||
|
@ -87,26 +87,15 @@
|
||||
sk_sp<SkFontMgr> SkFontMgr_New_Custom_Data(const uint8_t** datas, const size_t* sizes, int n);
|
||||
#endif
|
||||
|
||||
// 3x3 Matrices
|
||||
struct SimpleMatrix {
|
||||
SkScalar scaleX, skewX, transX;
|
||||
SkScalar skewY, scaleY, transY;
|
||||
SkScalar pers0, pers1, pers2;
|
||||
struct OptionalMatrix : SkMatrix {
|
||||
OptionalMatrix(uintptr_t mPtr) {
|
||||
if (mPtr) {
|
||||
const SkScalar* nineMatrixValues = reinterpret_cast<const SkScalar*>(mPtr);
|
||||
this->set9(nineMatrixValues);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SkMatrix toSkMatrix(const SimpleMatrix& sm) {
|
||||
return SkMatrix::MakeAll(sm.scaleX, sm.skewX , sm.transX,
|
||||
sm.skewY , sm.scaleY, sm.transY,
|
||||
sm.pers0 , sm.pers1 , sm.pers2);
|
||||
}
|
||||
|
||||
SimpleMatrix toSimpleSkMatrix(const SkMatrix& sm) {
|
||||
SimpleMatrix m {sm[0], sm[1], sm[2],
|
||||
sm[3], sm[4], sm[5],
|
||||
sm[6], sm[7], sm[8]};
|
||||
return m;
|
||||
}
|
||||
|
||||
// Experimental 4x4 matrices, also represented in JS with arrays.
|
||||
struct SimpleM44 {
|
||||
SkScalar m0, m1, m2, m3;
|
||||
@ -803,29 +792,16 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
}), allow_raw_pointers());
|
||||
function("_MakeLinearGradientShader", optional_override([](SkPoint start, SkPoint end,
|
||||
uintptr_t /* SkColor4f* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
|
||||
int count, SkTileMode mode, uint32_t flags)->sk_sp<SkShader> {
|
||||
int count, SkTileMode mode, uint32_t flags,
|
||||
uintptr_t /* SkScalar* */ mPtr)->sk_sp<SkShader> {
|
||||
SkPoint points[] = { start, end };
|
||||
// See comment above for uintptr_t explanation
|
||||
const SkColor4f* colors = reinterpret_cast<const SkColor4f*>(cPtr);
|
||||
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
|
||||
|
||||
const SkColor4f* colors = reinterpret_cast<const SkColor4f*>(cPtr);
|
||||
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
|
||||
OptionalMatrix localMatrix(mPtr);
|
||||
// TODO(nifong): do not assume color space. Support and test wide gamut color gradients
|
||||
return SkGradientShader::MakeLinear(points, colors, SkColorSpace::MakeSRGB(), positions, count,
|
||||
mode, flags, nullptr);
|
||||
}), allow_raw_pointers());
|
||||
function("_MakeLinearGradientShader", optional_override([](SkPoint start, SkPoint end,
|
||||
uintptr_t /* SkColor4f* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
|
||||
int count, SkTileMode mode, uint32_t flags,
|
||||
const SimpleMatrix& lm)->sk_sp<SkShader> {
|
||||
SkPoint points[] = { start, end };
|
||||
// See comment above for uintptr_t explanation
|
||||
const SkColor4f* colors = reinterpret_cast<const SkColor4f*> (cPtr);
|
||||
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
|
||||
|
||||
SkMatrix localMatrix = toSkMatrix(lm);
|
||||
|
||||
return SkGradientShader::MakeLinear(points, colors, SkColorSpace::MakeSRGB(), positions, count,
|
||||
mode, flags, &localMatrix);
|
||||
mode, flags, &localMatrix);
|
||||
}), allow_raw_pointers());
|
||||
#ifdef SK_SERIALIZE_SKP
|
||||
function("_MakeSkPicture", optional_override([](uintptr_t /* unint8_t* */ dPtr,
|
||||
@ -837,25 +813,14 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
return SkPicture::MakeFromData(data.get(), nullptr);
|
||||
}), allow_raw_pointers());
|
||||
#endif
|
||||
function("_MakeRadialGradientShader", optional_override([](SkPoint center, SkScalar radius,
|
||||
uintptr_t /* SkColor4f* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
|
||||
int count, SkTileMode mode, uint32_t flags)->sk_sp<SkShader> {
|
||||
// See comment above for uintptr_t explanation
|
||||
const SkColor4f* colors = reinterpret_cast<const SkColor4f*> (cPtr);
|
||||
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
|
||||
|
||||
return SkGradientShader::MakeRadial(center, radius, colors, SkColorSpace::MakeSRGB(), positions, count,
|
||||
mode, flags, nullptr);
|
||||
}), allow_raw_pointers());
|
||||
function("_MakeRadialGradientShader", optional_override([](SkPoint center, SkScalar radius,
|
||||
uintptr_t /* SkColor4f* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
|
||||
int count, SkTileMode mode, uint32_t flags,
|
||||
const SimpleMatrix& lm)->sk_sp<SkShader> {
|
||||
uintptr_t /* SkScalar* */ mPtr)->sk_sp<SkShader> {
|
||||
// See comment above for uintptr_t explanation
|
||||
const SkColor4f* colors = reinterpret_cast<const SkColor4f*> (cPtr);
|
||||
const SkColor4f* colors = reinterpret_cast<const SkColor4f*>(cPtr);
|
||||
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
|
||||
|
||||
SkMatrix localMatrix = toSkMatrix(lm);
|
||||
OptionalMatrix localMatrix(mPtr);
|
||||
return SkGradientShader::MakeRadial(center, radius, colors, SkColorSpace::MakeSRGB(), positions, count,
|
||||
mode, flags, &localMatrix);
|
||||
}), allow_raw_pointers());
|
||||
@ -864,61 +829,25 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
int count, SkTileMode mode,
|
||||
SkScalar startAngle, SkScalar endAngle,
|
||||
uint32_t flags,
|
||||
const SimpleMatrix& lm)->sk_sp<SkShader> {
|
||||
uintptr_t /* SkScalar* */ mPtr)->sk_sp<SkShader> {
|
||||
// See comment above for uintptr_t explanation
|
||||
const SkColor4f* colors = reinterpret_cast<const SkColor4f*> (cPtr);
|
||||
const SkColor4f* colors = reinterpret_cast<const SkColor4f*>(cPtr);
|
||||
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
|
||||
|
||||
SkMatrix localMatrix = toSkMatrix(lm);
|
||||
OptionalMatrix localMatrix(mPtr);
|
||||
return SkGradientShader::MakeSweep(cx, cy, colors, SkColorSpace::MakeSRGB(), positions, count,
|
||||
mode, startAngle, endAngle, flags,
|
||||
&localMatrix);
|
||||
}), allow_raw_pointers());
|
||||
function("_MakeSweepGradientShader", optional_override([](SkScalar cx, SkScalar cy,
|
||||
uintptr_t /* SkColor4f* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
|
||||
int count, uint32_t flags,
|
||||
const SimpleMatrix& lm)->sk_sp<SkShader> {
|
||||
// See comment above for uintptr_t explanation
|
||||
const SkColor4f* colors = reinterpret_cast<const SkColor4f*> (cPtr);
|
||||
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
|
||||
|
||||
SkMatrix localMatrix = toSkMatrix(lm);
|
||||
return SkGradientShader::MakeSweep(cx, cy, colors, SkColorSpace::MakeSRGB(), positions, count,
|
||||
flags, &localMatrix);
|
||||
}), allow_raw_pointers());
|
||||
function("_MakeSweepGradientShader", optional_override([](SkScalar cx, SkScalar cy,
|
||||
uintptr_t /* SkColor4f* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
|
||||
int count)->sk_sp<SkShader> {
|
||||
// See comment above for uintptr_t explanation
|
||||
const SkColor4f* colors = reinterpret_cast<const SkColor4f*> (cPtr);
|
||||
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
|
||||
|
||||
return SkGradientShader::MakeSweep(cx, cy, colors, SkColorSpace::MakeSRGB(), positions, count);
|
||||
}), allow_raw_pointers());
|
||||
function("_MakeTwoPointConicalGradientShader", optional_override([](
|
||||
SkPoint start, SkScalar startRadius,
|
||||
SkPoint end, SkScalar endRadius,
|
||||
uintptr_t /* SkColor4f* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
|
||||
int count, SkTileMode mode, uint32_t flags)->sk_sp<SkShader> {
|
||||
SkPoint start, SkScalar startRadius,
|
||||
SkPoint end, SkScalar endRadius,
|
||||
uintptr_t /* SkColor4f* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
|
||||
int count, SkTileMode mode, uint32_t flags,
|
||||
uintptr_t /* SkScalar* */ mPtr)->sk_sp<SkShader> {
|
||||
// See comment above for uintptr_t explanation
|
||||
const SkColor4f* colors = reinterpret_cast<const SkColor4f*> (cPtr);
|
||||
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
|
||||
|
||||
return SkGradientShader::MakeTwoPointConical(start, startRadius, end, endRadius,
|
||||
colors, SkColorSpace::MakeSRGB(), positions, count, mode,
|
||||
flags, nullptr);
|
||||
}), allow_raw_pointers());
|
||||
function("_MakeTwoPointConicalGradientShader", optional_override([](
|
||||
SkPoint start, SkScalar startRadius,
|
||||
SkPoint end, SkScalar endRadius,
|
||||
uintptr_t /* SkColor4f* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
|
||||
int count, SkTileMode mode, uint32_t flags,
|
||||
const SimpleMatrix& lm)->sk_sp<SkShader> {
|
||||
// See comment above for uintptr_t explanation
|
||||
const SkColor4f* colors = reinterpret_cast<const SkColor4f*> (cPtr);
|
||||
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
|
||||
|
||||
SkMatrix localMatrix = toSkMatrix(lm);
|
||||
OptionalMatrix localMatrix(mPtr);
|
||||
return SkGradientShader::MakeTwoPointConical(start, startRadius, end, endRadius,
|
||||
colors, SkColorSpace::MakeSRGB(), positions, count, mode,
|
||||
flags, &localMatrix);
|
||||
@ -972,8 +901,10 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
self.clipRRect(toRRect(r), op, doAntiAlias);
|
||||
}))
|
||||
.function("clipRect", select_overload<void (const SkRect&, SkClipOp, bool)>(&SkCanvas::clipRect))
|
||||
.function("concat", optional_override([](SkCanvas& self, const SimpleMatrix& m) {
|
||||
self.concat(toSkMatrix(m));
|
||||
.function("_concat", optional_override([](SkCanvas& self, uintptr_t /* SkScalar* */ mPtr) {
|
||||
// See comment above for uintptr_t explanation
|
||||
OptionalMatrix localMatrix(mPtr);
|
||||
self.concat(localMatrix);
|
||||
}))
|
||||
.function("drawArc", &SkCanvas::drawArc)
|
||||
// _drawAtlas takes an SkColor, unlike most private functions handling color.
|
||||
@ -1067,9 +998,17 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
.function("drawVertices", select_overload<void (const sk_sp<SkVertices>&, SkBlendMode, const SkPaint&)>(&SkCanvas::drawVertices))
|
||||
.function("flush", &SkCanvas::flush)
|
||||
.function("getSaveCount", &SkCanvas::getSaveCount)
|
||||
.function("getTotalMatrix", optional_override([](const SkCanvas& self)->SimpleMatrix {
|
||||
// We allocate room for the matrix from the JS side and free it there so as to not have
|
||||
// an awkward moment where we malloc something here and "just know" to free it on the
|
||||
// JS side.
|
||||
.function("_getTotalMatrix", optional_override([](const SkCanvas& self, uintptr_t /* uint8_t* */ mPtr) {
|
||||
// See comment above for uintptr_t explanation
|
||||
SkScalar* nineMatrixValues = reinterpret_cast<SkScalar*>(mPtr);
|
||||
if (!nineMatrixValues) {
|
||||
return; // matrix cannot be null
|
||||
}
|
||||
SkMatrix m = self.getTotalMatrix();
|
||||
return toSimpleSkMatrix(m);
|
||||
m.get9(nineMatrixValues);
|
||||
}))
|
||||
.function("makeSurface", optional_override([](SkCanvas& self, SimpleImageInfo sii)->sk_sp<SkSurface> {
|
||||
return self.makeSurface(toSkImageInfo(sii), nullptr);
|
||||
@ -1274,16 +1213,10 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
.function("width", &SkImage::width)
|
||||
.function("_encodeToData", select_overload<sk_sp<SkData>()const>(&SkImage::encodeToData))
|
||||
.function("_encodeToDataWithFormat", select_overload<sk_sp<SkData>(SkEncodedImageFormat encodedImageFormat, int quality)const>(&SkImage::encodeToData))
|
||||
// Allow localMatrix to be optional, so we have 2 declarations of these shaders
|
||||
.function("_makeShader", optional_override([](sk_sp<SkImage> self,
|
||||
SkTileMode tx, SkTileMode ty)->sk_sp<SkShader> {
|
||||
return self->makeShader(tx, ty, nullptr);
|
||||
}), allow_raw_pointers())
|
||||
.function("_makeShader", optional_override([](sk_sp<SkImage> self,
|
||||
SkTileMode tx, SkTileMode ty,
|
||||
const SimpleMatrix& lm)->sk_sp<SkShader> {
|
||||
SkMatrix localMatrix = toSkMatrix(lm);
|
||||
|
||||
uintptr_t /* SkScalar* */ mPtr)->sk_sp<SkShader> {
|
||||
OptionalMatrix localMatrix(mPtr);
|
||||
return self->makeShader(tx, ty, &localMatrix);
|
||||
}), allow_raw_pointers())
|
||||
.function("_readPixels", optional_override([](sk_sp<SkImage> self,
|
||||
@ -1309,9 +1242,10 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
return SkImageFilters::ColorFilter(cf, input);
|
||||
}))
|
||||
.class_function("MakeCompose", &SkImageFilters::Compose)
|
||||
.class_function("MakeMatrixTransform", optional_override([](SimpleMatrix sm, SkFilterQuality fq,
|
||||
.class_function("_MakeMatrixTransform", optional_override([](uintptr_t /* SkScalar* */ mPtr, SkFilterQuality fq,
|
||||
sk_sp<SkImageFilter> input)->sk_sp<SkImageFilter> {
|
||||
return SkImageFilters::MatrixTransform(toSkMatrix(sm), fq, input);
|
||||
OptionalMatrix matr(mPtr);
|
||||
return SkImageFilters::MatrixTransform(matr, fq, input);
|
||||
}));
|
||||
|
||||
class_<SkMaskFilter>("SkMaskFilter")
|
||||
@ -1507,21 +1441,18 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
}
|
||||
return effect;
|
||||
}))
|
||||
.function("_makeShader", optional_override([](SkRuntimeEffect& self, uintptr_t fPtr, size_t fLen, bool isOpaque)->sk_sp<SkShader> {
|
||||
.function("_makeShader", optional_override([](SkRuntimeEffect& self, uintptr_t fPtr, size_t fLen, bool isOpaque,
|
||||
uintptr_t /* SkScalar* */ mPtr)->sk_sp<SkShader> {
|
||||
// See comment above for uintptr_t explanation
|
||||
void* inputData = reinterpret_cast<void*>(fPtr);
|
||||
sk_sp<SkData> inputs = SkData::MakeFromMalloc(inputData, fLen);
|
||||
return self.makeShader(inputs, nullptr, 0, nullptr, isOpaque);
|
||||
}))
|
||||
.function("_makeShader", optional_override([](SkRuntimeEffect& self, uintptr_t fPtr, size_t fLen, bool isOpaque, SimpleMatrix sm)->sk_sp<SkShader> {
|
||||
// See comment above for uintptr_t explanation
|
||||
void* inputData = reinterpret_cast<void*>(fPtr);
|
||||
sk_sp<SkData> inputs = SkData::MakeFromMalloc(inputData, fLen);
|
||||
auto m = toSkMatrix(sm);
|
||||
return self.makeShader(inputs, nullptr, 0, &m, isOpaque);
|
||||
|
||||
OptionalMatrix localMatrix(mPtr);
|
||||
return self.makeShader(inputs, nullptr, 0, &localMatrix, isOpaque);
|
||||
}))
|
||||
.function("_makeShaderWithChildren", optional_override([](SkRuntimeEffect& self, uintptr_t fPtr, size_t fLen, bool isOpaque,
|
||||
uintptr_t /** SkShader*[] */cPtrs, size_t cLen)->sk_sp<SkShader> {
|
||||
uintptr_t /** SkShader*[] */cPtrs, size_t cLen,
|
||||
uintptr_t /* SkScalar* */ mPtr)->sk_sp<SkShader> {
|
||||
// See comment above for uintptr_t explanation
|
||||
void* inputData = reinterpret_cast<void*>(fPtr);
|
||||
sk_sp<SkData> inputs = SkData::MakeFromMalloc(inputData, fLen);
|
||||
@ -1533,25 +1464,8 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
// so we want to ref the new sk_sp so makeShader doesn't clean it up.
|
||||
children[i] = sk_ref_sp<SkShader>(childrenPtrs[i]);
|
||||
}
|
||||
auto s = self.makeShader(inputs, children, cLen, nullptr, isOpaque);
|
||||
delete[] children;
|
||||
return s;
|
||||
}))
|
||||
.function("_makeShaderWithChildren", optional_override([](SkRuntimeEffect& self, uintptr_t fPtr, size_t fLen, bool isOpaque,
|
||||
uintptr_t /** SkShader*[] */cPtrs, size_t cLen, SimpleMatrix sm)->sk_sp<SkShader> {
|
||||
// See comment above for uintptr_t explanation
|
||||
void* inputData = reinterpret_cast<void*>(fPtr);
|
||||
sk_sp<SkData> inputs = SkData::MakeFromMalloc(inputData, fLen);
|
||||
|
||||
sk_sp<SkShader>* children = new sk_sp<SkShader>[cLen];
|
||||
SkShader** childrenPtrs = reinterpret_cast<SkShader**>(cPtrs);
|
||||
for (size_t i = 0; i < cLen; i++) {
|
||||
// This bare pointer was already part of an sk_sp (owned outside of here),
|
||||
// so we want to ref the new sk_sp so makeShader doesn't clean it up.
|
||||
children[i] = sk_ref_sp<SkShader>(childrenPtrs[i]);
|
||||
}
|
||||
auto m = toSkMatrix(sm);
|
||||
auto s = self.makeShader(inputs, children, cLen, &m, isOpaque);
|
||||
OptionalMatrix localMatrix(mPtr);
|
||||
auto s = self.makeShader(inputs, children, cLen, &localMatrix, isOpaque);
|
||||
delete[] children;
|
||||
return s;
|
||||
}));
|
||||
@ -1827,24 +1741,6 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
.field("cap", &StrokeOpts::cap)
|
||||
.field("precision", &StrokeOpts::precision);
|
||||
|
||||
// Allows clients to supply a 1D array of 9 elements and the bindings
|
||||
// will automatically turn it into a 3x3 2D matrix.
|
||||
// e.g. path.transform([0,1,2,3,4,5,6,7,8])
|
||||
// This is likely simpler for the client than exposing SkMatrix
|
||||
// directly and requiring them to do a lot of .delete().
|
||||
value_array<SimpleMatrix>("SkMatrix")
|
||||
.element(&SimpleMatrix::scaleX)
|
||||
.element(&SimpleMatrix::skewX)
|
||||
.element(&SimpleMatrix::transX)
|
||||
|
||||
.element(&SimpleMatrix::skewY)
|
||||
.element(&SimpleMatrix::scaleY)
|
||||
.element(&SimpleMatrix::transY)
|
||||
|
||||
.element(&SimpleMatrix::pers0)
|
||||
.element(&SimpleMatrix::pers1)
|
||||
.element(&SimpleMatrix::pers2);
|
||||
|
||||
value_array<SimpleM44>("SkM44")
|
||||
.element(&SimpleM44::m0).element(&SimpleM44::m1).element(&SimpleM44::m2).element(&SimpleM44::m3)
|
||||
.element(&SimpleM44::m4).element(&SimpleM44::m5).element(&SimpleM44::m6).element(&SimpleM44::m7)
|
||||
|
@ -158,7 +158,6 @@ var CanvasKit = {
|
||||
clipPath: function() {},
|
||||
clipRRect: function() {},
|
||||
clipRect: function() {},
|
||||
concat: function() {},
|
||||
drawAnimatedImage: function() {},
|
||||
drawArc: function() {},
|
||||
drawCircle: function() {},
|
||||
@ -182,7 +181,6 @@ var CanvasKit = {
|
||||
drawVertices: function() {},
|
||||
flush: function() {},
|
||||
getSaveCount: function() {},
|
||||
getTotalMatrix: function() {},
|
||||
makeSurface: function() {},
|
||||
restore: function() {},
|
||||
restoreToCount: function() {},
|
||||
@ -194,9 +192,11 @@ var CanvasKit = {
|
||||
translate: function() {},
|
||||
|
||||
// private API
|
||||
_concat: function() {},
|
||||
_drawAtlas: function() {},
|
||||
_drawPoints: function() {},
|
||||
_drawSimpleText: function() {},
|
||||
_getTotalMatrix: function() {},
|
||||
_readPixels: function() {},
|
||||
_writePixels: function() {},
|
||||
delete: function() {},
|
||||
@ -278,6 +278,9 @@ var CanvasKit = {
|
||||
MakeColorFilter: function() {},
|
||||
MakeCompose: function() {},
|
||||
MakeMatrixTransform: function() {},
|
||||
|
||||
// private API
|
||||
_MakeMatrixTransform: function() {},
|
||||
},
|
||||
|
||||
// These are defined in interface.js
|
||||
@ -834,9 +837,11 @@ CanvasKit.SkSurface.prototype.captureFrameAsSkPicture = function() {};
|
||||
CanvasKit.SkImage.prototype.encodeToData = function() {};
|
||||
CanvasKit.SkImage.prototype.makeShader = function() {};
|
||||
|
||||
CanvasKit.SkCanvas.prototype.concat = function() {};
|
||||
CanvasKit.SkCanvas.prototype.drawAtlas = function() {};
|
||||
CanvasKit.SkCanvas.prototype.drawPoints = function() {};
|
||||
CanvasKit.SkCanvas.prototype.drawText = function() {};
|
||||
CanvasKit.SkCanvas.prototype.getTotalMatrix = function() {};
|
||||
/** @return {Uint8Array} */
|
||||
CanvasKit.SkCanvas.prototype.readPixels = function() {};
|
||||
CanvasKit.SkCanvas.prototype.writePixels = function() {};
|
||||
|
@ -259,6 +259,43 @@ function copy3dArray(arr, dest, ptr) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
var defaultPerspective = Float32Array.of(0, 0, 1);
|
||||
|
||||
// Copies the given DOMMatrix/Array/TypedArray to the CanvasKit heap and
|
||||
// returns a pointer to the memory. This memory is a float* of length 9.
|
||||
// If the passed in matrix is null/undefined, we return 0 (nullptr). All calls
|
||||
// on the C++ side should check for nullptr where appropriate. It is generally
|
||||
// the responsibility of the JS side code to call CanvasKit._free on the
|
||||
// allocated memory before returning to the user code.
|
||||
function copy3x3MatrixToWasm(matr) {
|
||||
if (!matr) {
|
||||
return nullptr;
|
||||
}
|
||||
var mPtr = CanvasKit._malloc(9 * 4); // 9 matrix scalars, each at 4 bytes.
|
||||
if (matr.length) {
|
||||
// TODO(kjlubick): Downsample a 16 length (4x4 matrix)
|
||||
if (matr.length !== 6 && matr.length !== 9) {
|
||||
throw 'invalid matrix size';
|
||||
}
|
||||
// This should be an array or typed array.
|
||||
// have to divide the pointer by 4 to "cast" it from bytes to float.
|
||||
CanvasKit.HEAPF32.set(matr, mPtr / 4);
|
||||
if (matr.length === 6) {
|
||||
CanvasKit.HEAPF32.set(defaultPerspective, 6 + mPtr / 4);
|
||||
}
|
||||
} else {
|
||||
// Try as if it's a DOMMatrix. Reminder that DOMMatrix lists their
|
||||
// column first, then row.
|
||||
var floats = Float32Array.of(
|
||||
matr.m11, matr.m21, matr.m41,
|
||||
matr.m12, matr.m22, matr.m42,
|
||||
matr.m14, matr.m24, matr.m44);
|
||||
// have to divide the pointer by 4 to "cast" it from bytes to float.
|
||||
CanvasKit.HEAPF32.set(floats, mPtr / 4);
|
||||
}
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
// Caching the Float32Arrays can save having to reallocate them
|
||||
// over and over again.
|
||||
var Float32ArrayCache = {};
|
||||
|
@ -806,12 +806,10 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
}
|
||||
|
||||
CanvasKit.SkImage.prototype.makeShader = function(xTileMode, yTileMode, localMatrix) {
|
||||
if (localMatrix) {
|
||||
localMatrix = prepare3x3MatrixForGoingToWasm(localMatrix);
|
||||
return this._makeShader(xTileMode, yTileMode, localMatrix);
|
||||
} else {
|
||||
return this._makeShader(xTileMode, yTileMode);
|
||||
}
|
||||
var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
|
||||
var shader = this._makeShader(xTileMode, yTileMode, localMatrixPtr);
|
||||
localMatrixPtr && CanvasKit._free(localMatrixPtr);
|
||||
return shader;
|
||||
}
|
||||
|
||||
CanvasKit.SkImage.prototype.readPixels = function(imageInfo, srcX, srcY) {
|
||||
@ -852,13 +850,18 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
// Free the allocated pixels in the WASM memory
|
||||
CanvasKit._free(pPtr);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
CanvasKit.SkCanvas.prototype.concat = function(matr) {
|
||||
var matrPtr = copy3x3MatrixToWasm(matr);
|
||||
this._concat(matrPtr);
|
||||
matrPtr && CanvasKit._free(matrPtr);
|
||||
}
|
||||
|
||||
// atlas is an SkImage, e.g. from CanvasKit.MakeImageFromEncoded
|
||||
// srcRects and dstXforms should be CanvasKit.SkRectBuilder and CanvasKit.RSXFormBuilder
|
||||
// or just arrays of floats in groups of 4.
|
||||
// colors, if provided, should be a CanvasKit.SkColorBuilder or array of Canvaskit.SimpleColor4f
|
||||
// colors, if provided, should be a CanvasKit.SkColorBuilder or array of CanvasKit.SimpleColor4f
|
||||
CanvasKit.SkCanvas.prototype.drawAtlas = function(atlas, srcRects, dstXforms, paint,
|
||||
/*optional*/ blendMode, colors) {
|
||||
if (!atlas || !paint || !srcRects || !dstXforms) {
|
||||
@ -887,14 +890,14 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
dstXformPtr = copy1dArray(dstXforms, CanvasKit.HEAPF32);
|
||||
}
|
||||
|
||||
var colorPtr = 0; // enscriptem doesn't like undefined for nullptr
|
||||
var colorPtr = nullptr;
|
||||
if (colors) {
|
||||
if (colors.build) {
|
||||
colorPtr = colors.build();
|
||||
} else {
|
||||
if (!isCanvasKitColor(colors[0])) {
|
||||
SkDebug('DrawAtlas color argument expected to be CanvasKit.SkRectBuilder or array of ' +
|
||||
'Canvaskit.SimpleColor4f, but got '+colors);
|
||||
'CanvasKit.SimpleColor4f, but got '+colors);
|
||||
return;
|
||||
}
|
||||
// convert here
|
||||
@ -937,6 +940,20 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
CanvasKit._free(ptr);
|
||||
}
|
||||
|
||||
CanvasKit.SkCanvas.prototype.getTotalMatrix = function() {
|
||||
var matrPtr = CanvasKit._malloc(9 * 4); // allocate space for the matrix
|
||||
// _getTotalMatrix will copy the values into the pointer.
|
||||
this._getTotalMatrix(matrPtr);
|
||||
// read them out into an array. TODO(kjlubick): If we change SkMatrix to be
|
||||
// typedArrays, then we should return a typed array here too.
|
||||
var rv = new Array(9);
|
||||
for (var i = 0; i < 9; i++) {
|
||||
rv[i] = CanvasKit.HEAPF32[matrPtr/4 + i]; // divide by 4 to "cast" to float.
|
||||
}
|
||||
CanvasKit._free(matrPtr);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// returns Uint8Array
|
||||
CanvasKit.SkCanvas.prototype.readPixels = function(x, y, w, h, alphaType,
|
||||
colorType, dstRowBytes) {
|
||||
@ -995,8 +1012,7 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
// colorMatrix is an SkColorMatrix (e.g. Float32Array of length 20)
|
||||
CanvasKit.SkColorFilter.MakeMatrix = function(colorMatrix) {
|
||||
if (!colorMatrix || colorMatrix.length !== 20) {
|
||||
SkDebug('ignoring invalid color matrix');
|
||||
return;
|
||||
throw 'invalid color matrix';
|
||||
}
|
||||
var fptr = copy1dArray(colorMatrix, CanvasKit.HEAPF32);
|
||||
// We know skia memcopies the floats, so we can free our memory after the call returns.
|
||||
@ -1005,6 +1021,14 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
return m;
|
||||
}
|
||||
|
||||
CanvasKit.SkImageFilter.MakeMatrixTransform = function(matr, filterQuality, input) {
|
||||
var matrPtr = copy3x3MatrixToWasm(matr);
|
||||
var imgF = CanvasKit.SkImageFilter._MakeMatrixTransform(matrPtr, filterQuality, input);
|
||||
|
||||
matrPtr && CanvasKit._free(matrPtr);
|
||||
return imgF;
|
||||
}
|
||||
|
||||
CanvasKit.SkSurface.prototype.captureFrameAsSkPicture = function(drawFrame) {
|
||||
// Set up SkPictureRecorder
|
||||
var spr = new CanvasKit.SkPictureRecorder();
|
||||
@ -1066,43 +1090,16 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
return dpe;
|
||||
}
|
||||
|
||||
function prepare3x3MatrixForGoingToWasm(matr) {
|
||||
if (!matr) {
|
||||
return [
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1,
|
||||
];
|
||||
}
|
||||
if (Array.isArray(matr)) {
|
||||
// Add perspective args if not provided.
|
||||
if (matr.length === 6) {
|
||||
matr.push(0, 0, 1);
|
||||
}
|
||||
return matr;
|
||||
}
|
||||
// DOMMatrix, which has their values in column major order.
|
||||
return [
|
||||
matr.a, matr.c, matr.e,
|
||||
matr.b, matr.d, matr.f,
|
||||
0, 0, 1,
|
||||
];
|
||||
}
|
||||
|
||||
CanvasKit.SkShader.MakeLinearGradient = function(start, end, colors, pos, mode, localMatrix, flags) {
|
||||
var colorPtr = copy2dArray(colors, CanvasKit.HEAPF32);
|
||||
var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
|
||||
flags = flags || 0;
|
||||
var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
|
||||
|
||||
if (localMatrix) {
|
||||
localMatrix = prepare3x3MatrixForGoingToWasm(localMatrix);
|
||||
var lgs = CanvasKit._MakeLinearGradientShader(start, end, colorPtr, posPtr,
|
||||
colors.length, mode, flags, localMatrix);
|
||||
} else {
|
||||
var lgs = CanvasKit._MakeLinearGradientShader(start, end, colorPtr, posPtr,
|
||||
colors.length, mode, flags);
|
||||
}
|
||||
var lgs = CanvasKit._MakeLinearGradientShader(start, end, colorPtr, posPtr,
|
||||
colors.length, mode, flags, localMatrixPtr);
|
||||
|
||||
localMatrixPtr && CanvasKit._free(localMatrixPtr);
|
||||
CanvasKit._free(colorPtr);
|
||||
CanvasKit._free(posPtr);
|
||||
return lgs;
|
||||
@ -1112,16 +1109,12 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
var colorPtr = copy2dArray(colors, CanvasKit.HEAPF32);
|
||||
var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
|
||||
flags = flags || 0;
|
||||
var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
|
||||
|
||||
if (localMatrix) {
|
||||
localMatrix = prepare3x3MatrixForGoingToWasm(localMatrix);
|
||||
var rgs = CanvasKit._MakeRadialGradientShader(center, radius, colorPtr, posPtr,
|
||||
colors.length, mode, flags, localMatrix);
|
||||
} else {
|
||||
var rgs = CanvasKit._MakeRadialGradientShader(center, radius, colorPtr, posPtr,
|
||||
colors.length, mode, flags);
|
||||
}
|
||||
var rgs = CanvasKit._MakeRadialGradientShader(center, radius, colorPtr, posPtr,
|
||||
colors.length, mode, flags, localMatrixPtr);
|
||||
|
||||
localMatrixPtr && CanvasKit._free(localMatrixPtr);
|
||||
CanvasKit._free(colorPtr);
|
||||
CanvasKit._free(posPtr);
|
||||
return rgs;
|
||||
@ -1133,35 +1126,31 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
flags = flags || 0;
|
||||
startAngle = startAngle || 0;
|
||||
endAngle = endAngle || 360;
|
||||
localMatrix = prepare3x3MatrixForGoingToWasm(localMatrix);
|
||||
var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
|
||||
|
||||
var sgs = CanvasKit._MakeSweepGradientShader(cx, cy, colorPtr, posPtr,
|
||||
colors.length, mode,
|
||||
startAngle, endAngle, flags,
|
||||
localMatrix);
|
||||
colors.length, mode,
|
||||
startAngle, endAngle, flags,
|
||||
localMatrixPtr);
|
||||
|
||||
localMatrixPtr && CanvasKit._free(localMatrixPtr);
|
||||
CanvasKit._free(colorPtr);
|
||||
CanvasKit._free(posPtr);
|
||||
return sgs;
|
||||
}
|
||||
|
||||
CanvasKit.SkShader.MakeTwoPointConicalGradient = function(start, startRadius, end, endRadius,
|
||||
colors, pos, mode, localMatrix, flags) {
|
||||
colors, pos, mode, localMatrix, flags) {
|
||||
var colorPtr = copy2dArray(colors, CanvasKit.HEAPF32);
|
||||
var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
|
||||
flags = flags || 0;
|
||||
var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
|
||||
|
||||
if (localMatrix) {
|
||||
localMatrix = prepare3x3MatrixForGoingToWasm(localMatrix);
|
||||
var rgs = CanvasKit._MakeTwoPointConicalGradientShader(
|
||||
var rgs = CanvasKit._MakeTwoPointConicalGradientShader(
|
||||
start, startRadius, end, endRadius,
|
||||
colorPtr, posPtr, colors.length, mode, flags, localMatrix);
|
||||
} else {
|
||||
var rgs = CanvasKit._MakeTwoPointConicalGradientShader(
|
||||
start, startRadius, end, endRadius,
|
||||
colorPtr, posPtr, colors.length, mode, flags);
|
||||
}
|
||||
colorPtr, posPtr, colors.length, mode, flags, localMatrixPtr);
|
||||
|
||||
localMatrixPtr && CanvasKit._free(localMatrixPtr);
|
||||
CanvasKit._free(colorPtr);
|
||||
CanvasKit._free(posPtr);
|
||||
return rgs;
|
||||
|
@ -128,4 +128,4 @@ describe('DOMMatrix', () => {
|
||||
|
||||
benchmarkAndReport('dommatrix_makeShader', setup, test, teardown);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,20 +1,23 @@
|
||||
CanvasKit._extraInitializations = CanvasKit._extraInitializations || [];
|
||||
CanvasKit._extraInitializations.push(function() {
|
||||
CanvasKit.SkRuntimeEffect.prototype.makeShader = function(floats, isOpaque, matrix) {
|
||||
CanvasKit.SkRuntimeEffect.prototype.makeShader = function(floats, isOpaque, localMatrix) {
|
||||
// We don't need to free these floats because they will become owned by the shader.
|
||||
var fptr = copy1dArray(floats, CanvasKit.HEAPF32);
|
||||
var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
|
||||
// Our array has 4 bytes per float, so be sure to account for that before
|
||||
// sending it over the wire.
|
||||
if (!matrix) {
|
||||
return this._makeShader(fptr, floats.length * 4, !!isOpaque);
|
||||
}
|
||||
return this._makeShader(fptr, floats.length * 4, !!isOpaque, matrix);
|
||||
var rts = this._makeShader(fptr, floats.length * 4, !!isOpaque, localMatrixPtr);
|
||||
localMatrixPtr && CanvasKit._free(localMatrixPtr);
|
||||
return rts;
|
||||
}
|
||||
|
||||
// childrenWithShaders is an array of other shaders (e.g. SkImage.makeShader())
|
||||
CanvasKit.SkRuntimeEffect.prototype.makeShaderWithChildren = function(floats, isOpaque, childrenShaders, matrix) {
|
||||
CanvasKit.SkRuntimeEffect.prototype.makeShaderWithChildren = function(floats, isOpaque, childrenShaders, localMatrix) {
|
||||
// We don't need to free these floats because they will become owned by the shader.
|
||||
var fptr = copy1dArray(floats, CanvasKit.HEAPF32);
|
||||
var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
|
||||
var barePointers = [];
|
||||
for (var i = 0; i<childrenShaders.length;i++) {
|
||||
for (var i = 0; i < childrenShaders.length; i++) {
|
||||
// childrenShaders are emscriptens smart pointer type. We want to get the bare pointer
|
||||
// and send that over the wire, so it can be re-wrapped as an sk_sp.
|
||||
barePointers.push(childrenShaders[i].$$.ptr);
|
||||
@ -22,9 +25,9 @@ CanvasKit._extraInitializations.push(function() {
|
||||
var childrenPointers = copy1dArray(barePointers, CanvasKit.HEAPU32);
|
||||
// Our array has 4 bytes per float, so be sure to account for that before
|
||||
// sending it over the wire.
|
||||
if (!matrix) {
|
||||
return this._makeShaderWithChildren(fptr, floats.length * 4, !!isOpaque, childrenPointers, barePointers.length);
|
||||
}
|
||||
return this._makeShaderWithChildren(fptr, floats.length * 4, !!isOpaque, childrenPointers, barePointers.length, matrix);
|
||||
var rts = this._makeShaderWithChildren(fptr, floats.length * 4, !!isOpaque, childrenPointers,
|
||||
barePointers.length, localMatrixPtr);
|
||||
localMatrixPtr && CanvasKit._free(localMatrixPtr);
|
||||
return rts;
|
||||
}
|
||||
});
|
@ -761,4 +761,28 @@ describe('CanvasKit\'s Canvas Behavior', function() {
|
||||
reportSurface(surface, 'drawvertices_texture_canvas', done);
|
||||
});
|
||||
});
|
||||
|
||||
it('can change the matrix on the canvas and read it back', function(done) {
|
||||
LoadCanvasKit.then(catchException(done, () => {
|
||||
const canvas = new CanvasKit.SkCanvas();
|
||||
|
||||
let matr = canvas.getTotalMatrix();
|
||||
expect(matr).toEqual(CanvasKit.SkMatrix.identity());
|
||||
|
||||
canvas.concat(CanvasKit.SkMatrix.rotated(Math.PI/4));
|
||||
const d = new DOMMatrix().translate(20, 10);
|
||||
canvas.concat(d);
|
||||
|
||||
matr = canvas.getTotalMatrix();
|
||||
const expected = CanvasKit.SkMatrix.multiply(
|
||||
CanvasKit.SkMatrix.rotated(Math.PI/4),
|
||||
CanvasKit.SkMatrix.translated(20, 10)
|
||||
);
|
||||
expect(matr.length).toEqual(expected.length);
|
||||
for (let i = 0; i < matr.length; i++) {
|
||||
expect(matr[i]).toBeCloseTo(expected[i], 5);
|
||||
}
|
||||
done();
|
||||
}));
|
||||
})
|
||||
});
|
||||
|
@ -161,4 +161,4 @@ void main(float2 xy, inout half4 color) {
|
||||
it('apply a local matrix to the children-based shader', (done) => {
|
||||
testChildrenShader('rtshader_children_rotated', done, CanvasKit.SkMatrix.rotated(Math.PI/12));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user