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