source: trunk/src/gui/image/qpicture.cpp@ 574

Last change on this file since 574 was 561, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.1 sources.

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