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