SVN_SILENT made messages (.desktop file)
[kdepim.git] / ktnef / qwmf.cpp
blobdf34738979644c803dec0ecc2a64984becbc2abc
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
22 #include <math.h>
23 #include <assert.h>
25 #include <QImage>
26 #include <QPainter>
27 #include <QPainterPath>
28 #include <QDataStream>
29 #include <QBuffer>
30 #include <QFile>
31 #include <QPolygon>
33 #include "ktnef_debug.h"
35 bool qwmfDebug = false;
37 #include "qwmf.h"
38 #include "wmfstruct.h"
39 #include "metafuncs.h"
41 #define QWMF_DEBUG 0
43 class WmfCmd
45 public:
46 ~WmfCmd()
48 delete next;
50 WmfCmd *next;
51 unsigned short funcIndex;
52 long numParm;
53 short *parm;
56 class WinObjHandle
58 public:
59 virtual ~WinObjHandle() {}
60 virtual void apply(QPainter &p) = 0;
63 class WinObjBrushHandle: public WinObjHandle
65 public:
66 void apply(QPainter &p) Q_DECL_OVERRIDE;
67 QBrush brush;
68 virtual ~WinObjBrushHandle() {}
71 class WinObjPenHandle: public WinObjHandle
73 public:
74 void apply(QPainter &p) Q_DECL_OVERRIDE;
75 QPen pen;
76 virtual ~WinObjPenHandle() {}
79 class WinObjPatternBrushHandle: public WinObjHandle
81 public:
82 void apply(QPainter &p) Q_DECL_OVERRIDE;
83 QBrush brush;
84 QImage image;
85 virtual ~WinObjPatternBrushHandle() {}
88 class WinObjFontHandle: public WinObjHandle
90 public:
91 void apply(QPainter &p) Q_DECL_OVERRIDE;
92 QFont font;
93 int rotation;
94 virtual ~WinObjFontHandle() {}
97 void WinObjBrushHandle::apply(QPainter &p)
99 p.setBrush(brush);
102 void WinObjPenHandle::apply(QPainter &p)
104 p.setPen(pen);
107 void WinObjPatternBrushHandle::apply(QPainter &p)
109 p.setBrush(brush);
112 void WinObjFontHandle::apply(QPainter &p)
114 p.setFont(font);
117 #define MAX_OBJHANDLE 64
119 //-----------------------------------------------------------------------------
120 QWinMetaFile::QWinMetaFile()
122 mValid = false;
123 mFirstCmd = NULL;
124 mObjHandleTab = NULL;
125 mDpi = 1000;
128 //-----------------------------------------------------------------------------
129 QWinMetaFile::~QWinMetaFile()
131 delete mFirstCmd;
132 if (mObjHandleTab) {
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";
144 return false;
147 if (!file.open(QIODevice::ReadOnly)) {
148 qCDebug(KTNEFAPPS_LOG) << "Cannot open file" << QFile::encodeName(filename);
149 return false;
152 QByteArray ba = file.readAll();
153 file.close();
155 QBuffer buffer(&ba);
156 buffer.open(QIODevice::ReadOnly);
157 return load(buffer);
160 //-----------------------------------------------------------------------------
161 bool QWinMetaFile::load(QBuffer &buffer)
163 QDataStream st;
164 WmfEnhMetaHeader eheader;
165 WmfMetaHeader header;
166 WmfPlaceableHeader pheader;
167 WORD checksum;
168 int filePos, idx, i;
169 WmfCmd *cmd, *last;
170 DWORD rdSize;
171 WORD rdFunc;
173 mTextAlign = 0;
174 mRotation = 0;
175 mTextColor = Qt::black;
176 if (mFirstCmd) {
177 delete mFirstCmd;
179 mFirstCmd = NULL;
181 st.setDevice(&buffer);
182 st.setByteOrder(QDataStream::LittleEndian); // Great, I love Qt !
184 //----- Read placeable metafile header
185 st >> pheader.key;
186 mIsPlaceable = (pheader.key == (DWORD)APMHEADER_KEY);
187 if (mIsPlaceable) {
188 st >> pheader.hmf;
189 st >> pheader.bbox.left;
190 st >> pheader.bbox.top;
191 st >> pheader.bbox.right;
192 st >> pheader.bbox.bottom;
193 st >> pheader.inch;
194 st >> pheader.reserved;
195 st >> pheader.checksum;
196 checksum = calcCheckSum(&pheader);
197 if (pheader.checksum != checksum) {
198 mIsPlaceable = false;
201 mDpi = pheader.inch;
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;
207 if (QWMF_DEBUG) {
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") << " )";
216 } else {
217 buffer.reset();
220 //----- Read as enhanced metafile header
221 filePos = buffer.pos();
222 st >> eheader.iType;
223 st >> eheader.nSize;
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;
248 if (QWMF_DEBUG) {
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);
263 st >> header.mtType;
264 st >> header.mtHeaderSize;
265 st >> header.mtVersion;
266 st >> header.mtSize;
267 st >> header.mtNoObjects;
268 st >> header.mtMaxRecord;
269 st >> header.mtNoParameters;
270 if (QWMF_DEBUG) {
271 qCDebug(KTNEFAPPS_LOG) << "WMF Header:" << "mtSize=" << header.mtSize;
275 //----- Test header validity
276 mValid = ((header.mtHeaderSize == 9) && (header.mtNoParameters == 0)) || mIsEnhanced || mIsPlaceable;
277 if (mValid) {
278 //----- Read Metafile Records
279 last = NULL;
280 rdFunc = -1;
281 while (!st.atEnd() && (rdFunc != 0)) {
282 st >> rdSize;
283 st >> rdFunc;
284 idx = findFunc(rdFunc);
285 rdSize -= 3;
287 cmd = new WmfCmd;
288 cmd->next = NULL;
289 if (last) {
290 last->next = cmd;
291 } else {
292 mFirstCmd = cmd;
295 cmd->funcIndex = idx;
296 cmd->numParm = rdSize;
297 cmd->parm = new WORD[ rdSize ];
298 last = cmd;
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 ]);
313 if (i < rdSize) {
314 qCDebug(KTNEFAPPS_LOG) << "WMF : file truncated !";
315 return false;
318 //----- Test records validities
319 mValid = (rdFunc == 0) && (mBBox.width() != 0) && (mBBox.height() != 0);
320 if (!mValid) {
321 qCDebug(KTNEFAPPS_LOG) << "WMF : incorrect file format !";
323 } else {
324 qCDebug(KTNEFAPPS_LOG) << "WMF Header : incorrect header !";
327 buffer.close();
328 return mValid;
331 //-----------------------------------------------------------------------------
332 bool QWinMetaFile::paint(QPaintDevice *aTarget, bool absolute)
334 int idx, i;
335 WmfCmd *cmd;
337 if (!mValid) {
338 return false;
341 assert(aTarget != NULL);
342 if (mPainter.isActive()) {
343 return false;
346 if (mObjHandleTab) {
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();
355 mWinding = false;
356 mAbsoluteCoord = absolute;
358 mPainter.begin(aTarget);
359 if (QWMF_DEBUG) {
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);
373 if (QWMF_DEBUG) {
374 QString str, param;
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 ]);
386 str += param;
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()
395 mWindowsCoord += 1;
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() );
403 mPainter.end();
404 return true;
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());
415 } else {
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 ]);
433 } else {
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 //-----------------------------------------------------------------------------
458 // Drawing
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 ]);
483 if (mWinding) {
484 mPainter.drawPolygon(*pa, Qt::WindingFill);
485 } else {
486 mPainter.drawPolygon(*pa, Qt::OddEvenFill);
489 delete pa;
492 //-----------------------------------------------------------------------------
493 void QWinMetaFile::polyPolygon(long, short *parm)
495 QRegion region;
496 int i, j, startPolygon;
498 mPainter.save();
500 // define clipping region
501 QRect win = bbox();
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 ]);
507 startPolygon += 2;
509 QRegion r(pa1);
510 region = region.eor(r);
512 mPainter.setClipRegion(region);
514 // fill polygons
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);
522 QPolygon *pa;
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;
531 mPainter.restore();
534 //-----------------------------------------------------------------------------
535 void QWinMetaFile::polyline(long, short *parm)
537 QPolygon *pa;
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);
621 } else {
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 *)
644 mPainter.save();
647 //-----------------------------------------------------------------------------
648 void QWinMetaFile::restoreDC(long, short *parm)
650 for (int i = 0; i > parm[ 0 ]; i--) {
651 mPainter.restore();
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() )
661 region = bbox();
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() )
677 region = bbox();
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 //-----------------------------------------------------------------------------
688 // Text
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 ];
712 copyParm[ 3 ] = 0;
713 memcpy(&copyParm[ 4 ], &parm[ 1 ], parm[ 0 ]);
715 extTextOut(num + 1, copyParm);
716 delete [] copyParm;
719 //-----------------------------------------------------------------------------
720 void QWinMetaFile::extTextOut(long num, short *parm)
722 char *ptStr;
723 int x, y, width, height;
724 int idxOffset;
726 if (parm[ 3 ] != 0) { // ETO_CLIPPED flag add 4 parameters
727 ptStr = (char *) & parm[ 8 ];
728 } else {
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();
738 mPainter.save();
740 if (mTextAlign & 0x01) { // (left, top) position = current logical position
741 x = mLastPos.x();
742 y = mLastPos.y();
743 } else { // (left, top) position = parameters
744 x = parm[ 1 ];
745 y = parm[ 0 ];
748 if (mRotation) {
749 mPainter.translate(parm[ 1 ], parm[ 0 ]);
750 mPainter.rotate(mRotation);
751 mPainter.translate(-parm[ 1 ], -parm[ 0 ]);
754 // alignment
755 if (mTextAlign & 0x06) {
756 x -= (width / 2);
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
766 int left = x;
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)));
772 } else {
773 mPainter.drawText(x, y, width, height, Qt::AlignLeft | Qt::AlignTop, QLatin1String(text));
776 mPainter.restore();
780 //-----------------------------------------------------------------------------
781 // Bitmap
782 //-----------------------------------------------------------------------------
783 void QWinMetaFile::dibBitBlt(long num, short *parm)
785 if (num > 9) { // DIB image
786 QImage bmpSrc;
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
794 mPainter.save();
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 ]);
804 mPainter.restore();
806 } else {
807 qCDebug(KTNEFAPPS_LOG) << "QWinMetaFile::dibBitBlt without image: not implemented";
811 //-----------------------------------------------------------------------------
812 void QWinMetaFile::dibStretchBlt(long num, short *parm)
814 QImage bmpSrc;
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
822 mPainter.save();
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);
835 mPainter.restore();
839 //-----------------------------------------------------------------------------
840 void QWinMetaFile::stretchDib(long num, short *parm)
842 QImage bmpSrc;
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
850 mPainter.save();
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);
863 mPainter.restore();
867 //-----------------------------------------------------------------------------
868 void QWinMetaFile::dibCreatePatternBrush(long num, short *parm)
870 WinObjPatternBrushHandle *handle = new WinObjPatternBrushHandle;
871 addHandle(handle);
872 QImage bmpSrc;
874 if (dibToBmp(bmpSrc, (char *)&parm[ 2 ], (num - 2) * 2)) {
875 handle->image = bmpSrc;
876 handle->brush.setTextureImage(handle->image);
880 //-----------------------------------------------------------------------------
881 // Object handle
882 //-----------------------------------------------------------------------------
883 void QWinMetaFile::selectObject(long, short *parm)
885 int idx = parm[ 0 ];
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;
902 addHandle(handle);
903 qCDebug(KTNEFAPPS_LOG) << "QWinMetaFile: unimplemented createObject";
906 //-----------------------------------------------------------------------------
907 void QWinMetaFile::createBrushIndirect(long, short *parm)
909 static Qt::BrushStyle hatchedStyleTab[] = {
910 Qt::HorPattern,
911 Qt::FDiagPattern,
912 Qt::BDiagPattern,
913 Qt::CrossPattern,
914 Qt::DiagCrossPattern
916 static Qt::BrushStyle styleTab[] = { Qt::SolidPattern,
917 Qt::NoBrush,
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;
927 short arg;
928 WinObjBrushHandle *handle = new WinObjBrushHandle;
929 addHandle(handle);
931 arg = parm[ 0 ];
932 if (arg == 2) {
933 arg = parm[ 3 ];
934 if (arg >= 0 && arg < 5) {
935 style = hatchedStyleTab[ arg ];
936 } else {
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 ];
942 } else {
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
956 Qt::PenStyle style;
957 WinObjPenHandle *handle = new WinObjPenHandle;
958 addHandle(handle);
960 if (parm[ 0 ] >= 0 && parm[ 0 ] < 6) {
961 style = styleTab[ parm[ 0 ] ];
962 } else {
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);
971 //int width = 0;
972 // TODO : width of pen proportional to device context width
973 // DOESN'T WORK
975 QRect devRec;
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;
990 addHandle(handle);
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 //-----------------------------------------------------------------------------
1006 // Misc
1007 //-----------------------------------------------------------------------------
1008 void QWinMetaFile::noop(long, short *)
1012 void QWinMetaFile::end(long, short *)
1014 // end of file :
1015 // qCDebug(KTNEFAPPS_LOG) <<"END bbox=(" << mBBox.left() <<";" << mBBox.top() <<";" << mBBox.width() <<";" << mBBox.height() <<")";
1018 //-----------------------------------------------------------------------------
1019 unsigned short QWinMetaFile::calcCheckSum(WmfPlaceableHeader *apmfh)
1021 WORD *lpWord;
1022 WORD wResult, i;
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 ];
1030 return wResult;
1033 //-----------------------------------------------------------------------------
1034 int QWinMetaFile::findFunc(unsigned short aFunc) const
1036 int i;
1038 for (i = 0; metaFuncTab[ i ].name; ++i)
1039 if (metaFuncTab[ i ].func == aFunc) {
1040 return i;
1043 // here : unknown function
1044 return i;
1047 //-----------------------------------------------------------------------------
1048 QPolygon *QWinMetaFile::pointArray(short num, short *parm)
1050 int i;
1052 mPoints.resize(num);
1054 for (i = 0; i < num; ++i, parm += 2) {
1055 mPoints.setPoint(i, parm[ 0 ], parm[ 1 ]);
1058 return &mPoints;
1061 //-----------------------------------------------------------------------------
1062 unsigned int QWinMetaFile::toDWord(short *parm)
1064 unsigned int l;
1066 #if !defined( WORDS_BIGENDIAN )
1067 l = *(unsigned int *)(parm);
1068 #else
1069 char *bytes;
1070 char swap[ 4 ];
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);
1077 #endif
1079 return l;
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)
1114 int idx;
1116 for (idx = 0; idx < MAX_OBJHANDLE; idx++)
1117 if (mObjHandleTab[ idx ] == NULL) {
1118 break;
1121 if (idx < MAX_OBJHANDLE) {
1122 mObjHandleTab[ idx ] = handle;
1123 } else {
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 ];
1163 } else {
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 {
1177 long winRasterOp;
1178 QPainter::CompositionMode qtRasterOp;
1179 } opTab[] = {
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
1198 int i;
1199 for (i = 0; i < 15; ++i)
1200 if (opTab[ i ].winRasterOp == parm) {
1201 break;
1204 if (i < 15) {
1205 return opTab[ i ].qtRasterOp;
1206 } else {
1207 return QPainter::CompositionMode_Source;
1211 //-----------------------------------------------------------------------------
1212 bool QWinMetaFile::dibToBmp(QImage &bmp, const char *dib, long size)
1214 typedef struct _BMPFILEHEADER {
1215 WORD bmType;
1216 DWORD bmSize;
1217 WORD bmReserved1;
1218 WORD bmReserved2;
1219 DWORD bmOffBits;
1220 } 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));
1227 // add BMP header
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";
1235 return false;
1236 } else {
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");
1240 return true;