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