1 /*
2 * Copyright (c) 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 "pasteboard_client_adapter_impl.h"
17
18 #include <mutex>
19 #include <securec.h>
20
21 #include "hisysevent_adapter.h"
22 #include "media_errors.h"
23 #include "nweb_log.h"
24 #include "ohos_adapter_helper.h"
25 #include "pasteboard_error.h"
26 #include "remote_uri.h"
27
28 using namespace OHOS::MiscServices;
29 using namespace OHOS::DistributedFS::ModuleRemoteUri;
30
31 namespace OHOS::NWeb {
32 constexpr char PASTE_BOARD_ERROR[] = "PASTE_BOARD_ERROR";
33 constexpr char ERROR_CODE[] = "ERROR_CODE";
34 constexpr char RECORD_SIZE[] = "RECORD_SIZE";
35 constexpr char DATA_TYPE[] = "DATA_TYPE";
36 constexpr char MIMETYPE_HYBRID[] = "hybrid";
37 constexpr char MIMETYPE_NULL[] = "null";
38
PasteboardObserverAdapterImpl(std::shared_ptr<PasteboardObserverAdapter> observer)39 PasteboardObserverAdapterImpl::PasteboardObserverAdapterImpl(
40 std::shared_ptr<PasteboardObserverAdapter> observer)
41 : observer_(observer) {}
42
OnPasteboardChanged()43 void PasteboardObserverAdapterImpl::OnPasteboardChanged()
44 {
45 if (observer_) {
46 observer_->OnPasteboardChanged();
47 }
48 }
49
PasteDataRecordAdapterImpl(std::shared_ptr<PasteDataRecord> record)50 PasteDataRecordAdapterImpl::PasteDataRecordAdapterImpl(
51 std::shared_ptr<PasteDataRecord> record)
52 : record_(record) {}
53
PasteDataRecordAdapterImpl(const std::string & mimeType)54 PasteDataRecordAdapterImpl::PasteDataRecordAdapterImpl(
55 const std::string& mimeType)
56 {
57 builder_ = std::make_shared<PasteDataRecord::Builder>(mimeType);
58 if (builder_) {
59 record_ = builder_->Build();
60 }
61 }
62
PasteDataRecordAdapterImpl(const std::string & mimeType,std::shared_ptr<std::string> htmlText,std::shared_ptr<std::string> plainText)63 PasteDataRecordAdapterImpl::PasteDataRecordAdapterImpl(
64 const std::string& mimeType,
65 std::shared_ptr<std::string> htmlText,
66 std::shared_ptr<std::string> plainText)
67 {
68 record_ = std::make_shared<PasteDataRecord>(mimeType,
69 htmlText,
70 nullptr,
71 plainText,
72 nullptr);
73 }
74
NewRecord(const std::string & mimeType)75 std::shared_ptr<PasteDataRecordAdapter> PasteDataRecordAdapter::NewRecord(
76 const std::string& mimeType)
77 {
78 return std::make_shared<PasteDataRecordAdapterImpl>(mimeType);
79 }
80
NewRecord(const std::string & mimeType,std::shared_ptr<std::string> htmlText,std::shared_ptr<std::string> plainText)81 std::shared_ptr<PasteDataRecordAdapter> PasteDataRecordAdapter::NewRecord(
82 const std::string& mimeType,
83 std::shared_ptr<std::string> htmlText,
84 std::shared_ptr<std::string> plainText)
85 {
86 return std::make_shared<PasteDataRecordAdapterImpl>(mimeType,
87 htmlText,
88 plainText);
89 }
90
SetHtmlText(std::shared_ptr<std::string> htmlText)91 bool PasteDataRecordAdapterImpl::SetHtmlText(std::shared_ptr<std::string> htmlText)
92 {
93 if (builder_) {
94 record_ = builder_->SetHtmlText(htmlText).Build();
95 return true;
96 }
97 WVLOG_E("record_ is null");
98 return false;
99 }
100
SetPlainText(std::shared_ptr<std::string> plainText)101 bool PasteDataRecordAdapterImpl::SetPlainText(std::shared_ptr<std::string> plainText)
102 {
103 if (builder_) {
104 record_ = builder_->SetPlainText(plainText).Build();
105 return true;
106 }
107 WVLOG_E("record_ is null");
108 return false;
109 }
110
SetUri(const std::string & uriString)111 bool PasteDataRecordAdapterImpl::SetUri(const std::string& uriString)
112 {
113 if (uriString.empty() || !builder_) {
114 WVLOG_E("record_ or uriString is null");
115 return false;
116 }
117 std::shared_ptr<OHOS::Uri> uri = std::make_shared<OHOS::Uri>(uriString);
118 record_ = builder_->SetUri(uri).Build();
119 return true;
120 }
121
SetCustomData(PasteCustomData & data)122 bool PasteDataRecordAdapterImpl::SetCustomData(PasteCustomData& data)
123 {
124 if (data.empty() || !builder_) {
125 WVLOG_E("custom data is empty or builder_ is null");
126 return false;
127 }
128 std::shared_ptr<MineCustomData> customData =
129 std::make_shared<MineCustomData>();
130 for (PasteCustomData::iterator iter = data.begin(); iter != data.end(); ++iter) {
131 customData->AddItemData(iter->first, iter->second);
132 }
133 record_ = builder_->SetCustomData(customData).Build();
134 return true;
135 }
136
ImageToClipboardAlphaType(const Media::ImageInfo & imgInfo)137 ClipBoardImageAlphaType PasteDataRecordAdapterImpl::ImageToClipboardAlphaType
138 (const Media::ImageInfo &imgInfo)
139 {
140 switch (imgInfo.alphaType) {
141 case Media::AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN :
142 return ClipBoardImageAlphaType::ALPHA_TYPE_UNKNOWN;
143 case Media::AlphaType::IMAGE_ALPHA_TYPE_OPAQUE :
144 return ClipBoardImageAlphaType::ALPHA_TYPE_OPAQUE;
145 case Media::AlphaType::IMAGE_ALPHA_TYPE_PREMUL :
146 return ClipBoardImageAlphaType::ALPHA_TYPE_PREMULTIPLIED;
147 default :
148 return ClipBoardImageAlphaType::ALPHA_TYPE_UNKNOWN;
149 }
150 }
151
ImageToClipboardColorType(const Media::ImageInfo & imgInfo)152 ClipBoardImageColorType PasteDataRecordAdapterImpl::ImageToClipboardColorType
153 (const Media::ImageInfo &imgInfo)
154 {
155 switch (imgInfo.pixelFormat) {
156 case Media::PixelFormat::RGBA_8888 :
157 return ClipBoardImageColorType::COLOR_TYPE_RGBA_8888;
158 case Media::PixelFormat::BGRA_8888 :
159 return ClipBoardImageColorType::COLOR_TYPE_BGRA_8888;
160 default :
161 return ClipBoardImageColorType::COLOR_TYPE_UNKNOWN;
162 }
163 }
164
ClipboardToImageAlphaType(ClipBoardImageAlphaType alphaType)165 Media::AlphaType PasteDataRecordAdapterImpl::ClipboardToImageAlphaType
166 (ClipBoardImageAlphaType alphaType)
167 {
168 switch (alphaType) {
169 case ClipBoardImageAlphaType::ALPHA_TYPE_UNKNOWN :
170 return Media::AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
171 case ClipBoardImageAlphaType::ALPHA_TYPE_OPAQUE :
172 return Media::AlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
173 case ClipBoardImageAlphaType::ALPHA_TYPE_PREMULTIPLIED :
174 return Media::AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
175 default :
176 return Media::AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
177 }
178 }
179
ClipboardToImageColorType(ClipBoardImageColorType colorType)180 Media::PixelFormat PasteDataRecordAdapterImpl::ClipboardToImageColorType
181 (ClipBoardImageColorType colorType)
182 {
183 switch (colorType) {
184 case ClipBoardImageColorType::COLOR_TYPE_RGBA_8888 :
185 return Media::PixelFormat::RGBA_8888;
186 case ClipBoardImageColorType::COLOR_TYPE_BGRA_8888 :
187 return Media::PixelFormat::BGRA_8888;
188 default :
189 return Media::PixelFormat::UNKNOWN;
190 }
191 }
192
SetImgData(std::shared_ptr<ClipBoardImageDataAdapter> imageData)193 bool PasteDataRecordAdapterImpl::SetImgData(std::shared_ptr<ClipBoardImageDataAdapter> imageData)
194 {
195 if (imageData == nullptr) {
196 WVLOG_E("imageData is null");
197 return false;
198 }
199 Media::InitializationOptions opt;
200 opt.size.width = imageData->GetWidth();
201 opt.size.height = imageData->GetHeight();
202 opt.pixelFormat = ClipboardToImageColorType(imageData->GetColorType());
203 opt.alphaType = ClipboardToImageAlphaType(imageData->GetAlphaType());
204 opt.editable = true;
205 std::unique_ptr<Media::PixelMap> pixelMap = Media::PixelMap::Create(opt);
206 if (pixelMap == nullptr) {
207 WVLOG_E("create pixel map failed");
208 return false;
209 }
210 uint64_t stride = static_cast<uint64_t>(imageData->GetWidth()) << 2;
211 uint64_t bufferSize = stride * static_cast<uint64_t>(imageData->GetHeight());
212 uint32_t ret = pixelMap->WritePixels(reinterpret_cast<const uint8_t *>(imageData->GetData()), bufferSize);
213 if (ret != Media::SUCCESS) {
214 WVLOG_E("write pixel map failed %{public}u", ret);
215 return false;
216 }
217
218 std::shared_ptr<Media::PixelMap> pixelMapIn = move(pixelMap);
219
220 if (!builder_) {
221 WVLOG_E("record_ is null");
222 return false;
223 }
224 record_ = builder_->SetPixelMap(pixelMapIn).Build();
225 return true;
226 }
227
GetMimeType()228 std::string PasteDataRecordAdapterImpl::GetMimeType()
229 {
230 return (record_ != nullptr) ? record_->GetMimeType() : "";
231 }
232
GetHtmlText()233 std::shared_ptr<std::string> PasteDataRecordAdapterImpl::GetHtmlText()
234 {
235 return (record_ != nullptr) ? record_->GetHtmlText() : nullptr;
236 }
237
GetPlainText()238 std::shared_ptr<std::string> PasteDataRecordAdapterImpl::GetPlainText()
239 {
240 return (record_ != nullptr) ? record_->GetPlainText() : nullptr;
241 }
242
GetImgData(std::shared_ptr<ClipBoardImageDataAdapter> imageData)243 bool PasteDataRecordAdapterImpl::GetImgData(std::shared_ptr<ClipBoardImageDataAdapter> imageData)
244 {
245 if (record_ == nullptr) {
246 WVLOG_E("record_ is null");
247 return false;
248 }
249
250 if (imageData == nullptr) {
251 WVLOG_E("imageData is null");
252 return false;
253 }
254
255 std::shared_ptr<Media::PixelMap> pixelMap = record_->GetPixelMap();
256 if (pixelMap == nullptr) {
257 WVLOG_E("pixelMap is null");
258 return false;
259 }
260
261 Media::ImageInfo imgInfo;
262 ClearImgBuffer();
263 bufferSize_ = pixelMap->GetCapacity();
264 if ((bufferSize_ == 0) || (pixelMap->GetPixels() == nullptr)) {
265 WVLOG_E("data in pixel map is empty");
266 return false;
267 }
268
269 imgBuffer_ = static_cast<uint8_t *>(calloc(static_cast<size_t>(bufferSize_), sizeof(uint8_t)));
270 if (imgBuffer_ == nullptr) {
271 WVLOG_E("calloc imgbuffer failed");
272 return false;
273 }
274
275 if (memcpy_s(imgBuffer_, bufferSize_, pixelMap->GetPixels(), bufferSize_)) {
276 WVLOG_E("memcpy imgbuffer failed");
277 ClearImgBuffer();
278 return false;
279 }
280
281 int32_t width = pixelMap->GetWidth();
282 int32_t height = pixelMap->GetHeight();
283 pixelMap->GetImageInfo(imgInfo);
284 int32_t rowBytes = pixelMap->GetRowBytes();
285
286 imageData->SetColorType(ImageToClipboardColorType(imgInfo));
287 imageData->SetAlphaType(ImageToClipboardAlphaType(imgInfo));
288 imageData->SetData((uint32_t *)(imgBuffer_));
289 imageData->SetDataSize(static_cast<size_t>(bufferSize_));
290 imageData->SetWidth(width);
291 imageData->SetHeight(height);
292 imageData->SetRowBytes(static_cast<size_t>(rowBytes));
293 return true;
294 }
295
GetUri()296 std::shared_ptr<std::string> PasteDataRecordAdapterImpl::GetUri()
297 {
298 if (record_ == nullptr) {
299 return nullptr;
300 }
301 auto uri = record_->GetUri();
302 if (uri == nullptr) {
303 return nullptr;
304 }
305 return std::make_shared<std::string>(uri->ToString());
306 }
307
GetCustomData()308 std::shared_ptr<PasteCustomData> PasteDataRecordAdapterImpl::GetCustomData()
309 {
310 if (record_ == nullptr) {
311 return nullptr;
312 }
313 auto customData = record_->GetCustomData();
314 if (customData == nullptr) {
315 return nullptr;
316 }
317 return std::make_shared<PasteCustomData>(customData->GetItemData());
318 }
319
ClearImgBuffer()320 void PasteDataRecordAdapterImpl::ClearImgBuffer()
321 {
322 if (imgBuffer_) {
323 free(imgBuffer_);
324 imgBuffer_ = nullptr;
325 bufferSize_ = 0;
326 }
327 }
328
Clear()329 void PasteDataRecordAdapterImpl::Clear()
330 {
331 ClearImgBuffer();
332 }
333
GetRecord()334 std::shared_ptr<PasteDataRecord> PasteDataRecordAdapterImpl::GetRecord()
335 {
336 return record_;
337 }
338
PasteDataAdapterImpl()339 PasteDataAdapterImpl::PasteDataAdapterImpl()
340 : data_(std::make_shared<PasteData>()) {}
341
PasteDataAdapterImpl(std::shared_ptr<PasteData> data)342 PasteDataAdapterImpl::PasteDataAdapterImpl(
343 std::shared_ptr<PasteData> data) : data_(data) {}
344
AddHtmlRecord(const std::string & html)345 void PasteDataAdapterImpl::AddHtmlRecord(const std::string& html)
346 {
347 if (data_ != nullptr) {
348 data_->AddHtmlRecord(html);
349 }
350 }
351
AddTextRecord(const std::string & text)352 void PasteDataAdapterImpl::AddTextRecord(const std::string& text)
353 {
354 if (data_ != nullptr) {
355 data_->AddTextRecord(text);
356 }
357 }
358
GetMimeTypes()359 std::vector<std::string> PasteDataAdapterImpl::GetMimeTypes()
360 {
361 return (data_ != nullptr) ? data_->GetMimeTypes() :
362 std::vector<std::string>();
363 }
364
GetPrimaryHtml()365 std::shared_ptr<std::string> PasteDataAdapterImpl::GetPrimaryHtml()
366 {
367 return (data_ != nullptr) ? data_->GetPrimaryHtml() : nullptr;
368 }
369
GetPrimaryText()370 std::shared_ptr<std::string> PasteDataAdapterImpl::GetPrimaryText()
371 {
372 return (data_ != nullptr) ? data_->GetPrimaryText() : nullptr;
373 }
374
GetPrimaryMimeType()375 std::shared_ptr<std::string> PasteDataAdapterImpl::GetPrimaryMimeType()
376 {
377 return (data_ != nullptr) ? data_->GetPrimaryMimeType() : nullptr;
378 }
379
GetRecordAt(std::size_t index)380 std::shared_ptr<PasteDataRecordAdapter> PasteDataAdapterImpl::GetRecordAt(
381 std::size_t index)
382 {
383 if (data_ == nullptr || data_->GetRecordCount() <= index) {
384 return nullptr;
385 }
386 return std::make_shared<PasteDataRecordAdapterImpl>(data_->GetRecordAt(index));
387 }
388
GetRecordCount()389 std::size_t PasteDataAdapterImpl::GetRecordCount()
390 {
391 return (data_ != nullptr) ? data_->GetRecordCount() : 0;
392 }
393
AllRecords()394 PasteRecordVector PasteDataAdapterImpl::AllRecords()
395 {
396 if (data_ == nullptr) {
397 return PasteRecordVector();
398 }
399 PasteRecordVector result;
400 for (auto& record: data_->AllRecords()) {
401 result.push_back(std::make_shared<PasteDataRecordAdapterImpl>(record));
402 }
403 return result;
404 }
405
GetInstance()406 PasteBoardClientAdapterImpl& PasteBoardClientAdapterImpl::GetInstance()
407 {
408 static PasteBoardClientAdapterImpl instance;
409 return instance;
410 }
411
TransitionCopyOption(CopyOptionMode copyOption)412 MiscServices::ShareOption PasteBoardClientAdapterImpl::TransitionCopyOption(CopyOptionMode copyOption)
413 {
414 auto shareOption = MiscServices::ShareOption::CrossDevice;
415 switch (copyOption) {
416 case CopyOptionMode::IN_APP:
417 shareOption = MiscServices::ShareOption::InApp;
418 break;
419 case CopyOptionMode::LOCAL_DEVICE:
420 shareOption = MiscServices::ShareOption::LocalDevice;
421 break;
422 case CopyOptionMode::CROSS_DEVICE:
423 shareOption = MiscServices::ShareOption::CrossDevice;
424 break;
425 default:
426 break;
427 }
428 return shareOption;
429 }
430
ReportPasteboardErrorEvent(int32_t errorCode,int32_t recordSize,const std::string & dataType)431 void ReportPasteboardErrorEvent(int32_t errorCode, int32_t recordSize, const std::string &dataType)
432 {
433 OhosAdapterHelper::GetInstance().GetHiSysEventAdapterInstance().Write(PASTE_BOARD_ERROR,
434 HiSysEventAdapter::EventType::FAULT, { ERROR_CODE, std::to_string(errorCode),
435 RECORD_SIZE, std::to_string(recordSize), DATA_TYPE, dataType });
436 }
437
GetPasteMimeTypeExtention(const PasteRecordVector & data)438 std::string GetPasteMimeTypeExtention(const PasteRecordVector& data)
439 {
440 if (data.empty()) {
441 return MIMETYPE_NULL;
442 }
443 bool isHybrid = false;
444 std::string primaryMimeType = data.front()->GetMimeType();
445 for (auto &item : data) {
446 if (primaryMimeType != item->GetMimeType()) {
447 isHybrid = true;
448 break;
449 }
450 }
451 if (isHybrid) {
452 return MIMETYPE_HYBRID;
453 }
454 return primaryMimeType;
455 }
456
GetPasteData(PasteRecordVector & data)457 bool PasteBoardClientAdapterImpl::GetPasteData(PasteRecordVector& data)
458 {
459 PasteData pData;
460 if (!PasteboardClient::GetInstance()->HasPasteData() ||
461 PasteboardClient::GetInstance()->GetPasteData(pData) != static_cast<int32_t>(PasteboardError::E_OK)) {
462 WVLOG_E("no data to paste or get data from clipboard failed");
463 ReportPasteboardErrorEvent(PasteboardClient::GetInstance()->GetPasteData(pData),
464 pData.AllRecords().size(), GetPasteMimeTypeExtention(data));
465 isLocalPaste_ = false;
466 tokenId_ = 0;
467 return false;
468 }
469 for (auto& record: pData.AllRecords()) {
470 data.push_back(std::make_shared<PasteDataRecordAdapterImpl>(record));
471 }
472 tokenId_ = pData.GetTokenId();
473 isLocalPaste_ = pData.IsLocalPaste();
474 return true;
475 }
476
SetPasteData(const PasteRecordVector & data,CopyOptionMode copyOption)477 void PasteBoardClientAdapterImpl::SetPasteData(const PasteRecordVector& data, CopyOptionMode copyOption)
478 {
479 if (copyOption == CopyOptionMode::NONE) {
480 WVLOG_E("SetPasteData failed, copy option mode is 'NONE'");
481 return;
482 }
483 std::vector<std::shared_ptr<PasteDataRecord>> recordList;
484 for (auto& record: data) {
485 PasteDataRecordAdapterImpl* rawRecord =
486 reinterpret_cast<PasteDataRecordAdapterImpl*>(record.get());
487 if (rawRecord == nullptr) {
488 continue;
489 }
490 recordList.push_back(rawRecord->GetRecord());
491 }
492 PasteData pData(recordList);
493 pData.SetTag(webviewPasteDataTag_);
494 auto shareOption = TransitionCopyOption(copyOption);
495 pData.SetShareOption(shareOption);
496 int32_t ret = PasteboardClient::GetInstance()->SetPasteData(pData);
497 if (ret != static_cast<int32_t>(PasteboardError::E_OK)) {
498 WVLOG_E("set paste data to clipboard failed");
499 ReportPasteboardErrorEvent(ret, pData.AllRecords().size(), GetPasteMimeTypeExtention(data));
500 }
501 }
502
HasPasteData()503 bool PasteBoardClientAdapterImpl::HasPasteData()
504 {
505 return PasteboardClient::GetInstance()->HasPasteData();
506 }
507
Clear()508 void PasteBoardClientAdapterImpl::Clear()
509 {
510 PasteRecordVector recordVector;
511 if (!GetPasteData(recordVector)) {
512 WVLOG_E("get paste data failed while clear");
513 PasteboardClient::GetInstance()->Clear();
514 return;
515 }
516 for (auto& record: recordVector) {
517 PasteDataRecordAdapterImpl* rawRecord =
518 reinterpret_cast<PasteDataRecordAdapterImpl*>(record.get());
519 if (rawRecord == nullptr) {
520 continue;
521 }
522 rawRecord->Clear();
523 }
524 PasteboardClient::GetInstance()->Clear();
525 }
526
OpenRemoteUri(const std::string & path)527 int32_t PasteBoardClientAdapterImpl::OpenRemoteUri(const std::string& path)
528 {
529 return RemoteUri::OpenRemoteUri(path);
530 }
531
IsLocalPaste()532 bool PasteBoardClientAdapterImpl::IsLocalPaste()
533 {
534 return isLocalPaste_;
535 }
536
GetTokenId()537 uint32_t PasteBoardClientAdapterImpl::GetTokenId()
538 {
539 return tokenId_;
540 }
541
AddPasteboardChangedObserver(std::shared_ptr<PasteboardObserverAdapter> callback)542 int32_t PasteBoardClientAdapterImpl::AddPasteboardChangedObserver(
543 std::shared_ptr<PasteboardObserverAdapter> callback)
544 {
545 static int32_t count = 0;
546 int32_t id = -1;
547 if (callback) {
548 sptr<PasteboardObserver> observer;
549 {
550 std::lock_guard<std::mutex> lock(mutex_);
551 observer = new (std::nothrow) PasteboardObserverAdapterImpl(callback);
552 if (!observer) {
553 return -1;
554 }
555
556 id = count++;
557 if (count < 0) {
558 count = 0;
559 }
560 reg_.emplace(std::make_pair(id, observer));
561 }
562 PasteboardClient::GetInstance()->AddPasteboardChangedObserver(observer);
563 }
564 return id;
565 }
566
RemovePasteboardChangedObserver(int32_t callbackId)567 void PasteBoardClientAdapterImpl::RemovePasteboardChangedObserver(
568 int32_t callbackId)
569 {
570 sptr<PasteboardObserver> observer;
571 {
572 std::lock_guard<std::mutex> lock(mutex_);
573 ObserverMap::iterator iter = reg_.find(callbackId);
574 if (iter == reg_.end()) {
575 return;
576 }
577 observer = iter->second;
578 reg_.erase(iter);
579 }
580 PasteboardClient::GetInstance()->RemovePasteboardChangedObserver(observer);
581 }
582 } // namespace OHOS::NWeb
583