Coverage Report

Created: 2026-05-16 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/image/qpicture.cpp
Line
Count
Source
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
28
QT_BEGIN_NAMESPACE
29
30
void 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
95
const char  *qt_mfhdr_tag = "QPIC"; // header tag
96
static const quint16 mfhdr_maj = QDataStream::Qt_DefaultCompiledVersion; // major version #
97
static 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
114
QPicture::QPicture(int formatVersion)
115
0
    : QPaintDevice(),
116
0
      d_ptr(new QPicturePrivate)
117
0
{
118
0
    Q_D(QPicture);
119
120
0
    if (formatVersion == 0)
121
0
        qWarning("QPicture: invalid format version 0");
122
123
    // still accept the 0 default from before Qt 3.0.
124
0
    if (formatVersion > 0 && formatVersion != (int)mfhdr_maj) {
125
0
        d->formatMajor = formatVersion;
126
0
        d->formatMinor = 0;
127
0
        d->formatOk = false;
128
0
    } else {
129
0
        d->resetFormat();
130
0
    }
131
0
}
132
133
/*!
134
    Constructs a copy of \a pic.
135
136
    This constructor is fast thanks to \l{implicit sharing}.
137
*/
138
139
QPicture::QPicture(const QPicture &pic)
140
0
    : QPaintDevice(), d_ptr(pic.d_ptr)
141
0
{
142
0
}
143
144
/*! \internal */
145
QPicture::QPicture(QPicturePrivate &dptr)
146
0
    : QPaintDevice(),
147
0
      d_ptr(&dptr)
