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