Reland "Switch to using a Float32Array (bound as value array) for color."
This is a reland of 4e79b6730dfce84f2d115ad3babf7b848d44a2b5
Original change's description:
> Switch to using a Float32Array (bound as value array) for color.
>
> Change-Id: I1bcca931954b1399c79f4074a3d57a68847ac785
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/276757
> Commit-Queue: Nathaniel Nifong <nifong@google.com>
> Reviewed-by: Kevin Lubick <kjlubick@google.com>
Change-Id: If6b9097b2fcd6b9dbf75c6dd22138e0b2531e70d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/278780
Commit-Queue: Nathaniel Nifong <nifong@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
diff --git a/modules/canvaskit/CHANGELOG.md b/modules/canvaskit/CHANGELOG.md
index bfce278..584c72c 100644
--- a/modules/canvaskit/CHANGELOG.md
+++ b/modules/canvaskit/CHANGELOG.md
@@ -6,9 +6,15 @@
## [Unreleased]
+### Changed
+ - CanvasKit colors are now represented with a TypedArray of four floats.
+
### Removed
+ - SkPaint.setColorf is obsolete and removed. setColor accepts a CanvasKit color which is
+ always composed of floats.
- localmatrix option for `SkShader.Lerp` and `SkShader.Blend`.
+
## [0.14.0] - 2020-03-18
### Added
diff --git a/modules/canvaskit/WasmAliases.h b/modules/canvaskit/WasmAliases.h
deleted file mode 100644
index ca017e1..0000000
--- a/modules/canvaskit/WasmAliases.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2019 Google LLC
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef WasmAliases_DEFINED
-#define WasmAliases_DEFINED
-
-#include <emscripten.h>
-#include <emscripten/bind.h>
-
-using namespace emscripten;
-
-// Self-documenting types
-using JSArray = emscripten::val;
-using JSObject = emscripten::val;
-using JSString = emscripten::val;
-using SkPathOrNull = emscripten::val;
-using Uint8Array = emscripten::val;
-using Float32Array = emscripten::val;
-
-#endif
diff --git a/modules/canvaskit/WasmCommon.h b/modules/canvaskit/WasmCommon.h
new file mode 100644
index 0000000..892ecc0
--- /dev/null
+++ b/modules/canvaskit/WasmCommon.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef WasmCommon_DEFINED
+#define WasmCommon_DEFINED
+
+#include <emscripten.h>
+#include <emscripten/bind.h>
+#include "include/core/SkColor.h"
+
+using namespace emscripten;
+
+// Self-documenting types
+using JSArray = emscripten::val;
+using JSObject = emscripten::val;
+using JSString = emscripten::val;
+using SkPathOrNull = emscripten::val;
+using Uint8Array = emscripten::val;
+using Float32Array = emscripten::val;
+
+// A struct used for binding the TypedArray colors passed to to canvaskit functions.
+// Canvaskit functions returning colors return a Float32Array, which looks the same
+// on the javascript side.
+struct SimpleColor4f {
+ // A sensible but noticeable default value to let you know you've called the
+ // default constructor.
+ float r = 1.0;
+ float g = 0.0;
+ float b = 1.0;
+ float a = 1.0;
+
+ SkColor4f toSkColor4f() const {
+ return SkColor4f({r, g, b, a});
+ };
+ SkColor toSkColor() const {
+ return toSkColor4f().toSkColor();
+ };
+};
+
+#endif
diff --git a/modules/canvaskit/canvaskit_bindings.cpp b/modules/canvaskit/canvaskit_bindings.cpp
index 1831f7d..b0f24e0 100644
--- a/modules/canvaskit/canvaskit_bindings.cpp
+++ b/modules/canvaskit/canvaskit_bindings.cpp
@@ -55,7 +55,7 @@
#include <iostream>
#include <string>
-#include "modules/canvaskit/WasmAliases.h"
+#include "modules/canvaskit/WasmCommon.h"
#include <emscripten.h>
#include <emscripten/bind.h>
@@ -134,6 +134,13 @@
return m;
}
+SimpleColor4f toSimpleColor4f(const SkColor4f c) {
+ SimpleColor4f color {
+ c.fR, c.fG, c.fB, c.fA,
+ };
+ return color;
+}
+
// Surface creation structs and helpers
struct SimpleImageInfo {
int width;
@@ -668,14 +675,17 @@
}
struct TonalColors {
- SkColor ambientColor;
- SkColor spotColor;
+ SimpleColor4f ambientColor;
+ SimpleColor4f spotColor;
};
-TonalColors computeTonalColors(const TonalColors& in) {
+TonalColors computeTonalColors(const TonalColors& in) {SkColor resultAmbient, resultSpot;
+ SkShadowUtils::ComputeTonalColors(
+ in.ambientColor.toSkColor(), in.spotColor.toSkColor(),
+ &resultAmbient, &resultSpot);
TonalColors out;
- SkShadowUtils::ComputeTonalColors(in.ambientColor, in.spotColor,
- &out.ambientColor, &out.spotColor);
+ out.ambientColor = toSimpleColor4f(SkColor4f::FromColor(resultAmbient));
+ out.spotColor = toSimpleColor4f(SkColor4f::FromColor(resultSpot));
return out;
}
@@ -792,28 +802,29 @@
return SkImage::MakeRasterData(info, pixelData, rowBytes);
}), allow_raw_pointers());
function("_MakeLinearGradientShader", optional_override([](SkPoint start, SkPoint end,
- uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
+ uintptr_t /* SkColor4f* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
int count, SkTileMode mode, uint32_t flags)->sk_sp<SkShader> {
SkPoint points[] = { start, end };
// See comment above for uintptr_t explanation
- const SkColor* colors = reinterpret_cast<const SkColor*> (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);
- return SkGradientShader::MakeLinear(points, colors, positions, count,
+ // 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 /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
+ 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 SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
+ 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, positions, count,
+ return SkGradientShader::MakeLinear(points, colors, SkColorSpace::MakeSRGB(), positions, count,
mode, flags, &localMatrix);
}), allow_raw_pointers());
#ifdef SK_SERIALIZE_SKP
@@ -827,89 +838,89 @@
}), allow_raw_pointers());
#endif
function("_MakeRadialGradientShader", optional_override([](SkPoint center, SkScalar radius,
- uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
+ 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 SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
+ const SkColor4f* colors = reinterpret_cast<const SkColor4f*> (cPtr);
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
- return SkGradientShader::MakeRadial(center, radius, colors, positions, count,
+ 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 /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
+ 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 SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
+ const SkColor4f* colors = reinterpret_cast<const SkColor4f*> (cPtr);
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
SkMatrix localMatrix = toSkMatrix(lm);
- return SkGradientShader::MakeRadial(center, radius, colors, positions, count,
+ return SkGradientShader::MakeRadial(center, radius, colors, SkColorSpace::MakeSRGB(), positions, count,
mode, flags, &localMatrix);
}), allow_raw_pointers());
function("_MakeSweepGradientShader", optional_override([](SkScalar cx, SkScalar cy,
- uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
+ uintptr_t /* SkColor4f* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
int count, SkTileMode mode,
SkScalar startAngle, SkScalar endAngle,
uint32_t flags,
const SimpleMatrix& lm)->sk_sp<SkShader> {
// See comment above for uintptr_t explanation
- const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
+ 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, positions, count,
+ 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 /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
+ 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 SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
+ 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, positions, count,
+ 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 /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
+ uintptr_t /* SkColor4f* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
int count)->sk_sp<SkShader> {
// See comment above for uintptr_t explanation
- const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
+ const SkColor4f* colors = reinterpret_cast<const SkColor4f*> (cPtr);
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
- return SkGradientShader::MakeSweep(cx, cy, colors, positions, count);
+ 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 /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
+ 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 SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
+ const SkColor4f* colors = reinterpret_cast<const SkColor4f*> (cPtr);
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
return SkGradientShader::MakeTwoPointConical(start, startRadius, end, endRadius,
- colors, positions, count, mode,
+ 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 /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
+ 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 SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
+ const SkColor4f* colors = reinterpret_cast<const SkColor4f*> (cPtr);
const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
SkMatrix localMatrix = toSkMatrix(lm);
return SkGradientShader::MakeTwoPointConical(start, startRadius, end, endRadius,
- colors, positions, count, mode,
+ colors, SkColorSpace::MakeSRGB(), positions, count, mode,
flags, &localMatrix);
}), allow_raw_pointers());
@@ -953,7 +964,9 @@
class_<SkCanvas>("SkCanvas")
.constructor<>()
- .function("clear", &SkCanvas::clear)
+ .function("clear", optional_override([](SkCanvas& self, SimpleColor4f c) {
+ self.clear(c.toSkColor());
+ }))
.function("clipPath", select_overload<void (const SkPath&, SkClipOp, bool)>(&SkCanvas::clipPath))
.function("clipRRect", optional_override([](SkCanvas& self, const SimpleRRect& r, SkClipOp op, bool doAntiAlias) {
self.clipRRect(toRRect(r), op, doAntiAlias);
@@ -963,6 +976,9 @@
self.concat(toSkMatrix(m));
}))
.function("drawArc", &SkCanvas::drawArc)
+ // _drawAtlas takes an SkColor, unlike most private functions handling color.
+ // This is because it takes an array of colors. Converting it on the Javascript side allows
+ // an allocation to be avoided here.
.function("_drawAtlas", optional_override([](SkCanvas& self,
const sk_sp<SkImage>& atlas, uintptr_t /* SkRSXform* */ xptr,
uintptr_t /* SkRect* */ rptr, uintptr_t /* SkColor* */ cptr, int count,
@@ -977,7 +993,12 @@
self.drawAtlas(atlas, dstXforms, srcRects, colors, count, mode, nullptr, paint);
}), allow_raw_pointers())
.function("drawCircle", select_overload<void (SkScalar, SkScalar, SkScalar, const SkPaint& paint)>(&SkCanvas::drawCircle))
- .function("drawColor", &SkCanvas::drawColor)
+ .function("drawColor", optional_override([](SkCanvas& self, SimpleColor4f c) {
+ self.drawColor(c.toSkColor());
+ }))
+ .function("drawColor", optional_override([](SkCanvas& self, SimpleColor4f c, SkBlendMode mode) {
+ self.drawColor(c.toSkColor(), mode);
+ }))
.function("drawDRRect",optional_override([](SkCanvas& self, const SimpleRRect& o, const SimpleRRect& i, const SkPaint& paint) {
self.drawDRRect(toRRect(o), toRRect(i), paint);
}))
@@ -1026,10 +1047,10 @@
.function("drawShadow", optional_override([](SkCanvas& self, const SkPath& path,
const SkPoint3& zPlaneParams,
const SkPoint3& lightPos, SkScalar lightRadius,
- SkColor ambientColor, SkColor spotColor,
+ SimpleColor4f ambientColor, SimpleColor4f spotColor,
uint32_t flags) {
SkShadowUtils::DrawShadow(&self, path, zPlaneParams, lightPos, lightRadius,
- ambientColor, spotColor, flags);
+ ambientColor.toSkColor(), spotColor.toSkColor(), flags);
}))
#ifndef SK_NO_FONTS
.function("_drawShapedText", &drawShapedText)
@@ -1111,7 +1132,9 @@
class_<SkColorFilter>("SkColorFilter")
.smart_ptr<sk_sp<SkColorFilter>>("sk_sp<SkColorFilter>>")
- .class_function("MakeBlend", &SkColorFilters::Blend)
+ .class_function("MakeBlend", optional_override([](SimpleColor4f c, SkBlendMode mode)->sk_sp<SkColorFilter> {
+ return SkColorFilters::Blend(c.toSkColor(), mode);
+ }))
.class_function("MakeCompose", &SkColorFilters::Compose)
.class_function("MakeLerp", &SkColorFilters::Lerp)
.class_function("MakeLinearToSRGBGamma", &SkColorFilters::LinearToSRGBGamma)
@@ -1305,7 +1328,11 @@
return p;
}))
.function("getBlendMode", &SkPaint::getBlendMode)
- .function("getColor", &SkPaint::getColor)
+ .function("getColor", optional_override([](SkPaint& self)->Float32Array {
+ const SimpleColor4f& c = toSimpleColor4f(self.getColor4f());
+ const float array[4] = {c.r, c.g, c.b, c.a};
+ return Float32Array(typed_memory_view(4, array));
+ }))
.function("getFilterQuality", &SkPaint::getFilterQuality)
.function("getStrokeCap", &SkPaint::getStrokeCap)
.function("getStrokeJoin", &SkPaint::getStrokeJoin)
@@ -1314,12 +1341,8 @@
.function("setAntiAlias", &SkPaint::setAntiAlias)
.function("setAlphaf", &SkPaint::setAlphaf)
.function("setBlendMode", &SkPaint::setBlendMode)
- .function("setColor", optional_override([](SkPaint& self, SkColor c) {
- self.setColor(c);
- }))
- .function("setColorf", optional_override([](SkPaint& self,
- float r, float g, float b, float a) {
- self.setColor({r, g, b, a});
+ .function("setColor", optional_override([](SkPaint& self, SimpleColor4f c) {
+ self.setColor({c.r, c.g, c.b, c.a});
}))
.function("setColorFilter", &SkPaint::setColorFilter)
.function("setFilterQuality", &SkPaint::setFilterQuality)
@@ -1465,7 +1488,11 @@
class_<SkShader>("SkShader")
.smart_ptr<sk_sp<SkShader>>("sk_sp<SkShader>")
.class_function("Blend", select_overload<sk_sp<SkShader>(SkBlendMode, sk_sp<SkShader>, sk_sp<SkShader>)>(&SkShaders::Blend))
- .class_function("Color", select_overload<sk_sp<SkShader>(SkColor)>(&SkShaders::Color))
+ .class_function("Color",
+ optional_override([](SimpleColor4f c)->sk_sp<SkShader> {
+ return SkShaders::Color(c.toSkColor4f(), SkColorSpace::MakeSRGB());
+ })
+ )
.class_function("Lerp", select_overload<sk_sp<SkShader>(float, sk_sp<SkShader>, sk_sp<SkShader>)>(&SkShaders::Lerp));
#ifdef SK_INCLUDE_RUNTIME_EFFECT
@@ -1824,16 +1851,12 @@
.element(&SimpleM44::m8).element(&SimpleM44::m9).element(&SimpleM44::m10).element(&SimpleM44::m11)
.element(&SimpleM44::m12).element(&SimpleM44::m13).element(&SimpleM44::m14).element(&SimpleM44::m15);
- constant("TRANSPARENT", SK_ColorTRANSPARENT);
- constant("RED", SK_ColorRED);
- constant("GREEN", SK_ColorGREEN);
- constant("BLUE", SK_ColorBLUE);
- constant("MAGENTA", SK_ColorMAGENTA);
- constant("YELLOW", SK_ColorYELLOW);
- constant("CYAN", SK_ColorCYAN);
- constant("BLACK", SK_ColorBLACK);
- constant("WHITE", SK_ColorWHITE);
- // TODO(?)
+ value_array<SimpleColor4f>("SkColor4f")
+ .element(&SimpleColor4f::r)
+ .element(&SimpleColor4f::g)
+ .element(&SimpleColor4f::b)
+ .element(&SimpleColor4f::a);
+
constant("MOVE_VERB", MOVE);
constant("LINE_VERB", LINE);
diff --git a/modules/canvaskit/externs.js b/modules/canvaskit/externs.js
index ddc2b3c..480fab3 100644
--- a/modules/canvaskit/externs.js
+++ b/modules/canvaskit/externs.js
@@ -25,6 +25,7 @@
var CanvasKit = {
// public API (i.e. things we declare in the pre-js file or in the cpp bindings)
Color: function() {},
+ Color4f: function() {},
/** @return {CanvasKit.SkRect} */
LTRBRect: function() {},
/** @return {CanvasKit.SkRect} */
@@ -534,12 +535,14 @@
skottie: {},
TRANSPARENT: {},
+ BLACK: {},
+ WHITE: {},
RED: {},
+ GREEN: {},
BLUE: {},
YELLOW: {},
CYAN: {},
- BLACK: {},
- WHITE: {},
+ MAGENTA: {},
MOVE_VERB: {},
LINE_VERB: {},
diff --git a/modules/canvaskit/helper.js b/modules/canvaskit/helper.js
index 2875261..485448c 100644
--- a/modules/canvaskit/helper.js
+++ b/modules/canvaskit/helper.js
@@ -4,34 +4,73 @@
return Math.round(Math.max(0, Math.min(c || 0, 255)));
}
-// Colors are just a 32 bit number with 8 bits each of a, r, g, b
-// The API is the same as CSS's representation of color rgba(), that is
+// Constructs a Color with the same API as CSS's rgba(), that is
// r,g,b are 0-255, and a is 0.0 to 1.0.
// if a is omitted, it will be assumed to be 1.0
+// Internally, Colors are a TypedArray of four unpremultiplied 32-bit floats: a, r, g, b
+// In order to construct one with more precision or in a wider gamut, use
+// CanvasKit.Color4f
CanvasKit.Color = function(r, g, b, a) {
if (a === undefined) {
a = 1;
}
- // The >>> 0 converts the signed int to an unsigned int. Skia's
- // SkColor object is an unsigned int.
- // https://stackoverflow.com/a/14891172
- return ((clamp(a*255) << 24) | (clamp(r) << 16) | (clamp(g) << 8) | (clamp(b) << 0)) >>> 0;
+ return CanvasKit.Color4f(clamp(r)/255, clamp(g)/255, clamp(b)/255, a);
}
-// returns [r, g, b, a] from a color
+// Construct a 4-float color.
+// Opaque if opacity is omitted.
+CanvasKit.Color4f = function(r, g, b, a) {
+ if (a === undefined) {
+ a = 1;
+ }
+ return Float32Array.of(r, g, b, a);
+}
+
+// Color constants use property getters to prevent other code from accidentally
+// changing them.
+Object.defineProperty(CanvasKit, "TRANSPARENT", {
+ get: function() { return CanvasKit.Color4f(0, 0, 0, 0); }
+});
+Object.defineProperty(CanvasKit, "BLACK", {
+ get: function() { return CanvasKit.Color4f(0, 0, 0, 1); }
+});
+Object.defineProperty(CanvasKit, "WHITE", {
+ get: function() { return CanvasKit.Color4f(1, 1, 1, 1); }
+});
+Object.defineProperty(CanvasKit, "RED", {
+ get: function() { return CanvasKit.Color4f(1, 0, 0, 1); }
+});
+Object.defineProperty(CanvasKit, "GREEN", {
+ get: function() { return CanvasKit.Color4f(0, 1, 0, 1); }
+});
+Object.defineProperty(CanvasKit, "BLUE", {
+ get: function() { return CanvasKit.Color4f(0, 0, 1, 1); }
+});
+Object.defineProperty(CanvasKit, "YELLOW", {
+ get: function() { return CanvasKit.Color4f(1, 1, 0, 1); }
+});
+Object.defineProperty(CanvasKit, "CYAN", {
+ get: function() { return CanvasKit.Color4f(0, 1, 1, 1); }
+});
+Object.defineProperty(CanvasKit, "MAGENTA", {
+ get: function() { return CanvasKit.Color4f(1, 0, 1, 1); }
+});
+
+// returns a css style [r, g, b, a] from a CanvasKit.Color
+// where r, g, b are returned as ints in the range [0, 255]
// where a is scaled between 0 and 1.0
CanvasKit.getColorComponents = function(color) {
return [
- (color >> 16) & 0xFF,
- (color >> 8) & 0xFF,
- (color >> 0) & 0xFF,
- ((color >> 24) & 0xFF) / 255,
- ]
+ Math.floor(color[0]*255),
+ Math.floor(color[1]*255),
+ Math.floor(color[2]*255),
+ color[3]
+ ];
}
// parseColorString takes in a CSS color value and returns a CanvasKit.Color
-// (which is just a 32 bit integer, 8 bits per channel). An optional colorMap
-// may be provided which maps custom strings to values (e.g. {'springgreen':4278255487}).
+// (which is an array of 4 floats in RGBA order). An optional colorMap
+// may be provided which maps custom strings to values.
// In the CanvasKit canvas2d shim layer, we provide this map for processing
// canvas2d calls, but not here for code size reasons.
CanvasKit.parseColorString = function(colorStr, colorMap) {
@@ -88,6 +127,26 @@
return CanvasKit.BLACK;
}
+function isCanvasKitColor(ob) {
+ if (!ob) {
+ return false;
+ }
+ return (ob.constructor === Float32Array && ob.length === 4);
+}
+
+// Warning information is lost by this conversion
+function toUint32Color(c) {
+ return ((clamp(c[3]*255) << 24) | (clamp(c[0]*255) << 16) | (clamp(c[1]*255) << 8) | (clamp(c[2]*255) << 0)) >>> 0;
+}
+function uIntColorToCanvasKitColor(c) {
+ return CanvasKit.Color(
+ (c >> 16) & 0xFF,
+ (c >> 8) & 0xFF,
+ (c >> 0) & 0xFF,
+ ((c >> 24) & 0xFF) / 255
+ );
+}
+
function valueOrPercent(aStr) {
if (aStr === undefined) {
return 1; // default to opaque.
@@ -100,16 +159,10 @@
}
CanvasKit.multiplyByAlpha = function(color, alpha) {
- if (alpha === 1) {
- return color;
- }
- // extract as int from 0 to 255
- var a = (color >> 24) & 0xFF;
- a *= alpha;
- // mask off the old alpha
- color &= 0xFFFFFF;
- // back to unsigned int to match SkColor.
- return (clamp(a) << 24 | color) >>> 0;
+ // make a copy of the color so the function remains pure.
+ var result = color.slice();
+ result[3] = Math.max(0, Math.min(result[3] * alpha, 1));
+ return result;
}
function radiansToDegrees(rad) {
diff --git a/modules/canvaskit/htmlcanvas/canvas2dcontext.js b/modules/canvaskit/htmlcanvas/canvas2dcontext.js
index 16f2a8e..f4fc8dd 100644
--- a/modules/canvaskit/htmlcanvas/canvas2dcontext.js
+++ b/modules/canvaskit/htmlcanvas/canvas2dcontext.js
@@ -79,7 +79,7 @@
Object.defineProperty(this, 'fillStyle', {
enumerable: true,
get: function() {
- if (Number.isInteger(this._fillStyle)) {
+ if (isCanvasKitColor(this._fillStyle)) {
return colorToString(this._fillStyle);
}
return this._fillStyle;
@@ -632,7 +632,7 @@
this._fillPaint = function() {
var paint = this._paint.copy();
paint.setStyle(CanvasKit.PaintStyle.Fill);
- if (Number.isInteger(this._fillStyle)) {
+ if (isCanvasKitColor(this._fillStyle)) {
var alphaColor = CanvasKit.multiplyByAlpha(this._fillStyle, this._globalAlpha);
paint.setColor(alphaColor);
} else {
@@ -1047,7 +1047,7 @@
this._strokePaint = function() {
var paint = this._paint.copy();
paint.setStyle(CanvasKit.PaintStyle.Stroke);
- if (Number.isInteger(this._strokeStyle)) {
+ if (isCanvasKitColor(this._strokeStyle)) {
var alphaColor = CanvasKit.multiplyByAlpha(this._strokeStyle, this._globalAlpha);
paint.setColor(alphaColor);
} else {
diff --git a/modules/canvaskit/htmlcanvas/color.js b/modules/canvaskit/htmlcanvas/color.js
index 606d92e..3b21b31 100644
--- a/modules/canvaskit/htmlcanvas/color.js
+++ b/modules/canvaskit/htmlcanvas/color.js
@@ -7,7 +7,158 @@
// the map, which saves (a tiny amount of) startup time
// and (a small amount of) code size.
/* @dict */
-var colorMap = {'aliceblue':4293982463,'antiquewhite':4294634455,'aqua':4278255615,'aquamarine':4286578644,'azure':4293984255,'beige':4294309340,'bisque':4294960324,'black':4278190080,'blanchedalmond':4294962125,'blue':4278190335,'blueviolet':4287245282,'brown':4289014314,'burlywood':4292786311,'cadetblue':4284456608,'chartreuse':4286578432,'chocolate':4291979550,'coral':4294934352,'cornflowerblue':4284782061,'cornsilk':4294965468,'crimson':4292613180,'cyan':4278255615,'darkblue':4278190219,'darkcyan':4278225803,'darkgoldenrod':4290283019,'darkgray':4289309097,'darkgreen':4278215680,'darkgrey':4289309097,'darkkhaki':4290623339,'darkmagenta':4287299723,'darkolivegreen':4283788079,'darkorange':4294937600,'darkorchid':4288230092,'darkred':4287299584,'darksalmon':4293498490,'darkseagreen':4287609999,'darkslateblue':4282924427,'darkslategray':4281290575,'darkslategrey':4281290575,'darkturquoise':4278243025,'darkviolet':4287889619,'deeppink':4294907027,'deepskyblue':4278239231,'dimgray':4285098345,'dimgrey':4285098345,'dodgerblue':4280193279,'firebrick':4289864226,'floralwhite':4294966000,'forestgreen':4280453922,'fuchsia':4294902015,'gainsboro':4292664540,'ghostwhite':4294506751,'gold':4294956800,'goldenrod':4292519200,'gray':4286611584,'green':4278222848,'greenyellow':4289593135,'grey':4286611584,'honeydew':4293984240,'hotpink':4294928820,'indianred':4291648604,'indigo':4283105410,'ivory':4294967280,'khaki':4293977740,'lavender':4293322490,'lavenderblush':4294963445,'lawngreen':4286381056,'lemonchiffon':4294965965,'lightblue':4289583334,'lightcoral':4293951616,'lightcyan':4292935679,'lightgoldenrodyellow':4294638290,'lightgray':4292072403,'lightgreen':4287688336,'lightgrey':4292072403,'lightpink':4294948545,'lightsalmon':4294942842,'lightseagreen':4280332970,'lightskyblue':4287090426,'lightslategray':4286023833,'lightslategrey':4286023833,'lightsteelblue':4289774814,'lightyellow':4294967264,'lime':4278255360,'limegreen':4281519410,'linen':4294635750,'magenta':4294902015,'maroon':4286578688,'mediumaquamarine':4284927402,'mediumblue':4278190285,'mediumorchid':4290401747,'mediumpurple':4287852763,'mediumseagreen':4282168177,'mediumslateblue':4286277870,'mediumspringgreen':4278254234,'mediumturquoise':4282962380,'mediumvioletred':4291237253,'midnightblue':4279834992,'mintcream':4294311930,'mistyrose':4294960353,'moccasin':4294960309,'navajowhite':4294958765,'navy':4278190208,'oldlace':4294833638,'olive':4286611456,'olivedrab':4285238819,'orange':4294944000,'orangered':4294919424,'orchid':4292505814,'palegoldenrod':4293847210,'palegreen':4288215960,'paleturquoise':4289720046,'palevioletred':4292571283,'papayawhip':4294963157,'peachpuff':4294957753,'peru':4291659071,'pink':4294951115,'plum':4292714717,'powderblue':4289781990,'purple':4286578816,'rebeccapurple':4284887961,'red':4294901760,'rosybrown':4290547599,'royalblue':4282477025,'saddlebrown':4287317267,'salmon':4294606962,'sandybrown':4294222944,'seagreen':4281240407,'seashell':4294964718,'sienna':4288696877,'silver':4290822336,'skyblue':4287090411,'slateblue':4285160141,'slategray':4285563024,'slategrey':4285563024,'snow':4294966010,'springgreen':4278255487,'steelblue':4282811060,'tan':4291998860,'teal':4278222976,'thistle':4292394968,'transparent':0,'tomato':4294927175,'turquoise':4282441936,'violet':4293821166,'wheat':4294303411,'white':4294967295,'whitesmoke':4294309365,'yellow':4294967040,'yellowgreen':4288335154};
+var colorMap = {
+ 'aliceblue': Float32Array.of(0.941, 0.973, 1.000, 1.000),
+ 'antiquewhite': Float32Array.of(0.980, 0.922, 0.843, 1.000),
+ 'aqua': Float32Array.of(0.000, 1.000, 1.000, 1.000),
+ 'aquamarine': Float32Array.of(0.498, 1.000, 0.831, 1.000),
+ 'azure': Float32Array.of(0.941, 1.000, 1.000, 1.000),
+ 'beige': Float32Array.of(0.961, 0.961, 0.863, 1.000),
+ 'bisque': Float32Array.of(1.000, 0.894, 0.769, 1.000),
+ 'black': Float32Array.of(0.000, 0.000, 0.000, 1.000),
+ 'blanchedalmond': Float32Array.of(1.000, 0.922, 0.804, 1.000),
+ 'blue': Float32Array.of(0.000, 0.000, 1.000, 1.000),
+ 'blueviolet': Float32Array.of(0.541, 0.169, 0.886, 1.000),
+ 'brown': Float32Array.of(0.647, 0.165, 0.165, 1.000),
+ 'burlywood': Float32Array.of(0.871, 0.722, 0.529, 1.000),
+ 'cadetblue': Float32Array.of(0.373, 0.620, 0.627, 1.000),
+ 'chartreuse': Float32Array.of(0.498, 1.000, 0.000, 1.000),
+ 'chocolate': Float32Array.of(0.824, 0.412, 0.118, 1.000),
+ 'coral': Float32Array.of(1.000, 0.498, 0.314, 1.000),
+ 'cornflowerblue': Float32Array.of(0.392, 0.584, 0.929, 1.000),
+ 'cornsilk': Float32Array.of(1.000, 0.973, 0.863, 1.000),
+ 'crimson': Float32Array.of(0.863, 0.078, 0.235, 1.000),
+ 'cyan': Float32Array.of(0.000, 1.000, 1.000, 1.000),
+ 'darkblue': Float32Array.of(0.000, 0.000, 0.545, 1.000),
+ 'darkcyan': Float32Array.of(0.000, 0.545, 0.545, 1.000),
+ 'darkgoldenrod': Float32Array.of(0.722, 0.525, 0.043, 1.000),
+ 'darkgray': Float32Array.of(0.663, 0.663, 0.663, 1.000),
+ 'darkgreen': Float32Array.of(0.000, 0.392, 0.000, 1.000),
+ 'darkgrey': Float32Array.of(0.663, 0.663, 0.663, 1.000),
+ 'darkkhaki': Float32Array.of(0.741, 0.718, 0.420, 1.000),
+ 'darkmagenta': Float32Array.of(0.545, 0.000, 0.545, 1.000),
+ 'darkolivegreen': Float32Array.of(0.333, 0.420, 0.184, 1.000),
+ 'darkorange': Float32Array.of(1.000, 0.549, 0.000, 1.000),
+ 'darkorchid': Float32Array.of(0.600, 0.196, 0.800, 1.000),
+ 'darkred': Float32Array.of(0.545, 0.000, 0.000, 1.000),
+ 'darksalmon': Float32Array.of(0.914, 0.588, 0.478, 1.000),
+ 'darkseagreen': Float32Array.of(0.561, 0.737, 0.561, 1.000),
+ 'darkslateblue': Float32Array.of(0.282, 0.239, 0.545, 1.000),
+ 'darkslategray': Float32Array.of(0.184, 0.310, 0.310, 1.000),
+ 'darkslategrey': Float32Array.of(0.184, 0.310, 0.310, 1.000),
+ 'darkturquoise': Float32Array.of(0.000, 0.808, 0.820, 1.000),
+ 'darkviolet': Float32Array.of(0.580, 0.000, 0.827, 1.000),
+ 'deeppink': Float32Array.of(1.000, 0.078, 0.576, 1.000),
+ 'deepskyblue': Float32Array.of(0.000, 0.749, 1.000, 1.000),
+ 'dimgray': Float32Array.of(0.412, 0.412, 0.412, 1.000),
+ 'dimgrey': Float32Array.of(0.412, 0.412, 0.412, 1.000),
+ 'dodgerblue': Float32Array.of(0.118, 0.565, 1.000, 1.000),
+ 'firebrick': Float32Array.of(0.698, 0.133, 0.133, 1.000),
+ 'floralwhite': Float32Array.of(1.000, 0.980, 0.941, 1.000),
+ 'forestgreen': Float32Array.of(0.133, 0.545, 0.133, 1.000),
+ 'fuchsia': Float32Array.of(1.000, 0.000, 1.000, 1.000),
+ 'gainsboro': Float32Array.of(0.863, 0.863, 0.863, 1.000),
+ 'ghostwhite': Float32Array.of(0.973, 0.973, 1.000, 1.000),
+ 'gold': Float32Array.of(1.000, 0.843, 0.000, 1.000),
+ 'goldenrod': Float32Array.of(0.855, 0.647, 0.125, 1.000),
+ 'gray': Float32Array.of(0.502, 0.502, 0.502, 1.000),
+ 'green': Float32Array.of(0.000, 0.502, 0.000, 1.000),
+ 'greenyellow': Float32Array.of(0.678, 1.000, 0.184, 1.000),
+ 'grey': Float32Array.of(0.502, 0.502, 0.502, 1.000),
+ 'honeydew': Float32Array.of(0.941, 1.000, 0.941, 1.000),
+ 'hotpink': Float32Array.of(1.000, 0.412, 0.706, 1.000),
+ 'indianred': Float32Array.of(0.804, 0.361, 0.361, 1.000),
+ 'indigo': Float32Array.of(0.294, 0.000, 0.510, 1.000),
+ 'ivory': Float32Array.of(1.000, 1.000, 0.941, 1.000),
+ 'khaki': Float32Array.of(0.941, 0.902, 0.549, 1.000),
+ 'lavender': Float32Array.of(0.902, 0.902, 0.980, 1.000),
+ 'lavenderblush': Float32Array.of(1.000, 0.941, 0.961, 1.000),
+ 'lawngreen': Float32Array.of(0.486, 0.988, 0.000, 1.000),
+ 'lemonchiffon': Float32Array.of(1.000, 0.980, 0.804, 1.000),
+ 'lightblue': Float32Array.of(0.678, 0.847, 0.902, 1.000),
+ 'lightcoral': Float32Array.of(0.941, 0.502, 0.502, 1.000),
+ 'lightcyan': Float32Array.of(0.878, 1.000, 1.000, 1.000),
+ 'lightgoldenrodyellow': Float32Array.of(0.980, 0.980, 0.824, 1.000),
+ 'lightgray': Float32Array.of(0.827, 0.827, 0.827, 1.000),
+ 'lightgreen': Float32Array.of(0.565, 0.933, 0.565, 1.000),
+ 'lightgrey': Float32Array.of(0.827, 0.827, 0.827, 1.000),
+ 'lightpink': Float32Array.of(1.000, 0.714, 0.757, 1.000),
+ 'lightsalmon': Float32Array.of(1.000, 0.627, 0.478, 1.000),
+ 'lightseagreen': Float32Array.of(0.125, 0.698, 0.667, 1.000),
+ 'lightskyblue': Float32Array.of(0.529, 0.808, 0.980, 1.000),
+ 'lightslategray': Float32Array.of(0.467, 0.533, 0.600, 1.000),
+ 'lightslategrey': Float32Array.of(0.467, 0.533, 0.600, 1.000),
+ 'lightsteelblue': Float32Array.of(0.690, 0.769, 0.871, 1.000),
+ 'lightyellow': Float32Array.of(1.000, 1.000, 0.878, 1.000),
+ 'lime': Float32Array.of(0.000, 1.000, 0.000, 1.000),
+ 'limegreen': Float32Array.of(0.196, 0.804, 0.196, 1.000),
+ 'linen': Float32Array.of(0.980, 0.941, 0.902, 1.000),
+ 'magenta': Float32Array.of(1.000, 0.000, 1.000, 1.000),
+ 'maroon': Float32Array.of(0.502, 0.000, 0.000, 1.000),
+ 'mediumaquamarine': Float32Array.of(0.400, 0.804, 0.667, 1.000),
+ 'mediumblue': Float32Array.of(0.000, 0.000, 0.804, 1.000),
+ 'mediumorchid': Float32Array.of(0.729, 0.333, 0.827, 1.000),
+ 'mediumpurple': Float32Array.of(0.576, 0.439, 0.859, 1.000),
+ 'mediumseagreen': Float32Array.of(0.235, 0.702, 0.443, 1.000),
+ 'mediumslateblue': Float32Array.of(0.482, 0.408, 0.933, 1.000),
+ 'mediumspringgreen': Float32Array.of(0.000, 0.980, 0.604, 1.000),
+ 'mediumturquoise': Float32Array.of(0.282, 0.820, 0.800, 1.000),
+ 'mediumvioletred': Float32Array.of(0.780, 0.082, 0.522, 1.000),
+ 'midnightblue': Float32Array.of(0.098, 0.098, 0.439, 1.000),
+ 'mintcream': Float32Array.of(0.961, 1.000, 0.980, 1.000),
+ 'mistyrose': Float32Array.of(1.000, 0.894, 0.882, 1.000),
+ 'moccasin': Float32Array.of(1.000, 0.894, 0.710, 1.000),
+ 'navajowhite': Float32Array.of(1.000, 0.871, 0.678, 1.000),
+ 'navy': Float32Array.of(0.000, 0.000, 0.502, 1.000),
+ 'oldlace': Float32Array.of(0.992, 0.961, 0.902, 1.000),
+ 'olive': Float32Array.of(0.502, 0.502, 0.000, 1.000),
+ 'olivedrab': Float32Array.of(0.420, 0.557, 0.137, 1.000),
+ 'orange': Float32Array.of(1.000, 0.647, 0.000, 1.000),
+ 'orangered': Float32Array.of(1.000, 0.271, 0.000, 1.000),
+ 'orchid': Float32Array.of(0.855, 0.439, 0.839, 1.000),
+ 'palegoldenrod': Float32Array.of(0.933, 0.910, 0.667, 1.000),
+ 'palegreen': Float32Array.of(0.596, 0.984, 0.596, 1.000),
+ 'paleturquoise': Float32Array.of(0.686, 0.933, 0.933, 1.000),
+ 'palevioletred': Float32Array.of(0.859, 0.439, 0.576, 1.000),
+ 'papayawhip': Float32Array.of(1.000, 0.937, 0.835, 1.000),
+ 'peachpuff': Float32Array.of(1.000, 0.855, 0.725, 1.000),
+ 'peru': Float32Array.of(0.804, 0.522, 0.247, 1.000),
+ 'pink': Float32Array.of(1.000, 0.753, 0.796, 1.000),
+ 'plum': Float32Array.of(0.867, 0.627, 0.867, 1.000),
+ 'powderblue': Float32Array.of(0.690, 0.878, 0.902, 1.000),
+ 'purple': Float32Array.of(0.502, 0.000, 0.502, 1.000),
+ 'rebeccapurple': Float32Array.of(0.400, 0.200, 0.600, 1.000),
+ 'red': Float32Array.of(1.000, 0.000, 0.000, 1.000),
+ 'rosybrown': Float32Array.of(0.737, 0.561, 0.561, 1.000),
+ 'royalblue': Float32Array.of(0.255, 0.412, 0.882, 1.000),
+ 'saddlebrown': Float32Array.of(0.545, 0.271, 0.075, 1.000),
+ 'salmon': Float32Array.of(0.980, 0.502, 0.447, 1.000),
+ 'sandybrown': Float32Array.of(0.957, 0.643, 0.376, 1.000),
+ 'seagreen': Float32Array.of(0.180, 0.545, 0.341, 1.000),
+ 'seashell': Float32Array.of(1.000, 0.961, 0.933, 1.000),
+ 'sienna': Float32Array.of(0.627, 0.322, 0.176, 1.000),
+ 'silver': Float32Array.of(0.753, 0.753, 0.753, 1.000),
+ 'skyblue': Float32Array.of(0.529, 0.808, 0.922, 1.000),
+ 'slateblue': Float32Array.of(0.416, 0.353, 0.804, 1.000),
+ 'slategray': Float32Array.of(0.439, 0.502, 0.565, 1.000),
+ 'slategrey': Float32Array.of(0.439, 0.502, 0.565, 1.000),
+ 'snow': Float32Array.of(1.000, 0.980, 0.980, 1.000),
+ 'springgreen': Float32Array.of(0.000, 1.000, 0.498, 1.000),
+ 'steelblue': Float32Array.of(0.275, 0.510, 0.706, 1.000),
+ 'tan': Float32Array.of(0.824, 0.706, 0.549, 1.000),
+ 'teal': Float32Array.of(0.000, 0.502, 0.502, 1.000),
+ 'thistle': Float32Array.of(0.847, 0.749, 0.847, 1.000),
+ 'tomato': Float32Array.of(1.000, 0.388, 0.278, 1.000),
+ 'transparent': Float32Array.of(0.000, 0.000, 0.000, 0.000),
+ 'turquoise': Float32Array.of(0.251, 0.878, 0.816, 1.000),
+ 'violet': Float32Array.of(0.933, 0.510, 0.933, 1.000),
+ 'wheat': Float32Array.of(0.961, 0.871, 0.702, 1.000),
+ 'white': Float32Array.of(1.000, 1.000, 1.000, 1.000),
+ 'whitesmoke': Float32Array.of(0.961, 0.961, 0.961, 1.000),
+ 'yellow': Float32Array.of(1.000, 1.000, 0.000, 1.000),
+ 'yellowgreen': Float32Array.of(0.604, 0.804, 0.196, 1.000),
+}
+
function colorToString(skcolor) {
// https://html.spec.whatwg.org/multipage/canvas.html#serialisation-of-a-color
var components = CanvasKit.getColorComponents(skcolor);
diff --git a/modules/canvaskit/interface.js b/modules/canvaskit/interface.js
index 495fb9d..40c5416 100644
--- a/modules/canvaskit/interface.js
+++ b/modules/canvaskit/interface.js
@@ -861,8 +861,7 @@
// 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 SkColor
- // (from CanvasKit.Color)
+ // 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) {
@@ -871,6 +870,7 @@
}
if (srcRects.length !== dstXforms.length || (colors && colors.length !== dstXforms.length)) {
SkDebug('Doing nothing since input arrays length mismatches');
+ return;
}
if (!blendMode) {
blendMode = CanvasKit.BlendMode.SrcOver;
@@ -895,6 +895,13 @@
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);
+ return;
+ }
+ // convert here
+ colors = colors.map(toUint32Color);
colorPtr = copy1dArray(colors, CanvasKit.HEAPU32);
}
}
@@ -1063,7 +1070,7 @@
}
CanvasKit.SkShader.MakeLinearGradient = function(start, end, colors, pos, mode, localMatrix, flags) {
- var colorPtr = copy1dArray(colors, CanvasKit.HEAPU32);
+ var colorPtr = copy2dArray(colors, CanvasKit.HEAPF32);
var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
flags = flags || 0;
@@ -1085,7 +1092,7 @@
}
CanvasKit.SkShader.MakeRadialGradient = function(center, radius, colors, pos, mode, localMatrix, flags) {
- var colorPtr = copy1dArray(colors, CanvasKit.HEAPU32);
+ var colorPtr = copy2dArray(colors, CanvasKit.HEAPF32);
var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
flags = flags || 0;
@@ -1107,7 +1114,7 @@
}
CanvasKit.SkShader.MakeSweepGradient = function(cx, cy, colors, pos, mode, localMatrix, flags, startAngle, endAngle) {
- var colorPtr = copy1dArray(colors, CanvasKit.HEAPU32);
+ var colorPtr = copy2dArray(colors, CanvasKit.HEAPF32);
var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
flags = flags || 0;
startAngle = startAngle || 0;
@@ -1135,7 +1142,7 @@
CanvasKit.SkShader.MakeTwoPointConicalGradient = function(start, startRadius, end, endRadius,
colors, pos, mode, localMatrix, flags) {
- var colorPtr = copy1dArray(colors, CanvasKit.HEAPU32);
+ var colorPtr = copy2dArray(colors, CanvasKit.HEAPF32);
var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
flags = flags || 0;
@@ -1257,6 +1264,7 @@
return CanvasKit._MakeImage(info, pptr, pixels.length, width * bytesPerPixel);
}
+// colors is an array of SimpleColor4f
CanvasKit.MakeSkVertices = function(mode, positions, textureCoordinates, colors,
indices, isVolatile) {
// Default isVolitile to true if not set
@@ -1282,7 +1290,8 @@
copy2dArray(textureCoordinates, CanvasKit.HEAPF32, builder.texCoords());
}
if (builder.colors()) {
- copy1dArray(colors, CanvasKit.HEAPU32, builder.colors());
+ // Convert from canvaskit 4f colors to 32 bit uint colors which builder supports.
+ copy1dArray(colors.map(toUint32Color), CanvasKit.HEAPU32, builder.colors());
}
if (builder.indices()) {
copy1dArray(indices, CanvasKit.HEAPU16, builder.indices());
diff --git a/modules/canvaskit/paragraph.js b/modules/canvaskit/paragraph.js
index 84d808e..d50edfd 100644
--- a/modules/canvaskit/paragraph.js
+++ b/modules/canvaskit/paragraph.js
@@ -65,11 +65,11 @@
CanvasKit.TextStyle = function(s) {
// Use [''] to tell closure not to minify the names
- s['backgroundColor'] = s['backgroundColor'] || 0;
- // Can't check for falsey as 0 is "white".
- if (s['color'] === undefined) {
+ if (!isCanvasKitColor(s['color'])) {
s['color'] = CanvasKit.BLACK;
}
+ s['foregroundColor'] = s['foregroundColor'] || CanvasKit.TRANSPARENT;
+ s['backgroundColor'] = s['backgroundColor'] || CanvasKit.TRANSPARENT;
s['decoration'] = s['decoration'] || 0;
s['decorationThickness'] = s['decorationThickness'] || 0;
s['fontSize'] = s['fontSize'] || 0;
@@ -83,7 +83,6 @@
SkDebug("no font families provided, text may draw wrong or not at all")
}
s['fontStyle'] = fontStyle(s['fontStyle']);
- s['foregroundColor'] = s['foregroundColor'] || 0;
return s;
}
diff --git a/modules/canvaskit/paragraph_bindings.cpp b/modules/canvaskit/paragraph_bindings.cpp
index 13f8c8e..7dc057a 100644
--- a/modules/canvaskit/paragraph_bindings.cpp
+++ b/modules/canvaskit/paragraph_bindings.cpp
@@ -21,7 +21,7 @@
#include <emscripten.h>
#include <emscripten/bind.h>
-#include "modules/canvaskit/WasmAliases.h"
+#include "modules/canvaskit/WasmCommon.h"
using namespace emscripten;
@@ -34,13 +34,13 @@
};
struct SimpleTextStyle {
- SkColor backgroundColor;
- SkColor color;
+ SimpleColor4f color;
+ SimpleColor4f foregroundColor;
+ SimpleColor4f backgroundColor;
uint8_t decoration;
SkScalar decorationThickness;
SkScalar fontSize;
SimpleFontStyle fontStyle;
- SkColor foregroundColor;
uintptr_t /* const char** */ fontFamilies;
int numFontFamilies;
@@ -48,20 +48,23 @@
para::TextStyle toTextStyle(const SimpleTextStyle& s) {
para::TextStyle ts;
- if (s.color != 0) {
- ts.setColor(s.color);
+
+ // textstyle.color doesn't support a 4f color, however the foreground and background fields below do.
+ ts.setColor(s.color.toSkColor());
+
+ // Emscripten will not allow a value_object to have an unset field, however
+ // It is functionally important that these paints be unset when no value was provided.
+ // paragraph.js defaults these colors to transparent in that case and we use that signal here.
+ if (s.foregroundColor.a > 0) {
+ SkPaint p1;
+ p1.setColor4f(s.foregroundColor.toSkColor4f());
+ ts.setForegroundColor(p1);
}
- if (s.foregroundColor != 0) {
- SkPaint p;
- p.setColor(s.foregroundColor);
- ts.setForegroundColor(p);
- }
-
- if (s.backgroundColor != 0) {
- SkPaint p;
- p.setColor(s.backgroundColor);
- ts.setBackgroundColor(p);
+ if (s.backgroundColor.a > 0) {
+ SkPaint p2;
+ p2.setColor4f(s.backgroundColor.toSkColor4f());
+ ts.setBackgroundColor(p2);
}
if (s.fontSize != 0) {
@@ -272,14 +275,14 @@
.field("textStyle", &SimpleParagraphStyle::textStyle);
value_object<SimpleTextStyle>("TextStyle")
- .field("backgroundColor", &SimpleTextStyle::backgroundColor)
.field("color", &SimpleTextStyle::color)
+ .field("foregroundColor", &SimpleTextStyle::foregroundColor)
+ .field("backgroundColor", &SimpleTextStyle::backgroundColor)
.field("decoration", &SimpleTextStyle::decoration)
.field("decorationThickness", &SimpleTextStyle::decorationThickness)
.field("_fontFamilies", &SimpleTextStyle::fontFamilies)
.field("fontSize", &SimpleTextStyle::fontSize)
.field("fontStyle", &SimpleTextStyle::fontStyle)
- .field("foregroundColor", &SimpleTextStyle::foregroundColor)
.field("_numFontFamilies", &SimpleTextStyle::numFontFamilies);
// The U stands for unsigned - we can't bind a generic/template object, so we have to specify it
diff --git a/modules/canvaskit/particles_bindings.cpp b/modules/canvaskit/particles_bindings.cpp
index aed39b4..be18932 100644
--- a/modules/canvaskit/particles_bindings.cpp
+++ b/modules/canvaskit/particles_bindings.cpp
@@ -15,7 +15,7 @@
#include <string>
-#include "modules/canvaskit/WasmAliases.h"
+#include "modules/canvaskit/WasmCommon.h"
#include <emscripten.h>
#include <emscripten/bind.h>
diff --git a/modules/canvaskit/skottie_bindings.cpp b/modules/canvaskit/skottie_bindings.cpp
index a7e44ae..a22a8b0 100644
--- a/modules/canvaskit/skottie_bindings.cpp
+++ b/modules/canvaskit/skottie_bindings.cpp
@@ -17,7 +17,7 @@
#include <emscripten.h>
#include <emscripten/bind.h>
-#include "modules/canvaskit/WasmAliases.h"
+#include "modules/canvaskit/WasmCommon.h"
#if SK_INCLUDE_MANAGED_SKOTTIE
#include "modules/skottie/include/SkottieProperty.h"
@@ -220,7 +220,9 @@
.function("render" , select_overload<void(SkCanvas*) const>(&ManagedAnimation::render), allow_raw_pointers())
.function("render" , select_overload<void(SkCanvas*, const SkRect&) const>
(&ManagedAnimation::render), allow_raw_pointers())
- .function("setColor" , &ManagedAnimation::setColor)
+ .function("setColor" , optional_override([](ManagedAnimation& self, const std::string& key, SimpleColor4f c) {
+ self.setColor(key, c.toSkColor());
+ }))
.function("setOpacity", &ManagedAnimation::setOpacity)
.function("getMarkers", &ManagedAnimation::getMarkers)
.function("getColorProps" , &ManagedAnimation::getColorProps)
diff --git a/modules/canvaskit/tests/canvas2d.spec.js b/modules/canvaskit/tests/canvas2d.spec.js
index db1ab23..6a6bbf3 100644
--- a/modules/canvaskit/tests/canvas2d.spec.js
+++ b/modules/canvaskit/tests/canvas2d.spec.js
@@ -14,6 +14,14 @@
container.innerHTML = '';
});
+ function expectColorCloseTo(a, b) {
+ expect(a.length).toEqual(4);
+ expect(b.length).toEqual(4);
+ for (let i=0; i<4; i++){
+ expect(a[i]).toBeCloseTo(b[i], 3);
+ }
+ }
+
describe('color strings', function() {
function hex(s) {
return parseInt(s, 16);
@@ -22,13 +30,13 @@
it('parses hex color strings', function(done) {
LoadCanvasKit.then(catchException(done, () => {
const parseColor = CanvasKit.parseColorString;
- expect(parseColor('#FED')).toEqual(
+ expectColorCloseTo(parseColor('#FED'),
CanvasKit.Color(hex('FF'), hex('EE'), hex('DD'), 1));
- expect(parseColor('#FEDC')).toEqual(
+ expectColorCloseTo(parseColor('#FEDC'),
CanvasKit.Color(hex('FF'), hex('EE'), hex('DD'), hex('CC')/255));
- expect(parseColor('#fed')).toEqual(
+ expectColorCloseTo(parseColor('#fed'),
CanvasKit.Color(hex('FF'), hex('EE'), hex('DD'), 1));
- expect(parseColor('#fedc')).toEqual(
+ expectColorCloseTo(parseColor('#fedc'),
CanvasKit.Color(hex('FF'), hex('EE'), hex('DD'), hex('CC')/255));
done();
}));
@@ -36,19 +44,19 @@
it('parses rgba color strings', function(done) {
LoadCanvasKit.then(catchException(done, () => {
const parseColor = CanvasKit.parseColorString;
- expect(parseColor('rgba(117, 33, 64, 0.75)')).toEqual(
+ expectColorCloseTo(parseColor('rgba(117, 33, 64, 0.75)'),
CanvasKit.Color(117, 33, 64, 0.75));
- expect(parseColor('rgb(117, 33, 64, 0.75)')).toEqual(
+ expectColorCloseTo(parseColor('rgb(117, 33, 64, 0.75)'),
CanvasKit.Color(117, 33, 64, 0.75));
- expect(parseColor('rgba(117,33,64)')).toEqual(
+ expectColorCloseTo(parseColor('rgba(117,33,64)'),
CanvasKit.Color(117, 33, 64, 1.0));
- expect(parseColor('rgb(117,33, 64)')).toEqual(
+ expectColorCloseTo(parseColor('rgb(117,33, 64)'),
CanvasKit.Color(117, 33, 64, 1.0));
- expect(parseColor('rgb(117,33, 64, 32%)')).toEqual(
+ expectColorCloseTo(parseColor('rgb(117,33, 64, 32%)'),
CanvasKit.Color(117, 33, 64, 0.32));
- expect(parseColor('rgb(117,33, 64, 0.001)')).toEqual(
+ expectColorCloseTo(parseColor('rgb(117,33, 64, 0.001)'),
CanvasKit.Color(117, 33, 64, 0.001));
- expect(parseColor('rgb(117,33,64,0)')).toEqual(
+ expectColorCloseTo(parseColor('rgb(117,33,64,0)'),
CanvasKit.Color(117, 33, 64, 0.0));
done();
}));
@@ -58,11 +66,11 @@
// Keep this one as the _testing version, because we don't include the large
// color map by default.
const parseColor = CanvasKit._testing.parseColor;
- expect(parseColor('grey')).toEqual(
+ expectColorCloseTo(parseColor('grey'),
CanvasKit.Color(128, 128, 128, 1.0));
- expect(parseColor('blanchedalmond')).toEqual(
+ expectColorCloseTo(parseColor('blanchedalmond'),
CanvasKit.Color(255, 235, 205, 1.0));
- expect(parseColor('transparent')).toEqual(
+ expectColorCloseTo(parseColor('transparent'),
CanvasKit.Color(0, 0, 0, 0));
done();
}));
@@ -75,7 +83,7 @@
expect(colorToString(CanvasKit.Color(102, 51, 153, 1.0))).toEqual('#663399');
expect(colorToString(CanvasKit.Color(255, 235, 205, 0.5))).toEqual(
- 'rgba(255, 235, 205, 0.50196078)');
+ 'rgba(255, 235, 205, 0.50000000)');
done();
}));
@@ -111,7 +119,7 @@
for (let tc of testCases) {
// Print out the test case if the two don't match.
expect(multiplyByAlpha(tc.inColor, tc.inAlpha))
- .toBe(tc.outColor, JSON.stringify(tc));
+ .toEqual(tc.outColor, JSON.stringify(tc));
}
done();
diff --git a/modules/canvaskit/tests/core.spec.js b/modules/canvaskit/tests/core.spec.js
index cc3c36d..f48684c 100644
--- a/modules/canvaskit/tests/core.spec.js
+++ b/modules/canvaskit/tests/core.spec.js
@@ -47,6 +47,15 @@
}));
});
+ function uIntColorToCanvasKitColor(c) {
+ return CanvasKit.Color(
+ (c >> 16) & 0xFF,
+ (c >> 8) & 0xFF,
+ (c >> 0) & 0xFF,
+ ((c >> 24) & 0xFF) / 255
+ );
+ }
+
it('can compute tonal colors', function(done) {
LoadCanvasKit.then(catchException(done, () => {
const input = {
@@ -54,14 +63,12 @@
spot: CanvasKit.RED,
};
const out = CanvasKit.computeTonalColors(input);
-
- expect(out.ambient).toEqual(CanvasKit.Color(0,0,0,1));
-
- const [r,g,b,a] = CanvasKit.getColorComponents(out.spot);
- expect(r).toEqual(44);
- expect(g).toEqual(0);
- expect(b).toEqual(0);
- expect(a).toBeCloseTo(0.969, 2);
+ expect(new Float32Array(out.ambient)).toEqual(CanvasKit.BLACK);
+ const expectedSpot = [0.173, 0, 0, 0.969];
+ expect(out.spot[0]).toBeCloseTo(expectedSpot[0], 3);
+ expect(out.spot[1]).toBeCloseTo(expectedSpot[1], 3);
+ expect(out.spot[2]).toBeCloseTo(expectedSpot[2], 3);
+ expect(out.spot[3]).toBeCloseTo(expectedSpot[3], 3);
done();
}));
});
@@ -221,7 +228,7 @@
const shader = CanvasKit.SkShader.MakeSweepGradient(
100,
100,
- [0xFF00FF00, 0xFF0000FF],
+ [CanvasKit.GREEN, CanvasKit.BLUE],
[0.0, 1.0],
CanvasKit.TileMode.Clamp,
);
@@ -731,8 +738,8 @@
it('exports consts correctly', function(done) {
LoadCanvasKit.then(catchException(done, () => {
- expect(CanvasKit.TRANSPARENT).toEqual(0);
- expect(CanvasKit.RED).toEqual(4294901760);
+ expect(CanvasKit.TRANSPARENT).toEqual(Float32Array.of(0, 0, 0, 0));
+ expect(CanvasKit.RED).toEqual(Float32Array.of(1, 0, 0, 1));
expect(CanvasKit.QUAD_VERB).toEqual(2);
expect(CanvasKit.CONIC_VERB).toEqual(3);
@@ -744,4 +751,15 @@
}));
});
+ it('can set and get a 4f color on a paint', function(done) {
+ LoadCanvasKit.then(catchException(done, () => {
+
+ const paint = new CanvasKit.SkPaint();
+ paint.setColor(CanvasKit.Color4f(3.3, 2.2, 1.1, 0.5));
+ expect(paint.getColor()).toEqual(Float32Array.of(3.3, 2.2, 1.1, 0.5));
+
+ done();
+ }));
+ });
+
});