• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "frameworks/bridge/js_frontend/engine/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