summaryrefslogtreecommitdiffstats
path: root/src/kernel/qpicture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/qpicture.cpp')
-rw-r--r--src/kernel/qpicture.cpp1229
1 files changed, 1229 insertions, 0 deletions
diff --git a/src/kernel/qpicture.cpp b/src/kernel/qpicture.cpp
new file mode 100644
index 0000000..d434516
--- /dev/null
+++ b/src/kernel/qpicture.cpp
@@ -0,0 +1,1229 @@
+/****************************************************************************
+**
+** Implementation of QPicture class
+**
+** Created : 940802
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the kernel module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qpicture.h"
+
+#ifndef QT_NO_PICTURE
+
+#include "qpainter.h"
+#include "qpixmap.h"
+#include "qimage.h"
+#include "qfile.h"
+#include "qdatastream.h"
+#include "qpaintdevicemetrics.h"
+
+#ifndef QT_NO_SVG
+#include "private/qsvgdevice_p.h"
+#endif
+
+/*!
+ \class QPicture qpicture.h
+ \brief The QPicture class is a paint device that records and
+ replays QPainter commands.
+
+ \ingroup graphics
+ \ingroup images
+ \ingroup shared
+
+ A picture serializes painter commands to an IO device in a
+ platform-independent format. For example, a picture created under
+ Windows can be read on a Sun SPARC.
+
+ Pictures are called meta-files on some platforms.
+
+ Qt pictures use a proprietary binary format. Unlike native picture
+ (meta-file) formats on many window systems, Qt pictures have no
+ limitations regarding their contents. Everything that can be
+ painted can also be stored in a picture, e.g. fonts, pixmaps,
+ regions, transformed graphics, etc.
+
+ QPicture is an \link shclass.html implicitly shared\endlink class.
+
+ Example of how to record a picture:
+ \code
+ QPicture pic;
+ QPainter p;
+ p.begin( &pic ); // paint in picture
+ p.drawEllipse( 10,20, 80,70 ); // draw an ellipse
+ p.end(); // painting done
+ pic.save( "drawing.pic" ); // save picture
+ \endcode
+
+ Example of how to replay a picture:
+ \code
+ QPicture pic;
+ pic.load( "drawing.pic" ); // load picture
+ QPainter p;
+ p.begin( &myWidget ); // paint in myWidget
+ p.drawPicture( pic ); // draw the picture
+ p.end(); // painting done
+ \endcode
+
+ Pictures can also be drawn using play(). Some basic data about a
+ picture is available, for example, size(), isNull() and
+ boundingRect().
+
+*/
+
+
+static const char *mfhdr_tag = "QPIC"; // header tag
+static const Q_UINT16 mfhdr_maj = 5; // major version #
+static const Q_UINT16 mfhdr_min = 0; // minor version #
+
+
+/*!
+ Constructs an empty picture.
+
+ The \a formatVersion parameter may be used to \e create a QPicture
+ that can be read by applications that are compiled with earlier
+ versions of Qt.
+ \list
+ \i \a formatVersion == 1 is binary compatible with Qt 1.x and later.
+ \i \a formatVersion == 2 is binary compatible with Qt 2.0.x and later.
+ \i \a formatVersion == 3 is binary compatible with Qt 2.1.x and later.
+ \i \a formatVersion == 4 is binary compatible with Qt 3.0.x and later.
+ \i \a formatVersion == 5 is binary compatible with Qt 3.1.
+ \endlist
+
+ Note that the default formatVersion is -1 which signifies the
+ current release, i.e. for Qt 3.1 a formatVersion of 5 is the same
+ as the default formatVersion of -1.
+
+ Reading pictures generated by earlier versions of Qt is supported
+ and needs no special coding; the format is automatically detected.
+*/
+
+QPicture::QPicture( int formatVersion )
+ : QPaintDevice( QInternal::Picture | QInternal::ExternalDevice )
+ // set device type
+{
+ d = new QPicturePrivate;
+
+#if defined(QT_CHECK_RANGE)
+ if ( formatVersion == 0 )
+ qWarning( "QPicture: invalid format version 0" );
+#endif
+
+ // still accept the 0 default from before Qt 3.0.
+ if ( formatVersion > 0 && formatVersion != (int)mfhdr_maj ) {
+ d->formatMajor = formatVersion;
+ d->formatMinor = 0;
+ d->formatOk = FALSE;
+ }
+ else {
+ d->resetFormat();
+ }
+}
+
+/*!
+ Constructs a \link shclass.html shallow copy\endlink of \a pic.
+*/
+
+QPicture::QPicture( const QPicture &pic )
+ : QPaintDevice( QInternal::Picture | QInternal::ExternalDevice )
+{
+ d = pic.d;
+ d->ref();
+}
+
+/*!
+ Destroys the picture.
+*/
+QPicture::~QPicture()
+{
+ if ( d->deref() )
+ delete d;
+}
+
+
+/*!
+ \fn bool QPicture::isNull() const
+
+ Returns TRUE if the picture contains no data; otherwise returns
+ FALSE.
+*/
+
+/*!
+ \fn uint QPicture::size() const
+
+ Returns the size of the picture data.
+
+ \sa data()
+*/
+
+/*!
+ \fn const char* QPicture::data() const
+
+ Returns a pointer to the picture data. The pointer is only valid
+ until the next non-const function is called on this picture. The
+ returned pointer is 0 if the picture contains no data.
+
+ \sa size(), isNull()
+*/
+
+/*!
+ Sets the picture data directly from \a data and \a size. This
+ function copies the input data.
+
+ \sa data(), size()
+*/
+
+void QPicture::setData( const char* data, uint size )
+{
+ detach();
+ QByteArray a( size );
+ memcpy( a.data(), data, size );
+ d->pictb.setBuffer( a ); // set byte array in buffer
+ d->resetFormat(); // we'll have to check
+}
+
+
+/*!
+ Loads a picture from the file specified by \a fileName and returns
+ TRUE if successful; otherwise returns FALSE.
+
+ By default, the file will be interpreted as being in the native
+ QPicture format. Specifying the \a format string is optional and
+ is only needed for importing picture data stored in a different
+ format.
+
+ Currently, the only external format supported is the \link
+ http://www.w3.org/Graphics/SVG/ W3C SVG \endlink format which
+ requires the \link xml.html Qt XML module \endlink. The
+ corresponding \a format string is "svg".
+
+ \sa save()
+*/
+
+bool QPicture::load( const QString &fileName, const char *format )
+{
+ QFile f( fileName );
+ if ( !f.open(IO_ReadOnly) )
+ return FALSE;
+ return load( &f, format );
+}
+
+/*!
+ \overload
+
+ \a dev is the device to use for loading.
+*/
+
+bool QPicture::load( QIODevice *dev, const char *format )
+{
+#ifndef QT_NO_SVG
+ if ( qstrcmp( format, "svg" ) == 0 ) {
+ QSvgDevice svg;
+ if ( !svg.load( dev ) )
+ return FALSE;
+ QPainter p( this );
+ bool b = svg.play( &p );
+ d->brect = svg.boundingRect();
+ return b;
+ }
+#endif
+ if ( format ) {
+ qWarning( "QPicture::load: No such picture format: %s", format );
+ return FALSE;
+ }
+
+ detach();
+ QByteArray a = dev->readAll();
+ d->pictb.setBuffer( a ); // set byte array in buffer
+ return d->checkFormat();
+}
+
+/*!
+ Saves a picture to the file specified by \a fileName and returns
+ TRUE if successful; otherwise returns FALSE.
+
+ Specifying the file \a format string is optional. It's not
+ recommended unless you intend to export the picture data for
+ use by a third party reader. By default the data will be saved in
+ the native QPicture file format.
+
+ Currently, the only external format supported is the \link
+ http://www.w3.org/Graphics/SVG/ W3C SVG \endlink format which
+ requires the \link xml.html Qt XML module \endlink. The
+ corresponding \a format string is "svg".
+
+ \sa load()
+*/
+
+bool QPicture::save( const QString &fileName, const char *format )
+{
+ if ( paintingActive() ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QPicture::save: still being painted on. "
+ "Call QPainter::end() first" );
+#endif
+ return FALSE;
+ }
+
+#ifndef QT_NO_SVG
+ // identical to QIODevice* code below but the file name
+ // makes a difference when it comes to saving pixmaps
+ if ( qstricmp( format, "svg" ) == 0 ) {
+ QSvgDevice svg;
+ QPainter p( &svg );
+ if ( !play( &p ) )
+ return FALSE;
+ svg.setBoundingRect( boundingRect() );
+ return svg.save( fileName );
+ }
+#endif
+
+ QFile f( fileName );
+ if ( !f.open(IO_WriteOnly) )
+ return FALSE;
+ return save( &f, format );
+}
+
+/*!
+ \overload
+
+ \a dev is the device to use for saving.
+*/
+
+bool QPicture::save( QIODevice *dev, const char *format )
+{
+ if ( paintingActive() ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QPicture::save: still being painted on. "
+ "Call QPainter::end() first" );
+#endif
+ return FALSE;
+ }
+
+#ifndef QT_NO_SVG
+ if ( qstricmp( format, "svg" ) == 0 ) {
+ QSvgDevice svg;
+ QPainter p( &svg );
+ if ( !play( &p ) )
+ return FALSE;
+ svg.setBoundingRect( boundingRect() );
+ return svg.save( dev );
+ }
+#endif
+ if ( format ) {
+ qWarning( "QPicture::save: No such picture format: %s", format );
+ return FALSE;
+ }
+
+ dev->writeBlock( d->pictb.buffer().data(), d->pictb.buffer().size() );
+ return TRUE;
+}
+
+/*!
+ Returns the picture's bounding rectangle or an invalid rectangle
+ if the picture contains no data.
+*/
+
+QRect QPicture::boundingRect() const
+{
+ if ( !d->formatOk )
+ d->checkFormat();
+ return d->brect;
+}
+
+/*!
+ Sets the picture's bounding rectangle to \a r. The automatically
+ calculated value is overriden.
+*/
+
+void QPicture::setBoundingRect( const QRect &r )
+{
+ if ( !d->formatOk )
+ d->checkFormat();
+ d->brect = r;
+}
+
+/*!
+ Replays the picture using \a painter, and returns TRUE if
+ successful; otherwise returns FALSE.
+
+ This function does exactly the same as QPainter::drawPicture()
+ with (x, y) = (0, 0).
+*/
+
+bool QPicture::play( QPainter *painter )
+{
+ if ( d->pictb.size() == 0 ) // nothing recorded
+ return TRUE;
+
+ if ( !d->formatOk && !d->checkFormat() )
+ return FALSE;
+
+ d->pictb.open( IO_ReadOnly ); // open buffer device
+ QDataStream s;
+ s.setDevice( &d->pictb ); // attach data stream to buffer
+ s.device()->at( 10 ); // go directly to the data
+ s.setVersion( d->formatMajor == 4 ? 3 : d->formatMajor );
+
+ Q_UINT8 c, clen;
+ Q_UINT32 nrecords;
+ s >> c >> clen;
+ Q_ASSERT( c == PdcBegin );
+ // bounding rect was introduced in ver 4. Read in checkFormat().
+ if ( d->formatMajor >= 4 ) {
+ Q_INT32 dummy;
+ s >> dummy >> dummy >> dummy >> dummy;
+ }
+ s >> nrecords;
+ if ( !exec( painter, s, nrecords ) ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QPicture::play: Format error" );
+#endif
+ d->pictb.close();
+ return FALSE;
+ }
+ d->pictb.close();
+ return TRUE; // no end-command
+}
+
+
+/*!
+ \internal
+ Iterates over the internal picture data and draws the picture using
+ \a painter.
+*/
+
+bool QPicture::exec( QPainter *painter, QDataStream &s, int nrecords )
+{
+#if defined(QT_DEBUG)
+ int strm_pos;
+#endif
+ Q_UINT8 c; // command id
+ Q_UINT8 tiny_len; // 8-bit length descriptor
+ Q_INT32 len; // 32-bit length descriptor
+ Q_INT16 i_16, i1_16, i2_16; // parameters...
+ Q_INT8 i_8;
+ Q_UINT32 ul;
+ QCString str1;
+ QString str;
+ QPoint p, p1, p2;
+ QRect r;
+ QPointArray a;
+ QColor color;
+ QFont font;
+ QPen pen;
+ QBrush brush;
+ QRegion rgn;
+#ifndef QT_NO_TRANSFORMATIONS
+ QWMatrix matrix;
+#endif
+
+ while ( nrecords-- && !s.eof() ) {
+ s >> c; // read cmd
+ s >> tiny_len; // read param length
+ if ( tiny_len == 255 ) // longer than 254 bytes
+ s >> len;
+ else
+ len = tiny_len;
+#if defined(QT_DEBUG)
+ strm_pos = s.device()->at();
+#endif
+ switch ( c ) { // exec cmd
+ case PdcNOP:
+ break;
+ case PdcDrawPoint:
+ s >> p;
+ painter->drawPoint( p );
+ break;
+ case PdcMoveTo:
+ s >> p;
+ painter->moveTo( p );
+ break;
+ case PdcLineTo:
+ s >> p;
+ painter->lineTo( p );
+ break;
+ case PdcDrawLine:
+ s >> p1 >> p2;
+ painter->drawLine( p1, p2 );
+ break;
+ case PdcDrawRect:
+ s >> r;
+ painter->drawRect( r );
+ break;
+ case PdcDrawRoundRect:
+ s >> r >> i1_16 >> i2_16;
+ painter->drawRoundRect( r, i1_16, i2_16 );
+ break;
+ case PdcDrawEllipse:
+ s >> r;
+ painter->drawEllipse( r );
+ break;
+ case PdcDrawArc:
+ s >> r >> i1_16 >> i2_16;
+ painter->drawArc( r, i1_16, i2_16 );
+ break;
+ case PdcDrawPie:
+ s >> r >> i1_16 >> i2_16;
+ painter->drawPie( r, i1_16, i2_16 );
+ break;
+ case PdcDrawChord:
+ s >> r >> i1_16 >> i2_16;
+ painter->drawChord( r, i1_16, i2_16 );
+ break;
+ case PdcDrawLineSegments:
+ s >> a;
+ painter->drawLineSegments( a );
+ break;
+ case PdcDrawPolyline:
+ s >> a;
+ painter->drawPolyline( a );
+ break;
+ case PdcDrawPolygon:
+ s >> a >> i_8;
+ painter->drawPolygon( a, i_8 );
+ break;
+ case PdcDrawCubicBezier:
+ s >> a;
+#ifndef QT_NO_BEZIER
+ painter->drawCubicBezier( a );
+#endif
+ break;
+ case PdcDrawText:
+ s >> p >> str1;
+ painter->drawText( p, str1 );
+ break;
+ case PdcDrawTextFormatted:
+ s >> r >> i_16 >> str1;
+ painter->drawText( r, i_16, str1 );
+ break;
+ case PdcDrawText2:
+ s >> p >> str;
+ painter->drawText( p, str );
+ break;
+ case PdcDrawText2Formatted:
+ s >> r >> i_16 >> str;
+ painter->drawText( r, i_16, str );
+ break;
+ case PdcDrawPixmap: {
+ QPixmap pixmap;
+ if ( d->formatMajor < 4 ) {
+ s >> p >> pixmap;
+ painter->drawPixmap( p, pixmap );
+ } else {
+ s >> r >> pixmap;
+ painter->drawPixmap( r, pixmap );
+ }
+ }
+ break;
+ case PdcDrawImage: {
+ QImage image;
+ if ( d->formatMajor < 4 ) {
+ s >> p >> image;
+ painter->drawImage( p, image );
+ } else {
+ s >> r >> image;
+ painter->drawImage( r, image );
+ }
+ }
+ break;
+ case PdcBegin:
+ s >> ul; // number of records
+ if ( !exec( painter, s, ul ) )
+ return FALSE;
+ break;
+ case PdcEnd:
+ if ( nrecords == 0 )
+ return TRUE;
+ break;
+ case PdcSave:
+ painter->save();
+ break;
+ case PdcRestore:
+ painter->restore();
+ break;
+ case PdcSetBkColor:
+ s >> color;
+ painter->setBackgroundColor( color );
+ break;
+ case PdcSetBkMode:
+ s >> i_8;
+ painter->setBackgroundMode( (Qt::BGMode)i_8 );
+ break;
+ case PdcSetROP:
+ s >> i_8;
+ painter->setRasterOp( (Qt::RasterOp)i_8 );
+ break;
+ case PdcSetBrushOrigin:
+ s >> p;
+ painter->setBrushOrigin( p );
+ break;
+ case PdcSetFont:
+ s >> font;
+ painter->setFont( font );
+ break;
+ case PdcSetPen:
+ s >> pen;
+ painter->setPen( pen );
+ break;
+ case PdcSetBrush:
+ s >> brush;
+ painter->setBrush( brush );
+ break;
+ case PdcSetTabStops:
+ s >> i_16;
+ painter->setTabStops( i_16 );
+ break;
+ case PdcSetTabArray:
+ s >> i_16;
+ if ( i_16 == 0 ) {
+ painter->setTabArray( 0 );
+ } else {
+ int *ta = new int[i_16];
+ Q_CHECK_PTR( ta );
+ for ( int i=0; i<i_16; i++ ) {
+ s >> i1_16;
+ ta[i] = i1_16;
+ }
+ painter->setTabArray( ta );
+ delete [] ta;
+ }
+ break;
+ case PdcSetVXform:
+ s >> i_8;
+#ifndef QT_NO_TRANSFORMATIONS
+ painter->setViewXForm( i_8 );
+#endif
+ break;
+ case PdcSetWindow:
+ s >> r;
+#ifndef QT_NO_TRANSFORMATIONS
+ painter->setWindow( r );
+#endif
+ break;
+ case PdcSetViewport:
+ s >> r;
+#ifndef QT_NO_TRANSFORMATIONS
+ painter->setViewport( r );
+#endif
+ break;
+ case PdcSetWXform:
+ s >> i_8;
+#ifndef QT_NO_TRANSFORMATIONS
+ painter->setWorldXForm( i_8 );
+#endif
+ break;
+ case PdcSetWMatrix:
+#ifndef QT_NO_TRANSFORMATIONS // #### fix me!
+ s >> matrix >> i_8;
+ painter->setWorldMatrix( matrix, i_8 );
+#endif
+ break;
+#ifndef QT_NO_TRANSFORMATIONS
+ case PdcSaveWMatrix:
+ painter->saveWorldMatrix();
+ break;
+ case PdcRestoreWMatrix:
+ painter->restoreWorldMatrix();
+ break;
+#endif
+ case PdcSetClip:
+ s >> i_8;
+ painter->setClipping( i_8 );
+ break;
+ case PdcSetClipRegion:
+ s >> rgn >> i_8;
+ painter->setClipRegion( rgn, (QPainter::CoordinateMode)i_8 );
+ break;
+ default:
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QPicture::play: Invalid command %d", c );
+#endif
+ if ( len ) // skip unknown command
+ s.device()->at( s.device()->at()+len );
+ }
+#if defined(QT_DEBUG)
+ //qDebug( "device->at(): %i, strm_pos: %i len: %i", s.device()->at(), strm_pos, len );
+ Q_ASSERT( Q_INT32(s.device()->at() - strm_pos) == len );
+#endif
+ }
+ return FALSE;
+}
+
+
+/*!
+ \internal
+ Records painter commands and stores them in the pictb buffer.
+*/
+
+bool QPicture::cmd( int c, QPainter *pt, QPDevCmdParam *p )
+{
+ detach();
+ return d->cmd( c, pt, p );
+}
+
+/*!
+ \internal
+ Implementation of the function forwarded above to the internal data struct.
+*/
+
+bool QPicture::QPicturePrivate::cmd( int c, QPainter *pt, QPDevCmdParam *p )
+{
+ QDataStream s;
+ s.setDevice( &pictb );
+ // when moving up to 4 the QDataStream version remained at 3
+ s.setVersion( formatMajor != 4 ? formatMajor : 3 );
+ if ( c == PdcBegin ) { // begin; write header
+ QByteArray empty( 0 );
+ pictb.setBuffer( empty ); // reset byte array in buffer
+ pictb.open( IO_WriteOnly );
+ s.writeRawBytes( mfhdr_tag, 4 );
+ s << (Q_UINT16)0 << (Q_UINT16)formatMajor << (Q_UINT16)formatMinor;
+ s << (Q_UINT8)c << (Q_UINT8)sizeof(Q_INT32);
+ brect = QRect();
+ if ( formatMajor >= 4 ) {
+ s << (Q_INT32)brect.left() << (Q_INT32)brect.top()
+ << (Q_INT32)brect.width() << (Q_INT32)brect.height();
+ }
+ trecs = 0;
+ s << (Q_UINT32)trecs; // total number of records
+ formatOk = FALSE;
+ return TRUE;
+ } else if ( c == PdcEnd ) { // end; calc checksum and close
+ trecs++;
+ s << (Q_UINT8)c << (Q_UINT8)0;
+ QByteArray buf = pictb.buffer();
+ int cs_start = sizeof(Q_UINT32); // pos of checksum word
+ int data_start = cs_start + sizeof(Q_UINT16);
+ int brect_start = data_start + 2*sizeof(Q_INT16) + 2*sizeof(Q_UINT8);
+ int pos = pictb.at();
+ pictb.at( brect_start );
+ if ( formatMajor >= 4 ) { // bounding rectangle
+ s << (Q_INT32)brect.left() << (Q_INT32)brect.top()
+ << (Q_INT32)brect.width() << (Q_INT32)brect.height();
+ }
+ s << (Q_UINT32)trecs; // write number of records
+ pictb.at( cs_start );
+ Q_UINT16 cs = (Q_UINT16)qChecksum( buf.data()+data_start, pos-data_start );
+ s << cs; // write checksum
+ pictb.close();
+ return TRUE;
+ }
+ trecs++;
+ s << (Q_UINT8)c; // write cmd to stream
+ s << (Q_UINT8)0; // write dummy length info
+ int pos = (int)pictb.at(); // save position
+ QRect br; // bounding rect addition
+ bool corr = FALSE; // correction for pen width
+
+ switch ( c ) {
+ case PdcDrawPoint:
+ case PdcMoveTo:
+ case PdcLineTo:
+ case PdcSetBrushOrigin:
+ s << *p[0].point;
+ br = QRect( *p[0].point, QSize( 1, 1 ) );
+ corr = TRUE;
+ break;
+ case PdcDrawLine:
+ s << *p[0].point << *p[1].point;
+ br = QRect( *p[0].point, *p[1].point ).normalize();
+ corr = TRUE;
+ break;
+ case PdcDrawRect:
+ case PdcDrawEllipse:
+ s << *p[0].rect;
+ br = *p[0].rect;
+ corr = TRUE;
+ break;
+ case PdcDrawRoundRect:
+ case PdcDrawArc:
+ case PdcDrawPie:
+ case PdcDrawChord:
+ s << *p[0].rect << (Q_INT16)p[1].ival << (Q_INT16)p[2].ival;
+ br = *p[0].rect;
+ corr = TRUE;
+ break;
+ case PdcDrawLineSegments:
+ case PdcDrawPolyline:
+ s << *p[0].ptarr;
+ br = p[0].ptarr->boundingRect();
+ corr = TRUE;
+ break;
+#ifndef QT_NO_BEZIER
+ case PdcDrawCubicBezier:
+ s << *p[0].ptarr;
+ br = p[0].ptarr->cubicBezier().boundingRect();
+ corr = TRUE;
+ break;
+#endif
+ case PdcDrawPolygon:
+ s << *p[0].ptarr << (Q_INT8)p[1].ival;
+ br = p[0].ptarr->boundingRect();
+ corr = TRUE;
+ break;
+ case PdcDrawText2:
+ if ( formatMajor == 1 ) {
+ pictb.at( pos - 2 );
+ s << (Q_UINT8)PdcDrawText << (Q_UINT8)0;
+ QCString str1( (*p[1].str).latin1() );
+ s << *p[0].point << str1;
+ }
+ else {
+ s << *p[0].point << *p[1].str;
+ }
+ br = pt->fontMetrics().boundingRect( *p[1].str );
+ br.moveBy( p[0].point->x(), p[0].point->y() );
+ break;
+ case PdcDrawText2Formatted:
+ if ( formatMajor == 1 ) {
+ pictb.at( pos - 2 );
+ s << (Q_UINT8)PdcDrawTextFormatted << (Q_UINT8)0;
+ QCString str1( (*p[2].str).latin1() );
+ s << *p[0].rect << (Q_INT16)p[1].ival << str1;
+ }
+ else {
+ s << *p[0].rect << (Q_INT16)p[1].ival << *p[2].str;
+ }
+ br = *p[0].rect;
+ break;
+ case PdcDrawPixmap:
+ if ( formatMajor < 4 ) {
+ s << *p[0].point;
+ s << *p[1].pixmap;
+ br = QRect( *p[0].point, p[1].pixmap->size() );
+ } else {
+ s << *p[0].rect;
+ s << *p[1].pixmap;
+ br = *p[0].rect;
+ }
+ break;
+ case PdcDrawImage:
+ if ( formatMajor < 4 ) {
+ QPoint pt( p[0].point->x(), p[0].point->y() );
+ s << pt;
+ s << *p[1].image;
+ br = QRect( *p[0].point, p[1].image->size() );
+ } else {
+ s << *p[0].rect;
+ s << *p[1].image;
+ br = *p[0].rect;
+ }
+ break;
+ case PdcSave:
+ case PdcRestore:
+ break;
+ case PdcSetBkColor:
+ s << *p[0].color;
+ break;
+ case PdcSetBkMode:
+ case PdcSetROP:
+ s << (Q_INT8)p[0].ival;
+ break;
+ case PdcSetFont: {
+ QFont fnt = *p[0].font;
+ if (fnt.pointSize() > 0)
+ // we have to store pixels to get correct replay.
+ // the resolution is 72 dpi, so points == pixels
+ fnt.setPixelSize(QFontInfo(fnt).pixelSize());
+ s << fnt;
+ }
+ break;
+ case PdcSetPen:
+ s << *p[0].pen;
+ break;
+ case PdcSetBrush:
+ s << *p[0].brush;
+ break;
+ case PdcSetTabStops:
+ s << (Q_INT16)p[0].ival;
+ break;
+ case PdcSetTabArray:
+ s << (Q_INT16)p[0].ival;
+ if ( p[0].ival ) {
+ int *ta = p[1].ivec;
+ for ( int i=0; i<p[0].ival; i++ )
+ s << (Q_INT16)ta[i];
+ }
+ break;
+ case PdcSetUnit:
+ case PdcSetVXform:
+ case PdcSetWXform:
+ case PdcSetClip:
+ s << (Q_INT8)p[0].ival;
+ break;
+#ifndef QT_NO_TRANSFORMATIONS
+ case PdcSetWindow:
+ case PdcSetViewport:
+ s << *p[0].rect;
+ break;
+ case PdcSetWMatrix:
+ s << *p[0].matrix << (Q_INT8)p[1].ival;
+ break;
+#endif
+ case PdcSetClipRegion:
+ s << *p[0].rgn;
+ s << (Q_INT8)p[1].ival;
+ break;
+#if defined(QT_CHECK_RANGE)
+ default:
+ qWarning( "QPicture::cmd: Command %d not recognized", c );
+#endif
+ }
+ int newpos = (int)pictb.at(); // new position
+ int length = newpos - pos;
+ if ( length < 255 ) { // write 8-bit length
+ pictb.at(pos - 1); // position to right index
+ s << (Q_UINT8)length;
+ } else { // write 32-bit length
+ s << (Q_UINT32)0; // extend the buffer
+ pictb.at(pos - 1); // position to right index
+ s << (Q_UINT8)255; // indicate 32-bit length
+ char *p = pictb.buffer().data();
+ memmove( p+pos+4, p+pos, length ); // make room for 4 byte
+ s << (Q_UINT32)length;
+ newpos += 4;
+ }
+ pictb.at( newpos ); // set to new position
+
+ if ( br.isValid() ) {
+ if ( corr ) { // widen bounding rect
+ int w2 = pt->pen().width() / 2;
+ br.setCoords( br.left() - w2, br.top() - w2,
+ br.right() + w2, br.bottom() + w2 );
+ }
+#ifndef QT_NO_TRANSFORMATIONS
+ br = pt->worldMatrix().map( br );
+#endif
+ if ( pt->hasClipping() ) {
+ QRect cr = pt->clipRegion().boundingRect();
+ br &= cr;
+ }
+ if ( br.isValid() )
+ brect |= br; // merge with existing rect
+ }
+
+ return TRUE;
+}
+
+
+/*!
+ Internal implementation of the virtual QPaintDevice::metric()
+ function.
+
+ Use the QPaintDeviceMetrics class instead.
+
+ A picture has the following hard-coded values: dpi=72,
+ numcolors=16777216 and depth=24.
+
+ \a m is the metric to get.
+*/
+
+int QPicture::metric( int m ) const
+{
+ int val;
+ switch ( m ) {
+ // ### hard coded dpi and color depth values !
+ case QPaintDeviceMetrics::PdmWidth:
+ val = d->brect.width();
+ break;
+ case QPaintDeviceMetrics::PdmHeight:
+ val = d->brect.height();
+ break;
+ case QPaintDeviceMetrics::PdmWidthMM:
+ val = int(25.4/72.0*d->brect.width());
+ break;
+ case QPaintDeviceMetrics::PdmHeightMM:
+ val = int(25.4/72.0*d->brect.height());
+ break;
+ case QPaintDeviceMetrics::PdmDpiX:
+ case QPaintDeviceMetrics::PdmPhysicalDpiX:
+ val = 72;
+ break;
+ case QPaintDeviceMetrics::PdmDpiY:
+ case QPaintDeviceMetrics::PdmPhysicalDpiY:
+ val = 72;
+ break;
+ case QPaintDeviceMetrics::PdmNumColors:
+ val = 16777216;
+ break;
+ case QPaintDeviceMetrics::PdmDepth:
+ val = 24;
+ break;
+ default:
+ val = 0;
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QPicture::metric: Invalid metric command" );
+#endif
+ }
+ return val;
+}
+
+/*!
+ Detaches from shared picture data and makes sure that this picture
+ is the only one referring to the data.
+
+ If multiple pictures share common data, this picture makes a copy
+ of the data and detaches itself from the sharing mechanism.
+ Nothing is done if there is just a single reference.
+*/
+
+void QPicture::detach()
+{
+ if ( d->count != 1 )
+ *this = copy();
+}
+
+/*!
+ Returns a \link shclass.html deep copy\endlink of the picture.
+*/
+
+QPicture QPicture::copy() const
+{
+ QPicture p;
+ QByteArray a( size() );
+ memcpy( a.data(), data(), size() );
+ p.d->pictb.setBuffer( a ); // set byte array in buffer
+ if ( d->pictb.isOpen() ) { // copy buffer state
+ p.d->pictb.open( d->pictb.mode() );
+ p.d->pictb.at( d->pictb.at() );
+ }
+ p.d->trecs = d->trecs;
+ p.d->formatOk = d->formatOk;
+ p.d->formatMinor = d->formatMajor;
+ p.d->brect = boundingRect();
+ return p;
+}
+
+/*****************************************************************************
+ QPainter member functions
+ *****************************************************************************/
+
+/*!
+ Replays the picture \a pic translated by (\a x, \a y).
+
+ This function does exactly the same as QPicture::play() when
+ called with (\a x, \a y) = (0, 0).
+*/
+
+void QPainter::drawPicture( int x, int y, const QPicture &pic )
+{
+ save();
+ translate( x, y );
+ ((QPicture*)&pic)->play( (QPainter*)this );
+ restore();
+}
+
+/*!
+ \overload void QPainter::drawPicture( const QPoint &p, const QPicture &pic )
+
+ Draws picture \a pic at point \a p.
+*/
+
+void QPainter::drawPicture( const QPoint &p, const QPicture &pic )
+{
+ drawPicture( p.x(), p.y(), pic );
+}
+
+/*!
+ \obsolete
+
+ Use one of the other QPainter::drawPicture() functions with a (0, 0)
+ offset instead.
+*/
+
+void QPainter::drawPicture( const QPicture &pic )
+{
+ drawPicture( 0, 0, pic );
+}
+
+/*!
+ Assigns a \link shclass.html shallow copy\endlink of \a p to this
+ picture and returns a reference to this picture.
+*/
+
+QPicture& QPicture::operator= (const QPicture& p)
+{
+ p.d->ref(); // avoid 'x = x'
+ if ( d->deref() )
+ delete d;
+ d = p.d;
+ return *this;
+}
+
+
+/*!
+ \internal
+
+ Sets formatOk to FALSE and resets the format version numbers to default
+*/
+
+void QPicture::QPicturePrivate::resetFormat()
+{
+ formatOk = FALSE;
+ formatMajor = mfhdr_maj;
+ formatMinor = mfhdr_min;
+}
+
+/*!
+ \internal
+
+ Checks data integrity and format version number. Set formatOk to TRUE
+ on success, to FALSE otherwise. Returns the resulting formatOk value.
+*/
+
+bool QPicture::QPicturePrivate::checkFormat()
+{
+ resetFormat();
+
+ // can't check anything in an empty buffer
+ if ( pictb.size() == 0 )
+ return FALSE;
+
+ pictb.open( IO_ReadOnly ); // open buffer device
+ QDataStream s;
+ s.setDevice( &pictb ); // attach data stream to buffer
+
+ char mf_id[4]; // picture header tag
+ s.readRawBytes( mf_id, 4 ); // read actual tag
+ if ( memcmp(mf_id, mfhdr_tag, 4) != 0 ) { // wrong header id
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QPicture::checkFormat: Incorrect header" );
+#endif
+ pictb.close();
+ return FALSE;
+ }
+
+ int cs_start = sizeof(Q_UINT32); // pos of checksum word
+ int data_start = cs_start + sizeof(Q_UINT16);
+ Q_UINT16 cs,ccs;
+ QByteArray buf = pictb.buffer(); // pointer to data
+ s >> cs; // read checksum
+ ccs = qChecksum( buf.data() + data_start, buf.size() - data_start );
+ if ( ccs != cs ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QPicture::checkFormat: Invalid checksum %x, %x expected",
+ ccs, cs );
+#endif
+ pictb.close();
+ return FALSE;
+ }
+
+ Q_UINT16 major, minor;
+ s >> major >> minor; // read version number
+ if ( major > mfhdr_maj ) { // new, incompatible version
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QPicture::checkFormat: Incompatible version %d.%d",
+ major, minor);
+#endif
+ pictb.close();
+ return FALSE;
+ }
+ s.setVersion( major != 4 ? major : 3 );
+
+ Q_UINT8 c, clen;
+ s >> c >> clen;
+ if ( c == PdcBegin ) {
+ if ( !( major >= 1 && major <= 3 )) {
+ Q_INT32 l, t, w, h;
+ s >> l >> t >> w >> h;
+ brect = QRect( l, t, w, h );
+ }
+ } else {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QPicture::checkFormat: Format error" );
+#endif
+ pictb.close();
+ return FALSE;
+ }
+ pictb.close();
+
+ formatOk = TRUE; // picture seems to be ok
+ formatMajor = major;
+ formatMinor = minor;
+ return TRUE;
+}
+
+/*****************************************************************************
+ QPicture stream functions
+ *****************************************************************************/
+
+/*!
+ \relates QPicture
+
+ Writes picture \a r to the stream \a s and returns a reference to
+ the stream.
+*/
+
+QDataStream &operator<<( QDataStream &s, const QPicture &r )
+{
+ Q_UINT32 size = r.d->pictb.buffer().size();
+ s << size;
+ // null picture ?
+ if ( size == 0 )
+ return s;
+ // just write the whole buffer to the stream
+ return s.writeRawBytes ( r.d->pictb.buffer().data(),
+ r.d->pictb.buffer().size() );
+}
+
+/*!
+ \relates QPicture
+
+ Reads a picture from the stream \a s into picture \a r and returns
+ a reference to the stream.
+*/
+
+QDataStream &operator>>( QDataStream &s, QPicture &r )
+{
+ QDataStream sr;
+
+ // "init"; this code is similar to the beginning of QPicture::cmd()
+ sr.setDevice( &r.d->pictb );
+ sr.setVersion( r.d->formatMajor );
+ Q_UINT32 len;
+ s >> len;
+ QByteArray data( len );
+ if ( len > 0 )
+ s.readRawBytes( data.data(), len );
+
+ r.d->pictb.setBuffer( data );
+ r.d->resetFormat();
+
+ return s;
+}
+
+#endif // QT_NO_PICTURE
+