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