1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <mutex>
17 #include "js_canvas.h"
18 #include "../brush_napi/js_brush.h"
19 #include "../pen_napi/js_pen.h"
20 #include "../path_napi/js_path.h"
21 #include "../text_blob_napi/js_text_blob.h"
22 #include "../js_drawing_utils.h"
23 #include "native_value.h"
24 #ifdef ROSEN_OHOS
25 #include "pixel_map.h"
26 #include "pixel_map_napi.h"
27 #endif
28 #include "draw/canvas.h"
29 #include "image/image.h"
30 #include "draw/path.h"
31 #include "text/text.h"
32 #include "text/text_blob.h"
33 #include "utils/point.h"
34 #include "utils/sampling_options.h"
35 #include "utils/rect.h"
36
37 namespace OHOS::Rosen {
38 #ifdef ROSEN_OHOS
39 using namespace Media;
40 namespace {
ColorSpaceToDrawingColorSpace(ColorSpace colorSpace)41 static std::shared_ptr<Drawing::ColorSpace> ColorSpaceToDrawingColorSpace(ColorSpace colorSpace)
42 {
43 switch (colorSpace) {
44 case ColorSpace::DISPLAY_P3:
45 return Drawing::ColorSpace::CreateRGB(
46 Drawing::CMSTransferFuncType::SRGB, Drawing::CMSMatrixType::DCIP3);
47 case ColorSpace::LINEAR_SRGB:
48 return Drawing::ColorSpace::CreateSRGBLinear();
49 case ColorSpace::SRGB:
50 return Drawing::ColorSpace::CreateSRGB();
51 default:
52 return Drawing::ColorSpace::CreateSRGB();
53 }
54 }
55
PixelFormatToDrawingColorType(PixelFormat pixelFormat)56 static Drawing::ColorType PixelFormatToDrawingColorType(PixelFormat pixelFormat)
57 {
58 switch (pixelFormat) {
59 case PixelFormat::RGB_565:
60 return Drawing::ColorType::COLORTYPE_RGB_565;
61 case PixelFormat::RGBA_8888:
62 return Drawing::ColorType::COLORTYPE_RGBA_8888;
63 case PixelFormat::BGRA_8888:
64 return Drawing::ColorType::COLORTYPE_BGRA_8888;
65 case PixelFormat::ALPHA_8:
66 return Drawing::ColorType::COLORTYPE_ALPHA_8;
67 case PixelFormat::RGBA_F16:
68 return Drawing::ColorType::COLORTYPE_RGBA_F16;
69 case PixelFormat::UNKNOWN:
70 case PixelFormat::ARGB_8888:
71 case PixelFormat::RGB_888:
72 case PixelFormat::NV21:
73 case PixelFormat::NV12:
74 case PixelFormat::CMYK:
75 default:
76 return Drawing::ColorType::COLORTYPE_UNKNOWN;
77 }
78 }
79
AlphaTypeToDrawingAlphaType(AlphaType alphaType)80 static Drawing::AlphaType AlphaTypeToDrawingAlphaType(AlphaType alphaType)
81 {
82 switch (alphaType) {
83 case AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
84 return Drawing::AlphaType::ALPHATYPE_UNKNOWN;
85 case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
86 return Drawing::AlphaType::ALPHATYPE_OPAQUE;
87 case AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
88 return Drawing::AlphaType::ALPHATYPE_PREMUL;
89 case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
90 return Drawing::AlphaType::ALPHATYPE_UNPREMUL;
91 default:
92 return Drawing::AlphaType::ALPHATYPE_UNKNOWN;
93 }
94 }
95
96 struct PixelMapReleaseContext {
PixelMapReleaseContextOHOS::Rosen::__anonce4dcf360111::PixelMapReleaseContext97 explicit PixelMapReleaseContext(std::shared_ptr<PixelMap> pixelMap) : pixelMap_(pixelMap) {}
98
~PixelMapReleaseContextOHOS::Rosen::__anonce4dcf360111::PixelMapReleaseContext99 ~PixelMapReleaseContext()
100 {
101 pixelMap_ = nullptr;
102 }
103
104 private:
105 std::shared_ptr<PixelMap> pixelMap_;
106 };
107
PixelMapReleaseProc(const void *,void * context)108 static void PixelMapReleaseProc(const void* /* pixels */, void* context)
109 {
110 PixelMapReleaseContext* ctx = static_cast<PixelMapReleaseContext*>(context);
111 if (ctx) {
112 delete ctx;
113 ctx = nullptr;
114 }
115 }
116
ExtractDrawingImage(std::shared_ptr<Media::PixelMap> pixelMap)117 std::shared_ptr<Drawing::Image> ExtractDrawingImage(
118 std::shared_ptr<Media::PixelMap> pixelMap)
119 {
120 if (!pixelMap) {
121 ROSEN_LOGE("Drawing_napi::pixelMap fail");
122 return nullptr;
123 }
124 ImageInfo imageInfo;
125 pixelMap->GetImageInfo(imageInfo);
126 Drawing::ImageInfo drawingImageInfo { imageInfo.size.width, imageInfo.size.height,
127 PixelFormatToDrawingColorType(imageInfo.pixelFormat),
128 AlphaTypeToDrawingAlphaType(imageInfo.alphaType),
129 ColorSpaceToDrawingColorSpace(imageInfo.colorSpace) };
130 Drawing::Pixmap imagePixmap(drawingImageInfo,
131 reinterpret_cast<const void*>(pixelMap->GetPixels()), pixelMap->GetRowBytes());
132 PixelMapReleaseContext* releaseContext = new PixelMapReleaseContext(pixelMap);
133 auto image = Drawing::Image::MakeFromRaster(imagePixmap, PixelMapReleaseProc, releaseContext);
134 if (!image) {
135 ROSEN_LOGE("Drawing_napi :RSPixelMapUtil::ExtractDrawingImage fail");
136 delete releaseContext;
137 releaseContext = nullptr;
138 }
139 return image;
140 }
141
ExtracetDrawingBitmap(std::shared_ptr<Media::PixelMap> pixelMap,Drawing::Bitmap & bitmap)142 bool ExtracetDrawingBitmap(std::shared_ptr<Media::PixelMap> pixelMap, Drawing::Bitmap& bitmap)
143 {
144 if (!pixelMap) {
145 ROSEN_LOGE("Drawing_napi ::pixelMap fail");
146 return false;
147 }
148 ImageInfo imageInfo;
149 pixelMap->GetImageInfo(imageInfo);
150 Drawing::ImageInfo drawingImageInfo { imageInfo.size.width, imageInfo.size.height,
151 PixelFormatToDrawingColorType(imageInfo.pixelFormat),
152 AlphaTypeToDrawingAlphaType(imageInfo.alphaType),
153 ColorSpaceToDrawingColorSpace(imageInfo.colorSpace) };
154 bitmap.SetInfo(drawingImageInfo);
155 bitmap.SetPixels(const_cast<void*>(reinterpret_cast<const void*>(pixelMap->GetPixels())));
156 return true;
157 }
158 }
159 #endif
160
161 namespace Drawing {
162 thread_local napi_ref JsCanvas::constructor_ = nullptr;
163 static std::mutex g_constructorInitMutex;
164
165 Canvas* g_drawingCanvas = nullptr;
166 const std::string CLASS_NAME = "Canvas";
Constructor(napi_env env,napi_callback_info info)167 napi_value JsCanvas::Constructor(napi_env env, napi_callback_info info)
168 {
169 napi_value jsThis = nullptr;
170 size_t argc = ARGC_ONE;
171 napi_value argv[ARGC_ONE] = {nullptr};
172 napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
173 if (status != napi_ok) {
174 ROSEN_LOGE("Drawing_napi: failed to napi_get_cb_info");
175 return nullptr;
176 }
177 if (argc == 0) {
178 if (g_drawingCanvas == nullptr) {
179 ROSEN_LOGE("Drawing_napi: m_canvas is nullptr");
180 return nullptr;
181 }
182 JsCanvas *jsCanvas = new(std::nothrow) JsCanvas(g_drawingCanvas);
183 status = napi_wrap(env, jsThis, jsCanvas, JsCanvas::Destructor, nullptr, nullptr);
184 if (status != napi_ok) {
185 delete jsCanvas;
186 ROSEN_LOGE("Drawing_napi: Failed to wrap native instance");
187 return nullptr;
188 }
189 } else {
190 #ifdef ROSEN_OHOS
191 PixelMapNapi* pixelMapNapi = nullptr;
192 napi_unwrap(env, argv[0], reinterpret_cast<void**>(&pixelMapNapi));
193 if (pixelMapNapi == nullptr) {
194 return nullptr;
195 }
196
197 if (pixelMapNapi != nullptr && pixelMapNapi->GetPixelNapiInner() == nullptr) {
198 return nullptr;
199 }
200
201 Bitmap bitmap;
202 if (!ExtracetDrawingBitmap(pixelMapNapi->GetPixelNapiInner(), bitmap)) {
203 return nullptr;
204 }
205
206 Canvas* canvas = new Canvas();
207 canvas->Bind(bitmap);
208 JsCanvas *jsCanvas = new(std::nothrow) JsCanvas(canvas, true);
209 status = napi_wrap(env, jsThis, jsCanvas, JsCanvas::Destructor, nullptr, nullptr);
210 if (status != napi_ok) {
211 delete jsCanvas;
212 ROSEN_LOGE("Drawing_napi: Failed to wrap native instance");
213 return nullptr;
214 }
215 #else
216 return nullptr;
217 #endif
218 }
219 return jsThis;
220 }
221
DeclareFuncAndCreateConstructor(napi_env env)222 bool JsCanvas::DeclareFuncAndCreateConstructor(napi_env env)
223 {
224 napi_property_descriptor properties[] = {
225 DECLARE_NAPI_FUNCTION("drawRect", JsCanvas::DrawRect),
226 DECLARE_NAPI_FUNCTION("drawCircle", JsCanvas::DrawCircle),
227 DECLARE_NAPI_FUNCTION("drawImage", JsCanvas::DrawImage),
228 DECLARE_NAPI_FUNCTION("drawColor", JsCanvas::DrawColor),
229 DECLARE_NAPI_FUNCTION("drawPoint", JsCanvas::DrawPoint),
230 DECLARE_NAPI_FUNCTION("drawPath", JsCanvas::DrawPath),
231 DECLARE_NAPI_FUNCTION("drawLine", JsCanvas::DrawLine),
232 DECLARE_NAPI_FUNCTION("drawTextBlob", JsCanvas::DrawText),
233 DECLARE_NAPI_FUNCTION("attachPen", JsCanvas::AttachPen),
234 DECLARE_NAPI_FUNCTION("attachBrush", JsCanvas::AttachBrush),
235 DECLARE_NAPI_FUNCTION("detachPen", JsCanvas::DetachPen),
236 DECLARE_NAPI_FUNCTION("detachBrush", JsCanvas::DetachBrush),
237 };
238
239 napi_value constructor = nullptr;
240 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
241 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
242 if (status != napi_ok) {
243 ROSEN_LOGE("Drawing_napi: DeclareFuncAndCreateConstructor Failed, define class fail");
244 return false;
245 }
246
247 status = napi_create_reference(env, constructor, 1, &constructor_);
248 if (status != napi_ok) {
249 ROSEN_LOGE("Drawing_napi: DeclareFuncAndCreateConstructor Failed, create reference fail");
250 return false;
251 }
252 return true;
253 }
254
CreateJsCanvas(napi_env env,Canvas * canvas,float width,float height)255 napi_value JsCanvas::CreateJsCanvas(napi_env env, Canvas* canvas, float width, float height)
256 {
257 napi_value constructor = nullptr;
258 napi_value result = nullptr;
259
260 {
261 std::lock_guard<std::mutex> lock(g_constructorInitMutex);
262 if (!constructor_) {
263 if (!DeclareFuncAndCreateConstructor(env)) {
264 ROSEN_LOGE("Drawing_napi: DeclareFuncAndCreateConstructor Failed");
265 return nullptr;
266 }
267 }
268 }
269
270 napi_status status = napi_get_reference_value(env, constructor_, &constructor);
271 if (status != napi_ok) {
272 ROSEN_LOGE("Drawing_napi: CreateJsCanvas napi_get_reference_value failed");
273 return nullptr;
274 }
275 g_drawingCanvas = canvas;
276 Rect rect(0, 0, width, height);
277 canvas->ClipRect(rect);
278 status = napi_new_instance(env, constructor, 0, nullptr, &result);
279 if (status != napi_ok) {
280 ROSEN_LOGE("Drawing_napi: New instance could not be obtained");
281 return nullptr;
282 }
283 return result;
284 }
285
Destructor(napi_env env,void * nativeObject,void * finalize)286 void JsCanvas::Destructor(napi_env env, void *nativeObject, void *finalize)
287 {
288 (void)finalize;
289 if (nativeObject != nullptr) {
290 JsCanvas *napi = reinterpret_cast<JsCanvas *>(nativeObject);
291 delete napi;
292 }
293 }
294
Init(napi_env env,napi_value exportObj)295 napi_value JsCanvas::Init(napi_env env, napi_value exportObj)
296 {
297 {
298 std::lock_guard<std::mutex> lock(g_constructorInitMutex);
299 if (!constructor_) {
300 if (!DeclareFuncAndCreateConstructor(env)) {
301 ROSEN_LOGE("Drawing_napi: DeclareFuncAndCreateConstructor Failed");
302 return nullptr;
303 }
304 }
305 }
306
307 napi_value constructor = nullptr;
308 napi_status status = napi_get_reference_value(env, constructor_, &constructor);
309 if (status != napi_ok) {
310 ROSEN_LOGE("Drawing_napi: napi_get_reference_value failed");
311 return nullptr;
312 }
313
314 status = napi_set_named_property(env, exportObj, CLASS_NAME.c_str(), constructor);
315 if (status != napi_ok) {
316 ROSEN_LOGE("Drawing_napi: Failed to set constructor");
317 return nullptr;
318 }
319 return exportObj;
320 }
321
~JsCanvas()322 JsCanvas::~JsCanvas()
323 {
324 if (owned_) {
325 delete m_canvas;
326 }
327 m_canvas = nullptr;
328 g_drawingCanvas = nullptr;
329 }
330
DrawRect(napi_env env,napi_callback_info info)331 napi_value JsCanvas::DrawRect(napi_env env, napi_callback_info info)
332 {
333 JsCanvas* me = CheckParamsAndGetThis<JsCanvas>(env, info);
334 return (me != nullptr) ? me->OnDrawRect(env, info) : nullptr;
335 }
336
OnDrawRect(napi_env env,napi_callback_info info)337 napi_value JsCanvas::OnDrawRect(napi_env env, napi_callback_info info)
338 {
339 if (m_canvas == nullptr) {
340 ROSEN_LOGE("JsCanvas::OnDrawRect canvas is nullptr");
341 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
342 }
343
344 size_t argc = ARGC_ONE;
345 napi_value argv[ARGC_ONE] = {nullptr};
346 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
347 if (status != napi_ok || argc < ARGC_ONE) {
348 ROSEN_LOGE("JsCanvas::OnDrawRect Argc is invalid: %{public}zu", argc);
349 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
350 }
351
352 napi_valuetype valueType = napi_undefined;
353 if (argv[0] == nullptr || napi_typeof(env, argv[0], &valueType) != napi_ok || valueType != napi_object) {
354 ROSEN_LOGE("JsCanvas::OnDrawRect Argv[0] is invalid");
355 return NapiGetUndefined(env);
356 }
357
358 napi_value tempValue = nullptr;
359 double left = 0.0;
360 double top = 0.0;
361 double right = 0.0;
362 double bottom = 0.0;
363 napi_get_named_property(env, argv[0], "left", &tempValue);
364 bool isLeftOk = ConvertFromJsValue(env, tempValue, left);
365 napi_get_named_property(env, argv[0], "right", &tempValue);
366 bool isRightOk = ConvertFromJsValue(env, tempValue, right);
367 napi_get_named_property(env, argv[0], "top", &tempValue);
368 bool isTopOk = ConvertFromJsValue(env, tempValue, top);
369 napi_get_named_property(env, argv[0], "bottom", &tempValue);
370 bool isBottomOk = ConvertFromJsValue(env, tempValue, bottom);
371 if (!(isLeftOk && isRightOk && isTopOk && isBottomOk)) {
372 ROSEN_LOGE("JsCanvas::OnDrawRect Argv[0] is invalid");
373 return NapiGetUndefined(env);
374 }
375
376 Drawing::Rect drawingRect = Drawing::Rect(left, top, right, bottom);
377 m_canvas->DrawRect(drawingRect);
378 return NapiGetUndefined(env);
379 }
380
DrawCircle(napi_env env,napi_callback_info info)381 napi_value JsCanvas::DrawCircle(napi_env env, napi_callback_info info)
382 {
383 JsCanvas* me = CheckParamsAndGetThis<JsCanvas>(env, info);
384 return (me != nullptr) ? me->OnDrawCircle(env, info) : nullptr;
385 }
386
OnDrawCircle(napi_env env,napi_callback_info info)387 napi_value JsCanvas::OnDrawCircle(napi_env env, napi_callback_info info)
388 {
389 if (m_canvas == nullptr) {
390 ROSEN_LOGE("JsCanvas::OnDrawCircle canvas is null");
391 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
392 }
393 size_t argc = ARGC_THREE;
394 napi_value argv[ARGC_THREE] = {nullptr};
395 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
396 if (status != napi_ok || argc < ARGC_THREE) {
397 ROSEN_LOGE("JsCanvas::OnDrawCircle Argc is invalid: %{public}zu", argc);
398 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
399 }
400
401 double x = 0.0;
402 double y = 0.0;
403 double radius = 0.0;
404 if (!(ConvertFromJsValue(env, argv[0], x) && ConvertFromJsValue(env, argv[ARGC_ONE], y) &&
405 ConvertFromJsValue(env, argv[ARGC_TWO], radius))) {
406 ROSEN_LOGE("JsCanvas::OnDrawCircle Argv is invalid");
407 return NapiGetUndefined(env);
408 }
409
410 Drawing::Point centerPt = Drawing::Point(x, y);
411 m_canvas->DrawCircle(centerPt, radius);
412 return NapiGetUndefined(env);
413 }
414
DrawImage(napi_env env,napi_callback_info info)415 napi_value JsCanvas::DrawImage(napi_env env, napi_callback_info info)
416 {
417 JsCanvas* me = CheckParamsAndGetThis<JsCanvas>(env, info);
418 return (me != nullptr) ? me->OnDrawImage(env, info) : nullptr;
419 }
420
OnDrawImage(napi_env env,napi_callback_info info)421 napi_value JsCanvas::OnDrawImage(napi_env env, napi_callback_info info)
422 {
423 #ifdef ROSEN_OHOS
424 if (m_canvas == nullptr) {
425 ROSEN_LOGE("JsCanvas::OnDrawImage canvas is nullptr");
426 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
427 }
428 size_t argc = ARGC_THREE;
429 napi_value argv[ARGC_THREE] = {nullptr};
430 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
431 if (status != napi_ok || argc < ARGC_THREE) {
432 ROSEN_LOGE("JsCanvas::OnDrawImage Argc is invalid: %{public}zu", argc);
433 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
434 }
435
436 PixelMapNapi* pixelMapNapi = nullptr;
437 double px = 0.0;
438 double py = 0.0;
439 napi_unwrap(env, argv[0], reinterpret_cast<void**>(&pixelMapNapi));
440 if (pixelMapNapi == nullptr ||
441 !(ConvertFromJsValue(env, argv[ARGC_ONE], px) && ConvertFromJsValue(env, argv[ARGC_TWO], py))) {
442 ROSEN_LOGE("JsCanvas::OnDrawImage Argv is invalid");
443 return NapiGetUndefined(env);
444 }
445
446 if (pixelMapNapi->GetPixelNapiInner() == nullptr) {
447 ROSEN_LOGE("JsCanvas::OnDrawImage pixelmap GetPixelNapiInner is nullptr");
448 return NapiGetUndefined(env);
449 }
450
451 std::shared_ptr<Drawing::Image> image = ExtractDrawingImage(pixelMapNapi->GetPixelNapiInner());
452 if (image == nullptr) {
453 ROSEN_LOGE("JsCanvas::OnDrawImage image is nullptr");
454 return NapiGetUndefined(env);
455 }
456
457 m_canvas->DrawImage(*image, px, py, Drawing::SamplingOptions());
458 #endif
459 return NapiGetUndefined(env);
460 }
461
DrawColor(napi_env env,napi_callback_info info)462 napi_value JsCanvas::DrawColor(napi_env env, napi_callback_info info)
463 {
464 JsCanvas* me = CheckParamsAndGetThis<JsCanvas>(env, info);
465 return (me != nullptr) ? me->OnDrawColor(env, info) : nullptr;
466 }
467
OnDrawColor(napi_env env,napi_callback_info info)468 napi_value JsCanvas::OnDrawColor(napi_env env, napi_callback_info info)
469 {
470 if (m_canvas == nullptr) {
471 ROSEN_LOGE("JsCanvas::OnDrawColor canvas is nullptr");
472 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
473 }
474 size_t argc = ARGC_TWO;
475 napi_value argv[ARGC_TWO] = {nullptr};
476 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
477 if (status != napi_ok || argc < ARGC_ONE || argc > ARGC_TWO) {
478 ROSEN_LOGE("JsCanvas::OnDrawColor Argc is invalid: %{public}zu", argc);
479 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
480 }
481
482 napi_value tempValue = nullptr;
483 int32_t alpha = 0;
484 int32_t red = 0;
485 int32_t green = 0;
486 int32_t blue = 0;
487 napi_get_named_property(env, argv[0], "alpha", &tempValue);
488 bool isAlphaOk = ConvertClampFromJsValue(env, tempValue, alpha, 0, Color::RGB_MAX);
489 napi_get_named_property(env, argv[0], "red", &tempValue);
490 bool isRedOk = ConvertClampFromJsValue(env, tempValue, red, 0, Color::RGB_MAX);
491 napi_get_named_property(env, argv[0], "green", &tempValue);
492 bool isGreenOk = ConvertClampFromJsValue(env, tempValue, green, 0, Color::RGB_MAX);
493 napi_get_named_property(env, argv[0], "blue", &tempValue);
494 bool isBlueOk = ConvertClampFromJsValue(env, tempValue, blue, 0, Color::RGB_MAX);
495 if (!(isAlphaOk && isRedOk && isGreenOk && isBlueOk)) {
496 ROSEN_LOGE("JsCanvas::OnDrawColor Argv[0] is invalid");
497 return NapiGetUndefined(env);
498 }
499
500 auto color = Color::ColorQuadSetARGB(alpha, red, green, blue);
501 if (argc == ARGC_ONE) {
502 m_canvas->DrawColor(color);
503 } else {
504 uint32_t jsMode = 0;
505 if (!ConvertFromJsValue(env, argv[1], jsMode)) {
506 ROSEN_LOGE("JsCanvas::OnDrawColor Argv[1] is invalid");
507 return NapiGetUndefined(env);
508 }
509 m_canvas->DrawColor(color, BlendMode(jsMode));
510 }
511 return NapiGetUndefined(env);
512 }
513
DrawPoint(napi_env env,napi_callback_info info)514 napi_value JsCanvas::DrawPoint(napi_env env, napi_callback_info info)
515 {
516 JsCanvas* me = CheckParamsAndGetThis<JsCanvas>(env, info);
517 return (me != nullptr) ? me->OnDrawPoint(env, info) : nullptr;
518 }
519
OnDrawPoint(napi_env env,napi_callback_info info)520 napi_value JsCanvas::OnDrawPoint(napi_env env, napi_callback_info info)
521 {
522 if (m_canvas == nullptr) {
523 ROSEN_LOGE("JsCanvas::OnDrawPoint canvas is nullptr");
524 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
525 }
526 size_t argc = ARGC_TWO;
527 napi_value argv[ARGC_TWO] = {nullptr};
528 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
529 if (status != napi_ok || argc < ARGC_TWO) {
530 ROSEN_LOGE("JsCanvas::OnDrawPoint Argc is invalid: %{public}zu", argc);
531 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
532 }
533 double px = 0.0;
534 double py = 0.0;
535 if (!(ConvertFromJsValue(env, argv[0], px) && ConvertFromJsValue(env, argv[1], py))) {
536 ROSEN_LOGE("JsCanvas::OnDrawPoint Argv is invalid");
537 return NapiGetUndefined(env);
538 }
539
540 m_canvas->DrawPoint(Point(px, py));
541 return NapiGetUndefined(env);
542 }
543
DrawPath(napi_env env,napi_callback_info info)544 napi_value JsCanvas::DrawPath(napi_env env, napi_callback_info info)
545 {
546 JsCanvas* me = CheckParamsAndGetThis<JsCanvas>(env, info);
547 return (me != nullptr) ? me->OnDrawPath(env, info) : nullptr;
548 }
549
OnDrawPath(napi_env env,napi_callback_info info)550 napi_value JsCanvas::OnDrawPath(napi_env env, napi_callback_info info)
551 {
552 if (m_canvas == nullptr) {
553 ROSEN_LOGE("JsCanvas::OnDrawPath canvas is nullptr");
554 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
555 }
556 size_t argc = ARGC_ONE;
557 napi_value argv[ARGC_ONE] = {nullptr};
558 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
559 if (status != napi_ok || argc < ARGC_ONE) {
560 ROSEN_LOGE("JsCanvas::OnDrawPath Argc is invalid: %{public}zu", argc);
561 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
562 }
563
564 JsPath* jsPath = nullptr;
565 napi_unwrap(env, argv[0], reinterpret_cast<void**>(&jsPath));
566 if (jsPath == nullptr) {
567 ROSEN_LOGE("JsCanvas::OnDrawPath jsPath is nullptr");
568 return NapiGetUndefined(env);
569 }
570
571 if (jsPath->GetPath() == nullptr) {
572 ROSEN_LOGE("JsCanvas::OnDrawPath path is nullptr");
573 return NapiGetUndefined(env);
574 }
575
576 m_canvas->DrawPath(*jsPath->GetPath());
577 return NapiGetUndefined(env);
578 }
579
DrawLine(napi_env env,napi_callback_info info)580 napi_value JsCanvas::DrawLine(napi_env env, napi_callback_info info)
581 {
582 JsCanvas* me = CheckParamsAndGetThis<JsCanvas>(env, info);
583 return (me != nullptr) ? me->OnDrawLine(env, info) : nullptr;
584 }
585
OnDrawLine(napi_env env,napi_callback_info info)586 napi_value JsCanvas::OnDrawLine(napi_env env, napi_callback_info info)
587 {
588 if (m_canvas == nullptr) {
589 ROSEN_LOGE("JsCanvas::OnDrawLine canvas is nullptr");
590 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
591 }
592 size_t argc = ARGC_FOUR;
593 napi_value argv[ARGC_FOUR] = {nullptr};
594 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
595 if (status != napi_ok || argc < ARGC_FOUR) {
596 ROSEN_LOGE("JsCanvas::OnDrawLine Argc is invalid: %{public}zu", argc);
597 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
598 }
599
600 double startPx = 0.0;
601 double startPy = 0.0;
602 double endPx = 0.0;
603 double endPy = 0.0;
604 if (!(ConvertFromJsValue(env, argv[0], startPx) && ConvertFromJsValue(env, argv[ARGC_ONE], startPy) &&
605 ConvertFromJsValue(env, argv[ARGC_TWO], endPx) && ConvertFromJsValue(env, argv[ARGC_THREE], endPy))) {
606 ROSEN_LOGE("JsCanvas::OnDrawLine Argv is invalid");
607 return NapiGetUndefined(env);
608 }
609
610 m_canvas->DrawLine(Point(startPx, startPy), Point(endPx, endPy));
611 return NapiGetUndefined(env);
612 }
613
DrawText(napi_env env,napi_callback_info info)614 napi_value JsCanvas::DrawText(napi_env env, napi_callback_info info)
615 {
616 JsCanvas* me = CheckParamsAndGetThis<JsCanvas>(env, info);
617 return (me != nullptr) ? me->OnDrawText(env, info) : nullptr;
618 }
619
OnDrawText(napi_env env,napi_callback_info info)620 napi_value JsCanvas::OnDrawText(napi_env env, napi_callback_info info)
621 {
622 if (m_canvas == nullptr) {
623 ROSEN_LOGE("JsCanvas::OnDrawText canvas is null");
624 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
625 }
626 size_t argc = ARGC_THREE;
627 napi_value argv[ARGC_THREE] = {nullptr};
628 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
629 if (status != napi_ok || argc < ARGC_THREE) {
630 ROSEN_LOGE("JsCanvas::OnDrawText Argc is invalid: %{public}zu", argc);
631 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
632 }
633
634 JsTextBlob* jsTextBlob = nullptr;
635 double x = 0.0;
636 double y = 0.0;
637 napi_unwrap(env, argv[0], reinterpret_cast<void **>(&jsTextBlob));
638 if (jsTextBlob == nullptr ||
639 !(ConvertFromJsValue(env, argv[ARGC_ONE], x) && ConvertFromJsValue(env, argv[ARGC_TWO], y))) {
640 ROSEN_LOGE("JsCanvas::OnDrawText Argv is invalid");
641 return NapiGetUndefined(env);
642 }
643
644 m_canvas->DrawTextBlob(jsTextBlob->GetTextBlob().get(), x, y);
645 return NapiGetUndefined(env);
646 }
647
AttachPen(napi_env env,napi_callback_info info)648 napi_value JsCanvas::AttachPen(napi_env env, napi_callback_info info)
649 {
650 JsCanvas* me = CheckParamsAndGetThis<JsCanvas>(env, info);
651 if (me == nullptr) {
652 return nullptr;
653 }
654 Canvas* canvas = me->GetCanvas();
655 if (canvas == nullptr) {
656 ROSEN_LOGE("JsCanvas::AttachPen canvas is nullptr");
657 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
658 }
659 size_t argc = ARGC_ONE;
660 napi_value argv[ARGC_ONE] = {nullptr};
661 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
662 if (status != napi_ok || argc < ARGC_ONE) {
663 ROSEN_LOGE("JsCanvas::AttachPen Argc is invalid: %{public}zu", argc);
664 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
665 }
666
667 JsPen* jsPen = nullptr;
668 napi_unwrap(env, argv[0], reinterpret_cast<void **>(&jsPen));
669 if (jsPen == nullptr) {
670 ROSEN_LOGE("JsCanvas::AttachPen jsPen is nullptr");
671 return NapiGetUndefined(env);
672 }
673 if (jsPen->GetPen() == nullptr) {
674 ROSEN_LOGE("JsCanvas::AttachPen pen is nullptr");
675 return NapiGetUndefined(env);
676 }
677 canvas->AttachPen(*jsPen->GetPen());
678 return NapiGetUndefined(env);
679 }
680
AttachBrush(napi_env env,napi_callback_info info)681 napi_value JsCanvas::AttachBrush(napi_env env, napi_callback_info info)
682 {
683 JsCanvas* me = CheckParamsAndGetThis<JsCanvas>(env, info);
684 if (me == nullptr) {
685 return nullptr;
686 }
687 Canvas* canvas = me->GetCanvas();
688 if (canvas == nullptr) {
689 ROSEN_LOGE("JsCanvas::AttachBrush canvas is nullptr");
690 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
691 }
692 size_t argc = ARGC_ONE;
693 napi_value argv[ARGC_ONE] = {nullptr};
694 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
695 if (status != napi_ok || argc < ARGC_ONE) {
696 ROSEN_LOGE("JsCanvas::AttachBrush Argc is invalid: %{public}zu", argc);
697 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
698 }
699
700 JsBrush* jsBrush = nullptr;
701 napi_unwrap(env, argv[0], reinterpret_cast<void **>(&jsBrush));
702 if (jsBrush == nullptr) {
703 ROSEN_LOGE("JsCanvas::AttachBrush jsBrush is nullptr");
704 return NapiGetUndefined(env);
705 }
706 if (jsBrush->GetBrush() == nullptr) {
707 ROSEN_LOGE("JsCanvas::AttachBrush brush is nullptr");
708 return NapiGetUndefined(env);
709 }
710 canvas->AttachBrush(*jsBrush->GetBrush());
711 return NapiGetUndefined(env);
712 }
713
DetachPen(napi_env env,napi_callback_info info)714 napi_value JsCanvas::DetachPen(napi_env env, napi_callback_info info)
715 {
716 JsCanvas* me = CheckParamsAndGetThis<JsCanvas>(env, info);
717 if (me == nullptr) {
718 return nullptr;
719 }
720 Canvas* canvas = me->GetCanvas();
721 if (canvas == nullptr) {
722 ROSEN_LOGE("JsCanvas::DetachPen canvas is null");
723 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
724 }
725 canvas->DetachPen();
726 return NapiGetUndefined(env);
727 }
728
DetachBrush(napi_env env,napi_callback_info info)729 napi_value JsCanvas::DetachBrush(napi_env env, napi_callback_info info)
730 {
731 JsCanvas* me = CheckParamsAndGetThis<JsCanvas>(env, info);
732 if (me == nullptr) {
733 return nullptr;
734 }
735 Canvas* canvas = me->GetCanvas();
736 if (canvas == nullptr) {
737 ROSEN_LOGE("JsCanvas::DetachBrush canvas is null");
738 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
739 }
740 canvas->DetachBrush();
741 return NapiGetUndefined(env);
742 }
743
GetCanvas()744 Canvas* JsCanvas::GetCanvas()
745 {
746 return m_canvas;
747 }
748
ResetCanvas()749 void JsCanvas::ResetCanvas()
750 {
751 g_drawingCanvas = nullptr;
752 m_canvas = nullptr;
753 }
754 } // namespace Drawing
755 } // namespace OHOS::Rosen
756