diff options
Diffstat (limited to 'lib/kwmf/qwmf.cpp')
-rw-r--r-- | lib/kwmf/qwmf.cpp | 1260 |
1 files changed, 1260 insertions, 0 deletions
diff --git a/lib/kwmf/qwmf.cpp b/lib/kwmf/qwmf.cpp new file mode 100644 index 00000000..8b6572ae --- /dev/null +++ b/lib/kwmf/qwmf.cpp @@ -0,0 +1,1260 @@ +/* Windows Meta File Loader/Painter Class Implementation + * + * Copyright ( C ) 1998 Stefan Taferner + * Modified 2002 thierry lorthiois + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or ( at your + * option ) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. You should have received a copy + * of the GNU General Public License along with this program; if not, write + * to the Free Software Foundation, Inc, 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include <math.h> +#include <assert.h> +#include <tqfileinfo.h> +#include <tqpixmap.h> +#include <tqpainter.h> +#include <tqdatastream.h> +#include <tqapplication.h> +#include <tqbuffer.h> +#include <kdebug.h> + +bool qwmfDebug = false; + +#include "qwmf.h" +#include "wmfstruct.h" +#include "metafuncs.h" + +#define TQWMF_DEBUG 0 + + +class WmfCmd +{ +public: + ~WmfCmd() { if ( next ) delete next; } + WmfCmd* next; + unsigned short funcIndex; + long numParm; + short* parm; +}; + + +class WinObjHandle +{ +public: + virtual void apply( TQPainter& p ) = 0; +}; + +class WinObjBrushHandle: public WinObjHandle +{ +public: + virtual void apply( TQPainter& p ); + TQBrush brush; + virtual ~WinObjBrushHandle() {}; +}; + +class WinObjPenHandle: public WinObjHandle +{ +public: + virtual void apply( TQPainter& p ); + TQPen pen; + virtual ~WinObjPenHandle() {}; +}; + +class WinObjPatternBrushHandle: public WinObjHandle +{ +public: + virtual void apply( TQPainter& p ); + TQBrush brush; + TQPixmap image; + virtual ~WinObjPatternBrushHandle() {}; +}; + +class WinObjFontHandle: public WinObjHandle +{ +public: + virtual void apply( TQPainter& p ); + TQFont font; + int rotation; + virtual ~WinObjFontHandle() {}; +}; + +void WinObjBrushHandle::apply( TQPainter& p ) +{ + p.setBrush( brush ); +} + +void WinObjPenHandle::apply( TQPainter& p ) +{ + p.setPen( pen ); +} + +void WinObjPatternBrushHandle::apply( TQPainter& p ) +{ + p.setBrush( brush ); +} + +void WinObjFontHandle::apply( TQPainter& p ) +{ + p.setFont( font ); +} + +#define MAX_OBJHANDLE 64 + + + +//----------------------------------------------------------------------------- +QWinMetaFile::QWinMetaFile() +{ + mValid = false; + mFirstCmd = NULL; + mObjHandleTab = NULL; + mDpi = 1000; +} + + +//----------------------------------------------------------------------------- +QWinMetaFile::~QWinMetaFile() +{ + if ( mFirstCmd ) delete mFirstCmd; + if ( mObjHandleTab ) delete[] mObjHandleTab; +} + + +//----------------------------------------------------------------------------- +bool QWinMetaFile::load( const TQString &filename ) +{ + TQFile file( filename ); + + if ( !file.exists() ) + { + kdDebug() << "File " << TQString(TQFile::encodeName(filename)) << " does not exist" << endl; + return false; + } + + if ( !file.open( IO_ReadOnly ) ) + { + kdDebug() << "Cannot open file " << TQString(TQFile::encodeName(filename)) << endl; + return false; + } + + TQByteArray ba = file.readAll(); + file.close(); + + TQBuffer buffer( ba ); + buffer.open( IO_ReadOnly ); + return load( buffer ); +} + +//----------------------------------------------------------------------------- +bool QWinMetaFile::load( TQBuffer &buffer ) +{ + TQDataStream st; + WmfEnhMetaHeader eheader; + WmfMetaHeader header; + WmfPlaceableHeader pheader; + WORD checksum; + int filePos, idx, i; + WmfCmd *cmd, *last; + DWORD rdSize; + WORD rdFunc; + + mTextAlign = 0; + mRotation = 0; + mTextColor = TQt::black; + if ( mFirstCmd ) delete mFirstCmd; + mFirstCmd = NULL; + + st.setDevice( &buffer ); + st.setByteOrder( TQDataStream::LittleEndian ); // Great, I love TQt ! + + //----- Read placeable metafile header + st >> pheader.key; + mIsPlaceable = ( pheader.key==( DWORD )APMHEADER_KEY ); + if ( mIsPlaceable ) + { + st >> pheader.hmf; + st >> pheader.bbox.left; + st >> pheader.bbox.top; + st >> pheader.bbox.right; + st >> pheader.bbox.bottom; + st >> pheader.inch; + st >> pheader.reserved; + st >> pheader.checksum; + checksum = calcCheckSum( &pheader ); + if ( pheader.checksum!=checksum ) mIsPlaceable = false; + + mDpi = pheader.inch; + mBBox.setLeft( pheader.bbox.left ); + mBBox.setTop( pheader.bbox.top ); + mBBox.setRight( pheader.bbox.right ); + mBBox.setBottom( pheader.bbox.bottom ); + mHeaderBoundingBox = mBBox; + if ( TQWMF_DEBUG ) + { + kdDebug() << endl << "-------------------------------------------------" << endl; + kdDebug() << "WMF Placeable Header ( " << static_cast<int>(sizeof( pheader ) ) << "):" << endl; + kdDebug() << " bbox=( " << mBBox.left() << "; " << mBBox.top() << "; " << mBBox.width() + << "; " << mBBox.height() << ")" << endl; + kdDebug() << " inch=" << pheader.inch << endl; + kdDebug() << " checksum=" << pheader.checksum << "( " + << (pheader.checksum==checksum?"ok":"wrong") << " )" << endl; + } + } + else buffer.at( 0 ); + + //----- Read as enhanced metafile header + filePos = buffer.at(); + st >> eheader.iType; + st >> eheader.nSize; + st >> eheader.rclBounds.left; + st >> eheader.rclBounds.top; + st >> eheader.rclBounds.right; + st >> eheader.rclBounds.bottom; + st >> eheader.rclFrame.left; + st >> eheader.rclFrame.top; + st >> eheader.rclFrame.right; + st >> eheader.rclFrame.bottom; + st >> eheader.dSignature; + mIsEnhanced = ( eheader.dSignature==ENHMETA_SIGNATURE ); + if ( mIsEnhanced ) // is it really enhanced ? + { + st >> eheader.nVersion; + st >> eheader.nBytes; + st >> eheader.nRecords; + st >> eheader.nHandles; + st >> eheader.sReserved; + st >> eheader.nDescription; + st >> eheader.offDescription; + st >> eheader.nPalEntries; + st >> eheader.szlDevice.width; + st >> eheader.szlDevice.height; + st >> eheader.szlMillimeters.width; + st >> eheader.szlMillimeters.height; + + if ( TQWMF_DEBUG ) + { + kdDebug() << endl << "-------------------------------------------------" << endl; + kdDebug() << "WMF Extended Header:" << endl; + kdDebug() << " iType=" << eheader.iType << endl; + kdDebug() << " nSize=" << eheader.nSize << endl; + kdDebug() << " rclBounds=( " << eheader.rclBounds.left << "; " << eheader.rclBounds.top << "; " + << eheader.rclBounds.right << "; " << eheader.rclBounds.bottom << ")" << endl; + kdDebug() << " rclFrame=( " << eheader.rclFrame.left << "; " << eheader.rclFrame.top << "; " + << eheader.rclFrame.right << "; " << eheader.rclFrame.bottom << ")" << endl; + kdDebug() << " nBytes=" << eheader.nBytes << endl; + kdDebug() << "\nNOT YET IMPLEMENTED, SORRY." << endl; + } + } + else // no, not enhanced + { + //----- Read as standard metafile header + buffer.at( filePos ); + st >> header.mtType; + st >> header.mtHeaderSize; + st >> header.mtVersion; + st >> header.mtSize; + st >> header.mtNoObjects; + st >> header.mtMaxRecord; + st >> header.mtNoParameters; + if ( TQWMF_DEBUG ) { + kdDebug() << "WMF Header: " << "mtSize=" << header.mtSize << endl; + } + } + + //----- Test header validity + mValid = ((header.mtHeaderSize == 9) && (header.mtNoParameters == 0)) || mIsEnhanced || mIsPlaceable; + if ( mValid ) + { + //----- Read Metafile Records + last = NULL; + rdFunc = -1; + while ( !st.eof() && (rdFunc != 0) ) + { + st >> rdSize; + st >> rdFunc; + idx = findFunc( rdFunc ); + rdSize -= 3; + + cmd = new WmfCmd; + cmd->next = NULL; + if ( last ) last->next = cmd; + else mFirstCmd = cmd; + + cmd->funcIndex = idx; + cmd->numParm = rdSize; + cmd->parm = new WORD[ rdSize ]; + last = cmd; + + for ( i=0; i<rdSize && !st.eof(); i++ ) + st >> cmd->parm[ i ]; + + + if ( rdFunc == 0x020B ) { // SETWINDOWORG: dimensions + mBBox.setLeft( cmd->parm[ 1 ] ); + mBBox.setTop( cmd->parm[ 0 ] ); + } + if ( rdFunc == 0x020C ) { // SETWINDOWEXT: dimensions + mBBox.setWidth( cmd->parm[ 1 ] ); + mBBox.setHeight( cmd->parm[ 0 ] ); + } + + if ( i<rdSize ) + { + kdDebug() << "WMF : file truncated !" << endl; + return false; + } + } + //----- Test records validities + mValid = (rdFunc == 0) && (mBBox.width() != 0) && (mBBox.height() != 0); + if ( !mValid ) { + kdDebug() << "WMF : incorrect file format !" << endl; + } + } + else { + kdDebug() << "WMF Header : incorrect header !" << endl; + } + + buffer.close(); + return mValid; +} + + +//----------------------------------------------------------------------------- +bool QWinMetaFile::paint( const TQPaintDevice* aTarget, bool absolute ) +{ + int idx, i; + WmfCmd* cmd; + + if ( !mValid ) return false; + + assert( aTarget!=NULL ); + if ( mPainter.isActive() ) return false; + + if ( mObjHandleTab ) delete[] mObjHandleTab; + mObjHandleTab = new WinObjHandle* [ MAX_OBJHANDLE ]; + for ( i=MAX_OBJHANDLE-1; i>=0; i-- ) + mObjHandleTab[ i ] = NULL; + + mPainter.resetXForm(); + mWinding = false; + mAbsoluteCoord = absolute; + + mPainter.begin( const_cast<TQPaintDevice*>(aTarget) ); + if ( TQWMF_DEBUG ) { + kdDebug() << "Bounding box : " << mBBox.left() + << " " << mBBox.top() << " " << mBBox.right() << " " << mBBox.bottom() << endl; + } + + if ( mAbsoluteCoord ) { + mPainter.setWindow( mBBox.top(), mBBox.left(), mBBox.width(), mBBox.height() ); + } + mInternalWorldMatrix.reset(); + + for ( cmd=mFirstCmd; cmd; cmd=cmd->next ) + { + idx = cmd->funcIndex; + ( this->*metaFuncTab[ idx ].method )( cmd->numParm, cmd->parm ); + + if ( TQWMF_DEBUG ) { + TQString str = "", param; + if ( metaFuncTab[ idx ].name == NULL ) { + str += "UNKNOWN "; + } + if ( metaFuncTab[ idx ].method == &QWinMetaFile::noop ) { + str += "UNIMPLEMENTED "; + } + str += metaFuncTab[ idx ].name; + str += " : "; + + for ( i=0 ; i < cmd->numParm ; i++ ) { + param.setNum( cmd->parm[ i ] ); + str += param; + str += " "; + } + kdDebug() << str << endl; + } + } +/* + // TODO: cleanup this code when TQPicture::setBoundingBox() is possible in KOClipart (QT31) + // because actually TQPicture::boundingBox() != mBBox() + mWindowsCoord += 1; + if ( mWindowsCoord == 2 ) { + kdDebug() << "DRAW ANGLES " << endl; + mPainter.setPen( TQt::white ); + mPainter.drawPoint( mBBox.left(), mBBox.top() ); + mPainter.drawPoint( mBBox.right(), mBBox.bottom() ); + } +*/ + mPainter.end(); + return true; +} + + +//----------------s------------------------------------------------------------- +// Metafile painter methods +//----------------------------------------------------------------------------- +void QWinMetaFile::setWindowOrg( long, short* parm ) +{ + if ( mAbsoluteCoord ) { + TQRect r = mPainter.window(); + mPainter.setWindow( parm[ 1 ], parm[ 0 ], r.width(), r.height() ); + } + else { + double dx = mInternalWorldMatrix.dx(); + double dy = mInternalWorldMatrix.dy(); + + mInternalWorldMatrix.translate( -dx, -dy ); + mInternalWorldMatrix.translate( -parm[ 1 ], -parm[ 0 ] ); + mPainter.translate( -dx, -dy ); + mPainter.translate( -parm[ 1 ], -parm[ 0 ] ); + } +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setWindowExt( long, short* parm ) +{ + // negative value allowed for width and height : TQABS() forbidden + if ( mAbsoluteCoord ) { + TQRect r = mPainter.window(); + mPainter.setWindow( r.left(), r.top(), parm[ 1 ], parm[ 0 ] ); + } + else { + if ( (parm[ 0 ] != 0) && (parm[ 1 ] != 0) ) { + TQRect r = mPainter.window(); + double dx = mInternalWorldMatrix.dx(); + double dy = mInternalWorldMatrix.dy(); + double sx = mInternalWorldMatrix.m11(); + double sy = mInternalWorldMatrix.m22(); + + mInternalWorldMatrix.translate( -dx, -dy ); + mInternalWorldMatrix.scale( 1/sx, 1/sy ); + mPainter.translate( -dx, -dy ); + mPainter.scale( 1/sx, 1/sy ); + + sx = (double)r.width() / (double)parm[ 1 ]; + sy = (double)r.height() / (double)parm[ 0 ]; + + mInternalWorldMatrix.scale( sx, sy ); + mInternalWorldMatrix.translate( dx, dy ); + mPainter.scale( sx, sy ); + mPainter.translate( dx, dy ); + } + } +} + + +//----------------------------------------------------------------------------- +// Drawing +//----------------------------------------------------------------------------- +void QWinMetaFile::lineTo( long, short* parm ) +{ + mPainter.lineTo( parm[ 1 ], parm[ 0 ] ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::moveTo( long, short* parm ) +{ + mPainter.moveTo( parm[ 1 ], parm[ 0 ] ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::ellipse( long, short* parm ) +{ + mPainter.drawEllipse( parm[ 3 ], parm[ 2 ], parm[ 1 ]-parm[ 3 ], parm[ 0 ]-parm[ 2 ] ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::polygon( long, short* parm ) +{ + TQPointArray* pa; + + pa = pointArray( parm[ 0 ], &parm[ 1 ] ); + mPainter.drawPolygon( *pa, mWinding ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::polyPolygon( long, short* parm ) +{ + TQRegion region; + int i, j, startPolygon; + + mPainter.save(); + + // define clipping region + TQRect win = bbox(); + startPolygon = 1+parm[ 0 ]; + for ( i=0 ; i < parm[ 0 ] ; i++ ) { + TQPointArray pa1( parm[ 1+i ] ); + for ( j=0 ; j < parm[ 1+i ] ; j++) { + pa1.setPoint ( j, parm[ startPolygon ], parm[ startPolygon+1 ] ); + startPolygon += 2; + } + TQRegion r( pa1 ); + region = region.eor( r ); + } + mPainter.setClipRegion( region, TQPainter::CoordPainter ); + + // fill polygons + mPainter.fillRect( win.left(), win.top(), win.width(), win.height(), mPainter.brush() ); + + // draw polygon's border if necessary + if ( mPainter.pen().style() != TQt::NoPen ) { + mPainter.setClipping( false ); + mPainter.setBrush( TQt::NoBrush ); + + TQPointArray* pa; + int idxPolygon = 1 + parm[ 0 ]; + for ( i=0 ; i < parm[ 0 ] ; i++ ) { + pa = pointArray( parm[ 1+i ], &parm[ idxPolygon ] ); + mPainter.drawPolygon( *pa ); + idxPolygon += parm[ 1+i ] * 2; + } + } + + mPainter.restore(); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::polyline( long, short* parm ) +{ + TQPointArray* pa; + + pa = pointArray( parm[ 0 ], &parm[ 1 ] ); + mPainter.drawPolyline( *pa ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::rectangle( long, short* parm ) +{ + mPainter.drawRect( parm[ 3 ], parm[ 2 ], parm[ 1 ]-parm[ 3 ], parm[ 0 ]-parm[ 2 ] ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::roundRect( long, short* parm ) +{ + int xRnd = 0, yRnd = 0; + + // convert (xRound, yRound) in percentage + if ( (parm[ 3 ] - parm[ 5 ]) != 0 ) + xRnd = (parm[ 1 ] * 100) / (parm[ 3 ] - parm[ 5 ]) ; + if ( (parm[ 2 ] - parm[ 4 ]) != 0 ) + yRnd = (parm[ 0 ] * 100) / (parm[ 2 ] - parm[ 4 ]) ; + + mPainter.drawRoundRect( parm[ 5 ], parm[ 4 ], parm[ 3 ]-parm[ 5 ], parm[ 2 ]-parm[ 4 ], xRnd, yRnd ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::arc( long, short* parm ) +{ + int xCenter, yCenter, angleStart, aLength; + + xCenter = parm[ 7 ] + ((parm[ 5 ] - parm[ 7 ]) / 2); + yCenter = parm[ 6 ] + ((parm[ 4 ] - parm[ 6 ]) / 2); + + xyToAngle ( parm[ 3 ] - xCenter, yCenter - parm[ 2 ], parm[ 1 ] - xCenter, yCenter - parm[ 0 ], angleStart, aLength ); + + mPainter.drawArc( parm[ 7 ], parm[ 6 ], parm[ 5 ]-parm[ 7 ], parm[ 4 ]-parm[ 6 ], angleStart, aLength); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::chord( long, short* parm ) +{ + int xCenter, yCenter, angleStart, aLength; + + xCenter = parm[ 7 ] + ((parm[ 5 ] - parm[ 7 ]) / 2); + yCenter = parm[ 6 ] + ((parm[ 4 ] - parm[ 6 ]) / 2); + + xyToAngle ( parm[ 3 ] - xCenter, yCenter - parm[ 2 ], parm[ 1 ] - xCenter, yCenter - parm[ 0 ], angleStart, aLength ); + + mPainter.drawChord( parm[ 7 ], parm[ 6 ], parm[ 5 ]-parm[ 7 ], parm[ 4 ]-parm[ 6 ], angleStart, aLength); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::pie( long, short* parm ) +{ + int xCenter, yCenter, angleStart, aLength; + + xCenter = parm[ 7 ] + ((parm[ 5 ] - parm[ 7 ]) / 2); + yCenter = parm[ 6 ] + ((parm[ 4 ] - parm[ 6 ]) / 2); + + xyToAngle ( parm[ 3 ] - xCenter, yCenter - parm[ 2 ], parm[ 1 ] - xCenter, yCenter - parm[ 0 ], angleStart, aLength ); + + mPainter.drawPie( parm[ 7 ], parm[ 6 ], parm[ 5 ]-parm[ 7 ], parm[ 4 ]-parm[ 6 ], angleStart, aLength); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setPolyFillMode( long, short* parm ) +{ + mWinding = parm[ 0 ]; +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setBkColor( long, short* parm ) +{ + mPainter.setBackgroundColor( color( parm ) ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setBkMode( long, short* parm ) +{ + if ( parm[ 0 ]==1 ) mPainter.setBackgroundMode( Qt::TransparentMode ); + else mPainter.setBackgroundMode( Qt::OpaqueMode ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setPixel( long, short* parm ) +{ + TQPen pen = mPainter.pen(); + mPainter.setPen( color( parm ) ); + mPainter.drawPoint( parm[ 3 ], parm[ 2 ] ); + mPainter.setPen( pen ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setRop( long, short* parm ) +{ + mPainter.setRasterOp( winToTQtRaster( parm[ 0 ] ) ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::saveDC( long, short* ) +{ + mPainter.save(); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::restoreDC( long, short *parm ) +{ + for ( int i=0; i > parm[ 0 ] ; i-- ) + mPainter.restore(); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::intersectClipRect( long, short* parm ) +{ +/* TODO: better implementation : need QT 3.0.2 + TQRegion region = mPainter.clipRegion(); + if ( region.isEmpty() ) + region = bbox(); +*/ + TQRegion region( bbox() ); + + TQRegion newRegion( parm[ 3 ], parm[ 2 ], parm[ 1 ] - parm[ 3 ], parm[ 0 ] - parm[ 2 ] ); + region = region.intersect( newRegion ); + + mPainter.setClipRegion( region, TQPainter::CoordPainter ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::excludeClipRect( long, short* parm ) +{ +/* TODO: better implementation : need QT 3.0.2 + TQRegion region = mPainter.clipRegion(); + if ( region.isEmpty() ) + region = bbox(); +*/ + TQRegion region( bbox() ); + + TQRegion newRegion( parm[ 3 ], parm[ 2 ], parm[ 1 ] - parm[ 3 ], parm[ 0 ] - parm[ 2 ] ); + region = region.subtract( newRegion ); + + mPainter.setClipRegion( region, TQPainter::CoordPainter ); +} + + +//----------------------------------------------------------------------------- +// Text +//----------------------------------------------------------------------------- +void QWinMetaFile::setTextColor( long, short* parm ) +{ + mTextColor = color( parm ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setTextAlign( long, short* parm ) +{ + mTextAlign = parm[ 0 ]; +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::textOut( long num, short* parm ) +{ + + short *copyParm = new short[ num + 1 ]; + + // re-order parameters + int idxOffset = (parm[ 0 ] / 2) + 1 + (parm[ 0 ] & 1); + copyParm[ 0 ] = parm[ idxOffset ]; + copyParm[ 1 ] = parm[ idxOffset + 1 ]; + copyParm[ 2 ] = parm[ 0 ]; + copyParm[ 3 ] = 0; + memcpy( ©Parm[ 4 ], &parm[ 1 ], parm[ 0 ] ); + + extTextOut( num + 1, copyParm ); + delete [] copyParm; +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::extTextOut( long num, short* parm ) +{ + char* ptStr; + int x, y, width, height; + int idxOffset; + + if ( parm[ 3 ] != 0 ) // ETO_CLIPPED flag add 4 parameters + ptStr = (char*)&parm[ 8 ]; + else + ptStr = (char*)&parm[ 4 ]; + + TQCString text( ptStr, parm[ 2 ] + 1 ); + + TQFontMetrics fm( mPainter.font() ); + width = fm.width( text ) + fm.descent(); // because fm.width(text) isn't rigth with Italic text + height = fm.height(); + + mPainter.save(); + + if ( mTextAlign & 0x01 ) { // (left, top) position = current logical position + TQPoint pos = mPainter.pos(); + x = pos.x(); + y = pos.y(); + } + else { // (left, top) position = parameters + x = parm[ 1 ]; + y = parm[ 0 ]; + } + + if ( mRotation ) { + mPainter.translate( parm[ 1 ], parm[ 0 ]); + mPainter.rotate ( mRotation ); + mPainter.translate( -parm[ 1 ], -parm[ 0 ] ); + } + + // alignment + if ( mTextAlign & 0x06 ) + x -= ( width / 2 ); + if ( mTextAlign & 0x08 ) + y -= (height - fm.descent()); + + mPainter.setPen( mTextColor ); + idxOffset = (parm[ 2 ] / 2) + 4 + (parm[ 2 ] & 1); + if ( ( parm[ 2 ] > 1 ) && ( num >= (idxOffset + parm[ 2 ]) ) && ( parm[ 3 ] == 0 ) ) { + // offset for each char + int left = x; + mPainter.drawText( left, y, width, height, TQt::AlignLeft | TQt::AlignTop, text.mid(0, 1) ); + for ( int i = 1; i < parm[ 2 ] ; i++ ) { + left += parm[ idxOffset + i - 1 ]; + mPainter.drawText( left, y, width, height, TQt::AlignLeft | TQt::AlignTop, text.mid(i, 1) ); + } + } + else { + mPainter.drawText( x, y, width, height, TQt::AlignLeft | TQt::AlignTop, text ); + } + + mPainter.restore(); + +} + + + +//----------------------------------------------------------------------------- +// Bitmap +//----------------------------------------------------------------------------- +void QWinMetaFile::dibBitBlt( long num, short* parm ) +{ + if ( num > 9 ) { // DIB image + TQImage bmpSrc; + + if ( dibToBmp( bmpSrc, (char*)&parm[ 8 ], (num - 8) * 2 ) ) { + long raster = toDWord( parm ); + + mPainter.setRasterOp( winToTQtRaster( raster ) ); + + // wmf file allow negative width or height + mPainter.save(); + if ( parm[ 5 ] < 0 ) { // width < 0 => horizontal flip + TQWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F ); + mPainter.setWorldMatrix( m, true ); + } + if ( parm[ 4 ] < 0 ) { // height < 0 => vertical flip + TQWMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F ); + mPainter.setWorldMatrix( m, true ); + } + mPainter.drawImage( parm[ 7 ], parm[ 6 ], bmpSrc, parm[ 3 ], parm[ 2 ], parm[ 5 ], parm[ 4 ] ); + mPainter.restore(); + } + } + else { + kdDebug() << "QWinMetaFile::dibBitBlt without image: not implemented " << endl; + } +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::dibStretchBlt( long num, short* parm ) +{ + TQImage bmpSrc; + + if ( dibToBmp( bmpSrc, (char*)&parm[ 10 ], (num - 10) * 2 ) ) { + long raster = toDWord( parm ); + + mPainter.setRasterOp( winToTQtRaster( raster ) ); + + // wmf file allow negative width or height + mPainter.save(); + if ( parm[ 7 ] < 0 ) { // width < 0 => horizontal flip + TQWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F ); + mPainter.setWorldMatrix( m, true ); + } + if ( parm[ 6 ] < 0 ) { // height < 0 => vertical flip + TQWMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F ); + mPainter.setWorldMatrix( m, true ); + } + bmpSrc = bmpSrc.copy( parm[ 5 ], parm[ 4 ], parm[ 3 ], parm[ 2 ] ); + // TODO: scale the bitmap ( TQImage::scale(parm[ 7 ], parm[ 6 ]) is actually too slow ) + + mPainter.drawImage( parm[ 9 ], parm[ 8 ], bmpSrc ); + mPainter.restore(); + } +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::stretchDib( long num, short* parm ) +{ + TQImage bmpSrc; + + if ( dibToBmp( bmpSrc, (char*)&parm[ 11 ], (num - 11) * 2 ) ) { + long raster = toDWord( parm ); + + mPainter.setRasterOp( winToTQtRaster( raster ) ); + + // wmf file allow negative width or height + mPainter.save(); + if ( parm[ 8 ] < 0 ) { // width < 0 => horizontal flip + TQWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F ); + mPainter.setWorldMatrix( m, true ); + } + if ( parm[ 7 ] < 0 ) { // height < 0 => vertical flip + TQWMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F ); + mPainter.setWorldMatrix( m, true ); + } + bmpSrc = bmpSrc.copy( parm[ 6 ], parm[ 5 ], parm[ 4 ], parm[ 3 ] ); + // TODO: scale the bitmap ( TQImage::scale(parm[ 8 ], parm[ 7 ]) is actually too slow ) + + mPainter.drawImage( parm[ 10 ], parm[ 9 ], bmpSrc ); + mPainter.restore(); + } +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::dibCreatePatternBrush( long num, short* parm ) +{ + WinObjPatternBrushHandle* handle = new WinObjPatternBrushHandle; + addHandle( handle ); + TQImage bmpSrc; + + if ( dibToBmp( bmpSrc, (char*)&parm[ 2 ], (num - 2) * 2 ) ) { + handle->image = bmpSrc; + handle->brush.setPixmap( handle->image ); + } +} + + +//----------------------------------------------------------------------------- +// Object handle +//----------------------------------------------------------------------------- +void QWinMetaFile::selectObject( long, short* parm ) +{ + int idx = parm[ 0 ]; + if ( idx>=0 && idx < MAX_OBJHANDLE && mObjHandleTab[ idx ] ) + mObjHandleTab[ idx ]->apply( mPainter ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::deleteObject( long, short* parm ) +{ + deleteHandle( parm[ 0 ] ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::createEmptyObject( long, short* ) +{ + // allocation of an empty object (to keep object counting in sync) + WinObjPenHandle* handle = new WinObjPenHandle; + addHandle( handle ); + kdDebug() << "QWinMetaFile: unimplemented createObject " << endl; +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::createBrushIndirect( long, short* parm ) +{ + static Qt::BrushStyle hatchedStyleTab[] = + { + Qt::HorPattern, + Qt::FDiagPattern, + Qt::BDiagPattern, + Qt::CrossPattern, + Qt::DiagCrossPattern + }; + static Qt::BrushStyle styleTab[] = + { Qt::SolidPattern, + Qt::NoBrush, + Qt::FDiagPattern, /* hatched */ + Qt::Dense4Pattern, /* should be custom bitmap pattern */ + Qt::HorPattern, /* should be BS_INDEXED (?) */ + Qt::VerPattern, /* should be device-independent bitmap */ + Qt::Dense6Pattern, /* should be device-independent packed-bitmap */ + Qt::Dense2Pattern, /* should be BS_PATTERN8x8 */ + Qt::Dense3Pattern /* should be device-independent BS_DIBPATTERN8x8 */ + }; + Qt::BrushStyle style; + short arg; + WinObjBrushHandle* handle = new WinObjBrushHandle; + addHandle( handle ); + + arg = parm[ 0 ]; + if ( arg==2 ) + { + arg = parm[ 3 ]; + if ( arg>=0 && arg<5 ) style = hatchedStyleTab[ arg ]; + else + { + kdDebug() << "QWinMetaFile::createBrushIndirect: invalid hatched brush " << arg << endl; + style = Qt::SolidPattern; + } + } + else if ( arg>=0 && arg<9 ) + style = styleTab[ arg ]; + else + { + kdDebug() << "QWinMetaFile::createBrushIndirect: invalid brush " << arg << endl; + style = Qt::SolidPattern; + } + handle->brush.setStyle( style ); + handle->brush.setColor( color( parm+1 ) ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::createPenIndirect( long, short* parm ) +{ + static Qt::PenStyle styleTab[] = + { Qt::SolidLine, Qt::DashLine, Qt::DotLine, Qt::DashDotLine, Qt::DashDotDotLine, + Qt::NoPen, Qt::SolidLine }; + Qt::PenStyle style; + WinObjPenHandle* handle = new WinObjPenHandle; + addHandle( handle ); + + if ( parm[ 0 ]>=0 && parm[ 0 ]<6 ) style=styleTab[ parm[ 0 ] ]; + else + { + kdDebug() << "QWinMetaFile::createPenIndirect: invalid pen " << parm[ 0 ] << endl; + style = Qt::SolidLine; + } + + handle->pen.setStyle( style ); + handle->pen.setColor( color( parm+3 ) ); + handle->pen.setCapStyle( Qt::RoundCap ); + + //int width = 0; + // TODO : width of pen proportional to device context width + // DOESN'T WORK +/* + TQRect devRec; + devRec = mPainter.xForm( mBBox ); + width = ( parm[ 0 ] * devRec.width() ) / mBBox.width() ; + kdDebug() << "CreatePenIndirect: " << endl; + kdDebug() << " log coord. : " << mBBox.width() << " " << mBBox.height() << endl; + kdDebug() << " log. pen : " << parm[ 1 ] << " " << parm[ 2 ] << endl; + kdDebug() << " dev. pen : " << width << endl; + handle->pen.setWidth( width ); +*/ +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::createFontIndirect( long , short* parm) +{ + WinObjFontHandle* handle = new WinObjFontHandle; + addHandle( handle ); + + TQString family( (const char*)&parm[ 9 ] ); + + mRotation = -parm[ 2 ] / 10; // text rotation (in 1/10 degree) + // TODO: memorisation of rotation in object Font + handle->font.setFamily( family ); + handle->font.setFixedPitch( ((parm[ 8 ] & 0x01) == 0) ); + // TODO: investigation why some test case need -2. (size of font in logical point) + handle->font.setPointSize( TQABS(parm[ 0 ]) - 2 ); + handle->font.setWeight( (parm[ 4 ] >> 3) ); + handle->font.setItalic( (parm[ 5 ] & 0x01) ); + handle->font.setUnderline( (parm[ 5 ] & 0x100) ); +} + + +//----------------------------------------------------------------------------- +// Misc +//----------------------------------------------------------------------------- +void QWinMetaFile::noop( long, short* ) +{ +} + + +void QWinMetaFile::end( long, short* ) +{ + // end of file : +// kdDebug() << "END bbox=( " << mBBox.left() << "; " << mBBox.top() << "; " << mBBox.width() << "; " << mBBox.height() << ")" << endl; +} + + +//----------------------------------------------------------------------------- +unsigned short QWinMetaFile::calcCheckSum( WmfPlaceableHeader* apmfh ) +{ + WORD* lpWord; + WORD wResult, i; + + // Start with the first word + wResult = *( lpWord = ( WORD* )( apmfh ) ); + // XOR in each of the other 9 words + for( i=1; i<=9; i++ ) + { + wResult ^= lpWord[ i ]; + } + return wResult; +} + + +//----------------------------------------------------------------------------- +int QWinMetaFile::findFunc( unsigned short aFunc ) const +{ + int i; + + for ( i=0; metaFuncTab[ i ].name; i++ ) + if ( metaFuncTab[ i ].func == aFunc ) return i; + + // here : unknown function + return i; +} + +//----------------------------------------------------------------------------- +TQPointArray* QWinMetaFile::pointArray( short num, short* parm ) +{ + int i; + + mPoints.resize( num ); + + for ( i=0; i<num; i++, parm+=2 ) + mPoints.setPoint( i, parm[ 0 ], parm[ 1 ] ); + + return &mPoints; +} + +//----------------------------------------------------------------------------- +unsigned int QWinMetaFile::toDWord( short* parm ) +{ + unsigned int l; + +#if !defined( WORDS_BIGENDIAN ) + l = *( unsigned int* )( parm ); +#else + char *bytes; + char swap[ 4 ]; + bytes = ( char* )parm; + swap[ 0 ] = bytes[ 2 ]; + swap[ 1 ] = bytes[ 3 ]; + swap[ 2 ] = bytes[ 0 ]; + swap[ 3 ] = bytes[ 1 ]; + l = *( unsigned int* )( swap ); +#endif + + return l; +} + + +//----------------------------------------------------------------------------- +TQColor QWinMetaFile::color( short* parm ) +{ + unsigned int colorRef; + int red, green, blue; + + colorRef = toDWord( parm ) & 0xffffff; + red = colorRef & 255; + green = ( colorRef>>8 ) & 255; + blue = ( colorRef>>16 ) & 255; + + return TQColor( red, green, blue ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::xyToAngle( int xStart, int yStart, int xEnd, int yEnd, int& angleStart, int& angleLength ) +{ + float aStart, aLength; + + aStart = atan2( yStart, xStart ); + aLength = atan2( yEnd, xEnd ) - aStart; + + angleStart = (int)(aStart * 2880 / 3.14166); + angleLength = (int)(aLength * 2880 / 3.14166); + if ( angleLength < 0 ) angleLength = 5760 + angleLength; +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::addHandle( WinObjHandle* handle ) +{ + int idx; + + for ( idx=0; idx < MAX_OBJHANDLE ; idx++ ) + if ( mObjHandleTab[ idx ] == NULL ) break; + + if ( idx < MAX_OBJHANDLE ) + mObjHandleTab[ idx ] = handle; + else + kdDebug() << "QWinMetaFile error: handle table full !" << endl; +} + +//----------------------------------------------------------------------------- +void QWinMetaFile::deleteHandle( int idx ) +{ + if ( idx >= 0 && idx < MAX_OBJHANDLE && mObjHandleTab[ idx ] ) + { + delete mObjHandleTab[ idx ]; + mObjHandleTab[ idx ] = NULL; + } +} + +//----------------------------------------------------------------------------- +TQt::RasterOp QWinMetaFile::winToTQtRaster( short parm ) const +{ + static const TQt::RasterOp opTab[] = + { + TQt::CopyROP, + TQt::ClearROP, TQt::NandROP, TQt::NotAndROP, TQt::NotCopyROP, + TQt::AndNotROP, TQt::NotROP, TQt::XorROP, TQt::NorROP, + TQt::AndROP, TQt::NotXorROP, TQt::NopROP, TQt::NotOrROP, + TQt::CopyROP, TQt::OrNotROP, TQt::OrROP, TQt::SetROP + }; + + if ( parm > 0 && parm <= 16 ) + return opTab[ parm ]; + else + return TQt::CopyROP; +} + +//----------------------------------------------------------------------------- +TQt::RasterOp QWinMetaFile::winToTQtRaster( long parm ) const +{ + /* TODO: Ternary raster operations + 0x00C000CA dest = (source AND pattern) + 0x00F00021 dest = pattern + 0x00FB0A09 dest = DPSnoo + 0x005A0049 dest = pattern XOR dest */ + static const struct OpTab + { + long winRasterOp; + TQt::RasterOp qtRasterOp; + } opTab[] = + { + { 0x00CC0020, TQt::CopyROP }, + { 0x00EE0086, TQt::OrROP }, + { 0x008800C6, TQt::AndROP }, + { 0x00660046, TQt::XorROP }, + { 0x00440328, TQt::AndNotROP }, + { 0x00330008, TQt::NotCopyROP }, + { 0x001100A6, TQt::NandROP }, + { 0x00C000CA, TQt::CopyROP }, + { 0x00BB0226, TQt::NotOrROP }, + { 0x00F00021, TQt::CopyROP }, + { 0x00FB0A09, TQt::CopyROP }, + { 0x005A0049, TQt::CopyROP }, + { 0x00550009, TQt::NotROP }, + { 0x00000042, TQt::ClearROP }, + { 0x00FF0062, TQt::SetROP } + }; + + int i; + for ( i=0 ; i < 15 ; i++ ) + if ( opTab[ i ].winRasterOp == parm ) + break; + + if ( i < 15 ) + return opTab[ i ].qtRasterOp; + else + return TQt::CopyROP; +} + +//----------------------------------------------------------------------------- +bool QWinMetaFile::dibToBmp( TQImage& bmp, const char* dib, long size ) +{ + typedef struct _BMPFILEHEADER { + WORD bmType; + DWORD bmSize; + WORD bmReserved1; + WORD bmReserved2; + DWORD bmOffBits; + } BMPFILEHEADER; + + int sizeBmp = size + 14; + + TQByteArray pattern( sizeBmp ); // BMP header and DIB data + pattern.fill(0); + memcpy( &pattern[ 14 ], dib, size ); + + // add BMP header + BMPFILEHEADER* bmpHeader; + bmpHeader = (BMPFILEHEADER*)((const char*)pattern); + bmpHeader->bmType = 0x4D42; + bmpHeader->bmSize = sizeBmp; + + if ( !bmp.loadFromData( (const uchar*)bmpHeader, pattern.size(), "BMP" ) ) { + kdDebug() << "QWinMetaFile::dibToBmp: invalid bitmap " << endl; + return false; + } + else { +// if ( bmp.save("/home/software/kde-cvs/qt/examples/wmf/test.bmp", "BMP") ) +// if ( bmp.load( "/home/software/kde-cvs/qt/examples/wmf/test.bmp", "BMP" ) ) +// fprintf(stderr, "Bitmap ok \n"); + return true; + } +} + |