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<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
123bool hasQMimeDataPeerType(const char *type)
124{
125 static constexpr const char *udmfTypesWithQMimeDataPeerTypes[] = {
126 QOhosUdsMeta<::OH_UdsFileUri>::udmfMetaId,
127 QOhosUdsMeta<::OH_UdsHyperlink>::udmfMetaId,
128 QOhosUdsMeta<::OH_UdsHtml>::udmfMetaId,
129 QOhosUdsMeta<::OH_UdsPixelMap>::udmfMetaId,
130 QOhosUdsMeta<::OH_UdsPlainText>::udmfMetaId,
131 };
132
133 return std::any_of(
134 std::begin(udmfTypesWithQMimeDataPeerTypes),
135 std::end(udmfTypesWithQMimeDataPeerTypes),
136 [&](const char *specificMetaType) {
137 return std::strcmp(type, specificMetaType) == 0;
138 });
139}
140
141bool isUdmfMetaFileType(const std::string &type)
142{
143 static constexpr const char *udmfMetaFileTypes[] = {
144 UDMF_META_GENERAL_FILE,
145 UDMF_META_AUDIO,
146 UDMF_META_FOLDER,
147 UDMF_META_IMAGE,
148 UDMF_META_VIDEO,
149 };
150
151 return std::any_of(
152 std::begin(udmfMetaFileTypes),
153 std::end(udmfMetaFileTypes),
154 [&](const char *specificMetaType) {
155 return type == specificMetaType;
156 });
157}
158
159std::vector<std::string> utdGetTypesByMimeType(const std::string &mimeType)
160{
161 unsigned int typesCount = 0;
162 auto func = Q_OHOS_NAMED_FUNC(::OH_Utd_GetTypesByMimeType);
163 const char **utdTypeIds = QArkUi::callArkUi(func, QArkUi::CZString(mimeType.c_str()), &typesCount);
164 if (utdTypeIds == nullptr && typesCount != 0) {
165 qOhosReportFatalErrorAndAbort(
166 "%s: got inconsistent result from %s() call: array is null, size is %u",
167 Q_FUNC_INFO, func.name(), typesCount);
168 }
169
170 auto result = utdTypeIds != nullptr
171 ? std::vector<std::string>(utdTypeIds, utdTypeIds + typesCount)
172 : std::vector<std::string>();
173
174 QArkUi::callArkUi(
175 Q_OHOS_NAMED_FUNC(::OH_Utd_DestroyStringList), utdTypeIds, typesCount);
176
177 return result;
178}
179
180std::shared_ptr<::OH_Utd> utdCreateOrNull(const std::string &typeId)
181{
182 return {
183 QArkUi::callArkUi(
184 Q_OHOS_NAMED_FUNC(::OH_Utd_Create),
185 QArkUi::CZString(typeId.c_str())),
186 [](::OH_Utd *utd) {
187 if (utd != nullptr)
188 QArkUi::callArkUi(Q_OHOS_NAMED_FUNC(::OH_Utd_Destroy), utd);
189 }
190 };
191}
192
194{
195 unsigned int typesCount = 0;
196 auto func = Q_OHOS_NAMED_FUNC(::OH_Utd_GetMimeTypes);
197 const char **mimeTypes = QArkUi::callArkUi(func, utd, &typesCount);
198 if (mimeTypes == nullptr && typesCount != 0) {
199 qOhosReportFatalErrorAndAbort(
200 "%s: got inconsistent result from %s() call: array is null, size is %u",
201 Q_FUNC_INFO, func.name(), typesCount);
202 }
203
204 auto result = mimeTypes != nullptr
205 ? std::vector<std::string>(mimeTypes, mimeTypes + typesCount)
206 : std::vector<std::string>();
207
208 return result;
209}
210
211template<typename T>
212bool hasMatchingTypeEntryInRecords(QSpan<QOhosUdmfRecord> records)
213{
214 static const auto searchTypeId = QOhosUdsMeta<T>::udmfMetaId;
215 return std::any_of(
216 records.begin(), records.end(),
217 [&](auto &record) {
218 auto recordTypes = record.getTypes();
219 return std::find(recordTypes.begin(), recordTypes.end(), searchTypeId) != recordTypes.end();
220 });
221}
222
223template<typename T>
225 QSpan<QOhosUdmfRecord> records,
226 const QOhosConsumer<QOhosUdsObject<T>> &processEntryFunc)
227{
228 for (auto &record : records) {
229 for (auto &typeId : record.getTypes()) {
230 if (QOhosUdsMeta<T>::udmfMetaId == typeId)
231 processEntryFunc(record.getEntry<T>());
232 }
233 }
234}
235
237 std::shared_ptr<void> context, QSpan<QOhosUdmfRecord> inputRecords,
239{
240 if (!hasMatchingTypeEntryInRecords<::OH_UdsFileUri>(inputRecords)
241 && !hasMatchingTypeEntryInRecords<::OH_UdsHyperlink>(inputRecords)) {
242 return;
243 }
244
245 outMimeDataSuppliers.emplace(
246 QString::fromUtf8(mimeTextUriList),
247 [context, inputRecords]() {
248 QList<QUrl> urls;
249 tryProcessEntriesOfTypeInRecords<::OH_UdsFileUri>(
250 inputRecords,
251 [&](auto udsEntry) {
252 urls.append(
253 {
254 QUrl::fromLocalFile(
255 QString::fromStdString(
256 QOhosPlatformServices::mapOhosFileUriToPathInJsThread(
257 udsEntry.getContent()))),
258 });
259 });
260 tryProcessEntriesOfTypeInRecords<::OH_UdsHyperlink>(
261 inputRecords,
262 [&](auto udsEntry) {
263 urls.append(QUrl(QString::fromStdString(udsEntry.getContent())));
264 });
265
266 QList<QVariant> urlsVariants;
267 for (const auto &url : urls)
268 urlsVariants.append(url);
269
270 return QVariant(urlsVariants);
271 });
272}
273
275 std::shared_ptr<void> context, QSpan<QOhosUdmfRecord> inputRecords,
277{
278 for (auto &record : inputRecords) {
279 for (auto &typeId : record.getTypes()) {
280 if (!hasQMimeDataPeerType(typeId.c_str()) && !isUdmfMetaFileType(typeId)) {
281 // FIXME: the `utdGetMimeTypes()` result interpretation is not quite
282 // clear. Documentaion does not mention why there is a list of possible mime types.
283 // Are they ordered in a specific manear? Is it possible to get en ampty list?
284 // Improve and fix the code when these are known.
285 auto optUtdWithTypeId = utdCreateOrNull(typeId);
286 auto mimeTypes = optUtdWithTypeId
287 ? utdGetMimeTypes(optUtdWithTypeId.get())
288 : std::vector<std::string>();
289 if (!mimeTypes.empty()) {
290 outMimeDataSuppliers.emplace(
291 QString::fromStdString(mimeTypes.front()),
292 [context, recordPtr = &record, typeId]() {
293 auto generalEntry = recordPtr->tryGetGeneralEntry(typeId);
294 if (!generalEntry.hasValue())
295 return QVariant();
296
297 return QVariant(
298 QByteArray(
299 reinterpret_cast<char *>(generalEntry.value().data()),
300 generalEntry.value().size()));
301 });
302 } else {
303 qOhosPrintfWarning(
304 "%s: cannot convert UTD type id '%s' to mime type. Skip this entry.",
305 Q_FUNC_INFO, typeId.c_str());
306 }
307 }
308 }
309 }
310}
311
312std::map<QString, QOhosSupplier<QVariant>> makeMimeDataSuppliersMapFromUdmfData(QOhosUdmfData udmfData)
313{
314 struct Context
315 {
316 QOhosUdmfData udmfData;
317 std::vector<QOhosUdmfRecord> records;
318 };
319
320 auto context = QtOhos::makeProxyWithJsThreadDeleter(std::make_shared<Context>());
321 context->udmfData = std::move(udmfData);
322 context->records = context->udmfData.getRecords();
323
324 if (context->records.size() == 0)
325 return {};
326
327 std::map<QString, QOhosSupplier<QVariant>> mimeDataSuppliers;
328
329 auto firstRecordSpan = QSpan(context->records.data(), 1);
330
331 if (hasMatchingTypeEntryInRecords<::OH_UdsPlainText>(firstRecordSpan)) {
332 mimeDataSuppliers.emplace(
333 QString::fromUtf8(mimeTextPlain),
334 [context]() {
335 QVariant value;
336 tryProcessEntriesOfTypeInRecords<::OH_UdsPlainText>(
337 QSpan(context->records.data(), 1),
338 [&](auto udsEntry) {
339 value = QString::fromUtf8(udsEntry.getContent(), -1);
340 });
341 return value;
342 });
343 }
344
345 if (hasMatchingTypeEntryInRecords<::OH_UdsHtml>(firstRecordSpan)) {
346 mimeDataSuppliers.emplace(
347 QString::fromUtf8(mimeTextHtml),
348 [context]() {
349 QVariant value;
350 tryProcessEntriesOfTypeInRecords<::OH_UdsHtml>(
351 QSpan(context->records.data(), 1),
352 [&](auto udsEntry) {
353 value = QString::fromUtf8(udsEntry.getContent(), -1);
354 });
355 return value;
356 });
357 }
358
359 if (hasMatchingTypeEntryInRecords<::OH_UdsPixelMap>(firstRecordSpan)) {
360 mimeDataSuppliers.emplace(
361 QString::fromUtf8(mimeAppXQtImage),
362 [context]() {
363 QVariant value;
364 tryProcessEntriesOfTypeInRecords<::OH_UdsPixelMap>(
365 QSpan(context->records.data(), 1),
366 [&](auto udsEntry) {
367 value = createQImageFromNativePixelMap(udsEntry.getContent().get());
368 });
369 return value;
370 });
371 }
372
373 addMimeDataSuppliersForUrlLikeEntriesFromRecords(
374 context, QSpan(context->records.data(), context->records.size()), mimeDataSuppliers);
375
376 addMimeDataSuppliersForGeneralEntriesFromRecords(context, firstRecordSpan, mimeDataSuppliers);
377
378 return mimeDataSuppliers;
379}
380
382{
383 return url.isLocalFile()
384 ? UdmfRecordEntryFactory::makeForUdsObjectFactory<::OH_UdsFileUri>(
385 [url]() {
386 return QOhosUdsObject<::OH_UdsFileUri>(
387 QOhosPlatformServices::mapPathToOhosUriInJsThread(
388 url.toLocalFile().toStdString()).c_str());
389 })
390 : UdmfRecordEntryFactory::makeForUdsObjectFactory<::OH_UdsHyperlink>(
391 [url]() {
392 return QOhosUdsObject<::OH_UdsHyperlink>(
393 url.toString().toStdString().c_str());
394 });
395}
396
397void addUrlEntryToUdmfRecord(const QUrl &url, QOhosUdmfRecord &outRecord)
398{
399 makeUdmfRecordEntryFactoryForUrl(url).addEntryToRecord(outRecord);
400}
401
403{
404 return {
405 QArkUi::callArkUiOrFailOnNullResult(
406 Q_OHOS_NAMED_FUNC(::OH_UdmfProperty_Create),
407 udmfData),
408 [](::OH_UdmfProperty *udmfProperty) {
409 QArkUi::callArkUi(
410 Q_OHOS_NAMED_FUNC(::OH_UdmfProperty_Destroy),
411 udmfProperty);
412 }
413 };
414}
415
416void addGeneralEntryToRecord(std::string mimeType, QSpan<std::uint8_t> dataBytes, QOhosUdmfRecord &record)
417{
418 if (dataBytes.size() == 0) {
419 qOhosPrintfWarning(
420 "%s: got empty data for type '%s', which is not supported by UDMF record, skipping this entry",
421 Q_FUNC_INFO, mimeType.c_str());
422 return;
423 }
424
425 auto optUtdTypeId = tryMapMimeTypeToUtdTypeId(mimeType);
426 if (optUtdTypeId.hasValue()) {
427 record.addGeneralEntry(optUtdTypeId.value(), dataBytes.data(), dataBytes.size());
428 } else {
429 qOhosPrintfWarning(
430 "%s: cannot convert mime type '%s' to type id. Skip this entry.",
431 Q_FUNC_INFO, mimeType.c_str());
432 }
433}
434
435template<typename RawUdsObject>
436UdmfRecordEntryFactory UdmfRecordEntryFactory::makeForUdsObjectFactory(
437 QOhosSupplier<QOhosUdsObject<RawUdsObject>> udsObjectFactory)
438{
439 auto sharedUdsObjectFactory = QtOhos::moveToSharedPtr(std::move(udsObjectFactory));
440 return UdmfRecordEntryFactory(
441 [sharedUdsObjectFactory]() {
442 void *data = (*sharedUdsObjectFactory)().release();
443 qOhosPrintfWarning(
444 "%s: generated '%s' data for OH_UdmfRecordProvider: %p",
445 Q_FUNC_INFO, QOhosUdsMeta<RawUdsObject>::udmfMetaId, data);
446 return data;
447 },
448 [sharedUdsObjectFactory](QOhosUdmfRecord &record) {
449 record.addEntry((*sharedUdsObjectFactory)());
450 });
451}
452
453UdmfRecordEntryFactory UdmfRecordEntryFactory::makeForGeneralDataWithMimeType(
454 std::string mimeType, QOhosSupplier<QSpan<std::uint8_t>> dataSupplier)
455{
456 return UdmfRecordEntryFactory(
457 []() {
458 return nullptr;
459 },
460 [mimeType, dataSupplier = std::move(dataSupplier)](QOhosUdmfRecord &record) {
461 addGeneralEntryToRecord(mimeType, dataSupplier(), record);
462 });
463}
464
466{
467 return UdmfRecordEntryFactory(
468 []() {
469 return nullptr;
470 },
471 [](QOhosUdmfRecord &) {
472 });
473}
474
475UdmfRecordEntryFactory::UdmfRecordEntryFactory(
476 QOhosSupplier<void *> recordProviderDataFactory,
477 std::function<void(QOhosUdmfRecord &)> recordAddEntryFunc)
478 : m_recordProviderDataFactory(std::move(recordProviderDataFactory))
479 , m_recordAddEntryFunc(std::move(recordAddEntryFunc))
480{
481}
482
484{
485 m_recordAddEntryFunc(udmfRecord);
486}
487
489{
490 return m_recordProviderDataFactory();
491}
492
494{
495 std::vector<UdmfRecordEntryMetaFactory> recordEntryMetaFactories;
496 for (auto qStrFormat : mimeDataFormats) {
497 auto format = qStrFormat.toStdString();
498 if (format == mimeTextPlain) {
499 recordEntryMetaFactories.emplace_back(
500 UdmfRecordEntryMetaFactory{
501 makeQOhosOptional<std::string>(QOhosUdsMeta<::OH_UdsPlainText>::udmfMetaId),
502 [](const QMimeData &mimeData) {
503 auto dataText = mimeData.text();
504 return UdmfRecordEntryFactory::makeForUdsObjectFactory<::OH_UdsPlainText>(
505 [dataText]() {
506 return QOhosUdsObject<::OH_UdsPlainText>(dataText.toStdString().c_str());
507 });
508 }
509 });
510 } else if (format == mimeTextHtml) {
511 recordEntryMetaFactories.emplace_back(
512 UdmfRecordEntryMetaFactory{
513 makeQOhosOptional<std::string>(QOhosUdsMeta<::OH_UdsHtml>::udmfMetaId),
514 [](const QMimeData &mimeData) {
515 auto dataHtml = mimeData.html();
516 return UdmfRecordEntryFactory::makeForUdsObjectFactory<::OH_UdsHtml>(
517 [dataHtml]() {
518 return QOhosUdsObject<::OH_UdsHtml>(dataHtml.toStdString().c_str());
519 });
520 }
521 });
522 } else if (format == mimeTextUriList) {
523 recordEntryMetaFactories.emplace_back(
524 UdmfRecordEntryMetaFactory{
525 makeEmptyQOhosOptional(),
526 [](const QMimeData &mimeData) {
527 auto dataUrls = mimeData.urls();
528 return !dataUrls.isEmpty()
529 ? makeUdmfRecordEntryFactoryForUrl(dataUrls.first())
530 : UdmfRecordEntryFactory::makeDummy();
531 }
532 });
533 } else if (format == mimeAppXQtImage) {
534 recordEntryMetaFactories.emplace_back(
535 UdmfRecordEntryMetaFactory{
536 makeQOhosOptional<std::string>(QOhosUdsMeta<::OH_UdsPixelMap>::udmfMetaId),
537 [](const QMimeData &mimeData) {
538 auto dataImage = qvariant_cast<QImage>(mimeData.imageData());
539 return UdmfRecordEntryFactory::makeForUdsObjectFactory<::OH_UdsPixelMap>(
540 [dataImage]() {
541 return QOhosUdsObject<::OH_UdsPixelMap>(createNativePixelMapFromQImage(dataImage));
542 });
543 }
544 });
545 } else {
546 recordEntryMetaFactories.emplace_back(
547 UdmfRecordEntryMetaFactory{
548 makeEmptyQOhosOptional(),
549 [qStrFormat](const QMimeData &mimeData) {
550 auto dataBytes = mimeData.data(qStrFormat);
551 return UdmfRecordEntryFactory::makeForGeneralDataWithMimeType(
552 qStrFormat.toStdString(),
553 [dataBytes]() {
554 return QSpan(
555 reinterpret_cast<std::uint8_t *>(const_cast<char *>(dataBytes.data())),
556 dataBytes.length());
557 });
558 }
559 });
560 }
561 }
562
563 return recordEntryMetaFactories;
564}
565
567 const QMimeData &mimeData, std::shared_ptr<QMimeData> optLazyProcessingMimeData)
568{
569 auto recordEntryMetaFactories = makeRecordEntryMetaFactoriesForMimeDataFormats(mimeData.formats());
570 if (recordEntryMetaFactories.empty())
571 return nullptr;
572
573 struct Context
574 {
575 std::vector<UdmfRecordEntryFactory> directEntryFactories;
576 std::map<std::string, std::function<UdmfRecordEntryFactory(const QMimeData &)>> entryMetaFactoryFuncsForProvider;
577 };
578
579 auto context = std::make_shared<Context>();
580
581 const bool useRecordProvider = optLazyProcessingMimeData != nullptr;
582
583 for (auto &recordEntryFactoryEntry : recordEntryMetaFactories) {
584 if (recordEntryFactoryEntry.udmfMetaId.hasValue() && useRecordProvider) {
585 context->entryMetaFactoryFuncsForProvider.emplace(
586 recordEntryFactoryEntry.udmfMetaId.value(),
587 std::move(recordEntryFactoryEntry.metaFactoryFunc));
588 } else {
589 context->directEntryFactories.push_back(
590 recordEntryFactoryEntry.metaFactoryFunc(mimeData));
591 }
592 }
593
594 return [context, optLazyProcessingMimeData]() {
595 QOhosUdmfRecord record;
596 for (const auto &directEntryFactory : context->directEntryFactories)
597 directEntryFactory.addEntryToRecord(record);
598 if (!context->entryMetaFactoryFuncsForProvider.empty()) {
599 auto lazyProcessingMimeData = optLazyProcessingMimeData;
600 record.setProviderForDataFetchFunc(
601 getMapKeys(context->entryMetaFactoryFuncsForProvider),
602 [context, lazyProcessingMimeData](const char *type) {
603 qOhosPrintfDebug("%s: got request for data '%s'", Q_FUNC_INFO, type);
604
605 auto typeStr = std::string(type);
606 auto optUdmfRecordEntryFactory = tryEvalInQtThreadWithConsumer<UdmfRecordEntryFactory>(
607 [context, lazyProcessingMimeData, typeStr](QOhosConsumer<UdmfRecordEntryFactory> resultConsumer) {
608 qOhosPrintfDebug("%s: processing request for data '%s' in Qt thread", Q_FUNC_INFO, typeStr.c_str());
609 auto entryMetaFactoryFuncIter = context->entryMetaFactoryFuncsForProvider.find(typeStr);
610 resultConsumer(
611 entryMetaFactoryFuncIter != context->entryMetaFactoryFuncsForProvider.end()
612 ? entryMetaFactoryFuncIter->second(*lazyProcessingMimeData)
614 qOhosPrintfDebug("%s: finished processing in Qt thread", Q_FUNC_INFO);
615 },
616 processQMimeDataInQtThreadTimeout);
617 qOhosPrintfDebug(
618 "%s: got result from Qt thread: %s",
619 Q_FUNC_INFO, QtOhos::mapBoolToTrueFalseStr(optUdmfRecordEntryFactory.hasValue()));
620
621 void *providerResult = optUdmfRecordEntryFactory.hasValue()
622 ? optUdmfRecordEntryFactory.value().makeRecordProviderDataForEntry()
623 : nullptr;
624 qOhosPrintfDebug("%s: provider result: %p", Q_FUNC_INFO, providerResult);
625
626 return providerResult;
627 });
628 }
629 return record;
630 };
631}
632
634 const QMimeData &mimeData, const QOhosOptional<bool> &shareInAppOnly,
635 std::shared_ptr<QMimeData> optLazyProcessingMimeData = nullptr)
636{
637 std::vector<std::function<QOhosUdmfRecord()>> recordFactories;
638
639 auto optDefaultRecordFactory = tryMakeDefaultUdmfRecordFactoryFromQMimeDataOrNull(
640 mimeData, optLazyProcessingMimeData);
641 if (optDefaultRecordFactory)
642 recordFactories.push_back(std::move(optDefaultRecordFactory));
643
644 if (mimeData.hasUrls()) {
645 auto urls = mimeData.urls();
646 for (int i = 1; i < urls.size(); ++i) {
647 auto dataUrl = urls.at(i);
648 recordFactories.emplace_back(
649 [dataUrl]() {
650 QOhosUdmfRecord record;
651 addUrlEntryToUdmfRecord(dataUrl, record);
652 return record;
653 });
654 }
655 }
656
657 recordFactories.emplace_back(
658 []() {
659 QOhosUdmfRecord record;
660 auto appInfoDataBytes = getAppInfoDataForThisProcess();
661 addGeneralEntryToRecord(
662 qtAppInfoDataPseudoMimeType, QSpan(&appInfoDataBytes[0], appInfoDataBytes.size()), record);
663 return record;
664 });
665
666 return [shareInAppOnly, recordFactories = std::move(recordFactories)]() {
667 QOhosUdmfData udmfData;
668
669 if (shareInAppOnly.hasValue()) {
670 auto udmfShareProperty = createUdmfPropertyForUdmfData(udmfData.nativePtr());
671 QArkUi::callArkUiOrFailOnErrorResult(
672 Q_OHOS_NAMED_FUNC(::OH_UdmfProperty_SetShareOption),
673 udmfShareProperty.get(),
674 shareInAppOnly.value()
675 ? ::Udmf_ShareOption::SHARE_OPTIONS_IN_APP
676 : ::Udmf_ShareOption::SHARE_OPTIONS_CROSS_APP);
677 }
678
679 for (const auto &recordFactory : recordFactories)
680 udmfData.addRecord(recordFactory());
681
682 return udmfData;
683 };
684}
685
686}
687
689 const QMimeData &mimeData, const QOhosOptional<bool> &shareInAppOnly)
690{
691 return makeUdmfDataFactoryFromQMimeDataImpl(mimeData, shareInAppOnly, nullptr);
692}
693
695 std::shared_ptr<QMimeData> mimeData, const QOhosOptional<bool> &shareInAppOnly)
696{
697 return makeUdmfDataFactoryFromQMimeDataImpl(*mimeData, shareInAppOnly, mimeData);
698}
699
701{
702 std::map<QString, QVariant> mimeDataMap;
703 for (auto &supplierEntry : makeMimeDataSuppliersMapFromUdmfData(std::move(udmfData)))
704 mimeDataMap.emplace(supplierEntry.first, supplierEntry.second());
705
706 return makeQOhosMimeDataFactory(std::move(mimeDataMap));
707}
708
710{
711 std::map<QString, QOhosSupplier<QVariant>> threadSafeSuppliers;
712 for (auto &supplierEntry : makeMimeDataSuppliersMapFromUdmfData(std::move(udmfData))) {
713 threadSafeSuppliers.emplace(
714 supplierEntry.first,
715 [mimeType = supplierEntry.first.toStdString(), baseSupplier = std::move(supplierEntry.second)]() {
716 qOhosPrintfDebug("%s: fetching data for MIME type '%s'", Q_FUNC_INFO, mimeType.c_str());
717 return QtOhos::evalInJsThread(
718 [&](QtOhos::JsState &) {
719 return baseSupplier();
720 });
721 });
722 }
723
724 return makeQOhosLazyFetchMimeDataFactory(std::move(threadSafeSuppliers));
725}
726
728 std::vector<std::string> udmfDataTypes)
729{
730 return [udmfDataTypes = std::move(udmfDataTypes)]() {
731 const auto dummyText = QString::fromUtf8(
732 "OHOS QPA: Drag data is not available before DROP. This is a system limitation.");
733
734 auto mimeData = std::make_unique<QMimeData>();
735
736 for (const auto &type : udmfDataTypes) {
737 if (type == QOhosUdsMeta<::OH_UdsPlainText>::udmfMetaId) {
738 mimeData->setText(dummyText);
739 } else if (type == QOhosUdsMeta<::OH_UdsHtml>::udmfMetaId) {
740 mimeData->setHtml(dummyText);
741 } else if (type == QOhosUdsMeta<::OH_UdsPixelMap>::udmfMetaId) {
742 mimeData->setImageData(QImage(1, 1, QImage::Format::Format_RGBA8888));
743 } else if (type == QOhosUdsMeta<::OH_UdsFileUri>::udmfMetaId || isUdmfMetaFileType(type)) {
744 mimeData->setUrls({});
745 }
746 }
747
748 if (mimeData->formats().isEmpty())
749 mimeData->setText(dummyText);
750
751 return mimeData;
752 };
753}
754
756{
757 auto qtAppInfoDataUtdTypeId = tryMapMimeTypeToUtdTypeId(qtAppInfoDataPseudoMimeType);
758 if (!qtAppInfoDataUtdTypeId.hasValue()) {
759 qOhosPrintfError("%s: Can't map %s to UTD type id", Q_FUNC_INFO, qtAppInfoDataPseudoMimeType);
760 return false;
761 }
762
763 auto udmfRecords = udmfData.getRecords();
764 auto thisProcessAppInfoData = getAppInfoDataForThisProcess();
765
766 return std::any_of(
767 udmfRecords.begin(), udmfRecords.end(),
768 [&](auto &udmfRecord) {
769 auto optAppInfoData = udmfRecord.tryGetGeneralEntry(qtAppInfoDataUtdTypeId.value());
770 if (!optAppInfoData.hasValue())
771 return false;
772
773 auto appInfoData = optAppInfoData.value();
774
775 return
776 static_cast<std::size_t>(appInfoData.size()) == thisProcessAppInfoData.size()
777 && std::memcmp(appInfoData.data(), thisProcessAppInfoData.data(), appInfoData.size()) == 0;
778 });
779}
780
781QOhosOptional<std::string> tryMapUtdTypeIdToMimeType(const std::string &utdTypeId)
782{
783 auto optUtdWithTypeId = utdCreateOrNull(utdTypeId);
784 auto mimeTypes = optUtdWithTypeId
785 ? utdGetMimeTypes(optUtdWithTypeId.get())
786 : std::vector<std::string>();
787
788 return !mimeTypes.empty()
789 ? makeQOhosOptional(mimeTypes.front())
791}
792
793QOhosOptional<std::string> tryMapMimeTypeToUtdTypeId(const std::string &mimeType)
794{
795 // FIXME: the `utdGetTypesByMimeType()` result interpretation is not quite clear.
796 // Documentaion does not mention why there is a list of possible type ids.
797 // Are they ordered in a specific manear? Is it possible to get en ampty list?
798 // Improve and fix the code when these are known.
799 auto utdTypeIds = utdGetTypesByMimeType(mimeType);
800 return
801 !utdTypeIds.empty()
802 ? makeQOhosOptional(utdTypeIds.front())
804}
805
806QT_END_NAMESPACE
std::enable_if_t< qohosplugincore_h_detail::isQOhosOptional< QOhosInvokeResult< Func, T > >, QOhosInvokeResult< Func, T > > andThen(Func &&func) const
void addGeneralEntry(const std::string &typeId, std::uint8_t *buff, std::uint32_t buffSize)
void addEntryToRecord(QOhosUdmfRecord &udmfRecord) const
static UdmfRecordEntryFactory makeForGeneralDataWithMimeType(std::string mimeType, QOhosSupplier< QSpan< 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)
void addMimeDataSuppliersForUrlLikeEntriesFromRecords(std::shared_ptr< void > context, QSpan< QOhosUdmfRecord > inputRecords, std::map< QString, QOhosSupplier< QVariant > > &outMimeDataSuppliers)
std::vector< std::string > utdGetMimeTypes(::OH_Utd *utd)
bool hasQMimeDataPeerType(const char *type)
constexpr auto processQMimeDataInQtThreadTimeout
std::shared_ptr<::OH_UdmfProperty > createUdmfPropertyForUdmfData(::OH_UdmfData *udmfData)
bool hasMatchingTypeEntryInRecords(QSpan< QOhosUdmfRecord > records)
std::vector< UdmfRecordEntryMetaFactory > makeRecordEntryMetaFactoriesForMimeDataFormats(QStringList mimeDataFormats)
std::function< QOhosUdmfRecord()> tryMakeDefaultUdmfRecordFactoryFromQMimeDataOrNull(const QMimeData &mimeData, std::shared_ptr< QMimeData > optLazyProcessingMimeData)
void addUrlEntryToUdmfRecord(const QUrl &url, QOhosUdmfRecord &outRecord)
std::shared_ptr<::OH_Utd > utdCreateOrNull(const std::string &typeId)
void addMimeDataSuppliersForGeneralEntriesFromRecords(std::shared_ptr< void > context, QSpan< QOhosUdmfRecord > inputRecords, std::map< QString, QOhosSupplier< QVariant > > &outMimeDataSuppliers)
void addGeneralEntryToRecord(std::string mimeType, QSpan< std::uint8_t > dataBytes, QOhosUdmfRecord &record)
bool isUdmfMetaFileType(const std::string &type)
QOhosOptional< T > tryEvalInQtThreadWithConsumer(std::function< void(QOhosConsumer< T >)> qtEvalFunc, ch::nanoseconds timeout)
void tryProcessEntriesOfTypeInRecords(QSpan< QOhosUdmfRecord > records, const QOhosConsumer< QOhosUdsObject< T > > &processEntryFunc)
std::string const char * mapBoolToTrueFalseStr(bool value)
QOhosOptional< void > 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)
std::function< UdmfRecordEntryFactory(const QMimeData &)> metaFactoryFunc