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 \note The state of the painter isn't preserved by this function.
363*/
364
365bool QPicture::play(QPainter *painter)
366{
367 Q_D(QPicture);
368
369 if (d->pictb.size() == 0) // nothing recorded
370 return true;
371
372 if (!d->formatOk && !d->checkFormat())
373 return false;
374
375 d->pictb.open(QIODevice::ReadOnly); // open buffer device
376 QDataStream s;
377 s.setDevice(&d->pictb); // attach data stream to buffer
378 s.device()->seek(10); // go directly to the data
379 s.setVersion(d->formatMajor == 4 ? 3 : d->formatMajor);
380
381 quint8 c, clen;
382 quint32 nrecords;
383 s >> c >> clen;
384 Q_ASSERT(c == QPicturePrivate::PdcBegin);
385 // bounding rect was introduced in ver 4. Read in checkFormat().
386 if (d->formatMajor >= 4) {
387 qint32 dummy;
388 s >> dummy >> dummy >> dummy >> dummy;
389 }
390 s >> nrecords;
391 if (!exec(painter, s, nrecords)) {
392 qWarning("QPicture::play: Format error");
393 d->pictb.close();
394 return false;
395 }
396 d->pictb.close();
397 return true; // no end-command
398}
399
400
401//
402// QFakeDevice is used to create fonts with a custom DPI
403//
404class QFakeDevice : public QPaintDevice
405{
406public:
407 QFakeDevice() { dpi_x = qt_defaultDpiX(); dpi_y = qt_defaultDpiY(); }
408 void setDpiX(int dpi) { dpi_x = dpi; }
409 void setDpiY(int dpi) { dpi_y = dpi; }
410 QPaintEngine *paintEngine() const override { return nullptr; }
411 int metric(PaintDeviceMetric m) const override
412 {
413 switch(m) {
414 case PdmPhysicalDpiX:
415 case PdmDpiX:
416 return dpi_x;
417 case PdmPhysicalDpiY:
418 case PdmDpiY:
419 return dpi_y;
420 default:
421 return QPaintDevice::metric(m);
422 }
423 }
424
425private:
426 int dpi_x;
427 int dpi_y;
428};
429
430/*!
431 \internal
432 Iterates over the internal picture data and draws the picture using
433 \a painter.
434*/
435
436bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
437{
438 Q_D(QPicture);
439#if defined(QT_DEBUG)
440 int strm_pos;
441#endif
442 quint8 c; // command id
443 quint8 tiny_len; // 8-bit length descriptor
444 qint32 len; // 32-bit length descriptor
445 qint16 i_16, i1_16, i2_16; // parameters...
446 qint8 i_8;
447 quint32 ul;
448 double dbl;
449 bool bl;
450 QByteArray str1;
451 QString str;
452 QPointF p, p1, p2;
453 QPoint ip, ip1, ip2;
454 QRect ir;
455 QRectF r;
456 QPolygonF a;
457 QPolygon ia;
458 QColor color;
459 QFont font;
460 QPen pen;
461 QBrush brush;
462 QRegion rgn;
463 qreal wmatrix[6];
464 QTransform matrix;
465
466 QTransform worldMatrix = painter->transform();
467 worldMatrix.scale(qreal(painter->device()->logicalDpiX()) / qreal(qt_defaultDpiX()),
468 qreal(painter->device()->logicalDpiY()) / qreal(qt_defaultDpiY()));
469 painter->setTransform(worldMatrix);
470
471 while (nrecords-- && !s.atEnd()) {
472 s >> c; // read cmd
473 s >> tiny_len; // read param length
474 if (tiny_len == 255) // longer than 254 bytes
475 s >> len;
476 else
477 len = tiny_len;
478#if defined(QT_DEBUG)
479 strm_pos = s.device()->pos();
480#endif
481 switch (c) { // exec cmd
482 case QPicturePrivate::PdcNOP:
483 break;
484 case QPicturePrivate::PdcDrawPoint:
485 if (d->formatMajor <= 5) {
486 s >> ip;
487 painter->drawPoint(ip);
488 } else {
489 s >> p;
490 painter->drawPoint(p);
491 }
492 break;
493 case QPicturePrivate::PdcDrawPoints:
494// ## implement me in the picture paint engine
495// s >> a >> i1_32 >> i2_32;
496// painter->drawPoints(a.mid(i1_32, i2_32));
497 break;
498 case QPicturePrivate::PdcDrawPath: {
499 QPainterPath path;
500 s >> path;
501 painter->drawPath(path);
502 break;
503 }
504 case QPicturePrivate::PdcDrawLine:
505 if (d->formatMajor <= 5) {
506 s >> ip1 >> ip2;
507 painter->drawLine(ip1, ip2);
508 } else {
509 s >> p1 >> p2;
510 painter->drawLine(p1, p2);
511 }
512 break;
513 case QPicturePrivate::PdcDrawRect:
514 if (d->formatMajor <= 5) {
515 s >> ir;
516 painter->drawRect(ir);
517 } else {
518 s >> r;
519 painter->drawRect(r);
520 }
521 break;
522 case QPicturePrivate::PdcDrawRoundRect:
523 if (d->formatMajor <= 5) {
524 s >> ir >> i1_16 >> i2_16;
525 painter->drawRoundedRect(ir, i1_16, i2_16, Qt::RelativeSize);
526 } else {
527 s >> r >> i1_16 >> i2_16;
528 painter->drawRoundedRect(r, i1_16, i2_16, Qt::RelativeSize);
529 }
530 break;
531 case QPicturePrivate::PdcDrawEllipse:
532 if (d->formatMajor <= 5) {
533 s >> ir;
534 painter->drawEllipse(ir);
535 } else {
536 s >> r;
537 painter->drawEllipse(r);
538 }
539 break;
540 case QPicturePrivate::PdcDrawArc:
541 if (d->formatMajor <= 5) {
542 s >> ir;
543 r = ir;
544 } else {
545 s >> r;
546 }
547 s >> i1_16 >> i2_16;
548 painter->drawArc(r, i1_16, i2_16);
549 break;
550 case QPicturePrivate::PdcDrawPie:
551 if (d->formatMajor <= 5) {
552 s >> ir;
553 r = ir;
554 } else {
555 s >> r;
556 }
557 s >> i1_16 >> i2_16;
558 painter->drawPie(r, i1_16, i2_16);
559 break;
560 case QPicturePrivate::PdcDrawChord:
561 if (d->formatMajor <= 5) {
562 s >> ir;
563 r = ir;
564 } else {
565 s >> r;
566 }
567 s >> i1_16 >> i2_16;
568 painter->drawChord(r, i1_16, i2_16);
569 break;
570 case QPicturePrivate::PdcDrawLineSegments:
571 s >> ia;
572 painter->drawLines(ia);
573 ia.clear();
574 break;
575 case QPicturePrivate::PdcDrawPolyline:
576 if (d->formatMajor <= 5) {
577 s >> ia;
578 painter->drawPolyline(ia);
579 ia.clear();
580 } else {
581 s >> a;
582 painter->drawPolyline(a);
583 a.clear();
584 }
585 break;
586 case QPicturePrivate::PdcDrawPolygon:
587 if (d->formatMajor <= 5) {
588 s >> ia >> i_8;
589 painter->drawPolygon(ia, i_8 ? Qt::WindingFill : Qt::OddEvenFill);
590 ia.clear();
591 } else {
592 s >> a >> i_8;
593 painter->drawPolygon(a, i_8 ? Qt::WindingFill : Qt::OddEvenFill);
594 a.clear();
595 }
596 break;
597 case QPicturePrivate::PdcDrawCubicBezier: {
598 s >> ia;
599 QPainterPath path;
600 Q_ASSERT(ia.size() == 4);
601 path.moveTo(ia.value(0));
602 path.cubicTo(ia.value(1), ia.value(2), ia.value(3));
603 painter->strokePath(path, painter->pen());
604 ia.clear();
605 }
606 break;
607 case QPicturePrivate::PdcDrawText:
608 s >> ip >> str1;
609 painter->drawText(ip, QString::fromLatin1(str1));
610 break;
611 case QPicturePrivate::PdcDrawTextFormatted:
612 s >> ir >> i_16 >> str1;
613 painter->drawText(ir, i_16, QString::fromLatin1(str1));
614 break;
615 case QPicturePrivate::PdcDrawText2:
616 if (d->formatMajor <= 5) {
617 s >> ip >> str;
618 painter->drawText(ip, str);
619 } else {
620 s >> p >> str;
621 painter->drawText(p, str);
622 }
623 break;
624 case QPicturePrivate::PdcDrawText2Formatted:
625 s >> ir;
626 s >> i_16;
627 s >> str;
628 painter->drawText(ir, i_16, str);
629 break;
630 case QPicturePrivate::PdcDrawTextItem: {
631 s >> p >> str >> font >> ul;
632
633 // the text layout direction is not used here because it's already
634 // aligned when QPicturePaintEngine::drawTextItem() serializes the
635 // drawText() call, therefore ul is unsed in this context
636
637 if (d->formatMajor >= 9) {
638 s >> dbl;
639 QFont fnt(font);
640 if (dbl != 1.0) {
641 QFakeDevice fake;
642 fake.setDpiX(qRound(dbl*qt_defaultDpiX()));
643 fake.setDpiY(qRound(dbl*qt_defaultDpiY()));
644 fnt = QFont(font, &fake);
645 }
646
647 qreal justificationWidth;
648 s >> justificationWidth;
649
650 int flags = Qt::TextSingleLine | Qt::TextDontClip | Qt::TextForceLeftToRight;
651
652 QSizeF size(1, 1);
653 if (justificationWidth > 0) {
654 size.setWidth(justificationWidth);
655 flags |= Qt::TextJustificationForced;
656 flags |= Qt::AlignJustify;
657 }
658
659 QFontMetrics fm(fnt);
660 QPointF pt(p.x(), p.y() - fm.ascent());
661 qt_format_text(fnt, QRectF(pt, size), flags, /*opt*/nullptr,
662 str, /*brect=*/nullptr, /*tabstops=*/0, /*...*/nullptr, /*tabarraylen=*/0, painter);
663 } else {
664 qt_format_text(font, QRectF(p, QSizeF(1, 1)), Qt::TextSingleLine | Qt::TextDontClip, /*opt*/nullptr,
665 str, /*brect=*/nullptr, /*tabstops=*/0, /*...*/nullptr, /*tabarraylen=*/0, painter);
666 }
667
668 break;
669 }
670 case QPicturePrivate::PdcDrawPixmap: {
671 QPixmap pixmap;
672 if (d->formatMajor < 4) {
673 s >> ip >> pixmap;
674 painter->drawPixmap(ip, pixmap);
675 } else if (d->formatMajor <= 5) {
676 s >> ir >> pixmap;
677 painter->drawPixmap(ir, pixmap);
678 } else {
679 QRectF sr;
680 if (d->in_memory_only) {
681 int index;
682 s >> r >> index >> sr;
683 Q_ASSERT(index < d->pixmap_list.size());
684 pixmap = d->pixmap_list.value(index);
685 } else {
686 s >> r >> pixmap >> sr;
687 }
688 painter->drawPixmap(r, pixmap, sr);
689 }
690 }
691 break;
692 case QPicturePrivate::PdcDrawTiledPixmap: {
693 QPixmap pixmap;
694 if (d->in_memory_only) {
695 int index;
696 s >> r >> index >> p;
697 Q_ASSERT(index < d->pixmap_list.size());
698 pixmap = d->pixmap_list.value(index);
699 } else {
700 s >> r >> pixmap >> p;
701 }
702 painter->drawTiledPixmap(r, pixmap, p);
703 }
704 break;
705 case QPicturePrivate::PdcDrawImage: {
706 QImage image;
707 if (d->formatMajor < 4) {
708 s >> p >> image;
709 painter->drawImage(p, image);
710 } else if (d->formatMajor <= 5){
711 s >> ir >> image;
712 painter->drawImage(ir, image, QRect(0, 0, ir.width(), ir.height()));
713 } else {
714 QRectF sr;
715 if (d->in_memory_only) {
716 int index;
717 s >> r >> index >> sr >> ul;
718 Q_ASSERT(index < d->image_list.size());
719 image = d->image_list.value(index);
720 } else {
721 s >> r >> image >> sr >> ul;
722 }
723 painter->drawImage(r, image, sr, Qt::ImageConversionFlags(ul));
724 }
725 }
726 break;
727 case QPicturePrivate::PdcBegin:
728 s >> ul; // number of records
729 if (!exec(painter, s, ul))
730 return false;
731 break;
732 case QPicturePrivate::PdcEnd:
733 if (nrecords == 0)
734 return true;
735 break;
736 case QPicturePrivate::PdcSave:
737 painter->save();
738 break;
739 case QPicturePrivate::PdcRestore:
740 painter->restore();
741 break;
742 case QPicturePrivate::PdcSetBkColor:
743 s >> color;
744 painter->setBackground(color);
745 break;
746 case QPicturePrivate::PdcSetBkMode:
747 s >> i_8;
748 painter->setBackgroundMode((Qt::BGMode)i_8);
749 break;
750 case QPicturePrivate::PdcSetROP: // NOP
751 s >> i_8;
752 break;
753 case QPicturePrivate::PdcSetBrushOrigin:
754 if (d->formatMajor <= 5) {
755 s >> ip;
756 painter->setBrushOrigin(ip);
757 } else {
758 s >> p;
759 painter->setBrushOrigin(p);
760 }
761 break;
762 case QPicturePrivate::PdcSetFont:
763 s >> font;
764 painter->setFont(font);
765 break;
766 case QPicturePrivate::PdcSetPen:
767 if (d->in_memory_only) {
768 int index;
769 s >> index;
770 Q_ASSERT(index < d->pen_list.size());
771 pen = d->pen_list.value(index);
772 } else {
773 s >> pen;
774 }
775 painter->setPen(pen);
776 break;
777 case QPicturePrivate::PdcSetBrush:
778 if (d->in_memory_only) {
779 int index;
780 s >> index;
781 Q_ASSERT(index < d->brush_list.size());
782 brush = d->brush_list.value(index);
783 } else {
784 s >> brush;
785 }
786 painter->setBrush(brush);
787 break;
788 case QPicturePrivate::PdcSetVXform:
789 s >> i_8;
790 painter->setViewTransformEnabled(i_8);
791 break;
792 case QPicturePrivate::PdcSetWindow:
793 if (d->formatMajor <= 5) {
794 s >> ir;
795 painter->setWindow(ir);
796 } else {
797 s >> r;
798 painter->setWindow(r.toRect());
799 }
800 break;
801 case QPicturePrivate::PdcSetViewport:
802 if (d->formatMajor <= 5) {
803 s >> ir;
804 painter->setViewport(ir);
805 } else {
806 s >> r;
807 painter->setViewport(r.toRect());
808 }
809 break;
810 case QPicturePrivate::PdcSetWXform:
811 s >> i_8;
812 painter->setWorldMatrixEnabled(i_8);
813 break;
814 case QPicturePrivate::PdcSetWMatrix:
815 if (d->formatMajor >= 8) {
816 s >> matrix >> i_8;
817 } else {
818 s >> wmatrix[0] >> wmatrix[1]
819 >> wmatrix[2] >> wmatrix[3]
820 >> wmatrix[4] >> wmatrix[5] >> i_8;
821 matrix = QTransform(wmatrix[0], wmatrix[1],
822 wmatrix[2], wmatrix[3],
823 wmatrix[4], wmatrix[5]);
824 }
825 // i_8 is always false due to updateXForm() in qpaintengine_pic.cpp
826 painter->setTransform(matrix * worldMatrix, i_8);
827 break;
828 case QPicturePrivate::PdcSetClip:
829 s >> i_8;
830 painter->setClipping(i_8);
831 break;
832 case QPicturePrivate::PdcSetClipRegion:
833 s >> rgn >> i_8;
834 if (d->formatMajor >= 9) {
835 painter->setClipRegion(rgn, Qt::ClipOperation(i_8));
836 } else {
837 painter->setClipRegion(rgn);
838 }
839 break;
840 case QPicturePrivate::PdcSetClipPath:
841 {
842 QPainterPath path;
843 s >> path >> i_8;
844 painter->setClipPath(path, Qt::ClipOperation(i_8));
845 break;
846 }
847 case QPicturePrivate::PdcSetRenderHint:
848 s >> ul;
849 painter->setRenderHint(QPainter::Antialiasing,
850 bool(ul & QPainter::Antialiasing));
851 painter->setRenderHint(QPainter::SmoothPixmapTransform,
852 bool(ul & QPainter::SmoothPixmapTransform));
853 break;
854 case QPicturePrivate::PdcSetCompositionMode:
855 s >> ul;
856 painter->setCompositionMode((QPainter::CompositionMode)ul);
857 break;
858 case QPicturePrivate::PdcSetClipEnabled:
859 s >> bl;
860 painter->setClipping(bl);
861 break;
862 case QPicturePrivate::PdcSetOpacity:
863 s >> dbl;
864 painter->setOpacity(qreal(dbl));
865 break;
866 default:
867 qWarning("QPicture::play: Invalid command %d", c);
868 if (len > 0) // skip unknown command
869 s.device()->seek(s.device()->pos()+len);
870 }
871#if defined(QT_DEBUG)
872 //qDebug("device->at(): %i, strm_pos: %i len: %i", (int)s.device()->pos(), strm_pos, len);
873 Q_ASSERT(qint32(s.device()->pos() - strm_pos) == len);
874#endif
875 }
876 return false;
877}
878
879/*!
880 \internal
881
882 Internal implementation of the virtual QPaintDevice::metric()
883 function.
884
885 A picture has the following hard-coded values: numcolors=16777216
886 and depth=24.
887
888 \a m is the metric to get.
889*/
890
891int QPicture::metric(PaintDeviceMetric m) const
892{
893 int val;
894 QRect brect = boundingRect();
895 switch (m) {
896 case PdmWidth:
897 val = brect.width();
898 break;
899 case PdmHeight:
900 val = brect.height();
901 break;
902 case PdmWidthMM:
903 val = int(25.4/qt_defaultDpiX()*brect.width());
904 break;
905 case PdmHeightMM:
906 val = int(25.4/qt_defaultDpiY()*brect.height());
907 break;
908 case PdmDpiX:
909 case PdmPhysicalDpiX:
910 val = qt_defaultDpiX();
911 break;
912 case PdmDpiY:
913 case PdmPhysicalDpiY:
914 val = qt_defaultDpiY();
915 break;
916 case PdmNumColors:
917 val = 16777216;
918 break;
919 case PdmDepth:
920 val = 24;
921 break;
922 case PdmDevicePixelRatio:
923 val = 1;
924 break;
925 case PdmDevicePixelRatioScaled:
926 val = 1 * QPaintDevice::devicePixelRatioFScale();
927 break;
928 default:
929 val = 0;
930 qWarning("QPicture::metric: Invalid metric command");
931 }
932 return val;
933}
934
935/*!
936 \fn void QPicture::detach()
937 \internal
938 Detaches from shared picture data and makes sure that this picture
939 is the only one referring to the data.
940
941 If multiple pictures share common data, this picture makes a copy
942 of the data and detaches itself from the sharing mechanism.
943 Nothing is done if there is just a single reference.
944*/
945
946/*! \fn bool QPicture::isDetached() const
947\internal
948*/
949
950/*!
951 Assigns picture \a p to this picture and returns a reference to
952 this picture.
953*/
954QPicture& QPicture::operator=(const QPicture &p)
955{
956 d_ptr = p.d_ptr;
957 return *this;
958}
959
960/*!
961 \fn void QPicture::swap(QPicture &other)
962 \since 4.8
963
964 Swaps picture \a other with this picture. This operation is very
965 fast and never fails.
966*/
967
968/*!
969 \internal
970
971 Constructs a QPicturePrivate
972*/
973QPicturePrivate::QPicturePrivate()
974 : in_memory_only(false)
975{
976}
977
978/*!
979 \internal
980
981 Copy-Constructs a QPicturePrivate. Needed when detaching.
982*/
983QPicturePrivate::QPicturePrivate(const QPicturePrivate &other)
984 : trecs(other.trecs),
985 formatOk(other.formatOk),
986 formatMinor(other.formatMinor),
987 brect(other.brect),
988 override_rect(other.override_rect),
989 in_memory_only(false)
990{
991 pictb.setData(other.pictb.data(), other.pictb.size());
992 if (other.pictb.isOpen()) {
993 pictb.open(other.pictb.openMode());
994 pictb.seek(other.pictb.pos());
995 }
996}
997
998/*!
999 \internal
1000
1001 Sets formatOk to false and resets the format version numbers to default
1002*/
1003
1004void QPicturePrivate::resetFormat()
1005{
1006 formatOk = false;
1007 formatMajor = mfhdr_maj;
1008 formatMinor = mfhdr_min;
1009}
1010
1011
1012/*!
1013 \internal
1014
1015 Checks data integrity and format version number. Set formatOk to
1016 true on success, to false otherwise. Returns the resulting formatOk
1017 value.
1018*/
1019bool QPicturePrivate::checkFormat()
1020{
1021 resetFormat();
1022
1023 // can't check anything in an empty buffer
1024 if (pictb.size() == 0 || pictb.isOpen())
1025 return false;
1026
1027 pictb.open(QIODevice::ReadOnly); // open buffer device
1028 QDataStream s;
1029 s.setDevice(&pictb); // attach data stream to buffer
1030
1031 char mf_id[4]; // picture header tag
1032 s.readRawData(mf_id, 4); // read actual tag
1033 int bufSize = pictb.buffer().size();
1034 if (memcmp(mf_id, qt_mfhdr_tag, 4) != 0 || bufSize < 12) { // wrong header id or size
1035 qWarning("QPicturePaintEngine::checkFormat: Incorrect header");
1036 pictb.close();
1037 return false;
1038 }
1039
1040 int cs_start = sizeof(quint32); // pos of checksum word
1041 int data_start = cs_start + sizeof(quint16);
1042 quint16 cs,ccs;
1043 const QByteArray buf = pictb.buffer(); // pointer to data
1044
1045 s >> cs; // read checksum
1046 ccs = (quint16) qChecksum(QByteArrayView(buf.constData() + data_start, buf.size() - data_start));
1047 if (ccs != cs) {
1048 qWarning("QPicturePaintEngine::checkFormat: Invalid checksum %x, %x expected",
1049 ccs, cs);
1050 pictb.close();
1051 return false;
1052 }
1053
1054 quint16 major, minor;
1055 s >> major >> minor; // read version number
1056 if (major > mfhdr_maj) { // new, incompatible version
1057 qWarning("QPicturePaintEngine::checkFormat: Incompatible version %d.%d",
1058 major, minor);
1059 pictb.close();
1060 return false;
1061 }
1062 s.setVersion(major != 4 ? major : 3);
1063
1064 quint8 c, clen;
1065 s >> c >> clen;
1066 if (c == QPicturePrivate::PdcBegin) {
1067 if (!(major >= 1 && major <= 3)) {
1068 qint32 l, t, w, h;
1069 s >> l >> t >> w >> h;
1070 brect = QRect(l, t, w, h);
1071 }
1072 } else {
1073 qWarning("QPicturePaintEngine::checkFormat: Format error");
1074 pictb.close();
1075 return false;
1076 }
1077 pictb.close();
1078
1079 formatOk = true; // picture seems to be ok
1080 formatMajor = major;
1081 formatMinor = minor;
1082 return true;
1083}
1084
1085/*! \internal */
1086QPaintEngine *QPicture::paintEngine() const
1087{
1088 if (!d_func()->paintEngine)
1089 const_cast<QPicture*>(this)->d_func()->paintEngine.reset(new QPicturePaintEngine);
1090 return d_func()->paintEngine.data();
1091}
1092
1093/*****************************************************************************
1094 QPicture stream functions
1095 *****************************************************************************/
1096
1097#ifndef QT_NO_DATASTREAM
1098/*!
1099 \relates QPicture
1100
1101 Writes picture \a r to the stream \a s and returns a reference to
1102 the stream.
1103*/
1104
1105QDataStream &operator<<(QDataStream &s, const QPicture &r)
1106{
1107 quint32 size = r.d_func()->pictb.buffer().size();
1108 s << size;
1109 // null picture ?
1110 if (size == 0)
1111 return s;
1112 // just write the whole buffer to the stream
1113 s.writeRawData (r.d_func()->pictb.buffer(), r.d_func()->pictb.buffer().size());
1114 return s;
1115}
1116
1117/*!
1118 \relates QPicture
1119
1120 Reads a picture from the stream \a s into picture \a r and returns
1121 a reference to the stream.
1122*/
1123
1124QDataStream &operator>>(QDataStream &s, QPicture &r)
1125{
1126 QDataStream sr;
1127
1128 // "init"; this code is similar to the beginning of QPicture::cmd()
1129 sr.setDevice(&r.d_func()->pictb);
1130 sr.setVersion(r.d_func()->formatMajor);
1131 quint32 len;
1132 s >> len;
1133 QByteArray data;
1134 if (len > 0) {
1135 data.resize(len);
1136 s.readRawData(data.data(), len);
1137 }
1138
1139 r.d_func()->pictb.setData(data);
1140 r.d_func()->resetFormat();
1141 return s;
1142}
1143#endif // QT_NO_DATASTREAM
1144
1145QT_END_NAMESPACE
1146
1147#endif // QT_NO_PICTURE
1148
1149/*!
1150 \typedef QPicture::DataPtr
1151 \internal
1152*/
1153
1154/*!
1155 \fn DataPtr &QPicture::data_ptr()
1156 \internal
1157*/
1158