Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qohosudmfconversions.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtCore/private/qohoscommon_p.h>
5#include <QtCore/private/qohoslogger_p.h>
6#include <QtCore/qspan.h>
7#include <QtCore/qurl.h>
8#include <QtGui/qimage.h>
9#include <algorithm>
10#include <chrono>
11#include <cstring>
12#include <database/udmf/udmf_err_code.h>
13#include <database/udmf/udmf_meta.h>
14#include <database/udmf/utd.h>
15#include <qarkui/qarkuiutils.h>
16#include <qohosmimedata.h>
17#include <qohospixelmapconversions.h>
18#include <qohosplatformservices.h>
19#include <qohosplugincore.h>
20#include <qohosudmfconversions.h>
21#include <qohosudmf.h>
22#include <qohosudsobject.h>
23#include <qohosutils.h>
24#include <random>
25#include <unistd.h>
26
27namespace ch = std::chrono;
28
29QT_BEGIN_NAMESPACE
30
31namespace {
32
33constexpr const char *mimeTextPlain = "text/plain";
34constexpr const char *mimeTextHtml = "text/html";
35constexpr const char *mimeTextUriList = "text/uri-list";
36constexpr const char *mimeAppXQtImage = "application/x-qt-image";
37
38const auto qtAppInfoDataPseudoMimeType = "io.qt.ohos.appInfoData";
39
40constexpr auto processQMimeDataInQtThreadTimeout = ch::seconds(2);
41
43{
44public:
45 template<typename RawUdsObject>
47 QOhosSupplier<QOhosUdsObject<RawUdsObject>> udsObjectFactory);
48
50 std::string mimeType, QOhosSupplier<QSpan<const std::uint8_t>> dataSupplier);
51
53
54 void addEntryToRecord(QOhosUdmfRecord &udmfRecord) const;
55
57
58private:
60 QOhosSupplier<void *> recordProviderDataFactory,
61 std::function<void(QOhosUdmfRecord &)> recordAddEntryFunc);
62
63 QOhosSupplier<void *> m_recordProviderDataFactory;
64 std::function<void(QOhosUdmfRecord &)> m_recordAddEntryFunc;
65};
66
72
74{
75 static std::vector<std::uint8_t> appInfoData = []() {
76 std::vector<std::uint8_t> appInfoData;
77
78 auto pidString = std::to_string(::getpid()) + ":";
79 std::copy(pidString.begin(), pidString.end(), std::back_inserter(appInfoData));
80
81 using RandomBytesEngine = std::independent_bits_engine<std::default_random_engine, 8, std::uint8_t>;
82 std::vector<std::uint8_t> key(64);
83 std::generate(std::begin(key), std::end(key), RandomBytesEngine(std::random_device()()));
84 std::copy(key.begin(), key.end(), std::back_inserter(appInfoData));
85
86 return appInfoData;
87 }();
88
89 return appInfoData;
90}
91
92template<typename T>
94 std::function<void(QOhosConsumer<T>)> qtEvalFunc, ch::nanoseconds timeout)
95{
96 auto sharedResultBox = std::make_shared<QOhosOptional<T>>();
97
98 auto qtTaskFinished = QtOhos::tryInvokeInQtThreadAndTryWaitForContinue(
99 [sharedResultBox, qtEvalFunc = std::move(qtEvalFunc)](std::function<void()> continueFunc) {
100 qtEvalFunc(
101 [sharedResultBox, continueFunc = std::move(continueFunc)](T result) {
102 *sharedResultBox = std::move(result);
103 continueFunc();
104 });
105 },
106 timeout);
107
108 return qtTaskFinished
109 ? std::move(*sharedResultBox)
111}
112
113template<typename T, typename K>
114std::vector<T> getMapKeys(const std::map<T, K> &inputMap)
115{
116 std::vector<T> mapKeys;
117 mapKeys.reserve(inputMap.size());
118 for (const auto &mapEntry : inputMap)
119 mapKeys.push_back(mapEntry.first);
120 return mapKeys;
121}
122
123template<typename T>
125{
126 return [value = std::move(value)]() {
127 return makeQOhosOptional(value);
128 };
129}
130
131bool hasQMimeDataPeerType(const char *type)
132{
133 static constexpr const char *udmfTypesWithQMimeDataPeerTypes[] = {
134 QOhosUdsMeta<::OH_UdsFileUri>::udmfMetaId,
135 QOhosUdsMeta<::OH_UdsHyperlink>::udmfMetaId,
136 QOhosUdsMeta<::OH_UdsHtml>::udmfMetaId,
137 QOhosUdsMeta<::OH_UdsPixelMap>::udmfMetaId,
138 QOhosUdsMeta<::OH_UdsPlainText>::udmfMetaId,
139 };
140
141 return std::any_of(
142 std::begin(udmfTypesWithQMimeDataPeerTypes),
143 std::end(udmfTypesWithQMimeDataPeerTypes),
144 [&](const char *specificMetaType) {
145 return std::strcmp(type, specificMetaType) == 0;
146 });
147}
148
149bool isUdmfMetaFileType(const std::string &type)
150{
151 static constexpr const char *udmfMetaFileTypes[] = {
152 UDMF_META_GENERAL_FILE,
153 UDMF_META_AUDIO,
154 UDMF_META_FOLDER,
155 UDMF_META_IMAGE,
156 UDMF_META_VIDEO,
157 };
158
159 return std::any_of(
160 std::begin(udmfMetaFileTypes),
161 std::end(udmfMetaFileTypes),
162 [&](const char *specificMetaType) {
163 return type == specificMetaType;
164 });
165}
166
167std::vector<std::string> utdGetTypesByMimeType(const std::string &mimeType)
168{
169 unsigned int typesCount = 0;
170 auto func = Q_OHOS_NAMED_FUNC(::OH_Utd_GetTypesByMimeType);
171 const char **utdTypeIds = QArkUi::callArkUi(func, QArkUi::CZString(mimeType.c_str()), &typesCount);
172 if (utdTypeIds == nullptr && typesCount != 0) {
173 qOhosReportFatalErrorAndAbort(
174 "%s: got inconsistent result from %s() call: array is null, size is %u",
175 Q_FUNC_INFO, func.name(), typesCount);
176 }
177
178 auto result = utdTypeIds != nullptr
179 ? std::vector<std::string>(utdTypeIds, utdTypeIds + typesCount)
180 : std::vector<std::string>();
181
182 QArkUi::callArkUi(
183 Q_OHOS_NAMED_FUNC(::OH_Utd_DestroyStringList), utdTypeIds, typesCount);
184
185 return result;
186}
187
188std::shared_ptr<::OH_Utd> utdCreateOrNull(const std::string &typeId)
189{
190 return {
191 QArkUi::callArkUi(
192 Q_OHOS_NAMED_FUNC(::OH_Utd_Create),
193 QArkUi::CZString(typeId.c_str())),
194 [](::OH_Utd *utd) {
195 if (utd != nullptr)
196 QArkUi::callArkUi(Q_OHOS_NAMED_FUNC(::OH_Utd_Destroy), utd);
197 }
198 };
199}
200
202{
203 unsigned int typesCount = 0;
204 auto func = Q_OHOS_NAMED_FUNC(::OH_Utd_GetMimeTypes);
205 const char **mimeTypes = QArkUi::callArkUi(func, utd, &typesCount);
206 if (mimeTypes == nullptr && typesCount != 0) {
207 qOhosReportFatalErrorAndAbort(
208 "%s: got inconsistent result from %s() call: array is null, size is %u",
209 Q_FUNC_INFO, func.name(), typesCount);
210 }
211
212 auto result = mimeTypes != nullptr
213 ? std::vector<std::string>(mimeTypes, mimeTypes + typesCount)
214 : std::vector<std::string>();
215
216 return result;
217}
218
219template<typename T>
220bool hasMatchingTypeEntryInRecords(QSpan<const QOhosUdmfRecord> records)
221{
222 static const auto searchTypeId = QOhosUdsMeta<T>::udmfMetaId;
223 return std::any_of(
224 records.begin(), records.end(),
225 [&](auto &record) {
226 auto recordTypes = record.getTypes();
227 return std::find(recordTypes.begin(), recordTypes.end(), searchTypeId) != recordTypes.end();
228 });
229}
230
231template<typename T>
233 QSpan<const QOhosUdmfRecord> records,
234 const QOhosConsumer<QOhosUdsObject<T>> &processEntryFunc)
235{
236 for (auto &record : records) {
237 for (auto &typeId : record.getTypes()) {
238 if (QOhosUdsMeta<T>::udmfMetaId == typeId)
239 processEntryFunc(record.getEntry<T>());
240 }
241 }
242}
243
245 std::shared_ptr<void> context, QSpan<const QOhosUdmfRecord> inputRecords,
247{
248 if (!hasMatchingTypeEntryInRecords<::OH_UdsFileUri>(inputRecords)
249 && !hasMatchingTypeEntryInRecords<::OH_UdsHyperlink>(inputRecords)) {
250 return;
251 }
252
253 outMimeDataSuppliers.emplace(
254 QString::fromUtf8(mimeTextUriList),
255 [context, inputRecords]() {
256 QList<QUrl> urls;
257 tryProcessEntriesOfTypeInRecords<::OH_UdsFileUri>(
258 inputRecords,
259 [&](auto udsEntry) {
260 urls.append(
261 {
262 QUrl::fromLocalFile(
263 QString::fromStdString(
264 QOhosPlatformServices::mapOhosFileUriToPathInJsThread(
265 udsEntry.getContent()))),
266 });
267 });
268 tryProcessEntriesOfTypeInRecords<::OH_UdsHyperlink>(
269 inputRecords,
270 [&](auto udsEntry) {
271 urls.append(QUrl(QString::fromStdString(udsEntry.getContent())));
272 });
273
274 QList<QVariant> urlsVariants;
275 for (const auto &url : urls)
276 urlsVariants.append(url);
277
278 return QVariant(urlsVariants);
279 });
280}
281
283 std::shared_ptr<void> context, QSpan<const QOhosUdmfRecord> inputRecords,
285{
286 for (auto &record : inputRecords) {
287 for (auto &typeId : record.getTypes()) {
288 if (!hasQMimeDataPeerType(typeId.c_str()) && !isUdmfMetaFileType(typeId)) {
289 // FIXME: the `utdGetMimeTypes()` result interpretation is not quite
290 // clear. Documentaion does not mention why there is a list of possible mime types.
291 // Are they ordered in a specific manear? Is it possible to get en ampty list?
292 // Improve and fix the code when these are known.
293 auto optUtdWithTypeId = utdCreateOrNull(typeId);
294 auto mimeTypes = optUtdWithTypeId
295 ? utdGetMimeTypes(optUtdWithTypeId.get())
296 : std::vector<std::string>();
297 if (!mimeTypes.empty()) {
298 outMimeDataSuppliers.emplace(
299 QString::fromStdString(mimeTypes.front()),
300 [context, recordPtr = &record, typeId]() {
301 auto generalEntry = recordPtr->tryGetGeneralEntry(typeId);
302 if (!generalEntry.has_value())
303 return QVariant();
304
305 return QVariant(
306 QByteArray(
307 reinterpret_cast<const char *>(generalEntry.value().data()),
308 generalEntry.value().size()));
309 });
310 } else {
311 qOhosPrintfWarning(
312 "%s: cannot convert UTD type id '%s' to mime type. Skip this entry.",
313 Q_FUNC_INFO, typeId.c_str());
314 }
315 }
316 }
317 }
318}
319
320std::map<QString, QOhosSupplier<QVariant>> makeMimeDataSuppliersMapFromUdmfData(QOhosUdmfData udmfData)
321{
322 struct Context
323 {
324 QOhosUdmfData udmfData;
325 std::vector<QOhosUdmfRecord> records;
326 };
327
328 auto context = QtOhos::makeProxyWithJsThreadDeleter(std::make_shared<Context>());
329 context->udmfData = std::move(udmfData);
330 context->records = context->udmfData.getRecords();
331
332 if (context->records.size() == 0)
333 return {};
334
335 std::map<QString, QOhosSupplier<QVariant>> mimeDataSuppliers;
336
337 auto firstRecordSpan = QSpan(context->records.data(), 1);
338
339 if (hasMatchingTypeEntryInRecords<::OH_UdsPlainText>(firstRecordSpan)) {
340 mimeDataSuppliers.emplace(
341 QString::fromUtf8(mimeTextPlain),
342 [context]() {
343 QVariant value;
344 tryProcessEntriesOfTypeInRecords<::OH_UdsPlainText>(
345 QSpan(context->records.data(), 1),
346 [&](auto udsEntry) {
347 value = QString::fromUtf8(udsEntry.getContent(), -1);
348 });
349 return value;
350 });
351 }
352
353 if (hasMatchingTypeEntryInRecords<::OH_UdsHtml>(firstRecordSpan)) {
354 mimeDataSuppliers.emplace(
355 QString::fromUtf8(mimeTextHtml),
356 [context]() {
357 QVariant value;
358 tryProcessEntriesOfTypeInRecords<::OH_UdsHtml>(
359 QSpan(context->records.data(), 1),
360 [&](auto udsEntry) {
361 value = QString::fromUtf8(udsEntry.getContent(), -1);
362 });
363 return value;
364 });
365 }
366
367 if (hasMatchingTypeEntryInRecords<::OH_UdsPixelMap>(firstRecordSpan)) {
368 mimeDataSuppliers.emplace(
369 QString::fromUtf8(mimeAppXQtImage),
370 [context]() {
371 QVariant value;
372 tryProcessEntriesOfTypeInRecords<::OH_UdsPixelMap>(
373 QSpan(context->records.data(), 1),
374 [&](auto udsEntry) {
375 value = createQImageFromNativePixelMap(udsEntry.getContent().get());
376 });
377 return value;
378 });
379 }
380
381 addMimeDataSuppliersForUrlLikeEntriesFromRecords(
382 context, QSpan(context->records.data(), context->records.size()), mimeDataSuppliers);
383
384 addMimeDataSuppliersForGeneralEntriesFromRecords(context, firstRecordSpan, mimeDataSuppliers);
385
386 return mimeDataSuppliers;
387}
388
390{
391 return url.isLocalFile()
392 ? UdmfRecordEntryFactory::makeForUdsObjectFactory<::OH_UdsFileUri>(
393 [url]() {
394 return QOhosUdsObject<::OH_UdsFileUri>(
395 QOhosPlatformServices::mapPathToOhosUriInJsThread(
396 url.toLocalFile().toStdString()).c_str());
397 })
398 : UdmfRecordEntryFactory::makeForUdsObjectFactory<::OH_UdsHyperlink>(
399 [url]() {
400 return QOhosUdsObject<::OH_UdsHyperlink>(
401 url.toString().toStdString().c_str());
402 });
403}
404
405void addUrlEntryToUdmfRecord(const QUrl &url, QOhosUdmfRecord &outRecord)
406{
407 makeUdmfRecordEntryFactoryForUrl(url).addEntryToRecord(outRecord);
408}
409
411{
412 return {
413 QArkUi::callArkUiOrFailOnNullResult(
414 Q_OHOS_NAMED_FUNC(::OH_UdmfProperty_Create),
415 udmfData),
416 [](::OH_UdmfProperty *udmfProperty) {
417 QArkUi::callArkUi(
418 Q_OHOS_NAMED_FUNC(::OH_UdmfProperty_Destroy),
419 udmfProperty);
420 }
421 };
422}
423
425{
426 return {
427 QArkUi::callArkUiOrFailOnNullResult(
428 Q_OHOS_NAMED_FUNC(::OH_UdsArrayBuffer_Create)),
429 [](::OH_UdsArrayBuffer *udsArrayBuffer) {
430 QArkUi::callArkUiOrFailOnErrorResult(
431 Q_OHOS_NAMED_FUNC(::OH_UdsArrayBuffer_Destroy),
432 udsArrayBuffer);
433 }
434 };
435}
436
438 createUdsArrayBufferWithData(QSpan<const std::uint8_t> data)
439{
440 auto udsArrayBuffer = createUdsArrayBuffer();
441 QArkUi::callArkUiOrFailOnErrorResult(
442 Q_OHOS_NAMED_FUNC(::OH_UdsArrayBuffer_SetData),
443 udsArrayBuffer.get(), const_cast<std::uint8_t *>(data.data()), data.size());
444 return udsArrayBuffer;
445}
446
447void addGeneralEntryToRecord(std::string mimeType, QSpan<const std::uint8_t> dataBytes, QOhosUdmfRecord &record)
448{
449 if (dataBytes.size() == 0) {
450 qOhosPrintfWarning(
451 "%s: got empty data for type '%s', which is not supported by UDMF record, skipping this entry",
452 Q_FUNC_INFO, mimeType.c_str());
453 return;
454 }
455
456 auto optUtdTypeId = tryMapMimeTypeToUtdTypeId(mimeType);
457 if (optUtdTypeId.has_value()) {
458 record.addGeneralEntry(optUtdTypeId.value(), dataBytes);
459 } else {
460 qOhosPrintfWarning(
461 "%s: cannot convert mime type '%s' to type id. Skip this entry.",
462 Q_FUNC_INFO, mimeType.c_str());
463 }
464}
465
466template<typename RawUdsObject>
467UdmfRecordEntryFactory UdmfRecordEntryFactory::makeForUdsObjectFactory(
468 QOhosSupplier<QOhosUdsObject<RawUdsObject>> udsObjectFactory)
469{
470 auto sharedUdsObjectFactory = QtOhos::moveToSharedPtr(std::move(udsObjectFactory));
471 return UdmfRecordEntryFactory(
472 [sharedUdsObjectFactory]() {
473 void *data = (*sharedUdsObjectFactory)().release();
474 qOhosPrintfWarning(
475 "%s: generated '%s' data for OH_UdmfRecordProvider: %p",
476 Q_FUNC_INFO, QOhosUdsMeta<RawUdsObject>::udmfMetaId, data);
477 return data;
478 },
479 [sharedUdsObjectFactory](QOhosUdmfRecord &record) {
480 record.addEntry((*sharedUdsObjectFactory)());
481 });
482}
483
484UdmfRecordEntryFactory UdmfRecordEntryFactory::makeForArrayBufferWithMimeType(
485 std::string mimeType, QOhosSupplier<QSpan<const std::uint8_t>> dataSupplier)
486{
487 auto sharedDataSupplier = QtOhos::moveToSharedPtr(std::move(dataSupplier));
488 return UdmfRecordEntryFactory(
489 [mimeType, sharedDataSupplier]() {
490 auto dataSpan = (*sharedDataSupplier)();
491 auto udsArrayBuffer = createUdsArrayBufferWithData(dataSpan);
492 qOhosPrintfDebug(
493 "%s: generated array buffer for OH_UdmfRecordProvider, mimeType='%s', size=%zu",
494 Q_FUNC_INFO, mimeType.c_str(), static_cast<std::size_t>(dataSpan.size()));
495 return udsArrayBuffer.release();
496 },
497 [mimeType, sharedDataSupplier](QOhosUdmfRecord &record) {
498 addGeneralEntryToRecord(mimeType, (*sharedDataSupplier)(), record);
499 });
500}
501
503{
504 return UdmfRecordEntryFactory(
505 []() {
506 return nullptr;
507 },
508 [](QOhosUdmfRecord &) {
509 });
510}
511
512UdmfRecordEntryFactory::UdmfRecordEntryFactory(
513 QOhosSupplier<void *> recordProviderDataFactory,
514 std::function<void(QOhosUdmfRecord &)> recordAddEntryFunc)
515 : m_recordProviderDataFactory(std::move(recordProviderDataFactory))
516 , m_recordAddEntryFunc(std::move(recordAddEntryFunc))
517{
518}
519
521{
522 m_recordAddEntryFunc(udmfRecord);
523}
524
526{
527 return m_recordProviderDataFactory();
528}
529
531{
532 std::vector<UdmfRecordEntryMetaFactory> recordEntryMetaFactories;
533 for (auto qStrFormat : mimeDataFormats) {
534 auto format = qStrFormat.toStdString();
535 if (format == mimeTextPlain) {
536 recordEntryMetaFactories.emplace_back(
537 UdmfRecordEntryMetaFactory{
538 makeOptionalValueSupplier<std::string>(QOhosUdsMeta<::OH_UdsPlainText>::udmfMetaId),
539 [](const QMimeData &mimeData) {
540 auto dataText = mimeData.text();
541 return UdmfRecordEntryFactory::makeForUdsObjectFactory<::OH_UdsPlainText>(
542 [dataText]() {
543 return QOhosUdsObject<::OH_UdsPlainText>(dataText.toStdString().c_str());
544 });
545 }
546 });
547 } else if (format == mimeTextHtml) {
548 recordEntryMetaFactories.emplace_back(
549 UdmfRecordEntryMetaFactory{
550 makeOptionalValueSupplier<std::string>(QOhosUdsMeta<::OH_UdsHtml>::udmfMetaId),
551 [](const QMimeData &mimeData) {
552 auto dataHtml = mimeData.html();
553 return UdmfRecordEntryFactory::makeForUdsObjectFactory<::OH_UdsHtml>(
554 [dataHtml]() {
555 return QOhosUdsObject<::OH_UdsHtml>(dataHtml.toStdString().c_str());
556 });
557 }
558 });
559 } else if (format == mimeTextUriList) {
560 recordEntryMetaFactories.emplace_back(
561 UdmfRecordEntryMetaFactory{
562 {},
563 [](const QMimeData &mimeData) {
564 auto dataUrls = mimeData.urls();
565 return !dataUrls.isEmpty()
566 ? makeUdmfRecordEntryFactoryForUrl(dataUrls.first())
567 : UdmfRecordEntryFactory::makeDummy();
568 }
569 });
570 } else if (format == mimeAppXQtImage) {
571 recordEntryMetaFactories.emplace_back(
572 UdmfRecordEntryMetaFactory{
573 makeOptionalValueSupplier<std::string>(QOhosUdsMeta<::OH_UdsPixelMap>::udmfMetaId),
574 [](const QMimeData &mimeData) {
575 auto dataImage = qvariant_cast<QImage>(mimeData.imageData());
576 return UdmfRecordEntryFactory::makeForUdsObjectFactory<::OH_UdsPixelMap>(
577 [dataImage]() {
578 return QOhosUdsObject<::OH_UdsPixelMap>(createNativePixelMapFromQImage(dataImage));
579 });
580 }
581 });
582 } else {
583 recordEntryMetaFactories.emplace_back(
584 UdmfRecordEntryMetaFactory{
585 [qStrFormat]() {
586 return tryMapMimeTypeToUtdTypeId(qStrFormat.toStdString());
587 },
588 [qStrFormat](const QMimeData &mimeData) {
589 auto dataBytes = mimeData.data(qStrFormat);
590 return UdmfRecordEntryFactory::makeForArrayBufferWithMimeType(
591 qStrFormat.toStdString(),
592 [dataBytes]() {
593 return QSpan<const std::uint8_t>(
594 reinterpret_cast<const std::uint8_t *>(dataBytes.constData()),
595 dataBytes.length());
596 });
597 }
598 });
599 }
600 }
601
602 return recordEntryMetaFactories;
603}
604
606 const QMimeData &mimeData, std::shared_ptr<QMimeData> optLazyProcessingMimeData)
607{
608 auto recordEntryMetaFactories = makeRecordEntryMetaFactoriesForMimeDataFormats(mimeData.formats());
609 if (recordEntryMetaFactories.empty())
610 return nullptr;
611
612 struct Context
613 {
614 std::vector<UdmfRecordEntryFactory> directEntryFactories;
615 std::vector<UdmfRecordEntryMetaFactory> providerEntries;
616 };
617
618 auto context = std::make_shared<Context>();
619
620 const bool useRecordProvider = optLazyProcessingMimeData != nullptr;
621
622 for (auto &recordEntryFactoryEntry : recordEntryMetaFactories) {
623 if (useRecordProvider && recordEntryFactoryEntry.optUdmfMetaIdFactory) {
624 context->providerEntries.push_back(std::move(recordEntryFactoryEntry));
625 } else {
626 context->directEntryFactories.push_back(
627 recordEntryFactoryEntry.metaFactoryFunc(mimeData));
628 }
629 }
630
631 return [context, optLazyProcessingMimeData]() {
632 QOhosUdmfRecord record;
633 for (const auto &directEntryFactory : context->directEntryFactories)
634 directEntryFactory.addEntryToRecord(record);
635
636 auto entryMetaFactoryFuncsForProvider =
637 std::make_shared<std::map<std::string, std::function<UdmfRecordEntryFactory(const QMimeData &)>>>();
638 for (const auto &providerEntry : context->providerEntries) {
639 auto optUdmfMetaId = providerEntry.optUdmfMetaIdFactory();
640 if (optUdmfMetaId.has_value()) {
641 entryMetaFactoryFuncsForProvider->emplace(
642 optUdmfMetaId.value(), providerEntry.metaFactoryFunc);
643 }
644 }
645
646 if (!entryMetaFactoryFuncsForProvider->empty()) {
647 auto lazyProcessingMimeData = optLazyProcessingMimeData;
648 record.setProviderForDataFetchFunc(
649 getMapKeys(*entryMetaFactoryFuncsForProvider),
650 [entryMetaFactoryFuncsForProvider, lazyProcessingMimeData](const char *type) {
651 qOhosPrintfDebug("%s: got request for data '%s'", Q_FUNC_INFO, type);
652
653 auto typeStr = std::string(type);
654 auto optUdmfRecordEntryFactory = tryEvalInQtThreadWithConsumer<UdmfRecordEntryFactory>(
655 [entryMetaFactoryFuncsForProvider, lazyProcessingMimeData, typeStr](QOhosConsumer<UdmfRecordEntryFactory> resultConsumer) {
656 qOhosPrintfDebug("%s: processing request for data '%s' in Qt thread", Q_FUNC_INFO, typeStr.c_str());
657 auto entryMetaFactoryFuncIter = entryMetaFactoryFuncsForProvider->find(typeStr);
658 resultConsumer(
659 entryMetaFactoryFuncIter != entryMetaFactoryFuncsForProvider->end()
660 ? entryMetaFactoryFuncIter->second(*lazyProcessingMimeData)
662 qOhosPrintfDebug("%s: finished processing in Qt thread", Q_FUNC_INFO);
663 },
664 processQMimeDataInQtThreadTimeout);
665 qOhosPrintfDebug(
666 "%s: got result from Qt thread: %s",
667 Q_FUNC_INFO, QtOhos::mapBoolToTrueFalseStr(optUdmfRecordEntryFactory.has_value()));
668
669 void *providerResult = optUdmfRecordEntryFactory.has_value()
670 ? optUdmfRecordEntryFactory.value().makeRecordProviderDataForEntry()
671 : nullptr;
672 qOhosPrintfDebug("%s: provider result: %p", Q_FUNC_INFO, providerResult);
673
674 return providerResult;
675 });
676 }
677 return record;
678 };
679}
680
682 const QMimeData &mimeData, const QOhosOptional<bool> &shareInAppOnly,
683 std::shared_ptr<QMimeData> optLazyProcessingMimeData = nullptr)
684{
685 std::vector<std::function<QOhosUdmfRecord()>> recordFactories;
686
687 auto optDefaultRecordFactory = tryMakeDefaultUdmfRecordFactoryFromQMimeDataOrNull(
688 mimeData, optLazyProcessingMimeData);
689 if (optDefaultRecordFactory)
690 recordFactories.push_back(std::move(optDefaultRecordFactory));
691
692 if (mimeData.hasUrls()) {
693 auto urls = mimeData.urls();
694 for (int i = 1; i < urls.size(); ++i) {
695 auto dataUrl = urls.at(i);
696 recordFactories.emplace_back(
697 [dataUrl]() {
698 QOhosUdmfRecord record;
699 addUrlEntryToUdmfRecord(dataUrl, record);
700 return record;
701 });
702 }
703 }
704
705 recordFactories.emplace_back(
706 []() {
707 QOhosUdmfRecord record;
708 auto appInfoDataBytes = getAppInfoDataForThisProcess();
709 addGeneralEntryToRecord(
710 qtAppInfoDataPseudoMimeType, QSpan<const std::uint8_t>(appInfoDataBytes.data(), appInfoDataBytes.size()), record);
711 return record;
712 });
713
714 return [shareInAppOnly, recordFactories = std::move(recordFactories)]() {
715 QOhosUdmfData udmfData;
716
717 if (shareInAppOnly.has_value()) {
718 auto udmfShareProperty = createUdmfPropertyForUdmfData(udmfData.nativePtr());
719 QArkUi::callArkUiOrFailOnErrorResult(
720 Q_OHOS_NAMED_FUNC(::OH_UdmfProperty_SetShareOption),
721 udmfShareProperty.get(),
722 shareInAppOnly.value()
723 ? ::Udmf_ShareOption::SHARE_OPTIONS_IN_APP
724 : ::Udmf_ShareOption::SHARE_OPTIONS_CROSS_APP);
725 }
726
727 for (const auto &recordFactory : recordFactories)
728 udmfData.addRecord(recordFactory());
729
730 return udmfData;
731 };
732}
733
734}
735
737 const QMimeData &mimeData, const QOhosOptional<bool> &shareInAppOnly)
738{
739 return makeUdmfDataFactoryFromQMimeDataImpl(mimeData, shareInAppOnly, nullptr);
740}
741
743 std::shared_ptr<QMimeData> mimeData, const QOhosOptional<bool> &shareInAppOnly)
744{
745 return makeUdmfDataFactoryFromQMimeDataImpl(*mimeData, shareInAppOnly, mimeData);
746}
747
749{
750 std::map<QString, QVariant> mimeDataMap;
751 for (auto &supplierEntry : makeMimeDataSuppliersMapFromUdmfData(std::move(udmfData)))
752 mimeDataMap.emplace(supplierEntry.first, supplierEntry.second());
753
754 return makeQOhosMimeDataFactory(std::move(mimeDataMap));
755}
756
758{
759 std::map<QString, QOhosSupplier<QVariant>> threadSafeSuppliers;
760 for (auto &supplierEntry : makeMimeDataSuppliersMapFromUdmfData(std::move(udmfData))) {
761 threadSafeSuppliers.emplace(
762 supplierEntry.first,
763 [mimeType = supplierEntry.first.toStdString(), baseSupplier = std::move(supplierEntry.second)]() {
764 qOhosPrintfDebug("%s: fetching data for MIME type '%s'", Q_FUNC_INFO, mimeType.c_str());
765 return QtOhos::evalInJsThread(
766 [&](QtOhos::JsState &) {
767 return baseSupplier();
768 },
769 Q_FUNC_INFO);
770 });
771 }
772
773 return makeQOhosLazyFetchMimeDataFactory(std::move(threadSafeSuppliers));
774}
775
777 std::vector<std::string> udmfDataTypes)
778{
779 return [udmfDataTypes = std::move(udmfDataTypes)]() {
780 const auto dummyText = QString::fromUtf8(
781 "OHOS QPA: Drag data is not available before DROP. This is a system limitation.");
782
783 auto mimeData = std::make_unique<QMimeData>();
784
785 for (const auto &type : udmfDataTypes) {
786 if (type == QOhosUdsMeta<::OH_UdsPlainText>::udmfMetaId) {
787 mimeData->setText(dummyText);
788 } else if (type == QOhosUdsMeta<::OH_UdsHtml>::udmfMetaId) {
789 mimeData->setHtml(dummyText);
790 } else if (type == QOhosUdsMeta<::OH_UdsPixelMap>::udmfMetaId) {
791 mimeData->setImageData(QImage(1, 1, QImage::Format::Format_RGBA8888));
792 } else if (type == QOhosUdsMeta<::OH_UdsFileUri>::udmfMetaId || isUdmfMetaFileType(type)) {
793 mimeData->setUrls({});
794 }
795 }
796
797 if (mimeData->formats().isEmpty())
798 mimeData->setText(dummyText);
799
800 return mimeData;
801 };
802}
803
805{
806 auto qtAppInfoDataUtdTypeId = tryMapMimeTypeToUtdTypeId(qtAppInfoDataPseudoMimeType);
807 if (!qtAppInfoDataUtdTypeId.has_value()) {
808 qOhosPrintfError("%s: Can't map %s to UTD type id", Q_FUNC_INFO, qtAppInfoDataPseudoMimeType);
809 return false;
810 }
811
812 auto udmfRecords = udmfData.getRecords();
813 auto thisProcessAppInfoData = getAppInfoDataForThisProcess();
814
815 return std::any_of(
816 udmfRecords.begin(), udmfRecords.end(),
817 [&](auto &udmfRecord) {
818 auto optAppInfoData = udmfRecord.tryGetGeneralEntry(qtAppInfoDataUtdTypeId.value());
819 if (!optAppInfoData.has_value())
820 return false;
821
822 auto appInfoData = optAppInfoData.value();
823
824 return
825 static_cast<std::size_t>(appInfoData.size()) == thisProcessAppInfoData.size()
826 && std::memcmp(appInfoData.data(), thisProcessAppInfoData.data(), appInfoData.size()) == 0;
827 });
828}
829
831{
832 auto optUtdWithTypeId = utdCreateOrNull(utdTypeId);
833 auto mimeTypes = optUtdWithTypeId
834 ? utdGetMimeTypes(optUtdWithTypeId.get())
835 : std::vector<std::string>();
836
837 return !mimeTypes.empty()
838 ? makeQOhosOptional(mimeTypes.front())
840}
841
843{
844 // FIXME: the `utdGetTypesByMimeType()` result interpretation is not quite clear.
845 // Documentaion does not mention why there is a list of possible type ids.
846 // Are they ordered in a specific manear? Is it possible to get en ampty list?
847 // Improve and fix the code when these are known.
848 auto utdTypeIds = utdGetTypesByMimeType(mimeType);
849 return
850 !utdTypeIds.empty()
851 ? makeQOhosOptional(utdTypeIds.front())
853}
854
855QT_END_NAMESPACE
void addEntryToRecord(QOhosUdmfRecord &udmfRecord) const
static UdmfRecordEntryFactory makeForArrayBufferWithMimeType(std::string mimeType, QOhosSupplier< QSpan< const std::uint8_t > > dataSupplier)
static UdmfRecordEntryFactory makeForUdsObjectFactory(QOhosSupplier< QOhosUdsObject< RawUdsObject > > udsObjectFactory)
std::function< QOhosUdmfData()> makeUdmfDataFactoryFromQMimeDataImpl(const QMimeData &mimeData, const QOhosOptional< bool > &shareInAppOnly, std::shared_ptr< QMimeData > optLazyProcessingMimeData=nullptr)
std::vector< std::uint8_t > getAppInfoDataForThisProcess()
std::vector< T > getMapKeys(const std::map< T, K > &inputMap)
UdmfRecordEntryFactory makeUdmfRecordEntryFactoryForUrl(const QUrl &url)
std::vector< std::string > utdGetTypesByMimeType(const std::string &mimeType)
std::vector< std::string > utdGetMimeTypes(::OH_Utd *utd)
bool hasQMimeDataPeerType(const char *type)
void addMimeDataSuppliersForUrlLikeEntriesFromRecords(std::shared_ptr< void > context, QSpan< const QOhosUdmfRecord > inputRecords, std::map< QString, QOhosSupplier< QVariant > > &outMimeDataSuppliers)
constexpr auto processQMimeDataInQtThreadTimeout
std::shared_ptr<::OH_UdmfProperty > createUdmfPropertyForUdmfData(::OH_UdmfData *udmfData)
QOhosSupplier< QOhosOptional< T > > makeOptionalValueSupplier(T value)
std::unique_ptr<::OH_UdsArrayBuffer, void(*)(::OH_UdsArrayBuffer *)> createUdsArrayBufferWithData(QSpan< const std::uint8_t > data)
std::vector< UdmfRecordEntryMetaFactory > makeRecordEntryMetaFactoriesForMimeDataFormats(QStringList mimeDataFormats)
void tryProcessEntriesOfTypeInRecords(QSpan< const QOhosUdmfRecord > records, const QOhosConsumer< QOhosUdsObject< T > > &processEntryFunc)
void addMimeDataSuppliersForGeneralEntriesFromRecords(std::shared_ptr< void > context, QSpan< const QOhosUdmfRecord > inputRecords, std::map< QString, QOhosSupplier< QVariant > > &outMimeDataSuppliers)
void addGeneralEntryToRecord(std::string mimeType, QSpan< const std::uint8_t > dataBytes, QOhosUdmfRecord &record)
std::unique_ptr<::OH_UdsArrayBuffer, void(*)(::OH_UdsArrayBuffer *)> createUdsArrayBuffer()
std::function< QOhosUdmfRecord()> tryMakeDefaultUdmfRecordFactoryFromQMimeDataOrNull(const QMimeData &mimeData, std::shared_ptr< QMimeData > optLazyProcessingMimeData)
void addUrlEntryToUdmfRecord(const QUrl &url, QOhosUdmfRecord &outRecord)
bool hasMatchingTypeEntryInRecords(QSpan< const QOhosUdmfRecord > records)
std::shared_ptr<::OH_Utd > utdCreateOrNull(const std::string &typeId)
bool isUdmfMetaFileType(const std::string &type)
QOhosOptional< T > tryEvalInQtThreadWithConsumer(std::function< void(QOhosConsumer< T >)> qtEvalFunc, ch::nanoseconds timeout)
std::string const char * mapBoolToTrueFalseStr(bool value)
std::nullopt_t makeEmptyQOhosOptional()
QT_BEGIN_NAMESPACE std::function< QOhosUdmfData()> makeUdmfDataFactoryFromQMimeData(const QMimeData &mimeData, const QOhosOptional< bool > &shareInAppOnly)
bool isQOhosUdmfDataConvertedFromThisProcessMimeData(QOhosUdmfData &udmfData)
QOhosOptional< std::string > tryMapUtdTypeIdToMimeType(const std::string &utdTypeId)
std::function< QOhosUdmfData()> makeLazyProcessingUdmfDataFactoryFromQMimeData(std::shared_ptr< QMimeData > mimeData, const QOhosOptional< bool > &shareInAppOnly)
QOhosOptional< std::string > tryMapMimeTypeToUtdTypeId(const std::string &mimeType)
QOhosSupplier< std::unique_ptr< QMimeData > > makeLazyFetchingQMimeDataFactoryFromUdmfData(QOhosUdmfData udmfData)
QOhosSupplier< std::unique_ptr< QMimeData > > createQMimeDataFactoryFromUdmfData(QOhosUdmfData udmfData)
QOhosSupplier< std::unique_ptr< QMimeData > > makeDummyQMimeDataFactoryFromUdmfDataTypes(std::vector< std::string > udmfDataTypes)
QOhosSupplier< QOhosOptional< std::string > > optUdmfMetaIdFactory
std::function< UdmfRecordEntryFactory(const QMimeData &)> metaFactoryFunc