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