• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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/js_render_image.h"
17 
18 #include "frameworks/core/common/container.h"
19 #include "bridge/declarative_frontend/jsview/js_rendering_context.h"
20 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
21 #include "napi/native_api.h"
22 #include "napi/native_node_api.h"
23 
24 namespace OHOS::Ace::Framework {
25 
BindNativeFunction(napi_env env,napi_value object,const char * name,napi_callback func)26 void BindNativeFunction(napi_env env, napi_value object, const char* name, napi_callback func)
27 {
28     std::string funcName(name);
29     napi_value result = nullptr;
30     napi_create_function(env, funcName.c_str(), funcName.length(), func, nullptr, &result);
31     napi_set_named_property(env, object, name, result);
32 }
33 
GetNapiCallbackInfoAndThis(napi_env env,napi_callback_info info)34 void* GetNapiCallbackInfoAndThis(napi_env env, napi_callback_info info)
35 {
36     napi_value value = nullptr;
37     napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &value, nullptr);
38     if (status != napi_ok) {
39         return nullptr;
40     }
41     void* result = nullptr;
42     status = napi_unwrap(env, value, &result);
43     if (status != napi_ok) {
44         return nullptr;
45     }
46     return result;
47 }
48 
DetachImageBitmap(napi_env env,void * value,void * hint)49 void* DetachImageBitmap(napi_env env, void* value, void* hint)
50 {
51     return value;
52 }
53 
AttachImageBitmap(napi_env env,void * value,void *)54 napi_value AttachImageBitmap(napi_env env, void* value, void*)
55 {
56     if (value == nullptr) {
57         LOGW("Invalid parameter.");
58         return nullptr;
59     }
60     auto image = reinterpret_cast<std::weak_ptr<JSRenderImage>*>(value)->lock();
61     if (image == nullptr) {
62         LOGW("Invalid context.");
63         return nullptr;
64     }
65 
66     napi_value imageBitmap = nullptr;
67     napi_create_object(env, &imageBitmap);
68     double width = image->GetWidth();
69     napi_value jsWidth = nullptr;
70     napi_create_double(env, width, &jsWidth);
71     double height = image->GetHeight();
72     napi_value jsHeight = nullptr;
73     napi_create_double(env, height, &jsHeight);
74     napi_value isImageBitmap = nullptr;
75     napi_create_int32(env, 1, &isImageBitmap);
76 
77     napi_set_named_property(env, imageBitmap, "width", jsWidth);
78     napi_set_named_property(env, imageBitmap, "height", jsHeight);
79     napi_set_named_property(env, imageBitmap, "isImageBitmap", isImageBitmap);
80     BindNativeFunction(env, imageBitmap, "close", JSRenderImage::JsClose);
81 
82     napi_coerce_to_native_binding_object(env, imageBitmap, DetachImageBitmap, AttachImageBitmap, value, nullptr);
83     napi_wrap(
84         env, imageBitmap, value,
85         [](napi_env env, void* data, void* hint) {
86             LOGD("Finalizer for image bitmap is called");
87             auto wrapper = reinterpret_cast<JSRenderImage*>(data);
88             delete wrapper;
89             wrapper = nullptr;
90         },
91         nullptr, nullptr);
92     return imageBitmap;
93 }
94 
JSRenderImage()95 JSRenderImage::JSRenderImage() {}
96 
Constructor(napi_env env,napi_callback_info info)97 napi_value JSRenderImage::Constructor(napi_env env, napi_callback_info info)
98 {
99     size_t argc = 1;
100     napi_value argv = nullptr;
101     napi_value thisVar = nullptr;
102     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &argv, &thisVar, nullptr));
103     if (argc <= 0 || argv == nullptr) {
104         LOGW("Invalid args.");
105         return nullptr;
106     }
107     size_t textLen = 0;
108     std::string textString = "";
109     napi_get_value_string_utf8(env, argv, nullptr, 0, &textLen);
110     std::unique_ptr<char[]> text = std::make_unique<char[]>(textLen + 1);
111     napi_get_value_string_utf8(env, argv, text.get(), textLen + 1, &textLen);
112     textString = text.get();
113     auto context = PipelineBase::GetCurrentContext();
114     if (!context) {
115         LOGW("Invalid context.");
116         return nullptr;
117     }
118     if (context->IsFormRender()) {
119         SrcType srcType = ImageSourceInfo::ResolveURIType(textString);
120         bool notSupport = (srcType == SrcType::NETWORK || srcType == SrcType::FILE || srcType == SrcType::DATA_ABILITY);
121         if (notSupport) {
122             LOGE("Not supported src : %{public}s when form render", textString.c_str());
123             return nullptr;
124         }
125     }
126     auto wrapper = new (std::nothrow) JSRenderImage();
127     wrapper->SetInstanceId(OHOS::Ace::Container::CurrentId());
128     wrapper->LoadImage(textString);
129     napi_coerce_to_native_binding_object(env, thisVar, DetachImageBitmap, AttachImageBitmap, wrapper, nullptr);
130     napi_wrap(
131         env, thisVar, wrapper,
132         [](napi_env env, void* data, void* hint) {
133             LOGD("Finalizer for image bitmap is called");
134             auto wrapper = reinterpret_cast<JSRenderImage*>(data);
135             delete wrapper;
136             wrapper = nullptr;
137         },
138         nullptr, nullptr);
139     return thisVar;
140 }
141 
InitImageBitmap(napi_env env)142 napi_value JSRenderImage::InitImageBitmap(napi_env env)
143 {
144     napi_value object = nullptr;
145     napi_create_object(env, &object);
146     napi_value isImageBitmap = nullptr;
147     napi_create_object(env, &isImageBitmap);
148     napi_create_int32(env, 1, &isImageBitmap);
149 
150     napi_property_descriptor desc[] = {
151         DECLARE_NAPI_GETTER_SETTER("width", JsGetWidth, JsSetWidth),
152         DECLARE_NAPI_GETTER_SETTER("height", JsGetHeight, JsSetHeight),
153         DECLARE_NAPI_FUNCTION("close", JsClose),
154         DECLARE_NAPI_PROPERTY("isImageBitmap", isImageBitmap),
155     };
156     napi_status status = napi_define_class(
157         env, "ImageBitmap", NAPI_AUTO_LENGTH, Constructor, nullptr, sizeof(desc) / sizeof(*desc), desc, &object);
158     if (status != napi_ok) {
159         LOGW("Initialize image bitmap failed");
160         return nullptr;
161     }
162     return object;
163 }
164 
JSBind(BindingTarget globalObj,void * nativeEngine)165 void JSRenderImage::JSBind(BindingTarget globalObj, void* nativeEngine)
166 {
167     if (!nativeEngine) {
168         return;
169     }
170     napi_env env = reinterpret_cast<napi_env>(nativeEngine);
171 
172     napi_value jsGlobalObj = nullptr;
173     napi_get_global(env, &jsGlobalObj);
174 
175     napi_value result = InitImageBitmap(env);
176     napi_set_named_property(env, jsGlobalObj, "ImageBitmap", result);
177 }
178 
JsGetWidth(napi_env env,napi_callback_info info)179 napi_value JSRenderImage::JsGetWidth(napi_env env, napi_callback_info info)
180 {
181     JSRenderImage* me = static_cast<JSRenderImage*>(GetNapiCallbackInfoAndThis(env, info));
182     return (me != nullptr) ? me->OnGetWidth(env) : nullptr;
183 }
184 
JsGetHeight(napi_env env,napi_callback_info info)185 napi_value JSRenderImage::JsGetHeight(napi_env env, napi_callback_info info)
186 {
187     JSRenderImage* me = static_cast<JSRenderImage*>(GetNapiCallbackInfoAndThis(env, info));
188     return (me != nullptr) ? me->OnGetHeight(env) : nullptr;
189 }
190 
JsClose(napi_env env,napi_callback_info info)191 napi_value JSRenderImage::JsClose(napi_env env, napi_callback_info info)
192 {
193     JSRenderImage* me = static_cast<JSRenderImage*>(GetNapiCallbackInfoAndThis(env, info));
194     return (me != nullptr) ? me->OnClose() : nullptr;
195 }
196 
JsSetWidth(napi_env env,napi_callback_info info)197 napi_value JSRenderImage::JsSetWidth(napi_env env, napi_callback_info info)
198 {
199     JSRenderImage* me = static_cast<JSRenderImage*>(GetNapiCallbackInfoAndThis(env, info));
200     return (me != nullptr) ? me->OnSetWidth() : nullptr;
201 }
202 
JsSetHeight(napi_env env,napi_callback_info info)203 napi_value JSRenderImage::JsSetHeight(napi_env env, napi_callback_info info)
204 {
205     JSRenderImage* me = static_cast<JSRenderImage*>(GetNapiCallbackInfoAndThis(env, info));
206     return (me != nullptr) ? me->OnSetHeight() : nullptr;
207 }
208 
OnGetWidth(napi_env env)209 napi_value JSRenderImage::OnGetWidth(napi_env env)
210 {
211     double width = 0.0;
212     width = width_;
213     width = PipelineBase::Px2VpWithCurrentDensity(width);
214     napi_value jsWidth = nullptr;
215     napi_create_double(env, width, &jsWidth);
216     return jsWidth;
217 }
218 
OnGetHeight(napi_env env)219 napi_value JSRenderImage::OnGetHeight(napi_env env)
220 {
221     double height = 0.0;
222     height = height_;
223     height = PipelineBase::Px2VpWithCurrentDensity(height);
224     napi_value jsHeight = nullptr;
225     napi_create_double(env, height, &jsHeight);
226     return jsHeight;
227 }
228 
OnSetWidth()229 napi_value JSRenderImage::OnSetWidth()
230 {
231     return nullptr;
232 }
233 
OnSetHeight()234 napi_value JSRenderImage::OnSetHeight()
235 {
236     return nullptr;
237 }
238 
OnClose()239 napi_value JSRenderImage::OnClose()
240 {
241     for (const auto& closeCallback : closeCallbacks_) {
242         if (!closeCallback) {
243             continue;
244         }
245         closeCallback();
246     }
247     width_ = 0;
248     height_ = 0;
249     return nullptr;
250 }
251 
OnImageDataReady()252 void JSRenderImage::OnImageDataReady()
253 {
254     CHECK_NULL_VOID(loadingCtx_);
255     width_ = loadingCtx_->GetImageSize().Width();
256     height_ = loadingCtx_->GetImageSize().Height();
257     loadingCtx_->MakeCanvasImageIfNeed(loadingCtx_->GetImageSize(), true, ImageFit::NONE);
258 }
259 
OnImageLoadSuccess()260 void JSRenderImage::OnImageLoadSuccess()
261 {
262     CHECK_NULL_VOID(loadingCtx_);
263     image_ = loadingCtx_->MoveCanvasImage();
264     CHECK_NULL_VOID(image_);
265     imageObj_ = loadingCtx_->MoveImageObject();
266     CHECK_NULL_VOID(imageObj_);
267     pixelMap_ = image_->GetPixelMap();
268     svgDom_ = imageObj_->GetSVGDom();
269     imageFit_ = loadingCtx_->GetImageFit();
270     imageSize_ = loadingCtx_->GetImageSize();
271 }
272 
OnImageLoadFail(const std::string & errorMsg)273 void JSRenderImage::OnImageLoadFail(const std::string& errorMsg)
274 {
275     width_ = 0;
276     height_ = 0;
277     pixelMap_ = nullptr;
278     svgDom_ = nullptr;
279 }
280 
LoadImage(const std::string & src)281 void JSRenderImage::LoadImage(const std::string& src)
282 {
283     src_ = src;
284     auto sourceInfo = ImageSourceInfo(src);
285     sourceInfo_ = sourceInfo;
286     LoadImage(sourceInfo);
287 }
288 
LoadImage(const ImageSourceInfo & sourceInfo)289 void JSRenderImage::LoadImage(const ImageSourceInfo& sourceInfo)
290 {
291     auto dataReadyCallback = [jsRenderImage = this](const ImageSourceInfo& sourceInfo) {
292         CHECK_NULL_VOID(jsRenderImage);
293         jsRenderImage->OnImageDataReady();
294     };
295     auto loadSuccessCallback = [jsRenderImage = this](const ImageSourceInfo& sourceInfo) {
296         CHECK_NULL_VOID(jsRenderImage);
297         jsRenderImage->OnImageLoadSuccess();
298     };
299     auto loadFailCallback = [jsRenderImage = this](const ImageSourceInfo& sourceInfo, const std::string& errorMsg) {
300         CHECK_NULL_VOID(jsRenderImage);
301         jsRenderImage->OnImageLoadFail(errorMsg);
302     };
303     NG::LoadNotifier loadNotifier(dataReadyCallback, loadSuccessCallback, loadFailCallback);
304     loadingCtx_ = AceType::MakeRefPtr<NG::ImageLoadingContext>(sourceInfo, std::move(loadNotifier), true);
305     loadingCtx_->LoadImageData();
306 }
307 
GetSrc()308 std::string JSRenderImage::GetSrc()
309 {
310     return src_;
311 }
312 
GetWidth()313 double JSRenderImage::GetWidth()
314 {
315     return width_;
316 }
317 
GetHeight()318 double JSRenderImage::GetHeight()
319 {
320     return height_;
321 }
322 
SetCloseCallback(std::function<void ()> && callback)323 void JSRenderImage::SetCloseCallback(std::function<void()>&& callback)
324 {
325     closeCallbacks_.emplace_back(std::move(callback));
326 }
327 } // namespace OHOS::Ace::Framework
328