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