summaryrefslogtreecommitdiffstats
path: root/lib/kwmf/kwmf.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kwmf/kwmf.cc')
-rw-r--r--lib/kwmf/kwmf.cc964
1 files changed, 964 insertions, 0 deletions
diff --git a/lib/kwmf/kwmf.cc b/lib/kwmf/kwmf.cc
new file mode 100644
index 00000000..989b3e29
--- /dev/null
+++ b/lib/kwmf/kwmf.cc
@@ -0,0 +1,964 @@
+/*
+ Copyright (C) 2000, S.R.Haque <shaheedhaque@hotmail.com>.
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+
+DESCRIPTION
+
+ This is based on code originally written by Stefan Taferner
+ (taferner@kde.org) and also borrows from libwmf (by Martin Vermeer and
+ Caolan McNamara).
+*/
+
+#include <kdebug.h>
+#include <math.h>
+#include <qfile.h>
+#include <qpointarray.h>
+#include <kwmf.h>
+#include <qrect.h>
+
+#define PI (3.14159265358979323846)
+
+const int KWmf::s_area = 30504;
+const int KWmf::s_maxHandles = 64;
+
+KWmf::KWmf(
+ unsigned dpi)
+{
+ m_dpi = dpi;
+ m_objectHandles = new WinObjHandle*[s_maxHandles];
+}
+
+KWmf::~KWmf()
+{
+ delete[] m_objectHandles;
+}
+
+//
+//
+//
+
+void KWmf::brushSet(
+ unsigned colour,
+ unsigned style)
+{
+ m_dc.m_brushColour = colour;
+ m_dc.m_brushStyle = style;
+}
+
+//-----------------------------------------------------------------------------
+unsigned KWmf::getColour(
+ S32 colour)
+{
+ unsigned red, green, blue;
+
+ red = colour & 255;
+ green = (colour >> 8) & 255;
+ blue = (colour >> 16) & 255;
+ return (red << 16) + (green << 8) + blue;
+}
+
+void KWmf::genericArc(
+ QString type,
+ QDataStream &operands)
+{
+ QPoint topLeft;
+ QPoint bottomRight;
+ QPoint start;
+ QPoint end;
+
+ topLeft = normalisePoint(operands);
+ bottomRight = normalisePoint(operands);
+ start = normalisePoint(operands);
+ end = normalisePoint(operands);
+
+ // WMF defines arcs with the major and minor axes of an ellipse, and two points.
+ // From each point draw a line to the center of the ellipse: the intercepts define
+ // the ends of the arc.
+
+ QRect ellipse(topLeft, bottomRight);
+ QPoint centre = ellipse.center();
+ double startAngle = atan2((double)(centre.y() - start.y()), (double)(centre.x() - start.x()));
+ double stopAngle = atan2((double)(centre.y() - end.y()), (double)(centre.x() - end.x()));
+
+ startAngle = 180 * startAngle / PI;
+ stopAngle = 180 * stopAngle / PI;
+
+ gotEllipse(m_dc, type, centre, ellipse.size() / 2,
+ static_cast<unsigned int>(startAngle),
+ static_cast<unsigned int>(stopAngle));
+}
+
+int KWmf::handleIndex(void) const
+{
+ int i;
+
+ for (i = 0; i < s_maxHandles; i++)
+ {
+ if (!m_objectHandles[i])
+ return i;
+ }
+ kdError(s_area) << "handle table full !" << endl;
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+KWmf::WinObjPenHandle *KWmf::handleCreatePen(void)
+{
+ WinObjPenHandle *handle = new WinObjPenHandle;
+ int idx = handleIndex();
+
+ if (idx >= 0)
+ m_objectHandles[idx] = handle;
+ return handle;
+}
+
+//-----------------------------------------------------------------------------
+KWmf::WinObjBrushHandle *KWmf::handleCreateBrush(void)
+{
+ WinObjBrushHandle *handle = new WinObjBrushHandle;
+ int idx = handleIndex();
+
+ if (idx >= 0)
+ m_objectHandles[idx] = handle;
+ return handle;
+}
+
+//-----------------------------------------------------------------------------
+void KWmf::handleDelete(int idx)
+{
+ if (idx >= 0 && idx < s_maxHandles && m_objectHandles[idx])
+ {
+ delete m_objectHandles[idx];
+ m_objectHandles[idx] = NULL;
+ }
+}
+
+//
+//
+//
+
+void KWmf::invokeHandler(
+ S16 opcode,
+ U32 words,
+ QDataStream &operands)
+{
+ typedef void (KWmf::*method)(U32 words, QDataStream &operands);
+
+ typedef struct
+ {
+ const char *name;
+ unsigned short opcode;
+ method handler;
+ } opcodeEntry;
+
+ static const opcodeEntry funcTab[] =
+ {
+ { "ANIMATEPALETTE", 0x0436, 0 },
+ { "ARC", 0x0817, &KWmf::opArc },
+ { "BITBLT", 0x0922, 0 },
+ { "CHORD", 0x0830, 0 },
+ { "CREATEBRUSHINDIRECT", 0x02FC, &KWmf::opBrushCreateIndirect },
+ { "CREATEFONTINDIRECT", 0x02FB, 0 },
+ { "CREATEPALETTE", 0x00F7, 0 },
+ { "CREATEPATTERNBRUSH", 0x01F9, 0 },
+ { "CREATEPENINDIRECT", 0x02FA, &KWmf::opPenCreateIndirect },
+ { "CREATEREGION", 0x06FF, 0 },
+ { "DELETEOBJECT", 0x01F0, &KWmf::opObjectDelete },
+ { "DIBBITBLT", 0x0940, 0 },
+ { "DIBCREATEPATTERNBRUSH",0x0142, 0 },
+ { "DIBSTRETCHBLT", 0x0b41, 0 },
+ { "ELLIPSE", 0x0418, &KWmf::opEllipse },
+ { "ESCAPE", 0x0626, &KWmf::opNoop },
+ { "EXCLUDECLIPRECT", 0x0415, 0 },
+ { "EXTFLOODFILL", 0x0548, 0 },
+ { "EXTTEXTOUT", 0x0a32, 0 },
+ { "FILLREGION", 0x0228, 0 },
+ { "FLOODFILL", 0x0419, 0 },
+ { "FRAMEREGION", 0x0429, 0 },
+ { "INTERSECTCLIPRECT", 0x0416, 0 },
+ { "INVERTREGION", 0x012A, 0 },
+ { "LINETO", 0x0213, &KWmf::opLineTo },
+ { "MOVETO", 0x0214, &KWmf::opMoveTo },
+ { "OFFSETCLIPRGN", 0x0220, 0 },
+ { "OFFSETVIEWPORTORG", 0x0211, 0 },
+ { "OFFSETWINDOWORG", 0x020F, 0 },
+ { "PAINTREGION", 0x012B, 0 },
+ { "PATBLT", 0x061D, 0 },
+ { "PIE", 0x081A, &KWmf::opPie },
+ { "POLYGON", 0x0324, &KWmf::opPolygon },
+ { "POLYLINE", 0x0325, &KWmf::opPolyline },
+ { "POLYPOLYGON", 0x0538, 0 },
+ { "REALIZEPALETTE", 0x0035, 0 },
+ { "RECTANGLE", 0x041B, &KWmf::opRectangle },
+ { "RESIZEPALETTE", 0x0139, 0 },
+ { "RESTOREDC", 0x0127, &KWmf::opRestoreDc },
+ { "ROUNDRECT", 0x061C, 0 },
+ { "SAVEDC", 0x001E, &KWmf::opSaveDc },
+ { "SCALEVIEWPORTEXT", 0x0412, 0 },
+ { "SCALEWINDOWEXT", 0x0410, 0 },
+ { "SELECTCLIPREGION", 0x012C, 0 },
+ { "SELECTOBJECT", 0x012D, &KWmf::opObjectSelect },
+ { "SELECTPALETTE", 0x0234, 0 },
+ { "SETBKCOLOR", 0x0201, 0 },
+ { "SETBKMODE", 0x0102, 0 },
+ { "SETDIBTODEV", 0x0d33, 0 },
+ { "SETMAPMODE", 0x0103, 0 },
+ { "SETMAPPERFLAGS", 0x0231, 0 },
+ { "SETPALENTRIES", 0x0037, 0 },
+ { "SETPIXEL", 0x041F, 0 },
+ { "SETPOLYFILLMODE", 0x0106, &KWmf::opPolygonSetFillMode },
+ { "SETRELABS", 0x0105, 0 },
+ { "SETROP2", 0x0104, 0 },
+ { "SETSTRETCHBLTMODE", 0x0107, 0 },
+ { "SETTEXTALIGN", 0x012E, 0 },
+ { "SETTEXTCHAREXTRA", 0x0108, 0 },
+ { "SETTEXTCOLOR", 0x0209, 0 },
+ { "SETTEXTJUSTIFICATION", 0x020A, 0 },
+ { "SETVIEWPORTEXT", 0x020E, 0 },
+ { "SETVIEWPORTORG", 0x020D, 0 },
+ { "SETWINDOWEXT", 0x020C, &KWmf::opWindowSetExt },
+ { "SETWINDOWORG", 0x020B, &KWmf::opWindowSetOrg },
+ { "STRETCHBLT", 0x0B23, 0 },
+ { "STRETCHDIB", 0x0f43, 0 },
+ { "TEXTOUT", 0x0521, 0 },
+ { NULL, 0, 0 }
+ };
+ unsigned i;
+ method result;
+
+ // Scan lookup table for operation.
+
+ for (i = 0; funcTab[i].name; i++)
+ {
+ if (funcTab[i].opcode == opcode)
+ {
+ break;
+ }
+ }
+
+ // Invoke handler.
+
+ result = funcTab[i].handler;
+ if (!result)
+ {
+ if (funcTab[i].name)
+ kdError(s_area) << "invokeHandler: unsupported opcode: " <<
+ funcTab[i].name <<
+ " operands: " << words << endl;
+ else
+ kdError(s_area) << "invokeHandler: unsupported opcode: 0x" <<
+ QString::number(opcode, 16) <<
+ " operands: " << words << endl;
+
+ // Skip data we cannot use.
+
+ for (i = 0; i < words; i++)
+ {
+ S16 discard;
+
+ operands >> discard;
+ }
+ }
+ else
+ {
+ kdDebug(s_area) << "invokeHandler: opcode: " << funcTab[i].name <<
+ " operands: " << words << endl;
+
+ // We don't invoke the handler directly on the incoming operands, but
+ // via a temporary datastream. This adds overhead, but eliminates the
+ // need for the individual handlers to read *exactly* the right amount
+ // of data (thus speeding development, and possibly adding some
+ // future-proofing).
+
+ if (words)
+ {
+ QByteArray *record = new QByteArray(words * 2);
+ QDataStream *body;
+
+ operands.readRawBytes(record->data(), words * 2);
+ body = new QDataStream(*record, IO_ReadOnly);
+ body->setByteOrder(QDataStream::LittleEndian);
+ (this->*result)(words, *body);
+ delete body;
+ delete record;
+ }
+ else
+ {
+ QDataStream *body = new QDataStream();
+
+ (this->*result)(words, *body);
+ delete body;
+ }
+ }
+}
+
+QPoint KWmf::normalisePoint(
+ QDataStream &operands)
+{
+ S16 x;
+ S16 y;
+
+ operands >> x >> y;
+ return QPoint((x - m_windowOrgX) * m_windowFlipX / m_dpi, (y - m_windowOrgY) * m_windowFlipY / m_dpi);
+}
+
+QSize KWmf::normaliseSize(
+ QDataStream &operands)
+{
+ S16 width;
+ S16 height;
+
+ operands >> width >> height;
+ return QSize(width / m_dpi, height / m_dpi);
+}
+
+bool KWmf::parse(
+ const QString &file)
+{
+ QFile in(file);
+ if (!in.open(IO_ReadOnly))
+ {
+ kdError(s_area) << "Unable to open input file!" << endl;
+ in.close();
+ return false;
+ }
+ QDataStream stream(&in);
+ bool result = parse(stream, in.size());
+ in.close();
+ return result;
+}
+
+bool KWmf::parse(
+ QDataStream &stream,
+ unsigned size)
+{
+ int startedAt;
+ bool isPlaceable;
+ bool isEnhanced;
+
+ startedAt = stream.device()->at();
+ stream.setByteOrder(QDataStream::LittleEndian); // Great, I love Qt !
+
+ for (int i = 0; i < s_maxHandles; i++)
+ m_objectHandles[i] = NULL;
+
+ typedef struct _RECT
+ {
+ S16 left;
+ S16 top;
+ S16 right;
+ S16 bottom;
+ } RECT;
+
+ typedef struct _RECTL
+ {
+ S32 left;
+ S32 top;
+ S32 right;
+ S32 bottom;
+ } RECTL;
+
+ typedef struct _SIZE
+ {
+ S16 width;
+ S16 height;
+ } SIZE;
+
+ typedef struct _SIZEL
+ {
+ S32 width;
+ S32 height;
+ } SIZEL;
+
+ struct WmfEnhMetaHeader
+ {
+ S32 iType; // Record type EMR_HEADER
+ S32 nSize; // Record size in bytes. This may be greater
+ // than the sizeof(ENHMETAHEADER).
+ RECTL rclBounds; // Inclusive-inclusive bounds in device units
+ RECTL rclFrame; // Inclusive-inclusive Picture Frame of metafile
+ // in .01 mm units
+ S32 dSignature; // Signature. Must be ENHMETA_SIGNATURE.
+ S32 nVersion; // Version number
+ S32 nBytes; // Size of the metafile in bytes
+ S32 nRecords; // Number of records in the metafile
+ S16 nHandles; // Number of handles in the handle table
+ // Handle index zero is reserved.
+ S16 sReserved; // Reserved. Must be zero.
+ S32 nDescription; // Number of chars in the unicode description string
+ // This is 0 if there is no description string
+ S32 offDescription; // Offset to the metafile description record.
+ // This is 0 if there is no description string
+ S32 nPalEntries; // Number of entries in the metafile palette.
+ SIZEL szlDevice; // Size of the reference device in pels
+ SIZEL szlMillimeters; // Size of the reference device in millimeters
+ };
+ #define ENHMETA_SIGNATURE 0x464D4520
+
+ struct WmfMetaHeader
+ {
+ S16 mtType;
+ S16 mtHeaderSize;
+ S16 mtVersion;
+ S32 mtSize;
+ S16 mtNoObjects;
+ S32 mtMaxRecord;
+ S16 mtNoParameters;
+ };
+
+ struct WmfPlaceableHeader
+ {
+ S32 key;
+ S16 hmf;
+ RECT bbox;
+ S16 inch;
+ S32 reserved;
+ S16 checksum;
+ };
+ #define APMHEADER_KEY 0x9AC6CDD7L
+
+ WmfPlaceableHeader pheader;
+ WmfEnhMetaHeader eheader;
+ WmfMetaHeader header;
+ S16 checksum;
+ int fileAt;
+
+ //----- Read placeable metafile header
+
+ stream >> pheader.key;
+ isPlaceable = (pheader.key == (S32)APMHEADER_KEY);
+ if (isPlaceable)
+ {
+ stream >> pheader.hmf;
+ stream >> pheader.bbox.left;
+ stream >> pheader.bbox.top;
+ stream >> pheader.bbox.right;
+ stream >> pheader.bbox.bottom;
+ stream >> pheader.inch;
+ stream >> pheader.reserved;
+ stream >> pheader.checksum;
+ checksum = 0;
+ S16 *ptr = (S16 *)&pheader;
+
+ // XOR in each of the S16s.
+
+ for (unsigned i = 0; i < sizeof(WmfPlaceableHeader)/sizeof(S16); i++)
+ {
+ checksum ^= ptr[i];
+ }
+ if (pheader.checksum != checksum)
+ isPlaceable = false;
+ m_dpi = (unsigned)((double)pheader.inch / m_dpi);
+ m_windowOrgX = pheader.bbox.left;
+ m_windowOrgY = pheader.bbox.top;
+ if (pheader.bbox.right > pheader.bbox.left)
+ m_windowFlipX = 1;
+ else
+ m_windowFlipX = -1;
+ if (pheader.bbox.bottom > pheader.bbox.top)
+ m_windowFlipY = 1;
+ else
+ m_windowFlipY = -1;
+ }
+ else
+ {
+ stream.device()->at(startedAt);
+ m_dpi = (unsigned)((double)576 / m_dpi);
+ m_windowOrgX = 0;
+ m_windowOrgY = 0;
+ m_windowFlipX = 1;
+ m_windowFlipY = 1;
+ }
+
+ //----- Read as enhanced metafile header
+
+ fileAt = stream.device()->at();
+ stream >> eheader.iType;
+ stream >> eheader.nSize;
+ stream >> eheader.rclBounds.left;
+ stream >> eheader.rclBounds.top;
+ stream >> eheader.rclBounds.right;
+ stream >> eheader.rclBounds.bottom;
+ stream >> eheader.rclFrame.left;
+ stream >> eheader.rclFrame.top;
+ stream >> eheader.rclFrame.right;
+ stream >> eheader.rclFrame.bottom;
+ stream >> eheader.dSignature;
+ isEnhanced = (eheader.dSignature == ENHMETA_SIGNATURE);
+ if (isEnhanced) // is it really enhanced ?
+ {
+ stream >> eheader.nVersion;
+ stream >> eheader.nBytes;
+ stream >> eheader.nRecords;
+ stream >> eheader.nHandles;
+ stream >> eheader.sReserved;
+ stream >> eheader.nDescription;
+ stream >> eheader.offDescription;
+ stream >> eheader.nPalEntries;
+ stream >> eheader.szlDevice.width;
+ stream >> eheader.szlDevice.height;
+ stream >> eheader.szlMillimeters.width;
+ stream >> eheader.szlMillimeters.height;
+
+ kdError(s_area) << "WMF Extended Header NOT YET IMPLEMENTED, SORRY." << endl;
+ /*
+ if (mSingleStep)
+ {
+ debug(" iType=%d", eheader.iType);
+ debug(" nSize=%d", eheader.nSize);
+ debug(" rclBounds=(%ld;%ld;%ld;%ld)",
+ eheader.rclBounds.left, eheader.rclBounds.top,
+ eheader.rclBounds.right, eheader.rclBounds.bottom);
+ debug(" rclFrame=(%ld;%ld;%ld;%ld)",
+ eheader.rclFrame.left, eheader.rclFrame.top,
+ eheader.rclFrame.right, eheader.rclFrame.bottom);
+ debug(" dSignature=%d", eheader.dSignature);
+ debug(" nVersion=%d", eheader.nVersion);
+ debug(" nBytes=%d", eheader.nBytes);
+ }
+ debug("NOT YET IMPLEMENTED, SORRY.");
+ */
+ return false;
+ }
+ else // no, not enhanced
+ {
+ // debug("WMF Header");
+ //----- Read as standard metafile header
+ stream.device()->at(fileAt);
+ stream >> header.mtType;
+ stream >> header.mtHeaderSize;
+ stream >> header.mtVersion;
+ stream >> header.mtSize;
+ stream >> header.mtNoObjects;
+ stream >> header.mtMaxRecord;
+ stream >> header.mtNoParameters;
+ /*
+ if (mSingleStep)
+ {
+ debug(" mtType=%u", header.mtType);
+ debug(" mtHeaderSize=%u", header.mtHeaderSize);
+ debug(" mtVersion=%u", header.mtVersion);
+ debug(" mtSize=%ld", header.mtSize);
+ }
+ */
+ }
+
+ walk((size - (stream.device()->at() - startedAt)) / 2, stream);
+ return true;
+}
+
+void KWmf::opArc(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ genericArc("arc", operands);
+}
+
+void KWmf::opBrushCreateIndirect(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ 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;
+ WinObjBrushHandle *handle = handleCreateBrush();
+ S16 arg;
+ S32 colour;
+ S16 discard;
+
+ operands >> arg >> colour;
+ handle->m_colour = getColour(colour);
+ if (arg == 2)
+ {
+ operands >> arg;
+ if (arg >= 0 && arg < 6)
+ {
+ style = hatchedStyleTab[arg];
+ }
+ else
+ {
+ kdError(s_area) << "createBrushIndirect: invalid hatched brush " << arg << endl;
+ style = Qt::SolidPattern;
+ }
+ }
+ else
+ if (arg >= 0 && arg < 9)
+ {
+ style = styleTab[arg];
+ operands >> discard;
+ }
+ else
+ {
+ kdError(s_area) << "createBrushIndirect: invalid brush " << arg << endl;
+ style = Qt::SolidPattern;
+ operands >> discard;
+ }
+ handle->m_style = style;
+}
+
+void KWmf::opEllipse(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ QPoint topLeft;
+ QPoint bottomRight;
+
+ topLeft = normalisePoint(operands);
+ bottomRight = normalisePoint(operands);
+
+ QRect ellipse(topLeft, bottomRight);
+
+ gotEllipse(m_dc, "full", ellipse.center(), ellipse.size() / 2, 0, 0);
+}
+
+void KWmf::opLineTo(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ QPoint lineTo;
+
+ lineTo = normalisePoint(operands);
+ QPointArray points(2);
+ points.setPoint(0, m_lineFrom);
+ points.setPoint(1, lineTo);
+ gotPolyline(m_dc, points);
+
+ // Remember this point for next time.
+
+ m_lineFrom = lineTo;
+}
+
+void KWmf::opMoveTo(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ m_lineFrom = normalisePoint(operands);
+}
+
+void KWmf::opNoop(
+ U32 words,
+ QDataStream &operands)
+{
+ skip(words, operands);
+}
+
+//-----------------------------------------------------------------------------
+void KWmf::opObjectDelete(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ S16 idx;
+
+ operands >> idx;
+ handleDelete(idx);
+}
+
+//-----------------------------------------------------------------------------
+void KWmf::opObjectSelect(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ S16 idx;
+
+ operands >> idx;
+ if (idx >= 0 && idx < s_maxHandles && m_objectHandles[idx])
+ m_objectHandles[idx]->apply(*this);
+}
+
+//
+//
+//
+
+void KWmf::opPenCreateIndirect(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ static Qt::PenStyle styleTab[] =
+ {
+ Qt::SolidLine,
+ Qt::DashLine,
+ Qt::DotLine,
+ Qt::DashDotLine,
+ Qt::DashDotDotLine,
+ Qt::NoPen,
+ Qt::SolidLine, // PS_INSIDEFRAME
+ Qt::SolidLine, // PS_USERSTYLE
+ Qt::SolidLine // PS_ALTERNATE
+ };
+ WinObjPenHandle *handle = handleCreatePen();
+ S16 arg;
+ S32 colour;
+
+ operands >> arg;
+ if (arg >= 0 && arg < 8)
+ {
+ handle->m_style = styleTab[arg];
+ }
+ else
+ {
+ kdError(s_area) << "createPenIndirect: invalid pen " << arg << endl;
+ handle->m_style = Qt::SolidLine;
+ }
+ operands >> arg;
+ handle->m_width = arg;
+ operands >> arg >> colour;
+ handle->m_colour = getColour(colour);
+}
+
+void KWmf::opPie(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ genericArc("pie", operands);
+}
+
+void KWmf::opPolygonSetFillMode(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ S16 tmp;
+
+ operands >> tmp;
+ m_dc.m_winding = tmp != 0;
+}
+
+void KWmf::opPolygon(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ S16 tmp;
+
+ operands >> tmp;
+ QPointArray points(tmp);
+
+ for (int i = 0; i < tmp; i++)
+ {
+ points.setPoint(i, normalisePoint(operands));
+ }
+ gotPolygon(m_dc, points);
+}
+
+void KWmf::opPolyline(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ S16 tmp;
+
+ operands >> tmp;
+ QPointArray points(tmp);
+
+ for (int i = 0; i < tmp; i++)
+ {
+ points.setPoint(i, normalisePoint(operands));
+ }
+ gotPolyline(m_dc, points);
+}
+
+void KWmf::opRectangle(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ QPoint topLeft;
+ QSize size;
+
+ topLeft = normalisePoint(operands);
+ size = normaliseSize(operands);
+ QRect rect(topLeft, size);
+ QPointArray points(4);
+
+ points.setPoint(0, topLeft);
+ points.setPoint(1, rect.topRight());
+ points.setPoint(2, rect.bottomRight());
+ points.setPoint(3, rect.bottomLeft());
+ gotRectangle(m_dc, points);
+}
+
+void KWmf::opRestoreDc(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ S16 pop;
+ S16 i;
+
+ operands >> pop;
+ for (i = 0; i < pop; i++)
+ {
+ m_dc = m_savedDcs.pop();
+ }
+}
+
+void KWmf::opSaveDc(
+ U32 /*words*/,
+ QDataStream &/*operands*/)
+{
+ m_savedDcs.push(m_dc);
+
+ // TBD: reinitialise m_dc.
+}
+
+void KWmf::opWindowSetOrg(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ S16 top;
+ S16 left;
+
+ operands >> top >> left;
+ m_windowOrgX = left;
+ m_windowOrgY = top;
+}
+
+void KWmf::opWindowSetExt(
+ U32 /*words*/,
+ QDataStream &operands)
+{
+ S16 height;
+ S16 width;
+
+ operands >> height >> width;
+ if (width > 0)
+ m_windowFlipX = 1;
+ else
+ m_windowFlipX = -1;
+ if (height > 0)
+ m_windowFlipY = 1;
+ else
+ m_windowFlipY = -1;
+}
+
+void KWmf::penSet(
+ unsigned colour,
+ unsigned style,
+ unsigned width)
+{
+ m_dc.m_penColour = colour;
+ m_dc.m_penStyle = style;
+ m_dc.m_penWidth = width;
+}
+
+void KWmf::skip(
+ U32 words,
+ QDataStream &operands)
+{
+ if ((int)words < 0)
+ {
+ kdError(s_area) << "skip: " << (int)words << endl;
+ return;
+ }
+ if (words)
+ {
+ U32 i;
+ S16 discard;
+
+ kdDebug(s_area) << "skip: " << words << endl;
+ for (i = 0; i < words; i++)
+ {
+ operands >> discard;
+ }
+ }
+}
+
+void KWmf::walk(
+ U32 words,
+ QDataStream &operands)
+{
+ // Read bits:
+ //
+ // struct WmfMetaRecord
+ // {
+ // S32 rdSize; // Record size (in words) of the function
+ // S16 rdFunction; // Record function number
+ // S16 rdParm[1]; // WORD array of parameters
+ // };
+ //
+ // struct WmfEnhMetaRecord
+ // {
+ // S32 iType; // Record type EMR_xxx
+ // S32 nSize; // Record size in bytes
+ // S32 dParm[1]; // DWORD array of parameters
+ // };
+
+ S32 wordCount;
+ S16 opcode;
+ U32 length = 0;
+
+ while (length < words)
+ {
+ operands >> wordCount;
+ operands >> opcode;
+
+ // If we get some duff data, protect ourselves.
+ if (length + wordCount > words)
+ {
+ wordCount = words - length;
+ }
+ length += wordCount;
+ if (opcode == 0)
+ {
+ // This appears to be an EOF marker.
+ break;
+ }
+
+ // Package the arguments...
+
+ invokeHandler(opcode, wordCount - 3, operands);
+ }
+
+ // Eat unexpected data that the caller may expect us to consume.
+ skip(words - length, operands);
+}
+
+KWmf::DrawContext::DrawContext()
+{
+ // TBD: initalise with proper values.
+ m_brushColour = 0x808080;
+ m_brushStyle = 1;
+ m_penColour = 0x808080;
+ m_penStyle = 1;
+ m_penWidth = 1;
+}
+
+void KWmf::WinObjBrushHandle::apply(
+ KWmf &p)
+{
+ p.brushSet(m_colour, m_style);
+}
+
+void KWmf::WinObjPenHandle::apply(
+ KWmf &p)
+{
+ p.penSet(m_colour, m_style, m_width);
+}