1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 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 "qpicture.h"
41 #include <private/qpicture_p.h>
42 
43 #ifndef QT_NO_PICTURE
44 
45 #include <private/qfactoryloader_p.h>
46 #include <private/qpaintengine_pic_p.h>
47 #include <private/qfont_p.h>
48 #include <qguiapplication.h>
49 
50 #include "qdatastream.h"
51 #include "qfile.h"
52 #include "qimage.h"
53 #include "qmutex.h"
54 #include "qpainter.h"
55 #include "qpainterpath.h"
56 #include "qpixmap.h"
57 #include "qregexp.h"
58 #include "qregion.h"
59 #include "qdebug.h"
60 #include <QtCore/private/qlocking_p.h>
61 
62 #include <algorithm>
63 
64 QT_BEGIN_NAMESPACE
65 
66 void qt_format_text(const QFont &fnt, const QRectF &_r,
67                     int tf, const QTextOption *opt, const QString& str, QRectF *brect,
68                     int tabstops, int *, int tabarraylen,
69                     QPainter *painter);
70 
71 /*!
72     \class QPicture
73     \brief The QPicture class is a paint device that records and
74     replays QPainter commands.
75 
76     \inmodule QtGui
77     \ingroup shared
78 
79 
80     A picture serializes painter commands to an IO device in a
81     platform-independent format. They are sometimes referred to as meta-files.
82 
83     Qt pictures use a proprietary binary format. Unlike native picture
84     (meta-file) formats on many window systems, Qt pictures have no
85     limitations regarding their contents. Everything that can be
86     painted on a widget or pixmap (e.g., fonts, pixmaps, regions,
87     transformed graphics, etc.)  can also be stored in a picture.
88 
89     QPicture is resolution independent, i.e. a QPicture can be
90     displayed on different devices (for example svg, pdf, ps, printer
91     and screen) looking the same. This is, for instance, needed for
92     WYSIWYG print preview. QPicture runs in the default system dpi,
93     and scales the painter to match differences in resolution
94     depending on the window system.
95 
96     Example of how to record a picture:
97     \snippet picture/picture.cpp 0
98 
99     Note that the list of painter commands is reset on each call to
100     the QPainter::begin() function.
101 
102     Example of how to replay a picture:
103     \snippet picture/picture.cpp 1
104 
105     Pictures can also be drawn using play(). Some basic data about a
106     picture is available, for example, size(), isNull() and
107     boundingRect().
108 
109     \sa QMovie
110 */
111 
112 /*!
113     \fn QPicture &QPicture::operator=(QPicture &&other)
114 
115     Move-assigns \a other to this QPicture instance.
116 
117     \since 5.2
118 */
119 
120 const char  *qt_mfhdr_tag = "QPIC"; // header tag
121 static const quint16 mfhdr_maj = QDataStream::Qt_DefaultCompiledVersion; // major version #
122 static const quint16 mfhdr_min = 0; // minor version #
123 
124 /*!
125     Constructs an empty picture.
126 
127     The \a formatVersion parameter may be used to \e create a QPicture
128     that can be read by applications that are compiled with earlier
129     versions of Qt.
130 
131     Note that the default formatVersion is -1 which signifies the
132     current release, i.e. for Qt 4.0 a formatVersion of 7 is the same
133     as the default formatVersion of -1.
134 
135     Reading pictures generated by earlier versions of Qt is not
136     supported in Qt 4.0.
137 */
138 
QPicture(int formatVersion)139 QPicture::QPicture(int formatVersion)
140     : QPaintDevice(),
141       d_ptr(new QPicturePrivate)
142 {
143     Q_D(QPicture);
144 
145     if (formatVersion == 0)
146         qWarning("QPicture: invalid format version 0");
147 
148     // still accept the 0 default from before Qt 3.0.
149     if (formatVersion > 0 && formatVersion != (int)mfhdr_maj) {
150         d->formatMajor = formatVersion;
151         d->formatMinor = 0;
152         d->formatOk = false;
153     } else {
154         d->resetFormat();
155     }
156 }
157 
158 /*!
159     Constructs a copy of \a pic.
160 
161     This constructor is fast thanks to \l{implicit sharing}.
162 */
163 
QPicture(const QPicture & pic)164 QPicture::QPicture(const QPicture &pic)
165     : QPaintDevice(), d_ptr(pic.d_ptr)
166 {
167 }
168 
169 /*! \internal */
QPicture(QPicturePrivate & dptr)170 QPicture::QPicture(QPicturePrivate &dptr)
171     : QPaintDevice(),
172       d_ptr(&dptr)
173 {
174 }
175 
176 /*!
177     Destroys the picture.
178 */
~QPicture()179 QPicture::~QPicture()
180 {
181 }
182 
183 /*!
184   \internal
185 */
devType() const186 int QPicture::devType() const
187 {
188     return QInternal::Picture;
189 }
190 
191 /*!
192     \fn bool QPicture::isNull() const
193 
194     Returns \c true if the picture contains no data; otherwise returns
195     false.
196 */
197 
198 /*!
199     \fn uint QPicture::size() const
200 
201     Returns the size of the picture data.
202 
203     \sa data()
204 */
205 
206 /*!
207     \fn const char* QPicture::data() const
208 
209     Returns a pointer to the picture data. The pointer is only valid
210     until the next non-const function is called on this picture. The
211     returned pointer is 0 if the picture contains no data.
212 
213     \sa size(), isNull()
214 */
215 
216 
isNull() const217 bool QPicture::isNull() const
218 {
219     return d_func()->pictb.buffer().isNull();
220 }
221 
size() const222 uint QPicture::size() const
223 {
224     return d_func()->pictb.buffer().size();
225 }
226 
data() const227 const char* QPicture::data() const
228 {
229     return d_func()->pictb.buffer();
230 }
231 
detach()232 void QPicture::detach()
233 {
234     d_ptr.detach();
235 }
236 
isDetached() const237 bool QPicture::isDetached() const
238 {
239     return d_func()->ref.loadRelaxed() == 1;
240 }
241 
242 /*!
243     Sets the picture data directly from \a data and \a size. This
244     function copies the input data.
245 
246     \sa data(), size()
247 */
248 
setData(const char * data,uint size)249 void QPicture::setData(const char* data, uint size)
250 {
251     detach();
252     d_func()->pictb.setData(data, size);
253     d_func()->resetFormat();                                // we'll have to check
254 }
255 
256 
257 /*!
258     Loads a picture from the file specified by \a fileName and returns
259     true if successful; otherwise invalidates the picture and returns \c false.
260 
261     Please note that the \a format parameter has been deprecated and
262     will have no effect.
263 
264     \sa save()
265 */
266 
load(const QString & fileName,const char * format)267 bool QPicture::load(const QString &fileName, const char *format)
268 {
269     QFile f(fileName);
270     if (!f.open(QIODevice::ReadOnly)) {
271         operator=(QPicture());
272         return false;
273     }
274     return load(&f, format);
275 }
276 
277 /*!
278     \overload
279 
280     \a dev is the device to use for loading.
281 */
282 
load(QIODevice * dev,const char * format)283 bool QPicture::load(QIODevice *dev, const char *format)
284 {
285     if(format) {
286 #ifndef QT_NO_PICTUREIO
287         QPictureIO io(dev, format);
288         if (io.read()) {
289             operator=(io.picture());
290             return true;
291         }
292 #endif
293         qWarning("QPicture::load: No such picture format: %s", format);
294         operator=(QPicture());
295         return false;
296     }
297 
298     detach();
299     QByteArray a = dev->readAll();
300 
301     d_func()->pictb.setData(a);                        // set byte array in buffer
302     return d_func()->checkFormat();
303 }
304 
305 /*!
306     Saves a picture to the file specified by \a fileName and returns
307     true if successful; otherwise returns \c false.
308 
309     Please note that the \a format parameter has been deprecated and
310     will have no effect.
311 
312     \sa load()
313 */
314 
save(const QString & fileName,const char * format)315 bool QPicture::save(const QString &fileName, const char *format)
316 {
317     if (paintingActive()) {
318         qWarning("QPicture::save: still being painted on. "
319                   "Call QPainter::end() first");
320         return false;
321     }
322 
323 
324     if(format) {
325 #ifndef QT_NO_PICTUREIO
326         QPictureIO io(fileName, format);
327         bool result = io.write();
328         if (result) {
329             operator=(io.picture());
330         } else if (format)
331 #else
332         bool result = false;
333 #endif
334         {
335             qWarning("QPicture::save: No such picture format: %s", format);
336         }
337         return result;
338     }
339 
340     QFile f(fileName);
341     if (!f.open(QIODevice::WriteOnly))
342         return false;
343     return save(&f, format);
344 }
345 
346 /*!
347     \overload
348 
349     \a dev is the device to use for saving.
350 */
351 
save(QIODevice * dev,const char * format)352 bool QPicture::save(QIODevice *dev, const char *format)
353 {
354     if (paintingActive()) {
355         qWarning("QPicture::save: still being painted on. "
356                   "Call QPainter::end() first");
357         return false;
358     }
359 
360     if(format) {
361 #ifndef QT_NO_PICTUREIO
362         QPictureIO io(dev, format);
363         bool result = io.write();
364         if (result) {
365             operator=(io.picture());
366         } else if (format)
367 #else
368         bool result = false;
369 #endif
370         {
371             qWarning("QPicture::save: No such picture format: %s", format);
372         }
373         return result;
374     }
375 
376     dev->write(d_func()->pictb.buffer(), d_func()->pictb.buffer().size());
377     return true;
378 }
379 
380 /*!
381     Returns the picture's bounding rectangle or an invalid rectangle
382     if the picture contains no data.
383 */
384 
boundingRect() const385 QRect QPicture::boundingRect() const
386 {
387     Q_D(const QPicture);
388     // Use override rect where possible.
389     if (!d->override_rect.isEmpty())
390         return d->override_rect;
391 
392     if (!d->formatOk)
393         d_ptr->checkFormat();
394 
395     return d->brect;
396 }
397 
398 /*!
399     Sets the picture's bounding rectangle to \a r. The automatically
400     calculated value is overridden.
401 */
402 
setBoundingRect(const QRect & r)403 void QPicture::setBoundingRect(const QRect &r)
404 {
405     d_func()->override_rect = r;
406 }
407 
408 /*!
409     Replays the picture using \a painter, and returns \c true if
410     successful; otherwise returns \c false.
411 
412     This function does exactly the same as QPainter::drawPicture()
413     with (x, y) = (0, 0).
414 */
415 
play(QPainter * painter)416 bool QPicture::play(QPainter *painter)
417 {
418     Q_D(QPicture);
419 
420     if (d->pictb.size() == 0)                        // nothing recorded
421         return true;
422 
423     if (!d->formatOk && !d->checkFormat())
424         return false;
425 
426     d->pictb.open(QIODevice::ReadOnly);                // open buffer device
427     QDataStream s;
428     s.setDevice(&d->pictb);                        // attach data stream to buffer
429     s.device()->seek(10);                        // go directly to the data
430     s.setVersion(d->formatMajor == 4 ? 3 : d->formatMajor);
431 
432     quint8  c, clen;
433     quint32 nrecords;
434     s >> c >> clen;
435     Q_ASSERT(c == QPicturePrivate::PdcBegin);
436     // bounding rect was introduced in ver 4. Read in checkFormat().
437     if (d->formatMajor >= 4) {
438         qint32 dummy;
439         s >> dummy >> dummy >> dummy >> dummy;
440     }
441     s >> nrecords;
442     if (!exec(painter, s, nrecords)) {
443         qWarning("QPicture::play: Format error");
444         d->pictb.close();
445         return false;
446     }
447     d->pictb.close();
448     return true;                                // no end-command
449 }
450 
451 
452 //
453 // QFakeDevice is used to create fonts with a custom DPI
454 //
455 class QFakeDevice : public QPaintDevice
456 {
457 public:
QFakeDevice()458     QFakeDevice() { dpi_x = qt_defaultDpiX(); dpi_y = qt_defaultDpiY(); }
setDpiX(int dpi)459     void setDpiX(int dpi) { dpi_x = dpi; }
setDpiY(int dpi)460     void setDpiY(int dpi) { dpi_y = dpi; }
paintEngine() const461     QPaintEngine *paintEngine() const override { return nullptr; }
metric(PaintDeviceMetric m) const462     int metric(PaintDeviceMetric m) const override
463     {
464         switch(m) {
465             case PdmPhysicalDpiX:
466             case PdmDpiX:
467                 return dpi_x;
468             case PdmPhysicalDpiY:
469             case PdmDpiY:
470                 return dpi_y;
471             default:
472                 return QPaintDevice::metric(m);
473         }
474     }
475 
476 private:
477     int dpi_x;
478     int dpi_y;
479 };
480 
481 /*!
482   \internal
483   Iterates over the internal picture data and draws the picture using
484   \a painter.
485 */
486 
exec(QPainter * painter,QDataStream & s,int nrecords)487 bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
488 {
489     Q_D(QPicture);
490 #if defined(QT_DEBUG)
491     int                strm_pos;
492 #endif
493     quint8     c;                      // command id
494     quint8     tiny_len;               // 8-bit length descriptor
495     qint32     len;                    // 32-bit length descriptor
496     qint16     i_16, i1_16, i2_16;     // parameters...
497     qint8      i_8;
498     quint32    ul;
499     double     dbl;
500     bool       bl;
501     QByteArray  str1;
502     QString     str;
503     QPointF     p, p1, p2;
504     QPoint      ip, ip1, ip2;
505     QRect       ir;
506     QRectF      r;
507     QPolygonF   a;
508     QPolygon    ia;
509     QColor      color;
510     QFont       font;
511     QPen        pen;
512     QBrush      brush;
513     QRegion     rgn;
514     QMatrix     wmatrix;
515     QTransform  matrix;
516 
517     QTransform worldMatrix = painter->transform();
518     worldMatrix.scale(qreal(painter->device()->logicalDpiX()) / qreal(qt_defaultDpiX()),
519                       qreal(painter->device()->logicalDpiY()) / qreal(qt_defaultDpiY()));
520     painter->setTransform(worldMatrix);
521 
522     while (nrecords-- && !s.atEnd()) {
523         s >> c;                 // read cmd
524         s >> tiny_len;          // read param length
525         if (tiny_len == 255)    // longer than 254 bytes
526             s >> len;
527         else
528             len = tiny_len;
529 #if defined(QT_DEBUG)
530         strm_pos = s.device()->pos();
531 #endif
532         switch (c) {            // exec cmd
533         case QPicturePrivate::PdcNOP:
534             break;
535         case QPicturePrivate::PdcDrawPoint:
536             if (d->formatMajor <= 5) {
537                 s >> ip;
538                 painter->drawPoint(ip);
539             } else {
540                 s >> p;
541                 painter->drawPoint(p);
542             }
543             break;
544         case QPicturePrivate::PdcDrawPoints:
545 // ## implement me in the picture paint engine
546 //                 s >> a >> i1_32 >> i2_32;
547 //                 painter->drawPoints(a.mid(i1_32, i2_32));
548             break;
549         case QPicturePrivate::PdcDrawPath: {
550             QPainterPath path;
551             s >> path;
552             painter->drawPath(path);
553             break;
554         }
555         case QPicturePrivate::PdcDrawLine:
556             if (d->formatMajor <= 5) {
557                 s >> ip1 >> ip2;
558                 painter->drawLine(ip1, ip2);
559             } else {
560                 s >> p1 >> p2;
561                 painter->drawLine(p1, p2);
562             }
563             break;
564         case QPicturePrivate::PdcDrawRect:
565             if (d->formatMajor <= 5) {
566                 s >> ir;
567                 painter->drawRect(ir);
568             } else {
569                 s >> r;
570                 painter->drawRect(r);
571             }
572             break;
573         case QPicturePrivate::PdcDrawRoundRect:
574             if (d->formatMajor <= 5) {
575                 s >> ir >> i1_16 >> i2_16;
576                 painter->drawRoundedRect(ir, i1_16, i2_16, Qt::RelativeSize);
577             } else {
578                 s >> r >> i1_16 >> i2_16;
579                 painter->drawRoundedRect(r, i1_16, i2_16, Qt::RelativeSize);
580             }
581             break;
582         case QPicturePrivate::PdcDrawEllipse:
583             if (d->formatMajor <= 5) {
584                 s >> ir;
585                 painter->drawEllipse(ir);
586             } else {
587                 s >> r;
588                 painter->drawEllipse(r);
589             }
590             break;
591         case QPicturePrivate::PdcDrawArc:
592             if (d->formatMajor <= 5) {
593                 s >> ir;
594                 r = ir;
595             } else {
596                 s >> r;
597             }
598             s >> i1_16 >> i2_16;
599             painter->drawArc(r, i1_16, i2_16);
600             break;
601         case QPicturePrivate::PdcDrawPie:
602             if (d->formatMajor <= 5) {
603                 s >> ir;
604                 r = ir;
605             } else {
606                 s >> r;
607             }
608             s >> i1_16 >> i2_16;
609             painter->drawPie(r, i1_16, i2_16);
610             break;
611         case QPicturePrivate::PdcDrawChord:
612             if (d->formatMajor <= 5) {
613                 s >> ir;
614                 r = ir;
615             } else {
616                 s >> r;
617             }
618             s >> i1_16 >> i2_16;
619             painter->drawChord(r, i1_16, i2_16);
620             break;
621         case QPicturePrivate::PdcDrawLineSegments:
622             s >> ia;
623             painter->drawLines(ia);
624             ia.clear();
625             break;
626         case QPicturePrivate::PdcDrawPolyline:
627             if (d->formatMajor <= 5) {
628                 s >> ia;
629                 painter->drawPolyline(ia);
630                 ia.clear();
631             } else {
632                 s >> a;
633                 painter->drawPolyline(a);
634                 a.clear();
635             }
636             break;
637         case QPicturePrivate::PdcDrawPolygon:
638             if (d->formatMajor <= 5) {
639                 s >> ia >> i_8;
640                 painter->drawPolygon(ia, i_8 ? Qt::WindingFill : Qt::OddEvenFill);
641                 ia.clear();
642             } else {
643                 s >> a >> i_8;
644                 painter->drawPolygon(a, i_8 ? Qt::WindingFill : Qt::OddEvenFill);
645                 a.clear();
646             }
647             break;
648         case QPicturePrivate::PdcDrawCubicBezier: {
649             s >> ia;
650             QPainterPath path;
651             Q_ASSERT(ia.size() == 4);
652             path.moveTo(ia.value(0));
653             path.cubicTo(ia.value(1), ia.value(2), ia.value(3));
654             painter->strokePath(path, painter->pen());
655             ia.clear();
656         }
657             break;
658         case QPicturePrivate::PdcDrawText:
659             s >> ip >> str1;
660             painter->drawText(ip, QString::fromLatin1(str1));
661             break;
662         case QPicturePrivate::PdcDrawTextFormatted:
663             s >> ir >> i_16 >> str1;
664             painter->drawText(ir, i_16, QString::fromLatin1(str1));
665             break;
666         case QPicturePrivate::PdcDrawText2:
667             if (d->formatMajor <= 5) {
668                 s >> ip >> str;
669                 painter->drawText(ip, str);
670             } else {
671                 s >> p >> str;
672                 painter->drawText(p, str);
673             }
674             break;
675         case QPicturePrivate::PdcDrawText2Formatted:
676             s >> ir;
677             s >> i_16;
678             s >> str;
679             painter->drawText(ir, i_16, str);
680             break;
681         case QPicturePrivate::PdcDrawTextItem: {
682             s >> p >> str >> font >> ul;
683 
684             // the text layout direction is not used here because it's already
685             // aligned when QPicturePaintEngine::drawTextItem() serializes the
686             // drawText() call, therefore ul is unsed in this context
687 
688             if (d->formatMajor >= 9) {
689                 s >> dbl;
690                 QFont fnt(font);
691                 if (dbl != 1.0) {
692                     QFakeDevice fake;
693                     fake.setDpiX(qRound(dbl*qt_defaultDpiX()));
694                     fake.setDpiY(qRound(dbl*qt_defaultDpiY()));
695                     fnt = QFont(font, &fake);
696                 }
697 
698                 qreal justificationWidth;
699                 s >> justificationWidth;
700 
701                 int flags = Qt::TextSingleLine | Qt::TextDontClip | Qt::TextForceLeftToRight;
702 
703                 QSizeF size(1, 1);
704                 if (justificationWidth > 0) {
705                     size.setWidth(justificationWidth);
706                     flags |= Qt::TextJustificationForced;
707                     flags |= Qt::AlignJustify;
708                 }
709 
710                 QFontMetrics fm(fnt);
711                 QPointF pt(p.x(), p.y() - fm.ascent());
712                 qt_format_text(fnt, QRectF(pt, size), flags, /*opt*/nullptr,
713                                str, /*brect=*/nullptr, /*tabstops=*/0, /*...*/nullptr, /*tabarraylen=*/0, painter);
714             } else {
715                 qt_format_text(font, QRectF(p, QSizeF(1, 1)), Qt::TextSingleLine | Qt::TextDontClip, /*opt*/nullptr,
716                                str, /*brect=*/nullptr, /*tabstops=*/0, /*...*/nullptr, /*tabarraylen=*/0, painter);
717             }
718 
719             break;
720         }
721         case QPicturePrivate::PdcDrawPixmap: {
722             QPixmap pixmap;
723             if (d->formatMajor < 4) {
724                 s >> ip >> pixmap;
725                 painter->drawPixmap(ip, pixmap);
726             } else if (d->formatMajor <= 5) {
727                 s >> ir >> pixmap;
728                 painter->drawPixmap(ir, pixmap);
729             } else {
730                 QRectF sr;
731                 if (d->in_memory_only) {
732                     int index;
733                     s >> r >> index >> sr;
734                     Q_ASSERT(index < d->pixmap_list.size());
735                     pixmap = d->pixmap_list.value(index);
736                 } else {
737                     s >> r >> pixmap >> sr;
738                 }
739                 painter->drawPixmap(r, pixmap, sr);
740             }
741         }
742             break;
743         case QPicturePrivate::PdcDrawTiledPixmap: {
744             QPixmap pixmap;
745             if (d->in_memory_only) {
746                 int index;
747                 s >> r >> index >> p;
748                 Q_ASSERT(index < d->pixmap_list.size());
749                 pixmap = d->pixmap_list.value(index);
750             } else {
751                 s >> r >> pixmap >> p;
752             }
753             painter->drawTiledPixmap(r, pixmap, p);
754         }
755             break;
756         case QPicturePrivate::PdcDrawImage: {
757             QImage image;
758             if (d->formatMajor < 4) {
759                 s >> p >> image;
760                 painter->drawImage(p, image);
761             } else if (d->formatMajor <= 5){
762                 s >> ir >> image;
763                 painter->drawImage(ir, image, QRect(0, 0, ir.width(), ir.height()));
764             } else {
765                 QRectF sr;
766                 if (d->in_memory_only) {
767                     int index;
768                     s >> r >> index >> sr >> ul;
769                     Q_ASSERT(index < d->image_list.size());
770                     image = d->image_list.value(index);
771                 } else {
772                     s >> r >> image >> sr >> ul;
773                 }
774                 painter->drawImage(r, image, sr, Qt::ImageConversionFlags(ul));
775             }
776         }
777             break;
778         case QPicturePrivate::PdcBegin:
779             s >> ul;                        // number of records
780             if (!exec(painter, s, ul))
781                 return false;
782             break;
783         case QPicturePrivate::PdcEnd:
784             if (nrecords == 0)
785                 return true;
786             break;
787         case QPicturePrivate::PdcSave:
788             painter->save();
789             break;
790         case QPicturePrivate::PdcRestore:
791             painter->restore();
792             break;
793         case QPicturePrivate::PdcSetBkColor:
794             s >> color;
795             painter->setBackground(color);
796             break;
797         case QPicturePrivate::PdcSetBkMode:
798             s >> i_8;
799             painter->setBackgroundMode((Qt::BGMode)i_8);
800             break;
801         case QPicturePrivate::PdcSetROP: // NOP
802             s >> i_8;
803             break;
804         case QPicturePrivate::PdcSetBrushOrigin:
805             if (d->formatMajor <= 5) {
806                 s >> ip;
807                 painter->setBrushOrigin(ip);
808             } else {
809                 s >> p;
810                 painter->setBrushOrigin(p);
811             }
812             break;
813         case QPicturePrivate::PdcSetFont:
814             s >> font;
815             painter->setFont(font);
816             break;
817         case QPicturePrivate::PdcSetPen:
818             if (d->in_memory_only) {
819                 int index;
820                 s >> index;
821                 Q_ASSERT(index < d->pen_list.size());
822                 pen = d->pen_list.value(index);
823             } else {
824                 s >> pen;
825             }
826             painter->setPen(pen);
827             break;
828         case QPicturePrivate::PdcSetBrush:
829             if (d->in_memory_only) {
830                 int index;
831                 s >> index;
832                 Q_ASSERT(index < d->brush_list.size());
833                 brush = d->brush_list.value(index);
834             } else {
835                 s >> brush;
836             }
837             painter->setBrush(brush);
838             break;
839         case QPicturePrivate::PdcSetVXform:
840             s >> i_8;
841             painter->setViewTransformEnabled(i_8);
842             break;
843         case QPicturePrivate::PdcSetWindow:
844             if (d->formatMajor <= 5) {
845                 s >> ir;
846                 painter->setWindow(ir);
847             } else {
848                 s >> r;
849                 painter->setWindow(r.toRect());
850             }
851             break;
852         case QPicturePrivate::PdcSetViewport:
853             if (d->formatMajor <= 5) {
854                 s >> ir;
855                 painter->setViewport(ir);
856             } else {
857                 s >> r;
858                 painter->setViewport(r.toRect());
859             }
860             break;
861         case QPicturePrivate::PdcSetWXform:
862             s >> i_8;
863             painter->setWorldMatrixEnabled(i_8);
864             break;
865         case QPicturePrivate::PdcSetWMatrix:
866             if (d->formatMajor >= 8) {
867                 s >> matrix >> i_8;
868             } else {
869                 s >> wmatrix >> i_8;
870                 matrix = QTransform(wmatrix);
871             }
872             // i_8 is always false due to updateXForm() in qpaintengine_pic.cpp
873             painter->setTransform(matrix * worldMatrix, i_8);
874             break;
875         case QPicturePrivate::PdcSetClip:
876             s >> i_8;
877             painter->setClipping(i_8);
878             break;
879         case QPicturePrivate::PdcSetClipRegion:
880             s >> rgn >> i_8;
881             if (d->formatMajor >= 9) {
882                 painter->setClipRegion(rgn, Qt::ClipOperation(i_8));
883             } else {
884                 painter->setClipRegion(rgn);
885             }
886             break;
887         case QPicturePrivate::PdcSetClipPath:
888             {
889                 QPainterPath path;
890                 s >> path >> i_8;
891                 painter->setClipPath(path, Qt::ClipOperation(i_8));
892                 break;
893             }
894         case QPicturePrivate::PdcSetRenderHint:
895             s >> ul;
896             painter->setRenderHint(QPainter::Antialiasing,
897                                    bool(ul & QPainter::Antialiasing));
898             painter->setRenderHint(QPainter::SmoothPixmapTransform,
899                                    bool(ul & QPainter::SmoothPixmapTransform));
900             break;
901         case QPicturePrivate::PdcSetCompositionMode:
902             s >> ul;
903             painter->setCompositionMode((QPainter::CompositionMode)ul);
904             break;
905         case QPicturePrivate::PdcSetClipEnabled:
906             s >> bl;
907             painter->setClipping(bl);
908             break;
909         case QPicturePrivate::PdcSetOpacity:
910             s >> dbl;
911             painter->setOpacity(qreal(dbl));
912             break;
913         default:
914             qWarning("QPicture::play: Invalid command %d", c);
915             if (len > 0)                    // skip unknown command
916                 s.device()->seek(s.device()->pos()+len);
917         }
918 #if defined(QT_DEBUG)
919         //qDebug("device->at(): %i, strm_pos: %i len: %i", (int)s.device()->pos(), strm_pos, len);
920         Q_ASSERT(qint32(s.device()->pos() - strm_pos) == len);
921 #endif
922     }
923     return false;
924 }
925 
926 /*!
927     \internal
928 
929     Internal implementation of the virtual QPaintDevice::metric()
930     function.
931 
932     A picture has the following hard-coded values: numcolors=16777216
933     and depth=24.
934 
935     \a m is the metric to get.
936 */
937 
metric(PaintDeviceMetric m) const938 int QPicture::metric(PaintDeviceMetric m) const
939 {
940     int val;
941     QRect brect = boundingRect();
942     switch (m) {
943         case PdmWidth:
944             val = brect.width();
945             break;
946         case PdmHeight:
947             val = brect.height();
948             break;
949         case PdmWidthMM:
950             val = int(25.4/qt_defaultDpiX()*brect.width());
951             break;
952         case PdmHeightMM:
953             val = int(25.4/qt_defaultDpiY()*brect.height());
954             break;
955         case PdmDpiX:
956         case PdmPhysicalDpiX:
957             val = qt_defaultDpiX();
958             break;
959         case PdmDpiY:
960         case PdmPhysicalDpiY:
961             val = qt_defaultDpiY();
962             break;
963         case PdmNumColors:
964             val = 16777216;
965             break;
966         case PdmDepth:
967             val = 24;
968             break;
969         case PdmDevicePixelRatio:
970             val = 1;
971             break;
972         case PdmDevicePixelRatioScaled:
973             val = 1 * QPaintDevice::devicePixelRatioFScale();
974             break;
975         default:
976             val = 0;
977             qWarning("QPicture::metric: Invalid metric command");
978     }
979     return val;
980 }
981 
982 /*!
983     \fn void QPicture::detach()
984     \internal
985     Detaches from shared picture data and makes sure that this picture
986     is the only one referring to the data.
987 
988     If multiple pictures share common data, this picture makes a copy
989     of the data and detaches itself from the sharing mechanism.
990     Nothing is done if there is just a single reference.
991 */
992 
993 /*! \fn bool QPicture::isDetached() const
994 \internal
995 */
996 
997 /*!
998     Assigns picture \a p to this picture and returns a reference to
999     this picture.
1000 */
operator =(const QPicture & p)1001 QPicture& QPicture::operator=(const QPicture &p)
1002 {
1003     d_ptr = p.d_ptr;
1004     return *this;
1005 }
1006 
1007 /*!
1008     \fn void QPicture::swap(QPicture &other)
1009     \since 4.8
1010 
1011     Swaps picture \a other with this picture. This operation is very
1012     fast and never fails.
1013 */
1014 
1015 /*!
1016   \internal
1017 
1018   Constructs a QPicturePrivate
1019 */
QPicturePrivate()1020 QPicturePrivate::QPicturePrivate()
1021     : in_memory_only(false)
1022 {
1023 }
1024 
1025 /*!
1026   \internal
1027 
1028   Copy-Constructs a QPicturePrivate. Needed when detaching.
1029 */
QPicturePrivate(const QPicturePrivate & other)1030 QPicturePrivate::QPicturePrivate(const QPicturePrivate &other)
1031     : trecs(other.trecs),
1032       formatOk(other.formatOk),
1033       formatMinor(other.formatMinor),
1034       brect(other.brect),
1035       override_rect(other.override_rect),
1036       in_memory_only(false)
1037 {
1038     pictb.setData(other.pictb.data(), other.pictb.size());
1039     if (other.pictb.isOpen()) {
1040         pictb.open(other.pictb.openMode());
1041         pictb.seek(other.pictb.pos());
1042     }
1043 }
1044 
1045 /*!
1046   \internal
1047 
1048   Sets formatOk to false and resets the format version numbers to default
1049 */
1050 
resetFormat()1051 void QPicturePrivate::resetFormat()
1052 {
1053     formatOk = false;
1054     formatMajor = mfhdr_maj;
1055     formatMinor = mfhdr_min;
1056 }
1057 
1058 
1059 /*!
1060   \internal
1061 
1062   Checks data integrity and format version number. Set formatOk to
1063   true on success, to false otherwise. Returns the resulting formatOk
1064   value.
1065 */
checkFormat()1066 bool QPicturePrivate::checkFormat()
1067 {
1068     resetFormat();
1069 
1070     // can't check anything in an empty buffer
1071     if (pictb.size() == 0 || pictb.isOpen())
1072         return false;
1073 
1074     pictb.open(QIODevice::ReadOnly);                        // open buffer device
1075     QDataStream s;
1076     s.setDevice(&pictb);                        // attach data stream to buffer
1077 
1078     char mf_id[4];                                // picture header tag
1079     s.readRawData(mf_id, 4);                        // read actual tag
1080     int bufSize = pictb.buffer().size();
1081     if (memcmp(mf_id, qt_mfhdr_tag, 4) != 0 || bufSize < 12) {   // wrong header id or size
1082         qWarning("QPicturePaintEngine::checkFormat: Incorrect header");
1083         pictb.close();
1084         return false;
1085     }
1086 
1087     int cs_start = sizeof(quint32);                // pos of checksum word
1088     int data_start = cs_start + sizeof(quint16);
1089     quint16 cs,ccs;
1090     QByteArray buf = pictb.buffer();        // pointer to data
1091 
1092     s >> cs;                                // read checksum
1093     ccs = (quint16) qChecksum(buf.constData() + data_start, buf.size() - data_start);
1094     if (ccs != cs) {
1095         qWarning("QPicturePaintEngine::checkFormat: Invalid checksum %x, %x expected",
1096                   ccs, cs);
1097         pictb.close();
1098         return false;
1099     }
1100 
1101     quint16 major, minor;
1102     s >> major >> minor;                        // read version number
1103     if (major > mfhdr_maj) {                // new, incompatible version
1104         qWarning("QPicturePaintEngine::checkFormat: Incompatible version %d.%d",
1105                   major, minor);
1106         pictb.close();
1107         return false;
1108     }
1109     s.setVersion(major != 4 ? major : 3);
1110 
1111     quint8  c, clen;
1112     s >> c >> clen;
1113     if (c == QPicturePrivate::PdcBegin) {
1114         if (!(major >= 1 && major <= 3)) {
1115             qint32 l, t, w, h;
1116             s >> l >> t >> w >> h;
1117             brect = QRect(l, t, w, h);
1118         }
1119     } else {
1120         qWarning("QPicturePaintEngine::checkFormat: Format error");
1121         pictb.close();
1122         return false;
1123     }
1124     pictb.close();
1125 
1126     formatOk = true;                        // picture seems to be ok
1127     formatMajor = major;
1128     formatMinor = minor;
1129     return true;
1130 }
1131 
1132 /*! \internal */
paintEngine() const1133 QPaintEngine *QPicture::paintEngine() const
1134 {
1135     if (!d_func()->paintEngine)
1136         const_cast<QPicture*>(this)->d_func()->paintEngine.reset(new QPicturePaintEngine);
1137     return d_func()->paintEngine.data();
1138 }
1139 
1140 /*****************************************************************************
1141   QPicture stream functions
1142  *****************************************************************************/
1143 
1144 #ifndef QT_NO_DATASTREAM
1145 /*!
1146     \relates QPicture
1147 
1148     Writes picture \a r to the stream \a s and returns a reference to
1149     the stream.
1150 */
1151 
operator <<(QDataStream & s,const QPicture & r)1152 QDataStream &operator<<(QDataStream &s, const QPicture &r)
1153 {
1154     quint32 size = r.d_func()->pictb.buffer().size();
1155     s << size;
1156     // null picture ?
1157     if (size == 0)
1158         return s;
1159     // just write the whole buffer to the stream
1160     s.writeRawData (r.d_func()->pictb.buffer(), r.d_func()->pictb.buffer().size());
1161     return s;
1162 }
1163 
1164 /*!
1165     \relates QPicture
1166 
1167     Reads a picture from the stream \a s into picture \a r and returns
1168     a reference to the stream.
1169 */
1170 
operator >>(QDataStream & s,QPicture & r)1171 QDataStream &operator>>(QDataStream &s, QPicture &r)
1172 {
1173     QDataStream sr;
1174 
1175     // "init"; this code is similar to the beginning of QPicture::cmd()
1176     sr.setDevice(&r.d_func()->pictb);
1177     sr.setVersion(r.d_func()->formatMajor);
1178     quint32 len;
1179     s >> len;
1180     QByteArray data;
1181     if (len > 0) {
1182         data.resize(len);
1183         s.readRawData(data.data(), len);
1184     }
1185 
1186     r.d_func()->pictb.setData(data);
1187     r.d_func()->resetFormat();
1188     return s;
1189 }
1190 #endif // QT_NO_DATASTREAM
1191 
1192 
1193 #ifndef QT_NO_PICTUREIO
1194 
1195 QT_BEGIN_INCLUDE_NAMESPACE
1196 #include "qregexp.h"
1197 #include "qpictureformatplugin.h"
1198 QT_END_INCLUDE_NAMESPACE
1199 
1200 #if QT_DEPRECATED_SINCE(5, 10)
1201 /*!
1202     \obsolete
1203 
1204     Returns a string that specifies the picture format of the file \a
1205     fileName, or \nullptr if the file cannot be read or if the format
1206     is not recognized.
1207 
1208     \sa load(), save()
1209 */
1210 
pictureFormat(const QString & fileName)1211 const char* QPicture::pictureFormat(const QString &fileName)
1212 {
1213     const QByteArray format = QPictureIO::pictureFormat(fileName);
1214     // This function returns a const char * from a QByteArray.
1215     // Double check that the QByteArray is not detached, otherwise
1216     // we would return a dangling pointer.
1217     Q_ASSERT(!format.isDetached());
1218     return format;
1219 }
1220 
1221 /*!
1222     \obsolete
1223 
1224     Returns a list of picture formats that are supported for picture
1225     input.
1226 
1227     \sa outputFormats(), inputFormatList(), QPictureIO
1228 */
inputFormats()1229 QList<QByteArray> QPicture::inputFormats()
1230 {
1231     return QPictureIO::inputFormats();
1232 }
1233 
qToStringList(const QList<QByteArray> & arr)1234 static QStringList qToStringList(const QList<QByteArray> &arr)
1235 {
1236     QStringList list;
1237     const int count = arr.count();
1238     list.reserve(count);
1239     for (int i = 0; i < count; ++i)
1240         list.append(QString::fromLatin1(arr.at(i)));
1241     return list;
1242 }
1243 
1244 /*!
1245     \obsolete
1246 
1247     Returns a list of picture formats that are supported for picture
1248     input.
1249 
1250     Note that if you want to iterate over the list, you should iterate
1251     over a copy, e.g.
1252     \snippet picture/picture.cpp 2
1253 
1254     \sa outputFormatList(), inputFormats(), QPictureIO
1255 */
inputFormatList()1256 QStringList QPicture::inputFormatList()
1257 {
1258     return qToStringList(QPictureIO::inputFormats());
1259 }
1260 
1261 
1262 /*!
1263     \obsolete
1264 
1265     Returns a list of picture formats that are supported for picture
1266     output.
1267 
1268     Note that if you want to iterate over the list, you should iterate
1269     over a copy, e.g.
1270     \snippet picture/picture.cpp 3
1271 
1272     \sa inputFormatList(), outputFormats(), QPictureIO
1273 */
outputFormatList()1274 QStringList QPicture::outputFormatList()
1275 {
1276     return qToStringList(QPictureIO::outputFormats());
1277 }
1278 
1279 /*!
1280     \obsolete
1281 
1282     Returns a list of picture formats that are supported for picture
1283     output.
1284 
1285     \sa inputFormats(), outputFormatList(), QPictureIO
1286 */
outputFormats()1287 QList<QByteArray> QPicture::outputFormats()
1288 {
1289     return QPictureIO::outputFormats();
1290 }
1291 #endif // QT_DEPRECATED_SINCE(5, 10)
1292 
1293 /*****************************************************************************
1294   QPictureIO member functions
1295  *****************************************************************************/
1296 
1297 /*!
1298     \obsolete
1299 
1300     \class QPictureIO
1301 
1302     \brief The QPictureIO class contains parameters for loading and
1303     saving pictures.
1304 
1305     \ingroup painting
1306     \ingroup io
1307     \inmodule QtGui
1308 
1309     QPictureIO contains a QIODevice object that is used for picture data
1310     I/O. The programmer can install new picture file formats in addition
1311     to those that Qt provides.
1312 
1313     You don't normally need to use this class; QPicture::load(),
1314     QPicture::save().
1315 
1316     \sa QPicture, QPixmap, QFile
1317 */
1318 
1319 struct QPictureIOData
1320 {
1321     QPicture        pi;                                // picture
1322     int                iostat;                                // IO status
1323     QByteArray        frmt;                                // picture format
1324     QIODevice  *iodev;                                // IO device
1325     QString        fname;                                // file name
1326     QString     descr;                                // picture description
1327     const char *parameters;
1328     int quality;
1329     float gamma;
1330 };
1331 
1332 /*!
1333     Constructs a QPictureIO object with all parameters set to zero.
1334 */
1335 
QPictureIO()1336 QPictureIO::QPictureIO()
1337 {
1338     init();
1339 }
1340 
1341 /*!
1342     Constructs a QPictureIO object with the I/O device \a ioDevice and a
1343     \a format tag.
1344 */
1345 
QPictureIO(QIODevice * ioDevice,const char * format)1346 QPictureIO::QPictureIO(QIODevice *ioDevice, const char *format)
1347 {
1348     init();
1349     d->iodev = ioDevice;
1350     d->frmt = format;
1351 }
1352 
1353 /*!
1354     Constructs a QPictureIO object with the file name \a fileName and a
1355     \a format tag.
1356 */
1357 
QPictureIO(const QString & fileName,const char * format)1358 QPictureIO::QPictureIO(const QString &fileName, const char* format)
1359 {
1360     init();
1361     d->frmt = format;
1362     d->fname = fileName;
1363 }
1364 
1365 /*!
1366     Contains initialization common to all QPictureIO constructors.
1367 */
1368 
init()1369 void QPictureIO::init()
1370 {
1371     d = new QPictureIOData();
1372     d->parameters = nullptr;
1373     d->quality = -1; // default quality of the current format
1374     d->gamma=0.0f;
1375     d->iostat = 0;
1376     d->iodev  = nullptr;
1377 }
1378 
1379 /*!
1380     Destroys the object and all related data.
1381 */
1382 
~QPictureIO()1383 QPictureIO::~QPictureIO()
1384 {
1385     if (d->parameters)
1386         delete [] d->parameters;
1387     delete d;
1388 }
1389 
1390 
1391 /*****************************************************************************
1392   QPictureIO picture handler functions
1393  *****************************************************************************/
1394 
1395 class QPictureHandler
1396 {
1397 public:
1398     QPictureHandler(const char *f, const char *h, const QByteArray& fl,
1399                      picture_io_handler r, picture_io_handler w);
1400     QByteArray              format;                        // picture format
1401     QRegExp              header;                        // picture header pattern
1402     enum TMode { Untranslated=0, TranslateIn, TranslateInOut } text_mode;
1403     picture_io_handler  read_picture;                // picture read function
1404     picture_io_handler  write_picture;                // picture write function
1405     bool              obsolete;                        // support not "published"
1406 };
1407 
QPictureHandler(const char * f,const char * h,const QByteArray & fl,picture_io_handler r,picture_io_handler w)1408 QPictureHandler::QPictureHandler(const char *f, const char *h, const QByteArray& fl,
1409                               picture_io_handler r, picture_io_handler w)
1410     : format(f), header(QString::fromLatin1(h))
1411 {
1412     text_mode = Untranslated;
1413     if (fl.contains('t'))
1414         text_mode = TranslateIn;
1415     else if (fl.contains('T'))
1416         text_mode = TranslateInOut;
1417     obsolete = fl.contains('O');
1418     read_picture  = r;
1419     write_picture = w;
1420 }
1421 
1422 typedef QList<QPictureHandler *> QPHList;
Q_GLOBAL_STATIC(QPHList,pictureHandlers)1423 Q_GLOBAL_STATIC(QPHList, pictureHandlers)
1424 
1425 void qt_init_picture_plugins()
1426 {
1427     typedef QMultiMap<int, QString> PluginKeyMap;
1428     typedef PluginKeyMap::const_iterator PluginKeyMapConstIterator;
1429 
1430     static QBasicMutex mutex;
1431     const auto locker = qt_scoped_lock(mutex);
1432     static QFactoryLoader loader(QPictureFormatInterface_iid,
1433                                  QStringLiteral("/pictureformats"));
1434 
1435     const PluginKeyMap keyMap = loader.keyMap();
1436     const PluginKeyMapConstIterator cend = keyMap.constEnd();
1437     for (PluginKeyMapConstIterator it = keyMap.constBegin(); it != cend; ++it) {
1438         if (QPictureFormatPlugin *format = qobject_cast<QPictureFormatPlugin*>(loader.instance(it.key())))
1439             format->installIOHandler(it.value());
1440     }
1441 }
1442 
cleanup()1443 static void cleanup()
1444 {
1445     // make sure that picture handlers are delete before plugin manager
1446     if (QPHList *list = pictureHandlers()) {
1447         qDeleteAll(*list);
1448         list->clear();
1449     }
1450 }
1451 
qt_init_picture_handlers()1452 void qt_init_picture_handlers()                // initialize picture handlers
1453 {
1454     static QBasicAtomicInt done = Q_BASIC_ATOMIC_INITIALIZER(0);
1455     if (done.testAndSetRelaxed(0, 1)) {
1456         qAddPostRoutine(cleanup);
1457     }
1458 }
1459 
get_picture_handler(const char * format)1460 static QPictureHandler *get_picture_handler(const char *format)
1461 {                                                // get pointer to handler
1462     qt_init_picture_handlers();
1463     qt_init_picture_plugins();
1464     if (QPHList *list = pictureHandlers()) {
1465         for (int i = 0; i < list->size(); ++i) {
1466             if (list->at(i)->format == format)
1467                 return list->at(i);
1468         }
1469     }
1470     return nullptr;                                        // no such handler
1471 }
1472 
1473 
1474 /*!
1475     Defines a picture I/O handler for the picture format called \a
1476     format, which is recognized using the regular
1477     expression defined in \a header, read using \a readPicture and
1478     written using \a writePicture.
1479 
1480     \a flags is a string of single-character flags for this format.
1481     The only flag defined currently is T (upper case), so the only
1482     legal value for \a flags are "T" and the empty string. The "T"
1483     flag means that the picture file is a text file, and Qt should treat
1484     all newline conventions as equivalent. (XPM files and some PPM
1485     files are text files for example.)
1486 
1487     \a format is used to select a handler to write a QPicture; \a header
1488     is used to select a handler to read an picture file.
1489 
1490     If \a readPicture is \nullptr, the QPictureIO will not be able
1491     to read pictures in \a format. If \a writePicture is \nullptr,
1492     the QPictureIO will not be able to write pictures in \a format. If
1493     both are null, the QPictureIO object is valid but useless.
1494 
1495     Example:
1496     \snippet picture/picture.cpp 6
1497     \codeline
1498     \snippet picture/picture.cpp 7
1499     \codeline
1500     \snippet picture/picture.cpp 8
1501 
1502     Before the regular expression test, all the 0 bytes in the file header are
1503     converted to 1 bytes. This is done because when Qt was ASCII-based, QRegExp
1504     could not handle 0 bytes in strings.
1505 
1506     The regexp is only applied on the first 14 bytes of the file.
1507 
1508     (Note that if one handlerIO supports writing a format and another
1509     supports reading it, Qt supports both reading and writing. If two
1510     handlers support the same operation, Qt chooses one arbitrarily.)
1511 */
1512 
defineIOHandler(const char * format,const char * header,const char * flags,picture_io_handler readPicture,picture_io_handler writePicture)1513 void QPictureIO::defineIOHandler(const char *format,
1514                                  const char *header,
1515                                  const char *flags,
1516                                  picture_io_handler readPicture,
1517                                  picture_io_handler writePicture)
1518 {
1519     qt_init_picture_handlers();
1520     if (QPHList *list = pictureHandlers()) {
1521         QPictureHandler *p;
1522         p = new QPictureHandler(format, header, QByteArray(flags), readPicture, writePicture);
1523         list->prepend(p);
1524     }
1525 }
1526 
1527 
1528 /*****************************************************************************
1529   QPictureIO normal member functions
1530  *****************************************************************************/
1531 
1532 /*!
1533     Returns the picture currently set.
1534 
1535     \sa setPicture()
1536 */
picture() const1537 const QPicture &QPictureIO::picture() const { return d->pi; }
1538 
1539 /*!
1540     Returns the picture's IO status. A non-zero value indicates an
1541     error, whereas 0 means that the IO operation was successful.
1542 
1543     \sa setStatus()
1544 */
status() const1545 int QPictureIO::status() const { return d->iostat; }
1546 
1547 /*!
1548     Returns the picture format string or \nullptr if no format has been
1549     explicitly set.
1550 */
format() const1551 const char *QPictureIO::format() const { return d->frmt; }
1552 
1553 /*!
1554     Returns the IO device currently set.
1555 
1556     \sa setIODevice()
1557 */
ioDevice() const1558 QIODevice *QPictureIO::ioDevice() const { return d->iodev; }
1559 
1560 /*!
1561     Returns the file name currently set.
1562 
1563     \sa setFileName()
1564 */
fileName() const1565 QString QPictureIO::fileName() const { return d->fname; }
1566 
1567 
1568 /*!
1569     Returns the picture description string.
1570 
1571     \sa setDescription()
1572 */
description() const1573 QString QPictureIO::description() const { return d->descr; }
1574 
1575 /*!
1576     Sets the picture to \a picture.
1577 
1578     \sa picture()
1579 */
setPicture(const QPicture & picture)1580 void QPictureIO::setPicture(const QPicture &picture)
1581 {
1582     d->pi = picture;
1583 }
1584 
1585 /*!
1586     Sets the picture IO status to \a status. A non-zero value indicates
1587     an error, whereas 0 means that the IO operation was successful.
1588 
1589     \sa status()
1590 */
setStatus(int status)1591 void QPictureIO::setStatus(int status)
1592 {
1593     d->iostat = status;
1594 }
1595 
1596 /*!
1597     Sets the picture format to \a format for the picture to be read or
1598     written.
1599 
1600     It is necessary to specify a format before writing an picture, but
1601     it is not necessary to specify a format before reading an picture.
1602 
1603     If no format has been set, Qt guesses the picture format before
1604     reading it. If a format is set the picture will only be read if it
1605     has that format.
1606 
1607     \sa read(), write(), format()
1608 */
setFormat(const char * format)1609 void QPictureIO::setFormat(const char *format)
1610 {
1611     d->frmt = format;
1612 }
1613 
1614 /*!
1615     Sets the IO device to be used for reading or writing an picture.
1616 
1617     Setting the IO device allows pictures to be read/written to any
1618     block-oriented QIODevice.
1619 
1620     If \a ioDevice is not null, this IO device will override file name
1621     settings.
1622 
1623     \sa setFileName()
1624 */
setIODevice(QIODevice * ioDevice)1625 void QPictureIO::setIODevice(QIODevice *ioDevice)
1626 {
1627     d->iodev = ioDevice;
1628 }
1629 
1630 /*!
1631     Sets the name of the file to read or write an picture from to \a
1632     fileName.
1633 
1634     \sa setIODevice()
1635 */
setFileName(const QString & fileName)1636 void QPictureIO::setFileName(const QString &fileName)
1637 {
1638     d->fname = fileName;
1639 }
1640 
1641 /*!
1642     Returns the quality of the written picture, related to the
1643     compression ratio.
1644 
1645     \sa setQuality(), QPicture::save()
1646 */
quality() const1647 int QPictureIO::quality() const
1648 {
1649     return d->quality;
1650 }
1651 
1652 /*!
1653     Sets the quality of the written picture to \a q, related to the
1654     compression ratio.
1655 
1656     \a q must be in the range -1..100. Specify 0 to obtain small
1657     compressed files, 100 for large uncompressed files. (-1 signifies
1658     the default compression.)
1659 
1660     \sa quality(), QPicture::save()
1661 */
1662 
setQuality(int q)1663 void QPictureIO::setQuality(int q)
1664 {
1665     d->quality = q;
1666 }
1667 
1668 /*!
1669     Returns the picture's parameters string.
1670 
1671     \sa setParameters()
1672 */
1673 
parameters() const1674 const char *QPictureIO::parameters() const
1675 {
1676     return d->parameters;
1677 }
1678 
1679 /*!
1680     Sets the picture's parameter string to \a parameters. This is for
1681     picture handlers that require special parameters.
1682 
1683     Although the current picture formats supported by Qt ignore the
1684     parameters string, it may be used in future extensions or by
1685     contributions (for example, JPEG).
1686 
1687     \sa parameters()
1688 */
1689 
setParameters(const char * parameters)1690 void QPictureIO::setParameters(const char *parameters)
1691 {
1692     if (d->parameters)
1693         delete [] d->parameters;
1694     d->parameters = qstrdup(parameters);
1695 }
1696 
1697 /*!
1698     Sets the gamma value at which the picture will be viewed to \a
1699     gamma. If the picture format stores a gamma value for which the
1700     picture is intended to be used, then this setting will be used to
1701     modify the picture. Setting to 0.0 will disable gamma correction
1702     (i.e. any specification in the file will be ignored).
1703 
1704     The default value is 0.0.
1705 
1706     \sa gamma()
1707 */
setGamma(float gamma)1708 void QPictureIO::setGamma(float gamma)
1709 {
1710     d->gamma=gamma;
1711 }
1712 
1713 /*!
1714     Returns the gamma value at which the picture will be viewed.
1715 
1716     \sa setGamma()
1717 */
gamma() const1718 float QPictureIO::gamma() const
1719 {
1720     return d->gamma;
1721 }
1722 
1723 /*!
1724     Sets the picture description string for picture handlers that support
1725     picture descriptions to \a description.
1726 
1727     Currently, no picture format supported by Qt uses the description
1728     string.
1729 */
1730 
setDescription(const QString & description)1731 void QPictureIO::setDescription(const QString &description)
1732 {
1733     d->descr = description;
1734 }
1735 
1736 
1737 /*!
1738     Returns a string that specifies the picture format of the file \a
1739     fileName, or null if the file cannot be read or if the format is
1740     not recognized.
1741 */
1742 
pictureFormat(const QString & fileName)1743 QByteArray QPictureIO::pictureFormat(const QString &fileName)
1744 {
1745     QFile file(fileName);
1746     QByteArray format;
1747     if (!file.open(QIODevice::ReadOnly))
1748         return format;
1749     format = pictureFormat(&file);
1750     file.close();
1751     return format;
1752 }
1753 
1754 /*!
1755     \overload
1756 
1757     Returns a string that specifies the picture format of the picture read
1758     from IO device \a d, or 0 if the device cannot be read or if the
1759     format is not recognized.
1760 
1761     Make sure that \a d is at the right position in the device (for
1762     example, at the beginning of the file).
1763 
1764     \sa QIODevice::pos()
1765 */
1766 
pictureFormat(QIODevice * d)1767 QByteArray QPictureIO::pictureFormat(QIODevice *d)
1768 {
1769     // if you change this change the documentation for defineIOHandler()
1770     const int buflen = 14;
1771 
1772     char buf[buflen];
1773     char buf2[buflen];
1774     qt_init_picture_handlers();
1775     qt_init_picture_plugins();
1776     int pos = d->pos();                      // save position
1777     int rdlen = d->read(buf, buflen);        // read a few bytes
1778 
1779     QByteArray format;
1780     if (rdlen != buflen)
1781         return format;
1782 
1783     memcpy(buf2, buf, buflen);
1784 
1785     for (int n = 0; n < rdlen; n++)
1786         if (buf[n] == '\0')
1787             buf[n] = '\001';
1788     if (rdlen > 0) {
1789         buf[rdlen - 1] = '\0';
1790         QString bufStr = QString::fromLatin1(buf);
1791         if (QPHList *list = pictureHandlers()) {
1792             for (int i = 0; i < list->size(); ++i) {
1793                 if (list->at(i)->header.indexIn(bufStr) != -1) { // try match with headers
1794                     format = list->at(i)->format;
1795                     break;
1796                 }
1797             }
1798         }
1799     }
1800     d->seek(pos);                                // restore position
1801     return format;
1802 }
1803 
1804 /*!
1805     Returns a sorted list of picture formats that are supported for
1806     picture input.
1807 */
inputFormats()1808 QList<QByteArray> QPictureIO::inputFormats()
1809 {
1810     QList<QByteArray> result;
1811 
1812     qt_init_picture_handlers();
1813     qt_init_picture_plugins();
1814 
1815     if (QPHList *list = pictureHandlers()) {
1816         for (int i = 0; i < list->size(); ++i) {
1817             QPictureHandler *p = list->at(i);
1818             if (p->read_picture && !p->obsolete  && !result.contains(p->format))
1819                 result.append(p->format);
1820         }
1821     }
1822     std::sort(result.begin(), result.end());
1823 
1824     return result;
1825 }
1826 
1827 /*!
1828     Returns a sorted list of picture formats that are supported for
1829     picture output.
1830 */
outputFormats()1831 QList<QByteArray> QPictureIO::outputFormats()
1832 {
1833     qt_init_picture_handlers();
1834     qt_init_picture_plugins();
1835 
1836     QList<QByteArray> result;
1837     if (QPHList *list = pictureHandlers()) {
1838         for (int i = 0; i < list->size(); ++i) {
1839             QPictureHandler *p = list->at(i);
1840             if (p->write_picture && !p->obsolete && !result.contains(p->format))
1841                 result.append(p->format);
1842         }
1843     }
1844     return result;
1845 }
1846 
1847 
1848 
1849 /*!
1850     Reads an picture into memory and returns \c true if the picture was
1851     successfully read; otherwise returns \c false.
1852 
1853     Before reading an picture you must set an IO device or a file name.
1854     If both an IO device and a file name have been set, the IO device
1855     will be used.
1856 
1857     Setting the picture file format string is optional.
1858 
1859     Note that this function does \e not set the \l{format()}{format} used to read the picture. If you need that
1860     information, use the pictureFormat() static functions.
1861 
1862     Example:
1863 
1864     \snippet picture/picture.cpp 4
1865 
1866     \sa setIODevice(), setFileName(), setFormat(), write(), QPixmap::load()
1867 */
read()1868 bool QPictureIO::read()
1869 {
1870     QFile           file;
1871     QByteArray      picture_format;
1872     QPictureHandler *h;
1873 
1874     if (d->iodev) {                                // read from io device
1875         // ok, already open
1876     } else if (!d->fname.isEmpty()) {                // read from file
1877         file.setFileName(d->fname);
1878         if (!file.open(QIODevice::ReadOnly))
1879             return false;                        // cannot open file
1880         d->iodev = &file;
1881     } else {                                        // no file name or io device
1882         return false;
1883     }
1884     if (d->frmt.isEmpty()) {
1885         // Try to guess format
1886         picture_format = pictureFormat(d->iodev);        // get picture format
1887         if (picture_format.isEmpty()) {
1888             if (file.isOpen()) {                        // unknown format
1889                 file.close();
1890                 d->iodev = nullptr;
1891             }
1892             return false;
1893         }
1894     } else {
1895         picture_format = d->frmt;
1896     }
1897 
1898     h = get_picture_handler(picture_format);
1899     if (file.isOpen()) {
1900 #if !defined(Q_OS_UNIX)
1901         if (h && h->text_mode) {                // reopen in translated mode
1902             file.close();
1903             file.open(QIODevice::ReadOnly | QIODevice::Text);
1904         }
1905         else
1906 #endif
1907             file.seek(0);                        // position to start
1908     }
1909     d->iostat = 1;                                        // assume error
1910 
1911     if (h && h->read_picture)
1912         (*h->read_picture)(this);
1913 
1914     if (file.isOpen()) {                        // picture was read using file
1915         file.close();
1916         d->iodev = nullptr;
1917     }
1918     return d->iostat == 0;                                // picture successfully read?
1919 }
1920 
1921 
1922 /*!
1923     Writes an picture to an IO device and returns \c true if the picture was
1924     successfully written; otherwise returns \c false.
1925 
1926     Before writing an picture you must set an IO device or a file name.
1927     If both an IO device and a file name have been set, the IO device
1928     will be used.
1929 
1930     The picture will be written using the specified picture format.
1931 
1932     Example:
1933     \snippet picture/picture.cpp 5
1934 
1935     \sa setIODevice(), setFileName(), setFormat(), read(), QPixmap::save()
1936 */
write()1937 bool QPictureIO::write()
1938 {
1939     if (d->frmt.isEmpty())
1940         return false;
1941     QPictureHandler *h = get_picture_handler(d->frmt);
1942     if (!h || !h->write_picture) {
1943         qWarning("QPictureIO::write: No such picture format handler: %s",
1944                  format());
1945         return false;
1946     }
1947     QFile file;
1948     if (!d->iodev && !d->fname.isEmpty()) {
1949         file.setFileName(d->fname);
1950         bool translate = h->text_mode==QPictureHandler::TranslateInOut;
1951         QIODevice::OpenMode fmode = translate ? QIODevice::WriteOnly | QIODevice::Text : QIODevice::OpenMode(QIODevice::WriteOnly);
1952         if (!file.open(fmode))                // couldn't create file
1953             return false;
1954         d->iodev = &file;
1955     }
1956     d->iostat = 1;
1957     (*h->write_picture)(this);
1958     if (file.isOpen()) {                        // picture was written using file
1959         file.close();
1960         d->iodev = nullptr;
1961     }
1962     return d->iostat == 0;                                // picture successfully written?
1963 }
1964 #endif //QT_NO_PICTUREIO
1965 
1966 QT_END_NAMESPACE
1967 
1968 #endif // QT_NO_PICTURE
1969 
1970 /*!
1971     \typedef QPicture::DataPtr
1972     \internal
1973 */
1974 
1975 /*!
1976     \fn DataPtr &QPicture::data_ptr()
1977     \internal
1978 */
1979