lib

kwmf.cpp
1/*
2 Copyright (C) 2000, S.R.Haque <shaheedhaque@hotmail.com>.
3 This file is part of the KDE project
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19
20DESCRIPTION
21
22 This is based on code originally written by Stefan Taferner
23 (taferner@kde.org) and also borrows from libwmf (by Martin Vermeer and
24 Caolan McNamara).
25*/
26
27#include <kdebug.h>
28#include <math.h>
29#include <tqfile.h>
30#include <tqpointarray.h>
31#include <kwmf.h>
32#include <tqrect.h>
33
34#define PI (3.14159265358979323846)
35
36const int KWmf::s_area = 30504;
37const int KWmf::s_maxHandles = 64;
38
39KWmf::KWmf(
40 unsigned dpi)
41{
42 m_dpi = dpi;
43 m_objectHandles = new WinObjHandle*[s_maxHandles];
44}
45
46KWmf::~KWmf()
47{
48 delete[] m_objectHandles;
49}
50
51//
52//
53//
54
55void KWmf::brushSet(
56 unsigned colour,
57 unsigned style)
58{
59 m_dc.m_brushColour = colour;
60 m_dc.m_brushStyle = style;
61}
62
63//-----------------------------------------------------------------------------
64unsigned KWmf::getColour(
65 S32 colour)
66{
67 unsigned red, green, blue;
68
69 red = colour & 255;
70 green = (colour >> 8) & 255;
71 blue = (colour >> 16) & 255;
72 return (red << 16) + (green << 8) + blue;
73}
74
75void KWmf::genericArc(
76 TQString type,
77 TQDataStream &operands)
78{
79 TQPoint topLeft;
80 TQPoint bottomRight;
81 TQPoint start;
82 TQPoint end;
83
84 topLeft = normalisePoint(operands);
85 bottomRight = normalisePoint(operands);
86 start = normalisePoint(operands);
87 end = normalisePoint(operands);
88
89 // WMF defines arcs with the major and minor axes of an ellipse, and two points.
90 // From each point draw a line to the center of the ellipse: the intercepts define
91 // the ends of the arc.
92
93 TQRect ellipse(topLeft, bottomRight);
94 TQPoint centre = ellipse.center();
95 double startAngle = atan2((double)(centre.y() - start.y()), (double)(centre.x() - start.x()));
96 double stopAngle = atan2((double)(centre.y() - end.y()), (double)(centre.x() - end.x()));
97
98 startAngle = 180 * startAngle / PI;
99 stopAngle = 180 * stopAngle / PI;
100
101 gotEllipse(m_dc, type, centre, ellipse.size() / 2,
102 static_cast<unsigned int>(startAngle),
103 static_cast<unsigned int>(stopAngle));
104}
105
106int KWmf::handleIndex(void) const
107{
108 int i;
109
110 for (i = 0; i < s_maxHandles; i++)
111 {
112 if (!m_objectHandles[i])
113 return i;
114 }
115 kdError(s_area) << "handle table full !" << endl;
116 return -1;
117}
118
119//-----------------------------------------------------------------------------
120KWmf::WinObjPenHandle *KWmf::handleCreatePen(void)
121{
122 WinObjPenHandle *handle = new WinObjPenHandle;
123 int idx = handleIndex();
124
125 if (idx >= 0)
126 m_objectHandles[idx] = handle;
127 return handle;
128}
129
130//-----------------------------------------------------------------------------
131KWmf::WinObjBrushHandle *KWmf::handleCreateBrush(void)
132{
133 WinObjBrushHandle *handle = new WinObjBrushHandle;
134 int idx = handleIndex();
135
136 if (idx >= 0)
137 m_objectHandles[idx] = handle;
138 return handle;
139}
140
141//-----------------------------------------------------------------------------
142void KWmf::handleDelete(int idx)
143{
144 if (idx >= 0 && idx < s_maxHandles && m_objectHandles[idx])
145 {
146 delete m_objectHandles[idx];
147 m_objectHandles[idx] = NULL;
148 }
149}
150
151//
152//
153//
154
155void KWmf::invokeHandler(
156 S16 opcode,
157 U32 words,
158 TQDataStream &operands)
159{
160 typedef void (KWmf::*method)(U32 words, TQDataStream &operands);
161
162 typedef struct
163 {
164 const char *name;
165 unsigned short opcode;
166 method handler;
167 } opcodeEntry;
168
169 static const opcodeEntry funcTab[] =
170 {
171 { "ANIMATEPALETTE", 0x0436, 0 },
172 { "ARC", 0x0817, &KWmf::opArc },
173 { "BITBLT", 0x0922, 0 },
174 { "CHORD", 0x0830, 0 },
175 { "CREATEBRUSHINDIRECT", 0x02FC, &KWmf::opBrushCreateIndirect },
176 { "CREATEFONTINDIRECT", 0x02FB, 0 },
177 { "CREATEPALETTE", 0x00F7, 0 },
178 { "CREATEPATTERNBRUSH", 0x01F9, 0 },
179 { "CREATEPENINDIRECT", 0x02FA, &KWmf::opPenCreateIndirect },
180 { "CREATEREGION", 0x06FF, 0 },
181 { "DELETEOBJECT", 0x01F0, &KWmf::opObjectDelete },
182 { "DIBBITBLT", 0x0940, 0 },
183 { "DIBCREATEPATTERNBRUSH",0x0142, 0 },
184 { "DIBSTRETCHBLT", 0x0b41, 0 },
185 { "ELLIPSE", 0x0418, &KWmf::opEllipse },
186 { "ESCAPE", 0x0626, &KWmf::opNoop },
187 { "EXCLUDECLIPRECT", 0x0415, 0 },
188 { "EXTFLOODFILL", 0x0548, 0 },
189 { "EXTTEXTOUT", 0x0a32, 0 },
190 { "FILLREGION", 0x0228, 0 },
191 { "FLOODFILL", 0x0419, 0 },
192 { "FRAMEREGION", 0x0429, 0 },
193 { "INTERSECTCLIPRECT", 0x0416, 0 },
194 { "INVERTREGION", 0x012A, 0 },
195 { "LINETO", 0x0213, &KWmf::opLineTo },
196 { "MOVETO", 0x0214, &KWmf::opMoveTo },
197 { "OFFSETCLIPRGN", 0x0220, 0 },
198 { "OFFSETVIEWPORTORG", 0x0211, 0 },
199 { "OFFSETWINDOWORG", 0x020F, 0 },
200 { "PAINTREGION", 0x012B, 0 },
201 { "PATBLT", 0x061D, 0 },
202 { "PIE", 0x081A, &KWmf::opPie },
203 { "POLYGON", 0x0324, &KWmf::opPolygon },
204 { "POLYLINE", 0x0325, &KWmf::opPolyline },
205 { "POLYPOLYGON", 0x0538, 0 },
206 { "REALIZEPALETTE", 0x0035, 0 },
207 { "RECTANGLE", 0x041B, &KWmf::opRectangle },
208 { "RESIZEPALETTE", 0x0139, 0 },
209 { "RESTOREDC", 0x0127, &KWmf::opRestoreDc },
210 { "ROUNDRECT", 0x061C, 0 },
211 { "SAVEDC", 0x001E, &KWmf::opSaveDc },
212 { "SCALEVIEWPORTEXT", 0x0412, 0 },
213 { "SCALEWINDOWEXT", 0x0410, 0 },
214 { "SELECTCLIPREGION", 0x012C, 0 },
215 { "SELECTOBJECT", 0x012D, &KWmf::opObjectSelect },
216 { "SELECTPALETTE", 0x0234, 0 },
217 { "SETBKCOLOR", 0x0201, 0 },
218 { "SETBKMODE", 0x0102, 0 },
219 { "SETDIBTODEV", 0x0d33, 0 },
220 { "SETMAPMODE", 0x0103, 0 },
221 { "SETMAPPERFLAGS", 0x0231, 0 },
222 { "SETPALENTRIES", 0x0037, 0 },
223 { "SETPIXEL", 0x041F, 0 },
224 { "SETPOLYFILLMODE", 0x0106, &KWmf::opPolygonSetFillMode },
225 { "SETRELABS", 0x0105, 0 },
226 { "SETROP2", 0x0104, 0 },
227 { "SETSTRETCHBLTMODE", 0x0107, 0 },
228 { "SETTEXTALIGN", 0x012E, 0 },
229 { "SETTEXTCHAREXTRA", 0x0108, 0 },
230 { "SETTEXTCOLOR", 0x0209, 0 },
231 { "SETTEXTJUSTIFICATION", 0x020A, 0 },
232 { "SETVIEWPORTEXT", 0x020E, 0 },
233 { "SETVIEWPORTORG", 0x020D, 0 },
234 { "SETWINDOWEXT", 0x020C, &KWmf::opWindowSetExt },
235 { "SETWINDOWORG", 0x020B, &KWmf::opWindowSetOrg },
236 { "STRETCHBLT", 0x0B23, 0 },
237 { "STRETCHDIB", 0x0f43, 0 },
238 { "TEXTOUT", 0x0521, 0 },
239 { NULL, 0, 0 }
240 };
241 unsigned i;
242 method result;
243
244 // Scan lookup table for operation.
245
246 for (i = 0; funcTab[i].name; i++)
247 {
248 if (funcTab[i].opcode == opcode)
249 {
250 break;
251 }
252 }
253
254 // Invoke handler.
255
256 result = funcTab[i].handler;
257 if (!result)
258 {
259 if (funcTab[i].name)
260 kdError(s_area) << "invokeHandler: unsupported opcode: " <<
261 funcTab[i].name <<
262 " operands: " << words << endl;
263 else
264 kdError(s_area) << "invokeHandler: unsupported opcode: 0x" <<
265 TQString::number(opcode, 16) <<
266 " operands: " << words << endl;
267
268 // Skip data we cannot use.
269
270 for (i = 0; i < words; i++)
271 {
272 S16 discard;
273
274 operands >> discard;
275 }
276 }
277 else
278 {
279 kdDebug(s_area) << "invokeHandler: opcode: " << funcTab[i].name <<
280 " operands: " << words << endl;
281
282 // We don't invoke the handler directly on the incoming operands, but
283 // via a temporary datastream. This adds overhead, but eliminates the
284 // need for the individual handlers to read *exactly* the right amount
285 // of data (thus speeding development, and possibly adding some
286 // future-proofing).
287
288 if (words)
289 {
290 TQByteArray *record = new TQByteArray(words * 2);
291 TQDataStream *body;
292
293 operands.readRawBytes(record->data(), words * 2);
294 body = new TQDataStream(*record, IO_ReadOnly);
295 body->setByteOrder(TQDataStream::LittleEndian);
296 (this->*result)(words, *body);
297 delete body;
298 delete record;
299 }
300 else
301 {
302 TQDataStream *body = new TQDataStream();
303
304 (this->*result)(words, *body);
305 delete body;
306 }
307 }
308}
309
310TQPoint KWmf::normalisePoint(
311 TQDataStream &operands)
312{
313 S16 x;
314 S16 y;
315
316 operands >> x >> y;
317 return TQPoint((x - m_windowOrgX) * m_windowFlipX / m_dpi, (y - m_windowOrgY) * m_windowFlipY / m_dpi);
318}
319
320TQSize KWmf::normaliseSize(
321 TQDataStream &operands)
322{
323 S16 width;
324 S16 height;
325
326 operands >> width >> height;
327 return TQSize(width / m_dpi, height / m_dpi);
328}
329
330bool KWmf::parse(
331 const TQString &file)
332{
333 TQFile in(file);
334 if (!in.open(IO_ReadOnly))
335 {
336 kdError(s_area) << "Unable to open input file!" << endl;
337 in.close();
338 return false;
339 }
340 TQDataStream stream(&in);
341 bool result = parse(stream, in.size());
342 in.close();
343 return result;
344}
345
346bool KWmf::parse(
347 TQDataStream &stream,
348 unsigned size)
349{
350 int startedAt;
351 bool isPlaceable;
352 bool isEnhanced;
353
354 startedAt = stream.device()->at();
355 stream.setByteOrder(TQDataStream::LittleEndian); // Great, I love TQt !
356
357 for (int i = 0; i < s_maxHandles; i++)
358 m_objectHandles[i] = NULL;
359
360 struct RECT
361 {
362 S16 left;
363 S16 top;
364 S16 right;
365 S16 bottom;
366 };
367
368 struct RECTL
369 {
370 S32 left;
371 S32 top;
372 S32 right;
373 S32 bottom;
374 };
375
376 struct SIZE
377 {
378 S16 width;
379 S16 height;
380 };
381
382 struct SIZEL
383 {
384 S32 width;
385 S32 height;
386 };
387
388 struct WmfEnhMetaHeader
389 {
390 S32 iType; // Record type EMR_HEADER
391 S32 nSize; // Record size in bytes. This may be greater
392 // than the sizeof(ENHMETAHEADER).
393 RECTL rclBounds; // Inclusive-inclusive bounds in device units
394 RECTL rclFrame; // Inclusive-inclusive Picture Frame of metafile
395 // in .01 mm units
396 S32 dSignature; // Signature. Must be ENHMETA_SIGNATURE.
397 S32 nVersion; // Version number
398 S32 nBytes; // Size of the metafile in bytes
399 S32 nRecords; // Number of records in the metafile
400 S16 nHandles; // Number of handles in the handle table
401 // Handle index zero is reserved.
402 S16 sReserved; // Reserved. Must be zero.
403 S32 nDescription; // Number of chars in the unicode description string
404 // This is 0 if there is no description string
405 S32 offDescription; // Offset to the metafile description record.
406 // This is 0 if there is no description string
407 S32 nPalEntries; // Number of entries in the metafile palette.
408 SIZEL szlDevice; // Size of the reference device in pels
409 SIZEL szlMillimeters; // Size of the reference device in millimeters
410 };
411 #define ENHMETA_SIGNATURE 0x464D4520
412
413 struct WmfMetaHeader
414 {
415 S16 mtType;
416 S16 mtHeaderSize;
417 S16 mtVersion;
418 S32 mtSize;
419 S16 mtNoObjects;
420 S32 mtMaxRecord;
421 S16 mtNoParameters;
422 };
423
424 struct WmfPlaceableHeader
425 {
426 S32 key;
427 S16 hmf;
428 RECT bbox;
429 S16 inch;
430 S32 reserved;
431 S16 checksum;
432 };
433 #define APMHEADER_KEY 0x9AC6CDD7L
434
435 WmfPlaceableHeader pheader;
436 WmfEnhMetaHeader eheader;
437 WmfMetaHeader header;
438 S16 checksum;
439 int fileAt;
440
441 //----- Read placeable metafile header
442
443 stream >> pheader.key;
444 isPlaceable = (pheader.key == (S32)APMHEADER_KEY);
445 if (isPlaceable)
446 {
447 stream >> pheader.hmf;
448 stream >> pheader.bbox.left;
449 stream >> pheader.bbox.top;
450 stream >> pheader.bbox.right;
451 stream >> pheader.bbox.bottom;
452 stream >> pheader.inch;
453 stream >> pheader.reserved;
454 stream >> pheader.checksum;
455 checksum = 0;
456 S16 *ptr = (S16 *)&pheader;
457
458 // XOR in each of the S16s.
459
460 for (unsigned i = 0; i < sizeof(WmfPlaceableHeader)/sizeof(S16); i++)
461 {
462 checksum ^= ptr[i];
463 }
464 if (pheader.checksum != checksum)
465 isPlaceable = false;
466 m_dpi = (unsigned)((double)pheader.inch / m_dpi);
467 m_windowOrgX = pheader.bbox.left;
468 m_windowOrgY = pheader.bbox.top;
469 if (pheader.bbox.right > pheader.bbox.left)
470 m_windowFlipX = 1;
471 else
472 m_windowFlipX = -1;
473 if (pheader.bbox.bottom > pheader.bbox.top)
474 m_windowFlipY = 1;
475 else
476 m_windowFlipY = -1;
477 }
478 else
479 {
480 stream.device()->at(startedAt);
481 m_dpi = (unsigned)((double)576 / m_dpi);
482 m_windowOrgX = 0;
483 m_windowOrgY = 0;
484 m_windowFlipX = 1;
485 m_windowFlipY = 1;
486 }
487
488 //----- Read as enhanced metafile header
489
490 fileAt = stream.device()->at();
491 stream >> eheader.iType;
492 stream >> eheader.nSize;
493 stream >> eheader.rclBounds.left;
494 stream >> eheader.rclBounds.top;
495 stream >> eheader.rclBounds.right;
496 stream >> eheader.rclBounds.bottom;
497 stream >> eheader.rclFrame.left;
498 stream >> eheader.rclFrame.top;
499 stream >> eheader.rclFrame.right;
500 stream >> eheader.rclFrame.bottom;
501 stream >> eheader.dSignature;
502 isEnhanced = (eheader.dSignature == ENHMETA_SIGNATURE);
503 if (isEnhanced) // is it really enhanced ?
504 {
505 stream >> eheader.nVersion;
506 stream >> eheader.nBytes;
507 stream >> eheader.nRecords;
508 stream >> eheader.nHandles;
509 stream >> eheader.sReserved;
510 stream >> eheader.nDescription;
511 stream >> eheader.offDescription;
512 stream >> eheader.nPalEntries;
513 stream >> eheader.szlDevice.width;
514 stream >> eheader.szlDevice.height;
515 stream >> eheader.szlMillimeters.width;
516 stream >> eheader.szlMillimeters.height;
517
518 kdError(s_area) << "WMF Extended Header NOT YET IMPLEMENTED, SORRY." << endl;
519 /*
520 if (mSingleStep)
521 {
522 debug(" iType=%d", eheader.iType);
523 debug(" nSize=%d", eheader.nSize);
524 debug(" rclBounds=(%ld;%ld;%ld;%ld)",
525 eheader.rclBounds.left, eheader.rclBounds.top,
526 eheader.rclBounds.right, eheader.rclBounds.bottom);
527 debug(" rclFrame=(%ld;%ld;%ld;%ld)",
528 eheader.rclFrame.left, eheader.rclFrame.top,
529 eheader.rclFrame.right, eheader.rclFrame.bottom);
530 debug(" dSignature=%d", eheader.dSignature);
531 debug(" nVersion=%d", eheader.nVersion);
532 debug(" nBytes=%d", eheader.nBytes);
533 }
534 debug("NOT YET IMPLEMENTED, SORRY.");
535 */
536 return false;
537 }
538 else // no, not enhanced
539 {
540 // debug("WMF Header");
541 //----- Read as standard metafile header
542 stream.device()->at(fileAt);
543 stream >> header.mtType;
544 stream >> header.mtHeaderSize;
545 stream >> header.mtVersion;
546 stream >> header.mtSize;
547 stream >> header.mtNoObjects;
548 stream >> header.mtMaxRecord;
549 stream >> header.mtNoParameters;
550 /*
551 if (mSingleStep)
552 {
553 debug(" mtType=%u", header.mtType);
554 debug(" mtHeaderSize=%u", header.mtHeaderSize);
555 debug(" mtVersion=%u", header.mtVersion);
556 debug(" mtSize=%ld", header.mtSize);
557 }
558 */
559 }
560
561 walk((size - (stream.device()->at() - startedAt)) / 2, stream);
562 return true;
563}
564
565void KWmf::opArc(
566 U32 /*words*/,
567 TQDataStream &operands)
568{
569 genericArc("arc", operands);
570}
571
572void KWmf::opBrushCreateIndirect(
573 U32 /*words*/,
574 TQDataStream &operands)
575{
576 static TQt::BrushStyle hatchedStyleTab[] =
577 {
578 TQt::HorPattern,
579 TQt::FDiagPattern,
580 TQt::BDiagPattern,
581 TQt::CrossPattern,
582 TQt::DiagCrossPattern
583 };
584 static TQt::BrushStyle styleTab[] =
585 {
586 TQt::SolidPattern,
587 TQt::NoBrush,
588 TQt::FDiagPattern, // hatched
589 TQt::Dense4Pattern, // should be custom bitmap pattern
590 TQt::HorPattern, // should be BS_INDEXED (?)
591 TQt::VerPattern, // should be device-independent bitmap
592 TQt::Dense6Pattern, // should be device-independent packed-bitmap
593 TQt::Dense2Pattern, // should be BS_PATTERN8x8
594 TQt::Dense3Pattern // should be device-independent BS_DIBPATTERN8x8
595 };
596 TQt::BrushStyle style;
597 WinObjBrushHandle *handle = handleCreateBrush();
598 S16 arg;
599 S32 colour;
600 S16 discard;
601
602 operands >> arg >> colour;
603 handle->m_colour = getColour(colour);
604 if (arg == 2)
605 {
606 operands >> arg;
607 if (arg >= 0 && arg < 6)
608 {
609 style = hatchedStyleTab[arg];
610 }
611 else
612 {
613 kdError(s_area) << "createBrushIndirect: invalid hatched brush " << arg << endl;
614 style = TQt::SolidPattern;
615 }
616 }
617 else
618 if (arg >= 0 && arg < 9)
619 {
620 style = styleTab[arg];
621 operands >> discard;
622 }
623 else
624 {
625 kdError(s_area) << "createBrushIndirect: invalid brush " << arg << endl;
626 style = TQt::SolidPattern;
627 operands >> discard;
628 }
629 handle->m_style = style;
630}
631
632void KWmf::opEllipse(
633 U32 /*words*/,
634 TQDataStream &operands)
635{
636 TQPoint topLeft;
637 TQPoint bottomRight;
638
639 topLeft = normalisePoint(operands);
640 bottomRight = normalisePoint(operands);
641
642 TQRect ellipse(topLeft, bottomRight);
643
644 gotEllipse(m_dc, "full", ellipse.center(), ellipse.size() / 2, 0, 0);
645}
646
647void KWmf::opLineTo(
648 U32 /*words*/,
649 TQDataStream &operands)
650{
651 TQPoint lineTo;
652
653 lineTo = normalisePoint(operands);
654 TQPointArray points(2);
655 points.setPoint(0, m_lineFrom);
656 points.setPoint(1, lineTo);
657 gotPolyline(m_dc, points);
658
659 // Remember this point for next time.
660
661 m_lineFrom = lineTo;
662}
663
664void KWmf::opMoveTo(
665 U32 /*words*/,
666 TQDataStream &operands)
667{
668 m_lineFrom = normalisePoint(operands);
669}
670
671void KWmf::opNoop(
672 U32 words,
673 TQDataStream &operands)
674{
675 skip(words, operands);
676}
677
678//-----------------------------------------------------------------------------
679void KWmf::opObjectDelete(
680 U32 /*words*/,
681 TQDataStream &operands)
682{
683 S16 idx;
684
685 operands >> idx;
686 handleDelete(idx);
687}
688
689//-----------------------------------------------------------------------------
690void KWmf::opObjectSelect(
691 U32 /*words*/,
692 TQDataStream &operands)
693{
694 S16 idx;
695
696 operands >> idx;
697 if (idx >= 0 && idx < s_maxHandles && m_objectHandles[idx])
698 m_objectHandles[idx]->apply(*this);
699}
700
701//
702//
703//
704
705void KWmf::opPenCreateIndirect(
706 U32 /*words*/,
707 TQDataStream &operands)
708{
709 static TQt::PenStyle styleTab[] =
710 {
711 TQt::SolidLine,
712 TQt::DashLine,
713 TQt::DotLine,
714 TQt::DashDotLine,
715 TQt::DashDotDotLine,
716 TQt::NoPen,
717 TQt::SolidLine, // PS_INSIDEFRAME
718 TQt::SolidLine, // PS_USERSTYLE
719 TQt::SolidLine // PS_ALTERNATE
720 };
721 WinObjPenHandle *handle = handleCreatePen();
722 S16 arg;
723 S32 colour;
724
725 operands >> arg;
726 if (arg >= 0 && arg < 8)
727 {
728 handle->m_style = styleTab[arg];
729 }
730 else
731 {
732 kdError(s_area) << "createPenIndirect: invalid pen " << arg << endl;
733 handle->m_style = TQt::SolidLine;
734 }
735 operands >> arg;
736 handle->m_width = arg;
737 operands >> arg >> colour;
738 handle->m_colour = getColour(colour);
739}
740
741void KWmf::opPie(
742 U32 /*words*/,
743 TQDataStream &operands)
744{
745 genericArc("pie", operands);
746}
747
748void KWmf::opPolygonSetFillMode(
749 U32 /*words*/,
750 TQDataStream &operands)
751{
752 S16 tmp;
753
754 operands >> tmp;
755 m_dc.m_winding = tmp != 0;
756}
757
758void KWmf::opPolygon(
759 U32 /*words*/,
760 TQDataStream &operands)
761{
762 S16 tmp;
763
764 operands >> tmp;
765 TQPointArray points(tmp);
766
767 for (int i = 0; i < tmp; i++)
768 {
769 points.setPoint(i, normalisePoint(operands));
770 }
771 gotPolygon(m_dc, points);
772}
773
774void KWmf::opPolyline(
775 U32 /*words*/,
776 TQDataStream &operands)
777{
778 S16 tmp;
779
780 operands >> tmp;
781 TQPointArray points(tmp);
782
783 for (int i = 0; i < tmp; i++)
784 {
785 points.setPoint(i, normalisePoint(operands));
786 }
787 gotPolyline(m_dc, points);
788}
789
790void KWmf::opRectangle(
791 U32 /*words*/,
792 TQDataStream &operands)
793{
794 TQPoint topLeft;
795 TQSize size;
796
797 topLeft = normalisePoint(operands);
798 size = normaliseSize(operands);
799 TQRect rect(topLeft, size);
800 TQPointArray points(4);
801
802 points.setPoint(0, topLeft);
803 points.setPoint(1, rect.topRight());
804 points.setPoint(2, rect.bottomRight());
805 points.setPoint(3, rect.bottomLeft());
806 gotRectangle(m_dc, points);
807}
808
809void KWmf::opRestoreDc(
810 U32 /*words*/,
811 TQDataStream &operands)
812{
813 S16 pop;
814 S16 i;
815
816 operands >> pop;
817 for (i = 0; i < pop; i++)
818 {
819 m_dc = m_savedDcs.pop();
820 }
821}
822
823void KWmf::opSaveDc(
824 U32 /*words*/,
825 TQDataStream &/*operands*/)
826{
827 m_savedDcs.push(m_dc);
828
829 // TBD: reinitialise m_dc.
830}
831
832void KWmf::opWindowSetOrg(
833 U32 /*words*/,
834 TQDataStream &operands)
835{
836 S16 top;
837 S16 left;
838
839 operands >> top >> left;
840 m_windowOrgX = left;
841 m_windowOrgY = top;
842}
843
844void KWmf::opWindowSetExt(
845 U32 /*words*/,
846 TQDataStream &operands)
847{
848 S16 height;
849 S16 width;
850
851 operands >> height >> width;
852 if (width > 0)
853 m_windowFlipX = 1;
854 else
855 m_windowFlipX = -1;
856 if (height > 0)
857 m_windowFlipY = 1;
858 else
859 m_windowFlipY = -1;
860}
861
862void KWmf::penSet(
863 unsigned colour,
864 unsigned style,
865 unsigned width)
866{
867 m_dc.m_penColour = colour;
868 m_dc.m_penStyle = style;
869 m_dc.m_penWidth = width;
870}
871
872void KWmf::skip(
873 U32 words,
874 TQDataStream &operands)
875{
876 if ((int)words < 0)
877 {
878 kdError(s_area) << "skip: " << (int)words << endl;
879 return;
880 }
881 if (words)
882 {
883 U32 i;
884 S16 discard;
885
886 kdDebug(s_area) << "skip: " << words << endl;
887 for (i = 0; i < words; i++)
888 {
889 operands >> discard;
890 }
891 }
892}
893
894void KWmf::walk(
895 U32 words,
896 TQDataStream &operands)
897{
898 // Read bits:
899 //
900 // struct WmfMetaRecord
901 // {
902 // S32 rdSize; // Record size (in words) of the function
903 // S16 rdFunction; // Record function number
904 // S16 rdParm[1]; // WORD array of parameters
905 // };
906 //
907 // struct WmfEnhMetaRecord
908 // {
909 // S32 iType; // Record type EMR_xxx
910 // S32 nSize; // Record size in bytes
911 // S32 dParm[1]; // DWORD array of parameters
912 // };
913
914 S32 wordCount;
915 S16 opcode;
916 U32 length = 0;
917
918 while (length < words)
919 {
920 operands >> wordCount;
921 operands >> opcode;
922
923 // If we get some duff data, protect ourselves.
924 if (length + wordCount > words)
925 {
926 wordCount = words - length;
927 }
928 length += wordCount;
929 if (opcode == 0)
930 {
931 // This appears to be an EOF marker.
932 break;
933 }
934
935 // Package the arguments...
936
937 invokeHandler(opcode, wordCount - 3, operands);
938 }
939
940 // Eat unexpected data that the caller may expect us to consume.
941 skip(words - length, operands);
942}
943
944KWmf::DrawContext::DrawContext()
945{
946 // TBD: initalise with proper values.
947 m_brushColour = 0x808080;
948 m_brushStyle = 1;
949 m_penColour = 0x808080;
950 m_penStyle = 1;
951 m_penWidth = 1;
952}
953
954void KWmf::WinObjBrushHandle::apply(
955 KWmf &p)
956{
957 p.brushSet(m_colour, m_style);
958}
959
960void KWmf::WinObjPenHandle::apply(
961 KWmf &p)
962{
963 p.penSet(m_colour, m_style, m_width);
964}
const char * name(StdAction id)