1 /*
2 * Copyright (c) 2021-2024 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 "bridge/declarative_frontend/jsview/canvas/js_offscreen_rendering_context.h"
17
18 #include "base/utils/utils.h"
19 #include "bridge/common/utils/engine_helper.h"
20 #include "bridge/declarative_frontend/engine/js_converter.h"
21 #include "bridge/declarative_frontend/jsview/models/canvas/offscreen_canvas_rendering_context_2d_model_impl.h"
22 #include "core/components_ng/pattern/canvas/offscreen_canvas_pattern.h"
23 #include "core/components_ng/pattern/canvas/offscreen_canvas_rendering_context_2d_model_ng.h"
24
25 namespace OHOS::Ace::Framework {
26 std::mutex JSOffscreenRenderingContext::mutex_;
27 std::unordered_map<uint32_t, RefPtr<AceType>> JSOffscreenRenderingContext::offscreenPatternMap_;
28 uint32_t JSOffscreenRenderingContext::offscreenPatternCount_ = 0;
29
JSOffscreenRenderingContext()30 JSOffscreenRenderingContext::JSOffscreenRenderingContext()
31 {
32 apiVersion_ = Container::GetCurrentApiTargetVersion();
33 id_ = offscreenPatternCount_;
34 #ifdef NG_BUILD
35 renderingContext2DModel_ = AceType::MakeRefPtr<NG::OffscreenCanvasRenderingContext2DModelNG>();
36 #else
37 if (Container::IsCurrentUseNewPipeline()) {
38 renderingContext2DModel_ = AceType::MakeRefPtr<NG::OffscreenCanvasRenderingContext2DModelNG>();
39 } else {
40 renderingContext2DModel_ = AceType::MakeRefPtr<Framework::OffscreenCanvasRenderingContext2DModelImpl>();
41 }
42 #endif
43 }
44
JSBind(BindingTarget globalObj)45 void JSOffscreenRenderingContext::JSBind(BindingTarget globalObj)
46 {
47 // Define the class "OffscreenCanvasRenderingContext2D"
48 JSClass<JSOffscreenRenderingContext>::Declare("OffscreenCanvasRenderingContext2D");
49
50 // Define all properties of the "OffscreenCanvasRenderingContext2D"
51 JSClass<JSOffscreenRenderingContext>::CustomProperty(
52 "filter", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetFilter);
53 JSClass<JSOffscreenRenderingContext>::CustomProperty(
54 "direction", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetDirection);
55 JSClass<JSOffscreenRenderingContext>::CustomProperty(
56 "fillStyle", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetFillStyle);
57 JSClass<JSOffscreenRenderingContext>::CustomProperty(
58 "strokeStyle", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetStrokeStyle);
59 JSClass<JSOffscreenRenderingContext>::CustomProperty(
60 "lineCap", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetLineCap);
61 JSClass<JSOffscreenRenderingContext>::CustomProperty(
62 "lineJoin", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetLineJoin);
63 JSClass<JSOffscreenRenderingContext>::CustomProperty(
64 "miterLimit", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetMiterLimit);
65 JSClass<JSOffscreenRenderingContext>::CustomProperty(
66 "lineWidth", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetLineWidth);
67 JSClass<JSOffscreenRenderingContext>::CustomProperty(
68 "font", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetFont);
69 JSClass<JSOffscreenRenderingContext>::CustomProperty(
70 "textAlign", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetTextAlign);
71 JSClass<JSOffscreenRenderingContext>::CustomProperty(
72 "textBaseline", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetTextBaseline);
73 JSClass<JSOffscreenRenderingContext>::CustomProperty(
74 "globalAlpha", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetGlobalAlpha);
75 JSClass<JSOffscreenRenderingContext>::CustomProperty(
76 "globalCompositeOperation", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetGlobalCompositeOperation);
77 JSClass<JSOffscreenRenderingContext>::CustomProperty(
78 "lineDashOffset", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetLineDashOffset);
79 JSClass<JSOffscreenRenderingContext>::CustomProperty(
80 "shadowBlur", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetShadowBlur);
81 JSClass<JSOffscreenRenderingContext>::CustomProperty(
82 "shadowColor", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetShadowColor);
83 JSClass<JSOffscreenRenderingContext>::CustomProperty(
84 "shadowOffsetX", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetShadowOffsetX);
85 JSClass<JSOffscreenRenderingContext>::CustomProperty(
86 "shadowOffsetY", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetShadowOffsetY);
87 JSClass<JSOffscreenRenderingContext>::CustomProperty(
88 "imageSmoothingEnabled", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetImageSmoothingEnabled);
89 JSClass<JSOffscreenRenderingContext>::CustomProperty(
90 "imageSmoothingQuality", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetImageSmoothingQuality);
91 JSClass<JSOffscreenRenderingContext>::CustomProperty(
92 "letterSpacing", &JSCanvasRenderer::JSGetEmpty, &JSCanvasRenderer::JsSetLetterSpacing);
93
94 // Define all methods of the "OffscreenCanvasRenderingContext2D"
95 JSClass<JSOffscreenRenderingContext>::CustomMethod(
96 "transferToImageBitmap", &JSOffscreenRenderingContext::JsTransferToImageBitmap);
97 JSClass<JSOffscreenRenderingContext>::CustomMethod("toDataURL", &JSCanvasRenderer::JsToDataUrl);
98 JSClass<JSOffscreenRenderingContext>::CustomMethod(
99 "createRadialGradient", &JSCanvasRenderer::JsCreateRadialGradient);
100 JSClass<JSOffscreenRenderingContext>::CustomMethod("fillRect", &JSCanvasRenderer::JsFillRect);
101 JSClass<JSOffscreenRenderingContext>::CustomMethod("strokeRect", &JSCanvasRenderer::JsStrokeRect);
102 JSClass<JSOffscreenRenderingContext>::CustomMethod("clearRect", &JSCanvasRenderer::JsClearRect);
103 JSClass<JSOffscreenRenderingContext>::CustomMethod(
104 "createLinearGradient", &JSCanvasRenderer::JsCreateLinearGradient);
105 JSClass<JSOffscreenRenderingContext>::CustomMethod("fillText", &JSCanvasRenderer::JsFillText);
106 JSClass<JSOffscreenRenderingContext>::CustomMethod("strokeText", &JSCanvasRenderer::JsStrokeText);
107 JSClass<JSOffscreenRenderingContext>::CustomMethod("measureText", &JSCanvasRenderer::JsMeasureText);
108 JSClass<JSOffscreenRenderingContext>::CustomMethod("moveTo", &JSCanvasRenderer::JsMoveTo);
109 JSClass<JSOffscreenRenderingContext>::CustomMethod("lineTo", &JSCanvasRenderer::JsLineTo);
110 JSClass<JSOffscreenRenderingContext>::CustomMethod("bezierCurveTo", &JSCanvasRenderer::JsBezierCurveTo);
111 JSClass<JSOffscreenRenderingContext>::CustomMethod("quadraticCurveTo", &JSCanvasRenderer::JsQuadraticCurveTo);
112 JSClass<JSOffscreenRenderingContext>::CustomMethod("arcTo", &JSCanvasRenderer::JsArcTo);
113 JSClass<JSOffscreenRenderingContext>::CustomMethod("arc", &JSCanvasRenderer::JsArc);
114 JSClass<JSOffscreenRenderingContext>::CustomMethod("ellipse", &JSCanvasRenderer::JsEllipse);
115 JSClass<JSOffscreenRenderingContext>::CustomMethod("fill", &JSCanvasRenderer::JsFill);
116 JSClass<JSOffscreenRenderingContext>::CustomMethod("stroke", &JSCanvasRenderer::JsStroke);
117 JSClass<JSOffscreenRenderingContext>::CustomMethod("clip", &JSCanvasRenderer::JsClip);
118 JSClass<JSOffscreenRenderingContext>::CustomMethod("rect", &JSCanvasRenderer::JsRect);
119 JSClass<JSOffscreenRenderingContext>::CustomMethod("roundRect", &JSCanvasRenderer::JsRoundRect);
120 JSClass<JSOffscreenRenderingContext>::CustomMethod("beginPath", &JSCanvasRenderer::JsBeginPath);
121 JSClass<JSOffscreenRenderingContext>::CustomMethod("closePath", &JSCanvasRenderer::JsClosePath);
122 JSClass<JSOffscreenRenderingContext>::CustomMethod("restore", &JSCanvasRenderer::JsRestore);
123 JSClass<JSOffscreenRenderingContext>::CustomMethod("save", &JSCanvasRenderer::JsSave);
124 JSClass<JSOffscreenRenderingContext>::CustomMethod("rotate", &JSCanvasRenderer::JsRotate);
125 JSClass<JSOffscreenRenderingContext>::CustomMethod("scale", &JSCanvasRenderer::JsScale);
126 JSClass<JSOffscreenRenderingContext>::CustomMethod("getTransform", &JSCanvasRenderer::JsGetTransform);
127 JSClass<JSOffscreenRenderingContext>::CustomMethod("setTransform", &JSCanvasRenderer::JsSetTransform);
128 JSClass<JSOffscreenRenderingContext>::CustomMethod("resetTransform", &JSCanvasRenderer::JsResetTransform);
129 JSClass<JSOffscreenRenderingContext>::CustomMethod("transform", &JSCanvasRenderer::JsTransform);
130 JSClass<JSOffscreenRenderingContext>::CustomMethod("translate", &JSCanvasRenderer::JsTranslate);
131 JSClass<JSOffscreenRenderingContext>::CustomMethod("setLineDash", &JSCanvasRenderer::JsSetLineDash);
132 JSClass<JSOffscreenRenderingContext>::CustomMethod("getLineDash", &JSCanvasRenderer::JsGetLineDash);
133 JSClass<JSOffscreenRenderingContext>::CustomMethod("drawImage", &JSCanvasRenderer::JsDrawImage);
134 JSClass<JSOffscreenRenderingContext>::CustomMethod("createPattern", &JSCanvasRenderer::JsCreatePattern);
135 JSClass<JSOffscreenRenderingContext>::CustomMethod("createImageData", &JSCanvasRenderer::JsCreateImageData);
136 JSClass<JSOffscreenRenderingContext>::CustomMethod("putImageData", &JSCanvasRenderer::JsPutImageData);
137 JSClass<JSOffscreenRenderingContext>::CustomMethod("getImageData", &JSCanvasRenderer::JsGetImageData);
138 JSClass<JSOffscreenRenderingContext>::CustomMethod("getJsonData", &JSCanvasRenderer::JsGetJsonData);
139 JSClass<JSOffscreenRenderingContext>::CustomMethod("getPixelMap", &JSCanvasRenderer::JsGetPixelMap);
140 JSClass<JSOffscreenRenderingContext>::CustomMethod("setPixelMap", &JSCanvasRenderer::JsSetPixelMap);
141 JSClass<JSOffscreenRenderingContext>::CustomMethod("createConicGradient", &JSCanvasRenderer::JsCreateConicGradient);
142 JSClass<JSOffscreenRenderingContext>::CustomMethod("saveLayer", &JSCanvasRenderer::JsSaveLayer);
143 JSClass<JSOffscreenRenderingContext>::CustomMethod("restoreLayer", &JSCanvasRenderer::JsRestoreLayer);
144 JSClass<JSOffscreenRenderingContext>::CustomMethod("reset", &JSCanvasRenderer::JsReset);
145
146 // Register the "OffscreenCanvasRenderingContext2D" to the golbal object of the vm
147 JSClass<JSOffscreenRenderingContext>::Bind(
148 globalObj, JSOffscreenRenderingContext::Constructor, JSOffscreenRenderingContext::Destructor);
149 }
150
151 // OffscreenCanvasRenderingContext2D(width: number, height: number, settings?: RenderingContextSettings,
152 // unit?: LengthMetricsUnit)
Constructor(const JSCallbackInfo & args)153 void JSOffscreenRenderingContext::Constructor(const JSCallbackInfo& args)
154 {
155 auto jsRenderContext = Referenced::MakeRefPtr<JSOffscreenRenderingContext>();
156 jsRenderContext->IncRefCount();
157 args.SetReturnValue(Referenced::RawPtr(jsRenderContext));
158
159 double width = 0.0;
160 double height = 0.0;
161 double density = jsRenderContext->GetDensity();
162 if (args.GetDoubleArg(0, width) && args.GetDoubleArg(1, height)) {
163 width *= density;
164 height *= density;
165 jsRenderContext->SetWidth(width);
166 jsRenderContext->SetHeight(height);
167 auto renderingContext =
168 AceType::DynamicCast<OffscreenCanvasRenderingContext2DModel>(jsRenderContext->renderingContext2DModel_);
169 auto offscreenPattern =
170 renderingContext->CreateOffscreenPattern(round(width), round(height));
171 CHECK_NULL_VOID(offscreenPattern);
172 size_t bitmapSize = renderingContext->GetBitmapSize(offscreenPattern);
173 args.SetSize(bitmapSize);
174 jsRenderContext->SetOffscreenPattern(offscreenPattern);
175 std::lock_guard<std::mutex> lock(mutex_);
176 offscreenPatternMap_[offscreenPatternCount_++] = offscreenPattern;
177 }
178 auto* jsContextSetting = args.UnwrapArg<JSRenderingContextSettings>(2);
179 if (jsContextSetting) {
180 bool anti = jsContextSetting->GetAntialias();
181 jsRenderContext->SetAnti(anti);
182 jsRenderContext->SetAntiAlias();
183 int32_t unit = 0;
184 if (args.GetInt32Arg(3, unit) && (static_cast<CanvasUnit>(unit) == CanvasUnit::PX)) { // 3: index of parameter
185 jsRenderContext->SetUnit(CanvasUnit::PX);
186 }
187 }
188 jsRenderContext->SetDensity();
189 }
190
Destructor(JSOffscreenRenderingContext * context)191 void JSOffscreenRenderingContext::Destructor(JSOffscreenRenderingContext* context)
192 {
193 CHECK_NULL_VOID(context);
194 uint32_t contextId = context->GetId();
195 context->DecRefCount();
196 std::lock_guard<std::mutex> lock(mutex_);
197 offscreenPatternMap_.erase(contextId);
198 }
199
JsTransferToImageBitmap(const JSCallbackInfo & info)200 void JSOffscreenRenderingContext::JsTransferToImageBitmap(const JSCallbackInfo& info)
201 {
202 ContainerScope scope(instanceId_);
203 #if !defined(PREVIEW)
204 auto engine = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
205 #else
206 auto engine = EngineHelper::GetCurrentEngineSafely();
207 #endif
208 CHECK_NULL_VOID(engine);
209 NativeEngine* nativeEngine = engine->GetNativeEngine();
210 CHECK_NULL_VOID(nativeEngine);
211 napi_env env = reinterpret_cast<napi_env>(nativeEngine);
212 napi_value renderImage = nullptr;
213 napi_create_object(env, &renderImage);
214 auto offscreenCanvasPattern = AceType::DynamicCast<NG::OffscreenCanvasPattern>(GetOffscreenPattern(id_));
215 CHECK_NULL_VOID(offscreenCanvasPattern);
216 auto pixelMap = offscreenCanvasPattern->TransferToImageBitmap();
217 if (!JSRenderImage::CreateJSRenderImage(env, pixelMap, renderImage)) {
218 return;
219 }
220 void* nativeObj = nullptr;
221 NAPI_CALL_RETURN_VOID(env, napi_unwrap(env, renderImage, &nativeObj));
222 auto jsImage = (JSRenderImage*)nativeObj;
223 CHECK_NULL_VOID(jsImage);
224 #ifndef PIXEL_MAP_SUPPORTED
225 auto imageData = offscreenCanvasPattern->GetImageData(0, 0, width_, height_);
226 CHECK_NULL_VOID(imageData);
227 jsImage->SetImageData(std::make_shared<Ace::ImageData>(*imageData));
228 #endif
229 jsImage->SetUnit(GetUnit());
230 jsImage->SetWidth(GetWidth());
231 jsImage->SetHeight(GetHeight());
232 info.SetReturnValue(JsConverter::ConvertNapiValueToJsVal(renderImage));
233 }
234 } // namespace OHOS::Ace::Framework
235