• 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/quickjs/offscreen_canvas_bridge.h"
17 #include "frameworks/bridge/js_frontend/engine/quickjs/qjs_engine.h"
18 
19 namespace OHOS::Ace::Framework {
20 namespace {
21 constexpr char IMAGE_SRC[] = "src";
22 constexpr char IMAGE_WIDTH[] = "width";
23 constexpr char IMAGE_HEIGHT[] = "height";
24 template<typename T>
ConvertStrToEnum(const char * key,const LinearMapNode<T> * map,size_t length,T defaultValue)25 inline T ConvertStrToEnum(const char* key, const LinearMapNode<T>* map, size_t length, T defaultValue)
26 {
27     int64_t index = BinarySearchFindIndex(map, length, key);
28     return index != -1 ? map[index].value : defaultValue;
29 }
GetJsDashValue(JSContext * ctx,JSValueConst value)30 inline std::vector<double> GetJsDashValue(JSContext* ctx, JSValueConst value)
31 {
32     ScopedString scopedString(ctx, value);
33     std::vector<std::string> props;
34     StringUtils::StringSplitter(scopedString.get(), ',', props);
35     std::vector<double> segments;
36 
37     for (const auto& prop : props) {
38         auto val = StringToDouble(prop);
39         // if there only exists 0 in props, it means that there is no dash style
40         if (NearZero(val) && props.size() == 1) {
41             return segments;
42         }
43         segments.emplace_back(val);
44     }
45     // if segment size is odd, copy one more to even
46     if (segments.size() % 2 != 0) {
47         segments.insert(segments.end(), segments.begin(), segments.end());
48     }
49     return segments;
50 }
51 const LinearMapNode<TextBaseline> BASELINE_TABLE[] = {
52     { "alphabetic", TextBaseline::ALPHABETIC },
53     { "bottom", TextBaseline::BOTTOM },
54     { "hanging", TextBaseline::HANGING },
55     { "ideographic", TextBaseline::IDEOGRAPHIC },
56     { "middle", TextBaseline::MIDDLE },
57     { "top", TextBaseline::TOP },
58 };
59 
60 const std::set<std::string> FONT_WEIGHTS = {
61     "normal", "bold", "lighter", "bolder", "100", "200", "300", "400", "500", "600", "700", "800", "900"
62 };
63 const std::set<std::string> FONT_STYLES = { "italic", "oblique", "normal" };
64 const std::set<std::string> FONT_FAMILIES = { "sans-serif", "serif", "monospace" };
65 const std::set<std::string> QUALITY_TYPE = { "low", "medium", "high" }; // Default value is low.
66 
GetJsDoubleVal(JSContext * ctx,JSValueConst value)67 inline double GetJsDoubleVal(JSContext* ctx, JSValueConst value)
68 {
69     // use ScopedString to parse double
70     ScopedString scopedVal(ctx, value);
71     auto jsonVal = JsonUtil::ParseJsonData(scopedVal.get());
72     if (jsonVal && jsonVal->IsNumber()) {
73         return jsonVal->GetDouble();
74     }
75     return 0.0;
76 }
77 
GetJsRectParam(JSContext * ctx,int32_t argc,JSValueConst * argv)78 inline Rect GetJsRectParam(JSContext* ctx, int32_t argc, JSValueConst* argv)
79 {
80     // 4 parameters: rect(x, y, width, height)
81     if ((!argv) || (argc != 4)) {
82         LOGE("argc error, argc = %{private}d", argc);
83         return Rect();
84     }
85     double x = GetJsDoubleVal(ctx, argv[0]);
86     double y = GetJsDoubleVal(ctx, argv[1]);
87     double width = GetJsDoubleVal(ctx, argv[2]);
88     double height = GetJsDoubleVal(ctx, argv[3]);
89     Rect rect = Rect(x, y, width, height);
90     return rect;
91 }
92 
JsParseTextDirection(JSContext * ctx,JSValue value)93 inline PaintState JsParseTextDirection(JSContext* ctx, JSValue value)
94 {
95     PaintState state;
96     JSValue textDirection = JS_GetPropertyStr(ctx, value, "textDirection");
97     ScopedString directionStr(ctx, textDirection);
98     state.SetOffTextDirection(ConvertStrToTextDirection(directionStr.get()));
99 
100     JS_FreeValue(ctx, textDirection);
101     return state;
102 }
103 
JsParseTextState(JSContext * ctx,JSValue value)104 inline PaintState JsParseTextState(JSContext* ctx, JSValue value)
105 {
106     PaintState state;
107     JSValue fontStyle = JS_GetPropertyStr(ctx, value, "font");
108     JSValue textAlign = JS_GetPropertyStr(ctx, value, "textAlign");
109     JSValue textBaseline = JS_GetPropertyStr(ctx, value, "textBaseline");
110     JSValue textDirection = JS_GetPropertyStr(ctx, value, "textDirection");
111 
112     // parse font styles
113     ScopedString alignStr(ctx, textAlign);
114     ScopedString directionStr(ctx, textDirection);
115     ScopedString baselineStr(ctx, textBaseline);
116     state.SetTextAlign(ConvertStrToTextAlign(alignStr.get()));
117     state.SetOffTextDirection(ConvertStrToTextDirection(directionStr.get()));
118 
119     TextStyle style;
120     style.SetTextBaseline(
121         ConvertStrToEnum(baselineStr.get(), BASELINE_TABLE, ArraySize(BASELINE_TABLE), TextBaseline::ALPHABETIC));
122     ScopedString font(ctx, fontStyle);
123     std::vector<std::string> fontProps;
124     StringUtils::StringSplitter(font.get(), ' ', fontProps);
125     for (const auto& fontProp : fontProps) {
126         if (FONT_WEIGHTS.find(fontProp) != FONT_WEIGHTS.end()) {
127             style.SetFontWeight(ConvertStrToFontWeight(fontProp));
128         } else if (FONT_STYLES.find(fontProp) != FONT_STYLES.end()) {
129             style.SetFontStyle(ConvertStrToFontStyle(fontProp));
130         } else if (FONT_FAMILIES.find(fontProp) != FONT_FAMILIES.end()) {
131             style.SetFontFamilies(ConvertStrToFontFamilies(fontProp));
132         } else if (fontProp.find("px") != std::string::npos) {
133             std::string fontSize = fontProp.substr(0, fontProp.size() - 2);
134             style.SetFontSize(Dimension(StringToDouble(fontProp)));
135         } else {
136             LOGW("parse text error");
137         }
138     }
139     state.SetTextStyle(style);
140     JS_FreeValue(ctx, fontStyle);
141     JS_FreeValue(ctx, textAlign);
142     JS_FreeValue(ctx, textBaseline);
143     JS_FreeValue(ctx, textDirection);
144 
145     return state;
146 }
147 }
148 std::unordered_map<int32_t, RefPtr<CanvasPath2D>> OffscreenCanvasBridge::path2Ds_;
149 int32_t OffscreenCanvasBridge::gradientCount_ = 0;
150 int32_t OffscreenCanvasBridge::patternCount_ = 0;
151 int32_t OffscreenCanvasBridge::path2dCount_ = 0;
152 std::unordered_map<int32_t, Pattern> OffscreenCanvasBridge::pattern_;
153 std::unordered_map<int32_t, Gradient> OffscreenCanvasBridge::gradientColors_;
154 int32_t OffscreenCanvasBridge::globalBridgeId_ = 0;
155 
GetCurrentBridgeId(JSContext * ctx,JSValueConst value)156 int32_t GetCurrentBridgeId(JSContext* ctx, JSValueConst value)
157 {
158     int32_t id = 0;
159     JSValue bridgeId = JS_GetPropertyStr(ctx, value, "__bridgeId");
160     if (JS_IsInteger(bridgeId) && (JS_ToInt32(ctx, &id, bridgeId)) < 0) {
161         id = 0;
162     }
163     JS_FreeValue(ctx, bridgeId);
164     return id;
165 }
166 
GetOffscreenCanvasBridge(JSContext * ctx,JSValueConst value)167 RefPtr<OffscreenCanvasBridge> GetOffscreenCanvasBridge(JSContext* ctx, JSValueConst value)
168 {
169     int32_t bridgeId =  GetCurrentBridgeId(ctx, value);
170     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
171     if (instance) {
172         auto page = instance->GetRunningPage();
173         if (page) {
174             auto bridge = AceType::DynamicCast<OffscreenCanvasBridge>(page->GetOffscreenCanvasBridgeById(bridgeId));
175             return bridge;
176         }
177     }
178 
179     return nullptr;
180 }
181 
OffscreenCanvasBridge(JSContext * ctx,int32_t width,int32_t height)182 OffscreenCanvasBridge::OffscreenCanvasBridge(JSContext* ctx, int32_t width, int32_t height)
183 {
184     width_ = width;
185     height_ = height;
186     bridgeId_ = globalBridgeId_++;
187     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
188     if (instance) {
189         auto pipelineContext = instance->GetDelegate()->GetPipelineContext();
190         if (pipelineContext) {
191             offscreenCanvas_ = pipelineContext->CreateOffscreenCanvas(width_, height_);
192         }
193     }
194 }
195 
196 const JSCFunctionListEntry JS_ANIMATION_FUNCS[] = {
197     JS_CGETSET_DEF("fillStyle", OffscreenCanvasBridge::JsFillStyleGetter, OffscreenCanvasBridge::JsFillStyleSetter),
198     JS_CGETSET_DEF("strokeStyle", OffscreenCanvasBridge::JsStrokeStyleGetter,
199         OffscreenCanvasBridge::JsStrokeStyleSetter),
200     JS_CGETSET_DEF("lineCap", OffscreenCanvasBridge::JsLineCapGetter, OffscreenCanvasBridge::JsLineCapSetter),
201     JS_CGETSET_DEF("lineJoin", OffscreenCanvasBridge::JsLineJoinGetter, OffscreenCanvasBridge::JsLineJoinSetter),
202     JS_CGETSET_DEF("miterLimit", OffscreenCanvasBridge::JsMiterLimitGetter, OffscreenCanvasBridge::JsMiterLimitSetter),
203     JS_CGETSET_DEF("lineWidth", OffscreenCanvasBridge::JsLineWidthGetter, OffscreenCanvasBridge::JsLineWidthSetter),
204     JS_CGETSET_DEF("textAlign", OffscreenCanvasBridge::JsTextAlignGetter, OffscreenCanvasBridge::JsTextAlignSetter),
205     JS_CGETSET_DEF("textBaseline", OffscreenCanvasBridge::JsTextBaselineGetter,
206         OffscreenCanvasBridge::JsTextBaselineSetter),
207     JS_CGETSET_DEF("font", OffscreenCanvasBridge::JsFontGetter, OffscreenCanvasBridge::JsFontSetter),
208     JS_CGETSET_DEF("globalAlpha", OffscreenCanvasBridge::JsAlphaGetter, OffscreenCanvasBridge::JsAlphaSetter),
209     JS_CGETSET_DEF("globalCompositeOperation",
210         OffscreenCanvasBridge::JsCompositeOperationGetter, OffscreenCanvasBridge::JsCompositeOperationSetter),
211     JS_CGETSET_DEF("lineDashOffset", OffscreenCanvasBridge::JsLineDashOffsetGetter,
212         OffscreenCanvasBridge::JsLineDashOffsetSetter),
213     JS_CGETSET_DEF("shadowBlur", OffscreenCanvasBridge::JsShadowBlurGetter, OffscreenCanvasBridge::JsShadowBlurSetter),
214     JS_CGETSET_DEF("shadowColor", OffscreenCanvasBridge::JsShadowColorGetter,
215         OffscreenCanvasBridge::JsShadowColorSetter),
216     JS_CGETSET_DEF("shadowOffsetX", OffscreenCanvasBridge::JsShadowOffsetXGetter,
217         OffscreenCanvasBridge::JsShadowOffsetXSetter),
218     JS_CGETSET_DEF("shadowOffsetY", OffscreenCanvasBridge::JsShadowOffsetYGetter,
219         OffscreenCanvasBridge::JsShadowOffsetYSetter),
220     JS_CGETSET_DEF("imageSmoothingEnabled",
221         OffscreenCanvasBridge::JsSmoothingEnabledGetter, OffscreenCanvasBridge::JsSmoothingEnabledSetter),
222     JS_CGETSET_DEF("imageSmoothingQuality",
223         OffscreenCanvasBridge::JsSmoothingQualityGetter, OffscreenCanvasBridge::JsSmoothingQualitySetter),
224     JS_CGETSET_DEF("filter",
225         OffscreenCanvasBridge::JsFilterParamGetter, OffscreenCanvasBridge::JsFilterParamSetter),
226 };
227 
GetBridge(JSContext * ctx)228 JSValue OffscreenCanvasBridge::GetBridge(JSContext* ctx)
229 {
230     JSValue bridge = JS_NewObject(ctx);
231 
232     const std::vector<std::pair<const char*, JSValue>> propertyTable = {
233         { "__bridgeId", JS_NewInt32(ctx, bridgeId_) },
234         { "getContext", JS_NewCFunction(ctx, JsGetContext, "getContext", 2) },
235         { "transferToImageBitmap", JS_NewCFunction(ctx, JsTransferToImageBitmap, "transferToImageBitmap", 0)},
236         { "toDataURL", JS_NewCFunction(ctx, JsToDataURL, "toDataURL", 2)},
237     };
238 
239     for (const auto& iter : propertyTable) {
240         JS_SetPropertyStr(ctx, bridge, iter.first, iter.second);
241     }
242     return bridge;
243 }
244 
GetGradient(JSContext * ctx,JSValueConst value)245 Gradient OffscreenCanvasBridge::GetGradient(JSContext* ctx, JSValueConst value)
246 {
247     int32_t id = 0;
248     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
249     if (JS_IsInteger(nodeId) && (JS_ToInt32(ctx, &id, nodeId)) < 0) {
250         JS_FreeValue(ctx, nodeId);
251         return Gradient();
252     }
253     JS_FreeValue(ctx, nodeId);
254     return gradientColors_[id];
255 }
256 
GetPattern(JSContext * ctx,JSValueConst value)257 Pattern OffscreenCanvasBridge::GetPattern(JSContext* ctx, JSValueConst value)
258 {
259     int32_t id = 0;
260     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
261     if (JS_IsInteger(nodeId) && (JS_ToInt32(ctx, &id, nodeId)) < 0) {
262         return Pattern();
263     }
264     JS_FreeValue(ctx, nodeId);
265     return pattern_[id];
266 }
267 
JsGetContext(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)268 JSValue OffscreenCanvasBridge::JsGetContext(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
269 {
270     ScopedString tmp(ctx, value);
271     auto bridge = GetOffscreenCanvasBridge(ctx, value);
272     if (bridge) {
273         JSValue renderContext = JS_NewObject(ctx);
274         const std::vector<std::pair<const char*, JSValue>> propertyTable = {
275             { "__bridgeId", JS_NewInt32(ctx, bridge->bridgeId_) },
276             { "createLinearGradient", JS_NewCFunction(ctx, JsCreateLinearGradient, "createLinearGradient", 4) },
277             { "createRadialGradient", JS_NewCFunction(ctx, JsCreateRadialGradient, "createRadialGradient", 6) },
278             { "createPattern", JS_NewCFunction(ctx, JsCreatePattern, "createPattern", 2) },
279             { "fillRect", JS_NewCFunction(ctx, JsFillRect, "fillRect", 4) },
280             { "clearRect", JS_NewCFunction(ctx, JsClearRect, "clearRect", 4) },
281             { "strokeRect", JS_NewCFunction(ctx, JsStrokeRect, "strokeRect", 4) },
282             { "beginPath", JS_NewCFunction(ctx, JsBeginPath, "beginPath", 0) },
283             { "closePath", JS_NewCFunction(ctx, JsClosePath, "closePath", 0) },
284             { "arc", JS_NewCFunction(ctx, JsArc, "arc", 6) },
285             { "moveTo", JS_NewCFunction(ctx, JsMoveTo, "moveTo", 2) },
286             { "arcTo", JS_NewCFunction(ctx, JsArcTo, "arcTo", 5) },
287             { "stroke", JS_NewCFunction(ctx, JsStroke, "stroke", 0) },
288             { "rotate", JS_NewCFunction(ctx, JsRotate, "rotate", 1) },
289             { "scale", JS_NewCFunction(ctx, JsScale, "scale", 2) },
290             { "fillText", JS_NewCFunction(ctx, JsFillText, "fillText", 3) },
291             { "strokeText", JS_NewCFunction(ctx, JsStrokeText, "strokeText", 3) },
292             { "measureText", JS_NewCFunction(ctx, JsMeasureText, "measureText", 1) },
293             { "rect", JS_NewCFunction(ctx, JsRect, "rect", 4) },
294             { "fill", JS_NewCFunction(ctx, JsFill, "fill", 0) },
295             { "clip", JS_NewCFunction(ctx, JsClip, "clip", 0) },
296             { "createImageData", JS_NewCFunction(ctx, JsCreateImageData, "createImageData", 2) },
297             { "putImageData", JS_NewCFunction(ctx, JsPutImageData, "putImageData", 7) },
298             { "getImageData", JS_NewCFunction(ctx, JsGetImageData, "getImageData", 4) },
299             { "restore", JS_NewCFunction(ctx, JsRestore, "restore", 0) },
300             { "save", JS_NewCFunction(ctx, JsSave, "save", 0) },
301             { "drawImage", JS_NewCFunction(ctx, JsDrawImage, "drawImage", 9) },
302             { "lineTo", JS_NewCFunction(ctx, JsLineTo, "lineTo", 2) },
303             { "bezierCurveTo", JS_NewCFunction(ctx, JsBezierCurveTo, "bezierCurveTo", 6) },
304             { "quadraticCurveTo", JS_NewCFunction(ctx, JsQuadraticCurveTo, "quadraticCurveTo", 4) },
305             { "ellipse", JS_NewCFunction(ctx, JsEllipse, "ellipse", 4) },
306             { "setTransform", JS_NewCFunction(ctx, JsSetTransform, "setTransform", 6) },
307             { "transform", JS_NewCFunction(ctx, JsTransform, "transform", 6) },
308             { "translate", JS_NewCFunction(ctx, JsTranslate, "translate", 2) },
309             { "getLineDash", JS_NewCFunction(ctx, JsGetLineDash, "getLineDash", 0) },
310             { "setLineDash", JS_NewCFunction(ctx, JsSetLineDash, "setLineDash", 1) },
311             { "createPath2D", JS_NewCFunction(ctx, JsCreatePath2D, "createPath2D", 0) },
312             { "isPointInStroke", JS_NewCFunction(ctx, JsIsPointInStroke, "isPointInStroke", 2) },
313             { "isPointInPath", JS_NewCFunction(ctx, JsIsPointInPath, "isPointInPath", 2) },
314             { "resetTransform", JS_NewCFunction(ctx, JsResetTransform, "resetTransform", 0) },
315         };
316 
317         for (const auto& iter : propertyTable) {
318             JS_SetPropertyStr(ctx, renderContext, iter.first, iter.second);
319         }
320         // getter and setter
321         JS_SetPropertyFunctionList(ctx, renderContext, JS_ANIMATION_FUNCS, countof(JS_ANIMATION_FUNCS));
322         return renderContext;
323     }
324 
325     return JS_NULL;
326 }
JsSetLineDash(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)327 JSValue OffscreenCanvasBridge::JsSetLineDash(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
328 {
329     // 1 parameter: setLineDash(segments)
330     if ((!argv) || (argc != 1)) {
331         LOGE("argc error, argc = %{private}d", argc);
332         return JS_NULL;
333     }
334     ScopedString dash(ctx, argv[0]);
335     JS_SetPropertyStr(ctx, value, "lineDash", JS_NewString(ctx, dash.get()));
336     auto segments = GetJsDashValue(ctx, argv[0]);
337     auto bridge = GetOffscreenCanvasBridge(ctx, value);
338     if (bridge) {
339         bridge->offscreenCanvas_->SetLineDash(segments);
340     }
341     return JS_NULL;
342 }
343 
JsGetLineDash(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)344 JSValue OffscreenCanvasBridge::JsGetLineDash(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
345 {
346     // 0 parameter: getLineDash()
347     if ((!argv) || (argc != 0)) {
348         LOGE("argc error, argc = %{private}d", argc);
349         return JS_NULL;
350     }
351     auto val = JS_GetPropertyStr(ctx, value, "lineDash");
352     return val;
353 }
JsTranslate(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)354 JSValue OffscreenCanvasBridge::JsTranslate(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
355 {
356     // 2 parameters: translate(x, y)
357     if ((!argv) || (argc != 2)) {
358         LOGE("argc error, argc = %{private}d", argc);
359         return JS_NULL;
360     }
361     double x = GetJsDoubleVal(ctx, argv[0]);
362     double y = GetJsDoubleVal(ctx, argv[1]);
363     auto bridge = GetOffscreenCanvasBridge(ctx, value);
364     if (bridge) {
365         bridge->offscreenCanvas_->Translate(x, y);
366     }
367     return JS_NULL;
368 }
JsTransform(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)369 JSValue OffscreenCanvasBridge::JsTransform(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
370 {
371     // 6 parameters: transform(a, b, c, d, e, f)
372     if ((!argv) || (argc != 6)) {
373         LOGE("argc error, argc = %{private}d", argc);
374         return JS_NULL;
375     }
376     TransformParam param;
377     param.scaleX = GetJsDoubleVal(ctx, argv[0]);
378     param.skewX = GetJsDoubleVal(ctx, argv[1]);
379     param.skewY = GetJsDoubleVal(ctx, argv[2]);
380     param.scaleY = GetJsDoubleVal(ctx, argv[3]);
381     param.translateX = GetJsDoubleVal(ctx, argv[4]);
382     param.translateY = GetJsDoubleVal(ctx, argv[5]);
383     auto bridge = GetOffscreenCanvasBridge(ctx, value);
384     if (bridge) {
385         bridge->offscreenCanvas_->Transform(param);
386     }
387     return JS_NULL;
388 }
389 
JsSetTransform(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)390 JSValue OffscreenCanvasBridge::JsSetTransform(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
391 {
392     // 6 parameters: setTransform(a, b, c, d, e, f)
393     if ((!argv) || (argc != 6)) {
394         LOGE("argc error, argc = %{private}d", argc);
395         return JS_NULL;
396     }
397     TransformParam param;
398     param.scaleX = GetJsDoubleVal(ctx, argv[0]);
399     param.skewX = GetJsDoubleVal(ctx, argv[1]);
400     param.skewY = GetJsDoubleVal(ctx, argv[2]);
401     param.scaleY = GetJsDoubleVal(ctx, argv[3]);
402     param.translateX = GetJsDoubleVal(ctx, argv[4]);
403     param.translateY = GetJsDoubleVal(ctx, argv[5]);
404     auto bridge = GetOffscreenCanvasBridge(ctx, value);
405     if (bridge) {
406         bridge->offscreenCanvas_->SetTransform(param);
407     }
408     return JS_NULL;
409 }
410 
JsEllipse(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)411 JSValue OffscreenCanvasBridge::JsEllipse(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
412 {
413     LOGD("JsEllipse");
414     // 7 or 8 parameters: ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise?)
415     if ((!argv) || (argc < 7 || argc > 8)) {
416         LOGE("argc error, argc = %{private}d", argc);
417         return JS_NULL;
418     }
419     EllipseParam param;
420     param.x = GetJsDoubleVal(ctx, argv[0]);
421     param.y = GetJsDoubleVal(ctx, argv[1]);
422     param.radiusX = GetJsDoubleVal(ctx, argv[2]);
423     param.radiusY = GetJsDoubleVal(ctx, argv[3]);
424     param.rotation = GetJsDoubleVal(ctx, argv[4]);
425     param.startAngle = GetJsDoubleVal(ctx, argv[5]);
426     param.endAngle = GetJsDoubleVal(ctx, argv[6]);
427     if (argc == 8) {
428         int32_t anti = static_cast<int32_t>(GetJsDoubleVal(ctx, argv[7]));
429         param.anticlockwise = (anti == 1);
430     }
431     auto bridge = GetOffscreenCanvasBridge(ctx, value);
432     if (bridge) {
433         bridge->offscreenCanvas_->Ellipse(param);
434     }
435     return JS_NULL;
436 }
JsQuadraticCurveTo(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)437 JSValue OffscreenCanvasBridge::JsQuadraticCurveTo(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
438 {
439     LOGD("JsQuadraticCurveTo");
440     // 4 parameters: quadraticCurveTo(cpx, cpy, x, y)
441     if ((!argv) || (argc != 4)) {
442         LOGE("argc error, argc = %{private}d", argc);
443         return JS_NULL;
444     }
445     QuadraticCurveParam param;
446     param.cpx = GetJsDoubleVal(ctx, argv[0]);
447     param.cpy = GetJsDoubleVal(ctx, argv[1]);
448     param.x = GetJsDoubleVal(ctx, argv[2]);
449     param.y = GetJsDoubleVal(ctx, argv[3]);
450     auto bridge = GetOffscreenCanvasBridge(ctx, value);
451     if (bridge) {
452         bridge->offscreenCanvas_->QuadraticCurveTo(param);
453     }
454     return JS_NULL;
455 }
JsBezierCurveTo(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)456 JSValue OffscreenCanvasBridge::JsBezierCurveTo(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
457 {
458     LOGD("JsBezierCurveTo");
459     // 6 parameters: bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
460     if ((!argv) || (argc != 6)) {
461         LOGE("argc error, argc = %{private}d", argc);
462         return JS_NULL;
463     }
464     BezierCurveParam param;
465     param.cp1x = GetJsDoubleVal(ctx, argv[0]);
466     param.cp1y = GetJsDoubleVal(ctx, argv[1]);
467     param.cp2x = GetJsDoubleVal(ctx, argv[2]);
468     param.cp2y = GetJsDoubleVal(ctx, argv[3]);
469     param.x = GetJsDoubleVal(ctx, argv[4]);
470     param.y = GetJsDoubleVal(ctx, argv[5]);
471     auto bridge = GetOffscreenCanvasBridge(ctx, value);
472     if (bridge) {
473         bridge->offscreenCanvas_->BezierCurveTo(param);
474     }
475     return JS_NULL;
476 }
477 
JsLineTo(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)478 JSValue OffscreenCanvasBridge::JsLineTo(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
479 {
480     // 2 parameters: lineTo(x, y)
481     if ((!argv) || (argc != 2)) {
482         LOGE("argc error, argc = %{private}d", argc);
483         return JS_NULL;
484     }
485     double x = GetJsDoubleVal(ctx, argv[0]);
486     double y = GetJsDoubleVal(ctx, argv[1]);
487     auto bridge = GetOffscreenCanvasBridge(ctx, value);
488     if (bridge) {
489         bridge->offscreenCanvas_->LineTo(x, y);
490     }
491     return JS_NULL;
492 }
493 
JsScale(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)494 JSValue OffscreenCanvasBridge::JsScale(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
495 {
496     // 2 parameters: scale(x, y)
497     if ((!argv) || (argc != 2)) {
498         LOGE("argc error, argc = %{private}d", argc);
499         return JS_NULL;
500     }
501     double x = GetJsDoubleVal(ctx, argv[0]);
502     double y = GetJsDoubleVal(ctx, argv[1]);
503     auto bridge = GetOffscreenCanvasBridge(ctx, value);
504     if (bridge) {
505         bridge->offscreenCanvas_->Scale(x, y);
506     }
507     return JS_NULL;
508 }
509 
JsRotate(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)510 JSValue OffscreenCanvasBridge::JsRotate(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
511 {
512     // 1 parameter: rotate(angle)
513     if ((!argv) || (argc != 1)) {
514         LOGE("argc error, argc = %{private}d", argc);
515         return JS_NULL;
516     }
517     double angle = GetJsDoubleVal(ctx, argv[0]);
518     auto bridge = GetOffscreenCanvasBridge(ctx, value);
519     if (bridge) {
520         bridge->offscreenCanvas_->Rotate(angle);
521     }
522     return JS_NULL;
523 }
JsClosePath(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)524 JSValue OffscreenCanvasBridge::JsClosePath(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
525 {
526     // 0 parameter: closePath()
527     if ((!argv) || (argc != 0)) {
528         LOGE("argc error, argc = %{private}d", argc);
529         return JS_NULL;
530     }
531     auto bridge = GetOffscreenCanvasBridge(ctx, value);
532     if (bridge) {
533         bridge->offscreenCanvas_->ClosePath();
534     }
535     return JS_NULL;
536 }
JsMoveTo(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)537 JSValue OffscreenCanvasBridge::JsMoveTo(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
538 {
539     // 2 parameters: moveTo(x, y)
540     if ((!argv) || (argc != 2)) {
541         LOGE("argc error, argc = %{private}d", argc);
542         return JS_NULL;
543     }
544     double x = GetJsDoubleVal(ctx, argv[0]);
545     double y = GetJsDoubleVal(ctx, argv[1]);
546     auto bridge = GetOffscreenCanvasBridge(ctx, value);
547     if (bridge) {
548         bridge->offscreenCanvas_->MoveTo(x, y);
549     }
550     return JS_NULL;
551 }
JsArcTo(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)552 JSValue OffscreenCanvasBridge::JsArcTo(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
553 {
554     LOGD("JsArcTo");
555     // 5 parameters: arcTo(x1, y1, x2, y2, radius)
556     if ((!argv) || (argc != 5)) {
557         LOGE("argc error, argc = %{private}d", argc);
558         return JS_NULL;
559     }
560     ArcToParam param;
561     param.x1 = GetJsDoubleVal(ctx, argv[0]);
562     param.y1 = GetJsDoubleVal(ctx, argv[1]);
563     param.x2 = GetJsDoubleVal(ctx, argv[2]);
564     param.y2 = GetJsDoubleVal(ctx, argv[3]);
565     param.radius = GetJsDoubleVal(ctx, argv[4]);
566     auto bridge = GetOffscreenCanvasBridge(ctx, value);
567     if (bridge) {
568         bridge->offscreenCanvas_->ArcTo(param);
569     }
570     return JS_NULL;
571 }
JsStroke(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)572 JSValue OffscreenCanvasBridge::JsStroke(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
573 {
574     LOGD("JsStroke");
575     // 0 or 1 parameter: ctx.stroke() / ctx.stroke(path)
576     if (argv != nullptr && argc == 1) {
577         JSValue typeVal = JS_GetPropertyStr(ctx, argv[0], "__type");
578         ScopedString type(ctx, typeVal);
579         if (std::strcmp(type.get(), "path2d") != 0) {
580             LOGE("Stroke Path2D failed, target is not path.");
581             return JS_NULL;
582         }
583         auto path = GetPath2D(ctx, argv[0]);
584         if (path == nullptr) {
585             LOGE("Stroke Path2D failed, target path is null.");
586             return JS_NULL;
587         }
588         auto bridge = GetOffscreenCanvasBridge(ctx, value);
589         if (bridge) {
590             bridge->offscreenCanvas_->Stroke(path);
591         }
592         return JS_NULL;
593     }
594     auto bridge = GetOffscreenCanvasBridge(ctx, value);
595     if (bridge) {
596         bridge->offscreenCanvas_->Stroke();
597     }
598     return JS_NULL;
599 }
600 
GetPath2D(JSContext * ctx,JSValueConst value)601 RefPtr<CanvasPath2D> OffscreenCanvasBridge::GetPath2D(JSContext* ctx, JSValueConst value)
602 {
603     int32_t id = 0;
604     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
605     if (JS_IsInteger(nodeId) && (JS_ToInt32(ctx, &id, nodeId)) < 0) {
606         return nullptr;
607     }
608     JS_FreeValue(ctx, nodeId);
609     return path2Ds_[id];
610 }
611 
JsArc(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)612 JSValue OffscreenCanvasBridge::JsArc(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
613 {
614     LOGD("JsArc");
615     // 5 or 6 parameters: arc(x, y, radius, startAngle, endAngle, anticlockwise?)
616     if ((!argv) || (argc < 5 || argc > 6)) {
617         LOGE("argc error, argc = %{private}d", argc);
618         return JS_NULL;
619     }
620     ArcParam param;
621     param.x = GetJsDoubleVal(ctx, argv[0]);
622     param.y = GetJsDoubleVal(ctx, argv[1]);
623     param.radius = GetJsDoubleVal(ctx, argv[2]);
624     param.startAngle = GetJsDoubleVal(ctx, argv[3]);
625     param.endAngle = GetJsDoubleVal(ctx, argv[4]);
626     if (argc == 6) {
627         ScopedString arg(ctx, argv[5]);
628         if (!arg.get()) {
629             LOGW("no value");
630             return JS_NULL;
631         }
632         std::unique_ptr<JsonValue> argPtr = JsonUtil::ParseJsonString(arg.get());
633         if (argPtr && argPtr->IsBool()) {
634             param.anticlockwise = argPtr->GetBool();
635         }
636     }
637     auto bridge = GetOffscreenCanvasBridge(ctx, value);
638     if (bridge) {
639         bridge->offscreenCanvas_->Arc(param);
640     }
641     return JS_NULL;
642 }
JsBeginPath(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)643 JSValue OffscreenCanvasBridge::JsBeginPath(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
644 {
645     LOGD("Js Begin path");
646     // 0 parameter: beginPath()
647     if ((!argv) || (argc != 0)) {
648         LOGE("argc error, argc = %{private}d", argc);
649         return JS_NULL;
650     }
651     auto bridge = GetOffscreenCanvasBridge(ctx, value);
652     if (bridge) {
653         bridge->offscreenCanvas_->BeginPath();
654     }
655     return JS_NULL;
656 }
657 
JsCreatePath2D(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)658 JSValue OffscreenCanvasBridge::JsCreatePath2D(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
659 {
660     JSValue path2D = JS_NewObject(ctx);
661     JS_SetPropertyStr(ctx, path2D, "__type", JS_NewString(ctx, "path2d"));
662     JS_SetPropertyStr(ctx, path2D, "__id", JS_NewInt32(ctx, path2dCount_));
663     JS_SetPropertyStr(ctx, path2D, "addPath", JS_NewCFunction(ctx, JsPath2DAddPath, "addPath", 1));
664     JS_SetPropertyStr(ctx, path2D, "setTransform", JS_NewCFunction(ctx, JsPath2DSetTransform, "setTransform", 6));
665     JS_SetPropertyStr(ctx, path2D, "moveTo", JS_NewCFunction(ctx, JsPath2DMoveTo, "moveTo", 2));
666     JS_SetPropertyStr(ctx, path2D, "lineTo", JS_NewCFunction(ctx, JsPath2DLineTo, "lineTo", 2));
667     JS_SetPropertyStr(ctx, path2D, "arc", JS_NewCFunction(ctx, JsPath2DArc, "arc", 6));
668     JS_SetPropertyStr(ctx, path2D, "arcTo", JS_NewCFunction(ctx, JsPath2DArcTo, "arcTo", 5));
669     JS_SetPropertyStr(ctx, path2D, "quadraticCurveTo",
670         JS_NewCFunction(ctx, JsPath2DQuadraticCurveTo, "quadraticCurveTo", 4));
671     JS_SetPropertyStr(ctx, path2D, "bezierCurveTo", JS_NewCFunction(ctx, JsPath2DBezierCurveTo, "bezierCurveTo", 6));
672     JS_SetPropertyStr(ctx, path2D, "ellipse", JS_NewCFunction(ctx, JsPath2DEllipse, "ellipse", 8));
673     JS_SetPropertyStr(ctx, path2D, "rect", JS_NewCFunction(ctx, JsPath2DRect, "rect", 4));
674     JS_SetPropertyStr(ctx, path2D, "closePath", JS_NewCFunction(ctx, JsPath2DClosePath, "closePath", 0));
675     path2Ds_[path2dCount_] = JsMakePath2D(ctx, value, argc, argv);
676     ++path2dCount_;
677     return path2D;
678 }
679 
JsPath2DAddPath(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)680 JSValue OffscreenCanvasBridge::JsPath2DAddPath(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
681 {
682     // 1 parameter: addPath(path)
683     if ((!argv) || (argc != 1)) {
684         LOGE("AddPath to Path2D failed, invalid args.");
685         return JS_NULL;
686     }
687     int32_t id = 0;
688     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
689     if (JS_IsInteger(nodeId) && JS_ToInt32(ctx, &id, nodeId) < 0) {
690         LOGE("AddPath to Path2D failed, unknown holder path.");
691         return JS_NULL;
692     }
693     auto holderPath = path2Ds_[id];
694     if (holderPath == nullptr) {
695         LOGE("AddPath to Path2D failed, holderPath is null.");
696         return JS_NULL;
697     }
698     JSValue typeVal = JS_GetPropertyStr(ctx, argv[0], "__type");
699     ScopedString type(ctx, typeVal);
700     if (std::strcmp(type.get(), "path2d") != 0) {
701         LOGE("AddPath to Path2D failed, to be added is not path.");
702         return JS_NULL;
703     }
704     auto toBeAdd = GetPath2D(ctx, argv[0]);
705     if (toBeAdd == nullptr) {
706         LOGE("AddPath to Path2D failed, to be added path is null.");
707         return JS_NULL;
708     }
709     holderPath->AddPath(toBeAdd);
710     return JS_NULL;
711 }
712 
JsPath2DSetTransform(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)713 JSValue OffscreenCanvasBridge::JsPath2DSetTransform(JSContext* ctx, JSValueConst value,
714     int32_t argc, JSValueConst* argv)
715 {
716     // 6 parameters: setTransform(a, b, c, d, e, f)
717     if ((!argv) || (argc != 6)) {
718         LOGE("Call Path2D SetTransform failed, invalid args.");
719         return JS_NULL;
720     }
721     int32_t id = 0;
722     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
723     if (JS_IsInteger(nodeId) && JS_ToInt32(ctx, &id, nodeId) < 0) {
724         LOGE("Call Path2D SetTransform failed, unknown holder path.");
725         return JS_NULL;
726     }
727     auto holderPath = path2Ds_[id];
728     if (holderPath == nullptr) {
729         LOGE("Call Path2D SetTransform failed, holderPath is null.");
730         return JS_NULL;
731     }
732     holderPath->SetTransform(GetJsDoubleVal(ctx, argv[0]), GetJsDoubleVal(ctx, argv[1]),
733         GetJsDoubleVal(ctx, argv[2]), GetJsDoubleVal(ctx, argv[3]),
734         GetJsDoubleVal(ctx, argv[4]), GetJsDoubleVal(ctx, argv[5]));
735     return JS_NULL;
736 }
737 
JsPath2DMoveTo(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)738 JSValue OffscreenCanvasBridge::JsPath2DMoveTo(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
739 {
740     // 2 parameters: moveTo(x, y)
741     if ((!argv) || (argc != 2)) {
742         LOGE("Call Path2D Arc MoveTo, invalid args.");
743         return JS_NULL;
744     }
745     int32_t id = 0;
746     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
747     if (JS_IsInteger(nodeId) && JS_ToInt32(ctx, &id, nodeId) < 0) {
748         LOGE("Call Path2D MoveTo failed, unknown holder path.");
749         return JS_NULL;
750     }
751     auto holderPath = path2Ds_[id];
752     if (holderPath == nullptr) {
753         LOGE("Call Path2D MoveTo failed, holderPath is null.");
754         return JS_NULL;
755     }
756     holderPath->MoveTo(GetJsDoubleVal(ctx, argv[0]), GetJsDoubleVal(ctx, argv[1]));
757     return JS_NULL;
758 }
759 
JsPath2DLineTo(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)760 JSValue OffscreenCanvasBridge::JsPath2DLineTo(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
761 {
762     // 2 parameters: lineTo(x, y)
763     if ((!argv) || (argc != 2)) {
764         LOGE("Call Path2D LineTo failed, invalid args.");
765         return JS_NULL;
766     }
767     int32_t id = 0;
768     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
769     if (JS_IsInteger(nodeId) && JS_ToInt32(ctx, &id, nodeId) < 0) {
770         LOGE("Call Path2D LineTo failed, unknown holder path.");
771         return JS_NULL;
772     }
773     auto holderPath = path2Ds_[id];
774     if (holderPath == nullptr) {
775         LOGE("Call Path2D LineTo failed, holderPath is null.");
776         return JS_NULL;
777     }
778     holderPath->LineTo(GetJsDoubleVal(ctx, argv[0]), GetJsDoubleVal(ctx, argv[1]));
779     return JS_NULL;
780 }
781 
JsPath2DArc(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)782 JSValue OffscreenCanvasBridge::JsPath2DArc(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
783 {
784     // 5 or 6 parameters: arc(x, y, radius, startAngle, endAngle, anticlockwise?)
785     if ((!argv) || (argc < 5) || (argc > 6)) {
786         LOGE("Call Path2D Arc failed, invalid args.");
787         return JS_NULL;
788     }
789     int32_t id = 0;
790     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
791     if (JS_IsInteger(nodeId) && JS_ToInt32(ctx, &id, nodeId) < 0) {
792         LOGE("Call Path2D Arc failed, unknown holder path.");
793         return JS_NULL;
794     }
795     auto holderPath = path2Ds_[id];
796     if (holderPath == nullptr) {
797         LOGE("Call Path2D Arc failed, holderPath is null.");
798         return JS_NULL;
799     }
800     bool anticlockwise = false;
801     if (argc == 6) {
802         int32_t anti = static_cast<int32_t>(GetJsDoubleVal(ctx, argv[7]));
803         anticlockwise = (anti == 1);
804     }
805     holderPath->Arc(GetJsDoubleVal(ctx, argv[0]), GetJsDoubleVal(ctx, argv[1]),
806         GetJsDoubleVal(ctx, argv[2]), GetJsDoubleVal(ctx, argv[3]),
807         GetJsDoubleVal(ctx, argv[4]), anticlockwise);
808     return JS_NULL;
809 }
810 
JsPath2DArcTo(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)811 JSValue OffscreenCanvasBridge::JsPath2DArcTo(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
812 {
813     // 5 parameters: arcTo(x1, y1, x2, y2, radius)
814     if ((!argv) || (argc != 5)) {
815         LOGE("Call Path2D ArcTo failed, invalid args.");
816         return JS_NULL;
817     }
818     int32_t id = 0;
819     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
820     if (JS_IsInteger(nodeId) && JS_ToInt32(ctx, &id, nodeId) < 0) {
821         LOGE("Call Path2D ArcTo failed, unknown holder path.");
822         return JS_NULL;
823     }
824     auto holderPath = path2Ds_[id];
825     if (holderPath == nullptr) {
826         LOGE("Call Path2D ArcTo failed, holderPath is null.");
827         return JS_NULL;
828     }
829     holderPath->ArcTo(GetJsDoubleVal(ctx, argv[0]), GetJsDoubleVal(ctx, argv[1]), GetJsDoubleVal(ctx, argv[2]),
830         GetJsDoubleVal(ctx, argv[3]), GetJsDoubleVal(ctx, argv[4]));
831     return JS_NULL;
832 }
833 
JsPath2DQuadraticCurveTo(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)834 JSValue OffscreenCanvasBridge::JsPath2DQuadraticCurveTo(JSContext* ctx, JSValueConst value,
835     int32_t argc, JSValueConst* argv)
836 {
837     // 4 parameters: quadraticCurveTo(cpx, cpy, x, y)
838     if ((!argv) || (argc != 4)) {
839         LOGE("Call Path2D QuadraticCurveTo failed, invalid args.");
840         return JS_NULL;
841     }
842     int32_t id = 0;
843     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
844     if (JS_IsInteger(nodeId) && JS_ToInt32(ctx, &id, nodeId) < 0) {
845         LOGE("Call Path2D QuadraticCurveTo failed, unknown holder path.");
846         return JS_NULL;
847     }
848     auto holderPath = path2Ds_[id];
849     if (holderPath == nullptr) {
850         LOGE("Call Path2D QuadraticCurveTo failed, holderPath is null.");
851         return JS_NULL;
852     }
853     holderPath->QuadraticCurveTo(GetJsDoubleVal(ctx, argv[0]), GetJsDoubleVal(ctx, argv[1]),
854         GetJsDoubleVal(ctx, argv[2]), GetJsDoubleVal(ctx, argv[3]));
855     return JS_NULL;
856 }
857 
JsPath2DBezierCurveTo(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)858 JSValue OffscreenCanvasBridge::JsPath2DBezierCurveTo(JSContext* ctx, JSValueConst value,
859     int32_t argc, JSValueConst* argv)
860 {
861     // 6 parameters: bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
862     if ((!argv) || (argc != 6)) {
863         LOGE("Call Path2D BezierCurveTo failed, invalid args.");
864         return JS_NULL;
865     }
866     int32_t id = 0;
867     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
868     if (JS_IsInteger(nodeId) && JS_ToInt32(ctx, &id, nodeId) < 0) {
869         LOGE("Call Path2D BezierCurveTo failed, unknown holder path.");
870         return JS_NULL;
871     }
872     auto holderPath = path2Ds_[id];
873     if (holderPath == nullptr) {
874         LOGE("Call Path2D BezierCurveTo failed, holderPath is null.");
875         return JS_NULL;
876     }
877     holderPath->BezierCurveTo(GetJsDoubleVal(ctx, argv[0]), GetJsDoubleVal(ctx, argv[1]),
878         GetJsDoubleVal(ctx, argv[2]), GetJsDoubleVal(ctx, argv[3]),
879         GetJsDoubleVal(ctx, argv[4]), GetJsDoubleVal(ctx, argv[5]));
880     return JS_NULL;
881 }
882 
JsPath2DEllipse(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)883 JSValue OffscreenCanvasBridge::JsPath2DEllipse(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
884 {
885     // 7 or 8 parameters: ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise?)
886     if ((!argv) || (argc < 7) || (argc > 8)) {
887         LOGE("Call Path2D Ellipse failed, invalid args.");
888         return JS_NULL;
889     }
890     int32_t id = 0;
891     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
892     if (JS_IsInteger(nodeId) && JS_ToInt32(ctx, &id, nodeId) < 0) {
893         LOGE("Call Path2D Ellipse failed, unknown holder path.");
894         return JS_NULL;
895     }
896     auto holderPath = path2Ds_[id];
897     if (holderPath == nullptr) {
898         LOGE("Call Path2D Ellipse failed, holderPath is null.");
899         return JS_NULL;
900     }
901     bool anticlockwise = false;
902     if (argc == 8) {
903         int32_t anti = static_cast<int32_t>(GetJsDoubleVal(ctx, argv[7]));
904         anticlockwise = (anti == 1);
905     }
906     holderPath->Ellipse(GetJsDoubleVal(ctx, argv[0]), GetJsDoubleVal(ctx, argv[1]),
907         GetJsDoubleVal(ctx, argv[2]), GetJsDoubleVal(ctx, argv[3]),
908         GetJsDoubleVal(ctx, argv[4]), GetJsDoubleVal(ctx, argv[5]),
909         GetJsDoubleVal(ctx, argv[6]), anticlockwise);
910     return JS_NULL;
911 }
912 
JsPath2DRect(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)913 JSValue OffscreenCanvasBridge::JsPath2DRect(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
914 {
915     // 4 parameters: rect(x, y, width, height)
916     if ((!argv) || (argc != 4)) {
917         LOGE("Call Path2D Rect failed, invalid args.");
918         return JS_NULL;
919     }
920     int32_t id = 0;
921     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
922     if (JS_IsInteger(nodeId) && JS_ToInt32(ctx, &id, nodeId) < 0) {
923         LOGE("Call Path2D Rect failed, unknown holder path.");
924         return JS_NULL;
925     }
926     auto holderPath = path2Ds_[id];
927     if (holderPath == nullptr) {
928         LOGE("Call Path2D Rect failed, holderPath is null.");
929         return JS_NULL;
930     }
931     holderPath->Rect(GetJsDoubleVal(ctx, argv[0]), GetJsDoubleVal(ctx, argv[1]),
932         GetJsDoubleVal(ctx, argv[2]), GetJsDoubleVal(ctx, argv[3]));
933     return JS_NULL;
934 }
935 
JsPath2DClosePath(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)936 JSValue OffscreenCanvasBridge::JsPath2DClosePath(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
937 {
938     int32_t id = 0;
939     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
940     if (JS_IsInteger(nodeId) && JS_ToInt32(ctx, &id, nodeId) < 0) {
941         LOGE("Call Path2D ClosePath failed, unknown holder path.");
942         return JS_NULL;
943     }
944     auto holderPath = path2Ds_[id];
945     if (holderPath == nullptr) {
946         LOGE("Call Path2D ClosePath failed, holderPath is null.");
947         return JS_NULL;
948     }
949     holderPath->ClosePath();
950     return JS_NULL;
951 }
952 
JsMakePath2D(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)953 RefPtr<CanvasPath2D> OffscreenCanvasBridge::JsMakePath2D(JSContext* ctx, JSValueConst value,
954     int32_t argc, JSValueConst* argv)
955 {
956     if (argv != nullptr && argc == 1) {
957         if (JS_IsString(argv[0])) {
958             // Example: ctx.createPath2D("M250 150 L150 350 L350 350 Z")
959             return AceType::MakeRefPtr<CanvasPath2D>(JS_ToCString(ctx, argv[0]));
960         } else {
961             JSValue typeVal = JS_GetPropertyStr(ctx, argv[0], "__type");
962             ScopedString type(ctx, typeVal);
963             if (std::strcmp(type.get(), "path2d") == 0) {
964                 // Example: ctx.createPath2D(path1)
965                 return AceType::MakeRefPtr<CanvasPath2D>(GetPath2D(ctx, argv[0]));
966             }
967         }
968     }
969     // Example: ctx.createPath2D()
970     return AceType::MakeRefPtr<CanvasPath2D>();
971 }
972 
JsTransferToImageBitmap(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)973 JSValue OffscreenCanvasBridge::JsTransferToImageBitmap(JSContext* ctx, JSValueConst value,
974     int32_t argc, JSValueConst* argv)
975 {
976     ScopedString tmp(ctx, value);
977     LOGE("111OffscreenCanvasBridge::JsTransferToImageBitmap value = %{public}s", tmp.get());
978 
979     auto bridge = GetOffscreenCanvasBridge(ctx, value);
980     if (bridge) {
981         JSValue imageBitmap = JS_NewObject(ctx);
982         const std::vector<std::pair<const char*, JSValue>> propertyTable = {
983             { "__bridgeId", JS_NewInt32(ctx, bridge->bridgeId_) },
984         };
985 
986         for (const auto& iter : propertyTable) {
987             JS_SetPropertyStr(ctx, imageBitmap, iter.first, iter.second);
988         }
989 
990         return imageBitmap;
991     }
992 
993     return JS_NULL;
994 }
995 
JsToDataURL(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)996 JSValue OffscreenCanvasBridge::JsToDataURL(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
997 {
998     if ((!argv) || (argc != 2)) {
999         LOGE("argc error, argc = %{private}d", argc);
1000         return JS_NULL;
1001     }
1002     ScopedString arg(ctx, argv[0]);
1003     if (!arg.get()) {
1004         LOGW("no value for text");
1005         return JS_NULL;
1006     }
1007     double quality = GetJsDoubleVal(ctx, argv[1]);
1008     ScopedString tmp(ctx, value);
1009     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1010     std::string url;
1011     if (bridge) {
1012         url = bridge->offscreenCanvas_->ToDataURL(arg.get(), quality);
1013     }
1014 
1015     return JS_NewString(ctx, url.c_str());
1016 }
1017 
JsCreateLinearGradient(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1018 JSValue OffscreenCanvasBridge::JsCreateLinearGradient(JSContext* ctx, JSValueConst value,
1019     int32_t argc, JSValueConst* argv)
1020 {
1021     // 4 parameters: createLinearGradient(x0, y0, x1, y1)
1022     if ((!argv) || (argc != 4)) {
1023         LOGE("argc error, argc = %{private}d", argc);
1024         return JS_NULL;
1025     }
1026     JSValue gradient = JS_NewObject(ctx);
1027     JS_SetPropertyStr(ctx, gradient, "__type", JS_NewString(ctx, "gradient"));
1028     JS_SetPropertyStr(ctx, gradient, "__id", JS_NewInt32(ctx, gradientCount_)); // global linear gradients
1029     JS_SetPropertyStr(ctx, gradient, "addColorStop", JS_NewCFunction(ctx, JsAddColorStop, "addColorStop", 2));
1030     Offset beginOffset = Offset(GetJsDoubleVal(ctx, argv[0]), GetJsDoubleVal(ctx, argv[1]));
1031     Offset endOffset = Offset(GetJsDoubleVal(ctx, argv[2]), GetJsDoubleVal(ctx, argv[3]));
1032     gradientColors_[gradientCount_].SetType(GradientType::LINEAR);
1033     gradientColors_[gradientCount_].SetBeginOffset(beginOffset);
1034     gradientColors_[gradientCount_].SetEndOffset(endOffset);
1035     ++gradientCount_;
1036     return gradient;
1037 }
1038 
JsAddColorStop(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1039 JSValue OffscreenCanvasBridge::JsAddColorStop(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1040 {
1041     // 2 parameters: addColorStop(offset, color)
1042     if ((!argv) || (argc != 2)) {
1043         LOGE("argc error, argc = %{private}d", argc);
1044         return JS_NULL;
1045     }
1046 
1047     GradientColor color;
1048     auto jsColor = JS_ToCString(ctx, argv[1]);
1049     color.SetColor(Color::FromString(jsColor));
1050     color.SetDimension(GetJsDoubleVal(ctx, argv[0]));
1051     int32_t id = 0;
1052     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__id");
1053     if (JS_IsInteger(nodeId) && JS_ToInt32(ctx, &id, nodeId) >= 0) {
1054         gradientColors_[id].AddColor(color);
1055     }
1056     JS_FreeValue(ctx, nodeId);
1057     JS_FreeCString(ctx, jsColor);
1058     return JS_NULL;
1059 }
1060 
JsCreatePattern(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1061 JSValue OffscreenCanvasBridge::JsCreatePattern(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1062 {
1063     LOGD("OffscreenCanvasBridge::JsCreatePattern");
1064     // 2 parameters: createPattern(image, repetition)
1065     if ((!argv) || (argc != 2)) {
1066         LOGE("argc error, argc = %{private}d", argc);
1067         return JS_NULL;
1068     }
1069 
1070     JSValue pattern = JS_NewObject(ctx);
1071     JS_SetPropertyStr(ctx, pattern, "__id", JS_NewFloat64(ctx, patternCount_));
1072     JS_SetPropertyStr(ctx, pattern, "__type", JS_NewString(ctx, "pattern"));
1073 
1074     if (!JS_IsObject(argv[0])) {
1075         return JS_NULL;
1076     }
1077     double width = 0.0;
1078     double height = 0.0;
1079     std::string imageSrc;
1080     auto jsSrc = JS_GetPropertyStr(ctx, argv[0], IMAGE_SRC);
1081     if (!JS_ToBool(ctx, jsSrc)) {
1082         ParseDomImage(ctx, argv[0], width, height, imageSrc);
1083     } else {
1084         auto jsWidth = JS_GetPropertyStr(ctx, argv[0], IMAGE_WIDTH);
1085         auto jsHeight = JS_GetPropertyStr(ctx, argv[0], IMAGE_HEIGHT);
1086         auto cImageSrc = JS_ToCString(ctx, jsSrc);
1087         imageSrc = cImageSrc;
1088         JS_ToFloat64(ctx, &width, jsWidth);
1089         JS_ToFloat64(ctx, &height, jsHeight);
1090         JS_FreeValue(ctx, jsWidth);
1091         JS_FreeValue(ctx, jsHeight);
1092         JS_FreeCString(ctx, cImageSrc);
1093     }
1094     auto repeat = JS_ToCString(ctx, argv[1]);
1095     pattern_[patternCount_].SetImgSrc(imageSrc);
1096     pattern_[patternCount_].SetImageWidth(width);
1097     pattern_[patternCount_].SetImageHeight(height);
1098     pattern_[patternCount_].SetRepetition(repeat);
1099     ++patternCount_;
1100 
1101     JS_FreeValue(ctx, jsSrc);
1102     JS_FreeCString(ctx, repeat);
1103     return pattern;
1104 }
1105 
JsCreateRadialGradient(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1106 JSValue OffscreenCanvasBridge::JsCreateRadialGradient(JSContext* ctx, JSValueConst value,
1107     int32_t argc, JSValueConst* argv)
1108 {
1109     LOGE("OffscreenCanvasBridge::JsCreateRadialGradient");
1110     // 6 parameters: createRadialGradient(x0, y0, r0, x1, y1, r1)
1111     if ((!argv) || (argc != 6)) {
1112         LOGE("argc error, argc = %{private}d", argc);
1113         return JS_NULL;
1114     }
1115     JSValue gradient = JS_NewObject(ctx);
1116     JS_SetPropertyStr(ctx, gradient, "__type", JS_NewString(ctx, "gradient"));
1117     JS_SetPropertyStr(ctx, gradient, "__id", JS_NewInt32(ctx, gradientCount_)); // global linear gradients
1118     JS_SetPropertyStr(ctx, gradient, "addColorStop", JS_NewCFunction(ctx, JsAddColorStop, "addColorStop", 2));
1119     Offset innerCenter = Offset(GetJsDoubleVal(ctx, argv[0]), GetJsDoubleVal(ctx, argv[1]));
1120     Offset outerCenter = Offset(GetJsDoubleVal(ctx, argv[3]), GetJsDoubleVal(ctx, argv[4]));
1121     double innerRadius = GetJsDoubleVal(ctx, argv[2]);
1122     double outerRadius = GetJsDoubleVal(ctx, argv[5]);
1123     gradientColors_[gradientCount_].SetType(GradientType::RADIAL);
1124     gradientColors_[gradientCount_].SetBeginOffset(innerCenter);
1125     gradientColors_[gradientCount_].SetEndOffset(outerCenter);
1126     gradientColors_[gradientCount_].SetInnerRadius(innerRadius);
1127     gradientColors_[gradientCount_].SetOuterRadius(outerRadius);
1128     ++gradientCount_;
1129     return gradient;
1130 }
1131 
ParseDomImage(JSContext * ctx,JSValueConst value,double & width,double & height,std::string & src)1132 void OffscreenCanvasBridge::ParseDomImage(JSContext* ctx, JSValueConst value,
1133     double& width, double& height, std::string& src)
1134 {
1135     auto jsAttr = JS_GetPropertyStr(ctx, value, "attr");
1136     auto jsSrc = JS_GetPropertyStr(ctx, jsAttr, IMAGE_SRC);
1137     auto imgSrc = JS_ToCString(ctx, jsSrc);
1138     src = imgSrc;
1139 
1140     auto jsStyle = JS_GetPropertyStr(ctx, value, "style");
1141     auto jsWidth = JS_GetPropertyStr(ctx, jsStyle, IMAGE_WIDTH);
1142     auto jsHeight = JS_GetPropertyStr(ctx, jsStyle, IMAGE_HEIGHT);
1143     auto cWidth = JS_ToCString(ctx, jsWidth);
1144     auto cHeight = JS_ToCString(ctx, jsHeight);
1145     std::string strWidth = cWidth;
1146     std::string strHeight = cHeight;
1147     width = StringToDouble(strWidth);
1148     height = StringToDouble(strHeight);
1149     if (NearZero(width)) {
1150         width = StringToDouble(strWidth.substr(0, strWidth.size() - 2)); // remove px units
1151     }
1152     if (NearZero(height)) {
1153         height = StringToDouble(strHeight.substr(0, strHeight.size() - 2));
1154     }
1155 
1156     JS_FreeValue(ctx, jsAttr);
1157     JS_FreeValue(ctx, jsSrc);
1158     JS_FreeValue(ctx, jsStyle);
1159     JS_FreeValue(ctx, jsWidth);
1160     JS_FreeValue(ctx, jsHeight);
1161     JS_FreeCString(ctx, cWidth);
1162     JS_FreeCString(ctx, cHeight);
1163     JS_FreeCString(ctx, imgSrc);
1164 }
1165 
JsFillRect(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1166 JSValue OffscreenCanvasBridge::JsFillRect(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1167 {
1168     ScopedString tmp(ctx, value);
1169     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1170     if (bridge) {
1171         double x = GetJsDoubleVal(ctx, argv[0]);
1172         double y = GetJsDoubleVal(ctx, argv[1]);
1173         double width = GetJsDoubleVal(ctx, argv[2]);
1174         double height = GetJsDoubleVal(ctx, argv[3]);
1175         Rect rect = Rect(x, y, width, height);
1176         bridge->offscreenCanvas_->FillRect(rect);
1177     }
1178 
1179     return JS_NULL;
1180 }
1181 
JsClearRect(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1182 JSValue OffscreenCanvasBridge::JsClearRect(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1183 {
1184     ScopedString tmp(ctx, value);
1185 
1186     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1187     if (bridge) {
1188         double x = GetJsDoubleVal(ctx, argv[0]);
1189         double y = GetJsDoubleVal(ctx, argv[1]);
1190         double width = GetJsDoubleVal(ctx, argv[2]);
1191         double height = GetJsDoubleVal(ctx, argv[3]);
1192         Rect rect = Rect(x, y, width, height);
1193         bridge->offscreenCanvas_->ClearRect(rect);
1194     }
1195 
1196     return JS_NULL;
1197 }
1198 
JsStrokeRect(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1199 JSValue OffscreenCanvasBridge::JsStrokeRect(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1200 {
1201     ScopedString tmp(ctx, value);
1202 
1203     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1204     if (bridge) {
1205         double x = GetJsDoubleVal(ctx, argv[0]);
1206         double y = GetJsDoubleVal(ctx, argv[1]);
1207         double width = GetJsDoubleVal(ctx, argv[2]);
1208         double height = GetJsDoubleVal(ctx, argv[3]);
1209         Rect rect = Rect(x, y, width, height);
1210         bridge->offscreenCanvas_->StrokeRect(rect);
1211     }
1212 
1213     return JS_NULL;
1214 }
1215 
JsRect(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1216 JSValue OffscreenCanvasBridge::JsRect(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1217 {
1218     LOGD("JsRect");
1219     Rect rect = GetJsRectParam(ctx, argc, argv);
1220     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1221     if (bridge) {
1222         bridge->offscreenCanvas_->AddRect(rect);
1223     }
1224     return JS_NULL;
1225 }
1226 
JsFill(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1227 JSValue OffscreenCanvasBridge::JsFill(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1228 {
1229     LOGD("JsFill");
1230     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1231     if (bridge) {
1232         bridge->offscreenCanvas_->Fill();
1233     }
1234     return JS_NULL;
1235 }
1236 
JsClip(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1237 JSValue OffscreenCanvasBridge::JsClip(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1238 {
1239     LOGD("JsClip");
1240     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1241     if (bridge) {
1242         bridge->offscreenCanvas_->Clip();
1243     }
1244     return JS_NULL;
1245 }
1246 
JsCreateImageData(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1247 JSValue OffscreenCanvasBridge::JsCreateImageData(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1248 {
1249     if (!argv) {
1250         return JS_NULL;
1251     }
1252 
1253     // 1 or 2 parameters: createImageData(imagedata) / createImageData(width, height)
1254     if (argc != 1 && argc != 2) {
1255         return JS_NULL;
1256     }
1257 
1258     JSValue imageData = JS_NewObject(ctx);
1259     int32_t width = 0;
1260     int32_t height = 0;
1261 
1262     if (argc == 2) {
1263         JS_ToInt32(ctx, &width, argv[0]);
1264         JS_ToInt32(ctx, &height, argv[1]);
1265     }
1266 
1267     if (argc == 1 && JS_IsObject(argv[0])) {
1268         auto jsWidth = JS_GetPropertyStr(ctx, argv[0], "width");
1269         auto jsHeight = JS_GetPropertyStr(ctx, argv[0], "height");
1270         JS_ToInt32(ctx, &width, jsWidth);
1271         JS_ToInt32(ctx, &height, jsHeight);
1272         JS_FreeValue(ctx, jsWidth);
1273         JS_FreeValue(ctx, jsHeight);
1274     }
1275 
1276     JSValue colorArray = JS_NewArray(ctx);
1277     uint32_t count = 0;
1278     for (auto i = 0; i < width; i++) {
1279         for (auto j = 0; j < height; j++) {
1280             JS_SetPropertyUint32(ctx, colorArray, count, JS_NewInt32(ctx, 255));
1281             JS_SetPropertyUint32(ctx, colorArray, count + 1, JS_NewInt32(ctx, 255));
1282             JS_SetPropertyUint32(ctx, colorArray, count + 2, JS_NewInt32(ctx, 255));
1283             JS_SetPropertyUint32(ctx, colorArray, count + 3, JS_NewInt32(ctx, 255));
1284             count += 4;
1285         }
1286     }
1287 
1288     JS_SetPropertyStr(ctx, imageData, "width", JS_NewInt32(ctx, width));
1289     JS_SetPropertyStr(ctx, imageData, "height", JS_NewInt32(ctx, height));
1290     JS_SetPropertyStr(ctx, imageData, "data", colorArray);
1291     return imageData;
1292 }
1293 
JsPutImageData(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1294 JSValue OffscreenCanvasBridge::JsPutImageData(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1295 {
1296     if (!argv) {
1297         return JS_NULL;
1298     }
1299 
1300     // 3 or 7 parameters: putImageData(data, dx, dy) / putImageData(data, dx, dy, dirtyX, dirtyY, dirtyW, dirtyH)
1301     if (argc != 3 && argc != 7 && !JS_IsObject(argv[0])) {
1302         return JS_NULL;
1303     }
1304 
1305     int32_t width = 0;
1306     int32_t height = 0;
1307     auto jsWidth = JS_GetPropertyStr(ctx, argv[0], "width");
1308     auto jsHeight = JS_GetPropertyStr(ctx, argv[0], "height");
1309     JS_ToInt32(ctx, &width, jsWidth);
1310     JS_ToInt32(ctx, &height, jsHeight);
1311     ImageData imageData;
1312     std::vector<std::string> array;
1313     ParseImageData(ctx, argv, argc, array, imageData);
1314 
1315     int64_t num = 0;
1316     for (int32_t i = 0; i < height; ++i) {
1317         for (int32_t j = 0; j < width; ++j) {
1318             if ((i >= imageData.dirtyY) && (i - imageData.dirtyY < imageData.dirtyHeight) && (j >= imageData.dirtyX) &&
1319                 (j - imageData.dirtyX < imageData.dirtyWidth)) {
1320                 int32_t flag = j + width * i;
1321                 if (array.size() > static_cast<uint32_t>(4 * flag + 3)) {
1322                     auto red = StringUtils::StringToInt(array[4 * flag]);
1323                     auto green = StringUtils::StringToInt(array[4 * flag + 1]);
1324                     auto blue = StringUtils::StringToInt(array[4 * flag + 2]);
1325                     auto alpha = StringUtils::StringToInt(array[4 * flag + 3]);
1326                     if (num < imageData.dirtyWidth * imageData.dirtyHeight) {
1327                         imageData.data.emplace_back(Color::FromARGB(alpha, red, green, blue));
1328                     }
1329                     num++;
1330                 }
1331             }
1332         }
1333     }
1334     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1335     if (bridge) {
1336         bridge->offscreenCanvas_->PutImageData(imageData);
1337     }
1338 
1339     JS_FreeValue(ctx, jsWidth);
1340     JS_FreeValue(ctx, jsHeight);
1341     return JS_NULL;
1342 }
1343 
ParseImageData(JSContext * ctx,JSValueConst * argv,int32_t argc,std::vector<std::string> & array,ImageData & imageData)1344 void OffscreenCanvasBridge::ParseImageData(
1345     JSContext* ctx, JSValueConst* argv, int32_t argc, std::vector<std::string>& array, ImageData& imageData)
1346 {
1347     int32_t width = 0;
1348     int32_t height = 0;
1349     auto jsWidth = JS_GetPropertyStr(ctx, argv[0], "width");
1350     auto jsHeight = JS_GetPropertyStr(ctx, argv[0], "height");
1351     auto jsData = JS_GetPropertyStr(ctx, argv[0], "data");
1352     JS_ToInt32(ctx, &width, jsWidth);
1353     JS_ToInt32(ctx, &height, jsHeight);
1354     ScopedString scopedString(ctx, jsData);
1355     StringUtils::StringSplitter(scopedString.get(), ',', array);
1356 
1357     JS_ToInt32(ctx, &imageData.x, argv[1]);
1358     JS_ToInt32(ctx, &imageData.y, argv[2]);
1359     imageData.dirtyWidth = width;
1360     imageData.dirtyHeight = height;
1361 
1362     if (argc == 7) {
1363         JS_ToInt32(ctx, &imageData.dirtyX, argv[3]);
1364         JS_ToInt32(ctx, &imageData.dirtyY, argv[4]);
1365         JS_ToInt32(ctx, &imageData.dirtyWidth, argv[5]);
1366         JS_ToInt32(ctx, &imageData.dirtyHeight, argv[6]);
1367     }
1368 
1369     imageData.dirtyWidth = imageData.dirtyX < 0 ? std::min(imageData.dirtyX + imageData.dirtyWidth, width)
1370         : std::min(width - imageData.dirtyX, imageData.dirtyWidth);
1371     imageData.dirtyHeight = imageData.dirtyY < 0 ? std::min(imageData.dirtyY + imageData.dirtyHeight, height)
1372         : std::min(height - imageData.dirtyY, imageData.dirtyHeight);
1373 
1374     JS_FreeValue(ctx, jsWidth);
1375     JS_FreeValue(ctx, jsHeight);
1376     JS_FreeValue(ctx, jsData);
1377 }
1378 
JsGetImageData(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1379 JSValue OffscreenCanvasBridge::JsGetImageData(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1380 {
1381     // 4 parameters: getImageData(sx, sy, sw, sh)
1382     if (!argv || (argc != 4)) {
1383         return JS_NULL;
1384     }
1385     Rect rect = GetJsRectParam(ctx, argc, argv);
1386     rect.SetLeft(static_cast<int32_t>(rect.Left()));
1387     rect.SetTop(static_cast<int32_t>(rect.Top()));
1388     rect.SetWidth(static_cast<int32_t>(rect.Width()));
1389     rect.SetHeight(static_cast<int32_t>(rect.Height()));
1390     std::unique_ptr<ImageData> data;
1391     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1392     if (bridge) {
1393         data = bridge->offscreenCanvas_->GetImageData(rect.Left(), rect.Top(), rect.Width(), rect.Height());
1394     }
1395     JSValue imageData = JS_NewObject(ctx);
1396     JS_SetPropertyStr(ctx, imageData, "width", JS_NewInt32(ctx, data->dirtyWidth));
1397     JS_SetPropertyStr(ctx, imageData, "height", JS_NewInt32(ctx, data->dirtyHeight));
1398     JSValue colorArray = JS_NewArray(ctx);
1399     uint32_t count = 0;
1400     // travel data
1401     for (auto i = 0; i < data->dirtyHeight; i++) {
1402         for (auto j = 0; j < data->dirtyWidth; j++) {
1403             // a pixel includes 4 data: red/green/blue/alpha
1404             int32_t idx = i * data->dirtyWidth + j;
1405             auto pixel = data->data[idx];
1406             JS_SetPropertyUint32(ctx, colorArray, count, JS_NewInt32(ctx, pixel.GetRed()));
1407             JS_SetPropertyUint32(ctx, colorArray, count + 1, JS_NewInt32(ctx, pixel.GetGreen()));
1408             JS_SetPropertyUint32(ctx, colorArray, count + 2, JS_NewInt32(ctx, pixel.GetBlue()));
1409             JS_SetPropertyUint32(ctx, colorArray, count + 3, JS_NewInt32(ctx, pixel.GetAlpha()));
1410             count += 4;
1411         }
1412     }
1413     JS_SetPropertyStr(ctx, imageData, "data", colorArray);
1414     return imageData;
1415 }
1416 
JsDrawImage(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1417 JSValue OffscreenCanvasBridge::JsDrawImage(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1418 {
1419     if (!argv || !JS_IsObject(argv[0])) {
1420         return JS_NULL;
1421     }
1422     CanvasImage image;
1423     double width = 0.0;
1424     double height = 0.0;
1425     auto src = JS_GetPropertyStr(ctx, argv[0], IMAGE_SRC);
1426     if (!JS_ToBool(ctx, src)) {
1427         ParseDomImage(ctx, argv[0], width, height, image.src);
1428     } else {
1429         auto imgSrc = JS_ToCString(ctx, src);
1430         image.src = imgSrc;
1431         auto jsWidth = JS_GetPropertyStr(ctx, argv[0], IMAGE_WIDTH);
1432         auto jsHeight = JS_GetPropertyStr(ctx, argv[0], IMAGE_HEIGHT);
1433         JS_ToFloat64(ctx, &width, jsWidth);
1434         JS_ToFloat64(ctx, &height, jsHeight);
1435         JS_FreeValue(ctx, jsWidth);
1436         JS_FreeValue(ctx, jsHeight);
1437         JS_FreeCString(ctx, imgSrc);
1438     }
1439     switch (argc) {
1440         // 3 parameters: drawImage(image, dx, dy)
1441         case 3:
1442             image.flag = 0;
1443             image.dx = GetJsDoubleVal(ctx, argv[1]);
1444             image.dy = GetJsDoubleVal(ctx, argv[2]);
1445             break;
1446             // 5 parameters: drawImage(image, dx, dy, dWidth, dHeight)
1447         case 5:
1448             image.flag = 1;
1449             image.dx = GetJsDoubleVal(ctx, argv[1]);
1450             image.dy = GetJsDoubleVal(ctx, argv[2]);
1451             image.dWidth = GetJsDoubleVal(ctx, argv[3]);
1452             image.dHeight = GetJsDoubleVal(ctx, argv[4]);
1453             break;
1454             // 9 parameters: drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
1455         case 9:
1456             image.flag = 2;
1457             image.sx = GetJsDoubleVal(ctx, argv[1]);
1458             image.sy = GetJsDoubleVal(ctx, argv[2]);
1459             image.sWidth = GetJsDoubleVal(ctx, argv[3]);
1460             image.sHeight = GetJsDoubleVal(ctx, argv[4]);
1461             image.dx = GetJsDoubleVal(ctx, argv[5]);
1462             image.dy = GetJsDoubleVal(ctx, argv[6]);
1463             image.dWidth = GetJsDoubleVal(ctx, argv[7]);
1464             image.dHeight = GetJsDoubleVal(ctx, argv[8]);
1465             break;
1466         default:
1467             break;
1468     }
1469     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1470     if (bridge) {
1471         bridge->offscreenCanvas_->DrawImage(image, width, height);
1472     }
1473 
1474     JS_FreeValue(ctx, src);
1475     return JS_NULL;
1476 }
1477 
JsRestore(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1478 JSValue OffscreenCanvasBridge::JsRestore(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1479 {
1480     LOGD("OffscreenCanvasBridge::JsRestore");
1481     // 0 parameter: restore()
1482     if ((!argv) || (argc != 0)) {
1483         LOGE("argc error, argc = %{private}d", argc);
1484         return JS_NULL;
1485     }
1486     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1487     if (bridge) {
1488         bridge->offscreenCanvas_->Restore();
1489     }
1490     return JS_NULL;
1491 }
1492 
JsSave(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1493 JSValue OffscreenCanvasBridge::JsSave(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1494 {
1495     // 0 parameter: save()
1496     if ((!argv) || (argc != 0)) {
1497         LOGE("argc error, argc = %{private}d", argc);
1498         return JS_NULL;
1499     }
1500     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1501     if (bridge) {
1502         bridge->offscreenCanvas_->Save();
1503     }
1504     return JS_NULL;
1505 }
1506 
JsFillStyleGetter(JSContext * ctx,JSValueConst value)1507 JSValue OffscreenCanvasBridge::JsFillStyleGetter(JSContext* ctx, JSValueConst value)
1508 {
1509     return JS_GetPropertyStr(ctx, value, "__fillStyle");
1510 }
1511 
JsHandleStyleSetter(JSContext * ctx,JSValueConst value,JSValueConst proto,FunctionCode functionCode)1512 JSValue OffscreenCanvasBridge::JsHandleStyleSetter(
1513     JSContext* ctx, JSValueConst value, JSValueConst proto, FunctionCode functionCode)
1514 {
1515     if (JS_IsString(proto)) {
1516         auto colorStr = JS_ToCString(ctx, proto);
1517         auto color = Color::FromString(colorStr);
1518         auto bridge = GetOffscreenCanvasBridge(ctx, value);
1519         if (bridge) {
1520             if (functionCode == FunctionCode::STROKE_STYLE_SETTER) {
1521                 bridge->offscreenCanvas_->SetStrokeColor(color);
1522                 bridge->offscreenCanvas_->SetStrokePattern(Pattern());
1523                 bridge->offscreenCanvas_->SetStrokeGradient(Gradient());
1524             } else if (functionCode == FunctionCode::FILL_STYLE_SETTER) {
1525                 bridge->offscreenCanvas_->SetFillColor(color);
1526                 bridge->offscreenCanvas_->SetFillPattern(Pattern());
1527                 bridge->offscreenCanvas_->SetFillGradient(Gradient());
1528             }
1529         }
1530         JS_FreeCString(ctx, colorStr);
1531     } else {
1532         JSValue typeVal = JS_GetPropertyStr(ctx, proto, "__type");
1533         ScopedString type(ctx, typeVal);
1534         if (std::strcmp(type.get(), "gradient") == 0) {
1535             auto gradient = GetGradient(ctx, proto);
1536             auto bridge = GetOffscreenCanvasBridge(ctx, value);
1537             if (bridge) {
1538                 if (functionCode == FunctionCode::STROKE_STYLE_SETTER) {
1539                     bridge->offscreenCanvas_->SetStrokeGradient(gradient);
1540                     bridge->offscreenCanvas_->SetStrokeColor(Color());
1541                     bridge->offscreenCanvas_->SetStrokePattern(Pattern());
1542                 } else if (functionCode == FunctionCode::FILL_STYLE_SETTER) {
1543                     bridge->offscreenCanvas_->SetFillGradient(gradient);
1544                     bridge->offscreenCanvas_->SetFillColor(Color());
1545                     bridge->offscreenCanvas_->SetFillPattern(Pattern());
1546                 }
1547             }
1548         } else if (std::strcmp(type.get(), "pattern") == 0) {
1549             auto pattern = GetPattern(ctx, proto);
1550             auto bridge = GetOffscreenCanvasBridge(ctx, value);
1551             if (bridge) {
1552                 if (functionCode == FunctionCode::STROKE_STYLE_SETTER) {
1553                     bridge->offscreenCanvas_->SetStrokePattern(pattern);
1554                     bridge->offscreenCanvas_->SetStrokeGradient(Gradient());
1555                     bridge->offscreenCanvas_->SetStrokeColor(Color());
1556                 } else if (functionCode == FunctionCode::FILL_STYLE_SETTER) {
1557                     bridge->offscreenCanvas_->SetFillPattern(pattern);
1558                     bridge->offscreenCanvas_->SetFillGradient(Gradient());
1559                     bridge->offscreenCanvas_->SetFillColor(Color());
1560                 }
1561             }
1562         }
1563     }
1564 
1565     if (functionCode == FunctionCode::STROKE_STYLE_SETTER) {
1566         JS_SetPropertyStr(ctx, value, "__strokeStyle", JS_DupValue(ctx, proto));
1567     } else if (functionCode == FunctionCode::FILL_STYLE_SETTER) {
1568         JS_SetPropertyStr(ctx, value, "__fillStyle", JS_DupValue(ctx, proto));
1569     } else {
1570         LOGW("No such type for set property.");
1571     }
1572     return JS_NULL;
1573 }
1574 
JsFillStyleSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1575 JSValue OffscreenCanvasBridge::JsFillStyleSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1576 {
1577     return JsHandleStyleSetter(ctx, value, proto, FunctionCode::FILL_STYLE_SETTER);
1578 }
1579 
JsStrokeStyleGetter(JSContext * ctx,JSValueConst value)1580 JSValue OffscreenCanvasBridge::JsStrokeStyleGetter(JSContext* ctx, JSValueConst value)
1581 {
1582     return JS_GetPropertyStr(ctx, value, "__strokeStyle");
1583 }
1584 
JsStrokeStyleSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1585 JSValue OffscreenCanvasBridge::JsStrokeStyleSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1586 {
1587     return JsHandleStyleSetter(ctx, value, proto, FunctionCode::STROKE_STYLE_SETTER);
1588 }
1589 
JsLineCapGetter(JSContext * ctx,JSValueConst value)1590 JSValue OffscreenCanvasBridge::JsLineCapGetter(JSContext* ctx, JSValueConst value)
1591 {
1592     return JS_GetPropertyStr(ctx, value, "__lineCap");
1593 }
1594 
JsLineCapSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1595 JSValue OffscreenCanvasBridge::JsLineCapSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1596 {
1597     ScopedString capStr(ctx, proto);
1598     static const LinearMapNode<LineCapStyle> lineCapTable[] = {
1599         { "butt", LineCapStyle::BUTT },
1600         { "round", LineCapStyle::ROUND },
1601         { "square", LineCapStyle::SQUARE },
1602     };
1603     auto lineCap = ConvertStrToEnum(capStr.get(), lineCapTable, ArraySize(lineCapTable), LineCapStyle::BUTT);
1604     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1605     if (bridge) {
1606         bridge->offscreenCanvas_->SetLineCap(lineCap);
1607     }
1608 
1609     JS_SetPropertyStr(ctx, value, "__lineCap", JS_DupValue(ctx, proto));
1610     return JS_NULL;
1611 }
1612 
JsLineJoinGetter(JSContext * ctx,JSValueConst value)1613 JSValue OffscreenCanvasBridge::JsLineJoinGetter(JSContext* ctx, JSValueConst value)
1614 {
1615     return JS_GetPropertyStr(ctx, value, "__lineJoin");
1616 }
1617 
JsLineJoinSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1618 JSValue OffscreenCanvasBridge::JsLineJoinSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1619 {
1620     ScopedString joinStr(ctx, proto);
1621     static const LinearMapNode<LineJoinStyle> lineJoinTable[3] = {
1622         { "bevel", LineJoinStyle::BEVEL },
1623         { "miter", LineJoinStyle::MITER },
1624         { "round", LineJoinStyle::ROUND },
1625     };
1626     auto lineJoin = ConvertStrToEnum(joinStr.get(), lineJoinTable, ArraySize(lineJoinTable), LineJoinStyle::MITER);
1627     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1628     if (bridge) {
1629         bridge->offscreenCanvas_->SetLineJoin(lineJoin);
1630     }
1631 
1632     JS_SetPropertyStr(ctx, value, "__lineJoin", JS_DupValue(ctx, proto));
1633     return JS_NULL;
1634 }
1635 
JsMiterLimitGetter(JSContext * ctx,JSValueConst value)1636 JSValue OffscreenCanvasBridge::JsMiterLimitGetter(JSContext* ctx, JSValueConst value)
1637 {
1638     return JS_GetPropertyStr(ctx, value, "__miterLimit");
1639 }
1640 
JsMiterLimitSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1641 JSValue OffscreenCanvasBridge::JsMiterLimitSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1642 {
1643     double limit = GetJsDoubleVal(ctx, proto);
1644     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1645     if (bridge) {
1646         bridge->offscreenCanvas_->SetMiterLimit(limit);
1647     }
1648 
1649     JS_SetPropertyStr(ctx, value, "__miterLimit", JS_DupValue(ctx, proto));
1650     return JS_NULL;
1651 }
1652 
JsLineWidthGetter(JSContext * ctx,JSValueConst value)1653 JSValue OffscreenCanvasBridge::JsLineWidthGetter(JSContext* ctx, JSValueConst value)
1654 {
1655     return JS_GetPropertyStr(ctx, value, "__lineWidth");
1656 }
1657 
JsLineWidthSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1658 JSValue OffscreenCanvasBridge::JsLineWidthSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1659 {
1660     double lineWidth = GetJsDoubleVal(ctx, proto);
1661     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1662     if (bridge) {
1663         bridge->offscreenCanvas_->SetLineWidth(lineWidth);
1664     }
1665 
1666     JS_SetPropertyStr(ctx, value, "__lineWidth", JS_DupValue(ctx, proto));
1667     return JS_NULL;
1668 }
1669 
JsTextAlignGetter(JSContext * ctx,JSValueConst value)1670 JSValue OffscreenCanvasBridge::JsTextAlignGetter(JSContext* ctx, JSValueConst value)
1671 {
1672     return JS_GetPropertyStr(ctx, value, "__textAlign");
1673 }
1674 
JsTextAlignSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1675 JSValue OffscreenCanvasBridge::JsTextAlignSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1676 {
1677     ScopedString alignStr(ctx, proto);
1678     auto align = ConvertStrToTextAlign(alignStr.get());
1679     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1680     if (bridge) {
1681         bridge->offscreenCanvas_->SetTextAlign(align);
1682     }
1683 
1684     JS_SetPropertyStr(ctx, value, "__textAlign", JS_DupValue(ctx, proto));
1685     return JS_NULL;
1686 }
1687 
JsTextBaselineGetter(JSContext * ctx,JSValueConst value)1688 JSValue OffscreenCanvasBridge::JsTextBaselineGetter(JSContext* ctx, JSValueConst value)
1689 {
1690     return JS_GetPropertyStr(ctx, value, "__textBaseline");
1691 }
1692 
JsTextBaselineSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1693 JSValue OffscreenCanvasBridge::JsTextBaselineSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1694 {
1695     ScopedString baselineStr(ctx, proto);
1696     auto baseline =
1697         ConvertStrToEnum(baselineStr.get(), BASELINE_TABLE, ArraySize(BASELINE_TABLE), TextBaseline::ALPHABETIC);
1698     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1699     if (bridge) {
1700         bridge->offscreenCanvas_->SetTextBaseline(baseline);
1701     }
1702 
1703     JS_SetPropertyStr(ctx, value, "__textBaseline", JS_DupValue(ctx, proto));
1704     return JS_NULL;
1705 }
1706 
JsFontGetter(JSContext * ctx,JSValueConst value)1707 JSValue OffscreenCanvasBridge::JsFontGetter(JSContext* ctx, JSValueConst value)
1708 {
1709     return JS_GetPropertyStr(ctx, value, "__font");
1710 }
1711 
JsFontSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1712 JSValue OffscreenCanvasBridge::JsFontSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1713 {
1714     ScopedString fontStr(ctx, proto);
1715     std::vector<std::string> fontProps;
1716     StringUtils::StringSplitter(fontStr.get(), ' ', fontProps);
1717     bool updateFontStyle = false;
1718     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1719     if (!bridge) {
1720         JS_SetPropertyStr(ctx, value, "__font", JS_DupValue(ctx, proto));
1721         return JS_UNDEFINED;
1722     }
1723 
1724     for (const auto& fontProp : fontProps) {
1725         if (FONT_WEIGHTS.find(fontProp) != FONT_WEIGHTS.end()) {
1726             auto weight = ConvertStrToFontWeight(fontProp);
1727             bridge->offscreenCanvas_->SetFontWeight(weight);
1728         } else if (FONT_STYLES.find(fontProp) != FONT_STYLES.end()) {
1729             updateFontStyle = true;
1730             auto fontStyle = ConvertStrToFontStyle(fontProp);
1731             bridge->offscreenCanvas_->SetFontStyle(fontStyle);
1732         } else if (FONT_FAMILIES.find(fontProp) != FONT_FAMILIES.end()) {
1733             auto families = ConvertStrToFontFamilies(fontProp);
1734             bridge->offscreenCanvas_->SetFontFamilies(families);
1735         } else if (fontProp.find("px") != std::string::npos) {
1736             std::string fontSize = fontProp.substr(0, fontProp.size() - 2);
1737             auto size = Dimension(StringToDouble(fontProp));
1738             bridge->offscreenCanvas_->SetFontSize(size);
1739         }
1740     }
1741     if (!updateFontStyle) {
1742         bridge->offscreenCanvas_->SetFontStyle(FontStyle::NORMAL);
1743     }
1744     JS_SetPropertyStr(ctx, value, "__font", JS_DupValue(ctx, proto));
1745     return JS_UNDEFINED;
1746 }
1747 
JsAlphaGetter(JSContext * ctx,JSValueConst value)1748 JSValue OffscreenCanvasBridge::JsAlphaGetter(JSContext* ctx, JSValueConst value)
1749 {
1750     return JS_GetPropertyStr(ctx, value, "__globalAlpha");
1751 }
1752 
JsAlphaSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1753 JSValue OffscreenCanvasBridge::JsAlphaSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1754 {
1755     double alpha = GetJsDoubleVal(ctx, proto);
1756     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1757     if (bridge) {
1758         bridge->offscreenCanvas_->SetAlpha(alpha);
1759     }
1760     JS_SetPropertyStr(ctx, value, "__globalAlpha", JS_DupValue(ctx, proto));
1761     return JS_NULL;
1762 }
1763 
JsCompositeOperationGetter(JSContext * ctx,JSValueConst value)1764 JSValue OffscreenCanvasBridge::JsCompositeOperationGetter(JSContext* ctx, JSValueConst value)
1765 {
1766     return JS_GetPropertyStr(ctx, value, "__globalCompositeOperation");
1767 }
1768 
JsCompositeOperationSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1769 JSValue OffscreenCanvasBridge::JsCompositeOperationSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1770 {
1771     ScopedString typeStr(ctx, proto);
1772     // this map must be sorted by key.
1773     static const LinearMapNode<CompositeOperation> compositeOperationTable[] = {
1774         { "copy", CompositeOperation::COPY },
1775         { "destination-atop", CompositeOperation::DESTINATION_ATOP },
1776         { "destination-in", CompositeOperation::DESTINATION_IN },
1777         { "destination-out", CompositeOperation::DESTINATION_OUT },
1778         { "destination-over", CompositeOperation::DESTINATION_OVER },
1779         { "lighter", CompositeOperation::LIGHTER },
1780         { "source-atop", CompositeOperation::SOURCE_ATOP },
1781 
1782         { "source-in", CompositeOperation::SOURCE_IN },
1783         { "source-out", CompositeOperation::SOURCE_OUT },
1784         { "source-over", CompositeOperation::SOURCE_OVER },
1785         { "xor", CompositeOperation::XOR },
1786     };
1787     auto type = ConvertStrToEnum(
1788         typeStr.get(), compositeOperationTable, ArraySize(compositeOperationTable), CompositeOperation::SOURCE_OVER);
1789     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1790     if (bridge) {
1791         bridge->offscreenCanvas_->SetCompositeType(type);
1792     }
1793 
1794     JS_SetPropertyStr(ctx, value, "__globalCompositeOperation", JS_DupValue(ctx, proto));
1795     return JS_NULL;
1796 }
1797 
JsLineDashOffsetGetter(JSContext * ctx,JSValueConst value)1798 JSValue OffscreenCanvasBridge::JsLineDashOffsetGetter(JSContext* ctx, JSValueConst value)
1799 {
1800     return JS_GetPropertyStr(ctx, value, "__lineDash");
1801 }
1802 
JsLineDashOffsetSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1803 JSValue OffscreenCanvasBridge::JsLineDashOffsetSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1804 {
1805     double dashoffset = GetJsDoubleVal(ctx, proto);
1806     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1807     if (bridge) {
1808         bridge->offscreenCanvas_->SetLineDashOffset(dashoffset);
1809     }
1810 
1811     JS_SetPropertyStr(ctx, value, "__lineDash", JS_DupValue(ctx, proto));
1812     return JS_NULL;
1813 }
1814 
JsShadowBlurGetter(JSContext * ctx,JSValueConst value)1815 JSValue OffscreenCanvasBridge::JsShadowBlurGetter(JSContext* ctx, JSValueConst value)
1816 {
1817     return JS_GetPropertyStr(ctx, value, "__shadowBlur");
1818 }
1819 
JsShadowBlurSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1820 JSValue OffscreenCanvasBridge::JsShadowBlurSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1821 {
1822     double blur = GetJsDoubleVal(ctx, proto);
1823     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1824     if (bridge) {
1825         bridge->offscreenCanvas_->SetShadowBlur(blur);
1826     }
1827     JS_SetPropertyStr(ctx, value, "__shadowBlur", JS_DupValue(ctx, proto));
1828     return JS_NULL;
1829 }
1830 
JsShadowColorGetter(JSContext * ctx,JSValueConst value)1831 JSValue OffscreenCanvasBridge::JsShadowColorGetter(JSContext* ctx, JSValueConst value)
1832 {
1833     return JS_GetPropertyStr(ctx, value, "__shadowColor");
1834 }
1835 
JsShadowColorSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1836 JSValue OffscreenCanvasBridge::JsShadowColorSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1837 {
1838     ScopedString colorStr(ctx, proto);
1839     auto color = Color::FromString(colorStr.get());
1840     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1841     if (bridge) {
1842         bridge->offscreenCanvas_->SetShadowColor(color);
1843     }
1844     JS_SetPropertyStr(ctx, value, "__shadowColor", JS_DupValue(ctx, proto));
1845     return JS_NULL;
1846 }
1847 
JsShadowOffsetXGetter(JSContext * ctx,JSValueConst value)1848 JSValue OffscreenCanvasBridge::JsShadowOffsetXGetter(JSContext* ctx, JSValueConst value)
1849 {
1850     return JS_GetPropertyStr(ctx, value, "__shadowOffsetX");
1851 }
1852 
JsShadowOffsetXSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1853 JSValue OffscreenCanvasBridge::JsShadowOffsetXSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1854 {
1855     double offsetX = GetJsDoubleVal(ctx, proto);
1856     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1857     if (bridge) {
1858         bridge->offscreenCanvas_->SetShadowOffsetX(offsetX);
1859     }
1860     JS_SetPropertyStr(ctx, value, "__shadowOffsetX", JS_DupValue(ctx, proto));
1861     return JS_NULL;
1862 }
1863 
JsShadowOffsetYGetter(JSContext * ctx,JSValueConst value)1864 JSValue OffscreenCanvasBridge::JsShadowOffsetYGetter(JSContext* ctx, JSValueConst value)
1865 {
1866     return JS_GetPropertyStr(ctx, value, "__shadowOffsetY");
1867 }
1868 
JsShadowOffsetYSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1869 JSValue OffscreenCanvasBridge::JsShadowOffsetYSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1870 {
1871     double offsetY = GetJsDoubleVal(ctx, proto);
1872     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1873     if (bridge) {
1874         bridge->offscreenCanvas_->SetShadowOffsetY(offsetY);
1875     }
1876     JS_SetPropertyStr(ctx, value, "__shadowOffsetY", JS_DupValue(ctx, proto));
1877     return JS_NULL;
1878 }
1879 
JsSmoothingEnabledGetter(JSContext * ctx,JSValueConst value)1880 JSValue OffscreenCanvasBridge::JsSmoothingEnabledGetter(JSContext* ctx, JSValueConst value)
1881 {
1882     return JS_GetPropertyStr(ctx, value, "__imageSmoothingEnabled");
1883 }
1884 
JsSmoothingEnabledSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1885 JSValue OffscreenCanvasBridge::JsSmoothingEnabledSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1886 {
1887     ScopedString enabledStr(ctx, proto);
1888     if (!enabledStr.get()) {
1889         return JS_NULL;
1890     }
1891     bool enabled = std::string(enabledStr.get()) == "true";
1892     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1893     if (bridge) {
1894         bridge->offscreenCanvas_->SetSmoothingEnabled(enabled);
1895     }
1896 
1897     JS_SetPropertyStr(ctx, value, "__imageSmoothingEnabled", JS_DupValue(ctx, proto));
1898     return JS_NULL;
1899 }
1900 
JsSmoothingQualityGetter(JSContext * ctx,JSValueConst value)1901 JSValue OffscreenCanvasBridge::JsSmoothingQualityGetter(JSContext* ctx, JSValueConst value)
1902 {
1903     return JS_GetPropertyStr(ctx, value, "__imageSmoothingQuality");
1904 }
1905 
JsSmoothingQualitySetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1906 JSValue OffscreenCanvasBridge::JsSmoothingQualitySetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1907 {
1908     ScopedString qualityStr(ctx, proto);
1909     if (!qualityStr.get()) {
1910         return JS_NULL;
1911     }
1912     std::string quality = qualityStr.get();
1913     if (QUALITY_TYPE.find(quality) == QUALITY_TYPE.end()) {
1914         return JS_NULL;
1915     }
1916 
1917     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1918     if (bridge) {
1919         bridge->offscreenCanvas_->SetSmoothingQuality(quality);
1920     }
1921 
1922     JS_SetPropertyStr(ctx, value, "__imageSmoothingQuality", JS_DupValue(ctx, proto));
1923     return JS_NULL;
1924 }
1925 
JsFilterParamGetter(JSContext * ctx,JSValueConst value)1926 JSValue OffscreenCanvasBridge::JsFilterParamGetter(JSContext* ctx, JSValueConst value)
1927 {
1928     return JS_GetPropertyStr(ctx, value, "__filter");
1929 }
1930 
JsFilterParamSetter(JSContext * ctx,JSValueConst value,JSValueConst proto)1931 JSValue OffscreenCanvasBridge::JsFilterParamSetter(JSContext* ctx, JSValueConst value, JSValueConst proto)
1932 {
1933     ScopedString qualityStr(ctx, proto);
1934     if (!qualityStr.get()) {
1935         return JS_NULL;
1936     }
1937     std::string quality = qualityStr.get();
1938     auto bridge = GetOffscreenCanvasBridge(ctx, value);
1939     if (bridge) {
1940         bridge->offscreenCanvas_->SetFilterParam(quality);
1941     }
1942     JS_SetPropertyStr(ctx, value, "__filter", JS_DupValue(ctx, proto));
1943     return JS_NULL;
1944 }
1945 
JsIsPointInStroke(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1946 JSValue OffscreenCanvasBridge::JsIsPointInStroke(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1947 {
1948     if (!argv || ((argc != 2) && (argc != 3))) {
1949         return JS_NULL;
1950     }
1951     bool ret = false;
1952     if (argv != nullptr && argc == 2) {
1953         double x = GetJsDoubleVal(ctx, argv[0]);
1954         double y = GetJsDoubleVal(ctx, argv[1]);
1955         auto bridge = GetOffscreenCanvasBridge(ctx, value);
1956         if (bridge) {
1957             ret = bridge->offscreenCanvas_->IsPointInStroke(x, y);
1958         }
1959         return JS_NewInt32(ctx, ret ? 1 : 0);
1960     }
1961 
1962     if (argv != nullptr && argc == 3) {
1963         double x = GetJsDoubleVal(ctx, argv[1]);
1964         double y = GetJsDoubleVal(ctx, argv[2]);
1965         JSValue typeVal = JS_GetPropertyStr(ctx, argv[0], "__type");
1966         ScopedString type(ctx, typeVal);
1967         if (std::strcmp(type.get(), "path2d") != 0) {
1968             LOGE("Stroke Path2D failed, target is not path.");
1969             return JS_NULL;
1970         }
1971         auto path = GetPath2D(ctx, argv[0]);
1972         if (path == nullptr) {
1973             LOGE("Stroke Path2D failed, target path is null.");
1974             return JS_NULL;
1975         }
1976         auto bridge = GetOffscreenCanvasBridge(ctx, value);
1977         if (bridge) {
1978             ret = bridge->offscreenCanvas_->IsPointInStroke(path, x, y);
1979         }
1980         return JS_NewInt32(ctx, ret ? 1 : 0);
1981     }
1982     return JS_NewInt32(ctx, ret ? 1 : 0);
1983 }
1984 
JsIsPointInPath(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1985 JSValue OffscreenCanvasBridge::JsIsPointInPath(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1986 {
1987     if (!argv || ((argc != 2) && (argc != 3))) {
1988         return JS_NULL;
1989     }
1990     bool ret = false;
1991     if (argv != nullptr && argc == 2) {
1992         double x = GetJsDoubleVal(ctx, argv[0]);
1993         double y = GetJsDoubleVal(ctx, argv[1]);
1994         auto bridge = GetOffscreenCanvasBridge(ctx, value);
1995         if (bridge) {
1996             ret = bridge->offscreenCanvas_->IsPointInPath(x, y);
1997         }
1998         return JS_NewInt32(ctx, ret ? 1 : 0);
1999     }
2000 
2001     if (argv != nullptr && argc == 3) {
2002         double x = GetJsDoubleVal(ctx, argv[1]);
2003         double y = GetJsDoubleVal(ctx, argv[2]);
2004         JSValue typeVal = JS_GetPropertyStr(ctx, argv[0], "__type");
2005         ScopedString type(ctx, typeVal);
2006         if (std::strcmp(type.get(), "path2d") != 0) {
2007             LOGE("Stroke Path2D failed, target is not path.");
2008             return JS_NULL;
2009         }
2010         auto path = GetPath2D(ctx, argv[0]);
2011         if (path == nullptr) {
2012             LOGE("Stroke Path2D failed, target path is null.");
2013             return JS_NULL;
2014         }
2015         auto bridge = GetOffscreenCanvasBridge(ctx, value);
2016         if (bridge) {
2017             ret = bridge->offscreenCanvas_->IsPointInPath(path, x, y);
2018         }
2019         return JS_NewInt32(ctx, ret ? 1 : 0);
2020     }
2021     return JS_NewInt32(ctx, ret ? 1 : 0);
2022 }
2023 
JsResetTransform(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2024 JSValue OffscreenCanvasBridge::JsResetTransform(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2025 {
2026     auto bridge = GetOffscreenCanvasBridge(ctx, value);
2027     if (bridge) {
2028         bridge->offscreenCanvas_->ResetTransform();
2029     }
2030 
2031     return JS_NULL;
2032 }
2033 
JsFillText(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2034 JSValue OffscreenCanvasBridge::JsFillText(
2035     JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2036 {
2037     // 3 parameters: fillText(text, x, y, [maxWidth])
2038     if ((!argv) || (argc != 3)) {
2039         LOGE("argc error, argc = %{private}d", argc);
2040         return JS_NULL;
2041     }
2042     ScopedString arg(ctx, argv[0]);
2043     if (!arg.get()) {
2044         return JS_NULL;
2045     }
2046     auto textState = JsParseTextDirection(ctx, value);
2047 
2048     std::string text = arg.get();
2049     double x = GetJsDoubleVal(ctx, argv[1]);
2050     double y = GetJsDoubleVal(ctx, argv[2]);
2051 
2052     auto bridge = GetOffscreenCanvasBridge(ctx, value);
2053     if (bridge) {
2054         bridge->offscreenCanvas_->FillText(text, x, y, textState);
2055     }
2056 
2057     return JS_NULL;
2058 }
2059 
JsStrokeText(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2060 JSValue OffscreenCanvasBridge::JsStrokeText(
2061     JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2062 {
2063     // 3 parameters: fillText(text, x, y, [maxWidth])
2064     if ((!argv) || (argc != 3)) {
2065         LOGE("argc error, argc = %{private}d", argc);
2066         return JS_NULL;
2067     }
2068     ScopedString arg(ctx, argv[0]);
2069     if (!arg.get()) {
2070         return JS_NULL;
2071     }
2072 
2073     auto textState = JsParseTextDirection(ctx, value);
2074     std::string text = arg.get();
2075     double x = GetJsDoubleVal(ctx, argv[1]);
2076     double y = GetJsDoubleVal(ctx, argv[2]);
2077 
2078     auto bridge = GetOffscreenCanvasBridge(ctx, value);
2079     if (bridge) {
2080         bridge->offscreenCanvas_->StrokeText(text, x, y, textState);
2081     }
2082 
2083     return JS_NULL;
2084 }
2085 
JsMeasureText(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2086 JSValue OffscreenCanvasBridge::JsMeasureText(
2087     JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2088 {
2089     // this func should return TextMetrics, including the width of the text
2090     LOGD("Js Measure Text");
2091     // 1 parameter: measureText(text)
2092     if ((!argv) || (argc != 1)) {
2093         LOGE("argc error, argc = %{private}d", argc);
2094         return JS_NULL;
2095     }
2096     ScopedString arg(ctx, argv[0]);
2097     if (!arg.get()) {
2098         LOGW("no value for text");
2099         return JS_NULL;
2100     }
2101     std::string text = arg.get();
2102     auto textState = JsParseTextState(ctx, value);
2103     double width = 0.0;
2104     double height = 0.0;
2105     auto bridge = GetOffscreenCanvasBridge(ctx, value);
2106     if (bridge) {
2107         width = bridge->offscreenCanvas_->MeasureText(text, textState);
2108         height = bridge->offscreenCanvas_->MeasureTextHeight(text, textState);
2109     }
2110 
2111     JSValue textMetrics = JS_NewObject(ctx);
2112     JS_SetPropertyStr(ctx, textMetrics, "width", JS_NewFloat64(ctx, width));
2113     JS_SetPropertyStr(ctx, textMetrics, "height", JS_NewFloat64(ctx, height));
2114     return textMetrics;
2115 }
2116 } // namespace OHOS::Ace::Framework
2117