1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2018 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtGui module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qinternalmimedata_p.h" |
41 | |
42 | #include <QtCore/qbuffer.h> |
43 | #include <QtGui/qimage.h> |
44 | #include <QtGui/qimagereader.h> |
45 | #include <QtGui/qimagewriter.h> |
46 | |
47 | QT_BEGIN_NAMESPACE |
48 | |
49 | static QStringList imageMimeFormats(const QList<QByteArray> &imageFormats) |
50 | { |
51 | QStringList formats; |
52 | formats.reserve(alloc: imageFormats.size()); |
53 | for (const auto &format : imageFormats) |
54 | formats.append(t: QLatin1String("image/" ) + QLatin1String(format.toLower())); |
55 | |
56 | //put png at the front because it is best |
57 | int pngIndex = formats.indexOf(string: QLatin1String("image/png" )); |
58 | if (pngIndex != -1 && pngIndex != 0) |
59 | formats.move(from: pngIndex, to: 0); |
60 | |
61 | return formats; |
62 | } |
63 | |
64 | static inline QStringList imageReadMimeFormats() |
65 | { |
66 | return imageMimeFormats(imageFormats: QImageReader::supportedImageFormats()); |
67 | } |
68 | |
69 | static inline QStringList imageWriteMimeFormats() |
70 | { |
71 | return imageMimeFormats(imageFormats: QImageWriter::supportedImageFormats()); |
72 | } |
73 | |
74 | QInternalMimeData::QInternalMimeData() |
75 | : QMimeData() |
76 | { |
77 | } |
78 | |
79 | QInternalMimeData::~QInternalMimeData() |
80 | { |
81 | } |
82 | |
83 | bool QInternalMimeData::hasFormat(const QString &mimeType) const |
84 | { |
85 | bool foundFormat = hasFormat_sys(mimeType); |
86 | if (!foundFormat && mimeType == QLatin1String("application/x-qt-image" )) { |
87 | QStringList imageFormats = imageReadMimeFormats(); |
88 | for (int i = 0; i < imageFormats.size(); ++i) { |
89 | if ((foundFormat = hasFormat_sys(mimeType: imageFormats.at(i)))) |
90 | break; |
91 | } |
92 | } |
93 | return foundFormat; |
94 | } |
95 | |
96 | QStringList QInternalMimeData::formats() const |
97 | { |
98 | QStringList realFormats = formats_sys(); |
99 | if (!realFormats.contains(str: QLatin1String("application/x-qt-image" ))) { |
100 | QStringList imageFormats = imageReadMimeFormats(); |
101 | for (int i = 0; i < imageFormats.size(); ++i) { |
102 | if (realFormats.contains(str: imageFormats.at(i))) { |
103 | realFormats += QLatin1String("application/x-qt-image" ); |
104 | break; |
105 | } |
106 | } |
107 | } |
108 | return realFormats; |
109 | } |
110 | |
111 | QVariant QInternalMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const |
112 | { |
113 | QVariant data = retrieveData_sys(mimeType, type); |
114 | if (mimeType == QLatin1String("application/x-qt-image" )) { |
115 | if (data.isNull() || (data.userType() == QMetaType::QByteArray && data.toByteArray().isEmpty())) { |
116 | // try to find an image |
117 | QStringList imageFormats = imageReadMimeFormats(); |
118 | for (int i = 0; i < imageFormats.size(); ++i) { |
119 | data = retrieveData_sys(mimeType: imageFormats.at(i), type); |
120 | if (data.isNull() || (data.userType() == QMetaType::QByteArray && data.toByteArray().isEmpty())) |
121 | continue; |
122 | break; |
123 | } |
124 | } |
125 | int typeId = type; |
126 | // we wanted some image type, but all we got was a byte array. Convert it to an image. |
127 | if (data.userType() == QMetaType::QByteArray |
128 | && (typeId == QMetaType::QImage || typeId == QMetaType::QPixmap || typeId == QMetaType::QBitmap)) |
129 | data = QImage::fromData(data: data.toByteArray()); |
130 | |
131 | } else if (mimeType == QLatin1String("application/x-color" ) && data.userType() == QMetaType::QByteArray) { |
132 | QColor c; |
133 | QByteArray ba = data.toByteArray(); |
134 | if (ba.size() == 8) { |
135 | ushort * colBuf = (ushort *)ba.data(); |
136 | c.setRgbF(r: qreal(colBuf[0]) / qreal(0xFFFF), |
137 | g: qreal(colBuf[1]) / qreal(0xFFFF), |
138 | b: qreal(colBuf[2]) / qreal(0xFFFF), |
139 | a: qreal(colBuf[3]) / qreal(0xFFFF)); |
140 | data = c; |
141 | } else { |
142 | qWarning(msg: "Qt: Invalid color format" ); |
143 | } |
144 | } else if (data.userType() != int(type) && data.userType() == QMetaType::QByteArray) { |
145 | // try to use mime data's internal conversion stuf. |
146 | QInternalMimeData *that = const_cast<QInternalMimeData *>(this); |
147 | that->setData(mimetype: mimeType, data: data.toByteArray()); |
148 | data = QMimeData::retrieveData(mimetype: mimeType, preferredType: type); |
149 | that->clear(); |
150 | } |
151 | return data; |
152 | } |
153 | |
154 | bool QInternalMimeData::canReadData(const QString &mimeType) |
155 | { |
156 | return imageReadMimeFormats().contains(str: mimeType); |
157 | } |
158 | |
159 | // helper functions for rendering mimedata to the system, this is needed because QMimeData is in core. |
160 | QStringList QInternalMimeData::formatsHelper(const QMimeData *data) |
161 | { |
162 | QStringList realFormats = data->formats(); |
163 | if (realFormats.contains(str: QLatin1String("application/x-qt-image" ))) { |
164 | // add all supported image formats |
165 | QStringList imageFormats = imageWriteMimeFormats(); |
166 | for (int i = 0; i < imageFormats.size(); ++i) { |
167 | if (!realFormats.contains(str: imageFormats.at(i))) |
168 | realFormats.append(t: imageFormats.at(i)); |
169 | } |
170 | } |
171 | return realFormats; |
172 | } |
173 | |
174 | bool QInternalMimeData::hasFormatHelper(const QString &mimeType, const QMimeData *data) |
175 | { |
176 | |
177 | bool foundFormat = data->hasFormat(mimetype: mimeType); |
178 | if (!foundFormat) { |
179 | if (mimeType == QLatin1String("application/x-qt-image" )) { |
180 | // check all supported image formats |
181 | QStringList imageFormats = imageWriteMimeFormats(); |
182 | for (int i = 0; i < imageFormats.size(); ++i) { |
183 | if ((foundFormat = data->hasFormat(mimetype: imageFormats.at(i)))) |
184 | break; |
185 | } |
186 | } else if (mimeType.startsWith(s: QLatin1String("image/" ))) { |
187 | return data->hasImage() && imageWriteMimeFormats().contains(str: mimeType); |
188 | } |
189 | } |
190 | return foundFormat; |
191 | } |
192 | |
193 | QByteArray QInternalMimeData::renderDataHelper(const QString &mimeType, const QMimeData *data) |
194 | { |
195 | QByteArray ba; |
196 | if (mimeType == QLatin1String("application/x-color" )) { |
197 | /* QMimeData can only provide colors as QColor or the name |
198 | of a color as a QByteArray or a QString. So we need to do |
199 | the conversion to application/x-color here. |
200 | The application/x-color format is : |
201 | type: application/x-color |
202 | format: 16 |
203 | data[0]: red |
204 | data[1]: green |
205 | data[2]: blue |
206 | data[3]: opacity |
207 | */ |
208 | ba.resize(size: 8); |
209 | ushort * colBuf = (ushort *)ba.data(); |
210 | QColor c = qvariant_cast<QColor>(v: data->colorData()); |
211 | colBuf[0] = ushort(c.redF() * 0xFFFF); |
212 | colBuf[1] = ushort(c.greenF() * 0xFFFF); |
213 | colBuf[2] = ushort(c.blueF() * 0xFFFF); |
214 | colBuf[3] = ushort(c.alphaF() * 0xFFFF); |
215 | } else { |
216 | ba = data->data(mimetype: mimeType); |
217 | if (ba.isEmpty()) { |
218 | if (mimeType == QLatin1String("application/x-qt-image" ) && data->hasImage()) { |
219 | QImage image = qvariant_cast<QImage>(v: data->imageData()); |
220 | QBuffer buf(&ba); |
221 | buf.open(openMode: QBuffer::WriteOnly); |
222 | // would there not be PNG ?? |
223 | image.save(device: &buf, format: "PNG" ); |
224 | } else if (mimeType.startsWith(s: QLatin1String("image/" )) && data->hasImage()) { |
225 | QImage image = qvariant_cast<QImage>(v: data->imageData()); |
226 | QBuffer buf(&ba); |
227 | buf.open(openMode: QBuffer::WriteOnly); |
228 | image.save(device: &buf, format: mimeType.mid(position: mimeType.indexOf(c: QLatin1Char('/')) + 1).toLatin1().toUpper()); |
229 | } |
230 | } |
231 | } |
232 | return ba; |
233 | } |
234 | |
235 | QT_END_NAMESPACE |
236 | |