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 "frameworks/bridge/js_frontend/engine/jsi/jsi_canvas_bridge.h"
17 
18 #include "frameworks/bridge/js_frontend/engine/jsi/ark_js_value.h"
19 #include "frameworks/bridge/js_frontend/engine/jsi/jsi_offscreen_canvas_bridge.h"
20 
21 #ifdef PIXEL_MAP_SUPPORTED
22 #include "pixel_map.h"
23 #include "pixel_map_napi.h"
24 #endif
25 
26 namespace OHOS::Ace::Framework {
27 namespace {
28 
29 constexpr char CANVAS_TYPE_WEBGL[] = "webgl";
30 constexpr char CANVAS_TYPE_WEBGL2[] = "webgl2";
31 constexpr char CANVAS_WEBGL_SO[] = "webglnapi";
32 
33 #if !defined(PREVIEW)
CreatePixelMapFromNapiValue(const shared_ptr<JsRuntime> & runtime,shared_ptr<JsValue> jsValue)34 RefPtr<PixelMap> CreatePixelMapFromNapiValue(const shared_ptr<JsRuntime>& runtime, shared_ptr<JsValue> jsValue)
35 {
36     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
37     if (!engine) {
38         LOGE(" engine is null.");
39         return nullptr;
40     }
41 
42     auto nativeEngine = static_cast<ArkNativeEngine*>(engine->GetNativeEngine());
43     if (!nativeEngine) {
44         LOGE("NativeEngine is null");
45         return nullptr;
46     }
47 
48     shared_ptr<ArkJSValue> arkJsValue = std::static_pointer_cast<ArkJSValue>(jsValue);
49     if (!arkJsValue) {
50         LOGE("arkJsValue is null.");
51         return nullptr;
52     }
53     shared_ptr<ArkJSRuntime> arkRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
54     if (!arkRuntime) {
55         LOGE("arkRuntime is null");
56         return nullptr;
57     }
58 
59     JSValueWrapper valueWrapper = arkJsValue->GetValue(arkRuntime);
60     napi_value napiValue = nativeEngine->ValueToNapiValue(valueWrapper);
61 
62     PixelMapNapiEntry pixelMapNapiEntry = JsEngine::GetPixelMapNapiEntry();
63     if (!pixelMapNapiEntry) {
64         LOGE("pixelMapNapiEntry is null");
65         return nullptr;
66     }
67     void* pixmapPtrAddr = pixelMapNapiEntry(
68         reinterpret_cast<napi_env>(nativeEngine), napiValue);
69     if (pixmapPtrAddr == nullptr) {
70         LOGE(" Failed to get pixmap pointer");
71         return nullptr;
72     }
73     return PixelMap::CreatePixelMap(pixmapPtrAddr);
74 }
75 #endif
76 
77 template<typename T>
ConvertStrToEnum(const char * key,const LinearMapNode<T> * map,size_t length,T defaultValue)78 inline T ConvertStrToEnum(const char* key, const LinearMapNode<T>* map, size_t length, T defaultValue)
79 {
80     int64_t index = BinarySearchFindIndex(map, length, key);
81     return index != -1 ? map[index].value : defaultValue;
82 }
83 
84 const LinearMapNode<TextBaseline> BASELINE_TABLE[] = {
85     { "alphabetic", TextBaseline::ALPHABETIC },
86     { "bottom", TextBaseline::BOTTOM },
87     { "hanging", TextBaseline::HANGING },
88     { "ideographic", TextBaseline::IDEOGRAPHIC },
89     { "middle", TextBaseline::MIDDLE },
90     { "top", TextBaseline::TOP },
91 };
92 
93 const std::set<std::string> FONT_WEIGHTS = { "normal", "bold", "lighter", "bolder",
94     "100", "200", "300", "400", "500", "600", "700", "800", "900" };
95 const std::set<std::string> FONT_STYLES = { "italic", "oblique", "normal" };
96 const std::set<std::string> FONT_FAMILIES = { "sans-serif", "serif", "monospace" };
97 const std::set<std::string> QUALITY_TYPE = { "low", "medium", "high" }; // Default value is low.
98 
GetJsDoubleVal(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value)99 inline double GetJsDoubleVal(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value)
100 {
101     if (!runtime || !value) {
102         LOGE("runtime or value is null.");
103         return 0.0;
104     }
105     if (value->IsNumber(runtime) || value->IsString(runtime)) {
106         return value->ToDouble(runtime);
107     }
108     return 0.0;
109 }
110 
GetJsDashValue(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value)111 inline std::vector<double> GetJsDashValue(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value)
112 {
113     std::vector<double> segments;
114     if (!runtime || !value) {
115         LOGE("runtime or value is null.");
116         return segments;
117     }
118     auto valueStr = value->ToString(runtime);
119     std::vector<std::string> props;
120     StringUtils::StringSplitter(valueStr, ',', props);
121     for (const auto& prop : props) {
122         auto val = StringUtils::StringToDouble(prop);
123         // if there only exists 0 in props, it means that there is no dash style
124         if (NearZero(val) && props.size() == 1) {
125             return segments;
126         }
127         segments.emplace_back(val);
128     }
129     // if segment size is odd, copy one more to even
130     if (segments.size() % 2 != 0) {
131         segments.insert(segments.end(), segments.begin(), segments.end());
132     }
133     return segments;
134 }
135 
GetJsRectParam(const shared_ptr<JsRuntime> & runtime,int32_t argc,const std::vector<shared_ptr<JsValue>> & argv)136 inline Rect GetJsRectParam(
137     const shared_ptr<JsRuntime>& runtime, int32_t argc, const std::vector<shared_ptr<JsValue>>& argv)
138 {
139     if (!runtime) {
140         LOGE("runtime is null.");
141         return Rect();
142     }
143     if (argc != 4) {
144         LOGE("argc error. argc = %{private}d", argc);
145         return Rect();
146     }
147     double x = GetJsDoubleVal(runtime, argv[0]);
148     double y = GetJsDoubleVal(runtime, argv[1]);
149     double width = GetJsDoubleVal(runtime, argv[2]);
150     double height = GetJsDoubleVal(runtime, argv[3]);
151     Rect rect = Rect(x, y, width, height);
152     return rect;
153 }
154 
GetCurrentNodeId(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value)155 inline NodeId GetCurrentNodeId(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value)
156 {
157     if (!runtime || !value) {
158         LOGE("runtime or value is null.");
159         return 0;
160     }
161     NodeId id = 0;
162     auto nodeId = value->GetProperty(runtime, "__nodeId");
163     if (nodeId && nodeId->IsInt32(runtime)) {
164         id = nodeId->ToInt32(runtime);
165     }
166     return id < 0 ? 0 : id;
167 }
168 
PushTaskToPage(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::function<void (const RefPtr<CanvasTaskPool> &)> & task)169 void PushTaskToPage(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
170     const std::function<void(const RefPtr<CanvasTaskPool>&)>& task)
171 {
172     if (!runtime || !value) {
173         LOGE("runtime or value is null.");
174         return;
175     }
176     // get node id
177     NodeId id = GetCurrentNodeId(runtime, value);
178     auto command = Referenced::MakeRefPtr<JsCommandContextOperation>(id, task);
179     // push command
180     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
181     if (!engine) {
182         LOGE("engine is null.");
183         return;
184     }
185     auto page = engine->GetRunningPage();
186     if (!page) {
187         LOGE("page is null.");
188         return;
189     }
190     page->PushCommand(command);
191 }
192 
JsParseTextState(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value)193 inline PaintState JsParseTextState(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value)
194 {
195     PaintState state;
196     auto fontStyle = value->GetProperty(runtime, "font");
197     auto textAlign = value->GetProperty(runtime, "textAlign");
198     auto textBaseline = value->GetProperty(runtime, "textBaseline");
199 
200     // parse font styles
201     auto alignStr = textAlign->ToString(runtime);
202     auto baselineStr = textBaseline->ToString(runtime);
203     auto fontStr = fontStyle->ToString(runtime);
204     state.SetTextAlign(ConvertStrToTextAlign(alignStr));
205     TextStyle style;
206     style.SetTextBaseline(
207         ConvertStrToEnum(baselineStr.c_str(), BASELINE_TABLE, ArraySize(BASELINE_TABLE), TextBaseline::ALPHABETIC));
208     std::vector<std::string> fontProps;
209     StringUtils::StringSplitter(fontStr, ' ', fontProps);
210     bool updateFontStyle = false;
211     for (const auto& fontProp : fontProps) {
212         if (FONT_WEIGHTS.find(fontProp) != FONT_WEIGHTS.end()) {
213             style.SetFontWeight(ConvertStrToFontWeight(fontProp));
214         } else if (FONT_STYLES.find(fontProp) != FONT_STYLES.end()) {
215             updateFontStyle = true;
216             style.SetFontStyle(ConvertStrToFontStyle(fontProp));
217         } else if (FONT_FAMILIES.find(fontProp) != FONT_FAMILIES.end()) {
218             style.SetFontFamilies(ConvertStrToFontFamilies(fontProp));
219         } else if (fontProp.find("px") != std::string::npos) {
220             std::string fontSize = fontProp.substr(0, fontProp.size() - 2);
221             style.SetFontSize(Dimension(StringToDouble(fontProp)));
222         } else {
223             LOGW("parse text error");
224         }
225     }
226     if (!updateFontStyle) {
227         auto task = [](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateFontStyle(FontStyle::NORMAL); };
228         PushTaskToPage(runtime, value, task);
229     }
230     state.SetTextStyle(style);
231     return state;
232 }
233 
234 } // namespace
235 
236 int32_t JsiCanvasBridge::gradientCount_ = 0;
237 int32_t JsiCanvasBridge::patternCount_ = 0;
238 int32_t JsiCanvasBridge::path2dCount_ = 0;
239 std::unordered_map<int32_t, Pattern> JsiCanvasBridge::pattern_;
240 std::unordered_map<int32_t, Gradient> JsiCanvasBridge::gradientColors_;
241 std::unordered_map<int32_t, RefPtr<CanvasPath2D>> JsiCanvasBridge::path2Ds_;
242 
~JsiCanvasBridge()243 JsiCanvasBridge::~JsiCanvasBridge()
244 {
245     if (webglRenderContext_) {
246         delete webglRenderContext_;
247         webglRenderContext_ = nullptr;
248     }
249     if (webgl2RenderContext_) {
250         delete webgl2RenderContext_;
251         webgl2RenderContext_ = nullptr;
252     }
253 }
254 
HandleJsContext(const shared_ptr<JsRuntime> & runtime,NodeId id,const std::string & args)255 void JsiCanvasBridge::HandleJsContext(const shared_ptr<JsRuntime>& runtime, NodeId id, const std::string& args)
256 {
257     std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args);
258     if (argsValue && argsValue->IsArray() && argsValue->GetArraySize() > 0) {
259         auto typeArg = argsValue->GetArrayItem(0);
260         if (typeArg && typeArg->IsString()) {
261             std::string type = typeArg->GetString();
262             if (type == std::string(CANVAS_TYPE_WEBGL)) {
263                 HandleWebglContext(runtime, id, args, webglRenderContext_);
264                 return;
265             } else if (type == std::string(CANVAS_TYPE_WEBGL2)) {
266                 HandleWebglContext(runtime, id, args, webgl2RenderContext_);
267                 return;
268             }
269         }
270     }
271 
272     renderContext_ = runtime->NewObject();
273     const std::vector<std::pair<const std::string, RegisterFunctionType>> contextTable = {
274         { "createLinearGradient", JsCreateLinearGradient },
275         { "createRadialGradient", JsCreateRadialGradient },
276         { "fillRect", JsFillRect },
277         { "strokeRect", JsStrokeRect },
278         { "clearRect", JsClearRect },
279         { "fillText", JsFillText },
280         { "strokeText", JsStrokeText },
281         { "measureText", JsMeasureText },
282         { "moveTo", JsMoveTo },
283         { "lineTo", JsLineTo },
284         { "bezierCurveTo", JsBezierCurveTo },
285         { "quadraticCurveTo", JsQuadraticCurveTo },
286         { "arcTo", JsArcTo },
287         { "arc", JsArc },
288         { "ellipse", JsEllipse },
289         { "fill", JsFill },
290         { "stroke", JsStroke },
291         { "clip", JsClip },
292         { "rect", JsRect },
293         { "beginPath", JsBeginPath },
294         { "closePath", JsClosePath },
295         { "restore", JsRestore },
296         { "save", JsSave },
297         { "rotate", JsRotate },
298         { "scale", JsScale },
299         { "setTransform", JsSetTransform },
300         { "transform", JsTransform },
301         { "translate", JsTranslate },
302         { "getLineDash", JsGetLineDash },
303         { "setLineDash", JsSetLineDash },
304         { "drawImage", JsDrawImage },
305         { "createPath2D", JsCreatePath2D },
306         { "createPattern", JsCreatePattern },
307         { "createImageData", JsCreateImageData },
308         { "putImageData", JsPutImageData },
309         { "getImageData", JsGetImageData },
310 #ifdef PIXEL_MAP_SUPPORTED
311         { "getPixelMap", JsGetPixelMap },
312 #endif
313         { "getJsonData", JsGetJsonData },
314         { "transferFromImageBitmap", JsTransferFromImageBitmap },
315         { "drawBitmapMesh", JsDrawBitmapMesh },
316     };
317     renderContext_->SetProperty(runtime, "__nodeId", runtime->NewInt32(id));
318     for (const auto& iter : contextTable) {
319         renderContext_->SetProperty(runtime, iter.first, runtime->NewFunction(iter.second));
320     }
321     static const std::vector<std::tuple<std::string, RegisterFunctionType, RegisterFunctionType>> animationFuncs = {
322         { "fillStyle", JsFillStyleGetter, JsFillStyleSetter },
323         { "strokeStyle", JsStrokeStyleGetter, JsStrokeStyleSetter },
324         { "lineCap", JsLineCapGetter, JsLineCapSetter },
325         { "lineJoin", JsLineJoinGetter, JsLineJoinSetter },
326         { "miterLimit", JsMiterLimitGetter, JsMiterLimitSetter },
327         { "lineWidth", JsLineWidthGetter, JsLineWidthSetter },
328         { "textAlign", JsTextAlignGetter, JsTextAlignSetter },
329         { "textBaseline", JsTextBaselineGetter, JsTextBaselineSetter },
330         { "font", JsFontGetter, JsFontSetter },
331         { "globalAlpha", JsAlphaGetter, JsAlphaSetter },
332         { "globalCompositeOperation", JsCompositeOperationGetter, JsCompositeOperationSetter },
333         { "lineDashOffset", JsLineDashOffsetGetter, JsLineDashOffsetSetter },
334         { "shadowBlur", JsShadowBlurGetter, JsShadowBlurSetter },
335         { "shadowColor", JsShadowColorGetter, JsShadowColorSetter },
336         { "shadowOffsetX", JsShadowOffsetXGetter, JsShadowOffsetXSetter },
337         { "shadowOffsetY", JsShadowOffsetYGetter, JsShadowOffsetYSetter },
338         { "imageSmoothingEnabled", JsSmoothingEnabledGetter, JsSmoothingEnabledSetter },
339         { "imageSmoothingQuality", JsSmoothingQualityGetter, JsSmoothingQualitySetter },
340         { "width", JsWidthGetter, nullptr },
341         { "height", JsHeightGetter, nullptr }
342     };
343     for (const auto& item : animationFuncs) {
344         auto getterTempl = runtime->NewFunction(std::get<1>(item));
345         auto setterTempl = runtime->NewFunction(std::get<2>(item));
346         bool ret = renderContext_->SetAccessorProperty(runtime, std::get<0>(item), getterTempl, setterTempl);
347         if (!ret) {
348             LOGE("Canvas set accessor property failed., name: %{public}s", std::get<0>(item).c_str());
349         }
350     }
351     JsSetAntiAlias(runtime, id, args);
352 }
353 
HandleWebglContext(const shared_ptr<JsRuntime> & runtime,NodeId id,const std::string & args,CanvasRenderContextBase * & canvasRenderContext)354 void JsiCanvasBridge::HandleWebglContext(const shared_ptr<JsRuntime>& runtime,
355     NodeId id, const std::string& args, CanvasRenderContextBase*& canvasRenderContext)
356 {
357 #ifdef PREVIEW
358     LOGW("[Engine Log] Unable to use Webgl in the previewer. Perform this operation on the "
359     "emulator or a real device instead.");
360     renderContext_ = runtime->NewUndefined();
361     return;
362 #endif
363 
364     renderContext_ = runtime->NewUndefined();
365     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
366     if (!engine) {
367         LOGE("engine is null.");
368         return;
369     }
370 
371     auto nativeEngine = static_cast<ArkNativeEngine*>(engine->GetNativeEngine());
372     if (!nativeEngine) {
373         LOGE("NativeEngine is null");
374         return;
375     }
376 
377     std::string moduleName(CANVAS_WEBGL_SO);
378     std::string pluginId(std::to_string(id));
379     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
380     LocalScope scope(pandaRuntime->GetEcmaVm());
381     auto obj = nativeEngine->GetModuleFromName(
382         moduleName, false, pluginId, args, WEBGL_RENDER_CONTEXT_NAME, reinterpret_cast<void**>(&canvasRenderContext));
383     if (!canvasRenderContext) {
384         LOGE("CanvasBridge invalid canvasRenderContext");
385         return;
386     }
387     if (obj.IsEmpty() || pandaRuntime->HasPendingException()) {
388         LOGE("Get local object failed.");
389         return;
390     }
391 
392     renderContext_ = runtime->NewObject();
393     auto renderContext = std::static_pointer_cast<ArkJSValue>(renderContext_);
394     renderContext->SetValue(pandaRuntime, obj);
395 
396     auto page = engine->GetRunningPage();
397     if (!page) {
398         LOGE("page is null.");
399         return;
400     }
401 
402     auto task = [canvasRenderContext, page, id]() {
403         auto canvas = AceType::DynamicCast<DOMCanvas>(page->GetDomDocument()->GetDOMNodeById(id));
404         if (!canvas) {
405             return;
406         }
407         auto paintChild = AceType::DynamicCast<CustomPaintComponent>(canvas->GetSpecializedComponent());
408         if (paintChild) {
409             auto pool = paintChild->GetTaskPool();
410             if (!pool) {
411                 return;
412             }
413             pool->WebGLInit(canvasRenderContext);
414         }
415     };
416 
417     auto delegate = engine->GetFrontendDelegate();
418     if (!delegate) {
419         LOGE("ToDataURL failed. delegate is null.");
420         return;
421     }
422 
423     delegate->PostSyncTaskToPage(task, "ArkUICanvasWebGLInit");
424 
425     canvasRenderContext->Init();
426 
427     auto canvas = AceType::DynamicCast<DOMCanvas>(page->GetDomDocument()->GetDOMNodeById(id));
428     if (!canvas) {
429         return;
430     }
431 
432     auto paintChild = AceType::DynamicCast<CustomPaintComponent>(canvas->GetSpecializedComponent());
433     if (!paintChild) {
434         return;
435     }
436 
437     auto pool = paintChild->GetTaskPool();
438     if (!pool) {
439         return;
440     }
441 
442     auto weakDelegate = AceType::WeakClaim(AceType::RawPtr(delegate));
443     auto weakPool = AceType::WeakClaim(AceType::RawPtr(pool));
444 
445     auto onWebGLUpdateCallback = [weakDelegate, weakPool]() {
446         auto delegate = weakDelegate.Upgrade();
447         if (delegate) {
448             auto task = [weakPool]() {
449                 auto pool = weakPool.Upgrade();
450                 if (pool) {
451                     pool->WebGLUpdate();
452                 }
453             };
454             delegate->PostUITask(task, "ArkUICanvasWebGLUpdate");
455         }
456     };
457     canvasRenderContext->SetUpdateCallback(onWebGLUpdateCallback);
458 }
459 
HandleToDataURL(const shared_ptr<JsRuntime> & runtime,NodeId id,const std::string & args)460 void JsiCanvasBridge::HandleToDataURL(const shared_ptr<JsRuntime>& runtime, NodeId id, const std::string& args)
461 {
462     if (!runtime) {
463         LOGE("HandleToDataURL failed. runtime is null.");
464         return;
465     }
466     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
467     if (!engine) {
468         LOGE("HandleToDataURL failed. engine is null.");
469         return;
470     }
471     auto page = engine->GetRunningPage();
472     if (!page) {
473         LOGE("HandleToDataURL failed. page is null.");
474         return;
475     }
476     std::string dataUrl;
477     auto task = [id, page, args, &dataUrl]() {
478         auto canvas = AceType::DynamicCast<DOMCanvas>(page->GetDomDocument()->GetDOMNodeById(id));
479         if (!canvas) {
480             LOGE("ToDataURL failed, DOMCanvas is null.");
481             return;
482         }
483         auto paintChild = AceType::DynamicCast<CustomPaintComponent>(canvas->GetSpecializedComponent());
484         auto pool = paintChild->GetTaskPool();
485         if (!pool) {
486             LOGE("ToDataURL failed, TaskPool is null.");
487             return;
488         }
489         dataUrl = pool->ToDataURL(args);
490     };
491     auto delegate = engine->GetFrontendDelegate();
492     if (!delegate) {
493         LOGE("ToDataURL failed. delegate is null.");
494         return;
495     }
496     delegate->PostSyncTaskToPage(task, "ArkUICanvasToDataURL");
497     dataURL_ = runtime->NewString(dataUrl);
498 }
499 
JsSetAntiAlias(const shared_ptr<JsRuntime> & runtime,NodeId id,const std::string & args)500 void JsiCanvasBridge::JsSetAntiAlias(const shared_ptr<JsRuntime>& runtime, NodeId id, const std::string& args)
501 {
502     if (!runtime) {
503         LOGE("JsSetAntiAlias failed. runtime is null.");
504         return;
505     }
506     bool isEnabled = args.find("\"antialias\":true") != std::string::npos;
507     auto task = [isEnabled](const RefPtr<CanvasTaskPool>& pool) { pool->SetAntiAlias(isEnabled); };
508     auto command = Referenced::MakeRefPtr<JsCommandContextOperation>(id, task);
509     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
510     if (!engine) {
511         LOGE("JsSetAntiAlias failed. engine is null.");
512         return;
513     }
514     auto page = engine->GetRunningPage();
515     if (!page) {
516         LOGE("JsSetAntiAlias failed. page is null.");
517         return;
518     }
519     page->PushCommand(command);
520     auto delegate = engine->GetFrontendDelegate();
521     if (page->CheckPageCreated() && delegate) {
522         delegate->TriggerPageUpdate(page->GetPageId());
523     }
524 }
525 
JsCreateLinearGradient(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)526 shared_ptr<JsValue> JsiCanvasBridge::JsCreateLinearGradient(const shared_ptr<JsRuntime>& runtime,
527     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
528 {
529     if (argc != 4) {
530         LOGE("argc error, argc = %{private}d", argc);
531         return runtime->NewUndefined();
532     }
533     shared_ptr<JsValue> gradient = runtime->NewObject();
534 
535     gradient->SetProperty(runtime, "__type", runtime->NewString("gradient"));
536     gradient->SetProperty(runtime, "__id", runtime->NewInt32(gradientCount_));
537     gradient->SetProperty(runtime, "addColorStop", runtime->NewFunction(JsAddColorStop));
538 
539     Offset beginOffset = Offset(GetJsDoubleVal(runtime, argv[0]), GetJsDoubleVal(runtime, argv[1]));
540     Offset endOffset = Offset(GetJsDoubleVal(runtime, argv[2]), GetJsDoubleVal(runtime, argv[3]));
541     gradientColors_[gradientCount_].SetBeginOffset(beginOffset);
542     gradientColors_[gradientCount_].SetEndOffset(endOffset);
543     ++gradientCount_;
544     return gradient;
545 }
546 
JsCreateRadialGradient(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)547 shared_ptr<JsValue> JsiCanvasBridge::JsCreateRadialGradient(const shared_ptr<JsRuntime>& runtime,
548     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
549 {
550     // 6 parameters: createRadialGradient(x0, y0, r0, x1, y1, r1)
551     if (argc != 6) {
552         LOGE("argc error, argc = %{private}d", argc);
553         return runtime->NewUndefined();
554     }
555     shared_ptr<JsValue> gradient = runtime->NewObject();
556     gradient->SetProperty(runtime, "__type", runtime->NewString("gradient"));
557     gradient->SetProperty(runtime, "__id", runtime->NewInt32(gradientCount_));
558     gradient->SetProperty(runtime, "addColorStop", runtime->NewFunction(JsAddColorStop));
559     Offset innerCenter = Offset(GetJsDoubleVal(runtime, argv[0]), GetJsDoubleVal(runtime, argv[1]));
560     Offset outerCenter = Offset(GetJsDoubleVal(runtime, argv[3]), GetJsDoubleVal(runtime, argv[4]));
561     double innerRadius = GetJsDoubleVal(runtime, argv[2]);
562     double outerRadius = GetJsDoubleVal(runtime, argv[5]);
563     gradientColors_[gradientCount_].SetType(GradientType::RADIAL);
564     gradientColors_[gradientCount_].SetBeginOffset(innerCenter);
565     gradientColors_[gradientCount_].SetEndOffset(outerCenter);
566     gradientColors_[gradientCount_].SetInnerRadius(innerRadius);
567     gradientColors_[gradientCount_].SetOuterRadius(outerRadius);
568     ++gradientCount_;
569     return gradient;
570 }
571 
JsAddColorStop(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)572 shared_ptr<JsValue> JsiCanvasBridge::JsAddColorStop(const shared_ptr<JsRuntime>& runtime,
573     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
574 {
575     if (argc != 2) {
576         LOGE("argc error, argc = %{private}d", argc);
577         return runtime->NewUndefined();
578     }
579 
580     GradientColor color;
581     auto jsColor = argv[1]->ToString(runtime);
582     color.SetColor(Color::FromString(jsColor));
583     color.SetDimension(GetJsDoubleVal(runtime, argv[0]));
584     int32_t id = -1;
585     auto nodeId = value->GetProperty(runtime, "__id");
586     if (nodeId && nodeId->IsInt32(runtime)) {
587         id = nodeId->ToInt32(runtime);
588     }
589     if (id < 0) {
590         return runtime->NewUndefined();
591     }
592     gradientColors_[id].AddColor(color);
593     return runtime->NewUndefined();
594 }
595 
GetGradient(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value)596 Gradient JsiCanvasBridge::GetGradient(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value)
597 {
598     int32_t id = -1;
599     auto nodeId = value->GetProperty(runtime, "__id");
600     if (nodeId && nodeId->IsInt32(runtime)) {
601         id = nodeId->ToInt32(runtime);
602     }
603     if (id < 0) {
604         return Gradient();
605     }
606     return gradientColors_[id];
607 }
608 
JsFillRect(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)609 shared_ptr<JsValue> JsiCanvasBridge::JsFillRect(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
610     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
611 {
612     if (argc != 4) {
613         LOGE("argc error, argc = %{private}d", argc);
614         return runtime->NewUndefined();
615     }
616     Rect rect = GetJsRectParam(runtime, argc, argv);
617     auto task = [rect](const RefPtr<CanvasTaskPool>& pool) { pool->FillRect(rect); };
618     PushTaskToPage(runtime, value, std::move(task));
619     return runtime->NewUndefined();
620 }
621 
JsStrokeRect(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)622 shared_ptr<JsValue> JsiCanvasBridge::JsStrokeRect(const shared_ptr<JsRuntime>& runtime,
623     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
624 {
625     if (argc != 4) {
626         LOGE("argc error, argc = %{private}d", argc);
627         return runtime->NewUndefined();
628     }
629     Rect rect = GetJsRectParam(runtime, argc, argv);
630     auto task = [rect](const RefPtr<CanvasTaskPool>& pool) { pool->StrokeRect(rect); };
631     PushTaskToPage(runtime, value, std::move(task));
632     return runtime->NewUndefined();
633 }
634 
JsClearRect(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)635 shared_ptr<JsValue> JsiCanvasBridge::JsClearRect(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
636     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
637 {
638     if (argc != 4) {
639         LOGE("argc error, argc = %{private}d", argc);
640         return runtime->NewUndefined();
641     }
642     Rect rect = GetJsRectParam(runtime, argc, argv);
643     auto task = [rect](const RefPtr<CanvasTaskPool>& pool) { pool->ClearRect(rect); };
644     PushTaskToPage(runtime, value, task);
645     return runtime->NewUndefined();
646 }
647 
JsFillText(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)648 shared_ptr<JsValue> JsiCanvasBridge::JsFillText(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
649     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
650 {
651     if (argc != 3) {
652         LOGE("argc error, argc = %{private}d", argc);
653         return runtime->NewUndefined();
654     }
655     if (!argv[0]) {
656         return runtime->NewUndefined();
657     }
658     auto text = argv[0]->ToString(runtime);
659     double x = GetJsDoubleVal(runtime, argv[1]);
660     double y = GetJsDoubleVal(runtime, argv[2]);
661     auto task = [text, x, y](const RefPtr<CanvasTaskPool>& pool) { pool->FillText(text, Offset(x, y)); };
662     PushTaskToPage(runtime, value, task);
663     return runtime->NewUndefined();
664 }
665 
JsStrokeText(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)666 shared_ptr<JsValue> JsiCanvasBridge::JsStrokeText(const shared_ptr<JsRuntime>& runtime,
667     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
668 {
669     if (argc != 3) {
670         LOGE("argc error, argc = %{private}d", argc);
671         return runtime->NewUndefined();
672     }
673     if (!argv[0]) {
674         return runtime->NewUndefined();
675     }
676     auto text = argv[0]->ToString(runtime);
677     double x = GetJsDoubleVal(runtime, argv[1]);
678     double y = GetJsDoubleVal(runtime, argv[2]);
679     auto task = [text, x, y](const RefPtr<CanvasTaskPool>& pool) { pool->StrokeText(text, Offset(x, y)); };
680     PushTaskToPage(runtime, value, task);
681     return runtime->NewUndefined();
682 }
683 
JsMeasureText(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)684 shared_ptr<JsValue> JsiCanvasBridge::JsMeasureText(const shared_ptr<JsRuntime>& runtime,
685     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
686 {
687     // this func should return TextMetrics, including the width of the text
688     if (argc != 1) {
689         LOGE("argc error, argc = %{private}d", argc);
690         return runtime->NewUndefined();
691     }
692     if (!argv[0]) {
693         return runtime->NewUndefined();
694     }
695     auto text = argv[0]->ToString(runtime);
696     auto textState = JsParseTextState(runtime, value);
697     NodeId id = GetCurrentNodeId(runtime, value);
698     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
699     if (!engine) {
700         LOGE("JsMeasureText failed. engine is null.");
701         return runtime->NewUndefined();
702     }
703     auto page = engine->GetRunningPage();
704     if (!page) {
705         LOGE("JsMeasureText failed. page is null.");
706         return runtime->NewUndefined();
707     }
708     double width = 0.0;
709     double height = 0.0;
710     auto task = [&text, &textState, id, page, &width, &height]() {
711         auto canvas = AceType::DynamicCast<DOMCanvas>(page->GetDomDocument()->GetDOMNodeById(id));
712         if (!canvas) {
713             return;
714         }
715         auto paintChild = AceType::DynamicCast<CustomPaintComponent>(canvas->GetSpecializedComponent());
716         auto canvasTask = paintChild->GetTaskPool();
717         if (!canvasTask) {
718             return;
719         }
720         width = canvasTask->MeasureText(text, textState);
721         height = canvasTask->MeasureTextHeight(text, textState);
722     };
723     auto delegate = engine->GetFrontendDelegate();
724     if (!delegate) {
725         LOGE("JsMeasureText failed. delegate is null.");
726         return runtime->NewUndefined();
727     }
728     delegate->PostSyncTaskToPage(task, "ArkUICanvasMeasureText");
729     auto textMetrics = runtime->NewObject();
730     textMetrics->SetProperty(runtime, "width", runtime->NewNumber(width));
731     textMetrics->SetProperty(runtime, "height", runtime->NewNumber(height));
732     return textMetrics;
733 }
734 
JsBeginPath(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)735 shared_ptr<JsValue> JsiCanvasBridge::JsBeginPath(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
736     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
737 {
738     if (argc != 0) {
739         LOGE("argc error, argc = %{private}d", argc);
740         return runtime->NewUndefined();
741     }
742     auto task = [](const RefPtr<CanvasTaskPool>& pool) { pool->BeginPath(); };
743     PushTaskToPage(runtime, value, task);
744     return runtime->NewUndefined();
745 }
746 
JsClosePath(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)747 shared_ptr<JsValue> JsiCanvasBridge::JsClosePath(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
748     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
749 {
750     if (argc != 0) {
751         LOGE("argc error, argc = %{private}d", argc);
752         return runtime->NewUndefined();
753     }
754     auto task = [](const RefPtr<CanvasTaskPool>& pool) { pool->ClosePath(); };
755     PushTaskToPage(runtime, value, task);
756     return runtime->NewUndefined();
757 }
758 
JsMoveTo(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)759 shared_ptr<JsValue> JsiCanvasBridge::JsMoveTo(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
760     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
761 {
762     if (argc != 2) {
763         LOGE("argc error, argc = %{private}d", argc);
764         return runtime->NewUndefined();
765     }
766     double x = GetJsDoubleVal(runtime, argv[0]);
767     double y = GetJsDoubleVal(runtime, argv[1]);
768     auto task = [x, y](const RefPtr<CanvasTaskPool>& pool) { pool->MoveTo(x, y); };
769     PushTaskToPage(runtime, value, task);
770     return runtime->NewUndefined();
771 }
772 
JsLineTo(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)773 shared_ptr<JsValue> JsiCanvasBridge::JsLineTo(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
774     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
775 {
776     if (argc != 2) {
777         LOGE("argc error, argc = %{private}d", argc);
778         return runtime->NewUndefined();
779     }
780     double x = GetJsDoubleVal(runtime, argv[0]);
781     double y = GetJsDoubleVal(runtime, argv[1]);
782     auto task = [x, y](const RefPtr<CanvasTaskPool>& pool) { pool->LineTo(x, y); };
783     PushTaskToPage(runtime, value, task);
784     return runtime->NewUndefined();
785 }
786 
JsBezierCurveTo(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)787 shared_ptr<JsValue> JsiCanvasBridge::JsBezierCurveTo(const shared_ptr<JsRuntime>& runtime,
788     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
789 {
790     if (argc != 6) {
791         LOGE("argc error, argc = %{private}d", argc);
792         return runtime->NewUndefined();
793     }
794     BezierCurveParam param;
795     param.cp1x = GetJsDoubleVal(runtime, argv[0]);
796     param.cp1y = GetJsDoubleVal(runtime, argv[1]);
797     param.cp2x = GetJsDoubleVal(runtime, argv[2]);
798     param.cp2y = GetJsDoubleVal(runtime, argv[3]);
799     param.x = GetJsDoubleVal(runtime, argv[4]);
800     param.y = GetJsDoubleVal(runtime, argv[5]);
801     auto task = [param](const RefPtr<CanvasTaskPool>& pool) { pool->BezierCurveTo(param); };
802     PushTaskToPage(runtime, value, task);
803     return runtime->NewUndefined();
804 }
805 
JsQuadraticCurveTo(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)806 shared_ptr<JsValue> JsiCanvasBridge::JsQuadraticCurveTo(const shared_ptr<JsRuntime>& runtime,
807     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
808 {
809     if (argc != 4) {
810         LOGE("argc error, argc = %{private}d", argc);
811         return runtime->NewUndefined();
812     }
813     QuadraticCurveParam param;
814     param.cpx = GetJsDoubleVal(runtime, argv[0]);
815     param.cpy = GetJsDoubleVal(runtime, argv[1]);
816     param.x = GetJsDoubleVal(runtime, argv[2]);
817     param.y = GetJsDoubleVal(runtime, argv[3]);
818     auto task = [param](const RefPtr<CanvasTaskPool>& pool) { pool->QuadraticCurveTo(param); };
819     PushTaskToPage(runtime, value, task);
820     return runtime->NewUndefined();
821 }
822 
JsArc(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)823 shared_ptr<JsValue> JsiCanvasBridge::JsArc(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
824     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
825 {
826     if (argc < 5 || argc > 6) {
827         LOGE("argc error, argc = %{private}d", argc);
828         return runtime->NewUndefined();
829     }
830     ArcParam param;
831     param.x = GetJsDoubleVal(runtime, argv[0]);
832     param.y = GetJsDoubleVal(runtime, argv[1]);
833     param.radius = GetJsDoubleVal(runtime, argv[2]);
834     param.startAngle = GetJsDoubleVal(runtime, argv[3]);
835     param.endAngle = GetJsDoubleVal(runtime, argv[4]);
836     if (argc == 6) {
837         if (!argv[5]) {
838             LOGW("no value");
839             return runtime->NewUndefined();
840         }
841         std::unique_ptr<JsonValue> argPtr = JsonUtil::ParseJsonString(argv[5]->ToString(runtime));
842         if (argPtr && argPtr->IsBool()) {
843             param.anticlockwise = argPtr->GetBool();
844         }
845     }
846     auto task = [param](const RefPtr<CanvasTaskPool>& pool) { pool->Arc(param); };
847     PushTaskToPage(runtime, value, task);
848     return runtime->NewUndefined();
849 }
850 
JsArcTo(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)851 shared_ptr<JsValue> JsiCanvasBridge::JsArcTo(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
852     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
853 {
854     if (argc != 5) {
855         LOGE("argc error, argc = %{private}d", argc);
856         return runtime->NewUndefined();
857     }
858     ArcToParam param;
859     param.x1 = GetJsDoubleVal(runtime, argv[0]);
860     param.y1 = GetJsDoubleVal(runtime, argv[1]);
861     param.x2 = GetJsDoubleVal(runtime, argv[2]);
862     param.y2 = GetJsDoubleVal(runtime, argv[3]);
863     param.radius = GetJsDoubleVal(runtime, argv[4]);
864     auto task = [param](const RefPtr<CanvasTaskPool>& pool) { pool->ArcTo(param); };
865     PushTaskToPage(runtime, value, task);
866     return runtime->NewUndefined();
867 }
868 
JsEllipse(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)869 shared_ptr<JsValue> JsiCanvasBridge::JsEllipse(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
870     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
871 {
872     // 7 or 8 parameters: ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise?)
873     if (argc < 7 || argc > 8) {
874         LOGE("argc error, argc = %{private}d", argc);
875         return runtime->NewUndefined();
876     }
877     EllipseParam param;
878     param.x = GetJsDoubleVal(runtime, argv[0]);
879     param.y = GetJsDoubleVal(runtime, argv[1]);
880     param.radiusX = GetJsDoubleVal(runtime, argv[2]);
881     param.radiusY = GetJsDoubleVal(runtime, argv[3]);
882     param.rotation = GetJsDoubleVal(runtime, argv[4]);
883     param.startAngle = GetJsDoubleVal(runtime, argv[5]);
884     param.endAngle = GetJsDoubleVal(runtime, argv[6]);
885     if (argc == 8) {
886         int32_t anti = static_cast<int32_t>(GetJsDoubleVal(runtime, argv[7]));
887         param.anticlockwise = (anti == 1);
888     }
889     auto task = [param](const RefPtr<CanvasTaskPool>& pool) { pool->Ellipse(param); };
890     PushTaskToPage(runtime, value, task);
891     return runtime->NewUndefined();
892 }
893 
JsRect(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)894 shared_ptr<JsValue> JsiCanvasBridge::JsRect(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
895     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
896 {
897     Rect rect = GetJsRectParam(runtime, argc, argv);
898     auto task = [rect](const RefPtr<CanvasTaskPool>& pool) { pool->AddRect(rect); };
899     PushTaskToPage(runtime, value, std::move(task));
900     return runtime->NewUndefined();
901 }
902 
JsFill(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)903 shared_ptr<JsValue> JsiCanvasBridge::JsFill(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
904     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
905 {
906     auto task = [](const RefPtr<CanvasTaskPool>& pool) { pool->Fill(); };
907     PushTaskToPage(runtime, value, task);
908     return runtime->NewUndefined();
909 }
910 
JsStroke(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)911 shared_ptr<JsValue> JsiCanvasBridge::JsStroke(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
912     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
913 {
914     // 0 or 1 parameter: ctx.stroke() / ctx.stroke(path)
915     if (argc == 1) {
916         auto typeVal = argv[0]->GetProperty(runtime, "__type");
917         auto type = typeVal->ToString(runtime);
918         if (type != "path2d") {
919             LOGE("Stroke Path2D failed, target is not path.");
920             return runtime->NewUndefined();
921         }
922         auto path = GetPath2D(runtime, argv[0]);
923         if (path == nullptr) {
924             LOGE("Stroke Path2D failed, target path is null.");
925             return runtime->NewUndefined();
926         }
927         auto task = [path](const RefPtr<CanvasTaskPool>& pool) { pool->Stroke(path); };
928         PushTaskToPage(runtime, value, task);
929         return runtime->NewUndefined();
930     }
931     auto task = [](const RefPtr<CanvasTaskPool>& pool) { pool->Stroke(); };
932     PushTaskToPage(runtime, value, task);
933     return runtime->NewUndefined();
934 }
935 
JsClip(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)936 shared_ptr<JsValue> JsiCanvasBridge::JsClip(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
937     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
938 {
939     auto task = [](const RefPtr<CanvasTaskPool>& pool) { pool->Clip(); };
940     PushTaskToPage(runtime, value, task);
941     return runtime->NewUndefined();
942 }
943 
JsRestore(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)944 shared_ptr<JsValue> JsiCanvasBridge::JsRestore(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
945     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
946 {
947     if (argc != 0) {
948         LOGE("argc error, argc = %{private}d", argc);
949         return runtime->NewUndefined();
950     }
951     auto task = [](const RefPtr<CanvasTaskPool>& pool) { pool->Restore(); };
952     PushTaskToPage(runtime, value, task);
953     return runtime->NewUndefined();
954 }
955 
JsSave(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)956 shared_ptr<JsValue> JsiCanvasBridge::JsSave(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
957     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
958 {
959     if (argc != 0) {
960         LOGE("argc error, argc = %{private}d", argc);
961         return runtime->NewUndefined();
962     }
963     auto task = [](const RefPtr<CanvasTaskPool>& pool) { pool->Save(); };
964     PushTaskToPage(runtime, value, task);
965     return runtime->NewUndefined();
966 }
967 
JsRotate(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)968 shared_ptr<JsValue> JsiCanvasBridge::JsRotate(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
969     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
970 {
971     double angle = GetJsDoubleVal(runtime, argv[0]);
972     auto task = [angle](const RefPtr<CanvasTaskPool>& pool) { pool->Rotate(angle); };
973     PushTaskToPage(runtime, value, task);
974     return runtime->NewUndefined();
975 }
976 
JsScale(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)977 shared_ptr<JsValue> JsiCanvasBridge::JsScale(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
978     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
979 {
980     if (argc != 2) {
981         LOGE("argc error, argc = %{private}d", argc);
982         return runtime->NewUndefined();
983     }
984     double x = GetJsDoubleVal(runtime, argv[0]);
985     double y = GetJsDoubleVal(runtime, argv[1]);
986     auto task = [x, y](const RefPtr<CanvasTaskPool>& pool) { pool->Scale(x, y); };
987     PushTaskToPage(runtime, value, task);
988     return runtime->NewUndefined();
989 }
990 
JsSetTransform(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)991 shared_ptr<JsValue> JsiCanvasBridge::JsSetTransform(const shared_ptr<JsRuntime>& runtime,
992     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
993 {
994     if (argc != 6) {
995         LOGE("argc error, argc = %{private}d", argc);
996         return runtime->NewUndefined();
997     }
998     TransformParam param;
999     param.scaleX = GetJsDoubleVal(runtime, argv[0]);
1000     param.skewX = GetJsDoubleVal(runtime, argv[1]);
1001     param.skewY = GetJsDoubleVal(runtime, argv[2]);
1002     param.scaleY = GetJsDoubleVal(runtime, argv[3]);
1003     param.translateX = GetJsDoubleVal(runtime, argv[4]);
1004     param.translateY = GetJsDoubleVal(runtime, argv[5]);
1005     auto task = [param](const RefPtr<CanvasTaskPool>& pool) { pool->SetTransform(param); };
1006     PushTaskToPage(runtime, value, task);
1007     return runtime->NewUndefined();
1008 }
1009 
JsTransform(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1010 shared_ptr<JsValue> JsiCanvasBridge::JsTransform(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
1011     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1012 {
1013     if (argc != 6) {
1014         LOGE("argc error, argc = %{private}d", argc);
1015         return runtime->NewUndefined();
1016     }
1017     TransformParam param;
1018     param.scaleX = GetJsDoubleVal(runtime, argv[0]);
1019     param.skewX = GetJsDoubleVal(runtime, argv[1]);
1020     param.skewY = GetJsDoubleVal(runtime, argv[2]);
1021     param.scaleY = GetJsDoubleVal(runtime, argv[3]);
1022     param.translateX = GetJsDoubleVal(runtime, argv[4]);
1023     param.translateY = GetJsDoubleVal(runtime, argv[5]);
1024     auto task = [param](const RefPtr<CanvasTaskPool>& pool) { pool->Transform(param); };
1025     PushTaskToPage(runtime, value, task);
1026     return runtime->NewUndefined();
1027 }
1028 
JsTranslate(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1029 shared_ptr<JsValue> JsiCanvasBridge::JsTranslate(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
1030     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1031 {
1032     if (argc != 2) {
1033         LOGE("argc error, argc = %{private}d", argc);
1034         return runtime->NewUndefined();
1035     }
1036     double x = GetJsDoubleVal(runtime, argv[0]);
1037     double y = GetJsDoubleVal(runtime, argv[1]);
1038     auto task = [x, y](const RefPtr<CanvasTaskPool>& pool) { pool->Translate(x, y); };
1039     PushTaskToPage(runtime, value, task);
1040     return runtime->NewUndefined();
1041 }
1042 
JsSetLineDash(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1043 shared_ptr<JsValue> JsiCanvasBridge::JsSetLineDash(const shared_ptr<JsRuntime>& runtime,
1044     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1045 {
1046     if (argc != 1) {
1047         LOGE("argc error, argc = %{private}d", argc);
1048         return runtime->NewUndefined();
1049     }
1050     auto dash = argv[0]->ToString(runtime);
1051     value->SetProperty(runtime, "lineDash", runtime->NewString(dash));
1052     auto segments = GetJsDashValue(runtime, argv[0]);
1053     auto task = [segments](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateLineDash(segments); };
1054     PushTaskToPage(runtime, value, task);
1055     return runtime->NewUndefined();
1056 }
1057 
JsGetLineDash(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1058 shared_ptr<JsValue> JsiCanvasBridge::JsGetLineDash(const shared_ptr<JsRuntime>& runtime,
1059     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1060 {
1061     if (argc != 0) {
1062         LOGE("argc error, argc = %{private}d", argc);
1063         return runtime->NewUndefined();
1064     }
1065     auto val = value->GetProperty(runtime, "lineDash");
1066     return val;
1067 }
1068 
ParseDomImage(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,double & width,double & height,std::string & src)1069 void JsiCanvasBridge::ParseDomImage(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
1070     double& width, double& height, std::string& src)
1071 {
1072     auto jsAttr = value->GetProperty(runtime, "attr");
1073     auto jsSrc = jsAttr->GetProperty(runtime, DOM_SRC);
1074     auto imgSrc = jsSrc->ToString(runtime);
1075     src = imgSrc;
1076 
1077     auto jsStyle = value->GetProperty(runtime, "style");
1078     auto jsWidth = jsStyle->GetProperty(runtime, DOM_WIDTH);
1079     auto jsHeight = jsStyle->GetProperty(runtime, DOM_HEIGHT);
1080     auto cWidth = jsWidth->ToString(runtime);
1081     auto cHeight = jsHeight->ToString(runtime);
1082     width = StringToDouble(cWidth);
1083     height = StringToDouble(cHeight);
1084 
1085     if (NearZero(width)) {
1086         width = StringToDouble(cWidth.substr(0, cWidth.size() - 2)); // 2: remove px units
1087     }
1088     if (NearZero(height)) {
1089         height = StringToDouble(cHeight.substr(0, cHeight.size() - 2)); // 2: remove px units
1090     }
1091 }
1092 
JsDrawImage(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1093 shared_ptr<JsValue> JsiCanvasBridge::JsDrawImage(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
1094     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1095 {
1096     if (!argv[0] || !argv[0]->IsObject(runtime)) {
1097         return runtime->NewUndefined();
1098     }
1099 
1100     RefPtr<PixelMap> pixelMap = nullptr;
1101     bool isPixelMap = false;
1102 
1103     CanvasImage image;
1104     double width = 0.0;
1105     double height = 0.0;
1106     auto src = argv[0]->GetProperty(runtime, DOM_SRC);
1107     if (src->IsUndefined(runtime)) {
1108 #if !defined(PREVIEW)
1109         pixelMap = CreatePixelMapFromNapiValue(runtime, argv[0]);
1110         if (!pixelMap) {
1111             LOGE("pixelMap is null");
1112             return runtime->NewUndefined();
1113         }
1114         isPixelMap = true;
1115 #else
1116         return runtime->NewUndefined();
1117 #endif
1118     } else if (!src->IsString(runtime)) {
1119         ParseDomImage(runtime, argv[0], width, height, image.src);
1120     } else {
1121         auto imgSrc = src->ToString(runtime);
1122         image.src = imgSrc;
1123         auto jsWidth = argv[0]->GetProperty(runtime, DOM_WIDTH);
1124         auto jsHeight = argv[0]->GetProperty(runtime, DOM_HEIGHT);
1125         width = jsWidth->ToDouble(runtime);
1126         height = jsHeight->ToDouble(runtime);
1127     }
1128     switch (argc) {
1129         case 3:
1130             image.flag = 0;
1131             image.dx = GetJsDoubleVal(runtime, argv[1]);
1132             image.dy = GetJsDoubleVal(runtime, argv[2]);
1133             break;
1134         case 5:
1135             image.flag = 1;
1136             image.dx = GetJsDoubleVal(runtime, argv[1]);
1137             image.dy = GetJsDoubleVal(runtime, argv[2]);
1138             image.dWidth = GetJsDoubleVal(runtime, argv[3]);
1139             image.dHeight = GetJsDoubleVal(runtime, argv[4]);
1140             break;
1141         case 9:
1142             image.flag = 2; // 2: image with scale
1143             image.sx = GetJsDoubleVal(runtime, argv[1]);
1144             image.sy = GetJsDoubleVal(runtime, argv[2]);
1145             image.sWidth = GetJsDoubleVal(runtime, argv[3]);
1146             image.sHeight = GetJsDoubleVal(runtime, argv[4]);
1147             image.dx = GetJsDoubleVal(runtime, argv[5]);
1148             image.dy = GetJsDoubleVal(runtime, argv[6]);
1149             image.dWidth = GetJsDoubleVal(runtime, argv[7]);
1150             image.dHeight = GetJsDoubleVal(runtime, argv[8]);
1151             break;
1152         default:
1153             break;
1154     }
1155     auto task = [image, width, height, isPixelMap, pixelMap](const RefPtr<CanvasTaskPool>& pool) {
1156         if (isPixelMap) {
1157             pool->DrawPixelMap(pixelMap, image);
1158         } else {
1159             pool->DrawImage(image, width, height);
1160         }
1161     };
1162     PushTaskToPage(runtime, value, task);
1163     return runtime->NewUndefined();
1164 }
1165 
JsCreatePath2D(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1166 shared_ptr<JsValue> JsiCanvasBridge::JsCreatePath2D(const shared_ptr<JsRuntime>& runtime,
1167     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1168 {
1169     shared_ptr<JsValue> path2D = runtime->NewObject();
1170     path2D->SetProperty(runtime, "__type", runtime->NewString("path2d"));
1171     path2D->SetProperty(runtime, "__id", runtime->NewInt32(path2dCount_));
1172     path2D->SetProperty(runtime, "addPath", runtime->NewFunction(JsPath2DAddPath));
1173     path2D->SetProperty(runtime, "setTransform", runtime->NewFunction(JsPath2DSetTransform));
1174     path2D->SetProperty(runtime, "moveTo", runtime->NewFunction(JsPath2DMoveTo));
1175     path2D->SetProperty(runtime, "lineTo", runtime->NewFunction(JsPath2DLineTo));
1176     path2D->SetProperty(runtime, "arc", runtime->NewFunction(JsPath2DArc));
1177     path2D->SetProperty(runtime, "arcTo", runtime->NewFunction(JsPath2DArcTo));
1178     path2D->SetProperty(runtime, "quadraticCurveTo", runtime->NewFunction(JsPath2DQuadraticCurveTo));
1179     path2D->SetProperty(runtime, "bezierCurveTo", runtime->NewFunction(JsPath2DBezierCurveTo));
1180     path2D->SetProperty(runtime, "ellipse", runtime->NewFunction(JsPath2DEllipse));
1181     path2D->SetProperty(runtime, "rect", runtime->NewFunction(JsPath2DRect));
1182     path2D->SetProperty(runtime, "closePath", runtime->NewFunction(JsPath2DClosePath));
1183     path2Ds_[path2dCount_] = JsMakePath2D(runtime, value, argv, argc);
1184     ++path2dCount_;
1185     return path2D;
1186 }
1187 
JsPath2DAddPath(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1188 shared_ptr<JsValue> JsiCanvasBridge::JsPath2DAddPath(const shared_ptr<JsRuntime>& runtime,
1189     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1190 {
1191     // 1 parameter: addPath(path)
1192     if (argc != 1) {
1193         LOGE("AddPath to Path2D failed, invalid args.");
1194         return runtime->NewUndefined();
1195     }
1196     int32_t id = -1;
1197     auto nodeId = value->GetProperty(runtime, "__id");
1198     if (nodeId && nodeId->IsInt32(runtime)) {
1199         id = nodeId->ToInt32(runtime);
1200     }
1201     if (id < 0) {
1202         return runtime->NewUndefined();
1203     }
1204     auto holderPath = path2Ds_[id];
1205     if (holderPath == nullptr) {
1206         LOGE("AddPath to Path2D failed, holderPath is null.");
1207         return runtime->NewUndefined();
1208     }
1209     auto typeVal = argv[0]->GetProperty(runtime, "__type");
1210     auto type = typeVal->ToString(runtime);
1211     if (type != "path2d") {
1212         LOGE("Stroke Path2D failed, target is not path.");
1213         return runtime->NewUndefined();
1214     }
1215     auto toBeAdd = GetPath2D(runtime, argv[0]);
1216     if (toBeAdd == nullptr) {
1217         LOGE("AddPath to Path2D failed, to be added path is null.");
1218         return runtime->NewUndefined();
1219     }
1220     holderPath->AddPath(toBeAdd);
1221     return runtime->NewUndefined();
1222 }
1223 
JsPath2DSetTransform(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1224 shared_ptr<JsValue> JsiCanvasBridge::JsPath2DSetTransform(const shared_ptr<JsRuntime>& runtime,
1225     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1226 {
1227     // 6 parameters: setTransform(a, b, c, d, e, f)
1228     if (argc != 6) {
1229         LOGE("Call Path2D SetTransform failed, invalid args.");
1230         return runtime->NewUndefined();
1231     }
1232     int32_t id = -1;
1233     auto nodeId = value->GetProperty(runtime, "__id");
1234     if (nodeId && nodeId->IsInt32(runtime)) {
1235         id = nodeId->ToInt32(runtime);
1236     }
1237     if (id < 0) {
1238         return runtime->NewUndefined();
1239     }
1240     auto holderPath = path2Ds_[id];
1241     if (holderPath == nullptr) {
1242         LOGE("Call Path2D SetTransform failed, holderPath is null.");
1243         return runtime->NewUndefined();
1244     }
1245     holderPath->SetTransform(GetJsDoubleVal(runtime, argv[0]), GetJsDoubleVal(runtime, argv[1]),
1246                              GetJsDoubleVal(runtime, argv[2]), GetJsDoubleVal(runtime, argv[3]),
1247                              GetJsDoubleVal(runtime, argv[4]), GetJsDoubleVal(runtime, argv[5]));
1248     return runtime->NewUndefined();
1249 }
1250 
JsPath2DMoveTo(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1251 shared_ptr<JsValue> JsiCanvasBridge::JsPath2DMoveTo(const shared_ptr<JsRuntime>& runtime,
1252     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1253 {
1254     // 2 parameters: moveTo(x, y)
1255     if (argc != 2) {
1256         LOGE("Call Path2D Arc MoveTo, invalid args.");
1257         return runtime->NewUndefined();
1258     }
1259     int32_t id = -1;
1260     auto nodeId = value->GetProperty(runtime, "__id");
1261     if (nodeId && nodeId->IsInt32(runtime)) {
1262         id = nodeId->ToInt32(runtime);
1263     }
1264     if (id < 0) {
1265         return runtime->NewUndefined();
1266     }
1267     auto holderPath = path2Ds_[id];
1268     if (holderPath == nullptr) {
1269         LOGE("Call Path2D MoveTo failed, holderPath is null.");
1270         return runtime->NewUndefined();
1271     }
1272     holderPath->MoveTo(GetJsDoubleVal(runtime, argv[0]), GetJsDoubleVal(runtime, argv[1]));
1273     return runtime->NewUndefined();
1274 }
1275 
JsPath2DLineTo(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1276 shared_ptr<JsValue> JsiCanvasBridge::JsPath2DLineTo(const shared_ptr<JsRuntime>& runtime,
1277     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1278 {
1279     // 2 parameters: lineTo(x, y)
1280     if (argc != 2) {
1281         LOGE("Call Path2D LineTo failed, invalid args.");
1282         return runtime->NewUndefined();
1283     }
1284     int32_t id = -1;
1285     auto nodeId = value->GetProperty(runtime, "__id");
1286     if (nodeId && nodeId->IsInt32(runtime)) {
1287         id = nodeId->ToInt32(runtime);
1288     }
1289     if (id < 0) {
1290         return runtime->NewUndefined();
1291     }
1292     auto holderPath = path2Ds_[id];
1293     if (holderPath == nullptr) {
1294         LOGE("Call Path2D LineTo failed, holderPath is null.");
1295         return runtime->NewUndefined();
1296     }
1297     holderPath->LineTo(GetJsDoubleVal(runtime, argv[0]), GetJsDoubleVal(runtime, argv[1]));
1298     return runtime->NewUndefined();
1299 }
1300 
JsPath2DArc(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1301 shared_ptr<JsValue> JsiCanvasBridge::JsPath2DArc(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value,
1302     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1303 {
1304     // 5 or 6 parameters: arc(x, y, radius, startAngle, endAngle, anticlockwise?)
1305     if (argc < 5 || argc > 6) {
1306         LOGE("Call Path2D Arc failed, invalid args.");
1307         return runtime->NewUndefined();
1308     }
1309     int32_t id = -1;
1310     auto nodeId = value->GetProperty(runtime, "__id");
1311     if (nodeId && nodeId->IsInt32(runtime)) {
1312         id = nodeId->ToInt32(runtime);
1313     }
1314     if (id < 0) {
1315         return runtime->NewUndefined();
1316     }
1317     auto holderPath = path2Ds_[id];
1318     if (holderPath == nullptr) {
1319         LOGE("Call Path2D Arc failed, holderPath is null.");
1320         return runtime->NewUndefined();
1321     }
1322     bool anticlockwise = false;
1323     if (argc == 6) {
1324         int32_t anti = static_cast<int32_t>(GetJsDoubleVal(runtime, argv[7]));
1325         anticlockwise = (anti == 1);
1326     }
1327     holderPath->Arc(GetJsDoubleVal(runtime, argv[0]), GetJsDoubleVal(runtime, argv[1]),
1328                     GetJsDoubleVal(runtime, argv[2]), GetJsDoubleVal(runtime, argv[3]),
1329                     GetJsDoubleVal(runtime, argv[4]), anticlockwise);
1330     return runtime->NewUndefined();
1331 }
1332 
JsPath2DArcTo(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1333 shared_ptr<JsValue> JsiCanvasBridge::JsPath2DArcTo(const shared_ptr<JsRuntime>& runtime,
1334     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1335 {
1336     // 5 parameters: arcTo(x1, y1, x2, y2, radius)
1337     if (argc != 5) {
1338         LOGE("Call Path2D ArcTo failed, invalid args.");
1339         return runtime->NewUndefined();
1340     }
1341     int32_t id = -1;
1342     auto nodeId = value->GetProperty(runtime, "__id");
1343     if (nodeId && nodeId->IsInt32(runtime)) {
1344         id = nodeId->ToInt32(runtime);
1345     }
1346     if (id < 0) {
1347         return runtime->NewUndefined();
1348     }
1349     auto holderPath = path2Ds_[id];
1350     if (holderPath == nullptr) {
1351         LOGE("Call Path2D ArcTo failed, holderPath is null.");
1352         return runtime->NewUndefined();
1353     }
1354     holderPath->ArcTo(GetJsDoubleVal(runtime, argv[0]), GetJsDoubleVal(runtime, argv[1]),
1355         GetJsDoubleVal(runtime, argv[2]), GetJsDoubleVal(runtime, argv[3]), GetJsDoubleVal(runtime, argv[4]));
1356     return runtime->NewUndefined();
1357 }
1358 
JsPath2DQuadraticCurveTo(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1359 shared_ptr<JsValue> JsiCanvasBridge::JsPath2DQuadraticCurveTo(const shared_ptr<JsRuntime>& runtime,
1360     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1361 {
1362     // 4 parameters: quadraticCurveTo(cpx, cpy, x, y)
1363     if (argc != 4) {
1364         LOGE("Call Path2D QuadraticCurveTo failed, invalid args.");
1365         return runtime->NewUndefined();
1366     }
1367     int32_t id = -1;
1368     auto nodeId = value->GetProperty(runtime, "__id");
1369     if (nodeId && nodeId->IsInt32(runtime)) {
1370         id = nodeId->ToInt32(runtime);
1371     }
1372     if (id < 0) {
1373         return runtime->NewUndefined();
1374     }
1375     auto holderPath = path2Ds_[id];
1376     if (holderPath == nullptr) {
1377         LOGE("Call Path2D QuadraticCurveTo failed, holderPath is null.");
1378         return runtime->NewUndefined();
1379     }
1380     holderPath->QuadraticCurveTo(GetJsDoubleVal(runtime, argv[0]), GetJsDoubleVal(runtime, argv[1]),
1381                                  GetJsDoubleVal(runtime, argv[2]), GetJsDoubleVal(runtime, argv[3]));
1382     return runtime->NewUndefined();
1383 }
1384 
JsPath2DBezierCurveTo(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1385 shared_ptr<JsValue> JsiCanvasBridge::JsPath2DBezierCurveTo(const shared_ptr<JsRuntime>& runtime,
1386     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1387 {
1388     // 6 parameters: bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
1389     if (argc != 6) {
1390         LOGE("Call Path2D BezierCurveTo failed, invalid args.");
1391         return runtime->NewUndefined();
1392     }
1393     int32_t id = -1;
1394     auto nodeId = value->GetProperty(runtime, "__id");
1395     if (nodeId && nodeId->IsInt32(runtime)) {
1396         id = nodeId->ToInt32(runtime);
1397     }
1398     if (id < 0) {
1399         return runtime->NewUndefined();
1400     }
1401     auto holderPath = path2Ds_[id];
1402     if (holderPath == nullptr) {
1403         LOGE("Call Path2D BezierCurveTo failed, holderPath is null.");
1404         return runtime->NewUndefined();
1405     }
1406     holderPath->BezierCurveTo(GetJsDoubleVal(runtime, argv[0]), GetJsDoubleVal(runtime, argv[1]),
1407                               GetJsDoubleVal(runtime, argv[2]), GetJsDoubleVal(runtime, argv[3]),
1408                               GetJsDoubleVal(runtime, argv[4]), GetJsDoubleVal(runtime, argv[5]));
1409     return runtime->NewUndefined();
1410 }
1411 
JsPath2DEllipse(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1412 shared_ptr<JsValue> JsiCanvasBridge::JsPath2DEllipse(const shared_ptr<JsRuntime>& runtime,
1413     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1414 {
1415     // 7 or 8 parameters: ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise?)
1416     if (argc < 7 || argc > 8) {
1417         LOGE("Call Path2D Ellipse failed, invalid args.");
1418         return runtime->NewUndefined();
1419     }
1420     int32_t id = -1;
1421     auto nodeId = value->GetProperty(runtime, "__id");
1422     if (nodeId && nodeId->IsInt32(runtime)) {
1423         id = nodeId->ToInt32(runtime);
1424     }
1425     if (id < 0) {
1426         return runtime->NewUndefined();
1427     }
1428     auto holderPath = path2Ds_[id];
1429     if (holderPath == nullptr) {
1430         LOGE("Call Path2D Ellipse failed, holderPath is null.");
1431         return runtime->NewUndefined();
1432     }
1433     bool anticlockwise = false;
1434     if (argc == 8) {
1435         int32_t anti = static_cast<int32_t>(GetJsDoubleVal(runtime, argv[7]));
1436         anticlockwise = (anti == 1);
1437     }
1438     holderPath->Ellipse(GetJsDoubleVal(runtime, argv[0]), GetJsDoubleVal(runtime, argv[1]),
1439                         GetJsDoubleVal(runtime, argv[2]), GetJsDoubleVal(runtime, argv[3]),
1440                         GetJsDoubleVal(runtime, argv[4]), GetJsDoubleVal(runtime, argv[5]),
1441                         GetJsDoubleVal(runtime, argv[6]), anticlockwise);
1442     return runtime->NewUndefined();
1443 }
1444 
JsPath2DRect(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1445 shared_ptr<JsValue> JsiCanvasBridge::JsPath2DRect(const shared_ptr<JsRuntime>& runtime,
1446     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1447 {
1448     // 4 parameters: rect(x, y, width, height)
1449     if (argc != 4) {
1450         LOGE("Call Path2D Rect failed, invalid args.");
1451         return runtime->NewUndefined();
1452     }
1453     int32_t id = -1;
1454     auto nodeId = value->GetProperty(runtime, "__id");
1455     if (nodeId && nodeId->IsInt32(runtime)) {
1456         id = nodeId->ToInt32(runtime);
1457     }
1458     if (id < 0) {
1459         return runtime->NewUndefined();
1460     }
1461     auto holderPath = path2Ds_[id];
1462     if (holderPath == nullptr) {
1463         LOGE("Call Path2D Rect failed, holderPath is null.");
1464         return runtime->NewUndefined();
1465     }
1466     holderPath->Rect(GetJsDoubleVal(runtime, argv[0]), GetJsDoubleVal(runtime, argv[1]),
1467         GetJsDoubleVal(runtime, argv[2]), GetJsDoubleVal(runtime, argv[3]));
1468     return runtime->NewUndefined();
1469 }
1470 
JsPath2DClosePath(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1471 shared_ptr<JsValue> JsiCanvasBridge::JsPath2DClosePath(const shared_ptr<JsRuntime>& runtime,
1472     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1473 {
1474     int32_t id = -1;
1475     auto nodeId = value->GetProperty(runtime, "__id");
1476     if (nodeId && nodeId->IsInt32(runtime)) {
1477         id = nodeId->ToInt32(runtime);
1478     }
1479     if (id < 0) {
1480         return runtime->NewUndefined();
1481     }
1482     auto holderPath = path2Ds_[id];
1483     if (holderPath == nullptr) {
1484         LOGE("Call Path2D ClosePath failed, holderPath is null.");
1485         return runtime->NewUndefined();
1486     }
1487     holderPath->ClosePath();
1488     return runtime->NewUndefined();
1489 }
1490 
JsMakePath2D(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1491 RefPtr<CanvasPath2D> JsiCanvasBridge::JsMakePath2D(const shared_ptr<JsRuntime>& runtime,
1492     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1493 {
1494     if (argc == 1) {
1495         if (argv[0]->IsString(runtime)) {
1496             // Example: ctx.createPath2D("M250 150 L150 350 L350 350 Z")
1497             return AceType::MakeRefPtr<CanvasPath2D>(argv[0]->ToString(runtime));
1498         } else {
1499             auto typeVal = argv[0]->GetProperty(runtime, "__type");
1500             auto type = typeVal->ToString(runtime);
1501             if (type == "path2d") {
1502                 // Example: ctx.createPath2D(path1)
1503                 return AceType::MakeRefPtr<CanvasPath2D>(GetPath2D(runtime, argv[0]));
1504             }
1505         }
1506     }
1507     // Example: ctx.createPath2D()
1508     return AceType::MakeRefPtr<CanvasPath2D>();
1509 }
1510 
GetPath2D(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value)1511 RefPtr<CanvasPath2D> JsiCanvasBridge::GetPath2D(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value)
1512 {
1513     if (!runtime || !value) {
1514         LOGE("runtime or value is null.");
1515         return nullptr;
1516     }
1517     auto nodeId = value->GetProperty(runtime, "__id");
1518     if (nodeId && nodeId->IsInt32(runtime)) {
1519         auto id = nodeId->ToInt32(runtime);
1520         if (id >= 0) {
1521             return path2Ds_[id];
1522         }
1523     }
1524     return nullptr;
1525 }
1526 
JsCreatePattern(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1527 shared_ptr<JsValue> JsiCanvasBridge::JsCreatePattern(const shared_ptr<JsRuntime>& runtime,
1528     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1529 {
1530     if (argc != 2) {
1531         LOGE("argc error, argc = %{private}d", argc);
1532         return runtime->NewUndefined();
1533     }
1534 
1535     auto pattern = runtime->NewObject();
1536     pattern->SetProperty(runtime, "__id", runtime->NewInt32(patternCount_));
1537     pattern->SetProperty(runtime, "__type", runtime->NewString("pattern"));
1538     if (!argv[0] || !argv[0]->IsObject(runtime)) {
1539         return runtime->NewUndefined();
1540     }
1541 
1542     double width = 0.0;
1543     double height = 0.0;
1544     std::string imageSrc;
1545     auto jsSrc = argv[0]->GetProperty(runtime, DOM_SRC);
1546     if (!jsSrc || !jsSrc->IsString(runtime)) {
1547         ParseDomImage(runtime, argv[0], width, height, imageSrc);
1548     } else {
1549         auto jsWidth = argv[0]->GetProperty(runtime, DOM_WIDTH);
1550         auto jsHeight = argv[0]->GetProperty(runtime, DOM_HEIGHT);
1551         imageSrc = jsSrc->ToString(runtime);
1552         width = jsWidth->ToDouble(runtime);
1553         height = jsHeight->ToDouble(runtime);
1554     }
1555     auto repeat = argv[1]->ToString(runtime);
1556     pattern_[patternCount_].SetImgSrc(imageSrc);
1557     pattern_[patternCount_].SetImageWidth(width);
1558     pattern_[patternCount_].SetImageHeight(height);
1559     pattern_[patternCount_].SetRepetition(repeat);
1560     ++patternCount_;
1561     return pattern;
1562 }
1563 
GetPattern(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value)1564 Pattern JsiCanvasBridge::GetPattern(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value)
1565 {
1566     int32_t id = -1;
1567     auto nodeId = value->GetProperty(runtime, "__id");
1568     if (nodeId && nodeId->IsInt32(runtime)) {
1569         id = nodeId->ToInt32(runtime);
1570     }
1571     return id < 0 ? Pattern() : pattern_[id];
1572 }
1573 
JsCreateImageData(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1574 shared_ptr<JsValue> JsiCanvasBridge::JsCreateImageData(const shared_ptr<JsRuntime>& runtime,
1575     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1576 {
1577     if (argc != 1 && argc != 2) {
1578         return runtime->NewUndefined();
1579     }
1580 
1581     auto imageData = runtime->NewObject();
1582     int32_t width = 0;
1583     int32_t height = 0;
1584 
1585     if (argc == 2) {
1586         width = argv[0]->ToInt32(runtime);
1587         height = argv[1]->ToInt32(runtime);
1588     }
1589 
1590     if (argc == 1 && argv[0]->IsObject(runtime)) {
1591         auto jsWidth = argv[0]->GetProperty(runtime, DOM_WIDTH);
1592         auto jsHeight = argv[0]->GetProperty(runtime, DOM_HEIGHT);
1593         width = jsWidth->ToInt32(runtime);
1594         height = jsHeight->ToInt32(runtime);
1595     }
1596 
1597     auto colorArray = runtime->NewArray();
1598     auto color = runtime->NewInt32(255);
1599     uint32_t count = 0;
1600     for (auto i = 0; i < width; i++) {
1601         for (auto j = 0; j < height; j++) {
1602             colorArray->SetProperty(runtime, runtime->NewInt32(count), color);
1603             colorArray->SetProperty(runtime, runtime->NewInt32(count + 1), color);
1604             colorArray->SetProperty(runtime, runtime->NewInt32(count + 2), color);
1605             colorArray->SetProperty(runtime, runtime->NewInt32(count + 3), color);
1606             count += 4;
1607         }
1608     }
1609     imageData->SetProperty(runtime, DOM_WIDTH, runtime->NewInt32(width));
1610     imageData->SetProperty(runtime, DOM_HEIGHT, runtime->NewInt32(height));
1611     imageData->SetProperty(runtime, "data", colorArray);
1612     return imageData;
1613 }
1614 
JsPutImageData(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1615 shared_ptr<JsValue> JsiCanvasBridge::JsPutImageData(const shared_ptr<JsRuntime>& runtime,
1616     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1617 {
1618     if (argc != 3 && argc != 7 && !argv[0]->IsObject(runtime)) {
1619         return runtime->NewUndefined();
1620     }
1621 
1622     int32_t width = 0;
1623     int32_t height = 0;
1624     auto jsWidth = argv[0]->GetProperty(runtime, DOM_WIDTH);
1625     auto jsHeight = argv[0]->GetProperty(runtime, DOM_HEIGHT);
1626     width = jsWidth->ToInt32(runtime);
1627     height = jsHeight->ToInt32(runtime);
1628     ImageData imageData;
1629     std::vector<std::string> array;
1630     ParseImageData(runtime, argv, argc, array, imageData);
1631 
1632     int64_t num = 0;
1633     for (int32_t i = 0; i < height; ++i) {
1634         for (int32_t j = 0; j < width; ++j) {
1635             if ((i >= imageData.dirtyY) && (i - imageData.dirtyY < imageData.dirtyHeight) && (j >= imageData.dirtyX) &&
1636                 (j - imageData.dirtyX < imageData.dirtyWidth)) {
1637                 int32_t flag = j + width * i;
1638                 if (array.size() > static_cast<uint32_t>(4 * flag + 3)) {
1639                     auto red = StringUtils::StringToInt(array[4 * flag]);
1640                     auto green = StringUtils::StringToInt(array[4 * flag + 1]);
1641                     auto blue = StringUtils::StringToInt(array[4 * flag + 2]);
1642                     auto alpha = StringUtils::StringToInt(array[4 * flag + 3]);
1643                     if (num < imageData.dirtyWidth * imageData.dirtyHeight) {
1644                         imageData.data.emplace_back(Color::FromARGB(alpha, red, green, blue).GetValue());
1645                     }
1646                     num++;
1647                 }
1648             }
1649         }
1650     }
1651 
1652     auto task = [imageData](const RefPtr<CanvasTaskPool>& pool) { pool->PutImageData(imageData); };
1653     PushTaskToPage(runtime, value, task);
1654     return runtime->NewUndefined();
1655 }
1656 
ParseImageData(const shared_ptr<JsRuntime> & runtime,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc,std::vector<std::string> & array,ImageData & imageData)1657 void JsiCanvasBridge::ParseImageData(const shared_ptr<JsRuntime>& runtime, const std::vector<shared_ptr<JsValue>>& argv,
1658     int32_t argc, std::vector<std::string>& array, ImageData& imageData)
1659 {
1660     int32_t width = 0;
1661     int32_t height = 0;
1662     auto jsWidth = argv[0]->GetProperty(runtime, DOM_WIDTH);
1663     auto jsHeight = argv[0]->GetProperty(runtime, DOM_HEIGHT);
1664     width = jsWidth->ToInt32(runtime);
1665     height = jsHeight->ToInt32(runtime);
1666 
1667     auto jsData = argv[0]->GetProperty(runtime, "data");
1668     auto jsDataStr = jsData->ToString(runtime);
1669     StringUtils::StringSplitter(jsDataStr, ',', array);
1670 
1671     imageData.x = argv[1]->ToInt32(runtime);
1672     imageData.y = argv[2]->ToInt32(runtime);
1673     imageData.dirtyWidth = width;
1674     imageData.dirtyHeight = height;
1675 
1676     if (argc == 7) {
1677         imageData.dirtyX = argv[3]->ToInt32(runtime);
1678         imageData.dirtyY = argv[4]->ToInt32(runtime);
1679         imageData.dirtyWidth = argv[5]->ToInt32(runtime);
1680         imageData.dirtyHeight = argv[6]->ToInt32(runtime);
1681     }
1682 
1683     imageData.dirtyWidth = imageData.dirtyX < 0 ? std::min(imageData.dirtyX + imageData.dirtyWidth, width)
1684                                                 : std::min(width - imageData.dirtyX, imageData.dirtyWidth);
1685     imageData.dirtyHeight = imageData.dirtyY < 0 ? std::min(imageData.dirtyY + imageData.dirtyHeight, height)
1686                                                  : std::min(height - imageData.dirtyY, imageData.dirtyHeight);
1687 }
1688 
JsGetImageData(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1689 shared_ptr<JsValue> JsiCanvasBridge::JsGetImageData(const shared_ptr<JsRuntime>& runtime,
1690     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1691 {
1692     if (argc != 4) {
1693         return runtime->NewUndefined();
1694     }
1695     Rect rect = GetJsRectParam(runtime, argc, std::move(argv));
1696     NodeId id = GetCurrentNodeId(runtime, value);
1697     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
1698     if (!engine) {
1699         LOGE("JsGetImageData failed. engine is null.");
1700         return runtime->NewUndefined();
1701     }
1702     auto page = engine->GetRunningPage();
1703     if (!page) {
1704         LOGE("JsGetImageData failed. page is null.");
1705         return runtime->NewUndefined();
1706     }
1707     std::unique_ptr<ImageData> data;
1708     auto task = [id, page, &rect, &data]() {
1709         auto canvas = AceType::DynamicCast<DOMCanvas>(page->GetDomDocument()->GetDOMNodeById(id));
1710         if (!canvas) {
1711             return;
1712         }
1713         auto paintChild = AceType::DynamicCast<CustomPaintComponent>(canvas->GetSpecializedComponent());
1714         auto canvasTask = paintChild->GetTaskPool();
1715         if (!canvasTask) {
1716             return;
1717         }
1718         data = canvasTask->GetImageData(rect.Left(), rect.Top(), rect.Width(), rect.Height());
1719     };
1720     auto delegate = engine->GetFrontendDelegate();
1721     if (!delegate) {
1722         LOGE("JsGetImageData failed. delegate is null.");
1723         return runtime->NewUndefined();
1724     }
1725     delegate->PostSyncTaskToPage(task, "ArkUICanvasGetImageData");
1726 
1727     auto imageData = runtime->NewObject();
1728     auto colorArray = runtime->NewArray();
1729     imageData->SetProperty(runtime, DOM_WIDTH, runtime->NewInt32(data->dirtyWidth));
1730     imageData->SetProperty(runtime, DOM_HEIGHT, runtime->NewInt32(data->dirtyHeight));
1731     uint32_t count = 0;
1732     // travel data
1733     for (auto i = 0; i < data->dirtyHeight; i++) {
1734         for (auto j = 0; j < data->dirtyWidth; j++) {
1735             // a pixel includes 4 data: red/green/blue/alpha
1736             int32_t idx = i * data->dirtyWidth + j;
1737             Color pixel = Color(data->data[idx]);
1738             colorArray->SetProperty(runtime, runtime->NewInt32(count), runtime->NewInt32(pixel.GetRed()));
1739             colorArray->SetProperty(runtime, runtime->NewInt32(count + 1), runtime->NewInt32(pixel.GetGreen()));
1740             colorArray->SetProperty(runtime, runtime->NewInt32(count + 2), runtime->NewInt32(pixel.GetBlue()));
1741             colorArray->SetProperty(runtime, runtime->NewInt32(count + 3), runtime->NewInt32(pixel.GetAlpha()));
1742             count += 4;
1743         }
1744     }
1745     imageData->SetProperty(runtime, "data", colorArray);
1746     return imageData;
1747 }
1748 
JsGetPixelMap(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1749 shared_ptr<JsValue>  JsiCanvasBridge::JsGetPixelMap(const shared_ptr<JsRuntime>& runtime,
1750     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1751 {
1752 #ifdef PIXEL_MAP_SUPPORTED
1753     // 0 Get input param
1754     if (argc != 4) {
1755         return runtime->NewUndefined();
1756     }
1757     Rect rect = GetJsRectParam(runtime, argc, std::move(argv));
1758     NodeId id = GetCurrentNodeId(runtime, value);
1759     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
1760     if (!engine) {
1761         LOGE("JsGetImageData failed. engine is null.");
1762         return runtime->NewUndefined();
1763     }
1764     auto page = engine->GetRunningPage();
1765     if (!page) {
1766         LOGE("JsGetImageData failed. page is null.");
1767         return runtime->NewUndefined();
1768     }
1769     std::unique_ptr<ImageData> imageData;
1770     auto task = [id, page, &rect, &imageData]() {
1771         auto canvas = AceType::DynamicCast<DOMCanvas>(page->GetDomDocument()->GetDOMNodeById(id));
1772         if (!canvas) {
1773             return;
1774         }
1775         auto paintChild = AceType::DynamicCast<CustomPaintComponent>(canvas->GetSpecializedComponent());
1776         auto canvasTask = paintChild->GetTaskPool();
1777         if (!canvasTask) {
1778             return;
1779         }
1780         imageData = canvasTask->GetImageData(rect.Left(), rect.Top(), rect.Width(), rect.Height());
1781     };
1782     auto delegate = engine->GetFrontendDelegate();
1783     if (!delegate) {
1784         LOGE("JsGetImageData failed. delegate is null.");
1785         return runtime->NewUndefined();
1786     }
1787     delegate->PostSyncTaskToPage(task, "ArkUICanvasGetImageData");
1788 
1789     // 1 Get data from canvas
1790     uint32_t final_height = static_cast<uint32_t>(imageData->dirtyHeight);
1791     uint32_t final_width = static_cast<uint32_t>(imageData->dirtyWidth);
1792     uint32_t length = final_height * final_width;
1793     uint32_t* data = new uint32_t[length];
1794     for (uint32_t i = 0; i < final_height; i++) {
1795         for (uint32_t j = 0; j < final_width; j++) {
1796             uint32_t idx = i * final_width + j;
1797             data[idx] = imageData->data[idx];
1798         }
1799     }
1800 
1801     // 2 Create pixelmap
1802     OHOS::Media::InitializationOptions options;
1803     options.alphaType = OHOS::Media::AlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
1804     options.pixelFormat = OHOS::Media::PixelFormat::RGBA_8888;
1805     options.scaleMode = OHOS::Media::ScaleMode::CENTER_CROP;
1806     options.size.width = static_cast<int32_t>(final_width);
1807     options.size.height = static_cast<int32_t>(final_height);
1808     options.editable = true;
1809     std::unique_ptr<OHOS::Media::PixelMap> pixelmap = OHOS::Media::PixelMap::Create(data, length, options);
1810     delete[] data;
1811     if (pixelmap == nullptr) {
1812         LOGE(" pixelmap is null.");
1813         return runtime->NewUndefined();
1814     }
1815 
1816     // 3 pixelmap to NapiValue
1817     auto nativeEngine = static_cast<ArkNativeEngine*>(engine->GetNativeEngine());
1818     if (!nativeEngine) {
1819         LOGE("NativeEngine is null");
1820         return runtime->NewUndefined();
1821     }
1822     napi_env env = reinterpret_cast<napi_env>(nativeEngine);
1823     std::shared_ptr<OHOS::Media::PixelMap> sharedPixelmap(pixelmap.release());
1824     napi_value napiValue = OHOS::Media::PixelMapNapi::CreatePixelMap(env, sharedPixelmap);
1825     if (!napiValue) {
1826         LOGE("napiValue is null");
1827         return runtime->NewUndefined();
1828     }
1829 
1830     auto arkRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
1831     if (!arkRuntime) {
1832         LOGE("arkRuntime is null");
1833         return runtime->NewUndefined();
1834     }
1835     auto jsValue = std::make_shared<ArkJSValue>(arkRuntime, NapiValueToLocalValue(napiValue));
1836     if (!jsValue) {
1837         LOGE("jsValue is null");
1838         return runtime->NewUndefined();
1839     }
1840     return jsValue;
1841 #else
1842     LOGW("[Engine Log] The function 'getPixelMap' is not supported on the current platform.");
1843     return runtime->NewUndefined();
1844 #endif
1845 }
1846 
JsGetJsonData(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1847 shared_ptr<JsValue> JsiCanvasBridge::JsGetJsonData(const shared_ptr<JsRuntime>& runtime,
1848     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1849 {
1850     if (argc != 1) {
1851         return runtime->NewUndefined();
1852     }
1853     NodeId id = GetCurrentNodeId(runtime, value);
1854     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
1855     if (!engine) {
1856         LOGE("JsGetJsonData failed. engine is null.");
1857         return runtime->NewUndefined();
1858     }
1859     auto page = engine->GetRunningPage();
1860     if (!page) {
1861         LOGE("JsGetJsonData failed. page is null.");
1862         return runtime->NewUndefined();
1863     }
1864     std::string path = argv[0]->ToString(runtime);
1865     std::string jsonData;
1866     auto task = [id, page, path, &jsonData]() {
1867         auto canvas = AceType::DynamicCast<DOMCanvas>(page->GetDomDocument()->GetDOMNodeById(id));
1868         if (!canvas) {
1869             return;
1870         }
1871         auto paintChild = AceType::DynamicCast<CustomPaintComponent>(canvas->GetSpecializedComponent());
1872         auto canvasTask = paintChild->GetTaskPool();
1873         if (!canvasTask) {
1874             return;
1875         }
1876         jsonData = canvasTask->GetJsonData(path);
1877     };
1878     auto delegate = engine->GetFrontendDelegate();
1879     if (!delegate) {
1880         LOGE("JsGetJsonData failed. delegate is null.");
1881         return runtime->NewUndefined();
1882     }
1883     delegate->PostSyncTaskToPage(task, "ArkUICanvasGetJsonData");
1884 
1885     return runtime->NewString(jsonData.c_str());
1886 }
1887 
JsTransferFromImageBitmap(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1888 shared_ptr<JsValue> JsiCanvasBridge::JsTransferFromImageBitmap(const shared_ptr<JsRuntime>& runtime,
1889     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1890 {
1891     if (argc != 1) {
1892         return runtime->NewUndefined();
1893     }
1894 
1895     int32_t bridgeId = 0;
1896     auto id = argv[0]->GetProperty(runtime, "__bridgeId");
1897     if (id && id->IsInt32(runtime)) {
1898         bridgeId = id->ToInt32(runtime);
1899     }
1900     bridgeId = bridgeId < 0 ? 0 : bridgeId;
1901 
1902     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
1903     if (!engine) {
1904         return runtime->NewUndefined();
1905     }
1906     auto page = engine->GetRunningPage();
1907     if (page) {
1908         RefPtr<JsiOffscreenCanvasBridge> bridge = AceType::DynamicCast<JsiOffscreenCanvasBridge>(
1909             page->GetOffscreenCanvasBridgeById(bridgeId));
1910         if (bridge) {
1911             auto offscreenCanvas = bridge->GetOffscreenCanvas();
1912             auto task = [offscreenCanvas](const RefPtr<CanvasTaskPool>& pool) {
1913                 pool->TransferFromImageBitmap(offscreenCanvas);
1914             };
1915             PushTaskToPage(runtime, value, task);
1916         }
1917     }
1918     return runtime->NewUndefined();
1919 }
1920 
JsDrawBitmapMesh(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1921 shared_ptr<JsValue> JsiCanvasBridge::JsDrawBitmapMesh(const shared_ptr<JsRuntime>& runtime,
1922     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1923 {
1924     if (argc != 4) {
1925         return runtime->NewUndefined();
1926     }
1927     int32_t bridgeId = 0;
1928     auto id = argv[0]->GetProperty(runtime, "__bridgeId");
1929     if (id && id->IsInt32(runtime)) {
1930         bridgeId = id->ToInt32(runtime);
1931     }
1932     bridgeId = bridgeId < 0 ? 0 : bridgeId;
1933     auto mesh = GetJsDashValue(runtime, argv[1]);
1934     int32_t column = argv[2]->ToInt32(runtime);
1935     int32_t row = argv[3]->ToInt32(runtime);
1936 
1937     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
1938     if (!engine) {
1939         return runtime->NewUndefined();
1940     }
1941     auto page = engine->GetRunningPage();
1942     if (page) {
1943         RefPtr<JsiOffscreenCanvasBridge> bridge = AceType::DynamicCast<JsiOffscreenCanvasBridge>(
1944             page->GetOffscreenCanvasBridgeById(bridgeId));
1945         if (bridge) {
1946             auto offscreenCanvas = bridge->GetOffscreenCanvas();
1947             auto task = [offscreenCanvas, mesh, column, row](const RefPtr<CanvasTaskPool>& pool) {
1948                 pool->DrawBitmapMesh(offscreenCanvas, mesh, column, row);
1949             };
1950             PushTaskToPage(runtime, value, task);
1951         }
1952     }
1953     return runtime->NewUndefined();
1954 }
1955 
JsFillStyleGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1956 shared_ptr<JsValue> JsiCanvasBridge::JsFillStyleGetter(const shared_ptr<JsRuntime>& runtime,
1957     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1958 {
1959     return value->GetProperty(runtime, "__fillStyle");
1960 }
1961 
JsFillStyleSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1962 shared_ptr<JsValue> JsiCanvasBridge::JsFillStyleSetter(const shared_ptr<JsRuntime>& runtime,
1963     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1964 {
1965     if (argv.empty() || argc == 0) {
1966         return runtime->NewUndefined();
1967     }
1968     auto proto = argv[0];
1969     if (!proto) {
1970         return runtime->NewUndefined();
1971     }
1972     if (proto->IsString(runtime)) {
1973         auto colorStr = proto->ToString(runtime);
1974         auto color = Color::FromString(colorStr);
1975         auto task = [color](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateFillColor(color); };
1976         PushTaskToPage(runtime, value, task);
1977     } else {
1978         auto typeVal = proto->GetProperty(runtime, "__type");
1979         auto type = typeVal->ToString(runtime);
1980         if (type == "gradient") {
1981             auto gradient = GetGradient(runtime, proto);
1982             auto task = [gradient](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateFillGradient(gradient); };
1983             PushTaskToPage(runtime, value, task);
1984         } else if (type == "pattern") {
1985             auto pattern = GetPattern(runtime, proto);
1986             auto task = [pattern](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateFillPattern(pattern); };
1987             PushTaskToPage(runtime, value, task);
1988         } else {
1989             LOGW("No such type for fill style.");
1990         }
1991     }
1992     value->SetProperty(runtime, "__fillStyle", proto);
1993     return runtime->NewUndefined();
1994 }
1995 
JsStrokeStyleGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)1996 shared_ptr<JsValue> JsiCanvasBridge::JsStrokeStyleGetter(const shared_ptr<JsRuntime>& runtime,
1997     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
1998 {
1999     return value->GetProperty(runtime, "__strokeStyle");
2000 }
2001 
JsStrokeStyleSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2002 shared_ptr<JsValue> JsiCanvasBridge::JsStrokeStyleSetter(const shared_ptr<JsRuntime>& runtime,
2003     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2004 {
2005     if (argv.empty() || argc == 0) {
2006         return runtime->NewUndefined();
2007     }
2008     auto proto = argv[0];
2009     if (!proto) {
2010         return runtime->NewUndefined();
2011     }
2012     if (proto->IsString(runtime)) {
2013         auto colorStr = proto->ToString(runtime);
2014         auto color = Color::FromString(colorStr);
2015         auto task = [color](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateStrokeColor(color); };
2016         PushTaskToPage(runtime, value, task);
2017     } else {
2018         auto typeVal = proto->GetProperty(runtime, "__type");
2019         auto type = typeVal->ToString(runtime);
2020         if (type == "gradient") {
2021             auto gradient = GetGradient(runtime, proto);
2022             auto task = [gradient](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateStrokeGradient(gradient); };
2023             PushTaskToPage(runtime, value, task);
2024         } else if (type == "pattern") {
2025             auto pattern = GetPattern(runtime, proto);
2026             auto task = [pattern](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateStrokePattern(pattern); };
2027             PushTaskToPage(runtime, value, task);
2028         } else {
2029             LOGW("No such type for stroke style.");
2030         }
2031     }
2032     value->SetProperty(runtime, "__strokeStyle", proto);
2033     return runtime->NewUndefined();
2034 }
2035 
JsLineCapGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2036 shared_ptr<JsValue> JsiCanvasBridge::JsLineCapGetter(const shared_ptr<JsRuntime>& runtime,
2037     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2038 {
2039     return value->GetProperty(runtime, "__lineCap");
2040 }
2041 
JsLineCapSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2042 shared_ptr<JsValue> JsiCanvasBridge::JsLineCapSetter(const shared_ptr<JsRuntime>& runtime,
2043     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2044 {
2045     if (argv.empty() || argc == 0) {
2046         return runtime->NewUndefined();
2047     }
2048     auto proto = argv[0];
2049     if (!proto) {
2050         return runtime->NewUndefined();
2051     }
2052     auto capStr = proto->ToString(runtime);
2053     static const LinearMapNode<LineCapStyle> lineCapTable[] = {
2054         { "butt", LineCapStyle::BUTT },
2055         { "round", LineCapStyle::ROUND },
2056         { "square", LineCapStyle::SQUARE },
2057     };
2058     auto lineCap = ConvertStrToEnum(capStr.c_str(), lineCapTable, ArraySize(lineCapTable), LineCapStyle::BUTT);
2059     auto task = [lineCap](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateLineCap(lineCap); };
2060     PushTaskToPage(runtime, value, task);
2061     value->SetProperty(runtime, "__lineCap", proto);
2062     return runtime->NewUndefined();
2063 }
2064 
JsLineJoinGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2065 shared_ptr<JsValue> JsiCanvasBridge::JsLineJoinGetter(const shared_ptr<JsRuntime>& runtime,
2066     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2067 {
2068     return value->GetProperty(runtime, "__lineJoin");
2069 }
2070 
JsLineJoinSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2071 shared_ptr<JsValue> JsiCanvasBridge::JsLineJoinSetter(const shared_ptr<JsRuntime>& runtime,
2072     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2073 {
2074     if (argv.empty() || argc == 0) {
2075         return runtime->NewUndefined();
2076     }
2077     auto proto = argv[0];
2078     if (!proto) {
2079         return runtime->NewUndefined();
2080     }
2081     auto joinStr = proto->ToString(runtime);
2082     static const LinearMapNode<LineJoinStyle> lineJoinTable[3] = {
2083         { "bevel", LineJoinStyle::BEVEL },
2084         { "miter", LineJoinStyle::MITER },
2085         { "round", LineJoinStyle::ROUND },
2086     };
2087     auto lineJoin = ConvertStrToEnum(joinStr.c_str(), lineJoinTable, ArraySize(lineJoinTable), LineJoinStyle::MITER);
2088     auto task = [lineJoin](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateLineJoin(lineJoin); };
2089     PushTaskToPage(runtime, value, task);
2090     value->SetProperty(runtime, "__lineJoin", proto);
2091     return runtime->NewUndefined();
2092 }
2093 
JsMiterLimitGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2094 shared_ptr<JsValue> JsiCanvasBridge::JsMiterLimitGetter(const shared_ptr<JsRuntime>& runtime,
2095     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2096 {
2097     return value->GetProperty(runtime, "__miterLimit");
2098 }
2099 
JsMiterLimitSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2100 shared_ptr<JsValue> JsiCanvasBridge::JsMiterLimitSetter(const shared_ptr<JsRuntime>& runtime,
2101     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2102 {
2103     if (argv.empty() || argc == 0) {
2104         return runtime->NewUndefined();
2105     }
2106     auto proto = argv[0];
2107     if (!proto) {
2108         return runtime->NewUndefined();
2109     }
2110     double limit = GetJsDoubleVal(runtime, proto);
2111     auto task = [limit](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateMiterLimit(limit); };
2112     PushTaskToPage(runtime, value, task);
2113     value->SetProperty(runtime, "__miterLimit", proto);
2114     return runtime->NewUndefined();
2115 }
2116 
JsLineWidthGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2117 shared_ptr<JsValue> JsiCanvasBridge::JsLineWidthGetter(const shared_ptr<JsRuntime>& runtime,
2118     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2119 {
2120     return value->GetProperty(runtime, "__lineWidth");
2121 }
2122 
JsLineWidthSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2123 shared_ptr<JsValue> JsiCanvasBridge::JsLineWidthSetter(const shared_ptr<JsRuntime>& runtime,
2124     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2125 {
2126     if (argv.empty() || argc == 0) {
2127         return runtime->NewUndefined();
2128     }
2129     auto proto = argv[0];
2130     if (!proto) {
2131         return runtime->NewUndefined();
2132     }
2133     double lineWidth = GetJsDoubleVal(runtime, proto);
2134     auto task = [lineWidth](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateLineWidth(lineWidth); };
2135     PushTaskToPage(runtime, value, task);
2136     value->SetProperty(runtime, "__lineWidth", proto);
2137     return runtime->NewUndefined();
2138 }
2139 
JsTextAlignGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2140 shared_ptr<JsValue> JsiCanvasBridge::JsTextAlignGetter(const shared_ptr<JsRuntime>& runtime,
2141     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2142 {
2143     return value->GetProperty(runtime, "__textAlign");
2144 }
2145 
JsTextAlignSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2146 shared_ptr<JsValue> JsiCanvasBridge::JsTextAlignSetter(const shared_ptr<JsRuntime>& runtime,
2147     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2148 {
2149     if (argv.empty() || argc == 0) {
2150         return runtime->NewUndefined();
2151     }
2152     auto proto = argv[0];
2153     if (!proto) {
2154         return runtime->NewUndefined();
2155     }
2156     auto alignStr = proto->ToString(runtime);
2157     auto align = ConvertStrToTextAlign(alignStr);
2158     auto task = [align](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateTextAlign(align); };
2159     PushTaskToPage(runtime, value, task);
2160     value->SetProperty(runtime, "__textAlign", proto);
2161     return runtime->NewUndefined();
2162 }
2163 
JsTextBaselineGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2164 shared_ptr<JsValue> JsiCanvasBridge::JsTextBaselineGetter(const shared_ptr<JsRuntime>& runtime,
2165     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2166 {
2167     return value->GetProperty(runtime, "__textBaseline");
2168 }
2169 
JsTextBaselineSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2170 shared_ptr<JsValue> JsiCanvasBridge::JsTextBaselineSetter(const shared_ptr<JsRuntime>& runtime,
2171     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2172 {
2173     if (argv.empty() || argc == 0) {
2174         return runtime->NewUndefined();
2175     }
2176     auto proto = argv[0];
2177     if (!proto) {
2178         return runtime->NewUndefined();
2179     }
2180     auto baselineStr = proto->ToString(runtime);
2181     auto baseline =
2182         ConvertStrToEnum(baselineStr.c_str(), BASELINE_TABLE, ArraySize(BASELINE_TABLE), TextBaseline::ALPHABETIC);
2183     auto task = [baseline](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateTextBaseline(baseline); };
2184     PushTaskToPage(runtime, value, task);
2185     value->SetProperty(runtime, "__textBaseline", proto);
2186     return runtime->NewUndefined();
2187 }
2188 
JsFontGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2189 shared_ptr<JsValue> JsiCanvasBridge::JsFontGetter(const shared_ptr<JsRuntime>& runtime,
2190     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2191 {
2192     return value->GetProperty(runtime, "__font");
2193 }
2194 
JsFontSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2195 shared_ptr<JsValue> JsiCanvasBridge::JsFontSetter(const shared_ptr<JsRuntime>& runtime,
2196     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2197 {
2198     if (argv.empty() || argc == 0) {
2199         return runtime->NewUndefined();
2200     }
2201     auto proto = argv[0];
2202     if (!proto) {
2203         return runtime->NewUndefined();
2204     }
2205     auto fontStr = proto->ToString(runtime);
2206     std::vector<std::string> fontProps;
2207     StringUtils::StringSplitter(fontStr, ' ', fontProps);
2208     for (const auto& fontProp : fontProps) {
2209         if (FONT_STYLES.find(fontProp) != FONT_STYLES.end()) {
2210             auto fontStyle = ConvertStrToFontStyle(fontProp);
2211             auto task = [fontStyle](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateFontStyle(fontStyle); };
2212             PushTaskToPage(runtime, value, task);
2213         } else if (FONT_WEIGHTS.find(fontProp) != FONT_WEIGHTS.end()) {
2214             auto weight = ConvertStrToFontWeight(fontProp);
2215             auto task = [weight](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateFontWeight(weight); };
2216             PushTaskToPage(runtime, value, task);
2217         } else if (FONT_FAMILIES.find(fontProp) != FONT_FAMILIES.end()) {
2218             auto families = ConvertStrToFontFamilies(fontProp);
2219             auto task = [families](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateFontFamilies(families); };
2220             PushTaskToPage(runtime, value, task);
2221         } else if (fontProp.find("px") != std::string::npos) {
2222             std::string fontSize = fontProp.substr(0, fontProp.size() - 2);
2223             auto size = Dimension(StringToDouble(fontProp));
2224             auto task = [size](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateFontSize(size); };
2225             PushTaskToPage(runtime, value, task);
2226         } else {
2227             LOGW("parse text error");
2228         }
2229     }
2230     value->SetProperty(runtime, "__font", proto);
2231     return runtime->NewUndefined();
2232 }
2233 
JsAlphaGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2234 shared_ptr<JsValue> JsiCanvasBridge::JsAlphaGetter(const shared_ptr<JsRuntime>& runtime,
2235     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2236 {
2237     return value->GetProperty(runtime, "__globalAlpha");
2238 }
2239 
JsAlphaSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2240 shared_ptr<JsValue> JsiCanvasBridge::JsAlphaSetter(const shared_ptr<JsRuntime>& runtime,
2241     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2242 {
2243     if (argv.empty() || argc == 0) {
2244         return runtime->NewUndefined();
2245     }
2246     auto proto = argv[0];
2247     if (!proto) {
2248         return runtime->NewUndefined();
2249     }
2250     double alpha = GetJsDoubleVal(runtime, proto);
2251     auto task = [alpha](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateGlobalAlpha(alpha); };
2252     PushTaskToPage(runtime, value, task);
2253     value->SetProperty(runtime, "__globalAlpha", proto);
2254     return runtime->NewUndefined();
2255 }
2256 
JsCompositeOperationGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2257 shared_ptr<JsValue> JsiCanvasBridge::JsCompositeOperationGetter(const shared_ptr<JsRuntime>& runtime,
2258     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2259 {
2260     return value->GetProperty(runtime, "__globalCompositeOperation");
2261 }
2262 
JsCompositeOperationSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2263 shared_ptr<JsValue> JsiCanvasBridge::JsCompositeOperationSetter(const shared_ptr<JsRuntime>& runtime,
2264     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2265 {
2266     if (argv.empty() || argc == 0) {
2267         return runtime->NewUndefined();
2268     }
2269     auto proto = argv[0];
2270     if (!proto) {
2271         return runtime->NewUndefined();
2272     }
2273     auto typeStr = proto->ToString(runtime);
2274     // this map must be sorted by key.
2275     static const LinearMapNode<CompositeOperation> compositeOperationTable[] = {
2276         { "copy", CompositeOperation::COPY },
2277         { "destination-atop", CompositeOperation::DESTINATION_ATOP },
2278         { "destination-in", CompositeOperation::DESTINATION_IN },
2279         { "destination-out", CompositeOperation::DESTINATION_OUT },
2280         { "destination-over", CompositeOperation::DESTINATION_OVER },
2281         { "lighter", CompositeOperation::LIGHTER },
2282         { "source-atop", CompositeOperation::SOURCE_ATOP },
2283         { "source-in", CompositeOperation::SOURCE_IN },
2284         { "source-out", CompositeOperation::SOURCE_OUT },
2285         { "source-over", CompositeOperation::SOURCE_OVER },
2286         { "xor", CompositeOperation::XOR },
2287     };
2288     auto type = ConvertStrToEnum(
2289         typeStr.c_str(), compositeOperationTable, ArraySize(compositeOperationTable), CompositeOperation::SOURCE_OVER);
2290     auto task = [type](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateCompositeOperation(type); };
2291     PushTaskToPage(runtime, value, task);
2292     value->SetProperty(runtime, "__globalCompositeOperation", proto);
2293     return runtime->NewUndefined();
2294 }
2295 
JsLineDashOffsetGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2296 shared_ptr<JsValue> JsiCanvasBridge::JsLineDashOffsetGetter(const shared_ptr<JsRuntime>& runtime,
2297     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2298 {
2299     return value->GetProperty(runtime, "__lineDash");
2300 }
2301 
JsLineDashOffsetSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2302 shared_ptr<JsValue> JsiCanvasBridge::JsLineDashOffsetSetter(const shared_ptr<JsRuntime>& runtime,
2303     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2304 {
2305     if (argv.empty() || argc == 0) {
2306         return runtime->NewUndefined();
2307     }
2308     auto proto = argv[0];
2309     if (!proto) {
2310         return runtime->NewUndefined();
2311     }
2312     double dashoffset = GetJsDoubleVal(runtime, proto);
2313     auto task = [dashoffset](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateLineDashOffset(dashoffset); };
2314     PushTaskToPage(runtime, value, task);
2315     value->SetProperty(runtime, "__lineDash", proto);
2316     return runtime->NewUndefined();
2317 }
2318 
JsShadowBlurGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2319 shared_ptr<JsValue> JsiCanvasBridge::JsShadowBlurGetter(const shared_ptr<JsRuntime>& runtime,
2320     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2321 {
2322     return value->GetProperty(runtime, "__shadowBlur");
2323 }
2324 
JsShadowBlurSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2325 shared_ptr<JsValue> JsiCanvasBridge::JsShadowBlurSetter(const shared_ptr<JsRuntime>& runtime,
2326     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2327 {
2328     if (argv.empty() || argc == 0) {
2329         return runtime->NewUndefined();
2330     }
2331     auto proto = argv[0];
2332     if (!proto) {
2333         return runtime->NewUndefined();
2334     }
2335     double blur = GetJsDoubleVal(runtime, proto);
2336     auto task = [blur](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateShadowBlur(blur); };
2337     PushTaskToPage(runtime, value, task);
2338     value->SetProperty(runtime, "__shadowBlur", proto);
2339     return runtime->NewUndefined();
2340 }
2341 
JsShadowColorGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2342 shared_ptr<JsValue> JsiCanvasBridge::JsShadowColorGetter(const shared_ptr<JsRuntime>& runtime,
2343     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2344 {
2345     return value->GetProperty(runtime, "__shadowColor");
2346 }
2347 
JsShadowColorSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2348 shared_ptr<JsValue> JsiCanvasBridge::JsShadowColorSetter(const shared_ptr<JsRuntime>& runtime,
2349     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2350 {
2351     if (argv.empty() || argc == 0) {
2352         return runtime->NewUndefined();
2353     }
2354     auto proto = argv[0];
2355     if (!proto) {
2356         return runtime->NewUndefined();
2357     }
2358     auto colorStr = proto->ToString(runtime);
2359     auto color = Color::FromString(colorStr);
2360     auto task = [color](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateShadowColor(color); };
2361     PushTaskToPage(runtime, value, task);
2362     value->SetProperty(runtime, "__shadowColor", proto);
2363     return runtime->NewUndefined();
2364 }
2365 
JsShadowOffsetXGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2366 shared_ptr<JsValue> JsiCanvasBridge::JsShadowOffsetXGetter(const shared_ptr<JsRuntime>& runtime,
2367     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2368 {
2369     return value->GetProperty(runtime, "__shadowOffsetX");
2370 }
2371 
JsShadowOffsetXSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2372 shared_ptr<JsValue> JsiCanvasBridge::JsShadowOffsetXSetter(const shared_ptr<JsRuntime>& runtime,
2373     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2374 {
2375     if (argv.empty() || argc == 0) {
2376         return runtime->NewUndefined();
2377     }
2378     auto proto = argv[0];
2379     if (!proto) {
2380         return runtime->NewUndefined();
2381     }
2382     double offsetX = GetJsDoubleVal(runtime, proto);
2383     auto task = [offsetX](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateShadowOffsetX(offsetX); };
2384     PushTaskToPage(runtime, value, task);
2385     value->SetProperty(runtime, "__shadowOffsetX", proto);
2386     return runtime->NewUndefined();
2387 }
2388 
JsShadowOffsetYGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2389 shared_ptr<JsValue> JsiCanvasBridge::JsShadowOffsetYGetter(const shared_ptr<JsRuntime>& runtime,
2390     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2391 {
2392     return value->GetProperty(runtime, "__shadowOffsetY");
2393 }
2394 
JsShadowOffsetYSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2395 shared_ptr<JsValue> JsiCanvasBridge::JsShadowOffsetYSetter(const shared_ptr<JsRuntime>& runtime,
2396     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2397 {
2398     if (argv.empty() || argc == 0) {
2399         return runtime->NewUndefined();
2400     }
2401     auto proto = argv[0];
2402     if (!proto) {
2403         return runtime->NewUndefined();
2404     }
2405     double offsetY = GetJsDoubleVal(runtime, proto);
2406     auto task = [offsetY](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateShadowOffsetY(offsetY); };
2407     PushTaskToPage(runtime, value, task);
2408     value->SetProperty(runtime, "__shadowOffsetY", proto);
2409     return runtime->NewUndefined();
2410 }
2411 
JsSmoothingEnabledGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2412 shared_ptr<JsValue> JsiCanvasBridge::JsSmoothingEnabledGetter(const shared_ptr<JsRuntime>& runtime,
2413     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2414 {
2415     return value->GetProperty(runtime, "__imageSmoothingEnabled");
2416 }
2417 
JsSmoothingEnabledSetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2418 shared_ptr<JsValue> JsiCanvasBridge::JsSmoothingEnabledSetter(const shared_ptr<JsRuntime>& runtime,
2419     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2420 {
2421     if (argv.empty() || argc == 0) {
2422         return runtime->NewUndefined();
2423     }
2424     auto proto = argv[0];
2425     if (!proto || !proto->IsBoolean(runtime)) {
2426         return runtime->NewUndefined();
2427     }
2428     auto enabled = proto->ToBoolean(runtime);
2429     auto task = [enabled](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateSmoothingEnabled(enabled); };
2430     PushTaskToPage(runtime, value, task);
2431     value->SetProperty(runtime, "__imageSmoothingEnabled", proto);
2432     return runtime->NewUndefined();
2433 }
2434 
JsSmoothingQualityGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2435 shared_ptr<JsValue> JsiCanvasBridge::JsSmoothingQualityGetter(const shared_ptr<JsRuntime>& runtime,
2436     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2437 {
2438     return value->GetProperty(runtime, "__imageSmoothingQuality");
2439 }
2440 
JsSmoothingQualitySetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2441 shared_ptr<JsValue> JsiCanvasBridge::JsSmoothingQualitySetter(const shared_ptr<JsRuntime>& runtime,
2442     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2443 {
2444     if (argv.empty() || argc == 0) {
2445         return runtime->NewUndefined();
2446     }
2447     auto proto = argv[0];
2448     if (!proto || !proto->IsString(runtime)) {
2449         return runtime->NewUndefined();
2450     }
2451     const std::string& quality = proto->ToString(runtime);
2452     if (quality.empty() || QUALITY_TYPE.find(quality) == QUALITY_TYPE.end()) {
2453         return runtime->NewUndefined();
2454     }
2455     auto task = [quality](const RefPtr<CanvasTaskPool>& pool) { pool->UpdateSmoothingQuality(quality); };
2456     PushTaskToPage(runtime, value, task);
2457     value->SetProperty(runtime, "__imageSmoothingQuality", proto);
2458     return runtime->NewUndefined();
2459 }
2460 
JsWidthGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2461 shared_ptr<JsValue> JsiCanvasBridge::JsWidthGetter(const shared_ptr<JsRuntime>& runtime,
2462     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2463 {
2464     NodeId id = GetCurrentNodeId(runtime, value);
2465     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
2466     if (!engine) {
2467         return runtime->NewUndefined();
2468     }
2469     auto page = engine->GetRunningPage();
2470     if (!page) {
2471         return runtime->NewUndefined();
2472     }
2473 
2474     double width = 0.0;
2475     auto task = [id, page, &width]() {
2476         auto canvas = AceType::DynamicCast<DOMCanvas>(page->GetDomDocument()->GetDOMNodeById(id));
2477         if (!canvas) {
2478             return;
2479         }
2480         auto paintChild = AceType::DynamicCast<CustomPaintComponent>(canvas->GetSpecializedComponent());
2481         if (!paintChild) {
2482             return;
2483         }
2484         auto canvasTask = paintChild->GetTaskPool();
2485         if (!canvasTask) {
2486             return;
2487         }
2488         width = canvasTask->GetWidth();
2489     };
2490     auto delegate = engine->GetFrontendDelegate();
2491     if (!delegate) {
2492         return runtime->NewUndefined();
2493     }
2494     delegate->PostSyncTaskToPage(task, "ArkUICanvasGetWidth");
2495 
2496     return runtime->NewNumber(width);
2497 }
2498 
JsHeightGetter(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)2499 shared_ptr<JsValue> JsiCanvasBridge::JsHeightGetter(const shared_ptr<JsRuntime>& runtime,
2500     const shared_ptr<JsValue>& value, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
2501 {
2502     NodeId id = GetCurrentNodeId(runtime, value);
2503     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
2504     if (!engine) {
2505         return runtime->NewUndefined();
2506     }
2507     auto page = engine->GetRunningPage();
2508     if (!page) {
2509         return runtime->NewUndefined();
2510     }
2511 
2512     double height = 0.0;
2513     auto task = [id, page, &height]() {
2514         auto canvas = AceType::DynamicCast<DOMCanvas>(page->GetDomDocument()->GetDOMNodeById(id));
2515         if (!canvas) {
2516             return;
2517         }
2518         auto paintChild = AceType::DynamicCast<CustomPaintComponent>(canvas->GetSpecializedComponent());
2519         if (!paintChild) {
2520             return;
2521         }
2522         auto canvasTask = paintChild->GetTaskPool();
2523         if (!canvasTask) {
2524             return;
2525         }
2526         height = canvasTask->GetHeight();
2527     };
2528     auto delegate = engine->GetFrontendDelegate();
2529     if (!delegate) {
2530         return runtime->NewUndefined();
2531     }
2532     delegate->PostSyncTaskToPage(task, "ArkUICanvasGetHeight");
2533 
2534     return runtime->NewNumber(height);
2535 }
2536 
2537 } // namespace OHOS::Ace::Framework
2538