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 "qregion.h"
58#include "qdebug.h"
59#include <QtCore/private/qlocking_p.h>
60
61#include <algorithm>
62
63QT_BEGIN_NAMESPACE
64
65void qt_format_text(const QFont &fnt, const QRectF &_r,
66 int tf, const QTextOption *opt, const QString& str, QRectF *brect,
67 int tabstops, int *, int tabarraylen,
68 QPainter *painter);
69
70/*!
71 \class QPicture
72 \brief The QPicture class is a paint device that records and
73 replays QPainter commands.
74
75 \inmodule QtGui
76 \ingroup shared
77
78
79 A picture serializes painter commands to an IO device in a
80 platform-independent format. They are sometimes referred to as meta-files.
81
82 Qt pictures use a proprietary binary format. Unlike native picture
83 (meta-file) formats on many window systems, Qt pictures have no
84 limitations regarding their contents. Everything that can be
85 painted on a widget or pixmap (e.g., fonts, pixmaps, regions,
86 transformed graphics, etc.) can also be stored in a picture.
87
88 QPicture is resolution independent, i.e. a QPicture can be
89 displayed on different devices (for example svg, pdf, ps, printer
90 and screen) looking the same. This is, for instance, needed for
91 WYSIWYG print preview. QPicture runs in the default system dpi,
92 and scales the painter to match differences in resolution
93 depending on the window system.
94
95 Example of how to record a picture:
96 \snippet picture/picture.cpp 0
97
98 Note that the list of painter commands is reset on each call to
99 the QPainter::begin() function.
100
101 Example of how to replay a picture:
102 \snippet picture/picture.cpp 1
103
104 Pictures can also be drawn using play(). Some basic data about a
105 picture is available, for example, size(), isNull() and
106 boundingRect().
107
108 \sa QMovie
109*/
110
111/*!
112 \fn QPicture &QPicture::operator=(QPicture &&other)
113
114 Move-assigns \a other to this QPicture instance.
115
116 \since 5.2
117*/
118
119const char *qt_mfhdr_tag = "QPIC"; // header tag
120static const quint16 mfhdr_maj = QDataStream::Qt_DefaultCompiledVersion; // major version #
121static const quint16 mfhdr_min = 0; // minor version #
122
123/*!
124 Constructs an empty picture.
125
126 The \a formatVersion parameter may be used to \e create a QPicture
127 that can be read by applications that are compiled with earlier
128 versions of Qt.
129
130 Note that the default formatVersion is -1 which signifies the
131 current release, i.e. for Qt 4.0 a formatVersion of 7 is the same
132 as the default formatVersion of -1.
133
134 Reading pictures generated by earlier versions of Qt is not
135 supported in Qt 4.0.
136*/
137
138QPicture::QPicture(int formatVersion)
139 : QPaintDevice(),
140 d_ptr(new QPicturePrivate)
141{
142 Q_D(QPicture);
143
144 if (formatVersion == 0)
145 qWarning("QPicture: invalid format version 0");
146
147 // still accept the 0 default from before Qt 3.0.
148 if (formatVersion > 0 && formatVersion != (int)mfhdr_maj) {
149 d->formatMajor = formatVersion;
150 d->formatMinor = 0;
151 d->formatOk = false;
152 } else {
153 d->resetFormat();
154 }
155}
156
157/*!
158 Constructs a copy of \a pic.
159
160 This constructor is fast thanks to \l{implicit sharing}.
161*/
162
163QPicture::QPicture(const QPicture &pic)
164 : QPaintDevice(), d_ptr(pic.d_ptr)
165{
166}
167
168/*! \internal */
169QPicture::QPicture(QPicturePrivate &dptr)
170 : QPaintDevice(),
171 d_ptr(&dptr)
172{
173}
174
175/*!
176 Destroys the picture.
177*/
178QPicture::~QPicture()
179{
180}
181
182/*!
183 \internal
184*/
185int QPicture::devType() const
186{
187 return QInternal::Picture;
188}
189
190/*!
191 \fn bool QPicture::isNull() const
192
193 Returns \c true if the picture contains no data; otherwise returns
194 false.
195*/
196
197/*!
198 \fn uint QPicture::size() const
199
200 Returns the size of the picture data.
201
202 \sa data()
203*/
204
205/*!
206 \fn const char* QPicture::data() const
207
208 Returns a pointer to the picture data. The pointer is only valid
209 until the next non-const function is called on this picture. The
210 returned pointer is 0 if the picture contains no data.
211
212 \sa size(), isNull()
213*/
214
215
216bool QPicture::isNull() const
217{
218 return d_func()->pictb.buffer().isNull();
219}
220
221uint QPicture::size() const
222{
223 return d_func()->pictb.buffer().size();
224}
225
226const char* QPicture::data() const
227{
228 return d_func()->pictb.buffer();
229}
230
231void QPicture::detach()
232{
233 d_ptr.detach();
234}
235
236bool QPicture::isDetached() const
237{
238 return d_func()->ref.loadRelaxed() == 1;
239}
240
241/*!
242 Sets the picture data directly from \a data and \a size. This
243 function copies the input data.
244
245 \sa data(), size()
246*/
247
248void QPicture::setData(const char* data, uint size)
249{
250 detach();
251 d_func()->pictb.setData(data, size);
252 d_func()->resetFormat(); // we'll have to check
253}
254
255
256/*!
257 Loads a picture from the file specified by \a fileName and returns
258 true if successful; otherwise invalidates the picture and returns \c false.
259
260 \sa save()
261*/
262
263bool QPicture::load(const QString &fileName)
264{
265 QFile f(fileName);
266 if (!f.open(QIODevice::ReadOnly)) {
267 operator=(QPicture());
268 return false;
269 }
270 return load(&f);
271}
272
273/*!
274 \overload
275
276 \a dev is the device to use for loading.
277*/
278
279bool QPicture::load(QIODevice *dev)
280{
281 detach();
282 QByteArray a = dev->readAll();
283
284 d_func()->pictb.setData(a); // set byte array in buffer
285 return d_func()->checkFormat();
286}
287
288/*!
289 Saves a picture to the file specified by \a fileName and returns
290 true if successful; otherwise returns \c false.
291
292 \sa load()
293*/
294
295bool QPicture::save(const QString &fileName)
296{
297 if (paintingActive()) {
298 qWarning("QPicture::save: still being painted on. "
299 "Call QPainter::end() first");
300 return false;
301 }
302
303 QFile f(fileName);
304 if (!f.open(QIODevice::WriteOnly))
305 return false;
306 return save(&f);
307}
308
309/*!
310 \overload
311
312 \a dev is the device to use for saving.
313*/
314
315bool QPicture::save(QIODevice *dev)
316{
317 if (paintingActive()) {
318 qWarning("QPicture::save: still being painted on. "
319 "Call QPainter::end() first");
320 return false;
321 }
322
323 dev->write(d_func()->pictb.buffer(), d_func()->pictb.buffer().size());
324 return true;
325}
326
327/*!
328 Returns the picture's bounding rectangle or an invalid rectangle
329 if the picture contains no data.
330*/
331
332QRect QPicture::boundingRect() const
333{
334 Q_D(const QPicture);
335 // Use override rect where possible.
336 if (!d->override_rect.isEmpty())
337 return d->override_rect;
338
339 if (!d->formatOk)
340 d_ptr->checkFormat();
341
342 return d->brect;
343}
344
345/*!
346 Sets the picture's bounding rectangle to \a r. The automatically
347 calculated value is overridden.
348*/
349
350void QPicture::setBoundingRect(const QRect &r)
351{
352 d_func()->override_rect = r;
353}
354
355/*!
356 Replays the picture using \a painter, and returns \c true if
357 successful; otherwise returns \c false.
358
359 This function does exactly the same as QPainter::drawPicture()
360 with (x, y) = (0, 0).
361*/
362
363bool QPicture::play(QPainter *painter)
364{
365 Q_D(QPicture);
366
367 if (d->pictb.size() == 0) // nothing recorded
368 return true;
369
370 if (!d->formatOk && !d->checkFormat())
371 return false;
372
373 d->pictb.open(QIODevice::ReadOnly); // open buffer device
374 QDataStream s;
375 s.setDevice(&d->pictb); // attach data stream to buffer
376 s.device()->seek(10); // go directly to the data
377 s.setVersion(d->formatMajor == 4 ? 3 : d->formatMajor);
378
379 quint8 c, clen;
380 quint32 nrecords;
381 s >> c >> clen;
382 Q_ASSERT(c == QPicturePrivate::PdcBegin);
383 // bounding rect was introduced in ver 4. Read in checkFormat().
384 if (d->formatMajor >= 4) {
385 qint32 dummy;
386 s >> dummy >> dummy >> dummy >> dummy;
387 }
388 s >> nrecords;
389 if (!exec(painter, s, nrecords)) {
390 qWarning("QPicture::play: Format error");
391 d->pictb.close();
392 return false;
393 }
394 d->pictb.close();
395 return true; // no end-command
396}
397
398
399//
400// QFakeDevice is used to create fonts with a custom DPI
401//
402class QFakeDevice : public QPaintDevice
403{
404public:
405 QFakeDevice() { dpi_x = qt_defaultDpiX(); dpi_y = qt_defaultDpiY(); }
406 void setDpiX(int dpi) { dpi_x = dpi; }
407 void setDpiY(int dpi) { dpi_y = dpi; }
408 QPaintEngine *paintEngine() const override { return nullptr; }
409 int metric(PaintDeviceMetric m) const override
410 {
411 switch(m) {
412 case PdmPhysicalDpiX:
413 case PdmDpiX:
414 return dpi_x;
415 case PdmPhysicalDpiY:
416 case PdmDpiY:
417 return dpi_y;
418 default:
419 return QPaintDevice::metric(m);
420 }
421 }
422
423private:
424 int dpi_x;
425 int dpi_y;
426};
427
428/*!
429 \internal
430 Iterates over the internal picture data and draws the picture using
431 \a painter.
432*/
433
434bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
435{
436 Q_D(QPicture);
437#if defined(QT_DEBUG)
438 int strm_pos;
439#endif
440 quint8 c; // command id
441 quint8 tiny_len; // 8-bit length descriptor
442 qint32 len; // 32-bit length descriptor
443 qint16 i_16, i1_16, i2_16; // parameters...
444 qint8 i_8;
445 quint32 ul;
446 double dbl;
447 bool bl;
448 QByteArray str1;
449 QString str;
450 QPointF p, p1, p2;
451 QPoint ip, ip1, ip2;
452 QRect ir;
453 QRectF r;
454 QPolygonF a;
455 QPolygon ia;
456 QColor color;
457 QFont font;
458 QPen pen;
459 QBrush brush;
460 QRegion rgn;
461 qreal wmatrix[6];
462 QTransform matrix;
463
464 QTransform worldMatrix = painter->transform();
465 worldMatrix.scale(qreal(painter->device()->logicalDpiX()) / qreal(qt_defaultDpiX()),
466 qreal(painter->device()->logicalDpiY()) / qreal(qt_defaultDpiY()));
467 painter->setTransform(worldMatrix);
468
469 while (nrecords-- && !s.atEnd()) {
470 s >> c; // read cmd
471 s >> tiny_len; // read param length
472 if (tiny_len == 255) // longer than 254 bytes
473 s >> len;
474 else
475 len = tiny_len;
476#if defined(QT_DEBUG)
477 strm_pos = s.device()->pos();
478#endif
479 switch (c) { // exec cmd
480 case QPicturePrivate::PdcNOP:
481 break;
482 case QPicturePrivate::PdcDrawPoint:
483 if (d->formatMajor <= 5) {
484 s >> ip;
485 painter->drawPoint(ip);
486 } else {
487 s >> p;
488 painter->drawPoint(p);
489 }
490 break;
491 case QPicturePrivate::PdcDrawPoints:
492// ## implement me in the picture paint engine
493// s >> a >> i1_32 >> i2_32;
494// painter->drawPoints(a.mid(i1_32, i2_32));
495 break;
496 case QPicturePrivate::PdcDrawPath: {
497 QPainterPath path;
498 s >> path;
499 painter->drawPath(path);
500 break;
501 }
502 case QPicturePrivate::PdcDrawLine:
503 if (d->formatMajor <= 5) {
504 s >> ip1 >> ip2;
505 painter->drawLine(ip1, ip2);
506 } else {
507 s >> p1 >> p2;
508 painter->drawLine(p1, p2);
509 }
510 break;
511 case QPicturePrivate::PdcDrawRect:
512 if (d->formatMajor <= 5) {
513 s >> ir;
514 painter->drawRect(ir);
515 } else {
516 s >> r;
517 painter->drawRect(r);
518 }
519 break;
520 case QPicturePrivate::PdcDrawRoundRect:
521 if (d->formatMajor <= 5) {
522 s >> ir >> i1_16 >> i2_16;
523 painter->drawRoundedRect(ir, i1_16, i2_16, Qt::RelativeSize);
524 } else {
525 s >> r >> i1_16 >> i2_16;
526 painter->drawRoundedRect(r, i1_16, i2_16, Qt::RelativeSize);
527 }
528 break;
529 case QPicturePrivate::PdcDrawEllipse:
530 if (d->formatMajor <= 5) {
531 s >> ir;
532 painter->drawEllipse(ir);
533 } else {
534 s >> r;
535 painter->drawEllipse(r);
536 }
537 break;
538 case QPicturePrivate::PdcDrawArc:
539 if (d->formatMajor <= 5) {
540 s >> ir;
541 r = ir;
542 } else {
543 s >> r;
544 }
545 s >> i1_16 >> i2_16;
546 painter->drawArc(r, i1_16, i2_16);
547 break;
548 case QPicturePrivate::PdcDrawPie:
549 if (d->formatMajor <= 5) {
550 s >> ir;
551 r = ir;
552 } else {
553 s >> r;
554 }
555 s >> i1_16 >> i2_16;
556 painter->drawPie(r, i1_16, i2_16);
557 break;
558 case QPicturePrivate::PdcDrawChord:
559 if (d->formatMajor <= 5) {
560 s >> ir;
561 r = ir;
562 } else {
563 s >> r;
564 }
565 s >> i1_16 >> i2_16;
566 painter->drawChord(r, i1_16, i2_16);
567 break;
568 case QPicturePrivate::PdcDrawLineSegments:
569 s >> ia;
570 painter->drawLines(ia);
571 ia.clear();
572 break;
573 case QPicturePrivate::PdcDrawPolyline:
574 if (d->formatMajor <= 5) {
575 s >> ia;
576 painter->drawPolyline(ia);
577 ia.clear();
578 } else {
579 s >> a;
580 painter->drawPolyline(a);
581 a.clear();
582 }
583 break;
584 case QPicturePrivate::PdcDrawPolygon:
585 if (d->formatMajor <= 5) {
586 s >> ia >> i_8;
587 painter->drawPolygon(ia, i_8 ? Qt::WindingFill : Qt::OddEvenFill);
588 ia.clear();
589 } else {
590 s >> a >> i_8;
591 painter->drawPolygon(a, i_8 ? Qt::WindingFill : Qt::OddEvenFill);
592 a.clear();
593 }
594 break;
595 case QPicturePrivate::PdcDrawCubicBezier: {
596 s >> ia;
597 QPainterPath path;
598 Q_ASSERT(ia.size() == 4);
599 path.moveTo(ia.value(0));
600 path.cubicTo(ia.value(1), ia.value(2), ia.value(3));
601 painter->strokePath(path, painter->pen());
602 ia.clear();
603 }
604 break;
605 case QPicturePrivate::PdcDrawText:
606 s >> ip >> str1;
607 painter->drawText(ip, QString::fromLatin1(str1));
608 break;
609 case QPicturePrivate::PdcDrawTextFormatted:
610 s >> ir >> i_16 >> str1;
611 painter->drawText(ir, i_16, QString::fromLatin1(str1));
612 break;
613 case QPicturePrivate::PdcDrawText2:
614 if (d->formatMajor <= 5) {
615 s >> ip >> str;
616 painter->drawText(ip, str);
617 } else {
618 s >> p >> str;
619 painter->drawText(p, str);
620 }
621 break;
622 case QPicturePrivate::PdcDrawText2Formatted:
623 s >> ir;
624 s >> i_16;
625 s >> str;
626 painter->drawText(ir, i_16, str);
627 break;
628 case QPicturePrivate::PdcDrawTextItem: {
629 s >> p >> str >> font >> ul;
630
631 // the text layout direction is not used here because it's already
632 // aligned when QPicturePaintEngine::drawTextItem() serializes the
633 // drawText() call, therefore ul is unsed in this context
634
635 if (d->formatMajor >= 9) {
636 s >> dbl;
637 QFont fnt(font);
638 if (dbl != 1.0) {
639 QFakeDevice fake;
640 fake.setDpiX(qRound(dbl*qt_defaultDpiX()));
641 fake.setDpiY(qRound(dbl*qt_defaultDpiY()));
642 fnt = QFont(font, &fake);
643 }
644
645 qreal justificationWidth;
646 s >> justificationWidth;
647
648 int flags = Qt::TextSingleLine | Qt::TextDontClip | Qt::TextForceLeftToRight;
649
650 QSizeF size(1, 1);
651 if (justificationWidth > 0) {
652 size.setWidth(justificationWidth);
653 flags |= Qt::TextJustificationForced;
654 flags |= Qt::AlignJustify;
655 }
656
657 QFontMetrics fm(fnt);
658 QPointF pt(p.x(), p.y() - fm.ascent());
659 qt_format_text(fnt, QRectF(pt, size), flags, /*opt*/nullptr,
660 str, /*brect=*/nullptr, /*tabstops=*/0, /*...*/nullptr, /*tabarraylen=*/0, painter);
661 } else {
662 qt_format_text(font, QRectF(p, QSizeF(1, 1)), Qt::TextSingleLine | Qt::TextDontClip, /*opt*/nullptr,
663 str, /*brect=*/nullptr, /*tabstops=*/0, /*...*/nullptr, /*tabarraylen=*/0, painter);
664 }
665
666 break;
667 }
668 case QPicturePrivate::PdcDrawPixmap: {
669 QPixmap pixmap;
670 if (d->formatMajor < 4) {
671 s >> ip >> pixmap;
672 painter->drawPixmap(ip, pixmap);
673 } else if (d->formatMajor <= 5) {
674 s >> ir >> pixmap;
675 painter->drawPixmap(ir, pixmap);
676 } else {
677 QRectF sr;
678 if (d->in_memory_only) {
679 int index;
680 s >> r >> index >> sr;
681 Q_ASSERT(index < d->pixmap_list.size());
682 pixmap = d->pixmap_list.value(index);
683 } else {
684 s >> r >> pixmap >> sr;
685 }
686 painter->drawPixmap(r, pixmap, sr);
687 }
688 }
689 break;
690 case QPicturePrivate::PdcDrawTiledPixmap: {
691 QPixmap pixmap;
692 if (d->in_memory_only) {
693 int index;
694 s >> r >> index >> p;
695 Q_ASSERT(index < d->pixmap_list.size());
696 pixmap = d->pixmap_list.value(index);
697 } else {
698 s >> r >> pixmap >> p;
699 }
700 painter->drawTiledPixmap(r, pixmap, p);
701 }
702 break;
703 case QPicturePrivate::PdcDrawImage: {
704 QImage image;
705 if (d->formatMajor < 4) {
706 s >> p >> image;
707 painter->drawImage(p, image);
708 } else if (d->formatMajor <= 5){
709 s >> ir >> image;
710 painter->drawImage(ir, image, QRect(0, 0, ir.width(), ir.height()));
711 } else {
712 QRectF sr;
713 if (d->in_memory_only) {
714 int index;
715 s >> r >> index >> sr >> ul;
716 Q_ASSERT(index < d->image_list.size());
717 image = d->image_list.value(index);
718 } else {
719 s >> r >> image >> sr >> ul;
720 }
721 painter->drawImage(r, image, sr, Qt::ImageConversionFlags(ul));
722 }
723 }
724 break;
725 case QPicturePrivate::PdcBegin:
726 s >> ul; // number of records
727 if (!exec(painter, s, ul))
728 return false;
729 break;
730 case QPicturePrivate::PdcEnd:
731 if (nrecords == 0)
732 return true;
733 break;
734 case QPicturePrivate::PdcSave:
735 painter->save();
736 break;
737 case QPicturePrivate::PdcRestore:
738 painter->restore();
739 break;
740 case QPicturePrivate::PdcSetBkColor:
741 s >> color;
742 painter->setBackground(color);
743 break;
744 case QPicturePrivate::PdcSetBkMode:
745 s >> i_8;
746 painter->setBackgroundMode((Qt::BGMode)i_8);
747 break;
748 case QPicturePrivate::PdcSetROP: // NOP
749 s >> i_8;
750 break;
751 case QPicturePrivate::PdcSetBrushOrigin:
752 if (d->formatMajor <= 5) {
753 s >> ip;
754 painter->setBrushOrigin(ip);
755 } else {
756 s >> p;
757 painter->setBrushOrigin(p);
758 }
759 break;
760 case QPicturePrivate::PdcSetFont:
761 s >> font;
762 painter->setFont(font);
763 break;
764 case QPicturePrivate::PdcSetPen:
765 if (d->in_memory_only) {
766 int index;
767 s >> index;
768 Q_ASSERT(index < d->pen_list.size());
769 pen = d->pen_list.value(index);
770 } else {
771 s >> pen;
772 }
773 painter->setPen(pen);
774 break;
775 case QPicturePrivate::PdcSetBrush:
776 if (d->in_memory_only) {
777 int index;
778 s >> index;
779 Q_ASSERT(index < d->brush_list.size());
780 brush = d->brush_list.value(index);
781 } else {
782 s >> brush;
783 }
784 painter->setBrush(brush);
785 break;
786 case QPicturePrivate::PdcSetVXform:
787 s >> i_8;
788 painter->setViewTransformEnabled(i_8);
789 break;
790 case QPicturePrivate::PdcSetWindow:
791 if (d->formatMajor <= 5) {
792 s >> ir;
793 painter->setWindow(ir);
794 } else {
795 s >> r;
796 painter->setWindow(r.toRect());
797 }
798 break;
799 case QPicturePrivate::PdcSetViewport:
800 if (d->formatMajor <= 5) {
801 s >> ir;
802 painter->setViewport(ir);
803 } else {
804 s >> r;
805 painter->setViewport(r.toRect());
806 }
807 break;
808 case QPicturePrivate::PdcSetWXform:
809 s >> i_8;
810 painter->setWorldMatrixEnabled(i_8);
811 break;
812 case QPicturePrivate::PdcSetWMatrix:
813 if (d->formatMajor >= 8) {
814 s >> matrix >> i_8;
815 } else {
816 s >> wmatrix[0] >> wmatrix[1]
817 >> wmatrix[2] >> wmatrix[3]
818 >> wmatrix[4] >> wmatrix[5] >> i_8;
819 matrix = QTransform(wmatrix[0], wmatrix[1],
820 wmatrix[2], wmatrix[3],
821 wmatrix[4], wmatrix[5]);
822 }
823 // i_8 is always false due to updateXForm() in qpaintengine_pic.cpp
824 painter->setTransform(matrix * worldMatrix, i_8);
825 break;
826 case QPicturePrivate::PdcSetClip:
827 s >> i_8;
828 painter->setClipping(i_8);
829 break;
830 case QPicturePrivate::PdcSetClipRegion:
831 s >> rgn >> i_8;
832 if (d->formatMajor >= 9) {
833 painter->setClipRegion(rgn, Qt::ClipOperation(i_8));
834 } else {
835 painter->setClipRegion(rgn);
836 }
837 break;
838 case QPicturePrivate::PdcSetClipPath:
839 {
840 QPainterPath path;
841 s >> path >> i_8;
842 painter->setClipPath(path, Qt::ClipOperation(i_8));
843 break;
844 }
845 case QPicturePrivate::PdcSetRenderHint:
846 s >> ul;
847 painter->setRenderHint(QPainter::Antialiasing,
848 bool(ul & QPainter::Antialiasing));
849 painter->setRenderHint(QPainter::SmoothPixmapTransform,
850 bool(ul & QPainter::SmoothPixmapTransform));
851 break;
852 case QPicturePrivate::PdcSetCompositionMode:
853 s >> ul;
854 painter->setCompositionMode((QPainter::CompositionMode)ul);
855 break;
856 case QPicturePrivate::PdcSetClipEnabled:
857 s >> bl;
858 painter->setClipping(bl);
859 break;
860 case QPicturePrivate::PdcSetOpacity:
861 s >> dbl;
862 painter->setOpacity(qreal(dbl));
863 break;
864 default:
865 qWarning("QPicture::play: Invalid command %d", c);
866 if (len > 0) // skip unknown command
867 s.device()->seek(s.device()->pos()+len);
868 }
869#if defined(QT_DEBUG)
870 //qDebug("device->at(): %i, strm_pos: %i len: %i", (int)s.device()->pos(), strm_pos, len);
871 Q_ASSERT(qint32(s.device()->pos() - strm_pos) == len);
872#endif
873 }
874 return false;
875}
876
877/*!
878 \internal
879
880 Internal implementation of the virtual QPaintDevice::metric()
881 function.
882
883 A picture has the following hard-coded values: numcolors=16777216
884 and depth=24.
885
886 \a m is the metric to get.
887*/
888
889int QPicture::metric(PaintDeviceMetric m) const
890{
891 int val;
892 QRect brect = boundingRect();
893 switch (m) {
894 case PdmWidth:
895 val = brect.width();
896 break;
897 case PdmHeight:
898 val = brect.height();
899 break;
900 case PdmWidthMM:
901 val = int(25.4/qt_defaultDpiX()*brect.width());
902 break;
903 case PdmHeightMM:
904 val = int(25.4/qt_defaultDpiY()*brect.height());
905 break;
906 case PdmDpiX:
907 case PdmPhysicalDpiX:
908 val = qt_defaultDpiX();
909 break;
910 case PdmDpiY:
911 case PdmPhysicalDpiY:
912 val = qt_defaultDpiY();
913 break;
914 case PdmNumColors:
915 val = 16777216;
916 break;
917 case PdmDepth:
918 val = 24;
919 break;
920 case PdmDevicePixelRatio:
921 val = 1;
922 break;
923 case PdmDevicePixelRatioScaled:
924 val = 1 * QPaintDevice::devicePixelRatioFScale();
925 break;
926 default:
927 val = 0;
928 qWarning("QPicture::metric: Invalid metric command");
929 }
930 return val;
931}
932
933/*!
934 \fn void QPicture::detach()
935 \internal
936 Detaches from shared picture data and makes sure that this picture
937 is the only one referring to the data.
938
939 If multiple pictures share common data, this picture makes a copy
940 of the data and detaches itself from the sharing mechanism.
941 Nothing is done if there is just a single reference.
942*/
943
944/*! \fn bool QPicture::isDetached() const
945\internal
946*/
947
948/*!
949 Assigns picture \a p to this picture and returns a reference to
950 this picture.
951*/
952QPicture& QPicture::operator=(const QPicture &p)
953{
954 d_ptr = p.d_ptr;
955 return *this;
956}
957
958/*!
959 \fn void QPicture::swap(QPicture &other)
960 \since 4.8
961
962 Swaps picture \a other with this picture. This operation is very
963 fast and never fails.
964*/
965
966/*!
967 \internal
968
969 Constructs a QPicturePrivate
970*/
971QPicturePrivate::QPicturePrivate()
972 : in_memory_only(false)
973{
974}
975
976/*!
977 \internal
978
979 Copy-Constructs a QPicturePrivate. Needed when detaching.
980*/
981QPicturePrivate::QPicturePrivate(const QPicturePrivate &other)
982 : trecs(other.trecs),
983 formatOk(other.formatOk),
984 formatMinor(other.formatMinor),
985 brect(other.brect),
986 override_rect(other.override_rect),
987 in_memory_only(false)
988{
989 pictb.setData(other.pictb.data(), other.pictb.size());
990 if (other.pictb.isOpen()) {
991 pictb.open(other.pictb.openMode());
992 pictb.seek(other.pictb.pos());
993 }
994}
995
996/*!
997 \internal
998
999 Sets formatOk to false and resets the format version numbers to default
1000*/
1001
1002void QPicturePrivate::resetFormat()
1003{
1004 formatOk = false;
1005 formatMajor = mfhdr_maj;
1006 formatMinor = mfhdr_min;
1007}
1008
1009
1010/*!
1011 \internal
1012
1013 Checks data integrity and format version number. Set formatOk to
1014 true on success, to false otherwise. Returns the resulting formatOk
1015 value.
1016*/
1017bool QPicturePrivate::checkFormat()
1018{
1019 resetFormat();
1020
1021 // can't check anything in an empty buffer
1022 if (pictb.size() == 0 || pictb.isOpen())
1023 return false;
1024
1025 pictb.open(QIODevice::ReadOnly); // open buffer device
1026 QDataStream s;
1027 s.setDevice(&pictb); // attach data stream to buffer
1028
1029 char mf_id[4]; // picture header tag
1030 s.readRawData(mf_id, 4); // read actual tag
1031 int bufSize = pictb.buffer().size();
1032 if (memcmp(mf_id, qt_mfhdr_tag, 4) != 0 || bufSize < 12) { // wrong header id or size
1033 qWarning("QPicturePaintEngine::checkFormat: Incorrect header");
1034 pictb.close();
1035 return false;
1036 }
1037
1038 int cs_start = sizeof(quint32); // pos of checksum word
1039 int data_start = cs_start + sizeof(quint16);
1040 quint16 cs,ccs;
1041 const QByteArray buf = pictb.buffer(); // pointer to data
1042
1043 s >> cs; // read checksum
1044 ccs = (quint16) qChecksum(QByteArrayView(buf.constData() + data_start, buf.size() - data_start));
1045 if (ccs != cs) {
1046 qWarning("QPicturePaintEngine::checkFormat: Invalid checksum %x, %x expected",
1047 ccs, cs);
1048 pictb.close();
1049 return false;
1050 }
1051
1052 quint16 major, minor;
1053 s >> major >> minor; // read version number
1054 if (major > mfhdr_maj) { // new, incompatible version
1055 qWarning("QPicturePaintEngine::checkFormat: Incompatible version %d.%d",
1056 major, minor);
1057 pictb.close();
1058 return false;
1059 }
1060 s.setVersion(major != 4 ? major : 3);
1061
1062 quint8 c, clen;
1063 s >> c >> clen;
1064 if (c == QPicturePrivate::PdcBegin) {
1065 if (!(major >= 1 && major <= 3)) {
1066 qint32 l, t, w, h;
1067 s >> l >> t >> w >> h;
1068 brect = QRect(l, t, w, h);
1069 }
1070 } else {
1071 qWarning("QPicturePaintEngine::checkFormat: Format error");
1072 pictb.close();
1073 return false;
1074 }
1075 pictb.close();
1076
1077 formatOk = true; // picture seems to be ok
1078 formatMajor = major;
1079 formatMinor = minor;
1080 return true;
1081}
1082
1083/*! \internal */
1084QPaintEngine *QPicture::paintEngine() const
1085{
1086 if (!d_func()->paintEngine)
1087 const_cast<QPicture*>(this)->d_func()->paintEngine.reset(new QPicturePaintEngine);
1088 return d_func()->paintEngine.data();
1089}
1090
1091/*****************************************************************************
1092 QPicture stream functions
1093 *****************************************************************************/
1094
1095#ifndef QT_NO_DATASTREAM
1096/*!
1097 \relates QPicture
1098
1099 Writes picture \a r to the stream \a s and returns a reference to
1100 the stream.
1101*/
1102
1103QDataStream &operator<<(QDataStream &s, const QPicture &r)
1104{
1105 quint32 size = r.d_func()->pictb.buffer().size();
1106 s << size;
1107 // null picture ?
1108 if (size == 0)
1109 return s;
1110 // just write the whole buffer to the stream
1111 s.writeRawData (r.d_func()->pictb.buffer(), r.d_func()->pictb.buffer().size());
1112 return s;
1113}
1114
1115/*!
1116 \relates QPicture
1117
1118 Reads a picture from the stream \a s into picture \a r and returns
1119 a reference to the stream.
1120*/
1121
1122QDataStream &operator>>(QDataStream &s, QPicture &r)
1123{
1124 QDataStream sr;
1125
1126 // "init"; this code is similar to the beginning of QPicture::cmd()
1127 sr.setDevice(&r.d_func()->pictb);
1128 sr.setVersion(r.d_func()->formatMajor);
1129 quint32 len;
1130 s >> len;
1131 QByteArray data;
1132 if (len > 0) {
1133 data.resize(len);
1134 s.readRawData(data.data(), len);
1135 }
1136
1137 r.d_func()->pictb.setData(data);
1138 r.d_func()->resetFormat();
1139 return s;
1140}
1141#endif // QT_NO_DATASTREAM
1142
1143QT_END_NAMESPACE
1144
1145#endif // QT_NO_PICTURE
1146
1147/*!
1148 \typedef QPicture::DataPtr
1149 \internal
1150*/
1151
1152/*!
1153 \fn DataPtr &QPicture::data_ptr()
1154 \internal
1155*/
1156