• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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