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