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