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