• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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