1// Copyright (C) 2018 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 "qinternalmimedata_p.h"
5
6#include <QtCore/qbuffer.h>
7#include <QtGui/qimage.h>
8#include <QtGui/qimagereader.h>
9#include <QtGui/qimagewriter.h>
10
11QT_BEGIN_NAMESPACE
12
13using namespace Qt::StringLiterals;
14
15static QStringList imageMimeFormats(const QList<QByteArray> &imageFormats)
16{
17 QStringList formats;
18 formats.reserve(asize: imageFormats.size());
19 for (const auto &format : imageFormats)
20 formats.append(t: "image/"_L1 + QLatin1StringView(format.toLower()));
21
22 //put png at the front because it is best
23 const qsizetype pngIndex = formats.indexOf(t: "image/png"_L1);
24 if (pngIndex != -1 && pngIndex != 0)
25 formats.move(from: pngIndex, to: 0);
26
27 return formats;
28}
29
30static inline QStringList imageReadMimeFormats()
31{
32 return imageMimeFormats(imageFormats: QImageReader::supportedImageFormats());
33}
34
35static inline QStringList imageWriteMimeFormats()
36{
37 return imageMimeFormats(imageFormats: QImageWriter::supportedImageFormats());
38}
39
40QInternalMimeData::QInternalMimeData()
41 : QMimeData()
42{
43}
44
45QInternalMimeData::~QInternalMimeData()
46{
47}
48
49bool QInternalMimeData::hasFormat(const QString &mimeType) const
50{
51 bool foundFormat = hasFormat_sys(mimeType);
52 if (!foundFormat && mimeType == "application/x-qt-image"_L1) {
53 QStringList imageFormats = imageReadMimeFormats();
54 for (int i = 0; i < imageFormats.size(); ++i) {
55 if ((foundFormat = hasFormat_sys(mimeType: imageFormats.at(i))))
56 break;
57 }
58 }
59 return foundFormat;
60}
61
62QStringList QInternalMimeData::formats() const
63{
64 QStringList realFormats = formats_sys();
65 if (!realFormats.contains(str: "application/x-qt-image"_L1)) {
66 QStringList imageFormats = imageReadMimeFormats();
67 for (int i = 0; i < imageFormats.size(); ++i) {
68 if (realFormats.contains(str: imageFormats.at(i))) {
69 realFormats += "application/x-qt-image"_L1;
70 break;
71 }
72 }
73 }
74 return realFormats;
75}
76
77QVariant QInternalMimeData::retrieveData(const QString &mimeType, QMetaType type) const
78{
79 QVariant data = retrieveData_sys(mimeType, type);
80 if (mimeType == "application/x-qt-image"_L1) {
81 if (data.isNull() || (data.metaType().id() == QMetaType::QByteArray && data.toByteArray().isEmpty())) {
82 // try to find an image
83 QStringList imageFormats = imageReadMimeFormats();
84 for (int i = 0; i < imageFormats.size(); ++i) {
85 data = retrieveData_sys(mimeType: imageFormats.at(i), type);
86 if (data.isNull() || (data.metaType().id() == QMetaType::QByteArray && data.toByteArray().isEmpty()))
87 continue;
88 break;
89 }
90 }
91 int typeId = type.id();
92 // we wanted some image type, but all we got was a byte array. Convert it to an image.
93 if (data.metaType().id() == QMetaType::QByteArray
94 && (typeId == QMetaType::QImage || typeId == QMetaType::QPixmap || typeId == QMetaType::QBitmap))
95 data = QImage::fromData(data: data.toByteArray());
96
97 } else if (mimeType == "application/x-color"_L1 && data.metaType().id() == QMetaType::QByteArray) {
98 QColor c;
99 QByteArray ba = data.toByteArray();
100 if (ba.size() == 8) {
101 ushort * colBuf = (ushort *)ba.data();
102 c.setRgbF(r: qreal(colBuf[0]) / qreal(0xFFFF),
103 g: qreal(colBuf[1]) / qreal(0xFFFF),
104 b: qreal(colBuf[2]) / qreal(0xFFFF),
105 a: qreal(colBuf[3]) / qreal(0xFFFF));
106 data = c;
107 } else {
108 qWarning(msg: "Qt: Invalid color format");
109 }
110 } else if (data.metaType() != type && data.metaType().id() == QMetaType::QByteArray) {
111 // try to use mime data's internal conversion stuf.
112 QInternalMimeData *that = const_cast<QInternalMimeData *>(this);
113 that->setData(mimetype: mimeType, data: data.toByteArray());
114 data = QMimeData::retrieveData(mimetype: mimeType, preferredType: type);
115 that->clear();
116 }
117 return data;
118}
119
120bool QInternalMimeData::canReadData(const QString &mimeType)
121{
122 return imageReadMimeFormats().contains(str: mimeType);
123}
124
125// helper functions for rendering mimedata to the system, this is needed because QMimeData is in core.
126QStringList QInternalMimeData::formatsHelper(const QMimeData *data)
127{
128 QStringList realFormats = data->formats();
129 if (realFormats.contains(str: "application/x-qt-image"_L1)) {
130 // add all supported image formats
131 QStringList imageFormats = imageWriteMimeFormats();
132 for (int i = 0; i < imageFormats.size(); ++i) {
133 if (!realFormats.contains(str: imageFormats.at(i)))
134 realFormats.append(t: imageFormats.at(i));
135 }
136 }
137 return realFormats;
138}
139
140bool QInternalMimeData::hasFormatHelper(const QString &mimeType, const QMimeData *data)
141{
142
143 bool foundFormat = data->hasFormat(mimetype: mimeType);
144 if (!foundFormat) {
145 if (mimeType == "application/x-qt-image"_L1) {
146 // check all supported image formats
147 QStringList imageFormats = imageWriteMimeFormats();
148 for (int i = 0; i < imageFormats.size(); ++i) {
149 if ((foundFormat = data->hasFormat(mimetype: imageFormats.at(i))))
150 break;
151 }
152 } else if (mimeType.startsWith(s: "image/"_L1)) {
153 return data->hasImage() && imageWriteMimeFormats().contains(str: mimeType);
154 }
155 }
156 return foundFormat;
157}
158
159QByteArray QInternalMimeData::renderDataHelper(const QString &mimeType, const QMimeData *data)
160{
161 QByteArray ba;
162 if (mimeType == "application/x-color"_L1) {
163 /* QMimeData can only provide colors as QColor or the name
164 of a color as a QByteArray or a QString. So we need to do
165 the conversion to application/x-color here.
166 The application/x-color format is :
167 type: application/x-color
168 format: 16
169 data[0]: red
170 data[1]: green
171 data[2]: blue
172 data[3]: opacity
173 */
174 ba.resize(size: 8);
175 ushort * colBuf = (ushort *)ba.data();
176 QColor c = qvariant_cast<QColor>(v: data->colorData());
177 colBuf[0] = ushort(c.redF() * 0xFFFF);
178 colBuf[1] = ushort(c.greenF() * 0xFFFF);
179 colBuf[2] = ushort(c.blueF() * 0xFFFF);
180 colBuf[3] = ushort(c.alphaF() * 0xFFFF);
181 } else {
182 ba = data->data(mimetype: mimeType);
183 if (ba.isEmpty()) {
184 if (mimeType == "application/x-qt-image"_L1 && data->hasImage()) {
185 QImage image = qvariant_cast<QImage>(v: data->imageData());
186 QBuffer buf(&ba);
187 buf.open(openMode: QBuffer::WriteOnly);
188 // would there not be PNG ??
189 image.save(device: &buf, format: "PNG");
190 } else if (mimeType.startsWith(s: "image/"_L1) && data->hasImage()) {
191 QImage image = qvariant_cast<QImage>(v: data->imageData());
192 QBuffer buf(&ba);
193 buf.open(openMode: QBuffer::WriteOnly);
194 image.save(device: &buf, format: mimeType.mid(position: mimeType.indexOf(c: u'/') + 1).toLatin1().toUpper());
195 }
196 }
197 }
198 return ba;
199}
200
201QT_END_NAMESPACE
202
203#include "moc_qinternalmimedata_p.cpp"
204

source code of qtbase/src/gui/kernel/qinternalmimedata.cpp