source: vendor/trolltech/current/src/kernel/qpicture.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 30.7 KB
Line 
1/****************************************************************************
2** $Id: qpicture.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QPicture class
5**
6** Created : 940802
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accodrance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qpicture.h"
39
40#ifndef QT_NO_PICTURE
41
42#include "qpainter.h"
43#include "qpixmap.h"
44#include "qimage.h"
45#include "qfile.h"
46#include "qdatastream.h"
47#include "qpaintdevicemetrics.h"
48
49#ifndef QT_NO_SVG
50#include "private/qsvgdevice_p.h"
51#endif
52
53/*!
54 \class QPicture qpicture.h
55 \brief The QPicture class is a paint device that records and
56 replays QPainter commands.
57
58 \ingroup graphics
59 \ingroup images
60 \ingroup shared
61
62 A picture serializes painter commands to an IO device in a
63 platform-independent format. For example, a picture created under
64 Windows can be read on a Sun SPARC.
65
66 Pictures are called meta-files on some platforms.
67
68 Qt pictures use a proprietary binary format. Unlike native picture
69 (meta-file) formats on many window systems, Qt pictures have no
70 limitations regarding their contents. Everything that can be
71 painted can also be stored in a picture, e.g. fonts, pixmaps,
72 regions, transformed graphics, etc.
73
74 QPicture is an \link shclass.html implicitly shared\endlink class.
75
76 Example of how to record a picture:
77 \code
78 QPicture pic;
79 QPainter p;
80 p.begin( &pic ); // paint in picture
81 p.drawEllipse( 10,20, 80,70 ); // draw an ellipse
82 p.end(); // painting done
83 pic.save( "drawing.pic" ); // save picture
84 \endcode
85
86 Example of how to replay a picture:
87 \code
88 QPicture pic;
89 pic.load( "drawing.pic" ); // load picture
90 QPainter p;
91 p.begin( &myWidget ); // paint in myWidget
92 p.drawPicture( pic ); // draw the picture
93 p.end(); // painting done
94 \endcode
95
96 Pictures can also be drawn using play(). Some basic data about a
97 picture is available, for example, size(), isNull() and
98 boundingRect().
99
100*/
101
102
103static const char *mfhdr_tag = "QPIC"; // header tag
104static const Q_UINT16 mfhdr_maj = 5; // major version #
105static const Q_UINT16 mfhdr_min = 0; // minor version #
106
107
108/*!
109 Constructs an empty picture.
110
111 The \a formatVersion parameter may be used to \e create a QPicture
112 that can be read by applications that are compiled with earlier
113 versions of Qt.
114 \list
115 \i \a formatVersion == 1 is binary compatible with Qt 1.x and later.
116 \i \a formatVersion == 2 is binary compatible with Qt 2.0.x and later.
117 \i \a formatVersion == 3 is binary compatible with Qt 2.1.x and later.
118 \i \a formatVersion == 4 is binary compatible with Qt 3.0.x and later.
119 \i \a formatVersion == 5 is binary compatible with Qt 3.1.
120 \endlist
121
122 Note that the default formatVersion is -1 which signifies the
123 current release, i.e. for Qt 3.1 a formatVersion of 5 is the same
124 as the default formatVersion of -1.
125
126 Reading pictures generated by earlier versions of Qt is supported
127 and needs no special coding; the format is automatically detected.
128*/
129
130QPicture::QPicture( int formatVersion )
131 : QPaintDevice( QInternal::Picture | QInternal::ExternalDevice )
132 // set device type
133{
134 d = new QPicturePrivate;
135
136#if defined(QT_CHECK_RANGE)
137 if ( formatVersion == 0 )
138 qWarning( "QPicture: invalid format version 0" );
139#endif
140
141 // still accept the 0 default from before Qt 3.0.
142 if ( formatVersion > 0 && formatVersion != (int)mfhdr_maj ) {
143 d->formatMajor = formatVersion;
144 d->formatMinor = 0;
145 d->formatOk = FALSE;
146 }
147 else {
148 d->resetFormat();
149 }
150}
151
152/*!
153 Constructs a \link shclass.html shallow copy\endlink of \a pic.
154*/
155
156QPicture::QPicture( const QPicture &pic )
157 : QPaintDevice( QInternal::Picture | QInternal::ExternalDevice )
158{
159 d = pic.d;
160 d->ref();
161}
162
163/*!
164 Destroys the picture.
165*/
166QPicture::~QPicture()
167{
168 if ( d->deref() )
169 delete d;
170}
171
172
173/*!
174 \fn bool QPicture::isNull() const
175
176 Returns TRUE if the picture contains no data; otherwise returns
177 FALSE.
178*/
179
180/*!
181 \fn uint QPicture::size() const
182
183 Returns the size of the picture data.
184
185 \sa data()
186*/
187
188/*!
189 \fn const char* QPicture::data() const
190
191 Returns a pointer to the picture data. The pointer is only valid
192 until the next non-const function is called on this picture. The
193 returned pointer is 0 if the picture contains no data.
194
195 \sa size(), isNull()
196*/
197
198/*!
199 Sets the picture data directly from \a data and \a size. This
200 function copies the input data.
201
202 \sa data(), size()
203*/
204
205void QPicture::setData( const char* data, uint size )
206{
207 detach();
208 QByteArray a( size );
209 memcpy( a.data(), data, size );
210 d->pictb.setBuffer( a ); // set byte array in buffer
211 d->resetFormat(); // we'll have to check
212}
213
214
215/*!
216 Loads a picture from the file specified by \a fileName and returns
217 TRUE if successful; otherwise returns FALSE.
218
219 By default, the file will be interpreted as being in the native
220 QPicture format. Specifying the \a format string is optional and
221 is only needed for importing picture data stored in a different
222 format.
223
224 Currently, the only external format supported is the \link
225 http://www.w3.org/Graphics/SVG/ W3C SVG \endlink format which
226 requires the \link xml.html Qt XML module \endlink. The
227 corresponding \a format string is "svg".
228
229 \sa save()
230*/
231
232bool QPicture::load( const QString &fileName, const char *format )
233{
234 QFile f( fileName );
235 if ( !f.open(IO_ReadOnly) )
236 return FALSE;
237 return load( &f, format );
238}
239
240/*!
241 \overload
242
243 \a dev is the device to use for loading.
244*/
245
246bool QPicture::load( QIODevice *dev, const char *format )
247{
248#ifndef QT_NO_SVG
249 if ( qstrcmp( format, "svg" ) == 0 ) {
250 QSvgDevice svg;
251 if ( !svg.load( dev ) )
252 return FALSE;
253 QPainter p( this );
254 bool b = svg.play( &p );
255 d->brect = svg.boundingRect();
256 return b;
257 }
258#endif
259 if ( format ) {
260 qWarning( "QPicture::load: No such picture format: %s", format );
261 return FALSE;
262 }
263
264 detach();
265 QByteArray a = dev->readAll();
266 d->pictb.setBuffer( a ); // set byte array in buffer
267 return d->checkFormat();
268}
269
270/*!
271 Saves a picture to the file specified by \a fileName and returns
272 TRUE if successful; otherwise returns FALSE.
273
274 Specifying the file \a format string is optional. It's not
275 recommended unless you intend to export the picture data for
276 use by a third party reader. By default the data will be saved in
277 the native QPicture file format.
278
279 Currently, the only external format supported is the \link
280 http://www.w3.org/Graphics/SVG/ W3C SVG \endlink format which
281 requires the \link xml.html Qt XML module \endlink. The
282 corresponding \a format string is "svg".
283
284 \sa load()
285*/
286
287bool QPicture::save( const QString &fileName, const char *format )
288{
289 if ( paintingActive() ) {
290#if defined(QT_CHECK_STATE)
291 qWarning( "QPicture::save: still being painted on. "
292 "Call QPainter::end() first" );
293#endif
294 return FALSE;
295 }
296
297#ifndef QT_NO_SVG
298 // identical to QIODevice* code below but the file name
299 // makes a difference when it comes to saving pixmaps
300 if ( qstricmp( format, "svg" ) == 0 ) {
301 QSvgDevice svg;
302 QPainter p( &svg );
303 if ( !play( &p ) )
304 return FALSE;
305 svg.setBoundingRect( boundingRect() );
306 return svg.save( fileName );
307 }
308#endif
309
310 QFile f( fileName );
311 if ( !f.open(IO_WriteOnly) )
312 return FALSE;
313 return save( &f, format );
314}
315
316/*!
317 \overload
318
319 \a dev is the device to use for saving.
320*/
321
322bool QPicture::save( QIODevice *dev, const char *format )
323{
324 if ( paintingActive() ) {
325#if defined(QT_CHECK_STATE)
326 qWarning( "QPicture::save: still being painted on. "
327 "Call QPainter::end() first" );
328#endif
329 return FALSE;
330 }
331
332#ifndef QT_NO_SVG
333 if ( qstricmp( format, "svg" ) == 0 ) {
334 QSvgDevice svg;
335 QPainter p( &svg );
336 if ( !play( &p ) )
337 return FALSE;
338 svg.setBoundingRect( boundingRect() );
339 return svg.save( dev );
340 }
341#endif
342 if ( format ) {
343 qWarning( "QPicture::save: No such picture format: %s", format );
344 return FALSE;
345 }
346
347 dev->writeBlock( d->pictb.buffer().data(), d->pictb.buffer().size() );
348 return TRUE;
349}
350
351/*!
352 Returns the picture's bounding rectangle or an invalid rectangle
353 if the picture contains no data.
354*/
355
356QRect QPicture::boundingRect() const
357{
358 if ( !d->formatOk )
359 d->checkFormat();
360 return d->brect;
361}
362
363/*!
364 Sets the picture's bounding rectangle to \a r. The automatically
365 calculated value is overriden.
366*/
367
368void QPicture::setBoundingRect( const QRect &r )
369{
370 if ( !d->formatOk )
371 d->checkFormat();
372 d->brect = r;
373}
374
375/*!
376 Replays the picture using \a painter, and returns TRUE if
377 successful; otherwise returns FALSE.
378
379 This function does exactly the same as QPainter::drawPicture()
380 with (x, y) = (0, 0).
381*/
382
383bool QPicture::play( QPainter *painter )
384{
385 if ( d->pictb.size() == 0 ) // nothing recorded
386 return TRUE;
387
388 if ( !d->formatOk && !d->checkFormat() )
389 return FALSE;
390
391 d->pictb.open( IO_ReadOnly ); // open buffer device
392 QDataStream s;
393 s.setDevice( &d->pictb ); // attach data stream to buffer
394 s.device()->at( 10 ); // go directly to the data
395 s.setVersion( d->formatMajor == 4 ? 3 : d->formatMajor );
396
397 Q_UINT8 c, clen;
398 Q_UINT32 nrecords;
399 s >> c >> clen;
400 Q_ASSERT( c == PdcBegin );
401 // bounding rect was introduced in ver 4. Read in checkFormat().
402 if ( d->formatMajor >= 4 ) {
403 Q_INT32 dummy;
404 s >> dummy >> dummy >> dummy >> dummy;
405 }
406 s >> nrecords;
407 if ( !exec( painter, s, nrecords ) ) {
408#if defined(QT_CHECK_RANGE)
409 qWarning( "QPicture::play: Format error" );
410#endif
411 d->pictb.close();
412 return FALSE;
413 }
414 d->pictb.close();
415 return TRUE; // no end-command
416}
417
418
419/*!
420 \internal
421 Iterates over the internal picture data and draws the picture using
422 \a painter.
423*/
424
425bool QPicture::exec( QPainter *painter, QDataStream &s, int nrecords )
426{
427#if defined(QT_DEBUG)
428 int strm_pos;
429#endif
430 Q_UINT8 c; // command id
431 Q_UINT8 tiny_len; // 8-bit length descriptor
432 Q_INT32 len; // 32-bit length descriptor
433 Q_INT16 i_16, i1_16, i2_16; // parameters...
434 Q_INT8 i_8;
435 Q_UINT32 ul;
436 QCString str1;
437 QString str;
438 QPoint p, p1, p2;
439 QRect r;
440 QPointArray a;
441 QColor color;
442 QFont font;
443 QPen pen;
444 QBrush brush;
445 QRegion rgn;
446#ifndef QT_NO_TRANSFORMATIONS
447 QWMatrix matrix;
448#endif
449
450 while ( nrecords-- && !s.eof() ) {
451 s >> c; // read cmd
452 s >> tiny_len; // read param length
453 if ( tiny_len == 255 ) // longer than 254 bytes
454 s >> len;
455 else
456 len = tiny_len;
457#if defined(QT_DEBUG)
458 strm_pos = s.device()->at();
459#endif
460 switch ( c ) { // exec cmd
461 case PdcNOP:
462 break;
463 case PdcDrawPoint:
464 s >> p;
465 painter->drawPoint( p );
466 break;
467 case PdcMoveTo:
468 s >> p;
469 painter->moveTo( p );
470 break;
471 case PdcLineTo:
472 s >> p;
473 painter->lineTo( p );
474 break;
475 case PdcDrawLine:
476 s >> p1 >> p2;
477 painter->drawLine( p1, p2 );
478 break;
479 case PdcDrawRect:
480 s >> r;
481 painter->drawRect( r );
482 break;
483 case PdcDrawRoundRect:
484 s >> r >> i1_16 >> i2_16;
485 painter->drawRoundRect( r, i1_16, i2_16 );
486 break;
487 case PdcDrawEllipse:
488 s >> r;
489 painter->drawEllipse( r );
490 break;
491 case PdcDrawArc:
492 s >> r >> i1_16 >> i2_16;
493 painter->drawArc( r, i1_16, i2_16 );
494 break;
495 case PdcDrawPie:
496 s >> r >> i1_16 >> i2_16;
497 painter->drawPie( r, i1_16, i2_16 );
498 break;
499 case PdcDrawChord:
500 s >> r >> i1_16 >> i2_16;
501 painter->drawChord( r, i1_16, i2_16 );
502 break;
503 case PdcDrawLineSegments:
504 s >> a;
505 painter->drawLineSegments( a );
506 break;
507 case PdcDrawPolyline:
508 s >> a;
509 painter->drawPolyline( a );
510 break;
511 case PdcDrawPolygon:
512 s >> a >> i_8;
513 painter->drawPolygon( a, i_8 );
514 break;
515 case PdcDrawCubicBezier:
516 s >> a;
517#ifndef QT_NO_BEZIER
518 painter->drawCubicBezier( a );
519#endif
520 break;
521 case PdcDrawText:
522 s >> p >> str1;
523 painter->drawText( p, str1 );
524 break;
525 case PdcDrawTextFormatted:
526 s >> r >> i_16 >> str1;
527 painter->drawText( r, i_16, str1 );
528 break;
529 case PdcDrawText2:
530 s >> p >> str;
531 painter->drawText( p, str );
532 break;
533 case PdcDrawText2Formatted:
534 s >> r >> i_16 >> str;
535 painter->drawText( r, i_16, str );
536 break;
537 case PdcDrawPixmap: {
538 QPixmap pixmap;
539 if ( d->formatMajor < 4 ) {
540 s >> p >> pixmap;
541 painter->drawPixmap( p, pixmap );
542 } else {
543 s >> r >> pixmap;
544 painter->drawPixmap( r, pixmap );
545 }
546 }
547 break;
548 case PdcDrawImage: {
549 QImage image;
550 if ( d->formatMajor < 4 ) {
551 s >> p >> image;
552 painter->drawImage( p, image );
553 } else {
554 s >> r >> image;
555 painter->drawImage( r, image );
556 }
557 }
558 break;
559 case PdcBegin:
560 s >> ul; // number of records
561 if ( !exec( painter, s, ul ) )
562 return FALSE;
563 break;
564 case PdcEnd:
565 if ( nrecords == 0 )
566 return TRUE;
567 break;
568 case PdcSave:
569 painter->save();
570 break;
571 case PdcRestore:
572 painter->restore();
573 break;
574 case PdcSetBkColor:
575 s >> color;
576 painter->setBackgroundColor( color );
577 break;
578 case PdcSetBkMode:
579 s >> i_8;
580 painter->setBackgroundMode( (Qt::BGMode)i_8 );
581 break;
582 case PdcSetROP:
583 s >> i_8;
584 painter->setRasterOp( (Qt::RasterOp)i_8 );
585 break;
586 case PdcSetBrushOrigin:
587 s >> p;
588 painter->setBrushOrigin( p );
589 break;
590 case PdcSetFont:
591 s >> font;
592 painter->setFont( font );
593 break;
594 case PdcSetPen:
595 s >> pen;
596 painter->setPen( pen );
597 break;
598 case PdcSetBrush:
599 s >> brush;
600 painter->setBrush( brush );
601 break;
602 case PdcSetTabStops:
603 s >> i_16;
604 painter->setTabStops( i_16 );
605 break;
606 case PdcSetTabArray:
607 s >> i_16;
608 if ( i_16 == 0 ) {
609 painter->setTabArray( 0 );
610 } else {
611 int *ta = new int[i_16];
612 Q_CHECK_PTR( ta );
613 for ( int i=0; i<i_16; i++ ) {
614 s >> i1_16;
615 ta[i] = i1_16;
616 }
617 painter->setTabArray( ta );
618 delete [] ta;
619 }
620 break;
621 case PdcSetVXform:
622 s >> i_8;
623#ifndef QT_NO_TRANSFORMATIONS
624 painter->setViewXForm( i_8 );
625#endif
626 break;
627 case PdcSetWindow:
628 s >> r;
629#ifndef QT_NO_TRANSFORMATIONS
630 painter->setWindow( r );
631#endif
632 break;
633 case PdcSetViewport:
634 s >> r;
635#ifndef QT_NO_TRANSFORMATIONS
636 painter->setViewport( r );
637#endif
638 break;
639 case PdcSetWXform:
640 s >> i_8;
641#ifndef QT_NO_TRANSFORMATIONS
642 painter->setWorldXForm( i_8 );
643#endif
644 break;
645 case PdcSetWMatrix:
646#ifndef QT_NO_TRANSFORMATIONS // #### fix me!
647 s >> matrix >> i_8;
648 painter->setWorldMatrix( matrix, i_8 );
649#endif
650 break;
651#ifndef QT_NO_TRANSFORMATIONS
652 case PdcSaveWMatrix:
653 painter->saveWorldMatrix();
654 break;
655 case PdcRestoreWMatrix:
656 painter->restoreWorldMatrix();
657 break;
658#endif
659 case PdcSetClip:
660 s >> i_8;
661 painter->setClipping( i_8 );
662 break;
663 case PdcSetClipRegion:
664 s >> rgn >> i_8;
665 painter->setClipRegion( rgn, (QPainter::CoordinateMode)i_8 );
666 break;
667 default:
668#if defined(QT_CHECK_RANGE)
669 qWarning( "QPicture::play: Invalid command %d", c );
670#endif
671 if ( len ) // skip unknown command
672 s.device()->at( s.device()->at()+len );
673 }
674#if defined(QT_DEBUG)
675 //qDebug( "device->at(): %i, strm_pos: %i len: %i", s.device()->at(), strm_pos, len );
676 Q_ASSERT( Q_INT32(s.device()->at() - strm_pos) == len );
677#endif
678 }
679 return FALSE;
680}
681
682
683/*!
684 \internal
685 Records painter commands and stores them in the pictb buffer.
686*/
687
688bool QPicture::cmd( int c, QPainter *pt, QPDevCmdParam *p )
689{
690 detach();
691 return d->cmd( c, pt, p );
692}
693
694/*!
695 \internal
696 Implementation of the function forwarded above to the internal data struct.
697*/
698
699bool QPicture::QPicturePrivate::cmd( int c, QPainter *pt, QPDevCmdParam *p )
700{
701 QDataStream s;
702 s.setDevice( &pictb );
703 // when moving up to 4 the QDataStream version remained at 3
704 s.setVersion( formatMajor != 4 ? formatMajor : 3 );
705 if ( c == PdcBegin ) { // begin; write header
706 QByteArray empty( 0 );
707 pictb.setBuffer( empty ); // reset byte array in buffer
708 pictb.open( IO_WriteOnly );
709 s.writeRawBytes( mfhdr_tag, 4 );
710 s << (Q_UINT16)0 << (Q_UINT16)formatMajor << (Q_UINT16)formatMinor;
711 s << (Q_UINT8)c << (Q_UINT8)sizeof(Q_INT32);
712 brect = QRect();
713 if ( formatMajor >= 4 ) {
714 s << (Q_INT32)brect.left() << (Q_INT32)brect.top()
715 << (Q_INT32)brect.width() << (Q_INT32)brect.height();
716 }
717 trecs = 0;
718 s << (Q_UINT32)trecs; // total number of records
719 formatOk = FALSE;
720 return TRUE;
721 } else if ( c == PdcEnd ) { // end; calc checksum and close
722 trecs++;
723 s << (Q_UINT8)c << (Q_UINT8)0;
724 QByteArray buf = pictb.buffer();
725 int cs_start = sizeof(Q_UINT32); // pos of checksum word
726 int data_start = cs_start + sizeof(Q_UINT16);
727 int brect_start = data_start + 2*sizeof(Q_INT16) + 2*sizeof(Q_UINT8);
728 int pos = pictb.at();
729 pictb.at( brect_start );
730 if ( formatMajor >= 4 ) { // bounding rectangle
731 s << (Q_INT32)brect.left() << (Q_INT32)brect.top()
732 << (Q_INT32)brect.width() << (Q_INT32)brect.height();
733 }
734 s << (Q_UINT32)trecs; // write number of records
735 pictb.at( cs_start );
736 Q_UINT16 cs = (Q_UINT16)qChecksum( buf.data()+data_start, pos-data_start );
737 s << cs; // write checksum
738 pictb.close();
739 return TRUE;
740 }
741 trecs++;
742 s << (Q_UINT8)c; // write cmd to stream
743 s << (Q_UINT8)0; // write dummy length info
744 int pos = (int)pictb.at(); // save position
745 QRect br; // bounding rect addition
746 bool corr = FALSE; // correction for pen width
747
748 switch ( c ) {
749 case PdcDrawPoint:
750 case PdcMoveTo:
751 case PdcLineTo:
752 case PdcSetBrushOrigin:
753 s << *p[0].point;
754 br = QRect( *p[0].point, QSize( 1, 1 ) );
755 corr = TRUE;
756 break;
757 case PdcDrawLine:
758 s << *p[0].point << *p[1].point;
759 br = QRect( *p[0].point, *p[1].point ).normalize();
760 corr = TRUE;
761 break;
762 case PdcDrawRect:
763 case PdcDrawEllipse:
764 s << *p[0].rect;
765 br = *p[0].rect;
766 corr = TRUE;
767 break;
768 case PdcDrawRoundRect:
769 case PdcDrawArc:
770 case PdcDrawPie:
771 case PdcDrawChord:
772 s << *p[0].rect << (Q_INT16)p[1].ival << (Q_INT16)p[2].ival;
773 br = *p[0].rect;
774 corr = TRUE;
775 break;
776 case PdcDrawLineSegments:
777 case PdcDrawPolyline:
778 s << *p[0].ptarr;
779 br = p[0].ptarr->boundingRect();
780 corr = TRUE;
781 break;
782#ifndef QT_NO_BEZIER
783 case PdcDrawCubicBezier:
784 s << *p[0].ptarr;
785 br = p[0].ptarr->cubicBezier().boundingRect();
786 corr = TRUE;
787 break;
788#endif
789 case PdcDrawPolygon:
790 s << *p[0].ptarr << (Q_INT8)p[1].ival;
791 br = p[0].ptarr->boundingRect();
792 corr = TRUE;
793 break;
794 case PdcDrawText2:
795 if ( formatMajor == 1 ) {
796 pictb.at( pos - 2 );
797 s << (Q_UINT8)PdcDrawText << (Q_UINT8)0;
798 QCString str1( (*p[1].str).latin1() );
799 s << *p[0].point << str1;
800 }
801 else {
802 s << *p[0].point << *p[1].str;
803 }
804 br = pt->fontMetrics().boundingRect( *p[1].str );
805 br.moveBy( p[0].point->x(), p[0].point->y() );
806 break;
807 case PdcDrawText2Formatted:
808 if ( formatMajor == 1 ) {
809 pictb.at( pos - 2 );
810 s << (Q_UINT8)PdcDrawTextFormatted << (Q_UINT8)0;
811 QCString str1( (*p[2].str).latin1() );
812 s << *p[0].rect << (Q_INT16)p[1].ival << str1;
813 }
814 else {
815 s << *p[0].rect << (Q_INT16)p[1].ival << *p[2].str;
816 }
817 br = *p[0].rect;
818 break;
819 case PdcDrawPixmap:
820 if ( formatMajor < 4 ) {
821 s << *p[0].point;
822 s << *p[1].pixmap;
823 br = QRect( *p[0].point, p[1].pixmap->size() );
824 } else {
825 s << *p[0].rect;
826 s << *p[1].pixmap;
827 br = *p[0].rect;
828 }
829 break;
830 case PdcDrawImage:
831 if ( formatMajor < 4 ) {
832 QPoint pt( p[0].point->x(), p[0].point->y() );
833 s << pt;
834 s << *p[1].image;
835 br = QRect( *p[0].point, p[1].image->size() );
836 } else {
837 s << *p[0].rect;
838 s << *p[1].image;
839 br = *p[0].rect;
840 }
841 break;
842 case PdcSave:
843 case PdcRestore:
844 break;
845 case PdcSetBkColor:
846 s << *p[0].color;
847 break;
848 case PdcSetBkMode:
849 case PdcSetROP:
850 s << (Q_INT8)p[0].ival;
851 break;
852 case PdcSetFont:
853 s << *p[0].font;
854 break;
855 case PdcSetPen:
856 s << *p[0].pen;
857 break;
858 case PdcSetBrush:
859 s << *p[0].brush;
860 break;
861 case PdcSetTabStops:
862 s << (Q_INT16)p[0].ival;
863 break;
864 case PdcSetTabArray:
865 s << (Q_INT16)p[0].ival;
866 if ( p[0].ival ) {
867 int *ta = p[1].ivec;
868 for ( int i=0; i<p[0].ival; i++ )
869 s << (Q_INT16)ta[i];
870 }
871 break;
872 case PdcSetUnit:
873 case PdcSetVXform:
874 case PdcSetWXform:
875 case PdcSetClip:
876 s << (Q_INT8)p[0].ival;
877 break;
878#ifndef QT_NO_TRANSFORMATIONS
879 case PdcSetWindow:
880 case PdcSetViewport:
881 s << *p[0].rect;
882 break;
883 case PdcSetWMatrix:
884 s << *p[0].matrix << (Q_INT8)p[1].ival;
885 break;
886#endif
887 case PdcSetClipRegion:
888 s << *p[0].rgn;
889 s << (Q_INT8)p[1].ival;
890 break;
891#if defined(QT_CHECK_RANGE)
892 default:
893 qWarning( "QPicture::cmd: Command %d not recognized", c );
894#endif
895 }
896 int newpos = (int)pictb.at(); // new position
897 int length = newpos - pos;
898 if ( length < 255 ) { // write 8-bit length
899 pictb.at(pos - 1); // position to right index
900 s << (Q_UINT8)length;
901 } else { // write 32-bit length
902 s << (Q_UINT32)0; // extend the buffer
903 pictb.at(pos - 1); // position to right index
904 s << (Q_UINT8)255; // indicate 32-bit length
905 char *p = pictb.buffer().data();
906 memmove( p+pos+4, p+pos, length ); // make room for 4 byte
907 s << (Q_UINT32)length;
908 newpos += 4;
909 }
910 pictb.at( newpos ); // set to new position
911
912 if ( br.isValid() ) {
913 if ( corr ) { // widen bounding rect
914 int w2 = pt->pen().width() / 2;
915 br.setCoords( br.left() - w2, br.top() - w2,
916 br.right() + w2, br.bottom() + w2 );
917 }
918#ifndef QT_NO_TRANSFORMATIONS
919 br = pt->worldMatrix().map( br );
920#endif
921 if ( pt->hasClipping() ) {
922 QRect cr = pt->clipRegion().boundingRect();
923 br &= cr;
924 }
925 if ( br.isValid() )
926 brect |= br; // merge with existing rect
927 }
928
929 return TRUE;
930}
931
932
933/*!
934 Internal implementation of the virtual QPaintDevice::metric()
935 function.
936
937 Use the QPaintDeviceMetrics class instead.
938
939 A picture has the following hard-coded values: dpi=72,
940 numcolors=16777216 and depth=24.
941
942 \a m is the metric to get.
943*/
944
945int QPicture::metric( int m ) const
946{
947 int val;
948 switch ( m ) {
949 // ### hard coded dpi and color depth values !
950 case QPaintDeviceMetrics::PdmWidth:
951 val = d->brect.width();
952 break;
953 case QPaintDeviceMetrics::PdmHeight:
954 val = d->brect.height();
955 break;
956 case QPaintDeviceMetrics::PdmWidthMM:
957 val = int(25.4/72.0*d->brect.width());
958 break;
959 case QPaintDeviceMetrics::PdmHeightMM:
960 val = int(25.4/72.0*d->brect.height());
961 break;
962 case QPaintDeviceMetrics::PdmDpiX:
963 case QPaintDeviceMetrics::PdmPhysicalDpiX:
964 val = 72;
965 break;
966 case QPaintDeviceMetrics::PdmDpiY:
967 case QPaintDeviceMetrics::PdmPhysicalDpiY:
968 val = 72;
969 break;
970 case QPaintDeviceMetrics::PdmNumColors:
971 val = 16777216;
972 break;
973 case QPaintDeviceMetrics::PdmDepth:
974 val = 24;
975 break;
976 default:
977 val = 0;
978#if defined(QT_CHECK_RANGE)
979 qWarning( "QPicture::metric: Invalid metric command" );
980#endif
981 }
982 return val;
983}
984
985/*!
986 Detaches from shared picture data and makes sure that this picture
987 is the only one referring to the data.
988
989 If multiple pictures share common data, this picture makes a copy
990 of the data and detaches itself from the sharing mechanism.
991 Nothing is done if there is just a single reference.
992*/
993
994void QPicture::detach()
995{
996 if ( d->count != 1 )
997 *this = copy();
998}
999
1000/*!
1001 Returns a \link shclass.html deep copy\endlink of the picture.
1002*/
1003
1004QPicture QPicture::copy() const
1005{
1006 QPicture p;
1007 QByteArray a( size() );
1008 memcpy( a.data(), data(), size() );
1009 p.d->pictb.setBuffer( a ); // set byte array in buffer
1010 if ( d->pictb.isOpen() ) { // copy buffer state
1011 p.d->pictb.open( d->pictb.mode() );
1012 p.d->pictb.at( d->pictb.at() );
1013 }
1014 p.d->trecs = d->trecs;
1015 p.d->formatOk = d->formatOk;
1016 p.d->formatMinor = d->formatMajor;
1017 p.d->brect = boundingRect();
1018 return p;
1019}
1020
1021/*****************************************************************************
1022 QPainter member functions
1023 *****************************************************************************/
1024
1025/*!
1026 Replays the picture \a pic translated by (\a x, \a y).
1027
1028 This function does exactly the same as QPicture::play() when
1029 called with (\a x, \a y) = (0, 0).
1030*/
1031
1032void QPainter::drawPicture( int x, int y, const QPicture &pic )
1033{
1034 save();
1035 translate( x, y );
1036 ((QPicture*)&pic)->play( (QPainter*)this );
1037 restore();
1038}
1039
1040/*!
1041 \overload void QPainter::drawPicture( const QPoint &p, const QPicture &pic )
1042
1043 Draws picture \a pic at point \a p.
1044*/
1045
1046void QPainter::drawPicture( const QPoint &p, const QPicture &pic )
1047{
1048 drawPicture( p.x(), p.y(), pic );
1049}
1050
1051/*!
1052 \obsolete
1053
1054 Use one of the other QPainter::drawPicture() functions with a (0, 0)
1055 offset instead.
1056*/
1057
1058void QPainter::drawPicture( const QPicture &pic )
1059{
1060 drawPicture( 0, 0, pic );
1061}
1062
1063/*!
1064 Assigns a \link shclass.html shallow copy\endlink of \a p to this
1065 picture and returns a reference to this picture.
1066*/
1067
1068QPicture& QPicture::operator= (const QPicture& p)
1069{
1070 p.d->ref(); // avoid 'x = x'
1071 if ( d->deref() )
1072 delete d;
1073 d = p.d;
1074 return *this;
1075}
1076
1077
1078/*!
1079 \internal
1080
1081 Sets formatOk to FALSE and resets the format version numbers to default
1082*/
1083
1084void QPicture::QPicturePrivate::resetFormat()
1085{
1086 formatOk = FALSE;
1087 formatMajor = mfhdr_maj;
1088 formatMinor = mfhdr_min;
1089}
1090
1091/*!
1092 \internal
1093
1094 Checks data integrity and format version number. Set formatOk to TRUE
1095 on success, to FALSE otherwise. Returns the resulting formatOk value.
1096*/
1097
1098bool QPicture::QPicturePrivate::checkFormat()
1099{
1100 resetFormat();
1101
1102 // can't check anything in an empty buffer
1103 if ( pictb.size() == 0 )
1104 return FALSE;
1105
1106 pictb.open( IO_ReadOnly ); // open buffer device
1107 QDataStream s;
1108 s.setDevice( &pictb ); // attach data stream to buffer
1109
1110 char mf_id[4]; // picture header tag
1111 s.readRawBytes( mf_id, 4 ); // read actual tag
1112 if ( memcmp(mf_id, mfhdr_tag, 4) != 0 ) { // wrong header id
1113#if defined(QT_CHECK_RANGE)
1114 qWarning( "QPicture::checkFormat: Incorrect header" );
1115#endif
1116 pictb.close();
1117 return FALSE;
1118 }
1119
1120 int cs_start = sizeof(Q_UINT32); // pos of checksum word
1121 int data_start = cs_start + sizeof(Q_UINT16);
1122 Q_UINT16 cs,ccs;
1123 QByteArray buf = pictb.buffer(); // pointer to data
1124 s >> cs; // read checksum
1125 ccs = qChecksum( buf.data() + data_start, buf.size() - data_start );
1126 if ( ccs != cs ) {
1127#if defined(QT_CHECK_STATE)
1128 qWarning( "QPicture::checkFormat: Invalid checksum %x, %x expected",
1129 ccs, cs );
1130#endif
1131 pictb.close();
1132 return FALSE;
1133 }
1134
1135 Q_UINT16 major, minor;
1136 s >> major >> minor; // read version number
1137 if ( major > mfhdr_maj ) { // new, incompatible version
1138#if defined(QT_CHECK_RANGE)
1139 qWarning( "QPicture::checkFormat: Incompatible version %d.%d",
1140 major, minor);
1141#endif
1142 pictb.close();
1143 return FALSE;
1144 }
1145 s.setVersion( major != 4 ? major : 3 );
1146
1147 Q_UINT8 c, clen;
1148 s >> c >> clen;
1149 if ( c == PdcBegin ) {
1150 if ( !( major >= 1 && major <= 3 )) {
1151 Q_INT32 l, t, w, h;
1152 s >> l >> t >> w >> h;
1153 brect = QRect( l, t, w, h );
1154 }
1155 } else {
1156#if defined(QT_CHECK_RANGE)
1157 qWarning( "QPicture::checkFormat: Format error" );
1158#endif
1159 pictb.close();
1160 return FALSE;
1161 }
1162 pictb.close();
1163
1164 formatOk = TRUE; // picture seems to be ok
1165 formatMajor = major;
1166 formatMinor = minor;
1167 return TRUE;
1168}
1169
1170/*****************************************************************************
1171 QPicture stream functions
1172 *****************************************************************************/
1173
1174/*!
1175 \relates QPicture
1176
1177 Writes picture \a r to the stream \a s and returns a reference to
1178 the stream.
1179*/
1180
1181QDataStream &operator<<( QDataStream &s, const QPicture &r )
1182{
1183 Q_UINT32 size = r.d->pictb.buffer().size();
1184 s << size;
1185 // null picture ?
1186 if ( size == 0 )
1187 return s;
1188 // just write the whole buffer to the stream
1189 return s.writeRawBytes ( r.d->pictb.buffer().data(),
1190 r.d->pictb.buffer().size() );
1191}
1192
1193/*!
1194 \relates QPicture
1195
1196 Reads a picture from the stream \a s into picture \a r and returns
1197 a reference to the stream.
1198*/
1199
1200QDataStream &operator>>( QDataStream &s, QPicture &r )
1201{
1202 QDataStream sr;
1203
1204 // "init"; this code is similar to the beginning of QPicture::cmd()
1205 sr.setDevice( &r.d->pictb );
1206 sr.setVersion( r.d->formatMajor );
1207 Q_UINT32 len;
1208 s >> len;
1209 QByteArray data( len );
1210 if ( len > 0 )
1211 s.readRawBytes( data.data(), len );
1212
1213 r.d->pictb.setBuffer( data );
1214 r.d->resetFormat();
1215
1216 return s;
1217}
1218
1219#endif // QT_NO_PICTURE
1220
Note: See TracBrowser for help on using the repository browser.