00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <math.h>
00021 #include <assert.h>
00022
00023 #include <QFileInfo>
00024 #include <QPixmap>
00025 #include <QPainter>
00026 #include <QPainterPath>
00027 #include <QDataStream>
00028 #include <QApplication>
00029 #include <QBuffer>
00030
00031 #include <Q3CString>
00032 #include <QPolygon>
00033
00034 #include <kdebug.h>
00035
00036 bool qwmfDebug = false;
00037
00038 #include "qwmf.h"
00039 #include "wmfstruct.h"
00040 #include "metafuncs.h"
00041
00042 #define QWMF_DEBUG 0
00043
00044
00045 class WmfCmd
00046 {
00047 public:
00048 ~WmfCmd() { if ( next ) delete next; }
00049 WmfCmd* next;
00050 unsigned short funcIndex;
00051 long numParm;
00052 short* parm;
00053 };
00054
00055
00056 class WinObjHandle
00057 {
00058 public:
00059 virtual ~WinObjHandle() {}
00060 virtual void apply( QPainter& p ) = 0;
00061 };
00062
00063 class WinObjBrushHandle: public WinObjHandle
00064 {
00065 public:
00066 virtual void apply( QPainter& p );
00067 QBrush brush;
00068 virtual ~WinObjBrushHandle() {};
00069 };
00070
00071 class WinObjPenHandle: public WinObjHandle
00072 {
00073 public:
00074 virtual void apply( QPainter& p );
00075 QPen pen;
00076 virtual ~WinObjPenHandle() {};
00077 };
00078
00079 class WinObjPatternBrushHandle: public WinObjHandle
00080 {
00081 public:
00082 virtual void apply( QPainter& p );
00083 QBrush brush;
00084 QPixmap image;
00085 virtual ~WinObjPatternBrushHandle() {};
00086 };
00087
00088 class WinObjFontHandle: public WinObjHandle
00089 {
00090 public:
00091 virtual void apply( QPainter& p );
00092 QFont font;
00093 int rotation;
00094 virtual ~WinObjFontHandle() {};
00095 };
00096
00097 void WinObjBrushHandle::apply( QPainter& p )
00098 {
00099 p.setBrush( brush );
00100 }
00101
00102 void WinObjPenHandle::apply( QPainter& p )
00103 {
00104 p.setPen( pen );
00105 }
00106
00107 void WinObjPatternBrushHandle::apply( QPainter& p )
00108 {
00109 p.setBrush( brush );
00110 }
00111
00112 void WinObjFontHandle::apply( QPainter& p )
00113 {
00114 p.setFont( font );
00115 }
00116
00117 #define MAX_OBJHANDLE 64
00118
00119
00120
00121
00122 QWinMetaFile::QWinMetaFile()
00123 {
00124 mValid = false;
00125 mFirstCmd = NULL;
00126 mObjHandleTab = NULL;
00127 mDpi = 1000;
00128 }
00129
00130
00131
00132 QWinMetaFile::~QWinMetaFile()
00133 {
00134 if ( mFirstCmd ) delete mFirstCmd;
00135 if ( mObjHandleTab ) delete[] mObjHandleTab;
00136 }
00137
00138
00139
00140 bool QWinMetaFile::load( const QString &filename )
00141 {
00142 QFile file( filename );
00143
00144 if ( !file.exists() )
00145 {
00146 kDebug() << "File " << QFile::encodeName(filename) << " does not exist" << endl;
00147 return false;
00148 }
00149
00150 if ( !file.open( QIODevice::ReadOnly ) )
00151 {
00152 kDebug() << "Cannot open file " << QFile::encodeName(filename) << endl;
00153 return false;
00154 }
00155
00156 QByteArray ba = file.readAll();
00157 file.close();
00158
00159 QBuffer buffer( &ba );
00160 buffer.open( QIODevice::ReadOnly );
00161 return load( buffer );
00162 }
00163
00164
00165 bool QWinMetaFile::load( QBuffer &buffer )
00166 {
00167 QDataStream st;
00168 WmfEnhMetaHeader eheader;
00169 WmfMetaHeader header;
00170 WmfPlaceableHeader pheader;
00171 WORD checksum;
00172 int filePos, idx, i;
00173 WmfCmd *cmd, *last;
00174 DWORD rdSize;
00175 WORD rdFunc;
00176
00177 mTextAlign = 0;
00178 mRotation = 0;
00179 mTextColor = Qt::black;
00180 if ( mFirstCmd ) delete mFirstCmd;
00181 mFirstCmd = NULL;
00182
00183 st.setDevice( &buffer );
00184 st.setByteOrder( QDataStream::LittleEndian );
00185
00186
00187 st >> pheader.key;
00188 mIsPlaceable = ( pheader.key==( DWORD )APMHEADER_KEY );
00189 if ( mIsPlaceable )
00190 {
00191 st >> pheader.hmf;
00192 st >> pheader.bbox.left;
00193 st >> pheader.bbox.top;
00194 st >> pheader.bbox.right;
00195 st >> pheader.bbox.bottom;
00196 st >> pheader.inch;
00197 st >> pheader.reserved;
00198 st >> pheader.checksum;
00199 checksum = calcCheckSum( &pheader );
00200 if ( pheader.checksum!=checksum ) mIsPlaceable = false;
00201
00202 mDpi = pheader.inch;
00203 mBBox.setLeft( pheader.bbox.left );
00204 mBBox.setTop( pheader.bbox.top );
00205 mBBox.setRight( pheader.bbox.right );
00206 mBBox.setBottom( pheader.bbox.bottom );
00207 mHeaderBoundingBox = mBBox;
00208 if ( QWMF_DEBUG )
00209 {
00210 kDebug() << endl << "-------------------------------------------------" << endl;
00211 kDebug() << "WMF Placeable Header ( " << static_cast<int>(sizeof( pheader ) ) << "):" << endl;
00212 kDebug() << " bbox=( " << mBBox.left() << "; " << mBBox.top() << "; " << mBBox.width()
00213 << "; " << mBBox.height() << ")" << endl;
00214 kDebug() << " inch=" << pheader.inch << endl;
00215 kDebug() << " checksum=" << pheader.checksum << "( "
00216 << (pheader.checksum==checksum?"ok":"wrong") << " )" << endl;
00217 }
00218 }
00219 else buffer.reset();
00220
00221
00222 filePos = buffer.pos();
00223 st >> eheader.iType;
00224 st >> eheader.nSize;
00225 st >> eheader.rclBounds.left;
00226 st >> eheader.rclBounds.top;
00227 st >> eheader.rclBounds.right;
00228 st >> eheader.rclBounds.bottom;
00229 st >> eheader.rclFrame.left;
00230 st >> eheader.rclFrame.top;
00231 st >> eheader.rclFrame.right;
00232 st >> eheader.rclFrame.bottom;
00233 st >> eheader.dSignature;
00234 mIsEnhanced = ( eheader.dSignature==ENHMETA_SIGNATURE );
00235 if ( mIsEnhanced )
00236 {
00237 st >> eheader.nVersion;
00238 st >> eheader.nBytes;
00239 st >> eheader.nRecords;
00240 st >> eheader.nHandles;
00241 st >> eheader.sReserved;
00242 st >> eheader.nDescription;
00243 st >> eheader.offDescription;
00244 st >> eheader.nPalEntries;
00245 st >> eheader.szlDevice.width;
00246 st >> eheader.szlDevice.height;
00247 st >> eheader.szlMillimeters.width;
00248 st >> eheader.szlMillimeters.height;
00249
00250 if ( QWMF_DEBUG )
00251 {
00252 kDebug() << endl << "-------------------------------------------------" << endl;
00253 kDebug() << "WMF Extended Header:" << endl;
00254 kDebug() << " iType=" << eheader.iType << endl;
00255 kDebug() << " nSize=" << eheader.nSize << endl;
00256 kDebug() << " rclBounds=( " << eheader.rclBounds.left << "; " << eheader.rclBounds.top << "; "
00257 << eheader.rclBounds.right << "; " << eheader.rclBounds.bottom << ")" << endl;
00258 kDebug() << " rclFrame=( " << eheader.rclFrame.left << "; " << eheader.rclFrame.top << "; "
00259 << eheader.rclFrame.right << "; " << eheader.rclFrame.bottom << ")" << endl;
00260 kDebug() << " nBytes=" << eheader.nBytes << endl;
00261 kDebug() << "\nNOT YET IMPLEMENTED, SORRY." << endl;
00262 }
00263 }
00264 else
00265 {
00266
00267 buffer.seek( filePos );
00268 st >> header.mtType;
00269 st >> header.mtHeaderSize;
00270 st >> header.mtVersion;
00271 st >> header.mtSize;
00272 st >> header.mtNoObjects;
00273 st >> header.mtMaxRecord;
00274 st >> header.mtNoParameters;
00275 if ( QWMF_DEBUG ) {
00276 kDebug() << "WMF Header: " << "mtSize=" << header.mtSize << endl;
00277 }
00278 }
00279
00280
00281 mValid = ((header.mtHeaderSize == 9) && (header.mtNoParameters == 0)) || mIsEnhanced || mIsPlaceable;
00282 if ( mValid )
00283 {
00284
00285 last = NULL;
00286 rdFunc = -1;
00287 while ( !st.atEnd() && (rdFunc != 0) )
00288 {
00289 st >> rdSize;
00290 st >> rdFunc;
00291 idx = findFunc( rdFunc );
00292 rdSize -= 3;
00293
00294 cmd = new WmfCmd;
00295 cmd->next = NULL;
00296 if ( last ) last->next = cmd;
00297 else mFirstCmd = cmd;
00298
00299 cmd->funcIndex = idx;
00300 cmd->numParm = rdSize;
00301 cmd->parm = new WORD[ rdSize ];
00302 last = cmd;
00303
00304 for ( i=0; i<rdSize && !st.atEnd(); i++ )
00305 st >> cmd->parm[ i ];
00306
00307
00308 if ( rdFunc == 0x020B ) {
00309 mBBox.setLeft( cmd->parm[ 1 ] );
00310 mBBox.setTop( cmd->parm[ 0 ] );
00311 }
00312 if ( rdFunc == 0x020C ) {
00313 mBBox.setWidth( cmd->parm[ 1 ] );
00314 mBBox.setHeight( cmd->parm[ 0 ] );
00315 }
00316
00317 if ( i<rdSize )
00318 {
00319 kDebug() << "WMF : file truncated !" << endl;
00320 return false;
00321 }
00322 }
00323
00324 mValid = (rdFunc == 0) && (mBBox.width() != 0) && (mBBox.height() != 0);
00325 if ( !mValid ) {
00326 kDebug() << "WMF : incorrect file format !" << endl;
00327 }
00328 }
00329 else {
00330 kDebug() << "WMF Header : incorrect header !" << endl;
00331 }
00332
00333 buffer.close();
00334 return mValid;
00335 }
00336
00337
00338
00339 bool QWinMetaFile::paint( QPaintDevice* aTarget, bool absolute )
00340 {
00341 int idx, i;
00342 WmfCmd* cmd;
00343
00344 if ( !mValid ) return false;
00345
00346 assert( aTarget!=NULL );
00347 if ( mPainter.isActive() ) return false;
00348
00349 if ( mObjHandleTab ) delete[] mObjHandleTab;
00350 mObjHandleTab = new WinObjHandle* [ MAX_OBJHANDLE ];
00351 for ( i=MAX_OBJHANDLE-1; i>=0; i-- )
00352 mObjHandleTab[ i ] = NULL;
00353
00354 mPainter.resetMatrix();
00355 mWinding = false;
00356 mAbsoluteCoord = absolute;
00357
00358 mPainter.begin( aTarget );
00359 if ( QWMF_DEBUG ) {
00360 kDebug() << "Bounding box : " << mBBox.left()
00361 << " " << mBBox.top() << " " << mBBox.right() << " " << mBBox.bottom() << endl;
00362 }
00363
00364 if ( mAbsoluteCoord ) {
00365 mPainter.setWindow( mBBox.top(), mBBox.left(), mBBox.width(), mBBox.height() );
00366 }
00367 mInternalWorldMatrix.reset();
00368
00369 for ( cmd=mFirstCmd; cmd; cmd=cmd->next )
00370 {
00371 idx = cmd->funcIndex;
00372 ( this->*metaFuncTab[ idx ].method )( cmd->numParm, cmd->parm );
00373
00374 if ( QWMF_DEBUG ) {
00375 QString str = "", param;
00376 if ( metaFuncTab[ idx ].name == NULL ) {
00377 str += "UNKNOWN ";
00378 }
00379 if ( metaFuncTab[ idx ].method == &QWinMetaFile::noop ) {
00380 str += "UNIMPLEMENTED ";
00381 }
00382 str += metaFuncTab[ idx ].name;
00383 str += " : ";
00384
00385 for ( i=0 ; i < cmd->numParm ; i++ ) {
00386 param.setNum( cmd->parm[ i ] );
00387 str += param;
00388 str += ' ';
00389 }
00390 kDebug() << str << endl;
00391 }
00392 }
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 mPainter.end();
00405 return true;
00406 }
00407
00408
00409
00410
00411
00412 void QWinMetaFile::setWindowOrg( long, short* parm )
00413 {
00414 if ( mAbsoluteCoord ) {
00415 QRect r = mPainter.window();
00416 mPainter.setWindow( parm[ 1 ], parm[ 0 ], r.width(), r.height() );
00417 }
00418 else {
00419 double dx = mInternalWorldMatrix.dx();
00420 double dy = mInternalWorldMatrix.dy();
00421
00422 mInternalWorldMatrix.translate( -dx, -dy );
00423 mInternalWorldMatrix.translate( -parm[ 1 ], -parm[ 0 ] );
00424 mPainter.translate( -dx, -dy );
00425 mPainter.translate( -parm[ 1 ], -parm[ 0 ] );
00426 }
00427 }
00428
00429
00430
00431 void QWinMetaFile::setWindowExt( long, short* parm )
00432 {
00433
00434 if ( mAbsoluteCoord ) {
00435 QRect r = mPainter.window();
00436 mPainter.setWindow( r.left(), r.top(), parm[ 1 ], parm[ 0 ] );
00437 }
00438 else {
00439 if ( (parm[ 0 ] != 0) && (parm[ 1 ] != 0) ) {
00440 QRect r = mPainter.window();
00441 double dx = mInternalWorldMatrix.dx();
00442 double dy = mInternalWorldMatrix.dy();
00443 double sx = mInternalWorldMatrix.m11();
00444 double sy = mInternalWorldMatrix.m22();
00445
00446 mInternalWorldMatrix.translate( -dx, -dy );
00447 mInternalWorldMatrix.scale( 1/sx, 1/sy );
00448 mPainter.translate( -dx, -dy );
00449 mPainter.scale( 1/sx, 1/sy );
00450
00451 sx = (double)r.width() / (double)parm[ 1 ];
00452 sy = (double)r.height() / (double)parm[ 0 ];
00453
00454 mInternalWorldMatrix.scale( sx, sy );
00455 mInternalWorldMatrix.translate( dx, dy );
00456 mPainter.scale( sx, sy );
00457 mPainter.translate( dx, dy );
00458 }
00459 }
00460 }
00461
00462
00463
00464
00465
00466 void QWinMetaFile::lineTo( long, short* parm )
00467 {
00468 mLastPos = QPoint( parm[ 1 ], parm[ 0 ] );
00469 }
00470
00471
00472
00473 void QWinMetaFile::moveTo( long, short* parm )
00474 {
00475 mPainter.drawLine( mLastPos, QPoint( parm[1], parm[0] ) );
00476 }
00477
00478
00479
00480 void QWinMetaFile::ellipse( long, short* parm )
00481 {
00482 mPainter.drawEllipse( parm[ 3 ], parm[ 2 ], parm[ 1 ]-parm[ 3 ], parm[ 0 ]-parm[ 2 ] );
00483 }
00484
00485
00486
00487 void QWinMetaFile::polygon( long, short* parm )
00488 {
00489 QPolygon* pa;
00490
00491 pa = pointArray( parm[ 0 ], &parm[ 1 ] );
00492 if( mWinding )
00493 mPainter.drawPolygon( *pa, Qt::WindingFill );
00494 else
00495 mPainter.drawPolygon( *pa, Qt::OddEvenFill );
00496
00497 delete pa;
00498 }
00499
00500
00501
00502 void QWinMetaFile::polyPolygon( long, short* parm )
00503 {
00504 QRegion region;
00505 int i, j, startPolygon;
00506
00507 mPainter.save();
00508
00509
00510 QRect win = bbox();
00511 startPolygon = 1+parm[ 0 ];
00512 for ( i=0 ; i < parm[ 0 ] ; i++ ) {
00513 QPolygon pa1( parm[ 1+i ] );
00514 for ( j=0 ; j < parm[ 1+i ] ; j++) {
00515 pa1.setPoint ( j, parm[ startPolygon ], parm[ startPolygon+1 ] );
00516 startPolygon += 2;
00517 }
00518 QRegion r( pa1 );
00519 region = region.eor( r );
00520 }
00521 mPainter.setClipRegion( region );
00522
00523
00524 mPainter.fillRect( win.left(), win.top(), win.width(), win.height(), mPainter.brush() );
00525
00526
00527 if ( mPainter.pen().style() != Qt::NoPen ) {
00528 mPainter.setClipping( false );
00529 mPainter.setBrush( Qt::NoBrush );
00530
00531 QPolygon* pa;
00532 int idxPolygon = 1 + parm[ 0 ];
00533 for ( i=0 ; i < parm[ 0 ] ; i++ ) {
00534 pa = pointArray( parm[ 1+i ], &parm[ idxPolygon ] );
00535 mPainter.drawPolygon( *pa );
00536 idxPolygon += parm[ 1+i ] * 2;
00537 }
00538 }
00539
00540 mPainter.restore();
00541 }
00542
00543
00544
00545 void QWinMetaFile::polyline( long, short* parm )
00546 {
00547 QPolygon* pa;
00548
00549 pa = pointArray( parm[ 0 ], &parm[ 1 ] );
00550 mPainter.drawPolyline( *pa );
00551 }
00552
00553
00554
00555 void QWinMetaFile::rectangle( long, short* parm )
00556 {
00557 mPainter.drawRect( parm[ 3 ], parm[ 2 ], parm[ 1 ]-parm[ 3 ], parm[ 0 ]-parm[ 2 ] );
00558 }
00559
00560
00561
00562 void QWinMetaFile::roundRect( long, short* parm )
00563 {
00564 int xRnd = 0, yRnd = 0;
00565
00566
00567 if ( (parm[ 3 ] - parm[ 5 ]) != 0 )
00568 xRnd = (parm[ 1 ] * 100) / (parm[ 3 ] - parm[ 5 ]) ;
00569 if ( (parm[ 2 ] - parm[ 4 ]) != 0 )
00570 yRnd = (parm[ 0 ] * 100) / (parm[ 2 ] - parm[ 4 ]) ;
00571
00572 mPainter.drawRoundRect( parm[ 5 ], parm[ 4 ], parm[ 3 ]-parm[ 5 ], parm[ 2 ]-parm[ 4 ], xRnd, yRnd );
00573 }
00574
00575
00576
00577 void QWinMetaFile::arc( long, short* parm )
00578 {
00579 int xCenter, yCenter, angleStart, aLength;
00580
00581 xCenter = parm[ 7 ] + ((parm[ 5 ] - parm[ 7 ]) / 2);
00582 yCenter = parm[ 6 ] + ((parm[ 4 ] - parm[ 6 ]) / 2);
00583
00584 xyToAngle ( parm[ 3 ] - xCenter, yCenter - parm[ 2 ], parm[ 1 ] - xCenter, yCenter - parm[ 0 ], angleStart, aLength );
00585
00586 mPainter.drawArc( parm[ 7 ], parm[ 6 ], parm[ 5 ]-parm[ 7 ], parm[ 4 ]-parm[ 6 ], angleStart, aLength);
00587 }
00588
00589
00590
00591 void QWinMetaFile::chord( long, short* parm )
00592 {
00593 int xCenter, yCenter, angleStart, aLength;
00594
00595 xCenter = parm[ 7 ] + ((parm[ 5 ] - parm[ 7 ]) / 2);
00596 yCenter = parm[ 6 ] + ((parm[ 4 ] - parm[ 6 ]) / 2);
00597
00598 xyToAngle ( parm[ 3 ] - xCenter, yCenter - parm[ 2 ], parm[ 1 ] - xCenter, yCenter - parm[ 0 ], angleStart, aLength );
00599
00600 mPainter.drawChord( parm[ 7 ], parm[ 6 ], parm[ 5 ]-parm[ 7 ], parm[ 4 ]-parm[ 6 ], angleStart, aLength);
00601 }
00602
00603
00604
00605 void QWinMetaFile::pie( long, short* parm )
00606 {
00607 int xCenter, yCenter, angleStart, aLength;
00608
00609 xCenter = parm[ 7 ] + ((parm[ 5 ] - parm[ 7 ]) / 2);
00610 yCenter = parm[ 6 ] + ((parm[ 4 ] - parm[ 6 ]) / 2);
00611
00612 xyToAngle ( parm[ 3 ] - xCenter, yCenter - parm[ 2 ], parm[ 1 ] - xCenter, yCenter - parm[ 0 ], angleStart, aLength );
00613
00614 mPainter.drawPie( parm[ 7 ], parm[ 6 ], parm[ 5 ]-parm[ 7 ], parm[ 4 ]-parm[ 6 ], angleStart, aLength);
00615 }
00616
00617
00618
00619 void QWinMetaFile::setPolyFillMode( long, short* parm )
00620 {
00621 mWinding = parm[ 0 ];
00622 }
00623
00624
00625
00626 void QWinMetaFile::setBkColor( long, short* parm )
00627 {
00628 mPainter.setBackground( QBrush( color( parm ) ) );
00629 }
00630
00631
00632
00633 void QWinMetaFile::setBkMode( long, short* parm )
00634 {
00635 if ( parm[ 0 ]==1 ) mPainter.setBackgroundMode( Qt::TransparentMode );
00636 else mPainter.setBackgroundMode( Qt::OpaqueMode );
00637 }
00638
00639
00640
00641 void QWinMetaFile::setPixel( long, short* parm )
00642 {
00643 QPen pen = mPainter.pen();
00644 mPainter.setPen( color( parm ) );
00645 mPainter.drawPoint( parm[ 3 ], parm[ 2 ] );
00646 mPainter.setPen( pen );
00647 }
00648
00649
00650
00651 void QWinMetaFile::setRop( long, short* parm )
00652 {
00653 mPainter.setCompositionMode( winToQtComposition( parm[ 0 ] ) );
00654 }
00655
00656
00657
00658 void QWinMetaFile::saveDC( long, short* )
00659 {
00660 mPainter.save();
00661 }
00662
00663
00664
00665 void QWinMetaFile::restoreDC( long, short *parm )
00666 {
00667 for ( int i=0; i > parm[ 0 ] ; i-- )
00668 mPainter.restore();
00669 }
00670
00671
00672
00673 void QWinMetaFile::intersectClipRect( long, short* parm )
00674 {
00675
00676
00677
00678
00679
00680 QRegion region( bbox() );
00681
00682 QRegion newRegion( parm[ 3 ], parm[ 2 ], parm[ 1 ] - parm[ 3 ], parm[ 0 ] - parm[ 2 ] );
00683 region = region.intersect( newRegion );
00684
00685 mPainter.setClipRegion( region );
00686 }
00687
00688
00689
00690 void QWinMetaFile::excludeClipRect( long, short* parm )
00691 {
00692
00693
00694
00695
00696
00697 QRegion region( bbox() );
00698
00699 QRegion newRegion( parm[ 3 ], parm[ 2 ], parm[ 1 ] - parm[ 3 ], parm[ 0 ] - parm[ 2 ] );
00700 region = region.subtract( newRegion );
00701
00702 mPainter.setClipRegion( region );
00703 }
00704
00705
00706
00707
00708
00709 void QWinMetaFile::setTextColor( long, short* parm )
00710 {
00711 mTextColor = color( parm );
00712 }
00713
00714
00715
00716 void QWinMetaFile::setTextAlign( long, short* parm )
00717 {
00718 mTextAlign = parm[ 0 ];
00719 }
00720
00721
00722
00723 void QWinMetaFile::textOut( long num, short* parm )
00724 {
00725
00726 short *copyParm = new short[ num + 1 ];
00727
00728
00729 int idxOffset = (parm[ 0 ] / 2) + 1 + (parm[ 0 ] & 1);
00730 copyParm[ 0 ] = parm[ idxOffset ];
00731 copyParm[ 1 ] = parm[ idxOffset + 1 ];
00732 copyParm[ 2 ] = parm[ 0 ];
00733 copyParm[ 3 ] = 0;
00734 memcpy( ©Parm[ 4 ], &parm[ 1 ], parm[ 0 ] );
00735
00736 extTextOut( num + 1, copyParm );
00737 delete [] copyParm;
00738 }
00739
00740
00741
00742 void QWinMetaFile::extTextOut( long num, short* parm )
00743 {
00744 char* ptStr;
00745 int x, y, width, height;
00746 int idxOffset;
00747
00748 if ( parm[ 3 ] != 0 )
00749 ptStr = (char*)&parm[ 8 ];
00750 else
00751 ptStr = (char*)&parm[ 4 ];
00752
00753 Q3CString text( ptStr, parm[ 2 ] + 1 );
00754
00755 QFontMetrics fm( mPainter.font() );
00756 width = fm.width( text ) + fm.descent();
00757 height = fm.height();
00758
00759 mPainter.save();
00760
00761 if ( mTextAlign & 0x01 ) {
00762 x = mLastPos.x();
00763 y = mLastPos.y();
00764 }
00765 else {
00766 x = parm[ 1 ];
00767 y = parm[ 0 ];
00768 }
00769
00770 if ( mRotation ) {
00771 mPainter.translate( parm[ 1 ], parm[ 0 ]);
00772 mPainter.rotate ( mRotation );
00773 mPainter.translate( -parm[ 1 ], -parm[ 0 ] );
00774 }
00775
00776
00777 if ( mTextAlign & 0x06 )
00778 x -= ( width / 2 );
00779 if ( mTextAlign & 0x08 )
00780 y -= (height - fm.descent());
00781
00782 mPainter.setPen( mTextColor );
00783 idxOffset = (parm[ 2 ] / 2) + 4 + (parm[ 2 ] & 1);
00784 if ( ( parm[ 2 ] > 1 ) && ( num >= (idxOffset + parm[ 2 ]) ) && ( parm[ 3 ] == 0 ) ) {
00785
00786 int left = x;
00787 mPainter.drawText( left, y, width, height, Qt::AlignLeft | Qt::AlignTop, text.mid(0, 1) );
00788 for ( int i = 1; i < parm[ 2 ] ; i++ ) {
00789 left += parm[ idxOffset + i - 1 ];
00790 mPainter.drawText( left, y, width, height, Qt::AlignLeft | Qt::AlignTop, text.mid(i, 1) );
00791 }
00792 }
00793 else {
00794 mPainter.drawText( x, y, width, height, Qt::AlignLeft | Qt::AlignTop, text );
00795 }
00796
00797 mPainter.restore();
00798
00799 }
00800
00801
00802
00803
00804
00805
00806 void QWinMetaFile::dibBitBlt( long num, short* parm )
00807 {
00808 if ( num > 9 ) {
00809 QImage bmpSrc;
00810
00811 if ( dibToBmp( bmpSrc, (char*)&parm[ 8 ], (num - 8) * 2 ) ) {
00812 long raster = toDWord( parm );
00813
00814 mPainter.setCompositionMode( winToQtComposition( raster ) );
00815
00816
00817 mPainter.save();
00818 if ( parm[ 5 ] < 0 ) {
00819 QMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F );
00820 mPainter.setMatrix( m, true );
00821 }
00822 if ( parm[ 4 ] < 0 ) {
00823 QMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F );
00824 mPainter.setMatrix( m, true );
00825 }
00826 mPainter.drawImage( parm[ 7 ], parm[ 6 ], bmpSrc, parm[ 3 ], parm[ 2 ], parm[ 5 ], parm[ 4 ] );
00827 mPainter.restore();
00828 }
00829 }
00830 else {
00831 kDebug() << "QWinMetaFile::dibBitBlt without image: not implemented " << endl;
00832 }
00833 }
00834
00835
00836
00837 void QWinMetaFile::dibStretchBlt( long num, short* parm )
00838 {
00839 QImage bmpSrc;
00840
00841 if ( dibToBmp( bmpSrc, (char*)&parm[ 10 ], (num - 10) * 2 ) ) {
00842 long raster = toDWord( parm );
00843
00844 mPainter.setCompositionMode( winToQtComposition( raster ) );
00845
00846
00847 mPainter.save();
00848 if ( parm[ 7 ] < 0 ) {
00849 QMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F );
00850 mPainter.setMatrix( m, true );
00851 }
00852 if ( parm[ 6 ] < 0 ) {
00853 QMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F );
00854 mPainter.setMatrix( m, true );
00855 }
00856 bmpSrc = bmpSrc.copy( parm[ 5 ], parm[ 4 ], parm[ 3 ], parm[ 2 ] );
00857
00858
00859 mPainter.drawImage( parm[ 9 ], parm[ 8 ], bmpSrc );
00860 mPainter.restore();
00861 }
00862 }
00863
00864
00865
00866 void QWinMetaFile::stretchDib( long num, short* parm )
00867 {
00868 QImage bmpSrc;
00869
00870 if ( dibToBmp( bmpSrc, (char*)&parm[ 11 ], (num - 11) * 2 ) ) {
00871 long raster = toDWord( parm );
00872
00873 mPainter.setCompositionMode( winToQtComposition( raster ) );
00874
00875
00876 mPainter.save();
00877 if ( parm[ 8 ] < 0 ) {
00878 QMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F );
00879 mPainter.setMatrix( m, true );
00880 }
00881 if ( parm[ 7 ] < 0 ) {
00882 QMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F );
00883 mPainter.setMatrix( m, true );
00884 }
00885 bmpSrc = bmpSrc.copy( parm[ 6 ], parm[ 5 ], parm[ 4 ], parm[ 3 ] );
00886
00887
00888 mPainter.drawImage( parm[ 10 ], parm[ 9 ], bmpSrc );
00889 mPainter.restore();
00890 }
00891 }
00892
00893
00894
00895 void QWinMetaFile::dibCreatePatternBrush( long num, short* parm )
00896 {
00897 WinObjPatternBrushHandle* handle = new WinObjPatternBrushHandle;
00898 addHandle( handle );
00899 QImage bmpSrc;
00900
00901 if ( dibToBmp( bmpSrc, (char*)&parm[ 2 ], (num - 2) * 2 ) ) {
00902 handle->image = QPixmap::fromImage( bmpSrc );
00903 handle->brush.setTexture( handle->image );
00904 }
00905 }
00906
00907
00908
00909
00910
00911 void QWinMetaFile::selectObject( long, short* parm )
00912 {
00913 int idx = parm[ 0 ];
00914 if ( idx>=0 && idx < MAX_OBJHANDLE && mObjHandleTab[ idx ] )
00915 mObjHandleTab[ idx ]->apply( mPainter );
00916 }
00917
00918
00919
00920 void QWinMetaFile::deleteObject( long, short* parm )
00921 {
00922 deleteHandle( parm[ 0 ] );
00923 }
00924
00925
00926
00927 void QWinMetaFile::createEmptyObject( long, short* )
00928 {
00929
00930 WinObjPenHandle* handle = new WinObjPenHandle;
00931 addHandle( handle );
00932 kDebug() << "QWinMetaFile: unimplemented createObject " << endl;
00933 }
00934
00935
00936
00937 void QWinMetaFile::createBrushIndirect( long, short* parm )
00938 {
00939 static Qt::BrushStyle hatchedStyleTab[] =
00940 {
00941 Qt::HorPattern,
00942 Qt::FDiagPattern,
00943 Qt::BDiagPattern,
00944 Qt::CrossPattern,
00945 Qt::DiagCrossPattern
00946 };
00947 static Qt::BrushStyle styleTab[] =
00948 { Qt::SolidPattern,
00949 Qt::NoBrush,
00950 Qt::FDiagPattern,
00951 Qt::Dense4Pattern,
00952 Qt::HorPattern,
00953 Qt::VerPattern,
00954 Qt::Dense6Pattern,
00955 Qt::Dense2Pattern,
00956 Qt::Dense3Pattern
00957 };
00958 Qt::BrushStyle style;
00959 short arg;
00960 WinObjBrushHandle* handle = new WinObjBrushHandle;
00961 addHandle( handle );
00962
00963 arg = parm[ 0 ];
00964 if ( arg==2 )
00965 {
00966 arg = parm[ 3 ];
00967 if ( arg>=0 && arg<5 ) style = hatchedStyleTab[ arg ];
00968 else
00969 {
00970 kDebug() << "QWinMetaFile::createBrushIndirect: invalid hatched brush " << arg << endl;
00971 style = Qt::SolidPattern;
00972 }
00973 }
00974 else if ( arg>=0 && arg<9 )
00975 style = styleTab[ arg ];
00976 else
00977 {
00978 kDebug() << "QWinMetaFile::createBrushIndirect: invalid brush " << arg << endl;
00979 style = Qt::SolidPattern;
00980 }
00981 handle->brush.setStyle( style );
00982 handle->brush.setColor( color( parm+1 ) );
00983 }
00984
00985
00986
00987 void QWinMetaFile::createPenIndirect( long, short* parm )
00988 {
00989 static Qt::PenStyle styleTab[] =
00990 { Qt::SolidLine, Qt::DashLine, Qt::DotLine, Qt::DashDotLine, Qt::DashDotDotLine,
00991 Qt::NoPen, Qt::SolidLine };
00992 Qt::PenStyle style;
00993 WinObjPenHandle* handle = new WinObjPenHandle;
00994 addHandle( handle );
00995
00996 if ( parm[ 0 ]>=0 && parm[ 0 ]<6 ) style=styleTab[ parm[ 0 ] ];
00997 else
00998 {
00999 kDebug() << "QWinMetaFile::createPenIndirect: invalid pen " << parm[ 0 ] << endl;
01000 style = Qt::SolidLine;
01001 }
01002
01003 handle->pen.setStyle( style );
01004 handle->pen.setColor( color( parm+3 ) );
01005 handle->pen.setCapStyle( Qt::RoundCap );
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020 }
01021
01022
01023
01024 void QWinMetaFile::createFontIndirect( long , short* parm)
01025 {
01026 WinObjFontHandle* handle = new WinObjFontHandle;
01027 addHandle( handle );
01028
01029 QString family( (const char*)&parm[ 9 ] );
01030
01031 mRotation = -parm[ 2 ] / 10;
01032
01033 handle->font.setFamily( family );
01034 handle->font.setFixedPitch( ((parm[ 8 ] & 0x01) == 0) );
01035
01036 handle->font.setPointSize( qAbs(parm[ 0 ]) - 2 );
01037 handle->font.setWeight( (parm[ 4 ] >> 3) );
01038 handle->font.setItalic( (parm[ 5 ] & 0x01) );
01039 handle->font.setUnderline( (parm[ 5 ] & 0x100) );
01040 }
01041
01042
01043
01044
01045
01046 void QWinMetaFile::noop( long, short* )
01047 {
01048 }
01049
01050
01051 void QWinMetaFile::end( long, short* )
01052 {
01053
01054
01055 }
01056
01057
01058
01059 unsigned short QWinMetaFile::calcCheckSum( WmfPlaceableHeader* apmfh )
01060 {
01061 WORD* lpWord;
01062 WORD wResult, i;
01063
01064
01065 wResult = *( lpWord = ( WORD* )( apmfh ) );
01066
01067 for( i=1; i<=9; i++ )
01068 {
01069 wResult ^= lpWord[ i ];
01070 }
01071 return wResult;
01072 }
01073
01074
01075
01076 int QWinMetaFile::findFunc( unsigned short aFunc ) const
01077 {
01078 int i;
01079
01080 for ( i=0; metaFuncTab[ i ].name; i++ )
01081 if ( metaFuncTab[ i ].func == aFunc ) return i;
01082
01083
01084 return i;
01085 }
01086
01087
01088 QPolygon* QWinMetaFile::pointArray( short num, short* parm )
01089 {
01090 int i;
01091
01092 mPoints.resize( num );
01093
01094 for ( i=0; i<num; i++, parm+=2 )
01095 mPoints.setPoint( i, parm[ 0 ], parm[ 1 ] );
01096
01097 return &mPoints;
01098 }
01099
01100
01101 unsigned int QWinMetaFile::toDWord( short* parm )
01102 {
01103 unsigned int l;
01104
01105 #if !defined( WORDS_BIGENDIAN )
01106 l = *( unsigned int* )( parm );
01107 #else
01108 char *bytes;
01109 char swap[ 4 ];
01110 bytes = ( char* )parm;
01111 swap[ 0 ] = bytes[ 2 ];
01112 swap[ 1 ] = bytes[ 3 ];
01113 swap[ 2 ] = bytes[ 0 ];
01114 swap[ 3 ] = bytes[ 1 ];
01115 l = *( unsigned int* )( swap );
01116 #endif
01117
01118 return l;
01119 }
01120
01121
01122
01123 QColor QWinMetaFile::color( short* parm )
01124 {
01125 unsigned int colorRef;
01126 int red, green, blue;
01127
01128 colorRef = toDWord( parm ) & 0xffffff;
01129 red = colorRef & 255;
01130 green = ( colorRef>>8 ) & 255;
01131 blue = ( colorRef>>16 ) & 255;
01132
01133 return QColor( red, green, blue );
01134 }
01135
01136
01137
01138 void QWinMetaFile::xyToAngle( int xStart, int yStart, int xEnd, int yEnd, int& angleStart, int& angleLength )
01139 {
01140 float aStart, aLength;
01141
01142 aStart = atan2( yStart, xStart );
01143 aLength = atan2( yEnd, xEnd ) - aStart;
01144
01145 angleStart = (int)(aStart * 2880 / 3.14166);
01146 angleLength = (int)(aLength * 2880 / 3.14166);
01147 if ( angleLength < 0 ) angleLength = 5760 + angleLength;
01148 }
01149
01150
01151
01152 void QWinMetaFile::addHandle( WinObjHandle* handle )
01153 {
01154 int idx;
01155
01156 for ( idx=0; idx < MAX_OBJHANDLE ; idx++ )
01157 if ( mObjHandleTab[ idx ] == NULL ) break;
01158
01159 if ( idx < MAX_OBJHANDLE )
01160 mObjHandleTab[ idx ] = handle;
01161 else
01162 kDebug() << "QWinMetaFile error: handle table full !" << endl;
01163 }
01164
01165
01166 void QWinMetaFile::deleteHandle( int idx )
01167 {
01168 if ( idx >= 0 && idx < MAX_OBJHANDLE && mObjHandleTab[ idx ] )
01169 {
01170 delete mObjHandleTab[ idx ];
01171 mObjHandleTab[ idx ] = NULL;
01172 }
01173 }
01174
01175
01176 QPainter::CompositionMode QWinMetaFile::winToQtComposition( short parm ) const
01177 {
01178 static const QPainter::CompositionMode opTab[] =
01179 {
01180
01181 QPainter::CompositionMode_Source,
01182 QPainter::CompositionMode_Clear,
01183 QPainter::CompositionMode_SourceOut,
01184 QPainter::CompositionMode_SourceOut,
01185 QPainter::CompositionMode_DestinationOut,
01186 QPainter::CompositionMode_DestinationOut,
01187 QPainter::CompositionMode_DestinationOut,
01188 QPainter::CompositionMode_Xor,
01189 QPainter::CompositionMode_Source,
01190 QPainter::CompositionMode_SourceIn,
01191 QPainter::CompositionMode_SourceIn,
01192 QPainter::CompositionMode_Destination,
01193 QPainter::CompositionMode_Destination,
01194 QPainter::CompositionMode_Source,
01195 QPainter::CompositionMode_Source,
01196 QPainter::CompositionMode_SourceOver,
01197 QPainter::CompositionMode_Source
01198 };
01199
01200 if ( parm > 0 && parm <= 16 )
01201 return opTab[ parm ];
01202 else
01203 return QPainter::CompositionMode_Source;
01204 }
01205
01206
01207 QPainter::CompositionMode QWinMetaFile::winToQtComposition( long parm ) const
01208 {
01209
01210
01211
01212
01213
01214 static const struct OpTab
01215 {
01216 long winRasterOp;
01217 QPainter::CompositionMode qtRasterOp;
01218 } opTab[] =
01219 {
01220
01221 { 0x00CC0020, QPainter::CompositionMode_Source },
01222 { 0x00EE0086, QPainter::CompositionMode_SourceOver },
01223 { 0x008800C6, QPainter::CompositionMode_SourceIn },
01224 { 0x00660046, QPainter::CompositionMode_Xor },
01225 { 0x00440328, QPainter::CompositionMode_DestinationOut },
01226 { 0x00330008, QPainter::CompositionMode_DestinationOut },
01227 { 0x001100A6, QPainter::CompositionMode_SourceOut },
01228 { 0x00C000CA, QPainter::CompositionMode_Source },
01229 { 0x00BB0226, QPainter::CompositionMode_Destination },
01230 { 0x00F00021, QPainter::CompositionMode_Source },
01231 { 0x00FB0A09, QPainter::CompositionMode_Source },
01232 { 0x005A0049, QPainter::CompositionMode_Source },
01233 { 0x00550009, QPainter::CompositionMode_DestinationOut },
01234 { 0x00000042, QPainter::CompositionMode_Clear },
01235 { 0x00FF0062, QPainter::CompositionMode_Source }
01236 };
01237
01238 int i;
01239 for ( i=0 ; i < 15 ; i++ )
01240 if ( opTab[ i ].winRasterOp == parm )
01241 break;
01242
01243 if ( i < 15 )
01244 return opTab[ i ].qtRasterOp;
01245 else
01246 return QPainter::CompositionMode_Source;
01247 }
01248
01249
01250 bool QWinMetaFile::dibToBmp( QImage& bmp, const char* dib, long size )
01251 {
01252 typedef struct _BMPFILEHEADER {
01253 WORD bmType;
01254 DWORD bmSize;
01255 WORD bmReserved1;
01256 WORD bmReserved2;
01257 DWORD bmOffBits;
01258 } BMPFILEHEADER;
01259
01260 int sizeBmp = size + 14;
01261 QByteArray pattern;
01262 pattern.fill( 0, sizeBmp );
01263 pattern.insert( 14, QByteArray::fromRawData(dib, size) );
01264
01265
01266 BMPFILEHEADER* bmpHeader;
01267 bmpHeader = (BMPFILEHEADER*)((const char*)pattern);
01268 bmpHeader->bmType = 0x4D42;
01269 bmpHeader->bmSize = sizeBmp;
01270
01271 if ( !bmp.loadFromData( (const uchar*)bmpHeader, pattern.size(), "BMP" ) ) {
01272 kDebug() << "QWinMetaFile::dibToBmp: invalid bitmap " << endl;
01273 return false;
01274 }
01275 else {
01276
01277
01278
01279 return true;
01280 }
01281 }
01282