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