1 /* Windows Meta File Loader/Painter Class Implementation
3 * Copyright ( C ) 1998 Stefan Taferner
4 * Modified 2002 thierry lorthiois
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or ( at your
9 * option ) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details. You should have received a copy
15 * of the GNU General Public License along with this program; if not, write
16 * to the Free Software Foundation, Inc, 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
20 #include <config-ktnef.h> // WORDS_BIGENDIAN
27 #include <QPainterPath>
28 #include <QDataStream>
33 #include "ktnef_debug.h"
35 bool qwmfDebug
= false;
38 #include "wmfstruct.h"
39 #include "metafuncs.h"
51 unsigned short funcIndex
;
59 virtual ~WinObjHandle() {}
60 virtual void apply(QPainter
&p
) = 0;
63 class WinObjBrushHandle
: public WinObjHandle
66 void apply(QPainter
&p
) Q_DECL_OVERRIDE
;
68 virtual ~WinObjBrushHandle() {}
71 class WinObjPenHandle
: public WinObjHandle
74 void apply(QPainter
&p
) Q_DECL_OVERRIDE
;
76 virtual ~WinObjPenHandle() {}
79 class WinObjPatternBrushHandle
: public WinObjHandle
82 void apply(QPainter
&p
) Q_DECL_OVERRIDE
;
85 virtual ~WinObjPatternBrushHandle() {}
88 class WinObjFontHandle
: public WinObjHandle
91 void apply(QPainter
&p
) Q_DECL_OVERRIDE
;
94 virtual ~WinObjFontHandle() {}
97 void WinObjBrushHandle::apply(QPainter
&p
)
102 void WinObjPenHandle::apply(QPainter
&p
)
107 void WinObjPatternBrushHandle::apply(QPainter
&p
)
112 void WinObjFontHandle::apply(QPainter
&p
)
117 #define MAX_OBJHANDLE 64
119 //-----------------------------------------------------------------------------
120 QWinMetaFile::QWinMetaFile()
124 mObjHandleTab
= NULL
;
128 //-----------------------------------------------------------------------------
129 QWinMetaFile::~QWinMetaFile()
133 delete[] mObjHandleTab
;
137 //-----------------------------------------------------------------------------
138 bool QWinMetaFile::load(const QString
&filename
)
140 QFile
file(filename
);
142 if (!file
.exists()) {
143 qCDebug(KTNEFAPPS_LOG
) << "File" << QFile::encodeName(filename
) << " does not exist";
147 if (!file
.open(QIODevice::ReadOnly
)) {
148 qCDebug(KTNEFAPPS_LOG
) << "Cannot open file" << QFile::encodeName(filename
);
152 QByteArray ba
= file
.readAll();
156 buffer
.open(QIODevice::ReadOnly
);
160 //-----------------------------------------------------------------------------
161 bool QWinMetaFile::load(QBuffer
&buffer
)
164 WmfEnhMetaHeader eheader
;
165 WmfMetaHeader header
;
166 WmfPlaceableHeader pheader
;
175 mTextColor
= Qt::black
;
181 st
.setDevice(&buffer
);
182 st
.setByteOrder(QDataStream::LittleEndian
); // Great, I love Qt !
184 //----- Read placeable metafile header
186 mIsPlaceable
= (pheader
.key
== (DWORD
)APMHEADER_KEY
);
189 st
>> pheader
.bbox
.left
;
190 st
>> pheader
.bbox
.top
;
191 st
>> pheader
.bbox
.right
;
192 st
>> pheader
.bbox
.bottom
;
194 st
>> pheader
.reserved
;
195 st
>> pheader
.checksum
;
196 checksum
= calcCheckSum(&pheader
);
197 if (pheader
.checksum
!= checksum
) {
198 mIsPlaceable
= false;
202 mBBox
.setLeft(pheader
.bbox
.left
);
203 mBBox
.setTop(pheader
.bbox
.top
);
204 mBBox
.setRight(pheader
.bbox
.right
);
205 mBBox
.setBottom(pheader
.bbox
.bottom
);
206 mHeaderBoundingBox
= mBBox
;
208 qCDebug(KTNEFAPPS_LOG
) << endl
<< "-------------------------------------------------";
209 qCDebug(KTNEFAPPS_LOG
) << "WMF Placeable Header (" << static_cast<int>(sizeof(pheader
)) << "):";
210 qCDebug(KTNEFAPPS_LOG
) << " bbox=(" << mBBox
.left() << ";" << mBBox
.top() << ";" << mBBox
.width()
211 << "; " << mBBox
.height() << ")";
212 qCDebug(KTNEFAPPS_LOG
) << " inch=" << pheader
.inch
;
213 qCDebug(KTNEFAPPS_LOG
) << " checksum=" << pheader
.checksum
<< "("
214 << (pheader
.checksum
== checksum
? "ok" : "wrong") << " )";
220 //----- Read as enhanced metafile header
221 filePos
= buffer
.pos();
224 st
>> eheader
.rclBounds
.left
;
225 st
>> eheader
.rclBounds
.top
;
226 st
>> eheader
.rclBounds
.right
;
227 st
>> eheader
.rclBounds
.bottom
;
228 st
>> eheader
.rclFrame
.left
;
229 st
>> eheader
.rclFrame
.top
;
230 st
>> eheader
.rclFrame
.right
;
231 st
>> eheader
.rclFrame
.bottom
;
232 st
>> eheader
.dSignature
;
233 mIsEnhanced
= (eheader
.dSignature
== ENHMETA_SIGNATURE
);
234 if (mIsEnhanced
) { // is it really enhanced ?
235 st
>> eheader
.nVersion
;
236 st
>> eheader
.nBytes
;
237 st
>> eheader
.nRecords
;
238 st
>> eheader
.nHandles
;
239 st
>> eheader
.sReserved
;
240 st
>> eheader
.nDescription
;
241 st
>> eheader
.offDescription
;
242 st
>> eheader
.nPalEntries
;
243 st
>> eheader
.szlDevice
.width
;
244 st
>> eheader
.szlDevice
.height
;
245 st
>> eheader
.szlMillimeters
.width
;
246 st
>> eheader
.szlMillimeters
.height
;
249 qCDebug(KTNEFAPPS_LOG
) << endl
<< "-------------------------------------------------";
250 qCDebug(KTNEFAPPS_LOG
) << "WMF Extended Header:";
251 qCDebug(KTNEFAPPS_LOG
) << " iType=" << eheader
.iType
;
252 qCDebug(KTNEFAPPS_LOG
) << " nSize=" << eheader
.nSize
;
253 qCDebug(KTNEFAPPS_LOG
) << " rclBounds=(" << eheader
.rclBounds
.left
<< ";" << eheader
.rclBounds
.top
<< ";"
254 << eheader
.rclBounds
.right
<< "; " << eheader
.rclBounds
.bottom
<< ")";
255 qCDebug(KTNEFAPPS_LOG
) << " rclFrame=(" << eheader
.rclFrame
.left
<< ";" << eheader
.rclFrame
.top
<< ";"
256 << eheader
.rclFrame
.right
<< "; " << eheader
.rclFrame
.bottom
<< ")";
257 qCDebug(KTNEFAPPS_LOG
) << " nBytes=" << eheader
.nBytes
;
258 qCDebug(KTNEFAPPS_LOG
) << "\nNOT YET IMPLEMENTED, SORRY.";
260 } else { // no, not enhanced
261 //----- Read as standard metafile header
262 buffer
.seek(filePos
);
264 st
>> header
.mtHeaderSize
;
265 st
>> header
.mtVersion
;
267 st
>> header
.mtNoObjects
;
268 st
>> header
.mtMaxRecord
;
269 st
>> header
.mtNoParameters
;
271 qCDebug(KTNEFAPPS_LOG
) << "WMF Header:" << "mtSize=" << header
.mtSize
;
275 //----- Test header validity
276 mValid
= ((header
.mtHeaderSize
== 9) && (header
.mtNoParameters
== 0)) || mIsEnhanced
|| mIsPlaceable
;
278 //----- Read Metafile Records
281 while (!st
.atEnd() && (rdFunc
!= 0)) {
284 idx
= findFunc(rdFunc
);
295 cmd
->funcIndex
= idx
;
296 cmd
->numParm
= rdSize
;
297 cmd
->parm
= new WORD
[ rdSize
];
300 for (i
= 0; i
< rdSize
&& !st
.atEnd(); ++i
) {
301 st
>> cmd
->parm
[ i
];
304 if (rdFunc
== 0x020B) { // SETWINDOWORG: dimensions
305 mBBox
.setLeft(cmd
->parm
[ 1 ]);
306 mBBox
.setTop(cmd
->parm
[ 0 ]);
308 if (rdFunc
== 0x020C) { // SETWINDOWEXT: dimensions
309 mBBox
.setWidth(cmd
->parm
[ 1 ]);
310 mBBox
.setHeight(cmd
->parm
[ 0 ]);
314 qCDebug(KTNEFAPPS_LOG
) << "WMF : file truncated !";
318 //----- Test records validities
319 mValid
= (rdFunc
== 0) && (mBBox
.width() != 0) && (mBBox
.height() != 0);
321 qCDebug(KTNEFAPPS_LOG
) << "WMF : incorrect file format !";
324 qCDebug(KTNEFAPPS_LOG
) << "WMF Header : incorrect header !";
331 //-----------------------------------------------------------------------------
332 bool QWinMetaFile::paint(QPaintDevice
*aTarget
, bool absolute
)
341 assert(aTarget
!= NULL
);
342 if (mPainter
.isActive()) {
347 delete[] mObjHandleTab
;
349 mObjHandleTab
= new WinObjHandle
* [ MAX_OBJHANDLE
];
350 for (i
= MAX_OBJHANDLE
- 1; i
>= 0; i
--) {
351 mObjHandleTab
[ i
] = NULL
;
354 mPainter
.resetMatrix();
356 mAbsoluteCoord
= absolute
;
358 mPainter
.begin(aTarget
);
360 qCDebug(KTNEFAPPS_LOG
) << "Bounding box :" << mBBox
.left()
361 << " " << mBBox
.top() << " " << mBBox
.right() << " " << mBBox
.bottom();
364 if (mAbsoluteCoord
) {
365 mPainter
.setWindow(mBBox
.top(), mBBox
.left(), mBBox
.width(), mBBox
.height());
367 mInternalWorldMatrix
.reset();
369 for (cmd
= mFirstCmd
; cmd
; cmd
= cmd
->next
) {
370 idx
= cmd
->funcIndex
;
371 (this->*metaFuncTab
[ idx
].method
)(cmd
->numParm
, cmd
->parm
);
375 if (metaFuncTab
[ idx
].name
== NULL
) {
376 str
+= QLatin1String("UNKNOWN ");
378 if (metaFuncTab
[ idx
].method
== &QWinMetaFile::noop
) {
379 str
+= QLatin1String("UNIMPLEMENTED ");
381 str
+= QLatin1String(metaFuncTab
[ idx
].name
);
382 str
+= QLatin1String(" : ");
384 for (i
= 0; i
< cmd
->numParm
; ++i
) {
385 param
.setNum(cmd
->parm
[ i
]);
387 str
+= QLatin1Char(' ');
389 qCDebug(KTNEFAPPS_LOG
) << str
;
393 // TODO: cleanup this code when QPicture::setBoundingBox() is possible in KOClipart (QT31)
394 // because actually QPicture::boundingBox() != mBBox()
396 if ( mWindowsCoord == 2 ) {
397 qCDebug(KTNEFAPPS_LOG) <<"DRAW ANGLES";
398 mPainter.setPen( Qt::white );
399 mPainter.drawPoint( mBBox.left(), mBBox.top() );
400 mPainter.drawPoint( mBBox.right(), mBBox.bottom() );
407 //----------------s-------------------------------------------------------------
408 // Metafile painter methods
409 //-----------------------------------------------------------------------------
410 void QWinMetaFile::setWindowOrg(long, short *parm
)
412 if (mAbsoluteCoord
) {
413 QRect r
= mPainter
.window();
414 mPainter
.setWindow(parm
[ 1 ], parm
[ 0 ], r
.width(), r
.height());
416 double dx
= mInternalWorldMatrix
.dx();
417 double dy
= mInternalWorldMatrix
.dy();
419 mInternalWorldMatrix
.translate(-dx
, -dy
);
420 mInternalWorldMatrix
.translate(-parm
[ 1 ], -parm
[ 0 ]);
421 mPainter
.translate(-dx
, -dy
);
422 mPainter
.translate(-parm
[ 1 ], -parm
[ 0 ]);
426 //-----------------------------------------------------------------------------
427 void QWinMetaFile::setWindowExt(long, short *parm
)
429 // negative value allowed for width and height : QABS() forbidden
430 if (mAbsoluteCoord
) {
431 QRect r
= mPainter
.window();
432 mPainter
.setWindow(r
.left(), r
.top(), parm
[ 1 ], parm
[ 0 ]);
434 if ((parm
[ 0 ] != 0) && (parm
[ 1 ] != 0)) {
435 QRect r
= mPainter
.window();
436 double dx
= mInternalWorldMatrix
.dx();
437 double dy
= mInternalWorldMatrix
.dy();
438 double sx
= mInternalWorldMatrix
.m11();
439 double sy
= mInternalWorldMatrix
.m22();
441 mInternalWorldMatrix
.translate(-dx
, -dy
);
442 mInternalWorldMatrix
.scale(1 / sx
, 1 / sy
);
443 mPainter
.translate(-dx
, -dy
);
444 mPainter
.scale(1 / sx
, 1 / sy
);
446 sx
= (double)r
.width() / (double)parm
[ 1 ];
447 sy
= (double)r
.height() / (double)parm
[ 0 ];
449 mInternalWorldMatrix
.scale(sx
, sy
);
450 mInternalWorldMatrix
.translate(dx
, dy
);
451 mPainter
.scale(sx
, sy
);
452 mPainter
.translate(dx
, dy
);
457 //-----------------------------------------------------------------------------
459 //-----------------------------------------------------------------------------
460 void QWinMetaFile::lineTo(long, short *parm
)
462 mPainter
.drawLine(mLastPos
, QPoint(parm
[1], parm
[0]));
465 //-----------------------------------------------------------------------------
466 void QWinMetaFile::moveTo(long, short *parm
)
468 mLastPos
= QPoint(parm
[ 1 ], parm
[ 0 ]);
471 //-----------------------------------------------------------------------------
472 void QWinMetaFile::ellipse(long, short *parm
)
474 mPainter
.drawEllipse(parm
[ 3 ], parm
[ 2 ], parm
[ 1 ] - parm
[ 3 ], parm
[ 0 ] - parm
[ 2 ]);
477 //-----------------------------------------------------------------------------
478 void QWinMetaFile::polygon(long, short *parm
)
480 QPolygon
*pa
; // causing a memleck ???
482 pa
= pointArray(parm
[ 0 ], &parm
[ 1 ]);
484 mPainter
.drawPolygon(*pa
, Qt::WindingFill
);
486 mPainter
.drawPolygon(*pa
, Qt::OddEvenFill
);
492 //-----------------------------------------------------------------------------
493 void QWinMetaFile::polyPolygon(long, short *parm
)
496 int i
, j
, startPolygon
;
500 // define clipping region
502 startPolygon
= 1 + parm
[ 0 ];
503 for (i
= 0; i
< parm
[ 0 ]; ++i
) {
504 QPolygon
pa1(parm
[ 1 + i
]);
505 for (j
= 0; j
< parm
[ 1 + i
]; j
++) {
506 pa1
.setPoint(j
, parm
[ startPolygon
], parm
[ startPolygon
+ 1 ]);
510 region
= region
.eor(r
);
512 mPainter
.setClipRegion(region
);
515 mPainter
.fillRect(win
.left(), win
.top(), win
.width(), win
.height(), mPainter
.brush());
517 // draw polygon's border if necessary
518 if (mPainter
.pen().style() != Qt::NoPen
) {
519 mPainter
.setClipping(false);
520 mPainter
.setBrush(Qt::NoBrush
);
523 int idxPolygon
= 1 + parm
[ 0 ];
524 for (i
= 0; i
< parm
[ 0 ]; ++i
) {
525 pa
= pointArray(parm
[ 1 + i
], &parm
[ idxPolygon
]);
526 mPainter
.drawPolygon(*pa
);
527 idxPolygon
+= parm
[ 1 + i
] * 2;
534 //-----------------------------------------------------------------------------
535 void QWinMetaFile::polyline(long, short *parm
)
539 pa
= pointArray(parm
[ 0 ], &parm
[ 1 ]);
540 mPainter
.drawPolyline(*pa
);
543 //-----------------------------------------------------------------------------
544 void QWinMetaFile::rectangle(long, short *parm
)
546 mPainter
.drawRect(parm
[ 3 ], parm
[ 2 ], parm
[ 1 ] - parm
[ 3 ], parm
[ 0 ] - parm
[ 2 ]);
549 //-----------------------------------------------------------------------------
550 void QWinMetaFile::roundRect(long, short *parm
)
552 int xRnd
= 0, yRnd
= 0;
554 // convert (xRound, yRound) in percentage
555 if ((parm
[ 3 ] - parm
[ 5 ]) != 0) {
556 xRnd
= (parm
[ 1 ] * 100) / (parm
[ 3 ] - parm
[ 5 ]);
558 if ((parm
[ 2 ] - parm
[ 4 ]) != 0) {
559 yRnd
= (parm
[ 0 ] * 100) / (parm
[ 2 ] - parm
[ 4 ]);
562 mPainter
.drawRoundRect(parm
[ 5 ], parm
[ 4 ], parm
[ 3 ] - parm
[ 5 ], parm
[ 2 ] - parm
[ 4 ], xRnd
, yRnd
);
565 //-----------------------------------------------------------------------------
566 void QWinMetaFile::arc(long, short *parm
)
568 int xCenter
, yCenter
, angleStart
, aLength
;
570 xCenter
= parm
[ 7 ] + ((parm
[ 5 ] - parm
[ 7 ]) / 2);
571 yCenter
= parm
[ 6 ] + ((parm
[ 4 ] - parm
[ 6 ]) / 2);
573 xyToAngle(parm
[ 3 ] - xCenter
, yCenter
- parm
[ 2 ], parm
[ 1 ] - xCenter
, yCenter
- parm
[ 0 ], angleStart
, aLength
);
575 mPainter
.drawArc(parm
[ 7 ], parm
[ 6 ], parm
[ 5 ] - parm
[ 7 ], parm
[ 4 ] - parm
[ 6 ], angleStart
, aLength
);
578 //-----------------------------------------------------------------------------
579 void QWinMetaFile::chord(long, short *parm
)
581 int xCenter
, yCenter
, angleStart
, aLength
;
583 xCenter
= parm
[ 7 ] + ((parm
[ 5 ] - parm
[ 7 ]) / 2);
584 yCenter
= parm
[ 6 ] + ((parm
[ 4 ] - parm
[ 6 ]) / 2);
586 xyToAngle(parm
[ 3 ] - xCenter
, yCenter
- parm
[ 2 ], parm
[ 1 ] - xCenter
, yCenter
- parm
[ 0 ], angleStart
, aLength
);
588 mPainter
.drawChord(parm
[ 7 ], parm
[ 6 ], parm
[ 5 ] - parm
[ 7 ], parm
[ 4 ] - parm
[ 6 ], angleStart
, aLength
);
591 //-----------------------------------------------------------------------------
592 void QWinMetaFile::pie(long, short *parm
)
594 int xCenter
, yCenter
, angleStart
, aLength
;
596 xCenter
= parm
[ 7 ] + ((parm
[ 5 ] - parm
[ 7 ]) / 2);
597 yCenter
= parm
[ 6 ] + ((parm
[ 4 ] - parm
[ 6 ]) / 2);
599 xyToAngle(parm
[ 3 ] - xCenter
, yCenter
- parm
[ 2 ], parm
[ 1 ] - xCenter
, yCenter
- parm
[ 0 ], angleStart
, aLength
);
601 mPainter
.drawPie(parm
[ 7 ], parm
[ 6 ], parm
[ 5 ] - parm
[ 7 ], parm
[ 4 ] - parm
[ 6 ], angleStart
, aLength
);
604 //-----------------------------------------------------------------------------
605 void QWinMetaFile::setPolyFillMode(long, short *parm
)
607 mWinding
= parm
[ 0 ];
610 //-----------------------------------------------------------------------------
611 void QWinMetaFile::setBkColor(long, short *parm
)
613 mPainter
.setBackground(QBrush(color(parm
)));
616 //-----------------------------------------------------------------------------
617 void QWinMetaFile::setBkMode(long, short *parm
)
619 if (parm
[ 0 ] == 1) {
620 mPainter
.setBackgroundMode(Qt::TransparentMode
);
622 mPainter
.setBackgroundMode(Qt::OpaqueMode
);
626 //-----------------------------------------------------------------------------
627 void QWinMetaFile::setPixel(long, short *parm
)
629 QPen pen
= mPainter
.pen();
630 mPainter
.setPen(color(parm
));
631 mPainter
.drawPoint(parm
[ 3 ], parm
[ 2 ]);
632 mPainter
.setPen(pen
);
635 //-----------------------------------------------------------------------------
636 void QWinMetaFile::setRop(long, short *parm
)
638 mPainter
.setCompositionMode(winToQtComposition(parm
[ 0 ]));
641 //-----------------------------------------------------------------------------
642 void QWinMetaFile::saveDC(long, short *)
647 //-----------------------------------------------------------------------------
648 void QWinMetaFile::restoreDC(long, short *parm
)
650 for (int i
= 0; i
> parm
[ 0 ]; i
--) {
655 //-----------------------------------------------------------------------------
656 void QWinMetaFile::intersectClipRect(long, short *parm
)
658 /* TODO: better implementation : need QT 3.0.2
659 QRegion region = mPainter.clipRegion();
660 if ( region.isEmpty() )
663 QRegion
region(bbox());
665 QRegion
newRegion(parm
[ 3 ], parm
[ 2 ], parm
[ 1 ] - parm
[ 3 ], parm
[ 0 ] - parm
[ 2 ]);
666 region
= region
.intersect(newRegion
);
668 mPainter
.setClipRegion(region
);
671 //-----------------------------------------------------------------------------
672 void QWinMetaFile::excludeClipRect(long, short *parm
)
674 /* TODO: better implementation : need QT 3.0.2
675 QRegion region = mPainter.clipRegion();
676 if ( region.isEmpty() )
679 QRegion
region(bbox());
681 QRegion
newRegion(parm
[ 3 ], parm
[ 2 ], parm
[ 1 ] - parm
[ 3 ], parm
[ 0 ] - parm
[ 2 ]);
682 region
= region
.subtract(newRegion
);
684 mPainter
.setClipRegion(region
);
687 //-----------------------------------------------------------------------------
689 //-----------------------------------------------------------------------------
690 void QWinMetaFile::setTextColor(long, short *parm
)
692 mTextColor
= color(parm
);
695 //-----------------------------------------------------------------------------
696 void QWinMetaFile::setTextAlign(long, short *parm
)
698 mTextAlign
= parm
[ 0 ];
701 //-----------------------------------------------------------------------------
702 void QWinMetaFile::textOut(long num
, short *parm
)
705 short *copyParm
= new short[ num
+ 1 ];
707 // re-order parameters
708 int idxOffset
= (parm
[ 0 ] / 2) + 1 + (parm
[ 0 ] & 1);
709 copyParm
[ 0 ] = parm
[ idxOffset
];
710 copyParm
[ 1 ] = parm
[ idxOffset
+ 1 ];
711 copyParm
[ 2 ] = parm
[ 0 ];
713 memcpy(©Parm
[ 4 ], &parm
[ 1 ], parm
[ 0 ]);
715 extTextOut(num
+ 1, copyParm
);
719 //-----------------------------------------------------------------------------
720 void QWinMetaFile::extTextOut(long num
, short *parm
)
723 int x
, y
, width
, height
;
726 if (parm
[ 3 ] != 0) { // ETO_CLIPPED flag add 4 parameters
727 ptStr
= (char *) & parm
[ 8 ];
729 ptStr
= (char *) & parm
[ 4 ];
732 QByteArray
text(ptStr
, parm
[ 2 ] + 1);
734 QFontMetrics
fm(mPainter
.font());
735 width
= fm
.width(QLatin1String(text
)) + fm
.descent(); // because fm.width(text) isn't rigth with Italic text
736 height
= fm
.height();
740 if (mTextAlign
& 0x01) { // (left, top) position = current logical position
743 } else { // (left, top) position = parameters
749 mPainter
.translate(parm
[ 1 ], parm
[ 0 ]);
750 mPainter
.rotate(mRotation
);
751 mPainter
.translate(-parm
[ 1 ], -parm
[ 0 ]);
755 if (mTextAlign
& 0x06) {
758 if (mTextAlign
& 0x08) {
759 y
-= (height
- fm
.descent());
762 mPainter
.setPen(mTextColor
);
763 idxOffset
= (parm
[ 2 ] / 2) + 4 + (parm
[ 2 ] & 1);
764 if ((parm
[ 2 ] > 1) && (num
>= (idxOffset
+ parm
[ 2 ])) && (parm
[ 3 ] == 0)) {
765 // offset for each char
767 mPainter
.drawText(left
, y
, width
, height
, Qt::AlignLeft
| Qt::AlignTop
, QLatin1String(text
.mid(0, 1)));
768 for (int i
= 1; i
< parm
[ 2 ]; ++i
) {
769 left
+= parm
[ idxOffset
+ i
- 1 ];
770 mPainter
.drawText(left
, y
, width
, height
, Qt::AlignLeft
| Qt::AlignTop
, QLatin1String(text
.mid(i
, 1)));
773 mPainter
.drawText(x
, y
, width
, height
, Qt::AlignLeft
| Qt::AlignTop
, QLatin1String(text
));
780 //-----------------------------------------------------------------------------
782 //-----------------------------------------------------------------------------
783 void QWinMetaFile::dibBitBlt(long num
, short *parm
)
785 if (num
> 9) { // DIB image
788 if (dibToBmp(bmpSrc
, (char *)&parm
[ 8 ], (num
- 8) * 2)) {
789 long raster
= toDWord(parm
);
791 mPainter
.setCompositionMode(winToQtComposition(raster
));
793 // wmf file allow negative width or height
795 if (parm
[ 5 ] < 0) { // width < 0 => horizontal flip
796 QMatrix
m(-1.0F
, 0.0F
, 0.0F
, 1.0F
, 0.0F
, 0.0F
);
797 mPainter
.setMatrix(m
, true);
799 if (parm
[ 4 ] < 0) { // height < 0 => vertical flip
800 QMatrix
m(1.0F
, 0.0F
, 0.0F
, -1.0F
, 0.0F
, 0.0F
);
801 mPainter
.setMatrix(m
, true);
803 mPainter
.drawImage(parm
[ 7 ], parm
[ 6 ], bmpSrc
, parm
[ 3 ], parm
[ 2 ], parm
[ 5 ], parm
[ 4 ]);
807 qCDebug(KTNEFAPPS_LOG
) << "QWinMetaFile::dibBitBlt without image: not implemented";
811 //-----------------------------------------------------------------------------
812 void QWinMetaFile::dibStretchBlt(long num
, short *parm
)
816 if (dibToBmp(bmpSrc
, (char *)&parm
[ 10 ], (num
- 10) * 2)) {
817 long raster
= toDWord(parm
);
819 mPainter
.setCompositionMode(winToQtComposition(raster
));
821 // wmf file allow negative width or height
823 if (parm
[ 7 ] < 0) { // width < 0 => horizontal flip
824 QMatrix
m(-1.0F
, 0.0F
, 0.0F
, 1.0F
, 0.0F
, 0.0F
);
825 mPainter
.setMatrix(m
, true);
827 if (parm
[ 6 ] < 0) { // height < 0 => vertical flip
828 QMatrix
m(1.0F
, 0.0F
, 0.0F
, -1.0F
, 0.0F
, 0.0F
);
829 mPainter
.setMatrix(m
, true);
831 bmpSrc
= bmpSrc
.copy(parm
[ 5 ], parm
[ 4 ], parm
[ 3 ], parm
[ 2 ]);
832 // TODO: scale the bitmap ( QImage::scale(parm[ 7 ], parm[ 6 ]) is actually too slow )
834 mPainter
.drawImage(parm
[ 9 ], parm
[ 8 ], bmpSrc
);
839 //-----------------------------------------------------------------------------
840 void QWinMetaFile::stretchDib(long num
, short *parm
)
844 if (dibToBmp(bmpSrc
, (char *)&parm
[ 11 ], (num
- 11) * 2)) {
845 long raster
= toDWord(parm
);
847 mPainter
.setCompositionMode(winToQtComposition(raster
));
849 // wmf file allow negative width or height
851 if (parm
[ 8 ] < 0) { // width < 0 => horizontal flip
852 QMatrix
m(-1.0F
, 0.0F
, 0.0F
, 1.0F
, 0.0F
, 0.0F
);
853 mPainter
.setMatrix(m
, true);
855 if (parm
[ 7 ] < 0) { // height < 0 => vertical flip
856 QMatrix
m(1.0F
, 0.0F
, 0.0F
, -1.0F
, 0.0F
, 0.0F
);
857 mPainter
.setMatrix(m
, true);
859 bmpSrc
= bmpSrc
.copy(parm
[ 6 ], parm
[ 5 ], parm
[ 4 ], parm
[ 3 ]);
860 // TODO: scale the bitmap ( QImage::scale(parm[ 8 ], parm[ 7 ]) is actually too slow )
862 mPainter
.drawImage(parm
[ 10 ], parm
[ 9 ], bmpSrc
);
867 //-----------------------------------------------------------------------------
868 void QWinMetaFile::dibCreatePatternBrush(long num
, short *parm
)
870 WinObjPatternBrushHandle
*handle
= new WinObjPatternBrushHandle
;
874 if (dibToBmp(bmpSrc
, (char *)&parm
[ 2 ], (num
- 2) * 2)) {
875 handle
->image
= bmpSrc
;
876 handle
->brush
.setTextureImage(handle
->image
);
880 //-----------------------------------------------------------------------------
882 //-----------------------------------------------------------------------------
883 void QWinMetaFile::selectObject(long, short *parm
)
886 if (idx
>= 0 && idx
< MAX_OBJHANDLE
&& mObjHandleTab
[ idx
]) {
887 mObjHandleTab
[ idx
]->apply(mPainter
);
891 //-----------------------------------------------------------------------------
892 void QWinMetaFile::deleteObject(long, short *parm
)
894 deleteHandle(parm
[ 0 ]);
897 //-----------------------------------------------------------------------------
898 void QWinMetaFile::createEmptyObject(long, short *)
900 // allocation of an empty object (to keep object counting in sync)
901 WinObjPenHandle
*handle
= new WinObjPenHandle
;
903 qCDebug(KTNEFAPPS_LOG
) << "QWinMetaFile: unimplemented createObject";
906 //-----------------------------------------------------------------------------
907 void QWinMetaFile::createBrushIndirect(long, short *parm
)
909 static Qt::BrushStyle hatchedStyleTab
[] = {
916 static Qt::BrushStyle styleTab
[] = { Qt::SolidPattern
,
918 Qt::FDiagPattern
, /* hatched */
919 Qt::Dense4Pattern
, /* should be custom bitmap pattern */
920 Qt::HorPattern
, /* should be BS_INDEXED (?) */
921 Qt::VerPattern
, /* should be device-independent bitmap */
922 Qt::Dense6Pattern
, /* should be device-independent packed-bitmap */
923 Qt::Dense2Pattern
, /* should be BS_PATTERN8x8 */
924 Qt::Dense3Pattern
/* should be device-independent BS_DIBPATTERN8x8 */
926 Qt::BrushStyle style
;
928 WinObjBrushHandle
*handle
= new WinObjBrushHandle
;
934 if (arg
>= 0 && arg
< 5) {
935 style
= hatchedStyleTab
[ arg
];
937 qCDebug(KTNEFAPPS_LOG
) << "QWinMetaFile::createBrushIndirect: invalid hatched brush" << arg
;
938 style
= Qt::SolidPattern
;
940 } else if (arg
>= 0 && arg
< 9) {
941 style
= styleTab
[ arg
];
943 qCDebug(KTNEFAPPS_LOG
) << "QWinMetaFile::createBrushIndirect: invalid brush" << arg
;
944 style
= Qt::SolidPattern
;
946 handle
->brush
.setStyle(style
);
947 handle
->brush
.setColor(color(parm
+ 1));
950 //-----------------------------------------------------------------------------
951 void QWinMetaFile::createPenIndirect(long, short *parm
)
953 static Qt::PenStyle styleTab
[] = { Qt::SolidLine
, Qt::DashLine
, Qt::DotLine
, Qt::DashDotLine
, Qt::DashDotDotLine
,
954 Qt::NoPen
, Qt::SolidLine
957 WinObjPenHandle
*handle
= new WinObjPenHandle
;
960 if (parm
[ 0 ] >= 0 && parm
[ 0 ] < 6) {
961 style
= styleTab
[ parm
[ 0 ] ];
963 qCDebug(KTNEFAPPS_LOG
) << "QWinMetaFile::createPenIndirect: invalid pen" << parm
[ 0 ];
964 style
= Qt::SolidLine
;
967 handle
->pen
.setStyle(style
);
968 handle
->pen
.setColor(color(parm
+ 3));
969 handle
->pen
.setCapStyle(Qt::RoundCap
);
972 // TODO : width of pen proportional to device context width
976 devRec = mPainter.transformed( mBBox );
977 width = ( parm[ 0 ] * devRec.width() ) / mBBox.width() ;
978 qCDebug(KTNEFAPPS_LOG) <<"CreatePenIndirect:";
979 qCDebug(KTNEFAPPS_LOG) <<" log coord. :" << mBBox.width() <<"" << mBBox.height();
980 qCDebug(KTNEFAPPS_LOG) <<" log. pen :" << parm[ 1 ] <<"" << parm[ 2 ];
981 qCDebug(KTNEFAPPS_LOG) <<" dev. pen :" << width;
982 handle->pen.setWidth( width );
986 //-----------------------------------------------------------------------------
987 void QWinMetaFile::createFontIndirect(long, short *parm
)
989 WinObjFontHandle
*handle
= new WinObjFontHandle
;
992 QString
family(QLatin1String((const char *)&parm
[ 9 ]));
994 mRotation
= -parm
[ 2 ] / 10; // text rotation (in 1/10 degree)
995 // TODO: memorisation of rotation in object Font
996 handle
->font
.setFamily(family
);
997 handle
->font
.setFixedPitch(((parm
[ 8 ] & 0x01) == 0));
998 // TODO: investigation why some test case need -2. (size of font in logical point)
999 handle
->font
.setPointSize(qAbs(parm
[ 0 ]) - 2);
1000 handle
->font
.setWeight((parm
[ 4 ] >> 3));
1001 handle
->font
.setItalic((parm
[ 5 ] & 0x01));
1002 handle
->font
.setUnderline((parm
[ 5 ] & 0x100));
1005 //-----------------------------------------------------------------------------
1007 //-----------------------------------------------------------------------------
1008 void QWinMetaFile::noop(long, short *)
1012 void QWinMetaFile::end(long, short *)
1015 // qCDebug(KTNEFAPPS_LOG) <<"END bbox=(" << mBBox.left() <<";" << mBBox.top() <<";" << mBBox.width() <<";" << mBBox.height() <<")";
1018 //-----------------------------------------------------------------------------
1019 unsigned short QWinMetaFile::calcCheckSum(WmfPlaceableHeader
*apmfh
)
1024 // Start with the first word
1025 wResult
= *(lpWord
= (WORD
*)(apmfh
));
1026 // XOR in each of the other 9 words
1027 for (i
= 1; i
<= 9; ++i
) {
1028 wResult
^= lpWord
[ i
];
1033 //-----------------------------------------------------------------------------
1034 int QWinMetaFile::findFunc(unsigned short aFunc
) const
1038 for (i
= 0; metaFuncTab
[ i
].name
; ++i
)
1039 if (metaFuncTab
[ i
].func
== aFunc
) {
1043 // here : unknown function
1047 //-----------------------------------------------------------------------------
1048 QPolygon
*QWinMetaFile::pointArray(short num
, short *parm
)
1052 mPoints
.resize(num
);
1054 for (i
= 0; i
< num
; ++i
, parm
+= 2) {
1055 mPoints
.setPoint(i
, parm
[ 0 ], parm
[ 1 ]);
1061 //-----------------------------------------------------------------------------
1062 unsigned int QWinMetaFile::toDWord(short *parm
)
1066 #if !defined( WORDS_BIGENDIAN )
1067 l
= *(unsigned int *)(parm
);
1071 bytes
= (char *)parm
;
1072 swap
[ 0 ] = bytes
[ 2 ];
1073 swap
[ 1 ] = bytes
[ 3 ];
1074 swap
[ 2 ] = bytes
[ 0 ];
1075 swap
[ 3 ] = bytes
[ 1 ];
1076 l
= *(unsigned int *)(swap
);
1082 //-----------------------------------------------------------------------------
1083 QColor
QWinMetaFile::color(short *parm
)
1085 unsigned int colorRef
;
1086 int red
, green
, blue
;
1088 colorRef
= toDWord(parm
) & 0xffffff;
1089 red
= colorRef
& 255;
1090 green
= (colorRef
>> 8) & 255;
1091 blue
= (colorRef
>> 16) & 255;
1093 return QColor(red
, green
, blue
);
1096 //-----------------------------------------------------------------------------
1097 void QWinMetaFile::xyToAngle(int xStart
, int yStart
, int xEnd
, int yEnd
, int &angleStart
, int &angleLength
)
1099 float aStart
, aLength
;
1101 aStart
= atan2((double)yStart
, (double)xStart
);
1102 aLength
= atan2((double)yEnd
, (double)xEnd
) - aStart
;
1104 angleStart
= (int)(aStart
* 2880 / 3.14166);
1105 angleLength
= (int)(aLength
* 2880 / 3.14166);
1106 if (angleLength
< 0) {
1107 angleLength
= 5760 + angleLength
;
1111 //-----------------------------------------------------------------------------
1112 void QWinMetaFile::addHandle(WinObjHandle
*handle
)
1116 for (idx
= 0; idx
< MAX_OBJHANDLE
; idx
++)
1117 if (mObjHandleTab
[ idx
] == NULL
) {
1121 if (idx
< MAX_OBJHANDLE
) {
1122 mObjHandleTab
[ idx
] = handle
;
1124 qCDebug(KTNEFAPPS_LOG
) << "QWinMetaFile error: handle table full !";
1128 //-----------------------------------------------------------------------------
1129 void QWinMetaFile::deleteHandle(int idx
)
1131 if (idx
>= 0 && idx
< MAX_OBJHANDLE
&& mObjHandleTab
[ idx
]) {
1132 delete mObjHandleTab
[ idx
];
1133 mObjHandleTab
[ idx
] = NULL
;
1137 //-----------------------------------------------------------------------------
1138 QPainter::CompositionMode
QWinMetaFile::winToQtComposition(short parm
) const
1140 static const QPainter::CompositionMode opTab
[] = {
1141 // ### untested (conversion from Qt::RasterOp)
1142 QPainter::CompositionMode_Source
, // Qt::CopyROP
1143 QPainter::CompositionMode_Clear
, // Qt::ClearROP
1144 QPainter::CompositionMode_SourceOut
, // Qt::NandROP
1145 QPainter::CompositionMode_SourceOut
, // Qt::NotAndROP
1146 QPainter::CompositionMode_DestinationOut
, // Qt::NotCopyROP
1147 QPainter::CompositionMode_DestinationOut
, // Qt::AndNotROP
1148 QPainter::CompositionMode_DestinationOut
, // Qt::NotROP
1149 QPainter::CompositionMode_Xor
, // Qt::XorROP
1150 QPainter::CompositionMode_Source
, // Qt::NorROP
1151 QPainter::CompositionMode_SourceIn
, // Qt::AndROP
1152 QPainter::CompositionMode_SourceIn
, // Qt::NotXorROP
1153 QPainter::CompositionMode_Destination
, // Qt::NopROP
1154 QPainter::CompositionMode_Destination
, // Qt::NotOrROP
1155 QPainter::CompositionMode_Source
, // Qt::CopyROP
1156 QPainter::CompositionMode_Source
, // Qt::OrNotROP
1157 QPainter::CompositionMode_SourceOver
, // Qt::OrROP
1158 QPainter::CompositionMode_Source
// Qt::SetROP
1161 if (parm
> 0 && parm
<= 16) {
1162 return opTab
[ parm
];
1164 return QPainter::CompositionMode_Source
;
1168 //-----------------------------------------------------------------------------
1169 QPainter::CompositionMode
QWinMetaFile::winToQtComposition(long parm
) const
1171 /* TODO: Ternary raster operations
1172 0x00C000CA dest = (source AND pattern)
1173 0x00F00021 dest = pattern
1174 0x00FB0A09 dest = DPSnoo
1175 0x005A0049 dest = pattern XOR dest */
1176 static const struct OpTab
{
1178 QPainter::CompositionMode qtRasterOp
;
1180 // ### untested (conversion from Qt::RasterOp)
1181 { 0x00CC0020, QPainter::CompositionMode_Source
}, // CopyROP
1182 { 0x00EE0086, QPainter::CompositionMode_SourceOver
}, // OrROP
1183 { 0x008800C6, QPainter::CompositionMode_SourceIn
}, // AndROP
1184 { 0x00660046, QPainter::CompositionMode_Xor
}, // XorROP
1185 { 0x00440328, QPainter::CompositionMode_DestinationOut
}, // AndNotROP
1186 { 0x00330008, QPainter::CompositionMode_DestinationOut
}, // NotCopyROP
1187 { 0x001100A6, QPainter::CompositionMode_SourceOut
}, // NandROP
1188 { 0x00C000CA, QPainter::CompositionMode_Source
}, // CopyROP
1189 { 0x00BB0226, QPainter::CompositionMode_Destination
}, // NotOrROP
1190 { 0x00F00021, QPainter::CompositionMode_Source
}, // CopyROP
1191 { 0x00FB0A09, QPainter::CompositionMode_Source
}, // CopyROP
1192 { 0x005A0049, QPainter::CompositionMode_Source
}, // CopyROP
1193 { 0x00550009, QPainter::CompositionMode_DestinationOut
}, // NotROP
1194 { 0x00000042, QPainter::CompositionMode_Clear
}, // ClearROP
1195 { 0x00FF0062, QPainter::CompositionMode_Source
} // SetROP
1199 for (i
= 0; i
< 15; ++i
)
1200 if (opTab
[ i
].winRasterOp
== parm
) {
1205 return opTab
[ i
].qtRasterOp
;
1207 return QPainter::CompositionMode_Source
;
1211 //-----------------------------------------------------------------------------
1212 bool QWinMetaFile::dibToBmp(QImage
&bmp
, const char *dib
, long size
)
1214 typedef struct _BMPFILEHEADER
{
1222 int sizeBmp
= size
+ 14;
1223 QByteArray pattern
; // BMP header and DIB data
1224 pattern
.fill(0, sizeBmp
); //resize and fill
1225 pattern
.insert(14, QByteArray::fromRawData(dib
, size
));
1228 BMPFILEHEADER
*bmpHeader
;
1229 bmpHeader
= (BMPFILEHEADER
*)((const char *)pattern
);
1230 bmpHeader
->bmType
= 0x4D42;
1231 bmpHeader
->bmSize
= sizeBmp
;
1233 if (!bmp
.loadFromData((const uchar
*)bmpHeader
, pattern
.size(), "BMP")) {
1234 qCDebug(KTNEFAPPS_LOG
) << "QWinMetaFile::dibToBmp: invalid bitmap";
1237 // if ( bmp.save("/home/software/kde-cvs/qt/examples/wmf/test.bmp", "BMP") )
1238 // if ( bmp.load( "/home/software/kde-cvs/qt/examples/wmf/test.bmp", "BMP" ) )
1239 // fprintf(stderr, "Bitmap ok \n");