Skip to content
102 changes: 58 additions & 44 deletions packages/skia/cpp/api/JsiSkCanvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class JsiSkCanvas : public JsiSkNativeObject<JsiSkCanvas> {
auto x = arguments[1].asNumber();
auto y = arguments[2].asNumber();
std::shared_ptr<SkPaint> paint;
if (count == 4) {
if (count >= 4 && !arguments[3].isNull() && !arguments[3].isUndefined()) {
paint = JsiSkPaint::fromValue(runtime, arguments[3]);
}
_canvas->drawImage(image, x, y, SkSamplingOptions(), paint.get());
Expand All @@ -86,8 +86,12 @@ class JsiSkCanvas : public JsiSkNativeObject<JsiSkCanvas> {
auto image = JsiSkImage::fromValue(runtime, arguments[0]);
auto src = JsiSkRect::fromValue(runtime, arguments[1]);
auto dest = JsiSkRect::fromValue(runtime, arguments[2]);
auto paint = JsiSkPaint::fromValue(runtime, arguments[3]);
auto fastSample = count >= 5 && arguments[4].getBool();
std::shared_ptr<SkPaint> paint;
if (count >= 4 && !arguments[3].isNull() && !arguments[3].isUndefined()) {
paint = JsiSkPaint::fromValue(runtime, arguments[3]);
}
auto fastSample = count >= 5 && !arguments[4].isNull() &&
!arguments[4].isUndefined() && arguments[4].getBool();
_canvas->drawImageRect(image, *src, *dest, SkSamplingOptions(), paint.get(),
fastSample ? SkCanvas::kFast_SrcRectConstraint
: SkCanvas::kStrict_SrcRectConstraint);
Expand All @@ -101,10 +105,8 @@ class JsiSkCanvas : public JsiSkNativeObject<JsiSkCanvas> {
float B = arguments[3].asNumber();
float C = arguments[4].asNumber();
std::shared_ptr<SkPaint> paint;
if (count == 6) {
if (!arguments[5].isNull()) {
paint = JsiSkPaint::fromValue(runtime, arguments[5]);
}
if (count >= 6 && !arguments[5].isNull() && !arguments[5].isUndefined()) {
paint = JsiSkPaint::fromValue(runtime, arguments[5]);
}
_canvas->drawImage(image, x, y, SkSamplingOptions({B, C}), paint.get());
return jsi::Value::undefined();
Expand All @@ -117,10 +119,8 @@ class JsiSkCanvas : public JsiSkNativeObject<JsiSkCanvas> {
auto fm = (SkFilterMode)arguments[3].asNumber();
auto mm = (SkMipmapMode)arguments[4].asNumber();
std::shared_ptr<SkPaint> paint;
if (count == 6) {
if (!arguments[5].isNull()) {
paint = JsiSkPaint::fromValue(runtime, arguments[5]);
}
if (count >= 6 && !arguments[5].isNull() && !arguments[5].isUndefined()) {
paint = JsiSkPaint::fromValue(runtime, arguments[5]);
}
_canvas->drawImage(image, x, y, SkSamplingOptions(fm, mm), paint.get());
return jsi::Value::undefined();
Expand All @@ -132,10 +132,8 @@ class JsiSkCanvas : public JsiSkNativeObject<JsiSkCanvas> {
auto dest = JsiSkRect::fromValue(runtime, arguments[2]);
auto fm = (SkFilterMode)arguments[3].asNumber();
std::shared_ptr<SkPaint> paint;
if (count == 5) {
if (!arguments[4].isNull()) {
paint = JsiSkPaint::fromValue(runtime, arguments[4]);
}
if (count >= 5 && !arguments[4].isNull() && !arguments[4].isUndefined()) {
paint = JsiSkPaint::fromValue(runtime, arguments[4]);
}
_canvas->drawImageNine(image.get(), center->round(), *dest, fm,
paint.get());
Expand All @@ -149,10 +147,8 @@ class JsiSkCanvas : public JsiSkNativeObject<JsiSkCanvas> {
float B = arguments[3].asNumber();
float C = arguments[4].asNumber();
std::shared_ptr<SkPaint> paint;
if (count == 6) {
if (!arguments[5].isNull()) {
paint = JsiSkPaint::fromValue(runtime, arguments[5]);
}
if (count >= 6 && !arguments[5].isNull() && !arguments[5].isUndefined()) {
paint = JsiSkPaint::fromValue(runtime, arguments[5]);
}
auto constraint =
SkCanvas::kStrict_SrcRectConstraint; // TODO: get from caller
Expand All @@ -168,10 +164,8 @@ class JsiSkCanvas : public JsiSkNativeObject<JsiSkCanvas> {
auto filter = (SkFilterMode)arguments[3].asNumber();
auto mipmap = (SkMipmapMode)arguments[4].asNumber();
std::shared_ptr<SkPaint> paint;
if (count == 6) {
if (!arguments[5].isNull()) {
paint = JsiSkPaint::fromValue(runtime, arguments[5]);
}
if (count >= 6 && !arguments[5].isNull() && !arguments[5].isUndefined()) {
paint = JsiSkPaint::fromValue(runtime, arguments[5]);
}
auto constraint = SkCanvas::kStrict_SrcRectConstraint;
_canvas->drawImageRect(image.get(), *src, *dest, {filter, mipmap},
Expand Down Expand Up @@ -216,9 +210,8 @@ class JsiSkCanvas : public JsiSkNativeObject<JsiSkCanvas> {

void drawPoints(double pointMode, std::vector<SkPoint> points,
std::shared_ptr<SkPaint> paint) {
// Check if we have at least one point
if (points.empty()) {
throw std::invalid_argument("Points array must not be empty");
return;
}
auto p = SkSpan(points.data(), points.size());
_canvas->drawPoints(static_cast<SkCanvas::PointMode>(pointMode), p, *paint);
Expand Down Expand Up @@ -287,11 +280,22 @@ class JsiSkCanvas : public JsiSkNativeObject<JsiSkCanvas> {
}
}

auto paint =
count >= 4 ? JsiSkPaint::fromValue(runtime, arguments[4]) : nullptr;
auto blendMode = static_cast<SkBlendMode>(arguments[3].asNumber());
// Matches CanvasKit's web default (see drawPatch in interface.js), which
// always falls back to kModulate regardless of whether colors are given.
SkBlendMode blendMode = SkBlendMode::kModulate;
if (count >= 4 && !arguments[3].isNull() && !arguments[3].isUndefined()) {
blendMode = static_cast<SkBlendMode>(arguments[3].asNumber());
}

std::shared_ptr<SkPaint> paint;
if (count >= 5 && !arguments[4].isNull() && !arguments[4].isUndefined()) {
paint = JsiSkPaint::fromValue(runtime, arguments[4]);
}
SkPaint defaultPaint;
const auto &paintRef = paint != nullptr ? *paint : defaultPaint;

_canvas->drawPatch(cubics.data(), colors.empty() ? nullptr : colors.data(),
texs.empty() ? nullptr : texs.data(), blendMode, *paint);
texs.empty() ? nullptr : texs.data(), blendMode, paintRef);
return jsi::Value::undefined();
}

Expand Down Expand Up @@ -362,20 +366,29 @@ class JsiSkCanvas : public JsiSkNativeObject<JsiSkCanvas> {
int save() { return _canvas->save(); }

JSI_HOST_FUNCTION(saveLayer) {
SkPaint *paint = (count >= 1 && !arguments[0].isUndefined())
? JsiSkPaint::fromValue(runtime, arguments[0]).get()
: nullptr;
SkRect *bounds =
count >= 2 && !arguments[1].isNull() && !arguments[1].isUndefined()
? JsiSkRect::fromValue(runtime, arguments[1]).get()
// Keep the wrapper smart pointers alive for the duration of the call:
// JsiSkRect::fromValue() (and, in principle, the others) may return a
// freshly allocated temporary when the argument is a plain JS object
// rather than a host object, so taking .get() from a temporary would
// leave a dangling pointer once the expression finishes evaluating.
std::shared_ptr<SkPaint> paintPtr =
(count >= 1 && !arguments[0].isNull() && !arguments[0].isUndefined())
? JsiSkPaint::fromValue(runtime, arguments[0])
: nullptr;
std::shared_ptr<SkRect> boundsPtr =
(count >= 2 && !arguments[1].isNull() && !arguments[1].isUndefined())
? JsiSkRect::fromValue(runtime, arguments[1])
: nullptr;
SkImageFilter *backdrop =
count >= 3 && !arguments[2].isNull() && !arguments[2].isUndefined()
? JsiSkImageFilter::fromValue(runtime, arguments[2]).get()
sk_sp<SkImageFilter> backdropPtr =
(count >= 3 && !arguments[2].isNull() && !arguments[2].isUndefined())
? JsiSkImageFilter::fromValue(runtime, arguments[2])
: nullptr;
SkCanvas::SaveLayerFlags flags = count >= 4 ? arguments[3].asNumber() : 0;
return jsi::Value(_canvas->saveLayer(
SkCanvas::SaveLayerRec(bounds, paint, backdrop, flags)));
SkCanvas::SaveLayerFlags flags =
count >= 4 && !arguments[3].isNull() && !arguments[3].isUndefined()
? static_cast<SkCanvas::SaveLayerFlags>(arguments[3].asNumber())
: 0;
return jsi::Value(_canvas->saveLayer(SkCanvas::SaveLayerRec(
boundsPtr.get(), paintPtr.get(), backdropPtr.get(), flags)));
}

void restore() { _canvas->restore(); }
Expand Down Expand Up @@ -411,7 +424,8 @@ class JsiSkCanvas : public JsiSkNativeObject<JsiSkCanvas> {
auto rects = arguments[1].asObject(runtime).asArray(runtime);
auto transforms = arguments[2].asObject(runtime).asArray(runtime);
auto paint = JsiSkPaint::fromValue(runtime, arguments[3]);
auto blendMode = count > 5 && !arguments[4].isUndefined()
auto blendMode = count >= 5 && !arguments[4].isNull() &&
!arguments[4].isUndefined()
? static_cast<SkBlendMode>(arguments[4].asNumber())
: SkBlendMode::kDstOver;

Expand Down Expand Up @@ -440,7 +454,7 @@ class JsiSkCanvas : public JsiSkNativeObject<JsiSkCanvas> {
}

std::vector<SkColor> colors;
if (count > 5 && !arguments[5].isUndefined()) {
if (count >= 6 && !arguments[5].isNull() && !arguments[5].isUndefined()) {
auto colorsArray = arguments[5].asObject(runtime).asArray(runtime);
int colorsSize = static_cast<int>(colorsArray.size(runtime));

Expand Down Expand Up @@ -470,7 +484,7 @@ class JsiSkCanvas : public JsiSkNativeObject<JsiSkCanvas> {
}
}
SkSamplingOptions sampling(SkFilterMode::kLinear);
if (count > 6) {
if (count >= 7 && !arguments[6].isNull() && !arguments[6].isUndefined()) {
sampling = SamplingOptionsFromValue(runtime, arguments[6]);
}
auto x = SkSpan(xforms.data(), xforms.size());
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading