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

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

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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