|
|
|
/*
|
|
|
|
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 <tqfile.h>
|
|
|
|
#include <tqpointarray.h>
|
|
|
|
#include <kwmf.h>
|
|
|
|
#include <tqrect.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(
|
|
|
|
TQString type,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
TQPoint topLeft;
|
|
|
|
TQPoint bottomRight;
|
|
|
|
TQPoint start;
|
|
|
|
TQPoint 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.
|
|
|
|
|
|
|
|
TQRect ellipse(topLeft, bottomRight);
|
|
|
|
TQPoint 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,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
typedef void (KWmf::*method)(U32 words, TQDataStream &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" <<
|
|
|
|
TQString::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)
|
|
|
|
{
|
|
|
|
TQByteArray *record = new TQByteArray(words * 2);
|
|
|
|
TQDataStream *body;
|
|
|
|
|
|
|
|
operands.readRawBytes(record->data(), words * 2);
|
|
|
|
body = new TQDataStream(*record, IO_ReadOnly);
|
|
|
|
body->setByteOrder(TQDataStream::LittleEndian);
|
|
|
|
(this->*result)(words, *body);
|
|
|
|
delete body;
|
|
|
|
delete record;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TQDataStream *body = new TQDataStream();
|
|
|
|
|
|
|
|
(this->*result)(words, *body);
|
|
|
|
delete body;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPoint KWmf::normalisePoint(
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
S16 x;
|
|
|
|
S16 y;
|
|
|
|
|
|
|
|
operands >> x >> y;
|
|
|
|
return TQPoint((x - m_windowOrgX) * m_windowFlipX / m_dpi, (y - m_windowOrgY) * m_windowFlipY / m_dpi);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQSize KWmf::normaliseSize(
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
S16 width;
|
|
|
|
S16 height;
|
|
|
|
|
|
|
|
operands >> width >> height;
|
|
|
|
return TQSize(width / m_dpi, height / m_dpi);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWmf::parse(
|
|
|
|
const TQString &file)
|
|
|
|
{
|
|
|
|
TQFile in(file);
|
|
|
|
if (!in.open(IO_ReadOnly))
|
|
|
|
{
|
|
|
|
kdError(s_area) << "Unable to open input file!" << endl;
|
|
|
|
in.close();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
TQDataStream stream(&in);
|
|
|
|
bool result = parse(stream, in.size());
|
|
|
|
in.close();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWmf::parse(
|
|
|
|
TQDataStream &stream,
|
|
|
|
unsigned size)
|
|
|
|
{
|
|
|
|
int startedAt;
|
|
|
|
bool isPlaceable;
|
|
|
|
bool isEnhanced;
|
|
|
|
|
|
|
|
startedAt = stream.device()->at();
|
|
|
|
stream.setByteOrder(TQDataStream::LittleEndian); // Great, I love TQt !
|
|
|
|
|
|
|
|
for (int i = 0; i < s_maxHandles; i++)
|
|
|
|
m_objectHandles[i] = NULL;
|
|
|
|
|
|
|
|
struct RECT
|
|
|
|
{
|
|
|
|
S16 left;
|
|
|
|
S16 top;
|
|
|
|
S16 right;
|
|
|
|
S16 bottom;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct RECTL
|
|
|
|
{
|
|
|
|
S32 left;
|
|
|
|
S32 top;
|
|
|
|
S32 right;
|
|
|
|
S32 bottom;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SIZE
|
|
|
|
{
|
|
|
|
S16 width;
|
|
|
|
S16 height;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SIZEL
|
|
|
|
{
|
|
|
|
S32 width;
|
|
|
|
S32 height;
|
|
|
|
};
|
|
|
|
|
|
|
|
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*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
genericArc("arc", operands);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWmf::opBrushCreateIndirect(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
static TQt::BrushStyle hatchedStyleTab[] =
|
|
|
|
{
|
|
|
|
TQt::HorPattern,
|
|
|
|
TQt::FDiagPattern,
|
|
|
|
TQt::BDiagPattern,
|
|
|
|
TQt::CrossPattern,
|
|
|
|
TQt::DiagCrossPattern
|
|
|
|
};
|
|
|
|
static TQt::BrushStyle styleTab[] =
|
|
|
|
{
|
|
|
|
TQt::SolidPattern,
|
|
|
|
TQt::NoBrush,
|
|
|
|
TQt::FDiagPattern, // hatched
|
|
|
|
TQt::Dense4Pattern, // should be custom bitmap pattern
|
|
|
|
TQt::HorPattern, // should be BS_INDEXED (?)
|
|
|
|
TQt::VerPattern, // should be device-independent bitmap
|
|
|
|
TQt::Dense6Pattern, // should be device-independent packed-bitmap
|
|
|
|
TQt::Dense2Pattern, // should be BS_PATTERN8x8
|
|
|
|
TQt::Dense3Pattern // should be device-independent BS_DIBPATTERN8x8
|
|
|
|
};
|
|
|
|
TQt::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 = TQt::SolidPattern;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (arg >= 0 && arg < 9)
|
|
|
|
{
|
|
|
|
style = styleTab[arg];
|
|
|
|
operands >> discard;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdError(s_area) << "createBrushIndirect: invalid brush " << arg << endl;
|
|
|
|
style = TQt::SolidPattern;
|
|
|
|
operands >> discard;
|
|
|
|
}
|
|
|
|
handle->m_style = style;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWmf::opEllipse(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
TQPoint topLeft;
|
|
|
|
TQPoint bottomRight;
|
|
|
|
|
|
|
|
topLeft = normalisePoint(operands);
|
|
|
|
bottomRight = normalisePoint(operands);
|
|
|
|
|
|
|
|
TQRect ellipse(topLeft, bottomRight);
|
|
|
|
|
|
|
|
gotEllipse(m_dc, "full", ellipse.center(), ellipse.size() / 2, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWmf::opLineTo(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
TQPoint lineTo;
|
|
|
|
|
|
|
|
lineTo = normalisePoint(operands);
|
|
|
|
TQPointArray 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*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
m_lineFrom = normalisePoint(operands);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWmf::opNoop(
|
|
|
|
U32 words,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
skip(words, operands);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void KWmf::opObjectDelete(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
S16 idx;
|
|
|
|
|
|
|
|
operands >> idx;
|
|
|
|
handleDelete(idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void KWmf::opObjectSelect(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
S16 idx;
|
|
|
|
|
|
|
|
operands >> idx;
|
|
|
|
if (idx >= 0 && idx < s_maxHandles && m_objectHandles[idx])
|
|
|
|
m_objectHandles[idx]->apply(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
void KWmf::opPenCreateIndirect(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
static TQt::PenStyle styleTab[] =
|
|
|
|
{
|
|
|
|
TQt::SolidLine,
|
|
|
|
TQt::DashLine,
|
|
|
|
TQt::DotLine,
|
|
|
|
TQt::DashDotLine,
|
|
|
|
TQt::DashDotDotLine,
|
|
|
|
TQt::NoPen,
|
|
|
|
TQt::SolidLine, // PS_INSIDEFRAME
|
|
|
|
TQt::SolidLine, // PS_USERSTYLE
|
|
|
|
TQt::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 = TQt::SolidLine;
|
|
|
|
}
|
|
|
|
operands >> arg;
|
|
|
|
handle->m_width = arg;
|
|
|
|
operands >> arg >> colour;
|
|
|
|
handle->m_colour = getColour(colour);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWmf::opPie(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
genericArc("pie", operands);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWmf::opPolygonSetFillMode(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
S16 tmp;
|
|
|
|
|
|
|
|
operands >> tmp;
|
|
|
|
m_dc.m_winding = tmp != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWmf::opPolygon(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
S16 tmp;
|
|
|
|
|
|
|
|
operands >> tmp;
|
|
|
|
TQPointArray points(tmp);
|
|
|
|
|
|
|
|
for (int i = 0; i < tmp; i++)
|
|
|
|
{
|
|
|
|
points.setPoint(i, normalisePoint(operands));
|
|
|
|
}
|
|
|
|
gotPolygon(m_dc, points);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWmf::opPolyline(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
S16 tmp;
|
|
|
|
|
|
|
|
operands >> tmp;
|
|
|
|
TQPointArray points(tmp);
|
|
|
|
|
|
|
|
for (int i = 0; i < tmp; i++)
|
|
|
|
{
|
|
|
|
points.setPoint(i, normalisePoint(operands));
|
|
|
|
}
|
|
|
|
gotPolyline(m_dc, points);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWmf::opRectangle(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
TQPoint topLeft;
|
|
|
|
TQSize size;
|
|
|
|
|
|
|
|
topLeft = normalisePoint(operands);
|
|
|
|
size = normaliseSize(operands);
|
|
|
|
TQRect rect(topLeft, size);
|
|
|
|
TQPointArray 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*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
S16 pop;
|
|
|
|
S16 i;
|
|
|
|
|
|
|
|
operands >> pop;
|
|
|
|
for (i = 0; i < pop; i++)
|
|
|
|
{
|
|
|
|
m_dc = m_savedDcs.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWmf::opSaveDc(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &/*operands*/)
|
|
|
|
{
|
|
|
|
m_savedDcs.push(m_dc);
|
|
|
|
|
|
|
|
// TBD: reinitialise m_dc.
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWmf::opWindowSetOrg(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &operands)
|
|
|
|
{
|
|
|
|
S16 top;
|
|
|
|
S16 left;
|
|
|
|
|
|
|
|
operands >> top >> left;
|
|
|
|
m_windowOrgX = left;
|
|
|
|
m_windowOrgY = top;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWmf::opWindowSetExt(
|
|
|
|
U32 /*words*/,
|
|
|
|
TQDataStream &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,
|
|
|
|
TQDataStream &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,
|
|
|
|
TQDataStream &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);
|
|
|
|
}
|