1 /*
2 * Copyright (c) 2021-2022 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 "bridge/declarative_frontend/jsview/js_canvas_renderer.h"
17 #include <cstdint>
18
19 #include "bridge/common/utils/engine_helper.h"
20 #include "bridge/declarative_frontend/engine/js_converter.h"
21 #include "bridge/declarative_frontend/engine/jsi/jsi_types.h"
22 #include "bridge/declarative_frontend/jsview/js_canvas_pattern.h"
23 #include "bridge/declarative_frontend/jsview/js_offscreen_rendering_context.h"
24 #include "bridge/declarative_frontend/jsview/models/canvas_renderer_model_impl.h"
25 #include "core/components/common/properties/paint_state.h"
26 #include "core/components_ng/pattern/canvas_renderer/canvas_renderer_model_ng.h"
27
28 #ifdef PIXEL_MAP_SUPPORTED
29 #include "pixel_map.h"
30 #include "pixel_map_napi.h"
31 #endif
32
33 namespace OHOS::Ace {
34 constexpr uint32_t PIXEL_SIZE = 4;
35 std::unique_ptr<CanvasRendererModel> CanvasRendererModel::instance_ = nullptr;
36 std::mutex CanvasRendererModel::mutex_;
GetInstance()37 CanvasRendererModel* CanvasRendererModel::GetInstance()
38 {
39 if (!instance_) {
40 std::lock_guard<std::mutex> lock(mutex_);
41 if (!instance_) {
42 #ifdef NG_BUILD
43 instance_.reset(new NG::CanvasRendererModelNG());
44 #else
45 if (Container::IsCurrentUseNewPipeline()) {
46 instance_.reset(new NG::CanvasRendererModelNG());
47 } else {
48 instance_.reset(new Framework::CanvasRendererModelImpl());
49 }
50 #endif
51 }
52 }
53 return instance_.get();
54 }
55 } // namespace OHOS::Ace
56
57 namespace OHOS::Ace::Framework {
58 std::unordered_map<int32_t, std::shared_ptr<Pattern>> JSCanvasRenderer::pattern_;
59 unsigned int JSCanvasRenderer::patternCount_ = 0;
60 namespace {
61
62 const std::set<std::string> FONT_WEIGHTS = {
63 "normal", "bold", "lighter", "bolder",
64 "100", "200", "300", "400", "500", "600", "700", "800", "900"
65 };
66 const std::set<std::string> FONT_STYLES = { "italic", "oblique", "normal" };
67 const std::set<std::string> FONT_FAMILIES = { "sans-serif", "serif", "monospace" };
68 const std::set<std::string> QUALITY_TYPE = { "low", "medium", "high" }; // Default value is low.
69 constexpr double DEFAULT_QUALITY = 0.92;
70 constexpr uint32_t COLOR_ALPHA_OFFSET = 24;
71 constexpr uint32_t COLOR_ALPHA_VALUE = 0xFF000000;
72 constexpr double DIFF = 1e-10;
73 template<typename T>
ConvertStrToEnum(const char * key,const LinearMapNode<T> * map,size_t length,T defaultValue)74 inline T ConvertStrToEnum(const char* key, const LinearMapNode<T>* map, size_t length, T defaultValue)
75 {
76 int64_t index = BinarySearchFindIndex(map, length, key);
77 return index != -1 ? map[index].value : defaultValue;
78 }
79
GetJsRectParam(const JSCallbackInfo & info)80 inline Rect GetJsRectParam(const JSCallbackInfo& info)
81 {
82 // 4 parameters: rect(x, y, width, height)
83 if (info.Length() != 4) {
84 return Rect();
85 }
86 double x = 0.0;
87 double y = 0.0;
88 double width = 0.0;
89 double height = 0.0;
90 JSViewAbstract::ParseJsDouble(info[0], x);
91 JSViewAbstract::ParseJsDouble(info[1], y);
92 JSViewAbstract::ParseJsDouble(info[2], width);
93 JSViewAbstract::ParseJsDouble(info[3], height);
94 x = PipelineBase::Vp2PxWithCurrentDensity(x);
95 y = PipelineBase::Vp2PxWithCurrentDensity(y);
96 width = PipelineBase::Vp2PxWithCurrentDensity(width);
97 height = PipelineBase::Vp2PxWithCurrentDensity(height);
98
99 Rect rect = Rect(x, y, width, height);
100 return rect;
101 }
102
ParseJsDoubleArray(const JSRef<JSVal> & jsValue,std::vector<double> & result)103 inline bool ParseJsDoubleArray(const JSRef<JSVal>& jsValue, std::vector<double>& result)
104 {
105 if (!jsValue->IsArray() && !jsValue->IsObject()) {
106 return false;
107 }
108
109 if (jsValue->IsArray()) {
110 JSRef<JSArray> array = JSRef<JSArray>::Cast(jsValue);
111 for (size_t i = 0; i < array->Length(); i++) {
112 JSRef<JSVal> value = array->GetValueAt(i);
113 if (value->IsNumber()) {
114 result.emplace_back(value->ToNumber<double>());
115 } else if (value->IsObject()) {
116 double singleResInt;
117 if (JSViewAbstract::ParseJsDouble(value, singleResInt)) {
118 result.emplace_back(singleResInt);
119 } else {
120 return false;
121 }
122 } else {
123 return false;
124 }
125 }
126 return true;
127 }
128 return false;
129 }
130
ParseJsInt(const JSRef<JSVal> & jsValue,int32_t & result)131 inline bool ParseJsInt(const JSRef<JSVal>& jsValue, int32_t& result)
132 {
133 if (!jsValue->IsNumber() && !jsValue->IsObject()) {
134 return false;
135 }
136
137 if (jsValue->IsNumber()) {
138 result = jsValue->ToNumber<int32_t>();
139 return true;
140 }
141
142 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(jsValue);
143 JSRef<JSVal> type = jsObj->GetProperty("type");
144 if (!type->IsNumber()) {
145 return false;
146 }
147
148 JSRef<JSVal> resId = jsObj->GetProperty("id");
149 if (!resId->IsNumber()) {
150 return false;
151 }
152 return false;
153 }
154
155 const LinearMapNode<TextBaseline> BASELINE_TABLE[] = {
156 { "alphabetic", TextBaseline::ALPHABETIC },
157 { "bottom", TextBaseline::BOTTOM },
158 { "hanging", TextBaseline::HANGING },
159 { "ideographic", TextBaseline::IDEOGRAPHIC },
160 { "middle", TextBaseline::MIDDLE },
161 { "top", TextBaseline::TOP },
162 };
163
ColorAlphaAdapt(uint32_t origin)164 uint32_t ColorAlphaAdapt(uint32_t origin)
165 {
166 uint32_t result = origin;
167 if ((origin >> COLOR_ALPHA_OFFSET) == 0) {
168 result = origin | COLOR_ALPHA_VALUE;
169 }
170 return result;
171 }
172
173 #if !defined(PREVIEW)
CreatePixelMapFromNapiValue(JSRef<JSVal> obj)174 RefPtr<PixelMap> CreatePixelMapFromNapiValue(JSRef<JSVal> obj)
175 {
176 if (!obj->IsObject()) {
177 return nullptr;
178 }
179 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
180 if (!runtime) {
181 return nullptr;
182 }
183 auto* nativeEngine = runtime->GetNativeEngine();
184 if (nativeEngine == nullptr) {
185 return nullptr;
186 }
187 #ifdef USE_ARK_ENGINE
188 panda::Local<JsiValue> value = obj.Get().GetLocalHandle();
189 #endif
190 JSValueWrapper valueWrapper = value;
191
192 napi_env env = reinterpret_cast<napi_env>(nativeEngine);
193 napi_handle_scope scope = nullptr;
194 napi_open_handle_scope(env, &scope);
195 napi_value napiValue = nativeEngine->ValueToNapiValue(valueWrapper);
196
197 PixelMapNapiEntry pixelMapNapiEntry = JsEngine::GetPixelMapNapiEntry();
198 if (!pixelMapNapiEntry) {
199 napi_close_handle_scope(env, scope);
200 return nullptr;
201 }
202
203 void* pixmapPtrAddr = pixelMapNapiEntry(env, napiValue);
204 if (pixmapPtrAddr == nullptr) {
205 napi_close_handle_scope(env, scope);
206 return nullptr;
207 }
208 napi_close_handle_scope(env, scope);
209 return PixelMap::CreatePixelMap(pixmapPtrAddr);
210 }
211 #endif
212 } // namespace
213
JSCanvasRenderer()214 JSCanvasRenderer::JSCanvasRenderer()
215 {
216 SetInstanceId(Container::CurrentIdSafely());
217 }
218
JsCreateLinearGradient(const JSCallbackInfo & info)219 void JSCanvasRenderer::JsCreateLinearGradient(const JSCallbackInfo& info)
220 {
221 ContainerScope scope(instanceId_);
222 JSRef<JSObject> pasteObj = JSClass<JSCanvasGradient>::NewInstance();
223 pasteObj->SetProperty("__type", "gradient");
224
225 if (info[0]->IsNumber() && info[1]->IsNumber() && info[2]->IsNumber()
226 && info[3]->IsNumber()) {
227 double x0 = 0.0;
228 double y0 = 0.0;
229 double x1 = 0.0;
230 double y1 = 0.0;
231 JSViewAbstract::ParseJsDouble(info[0], x0);
232 JSViewAbstract::ParseJsDouble(info[1], y0);
233 JSViewAbstract::ParseJsDouble(info[2], x1);
234 JSViewAbstract::ParseJsDouble(info[3], y1);
235 x0 = PipelineBase::Vp2PxWithCurrentDensity(x0);
236 y0 = PipelineBase::Vp2PxWithCurrentDensity(y0);
237 x1 = PipelineBase::Vp2PxWithCurrentDensity(x1);
238 y1 = PipelineBase::Vp2PxWithCurrentDensity(y1);
239 Offset beginOffset = Offset(x0, y0);
240 Offset endOffset = Offset(x1, y1);
241
242 Gradient* gradient = new Gradient();
243 gradient->SetType(GradientType::LINEAR);
244 gradient->SetBeginOffset(beginOffset);
245 gradient->SetEndOffset(endOffset);
246
247 auto pasteData = Referenced::Claim(pasteObj->Unwrap<JSCanvasGradient>());
248 pasteData->SetGradient(gradient);
249 info.SetReturnValue(pasteObj);
250 }
251 }
252
JsCreateRadialGradient(const JSCallbackInfo & info)253 void JSCanvasRenderer::JsCreateRadialGradient(const JSCallbackInfo& info)
254 {
255 ContainerScope scope(instanceId_);
256 JSRef<JSObject> pasteObj = JSClass<JSCanvasGradient>::NewInstance();
257 pasteObj->SetProperty("__type", "gradient");
258
259 if (info[0]->IsNumber() && info[1]->IsNumber() && info[2]->IsNumber()
260 && info[3]->IsNumber() && info[4]->IsNumber() && info[5]->IsNumber()) {
261 double startX = 0.0;
262 double startY = 0.0;
263 double startRadial = 0.0;
264 double endX = 0.0;
265 double endY = 0.0;
266 double endRadial = 0.0;
267 JSViewAbstract::ParseJsDouble(info[0], startX);
268 JSViewAbstract::ParseJsDouble(info[1], startY);
269 JSViewAbstract::ParseJsDouble(info[2], startRadial);
270 JSViewAbstract::ParseJsDouble(info[3], endX);
271 JSViewAbstract::ParseJsDouble(info[4], endY);
272 JSViewAbstract::ParseJsDouble(info[5], endRadial);
273 startX = PipelineBase::Vp2PxWithCurrentDensity(startX);
274 startY = PipelineBase::Vp2PxWithCurrentDensity(startY);
275 startRadial = PipelineBase::Vp2PxWithCurrentDensity(startRadial);
276 endX = PipelineBase::Vp2PxWithCurrentDensity(endX);
277 endY = PipelineBase::Vp2PxWithCurrentDensity(endY);
278 endRadial = PipelineBase::Vp2PxWithCurrentDensity(endRadial);
279 Offset innerCenter = Offset(startX, startY);
280 Offset outerCenter = Offset(endX, endY);
281
282 Gradient* gradient = new Gradient();
283 gradient->SetType(GradientType::RADIAL);
284 gradient->SetBeginOffset(innerCenter);
285 gradient->SetEndOffset(outerCenter);
286 gradient->SetInnerRadius(startRadial);
287 gradient->SetOuterRadius(endRadial);
288
289 auto pasteData = Referenced::Claim(pasteObj->Unwrap<JSCanvasGradient>());
290 pasteData->SetGradient(gradient);
291 info.SetReturnValue(pasteObj);
292 }
293 }
294
JsCreateConicGradient(const JSCallbackInfo & info)295 void JSCanvasRenderer::JsCreateConicGradient(const JSCallbackInfo& info)
296 {
297 ContainerScope scope(instanceId_);
298 if (info.Length() != 3) {
299 return;
300 }
301
302 JSRef<JSObject> pasteObj = JSClass<JSCanvasGradient>::NewInstance();
303 pasteObj->SetProperty("__type", "gradient");
304
305 // in radian
306 double startAngle = 0.0;
307 double x = 0.0;
308 double y = 0.0;
309 if (info[0]->IsNumber()) {
310 JSViewAbstract::ParseJsDouble(info[0], startAngle);
311 } else {
312 startAngle = 0.0;
313 }
314 if (info[1]->IsNumber()) {
315 JSViewAbstract::ParseJsDouble(info[1], x);
316 } else {
317 x = 0.0;
318 }
319 if (info[2]->IsNumber()) {
320 JSViewAbstract::ParseJsDouble(info[2], y);
321 } else {
322 y = 0.0;
323 }
324
325 x = PipelineBase::Vp2PxWithCurrentDensity(x);
326 y = PipelineBase::Vp2PxWithCurrentDensity(y);
327 startAngle = fmod(startAngle, (2 * M_PI));
328
329 Gradient* gradient = new Gradient();
330 gradient->SetType(GradientType::CONIC);
331 gradient->GetConicGradient().startAngle = AnimatableDimension(Dimension(startAngle));
332 gradient->GetConicGradient().centerX = AnimatableDimension(Dimension(x));
333 gradient->GetConicGradient().centerY = AnimatableDimension(Dimension(y));
334
335 auto pasteData = Referenced::Claim(pasteObj->Unwrap<JSCanvasGradient>());
336 pasteData->SetGradient(gradient);
337 info.SetReturnValue(pasteObj);
338 }
339
JsFillText(const JSCallbackInfo & info)340 void JSCanvasRenderer::JsFillText(const JSCallbackInfo& info)
341 {
342 ContainerScope scope(instanceId_);
343 if (info.Length() < 1) {
344 return;
345 }
346
347 if (info[0]->IsString() && info[1]->IsNumber() && info[2]->IsNumber()) {
348 double x = 0.0;
349 double y = 0.0;
350 std::string text = "";
351 JSViewAbstract::ParseJsString(info[0], text);
352 JSViewAbstract::ParseJsDouble(info[1], x);
353 JSViewAbstract::ParseJsDouble(info[2], y);
354 x = PipelineBase::Vp2PxWithCurrentDensity(x);
355 y = PipelineBase::Vp2PxWithCurrentDensity(y);
356 std::optional<double> maxWidth;
357 if (info.Length() >= 4) {
358 double width = 0.0;
359 if (info[3]->IsUndefined()) {
360 width = FLT_MAX;
361 } else if (info[3]->IsNumber()) {
362 JSViewAbstract::ParseJsDouble(info[3], width);
363 width = PipelineBase::Vp2PxWithCurrentDensity(width);
364 }
365 maxWidth = width;
366 }
367
368 BaseInfo baseInfo;
369 baseInfo.canvasPattern = canvasPattern_;
370 baseInfo.offscreenPattern = offscreenPattern_;
371 baseInfo.isOffscreen = isOffscreen_;
372 baseInfo.paintState = paintState_;
373
374 FillTextInfo fillTextInfo;
375 fillTextInfo.text = text;
376 fillTextInfo.x = x;
377 fillTextInfo.y = y;
378 fillTextInfo.maxWidth = maxWidth;
379
380 CanvasRendererModel::GetInstance()->SetFillText(baseInfo, fillTextInfo);
381 }
382 }
383
JsStrokeText(const JSCallbackInfo & info)384 void JSCanvasRenderer::JsStrokeText(const JSCallbackInfo& info)
385 {
386 ContainerScope scope(instanceId_);
387 if (info.Length() < 1) {
388 return;
389 }
390
391 if (info[0]->IsString() && info[1]->IsNumber() && info[2]->IsNumber()) {
392 double x = 0.0;
393 double y = 0.0;
394 std::string text = "";
395 JSViewAbstract::ParseJsString(info[0], text);
396 JSViewAbstract::ParseJsDouble(info[1], x);
397 JSViewAbstract::ParseJsDouble(info[2], y);
398 x = PipelineBase::Vp2PxWithCurrentDensity(x);
399 y = PipelineBase::Vp2PxWithCurrentDensity(y);
400 std::optional<double> maxWidth;
401 if (info.Length() >= 4) {
402 double width = 0.0;
403 if (info[3]->IsUndefined()) {
404 width = FLT_MAX;
405 } else if (info[3]->IsNumber()) {
406 JSViewAbstract::ParseJsDouble(info[3], width);
407 width = PipelineBase::Vp2PxWithCurrentDensity(width);
408 }
409 maxWidth = width;
410 }
411
412 BaseInfo baseInfo;
413 baseInfo.canvasPattern = canvasPattern_;
414 baseInfo.offscreenPattern = offscreenPattern_;
415 baseInfo.isOffscreen = isOffscreen_;
416 baseInfo.paintState = paintState_;
417
418 FillTextInfo fillTextInfo;
419 fillTextInfo.text = text;
420 fillTextInfo.x = x;
421 fillTextInfo.y = y;
422 fillTextInfo.maxWidth = maxWidth;
423
424 CanvasRendererModel::GetInstance()->SetStrokeText(baseInfo, fillTextInfo);
425 }
426 }
427
SetAntiAlias()428 void JSCanvasRenderer::SetAntiAlias()
429 {
430 BaseInfo baseInfo;
431 baseInfo.canvasPattern = canvasPattern_;
432 baseInfo.offscreenPattern = offscreenPattern_;
433 baseInfo.isOffscreen = isOffscreen_;
434 baseInfo.anti = anti_;
435
436 CanvasRendererModel::GetInstance()->SetAntiAlias(baseInfo);
437 }
438
JsSetFont(const JSCallbackInfo & info)439 void JSCanvasRenderer::JsSetFont(const JSCallbackInfo& info)
440 {
441 ContainerScope scope(instanceId_);
442 if (info.Length() < 1) {
443 return;
444 }
445 std::string fontStr = "";
446 JSViewAbstract::ParseJsString(info[0], fontStr);
447
448 BaseInfo baseInfo;
449 baseInfo.canvasPattern = canvasPattern_;
450 baseInfo.offscreenPattern = offscreenPattern_;
451 baseInfo.isOffscreen = isOffscreen_;
452
453 std::vector<std::string> fontProps;
454 StringUtils::StringSplitter(fontStr.c_str(), ' ', fontProps);
455 bool updateFontweight = false;
456 bool updateFontStyle = false;
457 for (const auto& fontProp : fontProps) {
458 if (FONT_WEIGHTS.find(fontProp) != FONT_WEIGHTS.end()) {
459 updateFontweight = true;
460 auto weight = ConvertStrToFontWeight(fontProp);
461 style_.SetFontWeight(weight);
462 CanvasRendererModel::GetInstance()->SetFontWeight(baseInfo, weight);
463 } else if (FONT_STYLES.find(fontProp) != FONT_STYLES.end()) {
464 updateFontStyle = true;
465 auto fontStyle = ConvertStrToFontStyle(fontProp);
466 style_.SetFontStyle(fontStyle);
467 CanvasRendererModel::GetInstance()->SetFontStyle(baseInfo, fontStyle);
468 } else if (FONT_FAMILIES.find(fontProp) != FONT_FAMILIES.end()) {
469 auto families = ConvertStrToFontFamilies(fontProp);
470 style_.SetFontFamilies(families);
471 CanvasRendererModel::GetInstance()->SetFontFamilies(baseInfo, families);
472 } else if (fontProp.find("px") != std::string::npos || fontProp.find("vp") != std::string::npos) {
473 Dimension size;
474 if (fontProp.find("vp") != std::string::npos) {
475 size = GetDimensionValue(fontProp);
476 } else {
477 std::string fontSize = fontProp.substr(0, fontProp.size() - 2);
478 size = Dimension(StringToDouble(fontProp));
479 }
480 style_.SetFontSize(size);
481 CanvasRendererModel::GetInstance()->SetFontSize(baseInfo, size);
482 }
483 }
484 if (!updateFontStyle) {
485 CanvasRendererModel::GetInstance()->SetFontStyle(baseInfo, FontStyle::NORMAL);
486 }
487 if (!updateFontweight) {
488 CanvasRendererModel::GetInstance()->SetFontWeight(baseInfo, FontWeight::NORMAL);
489 }
490 }
491
JsGetFont(const JSCallbackInfo & info)492 void JSCanvasRenderer::JsGetFont(const JSCallbackInfo& info)
493 {
494 return;
495 }
496
JsGetFillStyle(const JSCallbackInfo & info)497 void JSCanvasRenderer::JsGetFillStyle(const JSCallbackInfo& info)
498 {
499 return;
500 }
501
JsGetStrokeStyle(const JSCallbackInfo & info)502 void JSCanvasRenderer::JsGetStrokeStyle(const JSCallbackInfo& info)
503 {
504 return;
505 }
506
JsGetLineCap(const JSCallbackInfo & info)507 void JSCanvasRenderer::JsGetLineCap(const JSCallbackInfo& info)
508 {
509 return;
510 }
511
JsGetLineDash(const JSCallbackInfo & info)512 void JSCanvasRenderer::JsGetLineDash(const JSCallbackInfo& info)
513 {
514 ContainerScope scope(instanceId_);
515 BaseInfo baseInfo;
516 baseInfo.canvasPattern = canvasPattern_;
517 baseInfo.offscreenPattern = offscreenPattern_;
518 baseInfo.isOffscreen = isOffscreen_;
519
520 std::vector<double> lineDash = CanvasRendererModel::GetInstance()->GetLineDash(baseInfo);
521
522 JSRef<JSObject> lineDashObj = JSRef<JSObject>::New();
523 for (size_t i = 0; i < lineDash.size(); i++) {
524 lineDashObj->SetProperty<double>(std::to_string(i).c_str(), lineDash[i]);
525 }
526 info.SetReturnValue(lineDashObj);
527 }
528
JsGetLineJoin(const JSCallbackInfo & info)529 void JSCanvasRenderer::JsGetLineJoin(const JSCallbackInfo& info)
530 {
531 return;
532 }
533
JsGetMiterLimit(const JSCallbackInfo & info)534 void JSCanvasRenderer::JsGetMiterLimit(const JSCallbackInfo& info)
535 {
536 return;
537 }
538
JsGetLineWidth(const JSCallbackInfo & info)539 void JSCanvasRenderer::JsGetLineWidth(const JSCallbackInfo& info)
540 {
541 return;
542 }
543
JsGetTextAlign(const JSCallbackInfo & info)544 void JSCanvasRenderer::JsGetTextAlign(const JSCallbackInfo& info)
545 {
546 return;
547 }
548
JsGetTextBaseline(const JSCallbackInfo & info)549 void JSCanvasRenderer::JsGetTextBaseline(const JSCallbackInfo& info)
550 {
551 return;
552 }
553
JsGetGlobalAlpha(const JSCallbackInfo & info)554 void JSCanvasRenderer::JsGetGlobalAlpha(const JSCallbackInfo& info)
555 {
556 return;
557 }
558
JsGetGlobalCompositeOperation(const JSCallbackInfo & info)559 void JSCanvasRenderer::JsGetGlobalCompositeOperation(const JSCallbackInfo& info)
560 {
561 return;
562 }
563
JsGetLineDashOffset(const JSCallbackInfo & info)564 void JSCanvasRenderer::JsGetLineDashOffset(const JSCallbackInfo& info)
565 {
566 return;
567 }
568
JsGetShadowBlur(const JSCallbackInfo & info)569 void JSCanvasRenderer::JsGetShadowBlur(const JSCallbackInfo& info)
570 {
571 return;
572 }
573
JsGetShadowColor(const JSCallbackInfo & info)574 void JSCanvasRenderer::JsGetShadowColor(const JSCallbackInfo& info)
575 {
576 return;
577 }
578
JsGetShadowOffsetX(const JSCallbackInfo & info)579 void JSCanvasRenderer::JsGetShadowOffsetX(const JSCallbackInfo& info)
580 {
581 return;
582 }
583
JsGetShadowOffsetY(const JSCallbackInfo & info)584 void JSCanvasRenderer::JsGetShadowOffsetY(const JSCallbackInfo& info)
585 {
586 return;
587 }
588
JsGetImageSmoothingEnabled(const JSCallbackInfo & info)589 void JSCanvasRenderer::JsGetImageSmoothingEnabled(const JSCallbackInfo& info)
590 {
591 return;
592 }
593
JsGetImageSmoothingQuality(const JSCallbackInfo & info)594 void JSCanvasRenderer::JsGetImageSmoothingQuality(const JSCallbackInfo& info)
595 {
596 return;
597 }
598
ParseFillGradient(const JSCallbackInfo & info)599 void JSCanvasRenderer::ParseFillGradient(const JSCallbackInfo& info)
600 {
601 auto* jSCanvasGradient = JSRef<JSObject>::Cast(info[0])->Unwrap<JSCanvasGradient>();
602 if (!jSCanvasGradient) {
603 return;
604 }
605 Gradient* gradient = jSCanvasGradient->GetGradient();
606 if (!gradient) {
607 return;
608 }
609
610 BaseInfo baseInfo;
611 baseInfo.canvasPattern = canvasPattern_;
612 baseInfo.offscreenPattern = offscreenPattern_;
613 baseInfo.isOffscreen = isOffscreen_;
614
615 CanvasRendererModel::GetInstance()->SetFillGradient(baseInfo, *gradient);
616 }
617
ParseFillPattern(const JSCallbackInfo & info)618 void JSCanvasRenderer::ParseFillPattern(const JSCallbackInfo& info)
619 {
620 if (info.Length() < 1 || !info[0]->IsObject()) {
621 return;
622 }
623 auto* jSCanvasPattern = JSRef<JSObject>::Cast(info[0])->Unwrap<JSCanvasPattern>();
624 CHECK_NULL_VOID(jSCanvasPattern);
625 int32_t id = jSCanvasPattern->GetId();
626
627 BaseInfo baseInfo;
628 baseInfo.canvasPattern = canvasPattern_;
629 baseInfo.offscreenPattern = offscreenPattern_;
630 baseInfo.isOffscreen = isOffscreen_;
631
632 CanvasRendererModel::GetInstance()->SetFillPattern(baseInfo, GetPatternPtr(id));
633 }
634
JsSetFillStyle(const JSCallbackInfo & info)635 void JSCanvasRenderer::JsSetFillStyle(const JSCallbackInfo& info)
636 {
637 ContainerScope scope(instanceId_);
638 if (info.Length() < 1) {
639 return;
640 }
641
642 BaseInfo baseInfo;
643 baseInfo.canvasPattern = canvasPattern_;
644 baseInfo.offscreenPattern = offscreenPattern_;
645 baseInfo.isOffscreen = isOffscreen_;
646
647 if (info[0]->IsString()) {
648 Color color;
649 if (!JSViewAbstract::CheckColor(info[0], color, "CanvasRenderer", "fillStyle")) {
650 return;
651 }
652
653 CanvasRendererModel::GetInstance()->SetFillColor(baseInfo, color, true);
654 return;
655 }
656 if (info[0]->IsNumber()) {
657 auto color = Color(ColorAlphaAdapt(info[0]->ToNumber<uint32_t>()));
658 CanvasRendererModel::GetInstance()->SetFillColor(baseInfo, color, false);
659 return;
660 }
661 if (!info[0]->IsObject()) {
662 return;
663 }
664 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
665 JSRef<JSVal> typeValue = obj->GetProperty("__type");
666 std::string type = "";
667 JSViewAbstract::ParseJsString(typeValue, type);
668 if (type == "gradient") {
669 ParseFillGradient(info);
670 } else if (type == "pattern") {
671 ParseFillPattern(info);
672 }
673 }
674
ParseStorkeGradient(const JSCallbackInfo & info)675 void JSCanvasRenderer::ParseStorkeGradient(const JSCallbackInfo& info)
676 {
677 if (info.Length() < 1 || !info[0]->IsObject()) {
678 return;
679 }
680 auto* jSCanvasGradient = JSRef<JSObject>::Cast(info[0])->Unwrap<JSCanvasGradient>();
681 if (!jSCanvasGradient) {
682 return;
683 }
684 Gradient* gradient = jSCanvasGradient->GetGradient();
685 if (!gradient) {
686 return;
687 }
688
689 BaseInfo baseInfo;
690 baseInfo.canvasPattern = canvasPattern_;
691 baseInfo.offscreenPattern = offscreenPattern_;
692 baseInfo.isOffscreen = isOffscreen_;
693
694 CanvasRendererModel::GetInstance()->SetStrokeGradient(baseInfo, *gradient);
695 }
696
ParseStrokePattern(const JSCallbackInfo & info)697 void JSCanvasRenderer::ParseStrokePattern(const JSCallbackInfo& info)
698 {
699 if (info.Length() < 1 || !info[0]->IsObject()) {
700 return;
701 }
702 auto* jSCanvasPattern = JSRef<JSObject>::Cast(info[0])->Unwrap<JSCanvasPattern>();
703 CHECK_NULL_VOID(jSCanvasPattern);
704 int32_t id = jSCanvasPattern->GetId();
705
706 BaseInfo baseInfo;
707 baseInfo.canvasPattern = canvasPattern_;
708 baseInfo.offscreenPattern = offscreenPattern_;
709 baseInfo.isOffscreen = isOffscreen_;
710
711 CanvasRendererModel::GetInstance()->SetStrokePattern(baseInfo, GetPatternPtr(id));
712 }
713
JsSetStrokeStyle(const JSCallbackInfo & info)714 void JSCanvasRenderer::JsSetStrokeStyle(const JSCallbackInfo& info)
715 {
716 ContainerScope scope(instanceId_);
717 if (info.Length() < 1) {
718 return;
719 }
720
721 BaseInfo baseInfo;
722 baseInfo.canvasPattern = canvasPattern_;
723 baseInfo.offscreenPattern = offscreenPattern_;
724 baseInfo.isOffscreen = isOffscreen_;
725
726 if (info[0]->IsString()) {
727 Color color;
728 if (!JSViewAbstract::CheckColor(info[0], color, "CanvasRenderer", "strokeStyle")) {
729 return;
730 }
731 CanvasRendererModel::GetInstance()->SetStrokeColor(baseInfo, color, true);
732 return;
733 }
734 if (info[0]->IsNumber()) {
735 auto color = Color(ColorAlphaAdapt(info[0]->ToNumber<uint32_t>()));
736 CanvasRendererModel::GetInstance()->SetStrokeColor(baseInfo, color, false);
737 return;
738 }
739 if (!info[0]->IsObject()) {
740 return;
741 }
742 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
743 JSRef<JSVal> typeValue = obj->GetProperty("__type");
744 std::string type;
745 JSViewAbstract::ParseJsString(typeValue, type);
746 if (type == "gradient") {
747 ParseStorkeGradient(info);
748 } else if (type == "pattern") {
749 ParseStrokePattern(info);
750 }
751 }
752
JsMakePath2D(const JSCallbackInfo & info)753 RefPtr<CanvasPath2D> JSCanvasRenderer::JsMakePath2D(const JSCallbackInfo& info)
754 {
755 if (info.Length() == 1) {
756 if (info[0]->IsString()) {
757 std::string capStr = "";
758 JSViewAbstract::ParseJsString(info[0], capStr);
759 return AceType::MakeRefPtr<CanvasPath2D>(capStr);
760 }
761 }
762 // Example: ctx.createPath2D()
763 return AceType::MakeRefPtr<CanvasPath2D>();
764 }
765
UnwrapNapiImage(const JSRef<JSObject> jsObject)766 JSRenderImage* JSCanvasRenderer::UnwrapNapiImage(const JSRef<JSObject> jsObject)
767 {
768 ContainerScope scope(instanceId_);
769 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
770 if (runtime == nullptr) {
771 return nullptr;
772 }
773 auto vm = runtime->GetEcmaVm();
774 panda::Local<JsiValue> value = jsObject.Get().GetLocalHandle();
775 JSValueWrapper valueWrapper = value;
776 Global<JSValueRef> arkValue = valueWrapper;
777 napi_value napiValue = reinterpret_cast<napi_value>(*arkValue.ToLocal(vm));
778 panda::Local<panda::JSValueRef> nativeValue(reinterpret_cast<uintptr_t>(napiValue));
779 auto nativeObject = nativeValue->ToObject(vm);
780
781 napi_value isImageBitmap = nullptr;
782 Local<panda::StringRef> keyType = panda::StringRef::NewFromUtf8(vm, "isImageBitmap");
783 Local<panda::JSValueRef> valueType = nativeObject->Get(vm, keyType);
784 isImageBitmap = reinterpret_cast<napi_value>(*valueType);
785 if (isImageBitmap == nullptr) {
786 return nullptr;
787 }
788 int32_t type = 0;
789 panda::Local<panda::JSValueRef> localType(reinterpret_cast<uintptr_t>(isImageBitmap));
790 type = localType->Int32Value(vm);
791 if (!type) {
792 return nullptr;
793 }
794
795 JSRenderImage* jsImage = nullptr;
796 Local<panda::StringRef> keyObj = panda::StringRef::GetNapiWrapperString(vm);
797 Local<panda::JSValueRef> valObj = nativeObject->Get(vm, keyObj);
798 if (valObj->IsObject()) {
799 Local<panda::ObjectRef> ext(valObj);
800 auto ref = reinterpret_cast<NativeReference*>(ext->GetNativePointerField(0));
801 jsImage = ref != nullptr ? reinterpret_cast<JSRenderImage*>(ref->GetData()) : nullptr;
802 }
803 return jsImage;
804 }
805
JsDrawImage(const JSCallbackInfo & info)806 void JSCanvasRenderer::JsDrawImage(const JSCallbackInfo& info)
807 {
808 ContainerScope scope(instanceId_);
809 CanvasImage image;
810 ImageInfo imageInfo;
811 bool isImage = false;
812 if (!info[0]->IsObject()) {
813 return;
814 }
815 JSRenderImage* jsImage = UnwrapNapiImage(info[0]);
816 #if !defined(PREVIEW)
817 RefPtr<PixelMap> pixelMap = nullptr;
818 RefPtr<NG::SvgDomBase> svgDom = nullptr;
819 if ((jsImage && jsImage->IsSvg())) {
820 svgDom = jsImage->GetSvgDom();
821 CHECK_NULL_VOID(svgDom);
822 ImageFit imageFit = jsImage->GetImageFit();
823 isImage = true;
824 imageInfo.svgDom = svgDom;
825 imageInfo.isSvg = jsImage->IsSvg();
826 imageInfo.imageFit = imageFit;
827 } else {
828 if (jsImage) {
829 isImage = true;
830 pixelMap = jsImage->GetPixelMap();
831 } else {
832 pixelMap = CreatePixelMapFromNapiValue(info[0]);
833 }
834 CHECK_NULL_VOID(pixelMap);
835 }
836 imageInfo.isImage = false;
837 imageInfo.pixelMap = pixelMap;
838 #else
839 CHECK_NULL_VOID(jsImage);
840 isImage = true;
841 std::string imageValue = jsImage->GetSrc();
842 image.src = imageValue;
843 imageInfo.imgWidth = jsImage->GetWidth();
844 imageInfo.imgHeight = jsImage->GetHeight();
845 imageInfo.isImage = true;
846 #endif
847 ExtractInfoToImage(image, info, isImage);
848 image.instanceId = jsImage ? jsImage->GetInstanceId() : 0;
849 BaseInfo baseInfo;
850 baseInfo.canvasPattern = canvasPattern_;
851 baseInfo.offscreenPattern = offscreenPattern_;
852 baseInfo.isOffscreen = isOffscreen_;
853 imageInfo.image = image;
854
855 CanvasRendererModel::GetInstance()->DrawImage(baseInfo, imageInfo);
856 }
857
ExtractInfoToImage(CanvasImage & image,const JSCallbackInfo & info,bool isImage)858 void JSCanvasRenderer::ExtractInfoToImage(CanvasImage& image, const JSCallbackInfo& info, bool isImage)
859 {
860 ContainerScope scope(instanceId_);
861 switch (info.Length()) {
862 case 3:
863 image.flag = 0;
864 JSViewAbstract::ParseJsDouble(info[1], image.dx);
865 JSViewAbstract::ParseJsDouble(info[2], image.dy);
866 image.dx = PipelineBase::Vp2PxWithCurrentDensity(image.dx);
867 image.dy = PipelineBase::Vp2PxWithCurrentDensity(image.dy);
868 break;
869 // 5 parameters: drawImage(image, dx, dy, dWidth, dHeight)
870 case 5:
871 image.flag = 1;
872 JSViewAbstract::ParseJsDouble(info[1], image.dx);
873 JSViewAbstract::ParseJsDouble(info[2], image.dy);
874 JSViewAbstract::ParseJsDouble(info[3], image.dWidth);
875 JSViewAbstract::ParseJsDouble(info[4], image.dHeight);
876 image.dx = PipelineBase::Vp2PxWithCurrentDensity(image.dx);
877 image.dy = PipelineBase::Vp2PxWithCurrentDensity(image.dy);
878 image.dWidth = PipelineBase::Vp2PxWithCurrentDensity(image.dWidth);
879 image.dHeight = PipelineBase::Vp2PxWithCurrentDensity(image.dHeight);
880 break;
881 // 9 parameters: drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
882 case 9:
883 image.flag = 2;
884 JSViewAbstract::ParseJsDouble(info[1], image.sx);
885 JSViewAbstract::ParseJsDouble(info[2], image.sy);
886 JSViewAbstract::ParseJsDouble(info[3], image.sWidth);
887 JSViewAbstract::ParseJsDouble(info[4], image.sHeight);
888 JSViewAbstract::ParseJsDouble(info[5], image.dx);
889 JSViewAbstract::ParseJsDouble(info[6], image.dy);
890 JSViewAbstract::ParseJsDouble(info[7], image.dWidth);
891 JSViewAbstract::ParseJsDouble(info[8], image.dHeight);
892 if (isImage) {
893 image.sx = PipelineBase::Vp2PxWithCurrentDensity(image.sx);
894 image.sy = PipelineBase::Vp2PxWithCurrentDensity(image.sy);
895 image.sWidth = PipelineBase::Vp2PxWithCurrentDensity(image.sWidth);
896 image.sHeight = PipelineBase::Vp2PxWithCurrentDensity(image.sHeight);
897 }
898 image.dx = PipelineBase::Vp2PxWithCurrentDensity(image.dx);
899 image.dy = PipelineBase::Vp2PxWithCurrentDensity(image.dy);
900 image.dWidth = PipelineBase::Vp2PxWithCurrentDensity(image.dWidth);
901 image.dHeight = PipelineBase::Vp2PxWithCurrentDensity(image.dHeight);
902 break;
903 default:
904 break;
905 }
906 }
907
JsCreatePattern(const JSCallbackInfo & info)908 void JSCanvasRenderer::JsCreatePattern(const JSCallbackInfo& info)
909 {
910 ContainerScope scope(instanceId_);
911 if (info.Length() != 2) {
912 return;
913 }
914 if (info[0]->IsObject()) {
915 JSRenderImage* jsImage = UnwrapNapiImage(info[0]);
916 if (jsImage == nullptr) {
917 return;
918 }
919 std::string imageSrc = jsImage->GetSrc();
920 double imgWidth = jsImage->GetWidth();
921 double imgHeight = jsImage->GetHeight();
922 std::string repeat;
923
924 JSViewAbstract::ParseJsString(info[1], repeat);
925 auto pattern = std::make_shared<Pattern>();
926 pattern->SetImgSrc(imageSrc);
927 pattern->SetImageWidth(imgWidth);
928 pattern->SetImageHeight(imgHeight);
929 pattern->SetRepetition(repeat);
930 #if !defined(PREVIEW)
931 auto pixelMap = jsImage->GetPixelMap();
932 pattern->SetPixelMap(pixelMap);
933 #endif
934 pattern_[patternCount_] = pattern;
935
936 JSRef<JSObject> obj = JSClass<JSCanvasPattern>::NewInstance();
937 obj->SetProperty("__type", "pattern");
938 auto canvasPattern = Referenced::Claim(obj->Unwrap<JSCanvasPattern>());
939 canvasPattern->SetCanvasRenderer(AceType::WeakClaim(this));
940 canvasPattern->SetId(patternCount_);
941 patternCount_++;
942 info.SetReturnValue(obj);
943 }
944 }
945
JsCreateImageData(const JSCallbackInfo & info)946 void JSCanvasRenderer::JsCreateImageData(const JSCallbackInfo& info)
947 {
948 ContainerScope scope(instanceId_);
949 double fWidth = 0.0;
950 double fHeight = 0.0;
951 uint32_t finalWidth = 0;
952 uint32_t finalHeight = 0;
953 int32_t width = 0;
954 int32_t height = 0;
955
956 if (info.Length() == 2) {
957 JSViewAbstract::ParseJsDouble(info[0], fWidth);
958 JSViewAbstract::ParseJsDouble(info[1], fHeight);
959 fWidth = PipelineBase::Vp2PxWithCurrentDensity(fWidth);
960 fHeight = PipelineBase::Vp2PxWithCurrentDensity(fHeight);
961 }
962 if (info.Length() == 1 && info[0]->IsObject()) {
963 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
964 JSRef<JSVal> widthValue = obj->GetProperty("width");
965 JSRef<JSVal> heightValue = obj->GetProperty("height");
966 JSViewAbstract::ParseJsDouble(widthValue, fWidth);
967 JSViewAbstract::ParseJsDouble(heightValue, fHeight);
968 }
969
970 width = fWidth + DIFF;
971 height = fHeight + DIFF;
972 finalWidth = static_cast<uint32_t>(std::abs(width));
973 finalHeight = static_cast<uint32_t>(std::abs(height));
974 JSRef<JSArrayBuffer> arrayBuffer = JSRef<JSArrayBuffer>::New(finalWidth * finalHeight * PIXEL_SIZE);
975 // return the black image
976 auto* buffer = static_cast<uint32_t*>(arrayBuffer->GetBuffer());
977 for (uint32_t idx = 0; idx < finalWidth * finalHeight; ++idx) {
978 buffer[idx] = 0xffffffff;
979 }
980
981 JSRef<JSUint8ClampedArray> colorArray =
982 JSRef<JSUint8ClampedArray>::New(arrayBuffer->GetLocalHandle(), 0, arrayBuffer->ByteLength());
983
984 auto retObj = JSRef<JSObject>::New();
985 retObj->SetProperty("width", finalWidth);
986 retObj->SetProperty("height", finalHeight);
987 retObj->SetPropertyObject("data", colorArray);
988 info.SetReturnValue(retObj);
989 }
990
JsPutImageData(const JSCallbackInfo & info)991 void JSCanvasRenderer::JsPutImageData(const JSCallbackInfo& info)
992 {
993 ContainerScope scope(instanceId_);
994 if (info.Length() < 1 || !info[0]->IsObject()) {
995 return;
996 }
997 int32_t width = 0;
998 int32_t height = 0;
999 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
1000 JSRef<JSVal> widthValue = obj->GetProperty("width");
1001 JSRef<JSVal> heightValue = obj->GetProperty("height");
1002 ParseJsInt(widthValue, width);
1003 ParseJsInt(heightValue, height);
1004
1005 ImageData imageData;
1006 std::vector<uint8_t> array;
1007 ParseImageData(info, imageData, array);
1008
1009 for (int32_t i = std::max(imageData.dirtyY, 0); i < imageData.dirtyY + imageData.dirtyHeight; ++i) {
1010 for (int32_t j = std::max(imageData.dirtyX, 0); j < imageData.dirtyX + imageData.dirtyWidth; ++j) {
1011 uint32_t idx = 4 * (j + width * i);
1012 if (array.size() > idx + 3) {
1013 imageData.data.emplace_back(
1014 Color::FromARGB(array[idx + 3], array[idx], array[idx + 1], array[idx + 2]));
1015 }
1016 }
1017 }
1018
1019 BaseInfo baseInfo;
1020 baseInfo.canvasPattern = canvasPattern_;
1021 baseInfo.offscreenPattern = offscreenPattern_;
1022 baseInfo.isOffscreen = isOffscreen_;
1023
1024 CanvasRendererModel::GetInstance()->PutImageData(baseInfo, imageData);
1025 }
1026
ParseImageData(const JSCallbackInfo & info,ImageData & imageData,std::vector<uint8_t> & array)1027 void JSCanvasRenderer::ParseImageData(const JSCallbackInfo& info, ImageData& imageData, std::vector<uint8_t>& array)
1028 {
1029 ContainerScope scope(instanceId_);
1030 int32_t width = 0;
1031 int32_t height = 0;
1032
1033 if (info[0]->IsObject()) {
1034 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
1035 JSRef<JSVal> widthValue = obj->GetProperty("width");
1036 JSRef<JSVal> heightValue = obj->GetProperty("height");
1037 JSRef<JSVal> dataValue = obj->GetProperty("data");
1038 ParseJsInt(widthValue, width);
1039 ParseJsInt(heightValue, height);
1040 if (dataValue->IsUint8ClampedArray()) {
1041 JSRef<JSUint8ClampedArray> colorArray = JSRef<JSUint8ClampedArray>::Cast(dataValue);
1042 auto arrayBuffer = colorArray->GetArrayBuffer();
1043 auto* buffer = static_cast<uint8_t*>(arrayBuffer->GetBuffer());
1044 for (auto idx = 0; idx < arrayBuffer->ByteLength(); ++idx) {
1045 array.emplace_back(buffer[idx]);
1046 }
1047 }
1048 }
1049
1050 Dimension value;
1051 if (info[1]->IsString()) {
1052 std::string imageDataXStr = "";
1053 JSViewAbstract::ParseJsString(info[1], imageDataXStr);
1054 value = GetDimensionValue(imageDataXStr);
1055 imageData.x = value.Value();
1056 } else {
1057 ParseJsInt(info[1], imageData.x);
1058 imageData.x = PipelineBase::Vp2PxWithCurrentDensity(imageData.x);
1059 }
1060 if (info[2]->IsString()) {
1061 std::string imageDataYStr = "";
1062 JSViewAbstract::ParseJsString(info[2], imageDataYStr);
1063 value = GetDimensionValue(imageDataYStr);
1064 imageData.y = value.Value();
1065 } else {
1066 ParseJsInt(info[2], imageData.y);
1067 imageData.y = PipelineBase::Vp2PxWithCurrentDensity(imageData.y);
1068 }
1069
1070 imageData.dirtyWidth = width;
1071 imageData.dirtyHeight = height;
1072
1073 if (info.Length() == 7) {
1074 ParseImageDataAsStr(info, imageData);
1075 }
1076
1077 imageData.dirtyWidth = imageData.dirtyX < 0 ? std::min(imageData.dirtyX + imageData.dirtyWidth, width)
1078 : std::min(width - imageData.dirtyX, imageData.dirtyWidth);
1079 imageData.dirtyHeight = imageData.dirtyY < 0 ? std::min(imageData.dirtyY + imageData.dirtyHeight, height)
1080 : std::min(height - imageData.dirtyY, imageData.dirtyHeight);
1081 }
1082
ParseImageDataAsStr(const JSCallbackInfo & info,ImageData & imageData)1083 void JSCanvasRenderer::ParseImageDataAsStr(const JSCallbackInfo& info, ImageData& imageData)
1084 {
1085 ContainerScope scope(instanceId_);
1086 Dimension value;
1087 if (info[3]->IsString()) {
1088 std::string imageDataDirtyXStr = "";
1089 JSViewAbstract::ParseJsString(info[3], imageDataDirtyXStr);
1090 value = GetDimensionValue(imageDataDirtyXStr);
1091 imageData.dirtyX = value.Value();
1092 } else {
1093 ParseJsInt(info[3], imageData.dirtyX);
1094 imageData.dirtyX = PipelineBase::Vp2PxWithCurrentDensity(imageData.dirtyX);
1095 }
1096 if (info[4]->IsString()) {
1097 std::string imageDataDirtyYStr = "";
1098 JSViewAbstract::ParseJsString(info[4], imageDataDirtyYStr);
1099 value = GetDimensionValue(imageDataDirtyYStr);
1100 imageData.dirtyY = value.Value();
1101 } else {
1102 ParseJsInt(info[4], imageData.dirtyY);
1103 imageData.dirtyY = PipelineBase::Vp2PxWithCurrentDensity(imageData.dirtyY);
1104 }
1105 if (info[5]->IsString()) {
1106 std::string imageDataDirtWidth = "";
1107 JSViewAbstract::ParseJsString(info[5], imageDataDirtWidth);
1108 value = GetDimensionValue(imageDataDirtWidth);
1109 imageData.dirtyWidth = value.Value();
1110 } else {
1111 ParseJsInt(info[5], imageData.dirtyWidth);
1112 imageData.dirtyWidth = PipelineBase::Vp2PxWithCurrentDensity(imageData.dirtyWidth);
1113 }
1114 if (info[6]->IsString()) {
1115 std::string imageDataDirtyHeight = "";
1116 JSViewAbstract::ParseJsString(info[6], imageDataDirtyHeight);
1117 value = GetDimensionValue(imageDataDirtyHeight);
1118 imageData.dirtyHeight = value.Value();
1119 } else {
1120 ParseJsInt(info[6], imageData.dirtyHeight);
1121 imageData.dirtyHeight = PipelineBase::Vp2PxWithCurrentDensity(imageData.dirtyHeight);
1122 }
1123 }
1124
JsCloseImageBitmap(const std::string & src)1125 void JSCanvasRenderer::JsCloseImageBitmap(const std::string& src)
1126 {
1127 ContainerScope scope(instanceId_);
1128 BaseInfo baseInfo;
1129 baseInfo.canvasPattern = canvasPattern_;
1130 baseInfo.offscreenPattern = offscreenPattern_;
1131 baseInfo.isOffscreen = isOffscreen_;
1132
1133 CanvasRendererModel::GetInstance()->CloseImageBitmap(baseInfo, src);
1134 }
1135
JsGetImageData(const JSCallbackInfo & info)1136 void JSCanvasRenderer::JsGetImageData(const JSCallbackInfo& info)
1137 {
1138 ContainerScope scope(instanceId_);
1139 double fLeft = 0.0;
1140 double fTop = 0.0;
1141 double fWidth = 0.0;
1142 double fHeight = 0.0;
1143 uint32_t finalWidth = 0;
1144 uint32_t finalHeight = 0;
1145 int32_t left = 0;
1146 int32_t top = 0;
1147 int32_t width = 0;
1148 int32_t height = 0;
1149
1150 JSViewAbstract::ParseJsDouble(info[0], fLeft);
1151 JSViewAbstract::ParseJsDouble(info[1], fTop);
1152 JSViewAbstract::ParseJsDouble(info[2], fWidth);
1153 JSViewAbstract::ParseJsDouble(info[3], fHeight);
1154
1155 fLeft = PipelineBase::Vp2PxWithCurrentDensity(fLeft);
1156 fTop = PipelineBase::Vp2PxWithCurrentDensity(fTop);
1157 fWidth = PipelineBase::Vp2PxWithCurrentDensity(fWidth);
1158 fHeight = PipelineBase::Vp2PxWithCurrentDensity(fHeight);
1159
1160 left = fLeft;
1161 top = fTop;
1162 width = fWidth + DIFF;
1163 height = fHeight + DIFF;
1164
1165 finalWidth = static_cast<uint32_t>(std::abs(width));
1166 finalHeight = static_cast<uint32_t>(std::abs(height));
1167 int32_t length = finalHeight * finalWidth * 4;
1168 JSRef<JSArrayBuffer> arrayBuffer = JSRef<JSArrayBuffer>::New(length);
1169 auto* buffer = static_cast<uint8_t*>(arrayBuffer->GetBuffer());
1170
1171 BaseInfo baseInfo;
1172 baseInfo.canvasPattern = canvasPattern_;
1173 baseInfo.offscreenPattern = offscreenPattern_;
1174 baseInfo.isOffscreen = isOffscreen_;
1175
1176 ImageSize imageSize;
1177 imageSize.left = left;
1178 imageSize.top = top;
1179 imageSize.width = width;
1180 imageSize.height = height;
1181 CanvasRendererModel::GetInstance()->GetImageDataModel(baseInfo, imageSize, buffer);
1182
1183 JSRef<JSUint8ClampedArray> colorArray =
1184 JSRef<JSUint8ClampedArray>::New(arrayBuffer->GetLocalHandle(), 0, arrayBuffer->ByteLength());
1185
1186 auto retObj = JSRef<JSObject>::New();
1187 retObj->SetProperty("width", finalWidth);
1188 retObj->SetProperty("height", finalHeight);
1189 retObj->SetPropertyObject("data", colorArray);
1190 info.SetReturnValue(retObj);
1191 }
1192
JsGetPixelMap(const JSCallbackInfo & info)1193 void JSCanvasRenderer::JsGetPixelMap(const JSCallbackInfo& info)
1194 {
1195 ContainerScope scope(instanceId_);
1196 #ifdef PIXEL_MAP_SUPPORTED
1197 // 0 Get input param
1198 double fLeft = 0.0;
1199 double fTop = 0.0;
1200 double fWidth = 0.0;
1201 double fHeight = 0.0;
1202 int32_t left = 0;
1203 int32_t top = 0;
1204 int32_t width = 0;
1205 int32_t height = 0;
1206
1207 JSViewAbstract::ParseJsDouble(info[0], fLeft);
1208 JSViewAbstract::ParseJsDouble(info[1], fTop);
1209 JSViewAbstract::ParseJsDouble(info[2], fWidth);
1210 JSViewAbstract::ParseJsDouble(info[3], fHeight);
1211
1212 fLeft = PipelineBase::Vp2PxWithCurrentDensity(fLeft);
1213 fTop = PipelineBase::Vp2PxWithCurrentDensity(fTop);
1214 fWidth = PipelineBase::Vp2PxWithCurrentDensity(fWidth);
1215 fHeight = PipelineBase::Vp2PxWithCurrentDensity(fHeight);
1216
1217 left = fLeft;
1218 top = fTop;
1219 width = fWidth + DIFF;
1220 height = fHeight + DIFF;
1221
1222 BaseInfo baseInfo;
1223 baseInfo.canvasPattern = canvasPattern_;
1224 baseInfo.offscreenPattern = offscreenPattern_;
1225 baseInfo.isOffscreen = isOffscreen_;
1226
1227 ImageSize imageSize;
1228 imageSize.left = left;
1229 imageSize.top = top;
1230 imageSize.width = width;
1231 imageSize.height = height;
1232 auto pixelmap = CanvasRendererModel::GetInstance()->GetPixelMap(baseInfo, imageSize);
1233 CHECK_NULL_VOID(pixelmap);
1234
1235 // 3 pixelmap to NapiValue
1236 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
1237 CHECK_NULL_VOID(runtime);
1238 NativeEngine* nativeEngine = runtime->GetNativeEngine();
1239 CHECK_NULL_VOID(nativeEngine);
1240 napi_env env = reinterpret_cast<napi_env>(nativeEngine);
1241 auto pixelmapSharedPtr = pixelmap->GetPixelMapSharedPtr();
1242 napi_value napiValue = OHOS::Media::PixelMapNapi::CreatePixelMap(env, pixelmapSharedPtr);
1243
1244 // 4 NapiValue to JsValue
1245 #ifdef USE_ARK_ENGINE
1246 auto jsValue = JsConverter::ConvertNapiValueToJsVal(napiValue);
1247 info.SetReturnValue(jsValue);
1248 #else
1249 napi_value temp = nullptr;
1250 napi_create_int32(env, 0, &temp);
1251 napi_set_named_property(env, napiValue, "index", temp);
1252 #endif
1253 #else
1254 TAG_LOGI(
1255 AceLogTag::ACE_CANVAS, "[Engine Log] The function 'getPixelMap' is not supported on the current platform.");
1256 #endif
1257 }
1258
JsSetPixelMap(const JSCallbackInfo & info)1259 void JSCanvasRenderer::JsSetPixelMap(const JSCallbackInfo& info)
1260 {
1261 ContainerScope scope(instanceId_);
1262 if (info.Length() != 1) {
1263 return;
1264 }
1265 CanvasImage image;
1266 RefPtr<PixelMap> pixelMap = nullptr;
1267 if (info[0]->IsObject()) {
1268 #if !defined(PREVIEW)
1269 pixelMap = CreatePixelMapFromNapiValue(info[0]);
1270 #endif
1271 if (!pixelMap) {
1272 return;
1273 }
1274
1275 BaseInfo baseInfo;
1276 baseInfo.canvasPattern = canvasPattern_;
1277 baseInfo.offscreenPattern = offscreenPattern_;
1278 baseInfo.isOffscreen = isOffscreen_;
1279
1280 ImageInfo imageInfo;
1281 imageInfo.image = image;
1282 imageInfo.pixelMap = pixelMap;
1283
1284 CanvasRendererModel::GetInstance()->DrawPixelMap(baseInfo, imageInfo);
1285 }
1286 }
1287
JsDrawBitmapMesh(const JSCallbackInfo & info)1288 void JSCanvasRenderer::JsDrawBitmapMesh(const JSCallbackInfo& info)
1289 {
1290 ContainerScope scope(instanceId_);
1291 RefPtr<AceType> OffscreenPattern;
1292
1293 if (info.Length() != 4) {
1294 return;
1295 }
1296
1297 if (info[0]->IsObject()) {
1298 uint32_t id = 0;
1299 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
1300 JSRef<JSVal> jsId = obj->GetProperty("__id");
1301 JSViewAbstract::ParseJsInteger(jsId, id);
1302 OffscreenPattern = JSOffscreenRenderingContext::GetOffscreenPattern(id);
1303 } else {
1304 return;
1305 }
1306
1307 std::vector<double> mesh;
1308 double column;
1309 double row;
1310 if (!ParseJsDoubleArray(info[1], mesh)) {
1311 return;
1312 }
1313 if (!JSViewAbstract::ParseJsDouble(info[2], column)) {
1314 return;
1315 }
1316 if (!JSViewAbstract::ParseJsDouble(info[3], row)) {
1317 return;
1318 }
1319
1320 BitmapMeshInfo bitmapMeshInfo;
1321 bitmapMeshInfo.pool = canvasPattern_;
1322 bitmapMeshInfo.offscreenPattern = OffscreenPattern;
1323 bitmapMeshInfo.mesh = mesh;
1324 bitmapMeshInfo.column = column;
1325 bitmapMeshInfo.row = row;
1326 CanvasRendererModel::GetInstance()->DrawBitmapMesh(bitmapMeshInfo);
1327 }
1328
JsGetFilter(const JSCallbackInfo & info)1329 void JSCanvasRenderer::JsGetFilter(const JSCallbackInfo& info)
1330 {
1331 return;
1332 }
1333
JsSetFilter(const JSCallbackInfo & info)1334 void JSCanvasRenderer::JsSetFilter(const JSCallbackInfo& info)
1335 {
1336 ContainerScope scope(instanceId_);
1337 if (!info[0]->IsString() || info[0]->IsUndefined() || info[0]->IsNull()) {
1338 return;
1339 }
1340 std::string filterStr = "none";
1341 JSViewAbstract::ParseJsString(info[0], filterStr);
1342 if (filterStr == "") {
1343 return;
1344 }
1345
1346 BaseInfo baseInfo;
1347 baseInfo.canvasPattern = canvasPattern_;
1348 baseInfo.offscreenPattern = offscreenPattern_;
1349 baseInfo.isOffscreen = isOffscreen_;
1350
1351 CanvasRendererModel::GetInstance()->SetFilterParam(baseInfo, filterStr);
1352 }
1353
JsGetDirection(const JSCallbackInfo & info)1354 void JSCanvasRenderer::JsGetDirection(const JSCallbackInfo& info)
1355 {
1356 return;
1357 }
1358
JsSetDirection(const JSCallbackInfo & info)1359 void JSCanvasRenderer::JsSetDirection(const JSCallbackInfo& info)
1360 {
1361 ContainerScope scope(instanceId_);
1362 if (!info[0]->IsString()) {
1363 return;
1364 }
1365 std::string directionStr;
1366 JSViewAbstract::ParseJsString(info[0], directionStr);
1367 auto direction = ConvertStrToTextDirection(directionStr);
1368
1369 BaseInfo baseInfo;
1370 baseInfo.canvasPattern = canvasPattern_;
1371 baseInfo.offscreenPattern = offscreenPattern_;
1372 baseInfo.isOffscreen = isOffscreen_;
1373
1374 CanvasRendererModel::GetInstance()->SetTextDirection(baseInfo, direction);
1375 }
1376
JsGetJsonData(const JSCallbackInfo & info)1377 void JSCanvasRenderer::JsGetJsonData(const JSCallbackInfo& info)
1378 {
1379 ContainerScope scope(instanceId_);
1380 std::string path = "";
1381 std::string jsonData = "";
1382
1383 BaseInfo baseInfo;
1384 baseInfo.canvasPattern = canvasPattern_;
1385 baseInfo.offscreenPattern = offscreenPattern_;
1386 baseInfo.isOffscreen = isOffscreen_;
1387
1388 if (info[0]->IsString()) {
1389 JSViewAbstract::ParseJsString(info[0], path);
1390 jsonData = CanvasRendererModel::GetInstance()->GetJsonData(baseInfo, path);
1391 auto returnValue = JSVal(ToJSValue(jsonData));
1392 auto returnPtr = JSRef<JSVal>::Make(returnValue);
1393 info.SetReturnValue(returnPtr);
1394 }
1395 }
1396
JsToDataUrl(const JSCallbackInfo & info)1397 void JSCanvasRenderer::JsToDataUrl(const JSCallbackInfo& info)
1398 {
1399 ContainerScope scope(instanceId_);
1400 std::string dataUrl = "";
1401 std::string result = "";
1402 double quality = DEFAULT_QUALITY;
1403 if (info[0]->IsString()) {
1404 JSViewAbstract::ParseJsString(info[0], dataUrl);
1405 }
1406 if (info.Length() > 1 && info[1]->IsNumber()) {
1407 JSViewAbstract::ParseJsDouble(info[1], quality);
1408 }
1409
1410 BaseInfo baseInfo;
1411 baseInfo.canvasPattern = canvasPattern_;
1412 baseInfo.offscreenPattern = offscreenPattern_;
1413 baseInfo.isOffscreen = isOffscreen_;
1414
1415 result = CanvasRendererModel::GetInstance()->ToDataURL(baseInfo, dataUrl, quality);
1416
1417 auto returnValue = JSVal(ToJSValue(result));
1418 auto returnPtr = JSRef<JSVal>::Make(returnValue);
1419 info.SetReturnValue(returnPtr);
1420 }
1421
JsSetLineCap(const JSCallbackInfo & info)1422 void JSCanvasRenderer::JsSetLineCap(const JSCallbackInfo& info)
1423 {
1424 ContainerScope scope(instanceId_);
1425 if (info[0]->IsString()) {
1426 std::string capStr = "";
1427 JSViewAbstract::ParseJsString(info[0], capStr);
1428 static const LinearMapNode<LineCapStyle> lineCapTable[] = {
1429 { "butt", LineCapStyle::BUTT },
1430 { "round", LineCapStyle::ROUND },
1431 { "square", LineCapStyle::SQUARE },
1432 };
1433 auto lineCap = ConvertStrToEnum(capStr.c_str(), lineCapTable, ArraySize(lineCapTable), LineCapStyle::BUTT);
1434
1435 BaseInfo baseInfo;
1436 baseInfo.canvasPattern = canvasPattern_;
1437 baseInfo.offscreenPattern = offscreenPattern_;
1438 baseInfo.isOffscreen = isOffscreen_;
1439
1440 CanvasRendererModel::GetInstance()->SetLineCap(baseInfo, lineCap);
1441 }
1442 }
1443
JsSetLineJoin(const JSCallbackInfo & info)1444 void JSCanvasRenderer::JsSetLineJoin(const JSCallbackInfo& info)
1445 {
1446 ContainerScope scope(instanceId_);
1447 if (info[0]->IsString()) {
1448 std::string joinStr = "";
1449 JSViewAbstract::ParseJsString(info[0], joinStr);
1450 static const LinearMapNode<LineJoinStyle> lineJoinTable[3] = {
1451 { "bevel", LineJoinStyle::BEVEL },
1452 { "miter", LineJoinStyle::MITER },
1453 { "round", LineJoinStyle::ROUND },
1454 };
1455 auto lineJoin = ConvertStrToEnum(
1456 joinStr.c_str(), lineJoinTable, ArraySize(lineJoinTable), LineJoinStyle::MITER);
1457
1458 BaseInfo baseInfo;
1459 baseInfo.canvasPattern = canvasPattern_;
1460 baseInfo.offscreenPattern = offscreenPattern_;
1461 baseInfo.isOffscreen = isOffscreen_;
1462
1463 CanvasRendererModel::GetInstance()->SetLineJoin(baseInfo, lineJoin);
1464 }
1465 }
1466
JsSetMiterLimit(const JSCallbackInfo & info)1467 void JSCanvasRenderer::JsSetMiterLimit(const JSCallbackInfo& info)
1468 {
1469 ContainerScope scope(instanceId_);
1470 if (info[0]->IsNumber()) {
1471 double limit = 0.0;
1472 JSViewAbstract::ParseJsDouble(info[0], limit);
1473
1474 BaseInfo baseInfo;
1475 baseInfo.canvasPattern = canvasPattern_;
1476 baseInfo.offscreenPattern = offscreenPattern_;
1477 baseInfo.isOffscreen = isOffscreen_;
1478
1479 CanvasRendererModel::GetInstance()->SetMiterLimit(baseInfo, limit);
1480 }
1481 }
1482
JsSetLineWidth(const JSCallbackInfo & info)1483 void JSCanvasRenderer::JsSetLineWidth(const JSCallbackInfo& info)
1484 {
1485 ContainerScope scope(instanceId_);
1486 if (info[0]->IsNumber()) {
1487 double lineWidth = 0.0;
1488 JSViewAbstract::ParseJsDouble(info[0], lineWidth);
1489 lineWidth = PipelineBase::Vp2PxWithCurrentDensity(lineWidth);
1490
1491 BaseInfo baseInfo;
1492 baseInfo.canvasPattern = canvasPattern_;
1493 baseInfo.offscreenPattern = offscreenPattern_;
1494 baseInfo.isOffscreen = isOffscreen_;
1495
1496 CanvasRendererModel::GetInstance()->SetLineWidth(baseInfo, lineWidth);
1497 }
1498 }
1499
JsSetGlobalAlpha(const JSCallbackInfo & info)1500 void JSCanvasRenderer::JsSetGlobalAlpha(const JSCallbackInfo& info)
1501 {
1502 ContainerScope scope(instanceId_);
1503 if (info[0]->IsNumber()) {
1504 double alpha = 0.0;
1505 JSViewAbstract::ParseJsDouble(info[0], alpha);
1506
1507 BaseInfo baseInfo;
1508 baseInfo.canvasPattern = canvasPattern_;
1509 baseInfo.offscreenPattern = offscreenPattern_;
1510 baseInfo.isOffscreen = isOffscreen_;
1511
1512 CanvasRendererModel::GetInstance()->SetGlobalAlpha(baseInfo, alpha);
1513 }
1514 }
1515
JsSetGlobalCompositeOperation(const JSCallbackInfo & info)1516 void JSCanvasRenderer::JsSetGlobalCompositeOperation(const JSCallbackInfo& info)
1517 {
1518 ContainerScope scope(instanceId_);
1519 if (info[0]->IsString()) {
1520 std::string compositeStr = "";
1521 JSViewAbstract::ParseJsString(info[0], compositeStr);
1522
1523 static const LinearMapNode<CompositeOperation> compositeOperationTable[] = {
1524 { "copy", CompositeOperation::COPY },
1525 { "destination-atop", CompositeOperation::DESTINATION_ATOP },
1526 { "destination-in", CompositeOperation::DESTINATION_IN },
1527 { "destination-out", CompositeOperation::DESTINATION_OUT },
1528 { "destination-over", CompositeOperation::DESTINATION_OVER },
1529 { "lighter", CompositeOperation::LIGHTER },
1530 { "source-atop", CompositeOperation::SOURCE_ATOP },
1531
1532 { "source-in", CompositeOperation::SOURCE_IN },
1533 { "source-out", CompositeOperation::SOURCE_OUT },
1534 { "source-over", CompositeOperation::SOURCE_OVER },
1535 { "xor", CompositeOperation::XOR },
1536 };
1537 auto type = ConvertStrToEnum(
1538 compositeStr.c_str(), compositeOperationTable,
1539 ArraySize(compositeOperationTable), CompositeOperation::SOURCE_OVER);
1540
1541 BaseInfo baseInfo;
1542 baseInfo.canvasPattern = canvasPattern_;
1543 baseInfo.offscreenPattern = offscreenPattern_;
1544 baseInfo.isOffscreen = isOffscreen_;
1545
1546 CanvasRendererModel::GetInstance()->SetCompositeType(baseInfo, type);
1547 }
1548 }
1549
JsSetLineDashOffset(const JSCallbackInfo & info)1550 void JSCanvasRenderer::JsSetLineDashOffset(const JSCallbackInfo& info)
1551 {
1552 ContainerScope scope(instanceId_);
1553 if (info[0]->IsNumber()) {
1554 double lineDashOffset = 0.0;
1555 JSViewAbstract::ParseJsDouble(info[0], lineDashOffset);
1556 lineDashOffset = PipelineBase::Vp2PxWithCurrentDensity(lineDashOffset);
1557
1558 BaseInfo baseInfo;
1559 baseInfo.canvasPattern = canvasPattern_;
1560 baseInfo.offscreenPattern = offscreenPattern_;
1561 baseInfo.isOffscreen = isOffscreen_;
1562
1563 CanvasRendererModel::GetInstance()->SetLineDashOffset(baseInfo, lineDashOffset);
1564 }
1565 }
1566
JsSetShadowBlur(const JSCallbackInfo & info)1567 void JSCanvasRenderer::JsSetShadowBlur(const JSCallbackInfo& info)
1568 {
1569 ContainerScope scope(instanceId_);
1570 if (info[0]->IsNumber()) {
1571 double blur = 0.0;
1572 JSViewAbstract::ParseJsDouble(info[0], blur);
1573
1574 BaseInfo baseInfo;
1575 baseInfo.canvasPattern = canvasPattern_;
1576 baseInfo.offscreenPattern = offscreenPattern_;
1577 baseInfo.isOffscreen = isOffscreen_;
1578
1579 CanvasRendererModel::GetInstance()->SetShadowBlur(baseInfo, blur);
1580 }
1581 }
1582
JsSetShadowColor(const JSCallbackInfo & info)1583 void JSCanvasRenderer::JsSetShadowColor(const JSCallbackInfo& info)
1584 {
1585 ContainerScope scope(instanceId_);
1586 if (info[0]->IsString()) {
1587 std::string colorStr = "";
1588 JSViewAbstract::ParseJsString(info[0], colorStr);
1589 auto color = Color::FromString(colorStr);
1590
1591 BaseInfo baseInfo;
1592 baseInfo.canvasPattern = canvasPattern_;
1593 baseInfo.offscreenPattern = offscreenPattern_;
1594 baseInfo.isOffscreen = isOffscreen_;
1595
1596 CanvasRendererModel::GetInstance()->SetShadowColor(baseInfo, color);
1597 }
1598 }
1599
JsSetShadowOffsetX(const JSCallbackInfo & info)1600 void JSCanvasRenderer::JsSetShadowOffsetX(const JSCallbackInfo& info)
1601 {
1602 ContainerScope scope(instanceId_);
1603 if (info[0]->IsNumber()) {
1604 double offsetX = 0.0;
1605 JSViewAbstract::ParseJsDouble(info[0], offsetX);
1606 offsetX = PipelineBase::Vp2PxWithCurrentDensity(offsetX);
1607
1608 BaseInfo baseInfo;
1609 baseInfo.canvasPattern = canvasPattern_;
1610 baseInfo.offscreenPattern = offscreenPattern_;
1611 baseInfo.isOffscreen = isOffscreen_;
1612
1613 CanvasRendererModel::GetInstance()->SetShadowOffsetX(baseInfo, offsetX);
1614 }
1615 }
1616
JsSetShadowOffsetY(const JSCallbackInfo & info)1617 void JSCanvasRenderer::JsSetShadowOffsetY(const JSCallbackInfo& info)
1618 {
1619 ContainerScope scope(instanceId_);
1620 if (info[0]->IsNumber()) {
1621 double offsetY = 0.0;
1622 JSViewAbstract::ParseJsDouble(info[0], offsetY);
1623 offsetY = PipelineBase::Vp2PxWithCurrentDensity(offsetY);
1624
1625 BaseInfo baseInfo;
1626 baseInfo.canvasPattern = canvasPattern_;
1627 baseInfo.offscreenPattern = offscreenPattern_;
1628 baseInfo.isOffscreen = isOffscreen_;
1629
1630 CanvasRendererModel::GetInstance()->SetShadowOffsetY(baseInfo, offsetY);
1631 }
1632 }
1633
JsSetImageSmoothingEnabled(const JSCallbackInfo & info)1634 void JSCanvasRenderer::JsSetImageSmoothingEnabled(const JSCallbackInfo& info)
1635 {
1636 ContainerScope scope(instanceId_);
1637 if (info.Length() < 1) {
1638 return;
1639 }
1640
1641 bool enabled = false;
1642 if (JSViewAbstract::ParseJsBool(info[0], enabled)) {
1643 BaseInfo baseInfo;
1644 baseInfo.canvasPattern = canvasPattern_;
1645 baseInfo.offscreenPattern = offscreenPattern_;
1646 baseInfo.isOffscreen = isOffscreen_;
1647
1648 CanvasRendererModel::GetInstance()->SetSmoothingEnabled(baseInfo, enabled);
1649 }
1650 }
1651
JsSetImageSmoothingQuality(const JSCallbackInfo & info)1652 void JSCanvasRenderer::JsSetImageSmoothingQuality(const JSCallbackInfo& info)
1653 {
1654 ContainerScope scope(instanceId_);
1655 if (info.Length() < 1) {
1656 return;
1657 }
1658
1659 std::string quality = "";
1660 if (JSViewAbstract::ParseJsString(info[0], quality)) {
1661 if (QUALITY_TYPE.find(quality) == QUALITY_TYPE.end()) {
1662 return;
1663 }
1664
1665 BaseInfo baseInfo;
1666 baseInfo.canvasPattern = canvasPattern_;
1667 baseInfo.offscreenPattern = offscreenPattern_;
1668 baseInfo.isOffscreen = isOffscreen_;
1669
1670 CanvasRendererModel::GetInstance()->SetSmoothingQuality(baseInfo, quality);
1671 }
1672 }
1673
JsMoveTo(const JSCallbackInfo & info)1674 void JSCanvasRenderer::JsMoveTo(const JSCallbackInfo& info)
1675 {
1676 ContainerScope scope(instanceId_);
1677 if (info.Length() < 1) {
1678 return;
1679 }
1680
1681 if (info[0]->IsNumber() && info[1]->IsNumber()) {
1682 double x = 0.0;
1683 double y = 0.0;
1684 JSViewAbstract::ParseJsDouble(info[0], x);
1685 JSViewAbstract::ParseJsDouble(info[1], y);
1686 x = PipelineBase::Vp2PxWithCurrentDensity(x);
1687 y = PipelineBase::Vp2PxWithCurrentDensity(y);
1688
1689 BaseInfo baseInfo;
1690 baseInfo.canvasPattern = canvasPattern_;
1691 baseInfo.offscreenPattern = offscreenPattern_;
1692 baseInfo.isOffscreen = isOffscreen_;
1693
1694 CanvasRendererModel::GetInstance()->MoveTo(baseInfo, x, y);
1695 }
1696 }
1697
JsLineTo(const JSCallbackInfo & info)1698 void JSCanvasRenderer::JsLineTo(const JSCallbackInfo& info)
1699 {
1700 ContainerScope scope(instanceId_);
1701 if (info.Length() < 1) {
1702 return;
1703 }
1704
1705 if (info[0]->IsNumber() && info[1]->IsNumber()) {
1706 double x = 0.0;
1707 double y = 0.0;
1708 JSViewAbstract::ParseJsDouble(info[0], x);
1709 JSViewAbstract::ParseJsDouble(info[1], y);
1710 x = PipelineBase::Vp2PxWithCurrentDensity(x);
1711 y = PipelineBase::Vp2PxWithCurrentDensity(y);
1712
1713 BaseInfo baseInfo;
1714 baseInfo.canvasPattern = canvasPattern_;
1715 baseInfo.offscreenPattern = offscreenPattern_;
1716 baseInfo.isOffscreen = isOffscreen_;
1717
1718 CanvasRendererModel::GetInstance()->LineTo(baseInfo, x, y);
1719 }
1720 }
1721
JsBezierCurveTo(const JSCallbackInfo & info)1722 void JSCanvasRenderer::JsBezierCurveTo(const JSCallbackInfo& info)
1723 {
1724 ContainerScope scope(instanceId_);
1725 if (info.Length() < 1) {
1726 return;
1727 }
1728
1729 if (info[0]->IsNumber() && info[1]->IsNumber() && info[2]->IsNumber() && info[3]->IsNumber()
1730 && info[4]->IsNumber() && info[5]->IsNumber()) {
1731 BezierCurveParam param;
1732 JSViewAbstract::ParseJsDouble(info[0], param.cp1x);
1733 JSViewAbstract::ParseJsDouble(info[1], param.cp1y);
1734 JSViewAbstract::ParseJsDouble(info[2], param.cp2x);
1735 JSViewAbstract::ParseJsDouble(info[3], param.cp2y);
1736 JSViewAbstract::ParseJsDouble(info[4], param.x);
1737 JSViewAbstract::ParseJsDouble(info[5], param.y);
1738 param.cp1x = PipelineBase::Vp2PxWithCurrentDensity(param.cp1x);
1739 param.cp1y = PipelineBase::Vp2PxWithCurrentDensity(param.cp1y);
1740 param.cp2x = PipelineBase::Vp2PxWithCurrentDensity(param.cp2x);
1741 param.cp2y = PipelineBase::Vp2PxWithCurrentDensity(param.cp2y);
1742 param.x = PipelineBase::Vp2PxWithCurrentDensity(param.x);
1743 param.y = PipelineBase::Vp2PxWithCurrentDensity(param.y);
1744
1745 BaseInfo baseInfo;
1746 baseInfo.canvasPattern = canvasPattern_;
1747 baseInfo.offscreenPattern = offscreenPattern_;
1748 baseInfo.isOffscreen = isOffscreen_;
1749
1750 CanvasRendererModel::GetInstance()->BezierCurveTo(baseInfo, param);
1751 }
1752 }
1753
JsQuadraticCurveTo(const JSCallbackInfo & info)1754 void JSCanvasRenderer::JsQuadraticCurveTo(const JSCallbackInfo& info)
1755 {
1756 ContainerScope scope(instanceId_);
1757 if (info.Length() < 1) {
1758 return;
1759 }
1760
1761 if (info[0]->IsNumber() && info[1]->IsNumber() && info[2]->IsNumber() && info[3]->IsNumber()) {
1762 QuadraticCurveParam param;
1763 JSViewAbstract::ParseJsDouble(info[0], param.cpx);
1764 JSViewAbstract::ParseJsDouble(info[1], param.cpy);
1765 JSViewAbstract::ParseJsDouble(info[2], param.x);
1766 JSViewAbstract::ParseJsDouble(info[3], param.y);
1767 param.cpx = PipelineBase::Vp2PxWithCurrentDensity(param.cpx);
1768 param.cpy = PipelineBase::Vp2PxWithCurrentDensity(param.cpy);
1769 param.x = PipelineBase::Vp2PxWithCurrentDensity(param.x);
1770 param.y = PipelineBase::Vp2PxWithCurrentDensity(param.y);
1771
1772 BaseInfo baseInfo;
1773 baseInfo.canvasPattern = canvasPattern_;
1774 baseInfo.offscreenPattern = offscreenPattern_;
1775 baseInfo.isOffscreen = isOffscreen_;
1776
1777 CanvasRendererModel::GetInstance()->QuadraticCurveTo(baseInfo, param);
1778 }
1779 }
1780
JsArcTo(const JSCallbackInfo & info)1781 void JSCanvasRenderer::JsArcTo(const JSCallbackInfo& info)
1782 {
1783 ContainerScope scope(instanceId_);
1784 if (info.Length() < 1) {
1785 return;
1786 }
1787
1788 if (info[0]->IsNumber() && info[1]->IsNumber() && info[2]->IsNumber() && info[3]->IsNumber()
1789 && info[4]->IsNumber()) {
1790 ArcToParam param;
1791 JSViewAbstract::ParseJsDouble(info[0], param.x1);
1792 JSViewAbstract::ParseJsDouble(info[1], param.y1);
1793 JSViewAbstract::ParseJsDouble(info[2], param.x2);
1794 JSViewAbstract::ParseJsDouble(info[3], param.y2);
1795 JSViewAbstract::ParseJsDouble(info[4], param.radius);
1796 param.x1 = PipelineBase::Vp2PxWithCurrentDensity(param.x1);
1797 param.y1 = PipelineBase::Vp2PxWithCurrentDensity(param.y1);
1798 param.x2 = PipelineBase::Vp2PxWithCurrentDensity(param.x2);
1799 param.y2 = PipelineBase::Vp2PxWithCurrentDensity(param.y2);
1800 param.radius = PipelineBase::Vp2PxWithCurrentDensity(param.radius);
1801
1802 BaseInfo baseInfo;
1803 baseInfo.canvasPattern = canvasPattern_;
1804 baseInfo.offscreenPattern = offscreenPattern_;
1805 baseInfo.isOffscreen = isOffscreen_;
1806
1807 CanvasRendererModel::GetInstance()->ArcTo(baseInfo, param);
1808 }
1809 }
1810
JsArc(const JSCallbackInfo & info)1811 void JSCanvasRenderer::JsArc(const JSCallbackInfo& info)
1812 {
1813 ContainerScope scope(instanceId_);
1814 if (info.Length() < 1) {
1815 return;
1816 }
1817
1818 if (info[0]->IsNumber() && info[1]->IsNumber() && info[2]->IsNumber() && info[3]->IsNumber()
1819 && info[4]->IsNumber()) {
1820 ArcParam param;
1821 JSViewAbstract::ParseJsDouble(info[0], param.x);
1822 JSViewAbstract::ParseJsDouble(info[1], param.y);
1823 JSViewAbstract::ParseJsDouble(info[2], param.radius);
1824 JSViewAbstract::ParseJsDouble(info[3], param.startAngle);
1825 JSViewAbstract::ParseJsDouble(info[4], param.endAngle);
1826 param.x = PipelineBase::Vp2PxWithCurrentDensity(param.x);
1827 param.y = PipelineBase::Vp2PxWithCurrentDensity(param.y);
1828 param.radius = PipelineBase::Vp2PxWithCurrentDensity(param.radius);
1829
1830 if (info.Length() == 6) {
1831 JSViewAbstract::ParseJsBool(info[5], param.anticlockwise);
1832 }
1833
1834 BaseInfo baseInfo;
1835 baseInfo.canvasPattern = canvasPattern_;
1836 baseInfo.offscreenPattern = offscreenPattern_;
1837 baseInfo.isOffscreen = isOffscreen_;
1838
1839 CanvasRendererModel::GetInstance()->Arc(baseInfo, param);
1840 }
1841 }
1842
JsEllipse(const JSCallbackInfo & info)1843 void JSCanvasRenderer::JsEllipse(const JSCallbackInfo& info)
1844 {
1845 ContainerScope scope(instanceId_);
1846 if (info.Length() < 1) {
1847 return;
1848 }
1849
1850 if (info[0]->IsNumber() && info[1]->IsNumber() && info[2]->IsNumber() && info[3]->IsNumber()
1851 && info[4]->IsNumber() && info[5]->IsNumber() && info[6]->IsNumber()) {
1852 EllipseParam param;
1853 JSViewAbstract::ParseJsDouble(info[0], param.x);
1854 JSViewAbstract::ParseJsDouble(info[1], param.y);
1855 JSViewAbstract::ParseJsDouble(info[2], param.radiusX);
1856 JSViewAbstract::ParseJsDouble(info[3], param.radiusY);
1857 JSViewAbstract::ParseJsDouble(info[4], param.rotation);
1858 JSViewAbstract::ParseJsDouble(info[5], param.startAngle);
1859 JSViewAbstract::ParseJsDouble(info[6], param.endAngle);
1860 param.x = PipelineBase::Vp2PxWithCurrentDensity(param.x);
1861 param.y = PipelineBase::Vp2PxWithCurrentDensity(param.y);
1862 param.radiusX = PipelineBase::Vp2PxWithCurrentDensity(param.radiusX);
1863 param.radiusY = PipelineBase::Vp2PxWithCurrentDensity(param.radiusY);
1864
1865 if (info.Length() == 8) {
1866 JSViewAbstract::ParseJsBool(info[7], param.anticlockwise);
1867 }
1868
1869 BaseInfo baseInfo;
1870 baseInfo.canvasPattern = canvasPattern_;
1871 baseInfo.offscreenPattern = offscreenPattern_;
1872 baseInfo.isOffscreen = isOffscreen_;
1873
1874 CanvasRendererModel::GetInstance()->Ellipse(baseInfo, param);
1875 }
1876 }
1877
JsFill(const JSCallbackInfo & info)1878 void JSCanvasRenderer::JsFill(const JSCallbackInfo& info)
1879 {
1880 ContainerScope scope(instanceId_);
1881 std::string ruleStr = "";
1882 if (info.Length() == 1 && info[0]->IsString()) {
1883 // fill(rule) uses fillRule specified by the application developers
1884 JSViewAbstract::ParseJsString(info[0], ruleStr);
1885 } else if (info.Length() == 2) {
1886 // fill(path, rule) uses fillRule specified by the application developers
1887 JSViewAbstract::ParseJsString(info[1], ruleStr);
1888 }
1889 auto fillRule = CanvasFillRule::NONZERO;
1890 if (ruleStr == "nonzero") {
1891 fillRule = CanvasFillRule::NONZERO;
1892 } else if (ruleStr == "evenodd") {
1893 fillRule = CanvasFillRule::EVENODD;
1894 }
1895
1896 BaseInfo baseInfo;
1897 baseInfo.canvasPattern = canvasPattern_;
1898 baseInfo.offscreenPattern = offscreenPattern_;
1899 baseInfo.isOffscreen = isOffscreen_;
1900
1901 if (info.Length() == 0 ||
1902 (info.Length() == 1 && info[0]->IsString())) {
1903 CanvasRendererModel::GetInstance()->SetFillRuleForPath(baseInfo, fillRule);
1904 } else if (info.Length() == 2 ||
1905 (info.Length() == 1 && info[0]->IsObject())) {
1906 JSPath2D* jsCanvasPath = JSRef<JSObject>::Cast(info[0])->Unwrap<JSPath2D>();
1907 if (jsCanvasPath == nullptr) {
1908 return;
1909 }
1910 auto path = jsCanvasPath->GetCanvasPath2d();
1911
1912 CanvasRendererModel::GetInstance()->SetFillRuleForPath2D(baseInfo, fillRule, path);
1913 }
1914 }
1915
JsStroke(const JSCallbackInfo & info)1916 void JSCanvasRenderer::JsStroke(const JSCallbackInfo& info)
1917 {
1918 ContainerScope scope(instanceId_);
1919 // stroke always uses non-zero fillRule
1920 auto fillRule = CanvasFillRule::NONZERO;
1921 BaseInfo baseInfo;
1922 baseInfo.canvasPattern = canvasPattern_;
1923 baseInfo.offscreenPattern = offscreenPattern_;
1924 baseInfo.isOffscreen = isOffscreen_;
1925
1926 if (info.Length() == 1) {
1927 JSPath2D* jsCanvasPath = JSRef<JSObject>::Cast(info[0])->Unwrap<JSPath2D>();
1928 if (jsCanvasPath == nullptr) {
1929 return;
1930 }
1931 auto path = jsCanvasPath->GetCanvasPath2d();
1932 CanvasRendererModel::GetInstance()->SetStrokeRuleForPath2D(baseInfo, fillRule, path);
1933 return;
1934 }
1935
1936 CanvasRendererModel::GetInstance()->SetStrokeRuleForPath(baseInfo, fillRule);
1937 }
1938
JsClip(const JSCallbackInfo & info)1939 void JSCanvasRenderer::JsClip(const JSCallbackInfo& info)
1940 {
1941 ContainerScope scope(instanceId_);
1942 std::string ruleStr = "";
1943 if (info.Length() == 1 && info[0]->IsString()) {
1944 // clip(rule) uses fillRule specified by the application developers
1945 JSViewAbstract::ParseJsString(info[0], ruleStr);
1946 } else if (info.Length() == 2) {
1947 // clip(path, rule) uses fillRule specified by the application developers
1948 JSViewAbstract::ParseJsString(info[1], ruleStr);
1949 }
1950 auto fillRule = CanvasFillRule::NONZERO;
1951 if (ruleStr == "nonzero") {
1952 fillRule = CanvasFillRule::NONZERO;
1953 } else if (ruleStr == "evenodd") {
1954 fillRule = CanvasFillRule::EVENODD;
1955 }
1956
1957 BaseInfo baseInfo;
1958 baseInfo.canvasPattern = canvasPattern_;
1959 baseInfo.offscreenPattern = offscreenPattern_;
1960 baseInfo.isOffscreen = isOffscreen_;
1961
1962 if (info.Length() == 0 ||
1963 (info.Length() == 1 && info[0]->IsString())) {
1964 CanvasRendererModel::GetInstance()->SetClipRuleForPath(baseInfo, fillRule);
1965 } else if (info.Length() == 2 ||
1966 (info.Length() == 1 && info[0]->IsObject())) {
1967 JSPath2D* jsCanvasPath = JSRef<JSObject>::Cast(info[0])->Unwrap<JSPath2D>();
1968 if (jsCanvasPath == nullptr) {
1969 return;
1970 }
1971 auto path = jsCanvasPath->GetCanvasPath2d();
1972 CanvasRendererModel::GetInstance()->SetClipRuleForPath2D(baseInfo, fillRule, path);
1973 }
1974 }
1975
JsRect(const JSCallbackInfo & info)1976 void JSCanvasRenderer::JsRect(const JSCallbackInfo& info)
1977 {
1978 ContainerScope scope(instanceId_);
1979 Rect rect = GetJsRectParam(info);
1980
1981 BaseInfo baseInfo;
1982 baseInfo.canvasPattern = canvasPattern_;
1983 baseInfo.offscreenPattern = offscreenPattern_;
1984 baseInfo.isOffscreen = isOffscreen_;
1985
1986 CanvasRendererModel::GetInstance()->AddRect(baseInfo, rect);
1987 }
1988
JsBeginPath(const JSCallbackInfo & info)1989 void JSCanvasRenderer::JsBeginPath(const JSCallbackInfo& info)
1990 {
1991 ContainerScope scope(instanceId_);
1992 if (info.Length() != 0) {
1993 return;
1994 }
1995
1996 BaseInfo baseInfo;
1997 baseInfo.canvasPattern = canvasPattern_;
1998 baseInfo.offscreenPattern = offscreenPattern_;
1999 baseInfo.isOffscreen = isOffscreen_;
2000
2001 CanvasRendererModel::GetInstance()->BeginPath(baseInfo);
2002 }
2003
JsClosePath(const JSCallbackInfo & info)2004 void JSCanvasRenderer::JsClosePath(const JSCallbackInfo& info)
2005 {
2006 ContainerScope scope(instanceId_);
2007 if (info.Length() != 0) {
2008 return;
2009 }
2010
2011 BaseInfo baseInfo;
2012 baseInfo.canvasPattern = canvasPattern_;
2013 baseInfo.offscreenPattern = offscreenPattern_;
2014 baseInfo.isOffscreen = isOffscreen_;
2015
2016 CanvasRendererModel::GetInstance()->ClosePath(baseInfo);
2017 }
2018
JsRestore(const JSCallbackInfo & info)2019 void JSCanvasRenderer::JsRestore(const JSCallbackInfo& info)
2020 {
2021 ContainerScope scope(instanceId_);
2022 if (info.Length() != 0) {
2023 return;
2024 }
2025
2026 BaseInfo baseInfo;
2027 baseInfo.canvasPattern = canvasPattern_;
2028 baseInfo.offscreenPattern = offscreenPattern_;
2029 baseInfo.isOffscreen = isOffscreen_;
2030
2031 CanvasRendererModel::GetInstance()->Restore(baseInfo);
2032 }
2033
JsSave(const JSCallbackInfo & info)2034 void JSCanvasRenderer::JsSave(const JSCallbackInfo& info)
2035 {
2036 ContainerScope scope(instanceId_);
2037 if (info.Length() != 0) {
2038 return;
2039 }
2040
2041 BaseInfo baseInfo;
2042 baseInfo.canvasPattern = canvasPattern_;
2043 baseInfo.offscreenPattern = offscreenPattern_;
2044 baseInfo.isOffscreen = isOffscreen_;
2045
2046 CanvasRendererModel::GetInstance()->CanvasRendererSave(baseInfo);
2047 }
2048
JsRotate(const JSCallbackInfo & info)2049 void JSCanvasRenderer::JsRotate(const JSCallbackInfo& info)
2050 {
2051 ContainerScope scope(instanceId_);
2052 if (info.Length() != 1) {
2053 return;
2054 }
2055 double angle = 0.0;
2056 JSViewAbstract::ParseJsDouble(info[0], angle);
2057
2058 BaseInfo baseInfo;
2059 baseInfo.canvasPattern = canvasPattern_;
2060 baseInfo.offscreenPattern = offscreenPattern_;
2061 baseInfo.isOffscreen = isOffscreen_;
2062
2063 CanvasRendererModel::GetInstance()->CanvasRendererRotate(baseInfo, angle);
2064 }
2065
JsScale(const JSCallbackInfo & info)2066 void JSCanvasRenderer::JsScale(const JSCallbackInfo& info)
2067 {
2068 ContainerScope scope(instanceId_);
2069 if (info.Length() < 1) {
2070 return;
2071 }
2072
2073 if (info[0]->IsNumber() && info[1]->IsNumber()) {
2074 double x = 0.0;
2075 double y = 0.0;
2076 JSViewAbstract::ParseJsDouble(info[0], x);
2077 JSViewAbstract::ParseJsDouble(info[1], y);
2078
2079 BaseInfo baseInfo;
2080 baseInfo.canvasPattern = canvasPattern_;
2081 baseInfo.offscreenPattern = offscreenPattern_;
2082 baseInfo.isOffscreen = isOffscreen_;
2083
2084 CanvasRendererModel::GetInstance()->CanvasRendererScale(baseInfo, x, y);
2085 }
2086 }
2087
JsGetTransform(const JSCallbackInfo & info)2088 void JSCanvasRenderer::JsGetTransform(const JSCallbackInfo& info)
2089 {
2090 ContainerScope scope(instanceId_);
2091 JSRef<JSObject> obj = JSClass<JSMatrix2d>::NewInstance();
2092 obj->SetProperty("__type", "Matrix2D");
2093 if (Container::IsCurrentUseNewPipeline()) {
2094 BaseInfo baseInfo;
2095 baseInfo.canvasPattern = canvasPattern_;
2096 baseInfo.offscreenPattern = offscreenPattern_;
2097 baseInfo.isOffscreen = isOffscreen_;
2098
2099 TransformParam param = CanvasRendererModel::GetInstance()->GetTransform(baseInfo);
2100 auto matrix = Referenced::Claim(obj->Unwrap<JSMatrix2d>());
2101 CHECK_NULL_VOID(matrix);
2102 matrix->SetTransform(param);
2103 }
2104 info.SetReturnValue(obj);
2105 }
2106
JsSetTransform(const JSCallbackInfo & info)2107 void JSCanvasRenderer::JsSetTransform(const JSCallbackInfo& info)
2108 {
2109 ContainerScope scope(instanceId_);
2110 BaseInfo baseInfo;
2111 baseInfo.canvasPattern = canvasPattern_;
2112 baseInfo.offscreenPattern = offscreenPattern_;
2113 baseInfo.isOffscreen = isOffscreen_;
2114
2115 if (info.Length() == 6) {
2116 if (!(info[0]->IsNumber() && info[1]->IsNumber() && info[2]->IsNumber() && info[3]->IsNumber()
2117 && info[4]->IsNumber() && info[5]->IsNumber())) {
2118 return;
2119 }
2120 TransformParam param;
2121 JSViewAbstract::ParseJsDouble(info[0], param.scaleX);
2122 JSViewAbstract::ParseJsDouble(info[1], param.skewY);
2123 JSViewAbstract::ParseJsDouble(info[2], param.skewX);
2124 JSViewAbstract::ParseJsDouble(info[3], param.scaleY);
2125 JSViewAbstract::ParseJsDouble(info[4], param.translateX);
2126 JSViewAbstract::ParseJsDouble(info[5], param.translateY);
2127 param.translateX = PipelineBase::Vp2PxWithCurrentDensity(param.translateX);
2128 param.translateY = PipelineBase::Vp2PxWithCurrentDensity(param.translateY);
2129
2130 CanvasRendererModel::GetInstance()->SetTransform(baseInfo, param, true);
2131 return;
2132 } else if (info.Length() == 1) {
2133 if (!info[0]->IsObject()) {
2134 return;
2135 }
2136
2137 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
2138 auto* jsMatrix2d = JSRef<JSObject>::Cast(info[0])->Unwrap<JSMatrix2d>();
2139 CHECK_NULL_VOID(jsMatrix2d);
2140 TransformParam param = jsMatrix2d->GetTransform();
2141 CanvasRendererModel::GetInstance()->SetTransform(baseInfo, param, false);
2142 return;
2143 }
2144
2145 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
2146 TransformParam param = JSMatrix2d::GetTransformInfo(jsObj);
2147 CanvasRendererModel::GetInstance()->SetTransform(baseInfo, param, false);
2148 }
2149 }
2150
JsResetTransform(const JSCallbackInfo & info)2151 void JSCanvasRenderer::JsResetTransform(const JSCallbackInfo& info)
2152 {
2153 ContainerScope scope(instanceId_);
2154 if (info.Length() != 0) {
2155 return;
2156 }
2157
2158 BaseInfo baseInfo;
2159 baseInfo.canvasPattern = canvasPattern_;
2160 baseInfo.offscreenPattern = offscreenPattern_;
2161 baseInfo.isOffscreen = isOffscreen_;
2162
2163 CanvasRendererModel::GetInstance()->ResetTransform(baseInfo);
2164 }
2165
JsTransform(const JSCallbackInfo & info)2166 void JSCanvasRenderer::JsTransform(const JSCallbackInfo& info)
2167 {
2168 ContainerScope scope(instanceId_);
2169 if (info.Length() < 6) {
2170 return;
2171 }
2172
2173 if (info[0]->IsNumber() && info[1]->IsNumber() && info[2]->IsNumber() && info[3]->IsNumber() &&
2174 info[4]->IsNumber() && info[5]->IsNumber()) {
2175 TransformParam param;
2176 JSViewAbstract::ParseJsDouble(info[0], param.scaleX);
2177 JSViewAbstract::ParseJsDouble(info[1], param.skewX);
2178 JSViewAbstract::ParseJsDouble(info[2], param.skewY);
2179 JSViewAbstract::ParseJsDouble(info[3], param.scaleY);
2180 JSViewAbstract::ParseJsDouble(info[4], param.translateX);
2181 JSViewAbstract::ParseJsDouble(info[5], param.translateY);
2182 param.translateX = PipelineBase::Vp2PxWithCurrentDensity(param.translateX);
2183 param.translateY = PipelineBase::Vp2PxWithCurrentDensity(param.translateY);
2184
2185 BaseInfo baseInfo;
2186 baseInfo.canvasPattern = canvasPattern_;
2187 baseInfo.offscreenPattern = offscreenPattern_;
2188 baseInfo.isOffscreen = isOffscreen_;
2189
2190 CanvasRendererModel::GetInstance()->Transform(baseInfo, param);
2191 }
2192 }
2193
JsTranslate(const JSCallbackInfo & info)2194 void JSCanvasRenderer::JsTranslate(const JSCallbackInfo& info)
2195 {
2196 ContainerScope scope(instanceId_);
2197 if (info.Length() < 2) {
2198 return;
2199 }
2200
2201 if (info[0]->IsNumber() && info[1]->IsNumber()) {
2202 double x = 0.0;
2203 double y = 0.0;
2204 JSViewAbstract::ParseJsDouble(info[0], x);
2205 JSViewAbstract::ParseJsDouble(info[1], y);
2206 x = PipelineBase::Vp2PxWithCurrentDensity(x);
2207 y = PipelineBase::Vp2PxWithCurrentDensity(y);
2208
2209 BaseInfo baseInfo;
2210 baseInfo.canvasPattern = canvasPattern_;
2211 baseInfo.offscreenPattern = offscreenPattern_;
2212 baseInfo.isOffscreen = isOffscreen_;
2213
2214 CanvasRendererModel::GetInstance()->Translate(baseInfo, x, y);
2215 }
2216 }
2217
JsSetLineDash(const JSCallbackInfo & info)2218 void JSCanvasRenderer::JsSetLineDash(const JSCallbackInfo& info)
2219 {
2220 ContainerScope scope(instanceId_);
2221 std::vector<double> lineDash;
2222 ParseJsDoubleArray(info[0], lineDash);
2223 if (lineDash.size() % 2 != 0) {
2224 lineDash.insert(lineDash.end(), lineDash.begin(), lineDash.end());
2225 }
2226 if (!Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
2227 for (auto i = 0U; i < lineDash.size(); i++) {
2228 lineDash[i] = PipelineBase::Vp2PxWithCurrentDensity(lineDash[i]);
2229 }
2230 }
2231
2232 BaseInfo baseInfo;
2233 baseInfo.canvasPattern = canvasPattern_;
2234 baseInfo.offscreenPattern = offscreenPattern_;
2235 baseInfo.isOffscreen = isOffscreen_;
2236
2237 CanvasRendererModel::GetInstance()->SetLineDash(baseInfo, lineDash);
2238 }
2239
GetPattern(unsigned int id)2240 Pattern JSCanvasRenderer::GetPattern(unsigned int id)
2241 {
2242 if (id < 0 || id >= pattern_.size()) {
2243 return Pattern();
2244 }
2245 return *(pattern_[id].get());
2246 }
2247
GetPatternNG(int32_t id)2248 std::weak_ptr<Ace::Pattern> JSCanvasRenderer::GetPatternNG(int32_t id)
2249 {
2250 if (id < 0) {
2251 return std::shared_ptr<Pattern>();
2252 }
2253 return pattern_[id];
2254 }
2255
GetPatternPtr(int32_t id)2256 std::shared_ptr<Pattern> JSCanvasRenderer::GetPatternPtr(int32_t id)
2257 {
2258 if (id < 0 || id >= static_cast<int32_t>(pattern_.size())) {
2259 return std::shared_ptr<Pattern>();
2260 }
2261 return pattern_[id];
2262 }
2263
SetTransform(unsigned int id,const TransformParam & transform)2264 void JSCanvasRenderer::SetTransform(unsigned int id, const TransformParam& transform)
2265 {
2266 if (id >= 0 && id <= patternCount_) {
2267 pattern_[id]->SetScaleX(transform.scaleX);
2268 pattern_[id]->SetScaleY(transform.scaleY);
2269 pattern_[id]->SetSkewX(transform.skewX);
2270 pattern_[id]->SetSkewY(transform.skewY);
2271 pattern_[id]->SetTranslateX(transform.translateX);
2272 pattern_[id]->SetTranslateY(transform.translateY);
2273 }
2274 }
2275
JsSetTextAlign(const JSCallbackInfo & info)2276 void JSCanvasRenderer::JsSetTextAlign(const JSCallbackInfo& info)
2277 {
2278 ContainerScope scope(instanceId_);
2279 if (info.Length() < 1) {
2280 return;
2281 }
2282
2283 BaseInfo baseInfo;
2284 baseInfo.canvasPattern = canvasPattern_;
2285 baseInfo.offscreenPattern = offscreenPattern_;
2286 baseInfo.isOffscreen = isOffscreen_;
2287
2288 std::string value = "";
2289 if (info[0]->IsString()) {
2290 JSViewAbstract::ParseJsString(info[0], value);
2291 auto align = ConvertStrToTextAlign(value);
2292 paintState_.SetTextAlign(align);
2293 CanvasRendererModel::GetInstance()->SetTextAlign(baseInfo, align);
2294 }
2295 }
2296
JsSetTextBaseline(const JSCallbackInfo & info)2297 void JSCanvasRenderer::JsSetTextBaseline(const JSCallbackInfo& info)
2298 {
2299 ContainerScope scope(instanceId_);
2300 if (info.Length() < 1) {
2301 return;
2302 }
2303
2304 std::string textBaseline;
2305 if (info[0]->IsString()) {
2306 JSViewAbstract::ParseJsString(info[0], textBaseline);
2307 auto baseline = ConvertStrToEnum(
2308 textBaseline.c_str(), BASELINE_TABLE, ArraySize(BASELINE_TABLE), TextBaseline::ALPHABETIC);
2309 style_.SetTextBaseline(baseline);
2310
2311 BaseInfo baseInfo;
2312 baseInfo.canvasPattern = canvasPattern_;
2313 baseInfo.offscreenPattern = offscreenPattern_;
2314 baseInfo.isOffscreen = isOffscreen_;
2315
2316 CanvasRendererModel::GetInstance()->SetTextBaseline(baseInfo, baseline);
2317 }
2318 }
2319
JsMeasureText(const JSCallbackInfo & info)2320 void JSCanvasRenderer::JsMeasureText(const JSCallbackInfo& info)
2321 {
2322 ContainerScope scope(instanceId_);
2323 std::string text = "";
2324 paintState_.SetTextStyle(style_);
2325 double width = 0.0;
2326 double height = 0.0;
2327 TextMetrics textMetrics;
2328 if (info[0]->IsString()) {
2329 JSViewAbstract::ParseJsString(info[0], text);
2330
2331 BaseInfo baseInfo;
2332 baseInfo.canvasPattern = canvasPattern_;
2333 baseInfo.offscreenPattern = offscreenPattern_;
2334 baseInfo.isOffscreen = isOffscreen_;
2335 baseInfo.paintState = paintState_;
2336
2337 width = CanvasRendererModel::GetInstance()->GetMeasureTextWidth(baseInfo, text);
2338 height = CanvasRendererModel::GetInstance()->GetMeasureTextHeight(baseInfo, text);
2339 textMetrics = CanvasRendererModel::GetInstance()->GetMeasureTextMetrics(baseInfo, text);
2340
2341 auto retObj = JSRef<JSObject>::New();
2342 retObj->SetProperty("width",
2343 PipelineBase::Px2VpWithCurrentDensity(width));
2344 retObj->SetProperty("height",
2345 PipelineBase::Px2VpWithCurrentDensity(height));
2346 retObj->SetProperty("actualBoundingBoxLeft",
2347 PipelineBase::Px2VpWithCurrentDensity(textMetrics.actualBoundingBoxLeft));
2348 retObj->SetProperty("actualBoundingBoxRight",
2349 PipelineBase::Px2VpWithCurrentDensity(textMetrics.actualBoundingBoxRight));
2350 retObj->SetProperty("actualBoundingBoxAscent",
2351 PipelineBase::Px2VpWithCurrentDensity(textMetrics.actualBoundingBoxAscent));
2352 retObj->SetProperty("actualBoundingBoxDescent",
2353 PipelineBase::Px2VpWithCurrentDensity(textMetrics.actualBoundingBoxDescent));
2354 retObj->SetProperty("hangingBaseline",
2355 PipelineBase::Px2VpWithCurrentDensity(textMetrics.hangingBaseline));
2356 retObj->SetProperty("alphabeticBaseline",
2357 PipelineBase::Px2VpWithCurrentDensity(textMetrics.alphabeticBaseline));
2358 retObj->SetProperty("ideographicBaseline",
2359 PipelineBase::Px2VpWithCurrentDensity(textMetrics.ideographicBaseline));
2360 retObj->SetProperty("emHeightAscent",
2361 PipelineBase::Px2VpWithCurrentDensity(textMetrics.emHeightAscent));
2362 retObj->SetProperty("emHeightDescent",
2363 PipelineBase::Px2VpWithCurrentDensity(textMetrics.emHeightDescent));
2364 retObj->SetProperty("fontBoundingBoxAscent",
2365 PipelineBase::Px2VpWithCurrentDensity(textMetrics.fontBoundingBoxAscent));
2366 retObj->SetProperty("fontBoundingBoxDescent",
2367 PipelineBase::Px2VpWithCurrentDensity(textMetrics.fontBoundingBoxDescent));
2368 info.SetReturnValue(retObj);
2369 }
2370 }
2371
JsFillRect(const JSCallbackInfo & info)2372 void JSCanvasRenderer::JsFillRect(const JSCallbackInfo& info)
2373 {
2374 ContainerScope scope(instanceId_);
2375 if (info.Length() < 4) {
2376 return;
2377 }
2378
2379 if (info[0]->IsNumber() && info[1]->IsNumber() && info[2]->IsNumber() && info[3]->IsNumber()) {
2380 double x = 0.0;
2381 double y = 0.0;
2382 double width = 0.0;
2383 double height = 0.0;
2384 JSViewAbstract::ParseJsDouble(info[0], x);
2385 JSViewAbstract::ParseJsDouble(info[1], y);
2386 JSViewAbstract::ParseJsDouble(info[2], width);
2387 JSViewAbstract::ParseJsDouble(info[3], height);
2388 x = PipelineBase::Vp2PxWithCurrentDensity(x);
2389 y = PipelineBase::Vp2PxWithCurrentDensity(y);
2390 width = PipelineBase::Vp2PxWithCurrentDensity(width);
2391 height = PipelineBase::Vp2PxWithCurrentDensity(height);
2392
2393 Rect rect = Rect(x, y, width, height);
2394
2395 BaseInfo baseInfo;
2396 baseInfo.canvasPattern = canvasPattern_;
2397 baseInfo.offscreenPattern = offscreenPattern_;
2398 baseInfo.isOffscreen = isOffscreen_;
2399
2400 CanvasRendererModel::GetInstance()->FillRect(baseInfo, rect);
2401 }
2402 }
2403
JsStrokeRect(const JSCallbackInfo & info)2404 void JSCanvasRenderer::JsStrokeRect(const JSCallbackInfo& info)
2405 {
2406 ContainerScope scope(instanceId_);
2407 if (info.Length() < 4) {
2408 return;
2409 }
2410
2411 if (info[0]->IsNumber() && info[1]->IsNumber() && info[2]->IsNumber() && info[3]->IsNumber()) {
2412 double x = 0.0;
2413 double y = 0.0;
2414 double width = 0.0;
2415 double height = 0.0;
2416 JSViewAbstract::ParseJsDouble(info[0], x);
2417 JSViewAbstract::ParseJsDouble(info[1], y);
2418 JSViewAbstract::ParseJsDouble(info[2], width);
2419 JSViewAbstract::ParseJsDouble(info[3], height);
2420 x = PipelineBase::Vp2PxWithCurrentDensity(x);
2421 y = PipelineBase::Vp2PxWithCurrentDensity(y);
2422 width = PipelineBase::Vp2PxWithCurrentDensity(width);
2423 height = PipelineBase::Vp2PxWithCurrentDensity(height);
2424
2425 Rect rect = Rect(x, y, width, height);
2426
2427 BaseInfo baseInfo;
2428 baseInfo.canvasPattern = canvasPattern_;
2429 baseInfo.offscreenPattern = offscreenPattern_;
2430 baseInfo.isOffscreen = isOffscreen_;
2431
2432 CanvasRendererModel::GetInstance()->StrokeRect(baseInfo, rect);
2433 }
2434 }
2435
JsClearRect(const JSCallbackInfo & info)2436 void JSCanvasRenderer::JsClearRect(const JSCallbackInfo& info)
2437 {
2438 ContainerScope scope(instanceId_);
2439 if (info.Length() < 4) {
2440 return;
2441 }
2442
2443 if (info[0]->IsNumber() && info[1]->IsNumber() && info[2]->IsNumber() && info[3]->IsNumber()) {
2444 double x = 0.0;
2445 double y = 0.0;
2446 double width = 0.0;
2447 double height = 0.0;
2448 JSViewAbstract::ParseJsDouble(info[0], x);
2449 JSViewAbstract::ParseJsDouble(info[1], y);
2450 JSViewAbstract::ParseJsDouble(info[2], width);
2451 JSViewAbstract::ParseJsDouble(info[3], height);
2452 x = PipelineBase::Vp2PxWithCurrentDensity(x);
2453 y = PipelineBase::Vp2PxWithCurrentDensity(y);
2454 width = PipelineBase::Vp2PxWithCurrentDensity(width);
2455 height = PipelineBase::Vp2PxWithCurrentDensity(height);
2456
2457 Rect rect = Rect(x, y, width, height);
2458
2459 BaseInfo baseInfo;
2460 baseInfo.canvasPattern = canvasPattern_;
2461 baseInfo.offscreenPattern = offscreenPattern_;
2462 baseInfo.isOffscreen = isOffscreen_;
2463
2464 CanvasRendererModel::GetInstance()->ClearRect(baseInfo, rect);
2465 }
2466 }
2467
JsSaveLayer(const JSCallbackInfo & info)2468 void JSCanvasRenderer::JsSaveLayer(const JSCallbackInfo& info)
2469 {
2470 if (info.Length() != 0) {
2471 return;
2472 }
2473
2474 BaseInfo baseInfo;
2475 baseInfo.canvasPattern = canvasPattern_;
2476 baseInfo.offscreenPattern = offscreenPattern_;
2477 baseInfo.isOffscreen = isOffscreen_;
2478
2479 CanvasRendererModel::GetInstance()->SaveLayer(baseInfo);
2480 }
2481
JsRestoreLayer(const JSCallbackInfo & info)2482 void JSCanvasRenderer::JsRestoreLayer(const JSCallbackInfo& info)
2483 {
2484 if (info.Length() != 0) {
2485 return;
2486 }
2487
2488 BaseInfo baseInfo;
2489 baseInfo.canvasPattern = canvasPattern_;
2490 baseInfo.offscreenPattern = offscreenPattern_;
2491 baseInfo.isOffscreen = isOffscreen_;
2492
2493 CanvasRendererModel::GetInstance()->RestoreLayer(baseInfo);
2494 }
2495
GetDimensionValue(const std::string & str)2496 Dimension JSCanvasRenderer::GetDimensionValue(const std::string& str)
2497 {
2498 Dimension dimension = StringToDimension(str);
2499 if ((dimension.Unit() == DimensionUnit::NONE) || (dimension.Unit() == DimensionUnit::PX)) {
2500 return Dimension(dimension.Value());
2501 }
2502 if (dimension.Unit() == DimensionUnit::VP) {
2503 return Dimension(dimension.Value() * SystemProperties::GetResolution());
2504 }
2505 return Dimension(0.0);
2506 }
2507 } // namespace OHOS::Ace::Framework
2508