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 "adapter/ohos/capability/clipboard/clipboard_impl.h"
17 #include <vector>
18 
19 #include "adapter/ohos/osal/pixel_map_ohos.h"
20 #include "adapter/ohos/capability/html/html_to_span.h"
21 #include "base/log/log_wrapper.h"
22 #include "base/utils/utils.h"
23 #include "core/components_ng/pattern/text/span/span_string.h"
24 
25 namespace OHOS::Ace {
26 #ifndef SYSTEM_CLIPBOARD_SUPPORTED
27 namespace {
28 std::string g_clipboard;
29 RefPtr<PixelMap> g_pixmap;
30 } // namespace
31 #endif
32 
33 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
TransitionCopyOption(CopyOptions copyOption)34 MiscServices::ShareOption TransitionCopyOption(CopyOptions copyOption)
35 {
36     auto shareOption = MiscServices::ShareOption::InApp;
37     switch (copyOption) {
38         case CopyOptions::InApp:
39             shareOption = MiscServices::ShareOption::InApp;
40             break;
41         case CopyOptions::Local:
42             shareOption = MiscServices::ShareOption::LocalDevice;
43             break;
44         case CopyOptions::Distributed:
45             shareOption = MiscServices::ShareOption::CrossDevice;
46             break;
47         default:
48             break;
49     }
50     return shareOption;
51 }
52 
53 const std::string SPAN_STRING_TAG = "openharmony.styled-string";
54 #endif
55 
HasData(const std::function<void (bool hasData)> & callback)56 void ClipboardImpl::HasData(const std::function<void(bool hasData)>& callback)
57 {
58 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
59     bool hasData = false;
60     CHECK_NULL_VOID(taskExecutor_);
61     taskExecutor_->PostSyncTask(
62         [&hasData]() { hasData = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData(); },
63         TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardHasData");
64     callback(hasData);
65 #endif
66 }
67 
HasDataType(const std::function<void (bool hasData)> & callback,const std::vector<std::string> & mimeTypes)68 void ClipboardImpl::HasDataType(
69     const std::function<void(bool hasData)>& callback, const std::vector<std::string>& mimeTypes)
70 {
71 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
72     bool hasData = false;
73     CHECK_NULL_VOID(taskExecutor_);
74     taskExecutor_->PostSyncTask(
75         [&hasData, mimeTypes]() {
76             for (auto mimeType = mimeTypes.begin(); mimeType != mimeTypes.end(); ++mimeType) {
77                 hasData = OHOS::MiscServices::PasteboardClient::GetInstance()->HasDataType(*mimeType);
78                 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "Clipboard data mimeType %{public}s available ? %{public}d",
79                     mimeType->c_str(), hasData);
80                 if (hasData) {
81                     break;
82                 }
83             }
84         },
85         TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardHasDataType");
86     callback(hasData);
87 #endif
88 }
89 
SetData(const std::string & data,CopyOptions copyOption,bool isDragData)90 void ClipboardImpl::SetData(const std::string& data, CopyOptions copyOption, bool isDragData)
91 {
92     CHECK_NULL_VOID(taskExecutor_);
93 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
94     auto shareOption = TransitionCopyOption(copyOption);
95     taskExecutor_->PostTask(
96         [data, shareOption, isDragData]() {
97             auto pasteData = OHOS::MiscServices::PasteboardClient::GetInstance()->CreatePlainTextData(data);
98             CHECK_NULL_VOID(pasteData);
99             pasteData->SetShareOption(shareOption);
100             pasteData->SetDraggedDataFlag(isDragData);
101             OHOS::MiscServices::PasteboardClient::GetInstance()->SetPasteData(*pasteData);
102         },
103         TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardSetDataWithCopyOption");
104 #else
105     taskExecutor_->PostTask(
106         [data]() { g_clipboard = data; }, TaskExecutor::TaskType::UI, "ArkUIClipboardSetTextPasteData");
107 #endif
108 }
109 
SetPixelMapData(const RefPtr<PixelMap> & pixmap,CopyOptions copyOption)110 void ClipboardImpl::SetPixelMapData(const RefPtr<PixelMap>& pixmap, CopyOptions copyOption)
111 {
112     CHECK_NULL_VOID(taskExecutor_);
113 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
114     auto shareOption = TransitionCopyOption(copyOption);
115     taskExecutor_->PostTask(
116         [pixmap, shareOption]() {
117             CHECK_NULL_VOID(pixmap);
118             auto pixmapOhos = AceType::DynamicCast<PixelMapOhos>(pixmap);
119             CHECK_NULL_VOID(pixmapOhos);
120             auto pasteData = OHOS::MiscServices::PasteboardClient::GetInstance()->CreatePixelMapData(
121                 pixmapOhos->GetPixelMapSharedPtr());
122             CHECK_NULL_VOID(pasteData);
123             pasteData->SetShareOption(shareOption);
124             TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "Set pixmap to system clipboard");
125             OHOS::MiscServices::PasteboardClient::GetInstance()->SetPasteData(*pasteData);
126         },
127         TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardSetPixelMapWithCopyOption");
128 #else
129     taskExecutor_->PostTask(
130         [pixmap]() { g_pixmap = pixmap; }, TaskExecutor::TaskType::UI, "ArkUIClipboardSetImagePasteData");
131 #endif
132 }
133 
GetData(const std::function<void (const std::string &)> & callback,bool syncMode)134 void ClipboardImpl::GetData(const std::function<void(const std::string&)>& callback, bool syncMode)
135 {
136 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
137     if (!taskExecutor_ || !callback) {
138         return;
139     }
140 
141     if (syncMode) {
142         GetDataSync(callback);
143     } else {
144         GetDataAsync(callback);
145     }
146 #else
147     if (syncMode) {
148         callback(g_clipboard);
149         return;
150     }
151     CHECK_NULL_VOID(taskExecutor_);
152     taskExecutor_->PostTask(
153         [callback, taskExecutor = WeakClaim(RawPtr(taskExecutor_)), textData = g_clipboard]() {
154             callback(textData);
155         },
156         TaskExecutor::TaskType::UI, "ArkUIClipboardTextDataCallback");
157 #endif
158 }
159 
GetPixelMapData(const std::function<void (const RefPtr<PixelMap> &)> & callback,bool syncMode)160 void ClipboardImpl::GetPixelMapData(const std::function<void(const RefPtr<PixelMap>&)>& callback, bool syncMode)
161 {
162     if (!taskExecutor_ || !callback) {
163         return;
164     }
165 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
166     if (syncMode) {
167         GetPixelMapDataSync(callback);
168     } else {
169         GetPixelMapDataAsync(callback);
170     }
171 #else
172     if (syncMode) {
173         callback(g_pixmap);
174     } else {
175         taskExecutor_->PostTask([callback, taskExecutor = WeakClaim(RawPtr(taskExecutor_)),
176                                     imageData = g_pixmap]() { callback(imageData); },
177             TaskExecutor::TaskType::UI, "ArkUIClipboardImageDataCallback");
178     }
179 #endif
180 }
181 
CreatePasteDataMix()182 RefPtr<PasteDataMix> ClipboardImpl::CreatePasteDataMix()
183 {
184     return AceType::MakeRefPtr<PasteDataImpl>();
185 }
186 
AddMultiTypeRecord(const RefPtr<PasteDataMix> & pasteData,const RefPtr<MultiTypeRecordMix> & multiTypeRecord)187 void ClipboardImpl::AddMultiTypeRecord(
188     const RefPtr<PasteDataMix>& pasteData, const RefPtr<MultiTypeRecordMix>& multiTypeRecord)
189 {
190 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
191     CHECK_NULL_VOID(taskExecutor_);
192     auto peData = AceType::DynamicCast<PasteDataImpl>(pasteData);
193     CHECK_NULL_VOID(peData);
194     auto multiTypeRecordImpl = AceType::DynamicCast<MultiTypeRecordImpl>(multiTypeRecord);
195     CHECK_NULL_VOID(multiTypeRecordImpl);
196 
197     std::map<std::string, std::shared_ptr<OHOS::MiscServices::EntryValue>> multiTypeDataMap;
198     if (!multiTypeRecordImpl->GetPlainText().empty()) {
199         multiTypeDataMap[OHOS::MiscServices::MIMETYPE_TEXT_PLAIN] =
200             std::make_shared<OHOS::MiscServices::EntryValue>(multiTypeRecordImpl->GetPlainText());
201     }
202     if (!multiTypeRecordImpl->GetUri().empty()) {
203         multiTypeDataMap[OHOS::MiscServices::MIMETYPE_TEXT_URI] =
204             std::make_shared<OHOS::MiscServices::EntryValue>(multiTypeRecordImpl->GetUri());
205     }
206     if (multiTypeRecordImpl->GetPixelMap()) {
207         multiTypeDataMap[OHOS::MiscServices::MIMETYPE_PIXELMAP] =
208             std::make_shared<OHOS::MiscServices::EntryValue>(multiTypeRecordImpl->GetPixelMap());
209     }
210     if (!multiTypeRecordImpl->GetSpanStringBuffer().empty()) {
211         multiTypeDataMap[SPAN_STRING_TAG] =
212             std::make_shared<OHOS::MiscServices::EntryValue>(multiTypeRecordImpl->GetSpanStringBuffer());
213     }
214 
215     auto entry =
216         std::make_shared<std::map<std::string, std::shared_ptr<OHOS::MiscServices::EntryValue>>>(multiTypeDataMap);
217     peData->GetPasteDataData()->AddRecord(
218         MiscServices::PasteDataRecord::NewMultiTypeRecord(entry, GetMimeType(multiTypeDataMap)));
219 #endif
220 }
221 
222 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
GetMimeType(std::map<std::string,std::shared_ptr<OHOS::MiscServices::EntryValue>> multiTypeDataMap)223 const std::string ClipboardImpl::GetMimeType(
224     std::map<std::string, std::shared_ptr<OHOS::MiscServices::EntryValue>> multiTypeDataMap)
225 {
226     std::string mimeType;
227     if (multiTypeDataMap.find(SPAN_STRING_TAG) != multiTypeDataMap.end()) {
228         mimeType = SPAN_STRING_TAG;
229     }
230     if (multiTypeDataMap.find(OHOS::MiscServices::MIMETYPE_PIXELMAP) != multiTypeDataMap.end()) {
231         mimeType = OHOS::MiscServices::MIMETYPE_PIXELMAP;
232     }
233     if (multiTypeDataMap.find(OHOS::MiscServices::MIMETYPE_TEXT_URI) != multiTypeDataMap.end()) {
234         mimeType = OHOS::MiscServices::MIMETYPE_TEXT_URI;
235     }
236     if (multiTypeDataMap.find(OHOS::MiscServices::MIMETYPE_TEXT_PLAIN) != multiTypeDataMap.end()) {
237         mimeType = OHOS::MiscServices::MIMETYPE_TEXT_PLAIN;
238     }
239     return mimeType;
240 }
241 #endif
242 
SetPlainText(const std::string plainText)243 void MultiTypeRecordImpl::SetPlainText(const std::string plainText)
244 {
245     plainText_ = plainText;
246 }
SetUri(const std::string uri)247 void MultiTypeRecordImpl::SetUri(const std::string uri)
248 {
249     uri_ = uri;
250 }
SetPixelMap(RefPtr<PixelMap> pixelMap)251 void MultiTypeRecordImpl::SetPixelMap(RefPtr<PixelMap> pixelMap)
252 {
253     pixelMap_ = pixelMap;
254 }
GetPixelMap()255 const RefPtr<PixelMap> MultiTypeRecordImpl::GetPixelMap()
256 {
257     return pixelMap_;
258 }
GetPlainText()259 const std::string MultiTypeRecordImpl::GetPlainText()
260 {
261     return plainText_;
262 }
GetUri()263 const std::string MultiTypeRecordImpl::GetUri()
264 {
265     return uri_;
266 }
GetSpanStringBuffer()267 std::vector<uint8_t>& MultiTypeRecordImpl::GetSpanStringBuffer()
268 {
269     return spanStringBuffer_;
270 }
271 
AddPixelMapRecord(const RefPtr<PasteDataMix> & pasteData,const RefPtr<PixelMap> & pixmap)272 void ClipboardImpl::AddPixelMapRecord(const RefPtr<PasteDataMix>& pasteData, const RefPtr<PixelMap>& pixmap)
273 {
274 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
275     CHECK_NULL_VOID(taskExecutor_);
276     auto peData = AceType::DynamicCast<PasteDataImpl>(pasteData);
277     CHECK_NULL_VOID(peData);
278     auto pixmapOhos = AceType::DynamicCast<PixelMapOhos>(pixmap);
279     CHECK_NULL_VOID(pixmapOhos);
280     TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "add pixelMap record to pasteData");
281     peData->GetPasteDataData()->AddPixelMapRecord(pixmapOhos->GetPixelMapSharedPtr());
282 #endif
283 }
284 
AddImageRecord(const RefPtr<PasteDataMix> & pasteData,const std::string & uri)285 void ClipboardImpl::AddImageRecord(const RefPtr<PasteDataMix>& pasteData, const std::string& uri)
286 {
287 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
288     CHECK_NULL_VOID(taskExecutor_);
289     auto peData = AceType::DynamicCast<PasteDataImpl>(pasteData);
290     CHECK_NULL_VOID(peData);
291     TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "add url %{private}s record to pasteData", uri.c_str());
292     peData->GetPasteDataData()->AddUriRecord(OHOS::Uri(uri));
293 #endif
294 }
295 
AddTextRecord(const RefPtr<PasteDataMix> & pasteData,const std::string & selectedStr)296 void ClipboardImpl::AddTextRecord(const RefPtr<PasteDataMix>& pasteData, const std::string& selectedStr)
297 {
298 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
299     CHECK_NULL_VOID(taskExecutor_);
300     auto peData = AceType::DynamicCast<PasteDataImpl>(pasteData);
301     CHECK_NULL_VOID(peData);
302     TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "add text record to pasteData, length: %{public}d",
303         static_cast<int32_t>(StringUtils::ToWstring(selectedStr).length()));
304     peData->GetPasteDataData()->AddTextRecord(selectedStr);
305 #endif
306 }
307 
AddSpanStringRecord(const RefPtr<PasteDataMix> & pasteData,std::vector<uint8_t> & data)308 void ClipboardImpl::AddSpanStringRecord(const RefPtr<PasteDataMix>& pasteData, std::vector<uint8_t>& data)
309 {
310 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
311     CHECK_NULL_VOID(taskExecutor_);
312     auto peData = AceType::DynamicCast<PasteDataImpl>(pasteData);
313     CHECK_NULL_VOID(peData);
314     TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "add spanstring record to pasteData, length: %{public}d",
315         static_cast<int32_t>(data.size()));
316     peData->GetPasteDataData()->AddKvRecord(SPAN_STRING_TAG, data);
317 #endif
318 }
319 
SetData(const RefPtr<PasteDataMix> & pasteData,CopyOptions copyOption)320 void ClipboardImpl::SetData(const RefPtr<PasteDataMix>& pasteData, CopyOptions copyOption)
321 {
322 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
323     auto shareOption = TransitionCopyOption(copyOption);
324     auto peData = AceType::DynamicCast<PasteDataImpl>(pasteData);
325     CHECK_NULL_VOID(peData);
326     taskExecutor_->PostTask(
327         [peData, shareOption]() {
328             auto pasteData = peData->GetPasteDataData();
329             pasteData->SetShareOption(shareOption);
330             TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "add pasteData to clipboard, shareOption:  %{public}d", shareOption);
331             OHOS::MiscServices::PasteboardClient::GetInstance()->SetPasteData(*pasteData);
332         },
333         TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardSetMixDataWithCopyOption");
334 #endif
335 }
336 
GetData(const std::function<void (const std::string &,bool isLastRecord)> & textCallback,const std::function<void (const RefPtr<PixelMap> &,bool isLastRecord)> & pixelMapCallback,const std::function<void (const std::string &,bool isLastRecord)> & urlCallback,bool syncMode)337 void ClipboardImpl::GetData(const std::function<void(const std::string&, bool isLastRecord)>& textCallback,
338     const std::function<void(const RefPtr<PixelMap>&, bool isLastRecord)>& pixelMapCallback,
339     const std::function<void(const std::string&, bool isLastRecord)>& urlCallback, bool syncMode)
340 {
341 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
342     if (!taskExecutor_ || !textCallback || !pixelMapCallback || !urlCallback) {
343         return;
344     }
345 
346     if (syncMode) {
347         GetDataSync(textCallback, pixelMapCallback, urlCallback);
348     } else {
349         GetDataAsync(textCallback, pixelMapCallback, urlCallback);
350     }
351 #endif
352 }
353 
354 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
GetPasteDataData()355 std::shared_ptr<MiscServices::PasteData> PasteDataImpl::GetPasteDataData()
356 {
357     if (pasteData_ == nullptr) {
358         pasteData_ = std::make_shared<MiscServices::PasteData>();
359     }
360     return pasteData_;
361 }
SetUnifiedData(std::shared_ptr<MiscServices::PasteData> pasteData)362 void PasteDataImpl::SetUnifiedData(std::shared_ptr<MiscServices::PasteData> pasteData)
363 {
364     pasteData_ = pasteData;
365 }
366 
GetDataSync(const std::function<void (const std::string &)> & callback)367 void ClipboardImpl::GetDataSync(const std::function<void(const std::string&)>& callback)
368 {
369     std::string result;
370     taskExecutor_->PostSyncTask(
371         [&result]() {
372             auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
373             CHECK_NULL_VOID(has);
374             OHOS::MiscServices::PasteData pasteData;
375             auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
376             CHECK_NULL_VOID(ok);
377             for (const auto& pasteDataRecord : pasteData.AllRecords()) {
378                 if (pasteDataRecord == nullptr) {
379                     continue;
380                 }
381                 if (pasteDataRecord->GetCustomData() != nullptr) {
382                     auto customData = pasteDataRecord->GetCustomData();
383                     auto itemData = customData->GetItemData();
384                     if (itemData.find(SPAN_STRING_TAG) == itemData.end()) {
385                         continue;
386                     }
387                     auto spanStr = SpanString::DecodeTlv(itemData[SPAN_STRING_TAG]);
388                     if (spanStr) {
389                         result = spanStr->GetString();
390                         break;
391                     }
392                 }
393                 if (pasteDataRecord->GetHtmlText() != nullptr) {
394                     auto htmlText = pasteDataRecord->GetHtmlText();
395                     HtmlToSpan toSpan;
396                     auto spanStr = toSpan.ToSpanString(*htmlText, false);
397                     if (spanStr) {
398                         result = spanStr->GetString();
399                         break;
400                     }
401                 }
402             }
403             if (result.empty()) {
404                 auto textData = pasteData.GetPrimaryText();
405                 CHECK_NULL_VOID(textData);
406                 result = *textData;
407             }
408         },
409         TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetTextDataSync");
410     callback(result);
411 }
412 
GetDataAsync(const std::function<void (const std::string &)> & callback)413 void ClipboardImpl::GetDataAsync(const std::function<void(const std::string&)>& callback)
414 {
415     taskExecutor_->PostTask(
416         [callback, weakExecutor = WeakClaim(RawPtr(taskExecutor_)), weak = WeakClaim(this)]() {
417             auto clip = weak.Upgrade();
418             auto taskExecutor = weakExecutor.Upgrade();
419             CHECK_NULL_VOID(taskExecutor);
420             if (!OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData()) {
421                 TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "SystemKeyboardData is not exist from MiscServices");
422                 taskExecutor->PostTask(
423                     [callback]() { callback(""); }, TaskExecutor::TaskType::UI, "ArkUIClipboardHasDataFailed");
424                 return;
425             }
426             OHOS::MiscServices::PasteData pasteData;
427             if (!OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData)) {
428                 TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "Get SystemKeyboardData fail from MiscServices");
429                 taskExecutor->PostTask(
430                     [callback]() { callback(""); }, TaskExecutor::TaskType::UI, "ArkUIClipboardGetDataFailed");
431                 return;
432             }
433             std::string resText;
434             for (const auto& pasteDataRecord : pasteData.AllRecords()) {
435                 if (clip->ProcessPasteDataRecord(pasteDataRecord, resText)) {
436                     break;
437                 }
438             }
439             if (resText.empty()) {
440                 TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "Get SystemKeyboardTextData fail from MiscServices");
441                 taskExecutor->PostTask(
442                     [callback]() { callback(""); }, TaskExecutor::TaskType::UI, "ArkUIClipboardGetTextDataFailed");
443                 return;
444             }
445             TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "resText len:%{public}d", static_cast<int32_t>(resText.length()));
446             auto result = resText;
447             taskExecutor->PostTask(
448                 [callback, result]() { callback(result); },
449                 TaskExecutor::TaskType::UI, "ArkUIClipboardGetTextDataCallback");
450         },
451         TaskExecutor::TaskType::BACKGROUND, "ArkUIClipboardGetTextDataAsync");
452 }
453 
ProcessPasteDataRecord(const std::shared_ptr<MiscServices::PasteDataRecord> & pasteDataRecord,std::string & resText)454 bool ClipboardImpl::ProcessPasteDataRecord(const std::shared_ptr<MiscServices::PasteDataRecord>& pasteDataRecord,
455     std::string& resText)
456 {
457     if (pasteDataRecord == nullptr) {
458         return false;
459     }
460     TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "mimeType:%{public}s", pasteDataRecord->GetMimeType().c_str());
461     if (pasteDataRecord->GetHtmlText() != nullptr) {
462         auto htmlText = pasteDataRecord->GetHtmlText();
463         HtmlToSpan toSpan;
464         auto spanStr = toSpan.ToSpanString(*htmlText);
465         if (spanStr) {
466             resText = spanStr->GetString();
467             return true;
468         }
469     }
470     if (pasteDataRecord->GetCustomData() != nullptr) {
471         auto itemData = pasteDataRecord->GetCustomData()->GetItemData();
472         if (itemData.find(SPAN_STRING_TAG) != itemData.end()) {
473             auto spanStr = SpanString::DecodeTlv(itemData[SPAN_STRING_TAG]);
474             if (spanStr) {
475                 resText = spanStr->GetString();
476                 return true;
477             }
478         }
479     }
480     if (pasteDataRecord->GetPlainText() != nullptr) {
481         auto textData = pasteDataRecord->GetPlainText();
482         resText.append(*textData);
483     }
484     return false;
485 }
486 
GetDataSync(const std::function<void (const std::string &,bool isLastRecord)> & textCallback,const std::function<void (const RefPtr<PixelMap> &,bool isLastRecord)> & pixelMapCallback,const std::function<void (const std::string &,bool isLastRecord)> & urlCallback)487 void ClipboardImpl::GetDataSync(const std::function<void(const std::string&, bool isLastRecord)>& textCallback,
488     const std::function<void(const RefPtr<PixelMap>&, bool isLastRecord)>& pixelMapCallback,
489     const std::function<void(const std::string&, bool isLastRecord)>& urlCallback)
490 {
491     TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "get data from clipboard, sync");
492     OHOS::MiscServices::PasteData pasteData;
493     taskExecutor_->PostSyncTask(
494         [&pasteData]() {
495             auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
496             CHECK_NULL_VOID(has);
497             auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
498             CHECK_NULL_VOID(ok);
499         },
500         TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetPasteDataSync");
501 
502     auto count = pasteData.GetRecordCount();
503     size_t index = 0;
504     for (const auto& pasteDataRecord : pasteData.AllRecords()) {
505         index++;
506         if (pasteDataRecord == nullptr) {
507             continue;
508         }
509         bool isLastRecord = index == count;
510         if (pasteDataRecord->GetPlainText() != nullptr) {
511             auto textData = pasteDataRecord->GetPlainText();
512             auto result = *textData;
513             textCallback(result, isLastRecord);
514         } else if (pasteDataRecord->GetPixelMap() != nullptr) {
515             auto imageData = pasteDataRecord->GetPixelMap();
516             auto result = AceType::MakeRefPtr<PixelMapOhos>(imageData);
517             pixelMapCallback(result, isLastRecord);
518         } else if (pasteDataRecord->GetUri() != nullptr) {
519             auto textData = pasteDataRecord->GetUri();
520             auto result = (*textData).ToString();
521             urlCallback(result, isLastRecord);
522         }
523     }
524 }
525 
GetDataAsync(const std::function<void (const std::string &,bool isLastRecord)> & textCallback,const std::function<void (const RefPtr<PixelMap> &,bool isLastRecord)> & pixelMapCallback,const std::function<void (const std::string &,bool isLastRecord)> & urlCallback)526 void ClipboardImpl::GetDataAsync(const std::function<void(const std::string&, bool isLastRecord)>& textCallback,
527     const std::function<void(const RefPtr<PixelMap>&, bool isLastRecord)>& pixelMapCallback,
528     const std::function<void(const std::string&, bool isLastRecord)>& urlCallback)
529 {
530     TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "get data from clipboard, async");
531     taskExecutor_->PostTask(
532         [textCallback, pixelMapCallback, urlCallback, weakExecutor = WeakClaim(RawPtr(taskExecutor_))]() {
533             auto taskExecutor = weakExecutor.Upgrade();
534             auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
535             CHECK_NULL_VOID(has);
536             OHOS::MiscServices::PasteData pasteData;
537             auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
538             CHECK_NULL_VOID(ok);
539             auto count = pasteData.GetRecordCount();
540             size_t index = 0;
541             for (const auto& pasteDataRecord : pasteData.AllRecords()) {
542                 index++;
543                 if (pasteDataRecord == nullptr) {
544                     continue;
545                 }
546                 bool isLastRecord = index == count;
547                 if (pasteDataRecord->GetPlainText() != nullptr) {
548                     auto textData = pasteDataRecord->GetPlainText();
549                     auto result = *textData;
550                     taskExecutor->PostTask(
551                         [textCallback, result, isLastRecord]() { textCallback(result, isLastRecord); },
552                         TaskExecutor::TaskType::UI, "ArkUIClipboardGetTextCallback");
553                 } else if (pasteDataRecord->GetPixelMap() != nullptr) {
554                     auto imageData = pasteDataRecord->GetPixelMap();
555                     auto result = AceType::MakeRefPtr<PixelMapOhos>(imageData);
556                     taskExecutor->PostTask(
557                         [pixelMapCallback, result, isLastRecord]() { pixelMapCallback(result, isLastRecord); },
558                         TaskExecutor::TaskType::UI, "ArkUIClipboardGetImageCallback");
559                 } else if (pasteDataRecord->GetUri() != nullptr) {
560                     auto textData = pasteDataRecord->GetUri();
561                     auto result = (*textData).ToString();
562                     taskExecutor->PostTask([urlCallback, result, isLastRecord]() { urlCallback(result, isLastRecord); },
563                         TaskExecutor::TaskType::UI, "ArkUIClipboardGetUrlCallback");
564                 }
565             }
566         },
567         TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetDataAsync");
568 }
569 
GetSpanStringData(const std::function<void (std::vector<std::vector<uint8_t>> &,const std::string &,bool &)> & callback,bool syncMode)570 void ClipboardImpl::GetSpanStringData(
571     const std::function<void(std::vector<std::vector<uint8_t>>&, const std::string&, bool&)>& callback, bool syncMode)
572 {
573 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
574     if (!taskExecutor_ || !callback) {
575         return;
576     }
577 
578     GetSpanStringDataHelper(callback, syncMode);
579 #endif
580 }
581 
GetSpanStringDataHelper(const std::function<void (std::vector<std::vector<uint8_t>> &,const std::string &,bool &)> & callback,bool syncMode)582 void ClipboardImpl::GetSpanStringDataHelper(
583     const std::function<void(std::vector<std::vector<uint8_t>>&, const std::string&, bool&)>& callback, bool syncMode)
584 {
585     auto task = [callback, weakExecutor = WeakClaim(RawPtr(taskExecutor_)), weak = WeakClaim(this)]() {
586         auto clip = weak.Upgrade();
587         CHECK_NULL_VOID(clip);
588         auto taskExecutor = weakExecutor.Upgrade();
589         CHECK_NULL_VOID(taskExecutor);
590         auto hasData = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
591         CHECK_NULL_VOID(hasData);
592         OHOS::MiscServices::PasteData pasteData;
593         auto getDataRes = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
594         CHECK_NULL_VOID(getDataRes);
595         std::vector<std::vector<uint8_t>> arrays;
596         std::string text;
597         bool isMultiTypeRecord = false;
598         clip->ProcessSpanStringData(arrays, pasteData, text, isMultiTypeRecord);
599         auto textData = pasteData.GetPrimaryText();
600         if (textData && text.empty()) {
601             text.append(*textData);
602         }
603         auto result = text;
604         taskExecutor->PostTask(
605             [callback, arrays, result, isMultiTypeRecord]() mutable { callback(arrays, result, isMultiTypeRecord); },
606             TaskExecutor::TaskType::UI, "ArkUIClipboardGetSpanStringDataCallback");
607     };
608     if (syncMode) {
609         taskExecutor_->PostSyncTask(task, TaskExecutor::TaskType::BACKGROUND, "ArkUIClipboardGetSpanStringDataSync");
610     } else {
611         taskExecutor_->PostTask(task, TaskExecutor::TaskType::BACKGROUND, "ArkUIClipboardGetSpanStringDataAsync");
612     }
613 }
614 
ProcessSpanStringData(std::vector<std::vector<uint8_t>> & arrays,const OHOS::MiscServices::PasteData & pasteData,std::string & text,bool & isMultiTypeRecord)615 void ClipboardImpl::ProcessSpanStringData(std::vector<std::vector<uint8_t>>& arrays,
616     const OHOS::MiscServices::PasteData& pasteData, std::string& text, bool& isMultiTypeRecord)
617 {
618     for (const auto& pasteDataRecord : pasteData.AllRecords()) {
619         if (pasteDataRecord == nullptr) {
620             continue;
621         }
622 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
623         std::vector<std::string> types = { SPAN_STRING_TAG, OHOS::MiscServices::MIMETYPE_TEXT_URI,
624             OHOS::MiscServices::MIMETYPE_PIXELMAP, OHOS::MiscServices::MIMETYPE_TEXT_PLAIN,
625             OHOS::MiscServices::MIMETYPE_TEXT_HTML };
626         auto validTypes = pasteDataRecord->GetValidMimeTypes(types);
627         if (validTypes.size() > 1) {
628             isMultiTypeRecord = true;
629         }
630 #endif
631         auto hasSpanString = false;
632         auto entryPtr = pasteDataRecord->GetEntryByMimeType(SPAN_STRING_TAG);
633         if (entryPtr) {
634             // entryValue InstanceOf OHOS::MiscServices::EntryValue.
635             auto entryValue = entryPtr->GetValue();
636             auto spanStringBuffer = std::get_if<std::vector<uint8_t>>(&entryValue);
637             arrays.emplace_back(*spanStringBuffer);
638             hasSpanString = true;
639         }
640         if (pasteDataRecord->GetHtmlText() != nullptr && !hasSpanString) {
641             auto htmlText = pasteDataRecord->GetHtmlText();
642             HtmlToSpan toSpan;
643             auto spanStr = toSpan.ToSpanString(*htmlText);
644             if (spanStr) {
645                 std::vector<uint8_t> arr;
646                 spanStr->EncodeTlv(arr);
647                 arrays.emplace_back(arr);
648             }
649         }
650         if (pasteDataRecord->GetPlainText() != nullptr) {
651             auto textData = pasteDataRecord->GetPlainText();
652             text.append(*textData);
653         }
654     }
655 }
656 
GetPixelMapDataSync(const std::function<void (const RefPtr<PixelMap> &)> & callback)657 void ClipboardImpl::GetPixelMapDataSync(const std::function<void(const RefPtr<PixelMap>&)>& callback)
658 {
659     RefPtr<PixelMap> pixmap;
660     taskExecutor_->PostSyncTask(
661         [&pixmap]() {
662             auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
663             CHECK_NULL_VOID(has);
664             OHOS::MiscServices::PasteData pasteData;
665             auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
666             CHECK_NULL_VOID(ok);
667             auto imageData = pasteData.GetPrimaryPixelMap();
668             CHECK_NULL_VOID(imageData);
669             pixmap = AceType::MakeRefPtr<PixelMapOhos>(imageData);
670         },
671         TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetImageDataSync");
672     callback(pixmap);
673 }
674 
GetPixelMapDataAsync(const std::function<void (const RefPtr<PixelMap> &)> & callback)675 void ClipboardImpl::GetPixelMapDataAsync(const std::function<void(const RefPtr<PixelMap>&)>& callback)
676 {
677     taskExecutor_->PostTask(
678         [callback, weakExecutor = WeakClaim(RawPtr(taskExecutor_))]() {
679             auto taskExecutor = weakExecutor.Upgrade();
680             CHECK_NULL_VOID(taskExecutor);
681             auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
682             if (!has) {
683                 TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "SystemKeyboardData is not exist from MiscServices");
684                 taskExecutor->PostTask(
685                     [callback]() { callback(nullptr); }, TaskExecutor::TaskType::UI, "ArkUIClipboardHasDataFailed");
686                 return;
687             }
688             OHOS::MiscServices::PasteData pasteData;
689             auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
690             if (!ok) {
691                 TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "Get SystemKeyboardData fail from MiscServices");
692                 taskExecutor->PostTask(
693                     [callback]() { callback(nullptr); }, TaskExecutor::TaskType::UI, "ArkUIClipboardGetDataFailed");
694                 return;
695             }
696             auto imageData = pasteData.GetPrimaryPixelMap();
697             if (!imageData) {
698                 TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "Get SystemKeyboardImageData fail from MiscServices");
699                 taskExecutor->PostTask(
700                     [callback]() { callback(nullptr); },
701                     TaskExecutor::TaskType::UI, "ArkUIClipboardGetImageDataFailed");
702                 return;
703             }
704             auto result = AceType::MakeRefPtr<PixelMapOhos>(imageData);
705             taskExecutor->PostTask(
706                 [callback, result]() { callback(result); },
707                 TaskExecutor::TaskType::UI, "ArkUIClipboardGetImageDataCallback");
708         },
709         TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetImageDataAsync");
710 }
711 #endif
712 
Clear()713 void ClipboardImpl::Clear() {}
714 
715 } // namespace OHOS::Ace
716