148
0
{
149
0
}
150
151
/*!
152
    Destroys the picture.
153
*/
154
QPicture::~QPicture()
155
0
{
156
0
}
157
158
/*!
159
  \internal
160
*/
161
int QPicture::devType() const
162
0
{
163
0
    return QInternal::Picture;
164
0
}
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
192
bool QPicture::isNull() const
193
0
{
194
0
    return d_func()->pictb.buffer().isNull();
195
0
}
196
197
uint QPicture::size() const
198
0
{
199
0
    return d_func()->pictb.buffer().size();
200
0
}
201
202
const char* QPicture::data() const
203
0
{
204
0
    return d_func()->pictb.buffer();
205
0
}
206
207
void QPicture::detach()
208
0
{
209
0
    d_ptr.detach();
210
0
}
211
212
bool QPicture::isDetached() const
213
0
{
214
0
    return d_func()->ref.loadRelaxed() == 1;
215
0
}
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
224
void QPicture::setData(const char* data, uint size)
225
0
{
226
0
    detach();
227
0
    d_func()->pictb.setData(data, size);
228
0
    d_func()->resetFormat();                                // we'll have to check
229
0
}
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
239
bool QPicture::load(const QString &fileName)
240
0
{
241
0
    QFile f(fileName);
242
0
    if (!f.open(QIODevice::ReadOnly)) {
243
0
        operator=(QPicture());
244
0
        return false;
245
0
    }
246
0
    return load(&f);
247
0
}
248
249
/*!
250
    \overload
251
252
    \a dev is the device to use for loading.
253
*/
254
255
bool QPicture::load(QIODevice *dev)
256
0
{
257
0
    detach();
258
0
    QByteArray a = dev->readAll();
259
260
0
    d_func()->pictb.setData(a);                        // set byte array in buffer
261
0
    return d_func()->checkFormat();
262
0
}
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
271
bool QPicture::save(const QString &fileName)
272
0
{
273
0
    if (paintingActive()) {
274
0
        qWarning("QPicture::save: still being painted on. "
275
0
                  "Call QPainter::end() first");
276
0
        return false;
277
0
    }
278
279
0
    QFile f(fileName);
280
0
    if (!f.open(QIODevice::WriteOnly))
281
0
        return false;
282
0
    return save(&f);
283
0
}
284
285
/*!
286
    \overload
287
288
    \a dev is the device to use for saving.
289
*/
290
291
bool QPicture::save(QIODevice *dev)
292
0
{
293
0
    if (paintingActive()) {
294
0
        qWarning("QPicture::save: still being painted on. "
295
0
                  "Call QPainter::end() first");
296
0
        return false;
297
0
    }
298
299
0
    dev->write(d_func()->pictb.buffer(), d_func()->pictb.buffer().size());
300
0
    return true;
301
0
}
302
303
/*!
304
    Returns the picture's bounding rectangle or an invalid rectangle
305
    if the picture contains no data.
306
*/
307
308
QRect QPicture::boundingRect() const
309
0
{
310
0
    Q_D(const QPicture);
311
    // Use override rect where possible.
312
0
    if (!d->override_rect.isEmpty())
313
0
        return d->override_rect;
314
315
0
    if (!d->formatOk)
316
0
        d_ptr->checkFormat();
317
318
0
    return d->brect;
319
0
}
320
321
/*!
322
    Sets the picture's bounding rectangle to \a r. The automatically
323
    calculated value is overridden.
324
*/
325
326
void QPicture::setBoundingRect(const QRect &r)
327
0
{
328
0
    d_func()->override_rect = r;
329
0
}
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
341
bool QPicture::play(QPainter *painter)
342
0
{
343
0
    Q_D(QPicture);
344
345
0
    if (d->pictb.size() == 0)                        // nothing recorded
346
0
        return true;
347
348
0
    if (!d->formatOk && !d->checkFormat())
349
0
        return false;
350
351
0
    d->pictb.open(QIODevice::ReadOnly);                // open buffer device
352
0
    QDataStream s;
353
0
    s.setDevice(&d->pictb);                        // attach data stream to buffer
354
0
    s.device()->seek(10);                        // go directly to the data
355
0
    s.setVersion(d->formatMajor == 4 ? 3 : d->formatMajor);
356
357
0
    quint8  c, clen;
358
0
    quint32 nrecords;
359
0
    s >> c >> clen;
360
0
    Q_ASSERT(c == QPicturePrivate::PdcBegin);
361
    // bounding rect was introduced in ver 4. Read in checkFormat().
362
0
    if (d->formatMajor >= 4) {
363
0
        qint32 dummy;
364
0
        s >> dummy >> dummy >> dummy >> dummy;
365
0
    }
366
0
    s >> nrecords;
367
0
    if (!exec(painter, s, nrecords)) {
368
0
        qWarning("QPicture::play: Format error");
369
0
        d->pictb.close();
370
0
        return false;
371
0
    }
372
0
    d->pictb.close();
373
0
    return true;                                // no end-command
374
0
}
375
376
377
//
378
// QFakeDevice is used to create fonts with a custom DPI
379
//
380
class QFakeDevice : public QPaintDevice
381
{
382
public:
383
0
    QFakeDevice() { dpi_x = qt_defaultDpiX(); dpi_y = qt_defaultDpiY(); }
384
0
    void setDpiX(int dpi) { dpi_x = dpi; }
385
0
    void setDpiY(int dpi) { dpi_y = dpi; }
386
0
    QPaintEngine *paintEngine() const override { return nullptr; }
387
    int metric(PaintDeviceMetric m) const override
388
0
    {
389
0
        switch(m) {
390
0
            case PdmPhysicalDpiX:
391
0
            case PdmDpiX:
392
0
                return dpi_x;
393
0
            case PdmPhysicalDpiY:
394
0
            case PdmDpiY:
395
0
                return dpi_y;
396
0
            default:
397
0
                return QPaintDevice::metric(m);
398
0
        }
399
0
    }
400
401
private:
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
412
bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
413
0
{
414
0
    Q_D(QPicture);
415
0
#if defined(QT_DEBUG)
416
0
    int                strm_pos;
417
0
#endif
418
0
    quint8     c;                      // command id
419
0
    quint8     tiny_len;               // 8-bit length descriptor
420
0
    qint32     len;                    // 32-bit length descriptor
421
0
    qint16     i_16, i1_16, i2_16;     // parameters...
422
0
    qint8      i_8;
423
0
    quint32    ul;
424
0
    double     dbl;
425
0
    bool       bl;
426
0
    QByteArray  str1;
427
0
    QString     str;
428
0
    QPointF     p, p1, p2;
429
0
    QPoint      ip, ip1, ip2;
430
0
    QRect       ir;
431
0
    QRectF      r;
432
0
    QPolygonF   a;
433
0
    QPolygon    ia;
434
0
    QColor      color;
435
0
    QFont       font;
436
0
    QPen        pen;
437
0
    QBrush      brush;
438
0
    QRegion     rgn;
439
0
    qreal       wmatrix[6];
440
0
    QTransform  matrix;
441
442
0
    QTransform worldMatrix = painter->transform();
443
0
    worldMatrix.scale(qreal(painter->device()->logicalDpiX()) / qreal(qt_defaultDpiX()),
444
0
                      qreal(painter->device()->logicalDpiY()) / qreal(qt_defaultDpiY()));
445
0
    painter->setTransform(worldMatrix);
446
447
0
    while (nrecords-- && !s.atEnd()) {
448
0
        s >> c;                 // read cmd
449
0
        s >> tiny_len;          // read param length
450
0
        if (tiny_len == 255)    // longer than 254 bytes
451
0
            s >> len;
452
0
        else
453
0
            len = tiny_len;
454
0
#if defined(QT_DEBUG)
455
0
        strm_pos = s.device()->pos();
456
0
#endif
457
0
        switch (c) {            // exec cmd
458
0
        case QPicturePrivate::PdcNOP:
459
0
            break;
460
0
        case QPicturePrivate::PdcDrawPoint:
461
0
            if (d->formatMajor <= 5) {
462
0
                s >> ip;
463
0
                painter->drawPoint(ip);
464
0
            } else {
465
0
                s >> p;
466
0
                painter->drawPoint(p);
467
0
            }
468
0
            break;
469
0
        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
0
            break;
474
0
        case QPicturePrivate::PdcDrawPath: {
475
0
            QPainterPath path;
476
0
            s >> path;
477
0
            painter->drawPath(path);
478
0
            break;
479
0
        }
480
0
        case QPicturePrivate::PdcDrawLine:
481
0
            if (d->formatMajor <= 5) {
482
0
                s >> ip1 >> ip2;
483
0
                painter->drawLine(ip1, ip2);
484
0
            } else {
485
0
                s >> p1 >> p2;
486
0
                painter->drawLine(p1, p2);
487
0
            }
488
0
            break;
489
0
        case QPicturePrivate::PdcDrawRect:
490
0
            if (d->formatMajor <= 5) {
491
0
                s >> ir;
492
0
                painter->drawRect(ir);
493
0
            } else {
494
0
                s >> r;
495
0
                painter->drawRect(r);
496
0
            }
497
0
            break;
498
0
        case QPicturePrivate::PdcDrawRoundRect:
499
0
            if (d->formatMajor <= 5) {
500
0
                s >> ir >> i1_16 >> i2_16;
501
0
                painter->drawRoundedRect(ir, i1_16, i2_16, Qt::RelativeSize);
502
0
            } else {
503
0
                s >> r >> i1_16 >> i2_16;
504
0
                painter->drawRoundedRect(r, i1_16, i2_16, Qt::RelativeSize);
505
0
            }
506
0
            break;
507
0
        case QPicturePrivate::PdcDrawEllipse:
508
0
            if (d->formatMajor <= 5) {
509
0
                s >> ir;
510
0
                painter->drawEllipse(ir);
511
0
            } else {
512
0
                s >> r;
513
0
                painter->drawEllipse(r);
514
0
            }
515
0
            break;
516
0
        case QPicturePrivate::PdcDrawArc:
517
0
            if (d->formatMajor <= 5) {
518
0
                s >> ir;
519
0
                r = ir;
520
0
            } else {
521
0
                s >> r;
522
0
            }
523
0
            s >> i1_16 >> i2_16;
524
0
            painter->drawArc(r, i1_16, i2_16);
525
0
            break;
526
0
        case QPicturePrivate::PdcDrawPie:
527
0
            if (d->formatMajor <= 5) {
528
0
                s >> ir;
529
0
                r = ir;
530
0
            } else {
531
0
                s >> r;
532
0
            }
533
0
            s >> i1_16 >> i2_16;
534
0
            painter->drawPie(r, i1_16, i2_16);
535
0
            break;
536
0
        case QPicturePrivate::PdcDrawChord:
537
0
            if (d->formatMajor <= 5) {
538
0
                s >> ir;
539
0
                r = ir;
540
0
            } else {
541
0
                s >> r;
542
0
            }
543
0
            s >> i1_16 >> i2_16;
544
0
            painter->drawChord(r, i1_16, i2_16);
545
0
            break;
546
0
        case QPicturePrivate::PdcDrawLineSegments:
547
0
            s >> ia;
548
0
            painter->drawLines(ia);
549
0
            ia.clear();
550
0
            break;
551
0
        case QPicturePrivate::PdcDrawPolyline:
552
0
            if (d->formatMajor <= 5) {
553
0
                s >> ia;
554
0
                painter->drawPolyline(ia);
555
0
                ia.clear();
556
0
            } else {
557
0
                s >> a;
558
0
                painter->drawPolyline(a);
559
0
                a.clear();
560
0
            }
561
0
            break;
562
0
        case QPicturePrivate::PdcDrawPolygon:
563
0
            if (d->formatMajor <= 5) {
564
0
                s >> ia >> i_8;
565
0
                painter->drawPolygon(ia, i_8 ? Qt::WindingFill : Qt::OddEvenFill);
566
0
                ia.clear();
567
0
            } else {
568
0
                s >> a >> i_8;
569
0
                painter->drawPolygon(a, i_8 ? Qt::WindingFill : Qt::OddEvenFill);
570
0
                a.clear();
571
0
            }
572
0
            break;
573
0
        case QPicturePrivate::PdcDrawCubicBezier: {
574
0
            s >> ia;
575
0
            QPainterPath path;
576
0
            Q_ASSERT(ia.size() == 4);
577
0
            path.moveTo(ia.value(0));
578
0
            path.cubicTo(ia.value(1), ia.value(2), ia.value(3));
579
0
            painter->strokePath(path, painter->pen());
580
0
            ia.clear();
581
0
        }
582
0
            break;
583
0
        case QPicturePrivate::PdcDrawText:
584
0
            s >> ip >> str1;
585
0
            painter->drawText(ip, QString::fromLatin1(str1));
586
0
            break;
587
0
        case QPicturePrivate::PdcDrawTextFormatted:
588
0
            s >> ir >> i_16 >> str1;
589
0
            painter->drawText(ir, i_16, QString::fromLatin1(str1));
590
0
            break;
591
0
        case QPicturePrivate::PdcDrawText2:
592
0
            if (d->formatMajor <= 5) {
593
0
                s >> ip >> str;
594
0
                painter->drawText(ip, str);
595
0
            } else {
596
0
                s >> p >> str;
597
0
                painter->drawText(p, str);
598
0
            }
599
0
            break;
600
0
        case QPicturePrivate::PdcDrawText2Formatted:
601
0
            s >> ir;
602
0
            s >> i_16;
603
0
            s >> str;
604
0
            painter->drawText(ir, i_16, str);
605
0
            break;
606
0
        case QPicturePrivate::PdcDrawTextItem: {
607
0
            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
0
            if (d->formatMajor >= 9) {
614
0
                s >> dbl;
615
0
                QFont fnt(font);
616
0
                if (dbl != 1.0) {
617
0
                    QFakeDevice fake;
618
0
                    fake.setDpiX(qRound(dbl*qt_defaultDpiX()));
619
0
                    fake.setDpiY(qRound(dbl*qt_defaultDpiY()));
620
0
                    fnt = QFont(font, &fake);
621
0
                }
622
623
0
                qreal justificationWidth;
624
0
                s >> justificationWidth;
625
626
0
                int flags = Qt::TextSingleLine | Qt::TextDontClip | Qt::TextForceLeftToRight;
627
0
                int alignment = 0;
628
629
0
                QSizeF size(1, 1);
630
0
                if (justificationWidth > 0) {
631
0
                    size.setWidth(justificationWidth);
632
0
                    flags |= Qt::TextJustificationForced;
633
0
                    alignment |= Qt::AlignJustify;
634
0
                }
635
636
0
                QPointF pt(p.x(), p.y());
637
0
                if (d->formatMajor >= QDataStream::Qt_6_11) {
638
0
                    alignment |= Qt::AlignBaseline;
639
0
                } else {
640
0
                    QFontMetrics fm(fnt);
641
0
                    pt.ry() -= fm.ascent();
642
0
                }
643
644
0
                qt_format_text(fnt,
645
0
                               QRectF(pt, size),
646
0
                               flags,
647
0
                               alignment,
648
0
                               /*opt*/nullptr,
649
0
                               str,
650
0
                               /*brect=*/nullptr,
651
0
                               /*tabstops=*/0,
652
0
                               /*...*/nullptr,
653
0
                               /*tabarraylen=*/0,
654
0
                               painter);
655
0
            } else {
656
0
                qt_format_text(font,
657
0
                               QRectF(p, QSizeF(1, 1)),
658
0
                               Qt::TextSingleLine | Qt::TextDontClip,
659
0
                               0,
660
0
                               /*opt*/nullptr,
661
0
                               str,
662
0
                               /*brect=*/nullptr,
663
0
                               /*tabstops=*/0,
664
0
                               /*...*/nullptr,
665
0
                               /*tabarraylen=*/0,
666
0
                               painter);
667
0
            }
668
669
0
            break;
670
0
        }
671
0
        case QPicturePrivate::PdcDrawPixmap: {
672
0
            QPixmap pixmap;
673
0
            if (d->formatMajor < 4) {
674
0
                s >> ip >> pixmap;
675
0
                painter->drawPixmap(ip, pixmap);
676
0
            } else if (d->formatMajor <= 5) {
677
0
                s >> ir >> pixmap;
678
0
                painter->drawPixmap(ir, pixmap);
679
0
            } else {
680
0
                QRectF sr;
681
0
                if (d->in_memory_only) {
682
0
                    int index;
683
0
                    s >> r >> index >> sr;
684
0
                    Q_ASSERT(index < d->pixmap_list.size());
685
0
                    pixmap = d->pixmap_list.value(index);
686
0
                } else {
687
0
                    s >> r >> pixmap >> sr;
688
0
                }
689
0
                painter->drawPixmap(r, pixmap, sr);
690
0
            }
691
0
        }
692
0
            break;
693
0
        case QPicturePrivate::PdcDrawTiledPixmap: {
694
0
            QPixmap pixmap;
695
0
            if (d->in_memory_only) {
696
0
                int index;
697
0
                s >> r >> index >> p;
698
0
                Q_ASSERT(index < d->pixmap_list.size());
699
0
                pixmap = d->pixmap_list.value(index);
700
0
            } else {
701
0
                s >> r >> pixmap >> p;
702
0
            }
703
0
            painter->drawTiledPixmap(r, pixmap, p);
704
0
        }
705
0
            break;
706
0
        case QPicturePrivate::PdcDrawImage: {
707
0
            QImage image;
708
0
            if (d->formatMajor < 4) {
709
0
                s >> p >> image;
710
0
                painter->drawImage(p, image);
711
0
            } else if (d->formatMajor <= 5){
712
0
                s >> ir >> image;
713
0
                painter->drawImage(ir, image, QRect(0, 0, ir.width(), ir.height()));
714
0
            } else {
715
0
                QRectF sr;
716
0
                if (d->in_memory_only) {
717
0
                    int index;
718
0
                    s >> r >> index >> sr >> ul;
719
0
                    Q_ASSERT(index < d->image_list.size());
720
0
                    image = d->image_list.value(index);
721
0
                } else {
722
0
                    s >> r >> image >> sr >> ul;
723
0
                }
724
0
                painter->drawImage(r, image, sr, Qt::ImageConversionFlags(ul));
725
0
            }
726
0
        }
727
0
            break;
728
0
        case QPicturePrivate::PdcBegin:
729
0
            s >> ul;                        // number of records
730
0
            if (!exec(painter, s, ul))
731
0
                return false;
732
0
            break;
733
0
        case QPicturePrivate::PdcEnd:
734
0
            if (nrecords == 0)
735
0
                return true;
736
0
            break;
737
0
        case QPicturePrivate::PdcSave:
738
0
            painter->save();
739
0
            break;
740
0
        case QPicturePrivate::PdcRestore:
741
0
            painter->restore();
742
0
            break;
743
0
        case QPicturePrivate::PdcSetBkColor:
744
0
            s >> color;
745
0
            painter->setBackground(color);
746
0
            break;
747
0
        case QPicturePrivate::PdcSetBkMode:
748
0
            s >> i_8;
749
0
            painter->setBackgroundMode((Qt::BGMode)i_8);
750
0
            break;
751
0
        case QPicturePrivate::PdcSetROP: // NOP
752
0
            s >> i_8;
753
0
            break;
754
0
        case QPicturePrivate::PdcSetBrushOrigin:
755
0
            if (d->formatMajor <= 5) {
756
0
                s >> ip;
757
0
                painter->setBrushOrigin(ip);
758
0
            } else {
759
0
                s >> p;
760
0
                painter->setBrushOrigin(p);
761
0
            }
762
0
            break;
763
0
        case QPicturePrivate::PdcSetFont:
764
0
            s >> font;
765
0
            painter->setFont(font);
766
0
            break;
767
0
        case QPicturePrivate::PdcSetPen:
768
0
            if (d->in_memory_only) {
769
0
                int index;
770
0
                s >> index;
771
0
                Q_ASSERT(index < d->pen_list.size());
772
0
                pen = d->pen_list.value(index);
773
0
            } else {
774
0
                s >> pen;
775
0
            }
776
0
            painter->setPen(pen);
777
0
            break;
778
0
        case QPicturePrivate::PdcSetBrush:
779
0
            if (d->in_memory_only) {
780
0
                int index;
781
0
                s >> index;
782
0
                Q_ASSERT(index < d->brush_list.size());
783
0
                brush = d->brush_list.value(index);
784
0
            } else {
785
0
                s >> brush;
786
0
            }
787
0
            painter->setBrush(brush);
788
0
            break;
789
0
        case QPicturePrivate::PdcSetVXform:
790
0
            s >> i_8;
791
0
            painter->setViewTransformEnabled(i_8);
792
0
            break;
793
0
        case QPicturePrivate::PdcSetWindow:
794
0
            if (d->formatMajor <= 5) {
795
0
                s >> ir;
796
0
                painter->setWindow(ir);
797
0
            } else {
798
0
                s >> r;
799
0
                painter->setWindow(r.toRect());
800
0
            }
801
0
            break;
802
0
        case QPicturePrivate::PdcSetViewport:
803
0
            if (d->formatMajor <= 5) {
804
0
                s >> ir;
805
0
                painter->setViewport(ir);
806
0
            } else {
807
0
                s >> r;
808
0
                painter->setViewport(r.toRect());
809
0
            }
810
0
            break;
811
0
        case QPicturePrivate::PdcSetWXform:
812
0
            s >> i_8;
813
0
            painter->setWorldMatrixEnabled(i_8);
814
0
            break;
815
0
        case QPicturePrivate::PdcSetWMatrix:
816
0
            if (d->formatMajor >= 8) {
817
0
                s >> matrix >> i_8;
818
0
            } else {
819
0
                s >> wmatrix[0] >> wmatrix[1]
820
0
                  >> wmatrix[2] >> wmatrix[3]
821
0
                  >> wmatrix[4] >> wmatrix[5] >> i_8;
822
0
                matrix = QTransform(wmatrix[0], wmatrix[1],
823
0
                                    wmatrix[2], wmatrix[3],
824
0
                                    wmatrix[4], wmatrix[5]);
825
0
            }
826
            // i_8 is always false due to updateXForm() in qpaintengine_pic.cpp
827
0
            painter->setTransform(matrix * worldMatrix, i_8);
828
0
            break;
829
0
        case QPicturePrivate::PdcSetClip:
830
0
            s >> i_8;
831
0
            painter->setClipping(i_8);
832
0
            break;
833
0
        case QPicturePrivate::PdcSetClipRegion:
834
0
            s >> rgn >> i_8;
835
0
            if (d->formatMajor >= 9) {
836
0
                painter->setClipRegion(rgn, Qt::ClipOperation(i_8));
837
0
            } else {
838
0
                painter->setClipRegion(rgn);
839
0
            }
840
0
            break;
841
0
        case QPicturePrivate::PdcSetClipPath:
842
0
            {
843
0
                QPainterPath path;
844
0
                s >> path >> i_8;
845
0
                painter->setClipPath(path, Qt::ClipOperation(i_8));
846
0
                break;
847
0
            }
848
0
        case QPicturePrivate::PdcSetRenderHint:
849
0
            s >> ul;
850
0
            painter->setRenderHint(QPainter::Antialiasing,
851
0
                                   bool(ul & QPainter::Antialiasing));
852
0
            painter->setRenderHint(QPainter::SmoothPixmapTransform,
853
0
                                   bool(ul & QPainter::SmoothPixmapTransform));
854
0
            painter->setRenderHint(QPainter::NonCosmeticBrushPatterns,
855
0
                                   bool(ul & QPainter::NonCosmeticBrushPatterns));
856
0
            break;
857
0
        case QPicturePrivate::PdcSetCompositionMode:
858
0
            s >> ul;
859
0
            painter->setCompositionMode((QPainter::CompositionMode)ul);
860
0
            break;
861
0
        case QPicturePrivate::PdcSetClipEnabled:
862
0
            s >> bl;
863
0
            painter->setClipping(bl);
864
0
            break;
865
0
        case QPicturePrivate::PdcSetOpacity:
866
0
            s >> dbl;
867
0
            painter->setOpacity(qreal(dbl));
868
0
            break;
869
0
        default:
870
0
            qWarning("QPicture::play: Invalid command %d", c);
871
0
            if (len > 0)                    // skip unknown command
872
0
                s.device()->seek(s.device()->pos()+len);
873
0
        }
874
0
#if defined(QT_DEBUG)
875
        //qDebug("device->at(): %i, strm_pos: %i len: %i", (int)s.device()->pos(), strm_pos, len);
876
0
        Q_ASSERT(qint32(s.device()->pos() - strm_pos) == len);
877
0
#endif
878
0
    }
879
0
    return false;
880
0
}
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
894
int QPicture::metric(PaintDeviceMetric m) const
895
0
{
896
0
    int val;
897
0
    QRect brect = boundingRect();
898
0
    switch (m) {
899
0
        case PdmWidth:
900
0
            val = brect.width();
901
0
            break;
902
0
        case PdmHeight:
903
0
            val = brect.height();
904
0
            break;
905
0
        case PdmWidthMM:
906
0
            val = int(25.4/qt_defaultDpiX()*brect.width());
907
0
            break;
908
0
        case PdmHeightMM:
909
0
            val = int(25.4/qt_defaultDpiY()*brect.height());
910
0
            break;
911
0
        case PdmDpiX:
912
0
        case PdmPhysicalDpiX:
913
0
            val = qt_defaultDpiX();
914
0
            break;
915
0
        case PdmDpiY:
916
0
        case PdmPhysicalDpiY:
917
0
            val = qt_defaultDpiY();
918
0
            break;
919
0
        case PdmNumColors:
920
0
            val = 16777216;
921
0
            break;
922
0
        case PdmDepth:
923
0
            val = 24;
924
0
            break;
925
0
        case PdmDevicePixelRatio:
926
0
            val = 1;
927
0
            break;
928
0
        case PdmDevicePixelRatioScaled:
929
0
            val = 1 * QPaintDevice::devicePixelRatioFScale();
930
0
            break;
931
0
        default:
932
0
            val = 0;
933
0
            qWarning("QPicture::metric: Invalid metric command");
934
0
    }
935
0
    return val;
936
0
}
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
*/
957
QPicture& QPicture::operator=(const QPicture &p)
958
0
{
959
0
    d_ptr = p.d_ptr;
960
0
    return *this;
961
0
}
962
963
/*!
964
    \fn void QPicture::swap(QPicture &other)
965
    \memberswap{picture}
966
*/
967
968
/*!
969
  \internal
970
971
  Constructs a QPicturePrivate
972
*/
973
QPicturePrivate::QPicturePrivate()
974
0
    : pictb(&pictbData),
975
0
      in_memory_only(false)
976
0
{
977
0
}
978
979
/*!
980
  \internal
981
982
  Copy-Constructs a QPicturePrivate. Needed when detaching.
983
*/
984
QPicturePrivate::QPicturePrivate(const QPicturePrivate &other)
985
0
    : pictb(&pictbData),
986
0
      trecs(other.trecs),
987
0
      formatOk(other.formatOk),
988
0
      formatMinor(other.formatMinor),
989
0
      brect(other.brect),
990
0
      override_rect(other.override_rect),
991
0
      in_memory_only(false)
992
0
{
993
0
    pictb.setData(other.pictb.data(), other.pictb.size());
994
0
    if (other.pictb.isOpen()) {
995
0
        pictb.open(other.pictb.openMode());
996
0
        pictb.seek(other.pictb.pos());
997
0
    }
998
0
}
999
1000
/*!
1001
  \internal
1002
1003
  Sets formatOk to false and resets the format version numbers to default
1004
*/
1005
1006
void QPicturePrivate::resetFormat()
1007
0
{
1008
0
    formatOk = false;
1009
0
    formatMajor = mfhdr_maj;
1010
0
    formatMinor = mfhdr_min;
1011
0
}
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
*/
1021
bool QPicturePrivate::checkFormat()
1022
0
{
1023
0
    resetFormat();
1024
1025
    // can't check anything in an empty buffer
1026
0
    if (pictb.size() == 0 || pictb.isOpen())
1027
0
        return false;
1028
1029
0
    pictb.open(QIODevice::ReadOnly);                        // open buffer device
1030
0
    QDataStream s;
1031
0
    s.setDevice(&pictb);                        // attach data stream to buffer
1032
1033
0
    char mf_id[4];                                // picture header tag
1034
0
    s.readRawData(mf_id, 4);                        // read actual tag
1035
0
    int bufSize = pictb.buffer().size();
1036
0
    if (memcmp(mf_id, qt_mfhdr_tag, 4) != 0 || bufSize < 12) {   // wrong header id or size
1037
0
        qWarning("QPicturePaintEngine::checkFormat: Incorrect header");
1038
0
        pictb.close();
1039
0
        return false;
1040
0
    }
1041
1042
0
    int cs_start = sizeof(quint32);                // pos of checksum word
1043
0
    int data_start = cs_start + sizeof(quint16);
1044
0
    quint16 cs,ccs;
1045
0
    const QByteArray buf = pictb.buffer();        // pointer to data
1046
1047
0
    s >> cs;                                // read checksum
1048
0
    ccs = (quint16) qChecksum(QByteArrayView(buf.constData() + data_start, buf.size() - data_start));
1049
0
    if (ccs != cs) {
1050
0
        qWarning("QPicturePaintEngine::checkFormat: Invalid checksum %x, %x expected",
1051
0
                  ccs, cs);
1052
0
        pictb.close();
1053
0
        return false;
1054
0
    }
1055
1056
0
    quint16 major, minor;
1057
0
    s >> major >> minor;                        // read version number
1058
0
    if (major > mfhdr_maj) {                // new, incompatible version
1059
0
        qWarning("QPicturePaintEngine::checkFormat: Incompatible version %d.%d",
1060
0
                  major, minor);
1061
0
        pictb.close();
1062
0
        return false;
1063
0
    }
1064
0
    s.setVersion(major != 4 ? major : 3);
1065
1066
0
    quint8  c, clen;
1067
0
    s >> c >> clen;
1068
0
    if (c == QPicturePrivate::PdcBegin) {
1069
0
        if (!(major >= 1 && major <= 3)) {
1070
0
            qint32 l, t, w, h;
1071
0
            s >> l >> t >> w >> h;
1072
0
            brect = QRect(l, t, w, h);
1073
0
        }
1074
0
    } else {
1075
0
        qWarning("QPicturePaintEngine::checkFormat: Format error");
1076
0
        pictb.close();
1077
0
        return false;
1078
0
    }
1079
0
    pictb.close();
1080
1081
0
    formatOk = true;                        // picture seems to be ok
1082
0
    formatMajor = major;
1083
0
    formatMinor = minor;
1084
0
    return true;
1085
0
}
1086
1087
/*! \internal */
1088
QPaintEngine *QPicture::paintEngine() const
1089
0
{
1090
0
    if (!d_func()->paintEngine)
1091
0
        const_cast<QPicture*>(this)->d_func()->paintEngine.reset(new QPicturePaintEngine);
1092
0
    return d_func()->paintEngine.data();
1093
0
}
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
1107
QDataStream &operator<<(QDataStream &s, const QPicture &r)
1108
0
{
1109
0
    quint32 size = r.d_func()->pictb.buffer().size();
1110
0
    s << size;
1111
    // null picture ?
1112
0
    if (size == 0)
1113
0
        return s;
1114
    // just write the whole buffer to the stream
1115
0
    s.writeRawData (r.d_func()->pictb.buffer(), r.d_func()->pictb.buffer().size());
1116
0
    return s;
1117
0
}
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
1126
QDataStream &operator>>(QDataStream &s, QPicture &r)
1127
0
{
1128
0
    QDataStream sr;
1129
1130
    // "init"; this code is similar to the beginning of QPicture::cmd()
1131
0
    sr.setDevice(&r.d_func()->pictb);
1132
0
    sr.setVersion(r.d_func()->formatMajor);
1133
0
    quint32 len;
1134
0
    s >> len;
1135
0
    QByteArray data;
1136
0
    if (len > 0) {
1137
0
        data.resize(len);
1138
0
        s.readRawData(data.data(), len);
1139
0
    }
1140
1141
0
    r.d_func()->pictb.setData(data);
1142
0
    r.d_func()->resetFormat();
1143
0
    return s;
1144
0
}
1145
#endif // QT_NO_DATASTREAM
1146
1147
QT_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
*/