• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-2023 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 #include "async_call.h"
16 #include "napi_common_want.h"
17 #include "paste_data_record.h"
18 #include "pasteboard_common.h"
19 #include "pasteboard_hilog.h"
20 #include "pasteboard_js_err.h"
21 #include "pasteboard_napi.h"
22 #include "pastedata_napi.h"
23 #include "pastedata_record_napi.h"
24 
25 using namespace OHOS::MiscServices;
26 using namespace OHOS::Media;
27 
28 namespace OHOS {
29 namespace MiscServicesNapi {
30 static thread_local napi_ref g_pasteDataRecord = nullptr;
31 const int ARGC_TYPE_SET0 = 0;
32 const int ARGC_TYPE_SET1 = 1;
33 constexpr int32_t MIMETYPE_MAX_SIZE = 1024;
34 
PasteDataRecordNapi()35 PasteDataRecordNapi::PasteDataRecordNapi() : env_(nullptr)
36 {
37 }
38 
~PasteDataRecordNapi()39 PasteDataRecordNapi::~PasteDataRecordNapi()
40 {
41 }
42 
NewInstanceByRecord(napi_env env,napi_value & instance,const std::shared_ptr<MiscServices::PasteDataRecord> & record)43 bool PasteDataRecordNapi::NewInstanceByRecord(
44     napi_env env, napi_value &instance, const std::shared_ptr<MiscServices::PasteDataRecord> &record)
45 {
46     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
47     PasteDataRecordNapi *obj = nullptr;
48     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
49     if ((status != napi_ok) || (obj == nullptr)) {
50         return false;
51     }
52     obj->value_ = record;
53     obj->JSFillInstance(env, instance);
54     return true;
55 }
56 
NewHtmlTextRecordInstance(napi_env env,const std::string & text,napi_value & instance)57 bool PasteDataRecordNapi::NewHtmlTextRecordInstance(napi_env env, const std::string &text, napi_value &instance)
58 {
59     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
60     PasteDataRecordNapi *obj = nullptr;
61     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
62     if ((status != napi_ok) || (obj == nullptr)) {
63         return false;
64     }
65     obj->value_ = PasteboardClient::GetInstance()->CreateHtmlTextRecord(text);
66     obj->JSFillInstance(env, instance);
67     return true;
68 }
69 
NewPlainTextRecordInstance(napi_env env,const std::string & text,napi_value & instance)70 bool PasteDataRecordNapi::NewPlainTextRecordInstance(napi_env env, const std::string &text, napi_value &instance)
71 {
72     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
73     PasteDataRecordNapi *obj = nullptr;
74     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
75     if ((status != napi_ok) || (obj == nullptr)) {
76         return false;
77     }
78     obj->value_ = PasteboardClient::GetInstance()->CreatePlainTextRecord(text);
79     obj->JSFillInstance(env, instance);
80     return true;
81 }
82 
NewPixelMapRecordInstance(napi_env env,const std::shared_ptr<PixelMap> pixelMap,napi_value & instance)83 bool PasteDataRecordNapi::NewPixelMapRecordInstance(
84     napi_env env, const std::shared_ptr<PixelMap> pixelMap, napi_value &instance)
85 {
86     if (pixelMap == nullptr) {
87         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "pixelMap is nullptr.");
88         return false;
89     }
90 
91     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
92     PasteDataRecordNapi *obj = nullptr;
93     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
94     if ((status != napi_ok) || (obj == nullptr)) {
95         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "unwrap failed.");
96         return false;
97     }
98     obj->value_ = PasteboardClient::GetInstance()->CreatePixelMapRecord(pixelMap);
99     obj->JSFillInstance(env, instance);
100     return true;
101 }
102 
NewUriRecordInstance(napi_env env,const std::string & text,napi_value & instance)103 bool PasteDataRecordNapi::NewUriRecordInstance(napi_env env, const std::string &text, napi_value &instance)
104 {
105     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
106     PasteDataRecordNapi *obj = nullptr;
107     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
108     if ((status != napi_ok) || (obj == nullptr)) {
109         return false;
110     }
111     obj->value_ = PasteboardClient::GetInstance()->CreateUriRecord(OHOS::Uri(text));
112     obj->JSFillInstance(env, instance);
113     return true;
114 }
115 
NewWantRecordInstance(napi_env env,const std::shared_ptr<OHOS::AAFwk::Want> want,napi_value & instance)116 bool PasteDataRecordNapi::NewWantRecordInstance(
117     napi_env env, const std::shared_ptr<OHOS::AAFwk::Want> want, napi_value &instance)
118 {
119     if (!want) {
120         return false;
121     }
122 
123     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
124     PasteDataRecordNapi *obj = nullptr;
125     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
126     if ((status != napi_ok) || (obj == nullptr)) {
127         return false;
128     }
129     obj->value_ = PasteboardClient::GetInstance()->CreateWantRecord(want);
130     obj->JSFillInstance(env, instance);
131     return true;
132 }
133 
NewKvRecordInstance(napi_env env,const std::string & mimeType,const std::vector<uint8_t> & arrayBuffer,napi_value & instance)134 bool PasteDataRecordNapi::NewKvRecordInstance(
135     napi_env env, const std::string &mimeType, const std::vector<uint8_t> &arrayBuffer, napi_value &instance)
136 {
137     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
138     PasteDataRecordNapi *obj = nullptr;
139     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
140     if ((status != napi_ok) || (obj == nullptr)) {
141         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "unwrap failed");
142         return false;
143     }
144     obj->value_ = PasteboardClient::GetInstance()->CreateKvRecord(mimeType, arrayBuffer);
145     obj->JSFillInstance(env, instance);
146     return true;
147 }
148 
SetNamedPropertyByStr(napi_env env,napi_value & instance,const char * propName,const char * propValue)149 void PasteDataRecordNapi::SetNamedPropertyByStr(
150     napi_env env, napi_value &instance, const char *propName, const char *propValue)
151 {
152     if (propName == nullptr || propValue == nullptr) {
153         return;
154     }
155     napi_value prop = nullptr;
156     if (napi_create_string_utf8(env, propValue, NAPI_AUTO_LENGTH, &prop) == napi_ok) {
157         napi_set_named_property(env, instance, propName, prop);
158     }
159 }
160 
SetNapiKvData(napi_env env,std::shared_ptr<MineCustomData> customData)161 napi_value PasteDataRecordNapi::SetNapiKvData(napi_env env, std::shared_ptr<MineCustomData> customData)
162 {
163     if (customData == nullptr) {
164         return nullptr;
165     }
166     napi_value jsCustomData = nullptr;
167     napi_create_object(env, &jsCustomData);
168     auto itemData = customData->GetItemData();
169     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "size = %{public}d.", static_cast<uint32_t>(itemData.size()));
170     for (auto &item : itemData) {
171         void *data = nullptr;
172         napi_value arrayBuffer = nullptr;
173         size_t len = item.second.size();
174         NAPI_CALL(env, napi_create_arraybuffer(env, len, &data, &arrayBuffer));
175         if (memcpy_s(data, len, reinterpret_cast<const void *>(item.second.data()), len) != 0) {
176             return nullptr;
177         }
178         NAPI_CALL(env, napi_set_named_property(env, jsCustomData, item.first.c_str(), arrayBuffer));
179         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "mimeType = %{public}s.", item.first.c_str());
180     }
181     return jsCustomData;
182 }
183 
GetNativeKvData(napi_env env,napi_value napiValue)184 std::shared_ptr<MineCustomData> PasteDataRecordNapi::GetNativeKvData(napi_env env, napi_value napiValue)
185 {
186     napi_valuetype valueType = napi_undefined;
187     NAPI_CALL(env, napi_typeof(env, napiValue, &valueType));
188     NAPI_ASSERT(env, valueType == napi_object, "Wrong argument type. Object expected.");
189 
190     napi_value mimeTypes = nullptr;
191     NAPI_CALL(env, napi_get_property_names(env, napiValue, &mimeTypes));
192     uint32_t mimeTypesNum = 0;
193     NAPI_CALL(env, napi_get_array_length(env, mimeTypes, &mimeTypesNum));
194 
195     PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "mimeTypesNum = %{public}u", mimeTypesNum);
196     std::shared_ptr<MineCustomData> customData = std::make_shared<MineCustomData>();
197     for (uint32_t i = 0; i < mimeTypesNum; i++) {
198         napi_value mimeTypeNapi = nullptr;
199         NAPI_CALL(env, napi_get_element(env, mimeTypes, i, &mimeTypeNapi));
200 
201         std::string mimeType;
202         bool ret = GetValue(env, mimeTypeNapi, mimeType);
203         if (!ret || (mimeType.size() > MIMETYPE_MAX_SIZE) || mimeType == "") {
204             return nullptr;
205         }
206         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "mimeType = %{public}s,", mimeType.c_str());
207 
208         napi_value napiArrayBuffer = nullptr;
209         NAPI_CALL(env, napi_get_property(env, napiValue, mimeTypeNapi, &napiArrayBuffer));
210         void *data = nullptr;
211         size_t dataLen;
212         NAPI_CALL(env, napi_get_arraybuffer_info(env, napiArrayBuffer, &data, &dataLen));
213         customData->AddItemData(mimeType,
214             std::vector<uint8_t>(reinterpret_cast<uint8_t *>(data), reinterpret_cast<uint8_t *>(data) + dataLen));
215     }
216     return customData;
217 }
218 
JSFillInstance(napi_env env,napi_value & instance)219 void PasteDataRecordNapi::JSFillInstance(napi_env env, napi_value &instance)
220 {
221     if (value_ == nullptr) {
222         return;
223     }
224     PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "mimeType = %{public}s.", value_->GetMimeType().c_str());
225 
226     auto mimeType = value_->GetMimeType();
227     SetNamedPropertyByStr(env, instance, "mimeType", mimeType.c_str());
228 
229     auto plainText = value_->GetPlainText();
230     if (plainText != nullptr) {
231         SetNamedPropertyByStr(env, instance, "plainText", plainText->c_str());
232         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill plainText.");
233     }
234 
235     auto htmlText = value_->GetHtmlText();
236     if (htmlText != nullptr) {
237         SetNamedPropertyByStr(env, instance, "htmlText", htmlText->c_str());
238         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill htmlText.");
239     }
240 
241     auto uri = value_->GetUri();
242     if (uri != nullptr) {
243         SetNamedPropertyByStr(env, instance, "uri", uri->ToString().c_str());
244         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill uri.");
245     }
246 
247     auto want = value_->GetWant();
248     if (want != nullptr) {
249         napi_value jsWant = OHOS::AppExecFwk::WrapWant(env, *want);
250         napi_set_named_property(env, instance, "want", jsWant);
251         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill want.");
252     }
253 
254     auto pixelMap = value_->GetPixelMap();
255     if (pixelMap != nullptr) {
256         napi_value jsPixelMap = OHOS::Media::PixelMapNapi::CreatePixelMap(env, pixelMap);
257         napi_set_named_property(env, instance, "pixelMap", jsPixelMap);
258         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill pixelMap.");
259     }
260 
261     auto customData = value_->GetCustomData();
262     if (customData != nullptr) {
263         napi_value jsCustomData = PasteDataRecordNapi::SetNapiKvData(env, customData);
264         napi_set_named_property(env, instance, "data", jsCustomData);
265         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill data.");
266     }
267 }
268 
ConvertToText(napi_env env,napi_callback_info info)269 napi_value PasteDataRecordNapi::ConvertToText(napi_env env, napi_callback_info info)
270 {
271     PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "ConvertToText is called!");
272 
273     struct ExeContext {
274         std::string text;
275         PasteDataRecordNapi *obj = nullptr;
276     };
277     auto exeContext = std::make_shared<ExeContext>();
278     auto input = [exeContext](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
279         // convertToText(callback: AsyncCallback<string>) has 1 args
280         if (argc > 0 &&
281             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
282             return napi_invalid_arg;
283         }
284         PasteDataRecordNapi *obj = nullptr;
285         napi_status status = napi_unwrap(env, self, reinterpret_cast<void **>(&obj));
286         if (status == napi_ok || obj != nullptr) {
287             exeContext->obj = obj;
288         }
289         return napi_ok;
290     };
291 
292     auto exec = [exeContext](AsyncCall::Context *ctx) {
293         if ((exeContext->obj != nullptr) && (exeContext->obj->value_ != nullptr)) {
294             exeContext->text = exeContext->obj->value_->ConvertToText();
295         }
296     };
297     auto output = [exeContext](napi_env env, napi_value *result) -> napi_status {
298         napi_status status =
299             napi_create_string_utf8(env, (exeContext->text).c_str(), (exeContext->text).length(), result);
300         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "napi_create_string_utf8 status = %{public}d", status);
301         return status;
302     };
303 
304     // 0: the AsyncCall at the first position;
305     AsyncCall asyncCall(env, info, std::make_shared<AsyncCall::Context>(std::move(input), std::move(output)), 0);
306     return asyncCall.Call(env, exec);
307 }
308 
ConvertToTextV9(napi_env env,napi_callback_info info)309 napi_value PasteDataRecordNapi::ConvertToTextV9(napi_env env, napi_callback_info info)
310 {
311     PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "ConvertToTextV9 is called!");
312     return ConvertToText(env, info);
313 }
314 
ToPlainText(napi_env env,napi_callback_info info)315 napi_value PasteDataRecordNapi::ToPlainText(napi_env env, napi_callback_info info)
316 {
317     PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "ToPlainText is called!");
318     size_t argc = 1;
319     napi_value argv[1] = { 0 };
320     napi_value thisVar = nullptr;
321 
322     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
323     NAPI_ASSERT(env, argc >= ARGC_TYPE_SET0, "Wrong number of arguments");
324 
325     PasteDataRecordNapi *obj = nullptr;
326     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
327     if ((status != napi_ok) || (obj == nullptr)) {
328         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Get ToPlainText object failed");
329         return nullptr;
330     }
331 
332     std::string str = obj->value_->ConvertToText();
333     napi_value result = nullptr;
334     napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &result);
335     return result;
336 }
337 
PasteDataRecordInit(napi_env env,napi_value exports)338 napi_value PasteDataRecordNapi::PasteDataRecordInit(napi_env env, napi_value exports)
339 {
340     napi_property_descriptor properties[] = {
341         DECLARE_NAPI_FUNCTION("convertToText", ConvertToText),
342         DECLARE_NAPI_FUNCTION("convertToTextV9", ConvertToTextV9),
343         DECLARE_NAPI_FUNCTION("toPlainText", ToPlainText)
344     };
345 
346     napi_status status = napi_ok;
347 
348     napi_value constructor;
349     status = napi_define_class(env, "PasteDataRecord", NAPI_AUTO_LENGTH, New, nullptr,
350         sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
351     if (status != napi_ok) {
352         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to define class at PasteDataRecordInit");
353         return nullptr;
354     }
355 
356     status = napi_create_reference(env, constructor, 1, &g_pasteDataRecord);
357     if (status != napi_ok) {
358         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "PasteDataRecordInit create reference failed");
359         return nullptr;
360     }
361     napi_set_named_property(env, exports, "PasteDataRecord", constructor);
362     return exports;
363 }
364 
Destructor(napi_env env,void * nativeObject,void * finalize_hint)365 void PasteDataRecordNapi::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
366 {
367     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "Destructor");
368     PasteDataRecordNapi *obj = static_cast<PasteDataRecordNapi *>(nativeObject);
369     delete obj;
370 }
371 
New(napi_env env,napi_callback_info info)372 napi_value PasteDataRecordNapi::New(napi_env env, napi_callback_info info)
373 {
374     size_t argc = ARGC_TYPE_SET1;
375     napi_value argv[1] = { 0 };
376     napi_value thisVar = nullptr;
377     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
378 
379     // get native object
380     PasteDataRecordNapi *obj = new PasteDataRecordNapi();
381     obj->env_ = env;
382     ASSERT_CALL(env, napi_wrap(env, thisVar, obj, PasteDataRecordNapi::Destructor, nullptr, nullptr), obj);
383     return thisVar;
384 }
385 
NewInstance(napi_env env,napi_value & instance)386 napi_status PasteDataRecordNapi::NewInstance(napi_env env, napi_value &instance)
387 {
388     napi_status status = napi_invalid_arg;
389 
390     napi_value constructor;
391     status = napi_get_reference_value(env, g_pasteDataRecord, &constructor);
392     if (status != napi_ok) {
393         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "get reference failed");
394         return status;
395     }
396 
397     status = napi_new_instance(env, constructor, 0, nullptr, &instance);
398     if (status != napi_ok) {
399         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "new instance failed");
400         return status;
401     }
402 
403     return napi_ok;
404 }
405 } // namespace MiscServicesNapi
406 } // namespace OHOS
407