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
25namespace OHOS::Ace {
26#ifndef SYSTEM_CLIPBOARD_SUPPORTED
27namespace {
28std::string g_clipboard;
29RefPtr<PixelMap> g_pixmap;
30} // namespace
31#endif
32
33#ifdef SYSTEM_CLIPBOARD_SUPPORTED
34MiscServices::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
53const std::string SPAN_STRING_TAG = "openharmony.styled-string";
54#endif
55
56void 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
68void 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
90void 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
110void 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
134void 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
160void 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
182RefPtr<PasteDataMix> ClipboardImpl::CreatePasteDataMix()
183{
184    return AceType::MakeRefPtr<PasteDataImpl>();
185}
186
187void 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
223const 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
243void MultiTypeRecordImpl::SetPlainText(const std::string plainText)
244{
245    plainText_ = plainText;
246}
247void MultiTypeRecordImpl::SetUri(const std::string uri)
248{
249    uri_ = uri;
250}
251void MultiTypeRecordImpl::SetPixelMap(RefPtr<PixelMap> pixelMap)
252{
253    pixelMap_ = pixelMap;
254}
255const RefPtr<PixelMap> MultiTypeRecordImpl::GetPixelMap()
256{
257    return pixelMap_;
258}
259const std::string MultiTypeRecordImpl::GetPlainText()
260{
261    return plainText_;
262}
263const std::string MultiTypeRecordImpl::GetUri()
264{
265    return uri_;
266}
267std::vector<uint8_t>& MultiTypeRecordImpl::GetSpanStringBuffer()
268{
269    return spanStringBuffer_;
270}
271
272void 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
285void 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
296void 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
308void 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
320void 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
337void 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
355std::shared_ptr<MiscServices::PasteData> PasteDataImpl::GetPasteDataData()
356{
357    if (pasteData_ == nullptr) {
358        pasteData_ = std::make_shared<MiscServices::PasteData>();
359    }
360    return pasteData_;
361}
362void PasteDataImpl::SetUnifiedData(std::shared_ptr<MiscServices::PasteData> pasteData)
363{
364    pasteData_ = pasteData;
365}
366
367void 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
413void 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
454bool 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        TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "htmlText:%{private}s, length=%{public}zu", htmlText->c_str(),
464            htmlText->length());
465        HtmlToSpan toSpan;
466        auto spanStr = toSpan.ToSpanString(*htmlText);
467        if (spanStr) {
468            resText = spanStr->GetString();
469            return true;
470        }
471    }
472    if (pasteDataRecord->GetCustomData() != nullptr) {
473        auto itemData = pasteDataRecord->GetCustomData()->GetItemData();
474        if (itemData.find(SPAN_STRING_TAG) != itemData.end()) {
475            auto spanStr = SpanString::DecodeTlv(itemData[SPAN_STRING_TAG]);
476            if (spanStr) {
477                resText = spanStr->GetString();
478                return true;
479            }
480        }
481    }
482    if (pasteDataRecord->GetPlainText() != nullptr) {
483        auto textData = pasteDataRecord->GetPlainText();
484        TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "textData:%{private}s, length:%{public}zu", textData->c_str(),
485            textData->length());
486        resText.append(*textData);
487    }
488    return false;
489}
490
491void ClipboardImpl::GetDataSync(const std::function<void(const std::string&, bool isLastRecord)>& textCallback,
492    const std::function<void(const RefPtr<PixelMap>&, bool isLastRecord)>& pixelMapCallback,
493    const std::function<void(const std::string&, bool isLastRecord)>& urlCallback)
494{
495    TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "get data from clipboard, sync");
496    OHOS::MiscServices::PasteData pasteData;
497    taskExecutor_->PostSyncTask(
498        [&pasteData]() {
499            auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
500            CHECK_NULL_VOID(has);
501            auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
502            CHECK_NULL_VOID(ok);
503        },
504        TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetPasteDataSync");
505
506    auto count = pasteData.GetRecordCount();
507    size_t index = 0;
508    for (const auto& pasteDataRecord : pasteData.AllRecords()) {
509        index++;
510        if (pasteDataRecord == nullptr) {
511            continue;
512        }
513        bool isLastRecord = index == count;
514        if (pasteDataRecord->GetPlainText() != nullptr) {
515            auto textData = pasteDataRecord->GetPlainText();
516            auto result = *textData;
517            textCallback(result, isLastRecord);
518        } else if (pasteDataRecord->GetPixelMap() != nullptr) {
519            auto imageData = pasteDataRecord->GetPixelMap();
520            auto result = AceType::MakeRefPtr<PixelMapOhos>(imageData);
521            pixelMapCallback(result, isLastRecord);
522        } else if (pasteDataRecord->GetUri() != nullptr) {
523            auto textData = pasteDataRecord->GetUri();
524            auto result = (*textData).ToString();
525            urlCallback(result, isLastRecord);
526        }
527    }
528}
529
530void ClipboardImpl::GetDataAsync(const std::function<void(const std::string&, bool isLastRecord)>& textCallback,
531    const std::function<void(const RefPtr<PixelMap>&, bool isLastRecord)>& pixelMapCallback,
532    const std::function<void(const std::string&, bool isLastRecord)>& urlCallback)
533{
534    TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "get data from clipboard, async");
535    taskExecutor_->PostTask(
536        [textCallback, pixelMapCallback, urlCallback, weakExecutor = WeakClaim(RawPtr(taskExecutor_))]() {
537            auto taskExecutor = weakExecutor.Upgrade();
538            auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
539            CHECK_NULL_VOID(has);
540            OHOS::MiscServices::PasteData pasteData;
541            auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
542            CHECK_NULL_VOID(ok);
543            auto count = pasteData.GetRecordCount();
544            size_t index = 0;
545            for (const auto& pasteDataRecord : pasteData.AllRecords()) {
546                index++;
547                if (pasteDataRecord == nullptr) {
548                    continue;
549                }
550                bool isLastRecord = index == count;
551                if (pasteDataRecord->GetPlainText() != nullptr) {
552                    auto textData = pasteDataRecord->GetPlainText();
553                    auto result = *textData;
554                    taskExecutor->PostTask(
555                        [textCallback, result, isLastRecord]() { textCallback(result, isLastRecord); },
556                        TaskExecutor::TaskType::UI, "ArkUIClipboardGetTextCallback");
557                } else if (pasteDataRecord->GetPixelMap() != nullptr) {
558                    auto imageData = pasteDataRecord->GetPixelMap();
559                    auto result = AceType::MakeRefPtr<PixelMapOhos>(imageData);
560                    taskExecutor->PostTask(
561                        [pixelMapCallback, result, isLastRecord]() { pixelMapCallback(result, isLastRecord); },
562                        TaskExecutor::TaskType::UI, "ArkUIClipboardGetImageCallback");
563                } else if (pasteDataRecord->GetUri() != nullptr) {
564                    auto textData = pasteDataRecord->GetUri();
565                    auto result = (*textData).ToString();
566                    taskExecutor->PostTask([urlCallback, result, isLastRecord]() { urlCallback(result, isLastRecord); },
567                        TaskExecutor::TaskType::UI, "ArkUIClipboardGetUrlCallback");
568                }
569            }
570        },
571        TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetDataAsync");
572}
573
574void ClipboardImpl::GetSpanStringData(
575    const std::function<void(std::vector<std::vector<uint8_t>>&, const std::string&, bool&)>& callback, bool syncMode)
576{
577#ifdef SYSTEM_CLIPBOARD_SUPPORTED
578    if (!taskExecutor_ || !callback) {
579        return;
580    }
581
582    GetSpanStringDataHelper(callback, syncMode);
583#endif
584}
585
586void ClipboardImpl::GetSpanStringDataHelper(
587    const std::function<void(std::vector<std::vector<uint8_t>>&, const std::string&, bool&)>& callback, bool syncMode)
588{
589    auto task = [callback, weakExecutor = WeakClaim(RawPtr(taskExecutor_)), weak = WeakClaim(this)]() {
590        auto clip = weak.Upgrade();
591        CHECK_NULL_VOID(clip);
592        auto taskExecutor = weakExecutor.Upgrade();
593        CHECK_NULL_VOID(taskExecutor);
594        auto hasData = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
595        CHECK_NULL_VOID(hasData);
596        OHOS::MiscServices::PasteData pasteData;
597        auto getDataRes = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
598        CHECK_NULL_VOID(getDataRes);
599        std::vector<std::vector<uint8_t>> arrays;
600        std::string text;
601        bool isMultiTypeRecord = false;
602        clip->ProcessSpanStringData(arrays, pasteData, text, isMultiTypeRecord);
603        auto textData = pasteData.GetPrimaryText();
604        if (textData && text.empty()) {
605            text.append(*textData);
606        }
607        auto result = text;
608        taskExecutor->PostTask(
609            [callback, arrays, result, isMultiTypeRecord]() mutable { callback(arrays, result, isMultiTypeRecord); },
610            TaskExecutor::TaskType::UI, "ArkUIClipboardGetSpanStringDataCallback");
611    };
612    if (syncMode) {
613        taskExecutor_->PostSyncTask(task, TaskExecutor::TaskType::BACKGROUND, "ArkUIClipboardGetSpanStringDataSync");
614    } else {
615        taskExecutor_->PostTask(task, TaskExecutor::TaskType::BACKGROUND, "ArkUIClipboardGetSpanStringDataAsync");
616    }
617}
618
619void ClipboardImpl::ProcessSpanStringData(std::vector<std::vector<uint8_t>>& arrays,
620    const OHOS::MiscServices::PasteData& pasteData, std::string& text, bool& isMultiTypeRecord)
621{
622    for (const auto& pasteDataRecord : pasteData.AllRecords()) {
623        if (pasteDataRecord == nullptr) {
624            continue;
625        }
626#ifdef SYSTEM_CLIPBOARD_SUPPORTED
627        std::vector<std::string> types = { SPAN_STRING_TAG, OHOS::MiscServices::MIMETYPE_TEXT_URI,
628            OHOS::MiscServices::MIMETYPE_PIXELMAP, OHOS::MiscServices::MIMETYPE_TEXT_PLAIN };
629        auto validTypes = pasteDataRecord->GetValidMimeTypes(types);
630        if (validTypes.size() > 1) {
631            isMultiTypeRecord = true;
632        }
633#endif
634        auto hasSpanString = false;
635        auto entryPtr = pasteDataRecord->GetEntryByMimeType(SPAN_STRING_TAG);
636        if (entryPtr) {
637            // entryValue InstanceOf OHOS::MiscServices::EntryValue.
638            auto entryValue = entryPtr->GetValue();
639            auto spanStringBuffer = std::get_if<std::vector<uint8_t>>(&entryValue);
640            arrays.emplace_back(*spanStringBuffer);
641            hasSpanString = true;
642        }
643        if (pasteDataRecord->GetHtmlText() != nullptr && hasSpanString) {
644            auto htmlText = pasteDataRecord->GetHtmlText();
645            HtmlToSpan toSpan;
646            auto spanStr = toSpan.ToSpanString(*htmlText);
647            if (spanStr) {
648                std::vector<uint8_t> arr;
649                spanStr->EncodeTlv(arr);
650                arrays.emplace_back(arr);
651            }
652        }
653        if (pasteDataRecord->GetPlainText() != nullptr) {
654            auto textData = pasteDataRecord->GetPlainText();
655            text.append(*textData);
656        }
657    }
658}
659
660void ClipboardImpl::GetPixelMapDataSync(const std::function<void(const RefPtr<PixelMap>&)>& callback)
661{
662    RefPtr<PixelMap> pixmap;
663    taskExecutor_->PostSyncTask(
664        [&pixmap]() {
665            auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
666            CHECK_NULL_VOID(has);
667            OHOS::MiscServices::PasteData pasteData;
668            auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
669            CHECK_NULL_VOID(ok);
670            auto imageData = pasteData.GetPrimaryPixelMap();
671            CHECK_NULL_VOID(imageData);
672            pixmap = AceType::MakeRefPtr<PixelMapOhos>(imageData);
673        },
674        TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetImageDataSync");
675    callback(pixmap);
676}
677
678void ClipboardImpl::GetPixelMapDataAsync(const std::function<void(const RefPtr<PixelMap>&)>& callback)
679{
680    taskExecutor_->PostTask(
681        [callback, weakExecutor = WeakClaim(RawPtr(taskExecutor_))]() {
682            auto taskExecutor = weakExecutor.Upgrade();
683            CHECK_NULL_VOID(taskExecutor);
684            auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
685            if (!has) {
686                TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "SystemKeyboardData is not exist from MiscServices");
687                taskExecutor->PostTask(
688                    [callback]() { callback(nullptr); }, TaskExecutor::TaskType::UI, "ArkUIClipboardHasDataFailed");
689                return;
690            }
691            OHOS::MiscServices::PasteData pasteData;
692            auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
693            if (!ok) {
694                TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "Get SystemKeyboardData fail from MiscServices");
695                taskExecutor->PostTask(
696                    [callback]() { callback(nullptr); }, TaskExecutor::TaskType::UI, "ArkUIClipboardGetDataFailed");
697                return;
698            }
699            auto imageData = pasteData.GetPrimaryPixelMap();
700            if (!imageData) {
701                TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "Get SystemKeyboardImageData fail from MiscServices");
702                taskExecutor->PostTask(
703                    [callback]() { callback(nullptr); },
704                    TaskExecutor::TaskType::UI, "ArkUIClipboardGetImageDataFailed");
705                return;
706            }
707            auto result = AceType::MakeRefPtr<PixelMapOhos>(imageData);
708            taskExecutor->PostTask(
709                [callback, result]() { callback(result); },
710                TaskExecutor::TaskType::UI, "ArkUIClipboardGetImageDataCallback");
711        },
712        TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetImageDataAsync");
713}
714#endif
715
716void ClipboardImpl::Clear() {}
717
718} // namespace OHOS::Ace
719