home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / wmf.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-28  |  76.4 KB  |  2,585 lines

  1. /* WMF plug-in for The GIMP
  2.  * Copyright (C) 1998 Tor Lillqvist
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  *
  18.  * See http://www.iki.fi/tml/gimp/wmf/
  19.  */
  20.  
  21. #define VERSION "1999-10-30"
  22.  
  23. /* #define DEBUG */
  24.  
  25. #include "config.h"
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30.  
  31. #include <gtk/gtk.h>
  32.  
  33. #include <libgimp/gimp.h>
  34. #include <libgimp/gimpui.h>
  35.  
  36. #include "libgimp/stdplugins-intl.h"
  37.  
  38.  
  39. typedef guchar  BYTE;
  40. typedef guint16 WORD;
  41. typedef guint32 DWORD;
  42.  
  43. typedef gint16 SHORT;
  44. typedef gint32 LONG;
  45.  
  46. /* The following information is from O'Reilly's updates to the
  47.  * Encyclopedia of Graphics File Formats,
  48.  * http://www.ora.com/centers/gff/formats/micmeta/index.htm
  49.  */
  50.  
  51. typedef struct _WindowsMetaHeader
  52. {
  53.   WORD  FileType;       /* Type of metafile (0=memory, 1=disk) */
  54.   WORD  HeaderSize;     /* Size of header in WORDS (always 9) */
  55.   WORD  Version;        /* Version of Microsoft Windows used */
  56.   DWORD FileSize;       /* Total size of the metafile in WORDs */
  57.   WORD  NumOfObjects;   /* Number of objects in the file */
  58.   DWORD MaxRecordSize;  /* The size of largest record in WORDs */
  59.   WORD  NumOfParams;    /* Not Used (always 0) */
  60. } WMFHEAD;
  61.  
  62. #define SIZE_WMFHEAD 18
  63.  
  64. typedef struct _PlaceableMetaHeader
  65. {
  66.   DWORD Key;           /* Magic number (always 9AC6CDD7h) */
  67.   WORD  Handle;        /* Metafile HANDLE number (always 0) */
  68.   SHORT Left;          /* Left coordinate in metafile units */
  69.   SHORT Top;           /* Top coordinate in metafile units */
  70.   SHORT Right;         /* Right coordinate in metafile units */
  71.   SHORT Bottom;        /* Bottom coordinate in metafile units */
  72.   WORD  Inch;          /* Number of metafile units per inch */
  73.   DWORD Reserved;      /* Reserved (always 0) */
  74.   WORD  Checksum;      /* Checksum value for previous 10 WORDs */
  75. } PLACEABLEMETAHEADER;
  76.  
  77. #define SIZE_PLACEABLEMETAHEADER 22
  78.  
  79. typedef struct _Clipboard16MetaHeader
  80. {
  81.   SHORT MappingMode; /* Units used to playback metafile */
  82.   SHORT Width;       /* Width of the metafile */
  83.   SHORT Height;      /* Height of the metafile */
  84.   WORD  Handle;      /* Handle to the metafile in memory */
  85. } CLIPBOARD16METAHEADER;
  86.  
  87. #define SIZE_CLIPBOARD16METAHEADER 8
  88.  
  89. typedef struct _Clipboard32MetaHeader
  90. {
  91.   LONG  MappingMode; /* Units used to playback metafile */
  92.   LONG  Width;       /* Width of the metafile */
  93.   LONG  Height;      /* Height of the metafile */
  94.   DWORD Handle;      /* Handle to the metafile in memory */
  95. } CLIPBOARD32METAHEADER;
  96.  
  97. #define SIZE_CLIPBOARD32METAHEADER 16
  98.  
  99. typedef struct _EnhancedMetaHeader
  100. {
  101.   DWORD RecordType;       /* Record type */
  102.   DWORD RecordSize;       /* Size of the record in bytes */
  103.   LONG  BoundsLeft;       /* Left inclusive bounds */
  104.   LONG  BoundsRight;      /* Right inclusive bounds */
  105.   LONG  BoundsTop;        /* Top inclusive bounds */
  106.   LONG  BoundsBottom;     /* Bottom inclusive bounds */
  107.   LONG  FrameLeft;        /* Left side of inclusive picture frame */
  108.   LONG  FrameRight;       /* Right side of inclusive picture frame */
  109.   LONG  FrameTop;         /* Top side of inclusive picture frame */
  110.   LONG  FrameBottom;      /* Bottom side of inclusive picture frame */
  111.   DWORD Signature;        /* Signature ID (always 0x464D4520) */
  112.   DWORD Version;          /* Version of the metafile */
  113.   DWORD Size;             /* Size of the metafile in bytes */
  114.   DWORD NumOfRecords;     /* Number of records in the metafile */
  115.   WORD  NumOfHandles;     /* Number of handles in the handle table */
  116.   WORD  Reserved;         /* Not used (always 0) */
  117.   DWORD SizeOfDescrip;    /* Size of description string in WORDs */
  118.   DWORD OffsOfDescrip;    /* Offset of description string in metafile */
  119.   DWORD NumPalEntries;    /* Number of color palette entries */
  120.   LONG  WidthDevPixels;   /* Width of reference device in pixels */
  121.   LONG  HeightDevPixels;  /* Height of reference device in pixels */
  122.   LONG  WidthDevMM;       /* Width of reference device in millimeters */
  123.   LONG  HeightDevMM;      /* Height of reference device in millimeters */
  124. } ENHANCEDMETAHEADER;
  125.  
  126. #define SIZE_ENHANCEDMETAHEADER 88
  127.  
  128. typedef struct _StandardMetaRecord
  129. {
  130.   DWORD Size;          /* Total size of the record in WORDs */
  131.   WORD  Function;      /* Function number (defined in WINDOWS.H) */
  132. #if DOCUMENTATION_ONLY_ILLEGAL_C
  133.   WORD  Parameters[]; /* Parameter values passed to function */
  134. #endif
  135. } WMFRECORD;
  136.  
  137. #define SIZE_WMFRECORD 6
  138. #define WORDSIZE_WMFRECORD 3
  139.  
  140. #define EndOfFile        0x0000
  141.  
  142. #define AbortDoc        0x0052
  143. #define Arc            0x0817
  144. #define Chord            0x0830
  145. #define Ellipse            0x0418
  146. #define EndDoc            0x005E
  147. #define EndPage            0x0050
  148. #define ExcludeClipRect        0x0415
  149. #define ExtFloodFill        0x0548
  150. #define FillRegion        0x0228
  151. #define FloodFill        0x0419
  152. #define FrameRegion        0x0429
  153. #define IntersectClipRect    0x0416
  154. #define InvertRegion        0x012A
  155. #define LineTo            0x0213
  156. #define MoveTo            0x0214
  157. #define OffsetClipRgn        0x0220
  158. #define OffsetViewportOrg    0x0211
  159. #define OffsetWindowOrg        0x020F
  160. #define PaintRegion        0x012B
  161. #define PatBlt            0x061D
  162. #define Pie            0x081A
  163. #define RealizePalette        0x0035
  164. #define Rectangle        0x041B
  165. #define ResetDc            0x014C
  166. #define ResizePalette        0x0139
  167. #define RestoreDC        0x0127
  168. #define RoundRect        0x061C
  169. #define SaveDC            0x001E
  170. #define ScaleViewportExt    0x0412
  171. #define ScaleWindowExt        0x0410
  172. #define SelectClipRegion    0x012C
  173. #define SelectObject        0x012D
  174. #define SelectPalette        0x0234
  175. #define SetBkColor        0x0201
  176. #define SetBkMode        0x0102
  177. #define SetDibToDev        0x0d33
  178. #define SetMapMode        0x0103
  179. #define SetMapperFlags        0x0231
  180. #define SetPalEntries        0x0037
  181. #define SetPixel        0x041F
  182. #define SetPolyFillMode        0x0106
  183. #define SetRelabs        0x0105
  184. #define SetROP2            0x0104
  185. #define SetStretchBltMode    0x0107
  186. #define SetTextAlign        0x012E
  187. #define SetTextCharExtra    0x0108
  188. #define SetTextColor        0x0209
  189. #define SetTextJustification    0x020A
  190. #define SetViewportExt        0x020E
  191. #define SetViewportOrg        0x020D
  192. #define SetWindowExt        0x020C
  193. #define SetWindowOrg        0x020B
  194. #define StartDoc        0x014D
  195. #define StartPage        0x004F
  196.  
  197. #define AnimatePalette        0x0436
  198. #define BitBlt            0x0922
  199. #define CreateBitmap        0x06FE
  200. #define CreateBitmapIndirect    0x02FD
  201. #define CreateBrush        0x00F8
  202. #define CreateBrushIndirect    0x02FC
  203. #define CreateFontIndirect    0x02FB
  204. #define CreatePalette        0x00F7
  205. #define CreatePatternBrush    0x01F9
  206. #define CreatePenIndirect    0x02FA
  207. #define CreateRegion        0x06FF
  208. #define DeleteObject        0x01F0
  209. #define DibBitblt        0x0940
  210. #define DibCreatePatternBrush    0x0142
  211. #define DibStretchBlt        0x0B41
  212. #define DrawText        0x062F
  213. #define Escape            0x0626
  214. #define ExtTextOut        0x0A32
  215. #define Polygon            0x0324
  216. #define PolyPolygon        0x0538
  217. #define Polyline        0x0325
  218. #define TextOut            0x0521
  219. #define StretchBlt        0x0B23
  220. #define StretchDIBits        0x0F43
  221.  
  222. typedef struct _RGBTriple
  223. {
  224.   BYTE Red;
  225.   BYTE Green;
  226.   BYTE Blue;
  227. } RGBTRIPLE;
  228.  
  229. typedef struct _BitBltRecord
  230. {
  231.   DWORD     Size;             /* Total size of the record in WORDs */
  232.   WORD      Function;         /* Function number (0x0922) */
  233.   WORD      RasterOp;         /* High-order word for the raster operation */
  234.   WORD      YSrcOrigin;       /* Y-coordinate of the source origin */
  235.   WORD      XSrcOrigin;       /* X-coordinate of the source origin */
  236.   WORD      YDest;            /* Destination width */
  237.   WORD      XDest;            /* Destination height */
  238.   WORD      YDestOrigin;      /* Y-coordinate of the destination origin */
  239.   WORD      XDestOrigin;      /* X-coordinate of the destination origin */
  240.   /* DDB Bitmap */
  241.   DWORD     Width;            /* Width of bitmap in pixels */
  242.   DWORD     Height;           /* Height of bitmap in scan lines */
  243.   DWORD     BytesPerLine;     /* Number of bytes in each scan line */
  244.   WORD      NumColorPlanes;   /* Number of color planes in the bitmap */
  245.   WORD      BitsPerPixel;     /* Number of bits in each pixel */
  246. #if DOCUMENTATION_ONLY_ILLEGAL_C
  247.   RGBTRIPLE Bitmap[];         /* Bitmap data */
  248. #endif
  249. } BITBLTRECORD;
  250.  
  251. typedef struct _RGBQuad
  252. {
  253.   BYTE Red;
  254.   BYTE Green;
  255.   BYTE Blue;
  256.   BYTE Reserved;
  257. } RGBQUAD;
  258.  
  259. typedef struct _DibBitBltRecord
  260. {
  261.   DWORD   Size;             /* Total size of the record in WORDs */
  262.   WORD    Function;         /* Function number (0x0940) */
  263.   WORD    RasterOp;         /* High-order word for the raster operation */
  264.   WORD    YSrcOrigin;       /* Y-coordinate of the source origin */
  265.   WORD    XSrcOrigin;       /* X-coordinate of the source origin */
  266.   WORD    YDest;            /* Destination width */
  267.   WORD    XDest;            /* Destination height */
  268.   WORD    YDestOrigin;      /* Y-coordinate of the destination origin */
  269.   WORD    XDestOrigin;      /* X-coordinate of the destination origin */
  270.   /* DIB Bitmap */
  271.   DWORD   Width;            /* Width of bitmap in pixels */
  272.   DWORD   Height;           /* Height of bitmap in scan lines */
  273.   DWORD   BytesPerLine;     /* Number of bytes in each scan line */
  274.   WORD    NumColorPlanes;   /* Number of color planes in the bitmap */
  275.   WORD    BitsPerPixel;     /* Number of bits in each pixel */
  276.   DWORD   Compression;      /* Compression type */
  277.   DWORD   SizeImage;        /* Size of bitmap in bytes */
  278.   LONG    XPelsPerMeter;    /* Width of image in pixels per meter */
  279.   LONG    YPelsPerMeter;    /* Height of image in pixels per meter */
  280.   DWORD   ClrUsed;          /* Number of colors used */
  281.   DWORD   ClrImportant;     /* Number of important colors */
  282. #if DOCUMENTATION_ONLY_ILLEGAL_C
  283.   RGBQUAD Bitmap[];         /* Bitmap data */
  284. #endif
  285. } DIBBITBLTRECORD;
  286.  
  287. typedef struct _EnhancedMetaRecord
  288. {
  289.   DWORD Function;      /* Function number (defined in WINGDI.H) */
  290.   DWORD Size;          /* Total size of the record in WORDs */
  291. #if DOCUMENTATION_ONLY_ILLEGAL_C
  292.   DWORD Parameters[];   /* Parameter values passed to GDI function */
  293. #endif
  294. } EMFRECORD;
  295.  
  296. #define EMR_ABORTPATH        68
  297. #define EMR_POLYLINE        4
  298. #define EMR_ANGLEARC        41
  299. #define EMR_POLYLINE16        87
  300. #define EMR_ARC            45
  301. #define EMR_POLYLINETO        6
  302. #define EMR_ARCTO        55
  303. #define EMR_POLYLINETO16    89
  304. #define EMR_BEGINPATH        59
  305. #define EMR_POLYPOLYGON        8
  306. #define EMR_BITBLT        76
  307. #define EMR_POLYPOLYGON16    91
  308. #define EMR_CHORD        46
  309. #define EMR_POLYPOLYLINE    7
  310. #define EMR_CLOSEFIGURE        61
  311. #define EMR_POLYPOLYLINE16    90
  312. #define EMR_CREATEBRUSHINDIRECT    39
  313. #define EMR_POLYTEXTOUTA    96
  314. #define EMR_CREATEDIBPATTERNBRUSHPT 94
  315. #define EMR_POLYTEXTOUTW    97
  316. #define EMR_CREATEMONOBRUSH    93
  317. #define EMR_REALIZEPALETTE    52
  318. #define EMR_CREATEPALETTE    49
  319. #define EMR_RECTANGLE        43
  320.  
  321. #define EMR_CREATEPEN        38
  322. #define EMR_RESIZEPALETTE    51
  323. #define EMR_DELETEOBJECT    40
  324. #define EMR_RESTOREDC        34
  325. #define EMR_ELLIPSE        42
  326. #define EMR_ROUNDRECT        44
  327. #define EMR_ENDPATH        60
  328. #define EMR_SAVEDC        33
  329. #define EMR_EOF            14
  330. #define EMR_SCALEVIEWPORTEXTEX    31
  331. #define EMR_EXCLUDECLIPRECT    29
  332. #define EMR_SCALEWINDOWEXTEX    32
  333. #define EMR_EXTCREATEFONTINDIRECTW 82
  334. #define EMR_SELECTCLIPPATH    67
  335. #define EMR_EXTCREATEPEN    95
  336. #define EMR_SELECTOBJECT    37
  337. #define EMR_EXTFLOODFILL    53
  338. #define EMR_SELECTPALETTE    48
  339. #define EMR_EXTSELECTCLIPRGN    75
  340. #define EMR_SETARCDIRECTION    57
  341. #define EMR_EXTTEXTOUTA        83
  342. #define EMR_SETBKCOLOR        25
  343.  
  344. #define EMR_EXTTEXTOUTW        84
  345. #define EMR_SETBKMODE        18
  346. #define EMR_FILLPATH        62
  347. #define EMR_SETBRUSHORGEX    13
  348. #define EMR_FILLRGN        71
  349. #define EMR_SETCOLORADJUSTMENT    23
  350. #define EMR_FLATTENPATH        65
  351. #define EMR_SETDIBITSTODEVICE    80
  352. #define EMR_FRAMERGN        72
  353. #define EMR_SETMAPMODE        17
  354. #define EMR_GDICOMMENT        70
  355. #define EMR_SETMAPPERFLAGS    16
  356. #define EMR_HEADER        1
  357. #define EMR_SETMETARGN        28
  358. #define EMR_INTERSECTCLIPRECT    30
  359. #define EMR_SETMITERLIMIT    58
  360. #define EMR_INVERTRGN        73
  361. #define EMR_SETPALETTEENTRIES    50
  362. #define EMR_LINETO        54
  363. #define EMR_SETPIXELV        15
  364. #define EMR_MASKBLT        78
  365. #define EMR_SETPOLYFILLMODE    19
  366. #define EMR_MODIFYWORLDTRANSFORM 36
  367. #define EMR_SETROP2        20
  368.  
  369. #define EMR_MOVETOEX        27
  370. #define EMR_SETSTRETCHBLTMODE    21
  371. #define EMR_OFFSETCLIPRGN    26
  372. #define EMR_SETTEXTALIGN    22
  373. #define EMR_PAINTRGN        74
  374. #define EMR_SETTEXTCOLOR    24
  375. #define EMR_PIE            47
  376. #define EMR_SETVIEWPORTEXTEX    11
  377. #define EMR_PLGBLT        79
  378. #define EMR_SETVIEWPORTORGEX    12
  379. #define EMR_POLYBEZIER        2
  380. #define EMR_SETWINDOWEXTEX    9
  381. #define EMR_POLYBEZIER16    85
  382. #define EMR_SETWINDOWORGEX    10
  383. #define EMR_POLYBEZIERTO    5
  384. #define EMR_SETWORLDTRANSFORM    35
  385. #define EMR_POLYBEZIERTO16    88
  386. #define EMR_STRETCHBLT        77
  387. #define EMR_POLYDRAW        56
  388. #define EMR_STRETCHDIBITS    81
  389. #define EMR_POLYDRAW16        92
  390. #define EMR_STROKEANDFILLPATH    63
  391.  
  392. #define EMR_POLYGON        3
  393. #define EMR_STROKEPATH        64
  394. #define EMR_POLYGON16        86
  395. #define EMR_WIDENPATH        66
  396.  
  397. typedef struct _PaletteEntry
  398. {
  399.   BYTE Red;       /* Red component value */
  400.   BYTE Green;     /* Green component value */
  401.   BYTE Blue;      /* Blue component value */
  402.   BYTE Flags;     /* Flag values */
  403. } PALENT;
  404.  
  405. typedef struct _EndOfRecord
  406. {
  407.   DWORD  Function;        /* End Of Record ID (14) */
  408.   DWORD  Size;            /* Total size of the record in WORDs */
  409.   DWORD  NumPalEntries;   /* Number of color palette entries */
  410.   DWORD  OffPalEntries;   /* Offset of color palette entries */
  411. #if DOCUMENTATION_ONLY_ILLEGAL_C
  412.   PALENT Palette[];       /* The color palette data */
  413.   DWORD  OffToEOF;        /* Offset to beginning of this record */
  414. #endif
  415. } ENDOFRECORD;
  416.  
  417. typedef struct _GdiCommentRecord
  418. {
  419.   DWORD   Function;      /* GDI Comment ID (70) */
  420.   DWORD   Size;          /* Total size of the record in WORDs */
  421.   DWORD   SizeOfData;    /* Size of comment data in bytes */
  422. #if DOCUMENTATION_ONLY_ILLEGAL_C
  423.   BYTE    Data[];        /* Comment data */        
  424. #endif
  425. } GDICOMMENTRECORD;
  426.  
  427. typedef struct _GdiCommentMetafile
  428. {
  429.   DWORD Identifier;       /* Comment ID (0x43494447) */
  430.   DWORD Comment;          /* Metafile ID (0x80000001) */
  431.   DWORD Version;          /* Version of the metafile */
  432.   DWORD Checksum;         /* Checksum value of the metafile */
  433.   DWORD Flags;            /* Flags (always 0) */
  434.   DWORD Size;             /* Size of the metafile data in bytes */
  435. } GDICOMMENTMETAFILE;
  436.  
  437. typedef struct _GdiCommentBeginGroup
  438. {
  439.   DWORD Identifier;       /* Comment ID (0x43494447) */
  440.   DWORD Comment;          /* BeginGroup ID (0x00000002) */
  441.   LONG  BoundsLeft;       /* Left side of bounding rectangle */
  442.   LONG  BoundsRight;      /* Right side of bounding rectangle */
  443.   LONG  BoundsTop;        /* Top side of bounding rectangle */
  444.   LONG  BoundsBottom;     /* Bottom side of bounding rectangle */
  445.   DWORD SizeOfDescrip;    /* Number of characters in the description */     
  446. } GDICOMMENTBEGINGROUP;
  447.  
  448. typedef struct _GdiCommentEndGroup
  449. {
  450.   DWORD Identifier;       /* Comment ID (0x43494447) */
  451.   DWORD Comment;          /* EndGroup ID (0x00000003) */
  452. } GDICOMMENTENDGROUP;
  453.  
  454. typedef struct _EmrFormat
  455. {
  456.   DWORD Signature;    /* Format signature */
  457.   DWORD Version;      /* Format version number */
  458.   DWORD Data;         /* Size of data in bytes */
  459.   DWORD OffsetToData; /* Offset to data */
  460. } EMRFORMAT;
  461.  
  462. typedef struct _GdiCommentMultiFormats
  463. {
  464.   DWORD Identifier;       /* Comment ID (0x43494447) */
  465.   DWORD Comment;          /* Multiformats ID (0x40000004) */
  466.   LONG  BoundsLeft;       /* Left side of bounding rectangle */
  467.   LONG  BoundsRight;      /* Right side of bounding rectangle */
  468.   LONG  BoundsTop;        /* Top side of bounding rectangle */
  469.   LONG  BoundsBottom;     /* Bottom side of bounding rectangle */
  470.   DWORD NumFormats;       /* Number of formats in comment */
  471. #if DOCUMENTATION_ONLY_ILLEGAL_C
  472.   EMRFORMAT Data[];       /* Array of comment data */
  473. #endif
  474. } GDICOMMENTMULTIFORMATS;
  475.  
  476. /* Binary raster ops */
  477. #define R2_BLACK            1
  478. #define R2_NOTMERGEPEN      2
  479. #define R2_MASKNOTPEN       3
  480. #define R2_NOTCOPYPEN       4
  481. #define R2_MASKPENNOT       5
  482. #define R2_NOT              6
  483. #define R2_XORPEN           7
  484. #define R2_NOTMASKPEN       8
  485. #define R2_MASKPEN          9
  486. #define R2_NOTXORPEN       10
  487. #define R2_NOP             11
  488. #define R2_MERGENOTPEN     12
  489. #define R2_COPYPEN         13
  490. #define R2_MERGEPENNOT     14
  491. #define R2_MERGEPEN        15
  492. #define R2_WHITE           16
  493.  
  494. /* Background mix modes */
  495. #define TRANSPARENT        1
  496. #define OPAQUE            2
  497.  
  498. /* Brush styles */
  499. #define BS_SOLID            0
  500. #define BS_NULL             1
  501. #define BS_HATCHED          2
  502. #define BS_PATTERN          3
  503. #define BS_DIBPATTERN       5
  504. #define BS_DIBPATTERNPT     6
  505. #define BS_PATTERN8X8       7
  506. #define BS_DIBPATTERN8X8    8
  507. #define BS_MONOPATTERN      9
  508.  
  509. /* Pen styles */
  510. #define PS_SOLID            0
  511. #define PS_DASH             1
  512. #define PS_DOT              2
  513. #define PS_DASHDOT          3
  514. #define PS_DASHDOTDOT       4
  515. #define PS_NULL             5
  516. #define PS_INSIDEFRAME      6
  517.  
  518. /* Polygon fill modes */
  519. #define ALTERNATE        1
  520. #define WINDING            2
  521.  
  522. /* Modes for SetMapMode */
  523. #define MM_TEXT             1
  524. #define MM_LOMETRIC         2
  525. #define MM_HIMETRIC         3
  526. #define MM_LOENGLISH        4
  527. #define MM_HIENGLISH        5
  528. #define MM_TWIPS            6
  529. #define MM_ISOTROPIC        7
  530. #define MM_ANISOTROPIC      8
  531.  
  532.  
  533. #define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
  534.  
  535. #define NPARMWORDS 16
  536.  
  537. #ifndef G_BYTE_ORDER        /* Development glib has byte sex stuff,
  538.                  * but if we're on 1.0, use something else
  539.                  */
  540.  
  541. #define G_LITTLE_ENDIAN 1234
  542. #define G_BIG_ENDIAN    4321
  543.  
  544. #if defined(__i386__)
  545. #define G_BYTE_ORDER G_LITTLE_ENDIAN
  546. #elif defined(__hppa) || defined(__sparc)
  547. #define G_BYTE_ORDER G_BIG_ENDIAN
  548. #else
  549. #error set byte order by hand by adding your machine above
  550. #endif
  551.  
  552. /* This is straight from the newest glib.h */
  553.  
  554. /* Basic bit swapping functions
  555.  */
  556. #define GUINT16_SWAP_LE_BE_CONSTANT(val)    ((guint16) ( \
  557.     (((guint16) (val) & (guint16) 0x00ffU) << 8) | \
  558.     (((guint16) (val) & (guint16) 0xff00U) >> 8)))
  559. #define GUINT32_SWAP_LE_BE_CONSTANT(val)    ((guint32) ( \
  560.     (((guint32) (val) & (guint32) 0x000000ffU) << 24) | \
  561.     (((guint32) (val) & (guint32) 0x0000ff00U) <<  8) | \
  562.     (((guint32) (val) & (guint32) 0x00ff0000U) >>  8) | \
  563.     (((guint32) (val) & (guint32) 0xff000000U) >> 24)))
  564.  
  565. /* Intel specific stuff for speed
  566.  */
  567. #if defined (__i386__) && (defined __GNUC__)
  568.  
  569. #  define GUINT16_SWAP_LE_BE_X86(val) \
  570.      (__extension__                        \
  571.       ({ register guint16 __v;                    \
  572.      if (__builtin_constant_p (val))            \
  573.        __v = GUINT16_SWAP_LE_BE_CONSTANT (val);        \
  574.      else                            \
  575.        __asm__ __volatile__ ("rorw $8, %w0"            \
  576.                  : "=r" (__v)            \
  577.                  : "0" ((guint16) (val))    \
  578.                  : "cc");            \
  579.     __v; }))
  580.  
  581. #  define GUINT16_SWAP_LE_BE(val) \
  582.      ((guint16) GUINT16_SWAP_LE_BE_X86 ((guint16) (val)))
  583.  
  584. #  if !defined(__i486__) && !defined(__i586__) \
  585.       && !defined(__pentium__) && !defined(__pentiumpro__) && !defined(__i686__)
  586. #     define GUINT32_SWAP_LE_BE_X86(val) \
  587.         (__extension__                        \
  588.          ({ register guint32 __v;                \
  589.         if (__builtin_constant_p (val))            \
  590.           __v = GUINT32_SWAP_LE_BE_CONSTANT (val);        \
  591.       else                            \
  592.         __asm__ __volatile__ ("rorw $8, %w0\n\t"        \
  593.                   "rorl $16, %0\n\t"        \
  594.                   "rorw $8, %w0"        \
  595.                   : "=r" (__v)            \
  596.                   : "0" ((guint32) (val))    \
  597.                   : "cc");            \
  598.     __v; }))
  599.  
  600. #  else /* 486 and higher has bswap */
  601. #     define GUINT32_SWAP_LE_BE_X86(val) \
  602.         (__extension__                        \
  603.          ({ register guint32 __v;                \
  604.         if (__builtin_constant_p (val))            \
  605.           __v = GUINT32_SWAP_LE_BE_CONSTANT (val);        \
  606.       else                            \
  607.         __asm__ __volatile__ ("bswap %0"            \
  608.                   : "=r" (__v)            \
  609.                   : "0" ((guint32) (val)));    \
  610.     __v; }))
  611. #  endif /* processor specific 32-bit stuff */
  612.  
  613. #  define GUINT32_SWAP_LE_BE(val) \
  614.      ((guint32) GUINT32_SWAP_LE_BE_X86 ((guint32) (val)))
  615.  
  616. #else /* !__i386__ */
  617. #  define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
  618. #  define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val))
  619. #endif /* __i386__ */
  620.  
  621. #ifdef HAVE_GINT64
  622. #define GUINT64_SWAP_LE_BE(val)         ((guint64) ( \
  623.     (((guint64) (val) & (guint64) 0x00000000000000ffU) << 56) | \
  624.     (((guint64) (val) & (guint64) 0x000000000000ff00U) << 40) | \
  625.     (((guint64) (val) & (guint64) 0x0000000000ff0000U) << 24) | \
  626.     (((guint64) (val) & (guint64) 0x00000000ff000000U) <<  8) | \
  627.     (((guint64) (val) & (guint64) 0x000000ff00000000U) >>  8) | \
  628.     (((guint64) (val) & (guint64) 0x0000ff0000000000U) >> 24) | \
  629.     (((guint64) (val) & (guint64) 0x00ff000000000000U) >> 40) | \
  630.     (((guint64) (val) & (guint64) 0xff00000000000000U) >> 56)))
  631. #endif
  632.  
  633. #define GUINT16_SWAP_LE_PDP(val)    ((guint16) (val))
  634. #define GUINT16_SWAP_BE_PDP(val)    (GUINT16_SWAP_LE_BE (val))
  635. #define GUINT32_SWAP_LE_PDP(val)    ((guint32) ( \
  636.     (((guint32) (val) & (guint32) 0x0000ffffU) << 16) | \
  637.     (((guint32) (val) & (guint32) 0xffff0000U) >> 16)))
  638. #define GUINT32_SWAP_BE_PDP(val)    ((guint32) ( \
  639.     (((guint32) (val) & (guint32) 0x00ff00ffU) << 8) | \
  640.     (((guint32) (val) & (guint32) 0xff00ff00U) >> 8)))
  641.  
  642. #if G_BYTE_ORDER == G_LITTLE_ENDIAN
  643. #  define GINT16_TO_LE(val)        ((gint16) (val))
  644. #  define GUINT16_TO_LE(val)        ((guint16) (val))
  645. #  define GINT16_TO_BE(val)        ((gint16) GUINT16_SWAP_LE_BE (val))
  646. #  define GUINT16_TO_BE(val)        (GUINT16_SWAP_LE_BE (val))
  647. #  define GINT16_FROM_LE(val)        ((gint16) (val))
  648. #  define GUINT16_FROM_LE(val)        ((guint16) (val))
  649. #  define GINT16_FROM_BE(val)        ((gint16) GUINT16_SWAP_LE_BE (val))
  650. #  define GUINT16_FROM_BE(val)        (GUINT16_SWAP_LE_BE (val))
  651. #  define GINT32_TO_LE(val)        ((gint32) (val))
  652. #  define GUINT32_TO_LE(val)        ((guint32) (val))
  653. #  define GINT32_TO_BE(val)        ((gint32) GUINT32_SWAP_LE_BE (val))
  654. #  define GUINT32_TO_BE(val)        (GUINT32_SWAP_LE_BE (val))
  655. #  define GINT32_FROM_LE(val)        ((gint32) (val))
  656. #  define GUINT32_FROM_LE(val)        ((guint32) (val))
  657. #  define GINT32_FROM_BE(val)        ((gint32) GUINT32_SWAP_LE_BE (val))
  658. #  define GUINT32_FROM_BE(val)        (GUINT32_SWAP_LE_BE (val))
  659. #  ifdef HAVE_GINT64
  660. #  define GINT64_TO_LE(val)        ((gint64) (val))
  661. #  define GUINT64_TO_LE(val)        ((guint64) (val))
  662. #  define GINT64_TO_BE(val)        ((gint64) GUINT64_SWAP_LE_BE (val))
  663. #  define GUINT64_TO_BE(val)        (GUINT64_SWAP_LE_BE (val))
  664. #  define GINT64_FROM_LE(val)        ((gint64) (val))
  665. #  define GUINT64_FROM_LE(val)        ((guint64) (val))
  666. #  define GINT64_FROM_BE(val)        ((gint64) GUINT64_SWAP_LE_BE (val))
  667. #  define GUINT64_FROM_BE(val)        (GUINT64_SWAP_LE_BE (val))
  668. #  endif
  669. #elif G_BYTE_ORDER == G_BIG_ENDIAN
  670. #  define GINT16_TO_BE(val)        ((gint16) (val))
  671. #  define GUINT16_TO_BE(val)        ((guint16) (val))
  672. #  define GINT16_TO_LE(val)        ((gint16) GUINT16_SWAP_LE_BE (val))
  673. #  define GUINT16_TO_LE(val)        (GUINT16_SWAP_LE_BE (val))
  674. #  define GINT16_FROM_BE(val)        ((gint16) (val))
  675. #  define GUINT16_FROM_BE(val)        ((guint16) (val))
  676. #  define GINT16_FROM_LE(val)        ((gint16) GUINT16_SWAP_LE_BE (val))
  677. #  define GUINT16_FROM_LE(val)        (GUINT16_SWAP_LE_BE (val))
  678. #  define GINT32_TO_BE(val)        ((gint32) (val))
  679. #  define GUINT32_TO_BE(val)        ((guint32) (val))
  680. #  define GINT32_TO_LE(val)        ((gint32) GUINT32_SWAP_LE_BE (val))
  681. #  define GUINT32_TO_LE(val)        (GUINT32_SWAP_LE_BE (val))
  682. #  define GINT32_FROM_BE(val)        ((gint32) (val))
  683. #  define GUINT32_FROM_BE(val)        ((guint32) (val))
  684. #  define GINT32_FROM_LE(val)        ((gint32) GUINT32_SWAP_LE_BE (val))
  685. #  define GUINT32_FROM_LE(val)        (GUINT32_SWAP_LE_BE (val))
  686. #  ifdef HAVE_GINT64
  687. #  define GINT64_TO_BE(val)        ((gint64) (val))
  688. #  define GUINT64_TO_BE(val)        ((guint64) (val))
  689. #  define GINT64_TO_LE(val)        ((gint64) GUINT64_SWAP_LE_BE (val))
  690. #  define GUINT64_TO_LE(val)        (GUINT64_SWAP_LE_BE (val))
  691. #  define GINT64_FROM_BE(val)        ((gint64) (val))
  692. #  define GUINT64_FROM_BE(val)        ((guint64) (val))
  693. #  define GINT64_FROM_LE(val)        ((gint64) GUINT64_SWAP_LE_BE (val))
  694. #  define GUINT64_FROM_LE(val)        (GUINT64_SWAP_LE_BE (val))
  695. #  endif
  696. #else
  697. /* PDP stuff not implemented */
  698. #endif
  699.  
  700. #if (SIZEOF_LONG == 8)
  701. #  define GLONG_TO_LE(val)        ((glong) GINT64_TO_LE (val))
  702. #  define GULONG_TO_LE(val)        ((gulong) GUINT64_TO_LE (val))
  703. #  define GLONG_TO_BE(val)        ((glong) GINT64_TO_BE (val))
  704. #  define GULONG_TO_BE(val)        ((gulong) GUINT64_TO_BE (val))
  705. #  define GLONG_FROM_LE(val)        ((glong) GINT64_FROM_LE (val))
  706. #  define GULONG_FROM_LE(val)        ((gulong) GUINT64_FROM_LE (val))
  707. #  define GLONG_FROM_BE(val)        ((glong) GINT64_FROM_BE (val))
  708. #  define GULONG_FROM_BE(val)        ((gulong) GUINT64_FROM_BE (val))
  709. #elif (SIZEOF_LONG == 4)
  710. #  define GLONG_TO_LE(val)        ((glong) GINT32_TO_LE (val))
  711. #  define GULONG_TO_LE(val)        ((gulong) GUINT32_TO_LE (val))
  712. #  define GLONG_TO_BE(val)        ((glong) GINT32_TO_BE (val))
  713. #  define GULONG_TO_BE(val)        ((gulong) GUINT32_TO_BE (val))
  714. #  define GLONG_FROM_LE(val)        ((glong) GINT32_FROM_LE (val))
  715. #  define GULONG_FROM_LE(val)        ((gulong) GUINT32_FROM_LE (val))
  716. #  define GLONG_FROM_BE(val)        ((glong) GINT32_FROM_BE (val))
  717. #  define GULONG_FROM_BE(val)        ((gulong) GUINT32_FROM_BE (val))
  718. #endif
  719.  
  720. #if (SIZEOF_INT == 8)
  721. #  define GINT_TO_LE(val)        ((gint) GINT64_TO_LE (val))
  722. #  define GUINT_TO_LE(val)        ((guint) GUINT64_TO_LE (val))
  723. #  define GINT_TO_BE(val)        ((gint) GINT64_TO_BE (val))
  724. #  define GUINT_TO_BE(val)        ((guint) GUINT64_TO_BE (val))
  725. #  define GINT_FROM_LE(val)        ((gint) GINT64_FROM_LE (val))
  726. #  define GUINT_FROM_LE(val)        ((guint) GUINT64_FROM_LE (val))
  727. #  define GINT_FROM_BE(val)        ((gint) GINT64_FROM_BE (val))
  728. #  define GUINT_FROM_BE(val)        ((guint) GUINT64_FROM_BE (val))
  729. #elif (SIZEOF_INT == 4)
  730. #  define GINT_TO_LE(val)        ((gint) GINT32_TO_LE (val))
  731. #  define GUINT_TO_LE(val)        ((guint) GUINT32_TO_LE (val))
  732. #  define GINT_TO_BE(val)        ((gint) GINT32_TO_BE (val))
  733. #  define GUINT_TO_BE(val)        ((guint) GUINT32_TO_BE (val))
  734. #  define GINT_FROM_LE(val)        ((gint) GINT32_FROM_LE (val))
  735. #  define GUINT_FROM_LE(val)        ((guint) GUINT32_FROM_LE (val))
  736. #  define GINT_FROM_BE(val)        ((gint) GINT32_FROM_BE (val))
  737. #  define GUINT_FROM_BE(val)        ((guint) GUINT32_FROM_BE (val))
  738. #elif (SIZEOF_INT == 2)
  739. #  define GINT_TO_LE(val)        ((gint) GINT16_TO_LE (val))
  740. #  define GUINT_TO_LE(val)        ((guint) GUINT16_TO_LE (val))
  741. #  define GINT_TO_BE(val)        ((gint) GINT16_TO_BE (val))
  742. #  define GUINT_TO_BE(val)        ((guint) GUINT16_TO_BE (val))
  743. #  define GINT_FROM_LE(val)        ((gint) GINT16_FROM_LE (val))
  744. #  define GUINT_FROM_LE(val)        ((guint) GUINT16_FROM_LE (val))
  745. #  define GINT_FROM_BE(val)        ((gint) GINT16_FROM_BE (val))
  746. #  define GUINT_FROM_BE(val)        ((guint) GUINT16_FROM_BE (val))
  747. #endif
  748.  
  749. #endif
  750.  
  751. typedef struct
  752. {
  753.   double scale;
  754. } WMFLoadVals;
  755.  
  756. static WMFLoadVals load_vals =
  757. {
  758.   1.0                /* scale */
  759. };
  760.  
  761. typedef struct
  762. {
  763.   gint run;
  764. } WMFLoadInterface;
  765.  
  766. static WMFLoadInterface load_interface =
  767. {
  768.   FALSE
  769. };
  770.  
  771. typedef struct
  772. {
  773.   GtkWidget *dialog;
  774.   GtkAdjustment *scale;
  775. } LoadDialogVals;
  776.  
  777. typedef enum
  778. {
  779.   OBJ_BITMAP,
  780.   OBJ_BRUSH,
  781.   OBJ_PATTERNBRUSH,
  782.   OBJ_FONT,
  783.   OBJ_PEN,
  784.   OBJ_REGION,
  785.   OBJ_PALETTE
  786. } ObjectType;
  787.  
  788. typedef struct
  789. {
  790.   int dummy;
  791. } BitmapObject;
  792.  
  793. typedef struct
  794. {
  795.   GdkColor color;
  796.   gboolean invisible;
  797.   guint style;
  798.   glong hatch;
  799. } BrushObject;
  800.  
  801. typedef struct
  802. {
  803.   int dummy;
  804. } PatternBrushObject;
  805.  
  806. typedef struct
  807. {
  808.   GdkColor color;
  809.   gboolean invisible;
  810.   gushort width;
  811.   GdkLineStyle style;
  812. } PenObject;
  813.  
  814. typedef struct
  815. {
  816.   GdkFont *font;
  817. } FontObject;
  818.  
  819. typedef struct
  820. {
  821.   int dummy;
  822. } PaletteObject;
  823.  
  824. typedef struct
  825. {
  826.   ObjectType type;
  827.   union
  828.   {
  829.     BitmapObject bitmap;
  830.     BrushObject brush;
  831.     PatternBrushObject pbrush;
  832.     PenObject pen;
  833.     FontObject font;
  834.     PaletteObject palette;
  835.   } u;
  836. } Object;
  837.  
  838. typedef struct
  839. {
  840.   GdkGC *gc;
  841.   GdkColor bg;
  842.   BrushObject *brush;
  843.   PenObject *pen;
  844.   FontObject *font;
  845.   GdkColor textColor;
  846.   gint tag;
  847. } DC;
  848.  
  849. static gint saved_dc_tag = 1;
  850.  
  851. typedef struct
  852. {
  853.   GdkPixmap *pixmap;
  854.   DC dc;
  855.   GSList *dc_stack;
  856.   GdkColormap *colormap;
  857.   guint width, height;
  858.   double scalex, scaley;
  859.   double curx, cury;
  860. } Canvas;
  861.  
  862. typedef struct
  863. {
  864.   gboolean valid;
  865.   gint org_x, org_y;
  866.   gint ext_x, ext_y;
  867. } OrgAndExt;
  868.  
  869. static void   query      (void);
  870. static void   run        (gchar   *name,
  871.                           gint     nparams,
  872.                           GimpParam  *param,
  873.                           gint    *nreturn_vals,
  874.                           GimpParam **return_vals);
  875. static gint32 load_image (gchar   *filename);
  876.  
  877. static gint readparams (DWORD  size,
  878.             guint  nparams,
  879.             FILE  *fd,
  880.             WORD  *params);
  881.  
  882. static void sync_record (DWORD  size,
  883.              guint  nparams,
  884.              FILE  *fd);
  885.  
  886. GimpPlugInInfo PLUG_IN_INFO =
  887. {
  888.   NULL,  /* init_proc  */
  889.   NULL,  /* quit_proc  */
  890.   query, /* query_proc */
  891.   run,   /* run_proc   */
  892. };
  893.  
  894. static GimpRunModeType l_run_mode;
  895.  
  896. static int pixs_per_in;
  897.  
  898. static void
  899. load_ok_callback (GtkWidget *widget,
  900.                   gpointer   data)
  901.  
  902. {
  903.   LoadDialogVals *vals = (LoadDialogVals *)data;
  904.  
  905.   /* Read scale */
  906.   load_vals.scale = pow (2.0, vals->scale->value);
  907.  
  908.   load_interface.run = TRUE;
  909.   gtk_widget_destroy (GTK_WIDGET (vals->dialog));
  910. }
  911.  
  912. static gint
  913. load_dialog (gchar *file_name)
  914. {
  915.   LoadDialogVals *vals;
  916.   GtkWidget *frame;
  917.   GtkWidget *vbox;
  918.   GtkWidget *label;
  919.   GtkWidget *table;
  920.   GtkWidget *slider;
  921.  
  922.   gimp_ui_init ("wmf", FALSE);
  923.  
  924.   vals = g_new (LoadDialogVals, 1);
  925.  
  926.   vals->dialog = gimp_dialog_new ( _("Load Windows Metafile"), "wmf",
  927.                   gimp_standard_help_func, "filters/wmf.html",
  928.                   GTK_WIN_POS_MOUSE,
  929.                   FALSE, TRUE, FALSE,
  930.  
  931.                   _("OK"), load_ok_callback,
  932.                   vals, NULL, NULL, TRUE, FALSE,
  933.                   _("Cancel"), gtk_widget_destroy,
  934.                   NULL, 1, NULL, FALSE, TRUE,
  935.  
  936.                   NULL);
  937.  
  938.   gtk_signal_connect (GTK_OBJECT (vals->dialog), "destroy",
  939.                       GTK_SIGNAL_FUNC (gtk_main_quit),
  940.                       NULL);
  941.  
  942.   /* Rendering */
  943.   frame = gtk_frame_new (g_strdup_printf ( _("Rendering %s"), file_name));
  944.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  945.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  946.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dialog)->vbox), frame,
  947.               TRUE, TRUE, 0);
  948.  
  949.   vbox = gtk_vbox_new (FALSE, 4);
  950.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  951.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  952.  
  953.   /* Scale label */
  954.   table = gtk_table_new (1, 2, FALSE);
  955.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  956.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  957.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  958.   gtk_widget_show (table);
  959.  
  960.   label = gtk_label_new ( _("Scale (log 2):"));
  961.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
  962.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
  963.             GTK_FILL, GTK_FILL, 0, 0);
  964.   gtk_widget_show (label);
  965.  
  966.   /* Scale slider */
  967.   vals->scale = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, -2.0, 2.0, 0.2, 0.2, 0.0));
  968.   slider = gtk_hscale_new (vals->scale);
  969.   gtk_table_attach (GTK_TABLE (table), slider, 1, 2, 0, 1,
  970.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  971.   gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
  972.   gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
  973.   gtk_widget_show (slider);
  974.  
  975.   gtk_widget_show (vbox);
  976.   gtk_widget_show (frame);
  977.  
  978.   gtk_widget_show (vals->dialog);
  979.  
  980.   gtk_main ();
  981.   gdk_flush ();
  982.  
  983.   g_free (vals);
  984.  
  985.   return load_interface.run;
  986. }
  987.  
  988. static void
  989. check_load_vals (void)
  990. {
  991.   if (load_vals.scale < 0.01)
  992.     load_vals.scale = 0.01;
  993.   else if (load_vals.scale > 100.)
  994.     load_vals.scale = 100.;
  995. }
  996.  
  997. MAIN ()
  998.  
  999. static void
  1000. query (void)
  1001. {
  1002.   static GimpParamDef load_args[] =
  1003.   {
  1004.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  1005.     { GIMP_PDB_STRING, "filename", "The name of the file to load" },
  1006.     { GIMP_PDB_STRING, "raw_filename", "The name entered" }
  1007.   };
  1008.   static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
  1009.  
  1010.   static GimpParamDef load_return_vals[] =
  1011.   {
  1012.     { GIMP_PDB_IMAGE, "image", "Output image" }
  1013.   };
  1014.   static gint nload_return_vals = (sizeof (load_return_vals) /
  1015.                    sizeof (load_return_vals[0]));
  1016.  
  1017.   static GimpParamDef load_setargs_args[] =
  1018.   {
  1019.     { GIMP_PDB_FLOAT, "scale", "Scale in which to load image" }
  1020.   };
  1021.   static gint nload_setargs_args = (sizeof (load_setargs_args) /
  1022.                     sizeof (load_setargs_args[0]));
  1023.  
  1024.   gimp_install_procedure ("file_wmf_load",
  1025.                           "loads files of the Windows(tm) metafile file format",
  1026.                           "FIXME: write help for file_wmf_load",
  1027.                           "Tor Lillqvist <tml@iki.fi>",
  1028.                           "Tor Lillqvist",
  1029.                           "1998",
  1030.                           "<Load>/WMF",
  1031.               NULL,
  1032.                           GIMP_PLUGIN,
  1033.                           nload_args, nload_return_vals,
  1034.                           load_args, load_return_vals);
  1035.  
  1036.   gimp_install_procedure ("file_wmf_load_setargs",
  1037.               "set additional parameters for the procedure file_wmf_load",
  1038.               "set additional parameters for the procedure file_wmf_load",
  1039.               "Tor Lillqvist <tml@iki.fi>",
  1040.                           "Tor Lillqvist",
  1041.                           "1998",
  1042.               NULL,
  1043.               NULL,
  1044.               GIMP_PLUGIN,
  1045.               nload_setargs_args, 0,
  1046.               load_setargs_args, NULL);
  1047.   
  1048.   gimp_register_magic_load_handler ("file_wmf_load",
  1049.                     "wmf,apm",
  1050.                     "",
  1051.                     "0,string,\\327\\315\\306\\232");
  1052. }
  1053.  
  1054. static void
  1055. run (gchar   *name,
  1056.      gint     nparams,
  1057.      GimpParam  *param,
  1058.      gint    *nreturn_vals,
  1059.      GimpParam **return_vals)
  1060. {
  1061.   static GimpParam values[2];
  1062.   GimpPDBStatusType   status = GIMP_PDB_SUCCESS;
  1063.   gint32        image_ID;
  1064.  
  1065.   l_run_mode = param[0].data.d_int32;
  1066.  
  1067.   *nreturn_vals = 1;
  1068.   *return_vals  = values;
  1069.   values[0].type          = GIMP_PDB_STATUS;
  1070.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  1071.  
  1072.   if (strcmp (name, "file_wmf_load") == 0)
  1073.     {
  1074.       switch (l_run_mode)
  1075.     {
  1076.     case GIMP_RUN_INTERACTIVE:
  1077.       INIT_I18N_UI();
  1078.       gimp_get_data ("file_wmf_load", &load_vals);
  1079.  
  1080.       if (!load_dialog (param[1].data.d_string))
  1081.         status = GIMP_PDB_CANCEL;
  1082.       break;
  1083.       
  1084.     case GIMP_RUN_NONINTERACTIVE:
  1085.       INIT_I18N();
  1086.       gimp_get_data ("file_wmf_load", &load_vals);
  1087.       break;
  1088.  
  1089.     case GIMP_RUN_WITH_LAST_VALS:
  1090.       INIT_I18N();
  1091.       gimp_get_data ("file_wmf_load", &load_vals);
  1092.  
  1093.     default:
  1094.       break;
  1095.     }
  1096.  
  1097.       if (status == GIMP_PDB_SUCCESS)
  1098.     {
  1099.       check_load_vals ();
  1100.       
  1101.       image_ID = load_image (param[1].data.d_string);
  1102.       
  1103.       if (image_ID != -1)
  1104.         {
  1105.           gimp_set_data ("file_wmf_load", &load_vals, sizeof (load_vals));
  1106.           
  1107.           *nreturn_vals = 2;
  1108.           values[1].type         = GIMP_PDB_IMAGE;
  1109.           values[1].data.d_image = image_ID;
  1110.         }
  1111.       else
  1112.         {
  1113.           status = GIMP_PDB_EXECUTION_ERROR;
  1114.         }
  1115.     }
  1116.     }
  1117.   else
  1118.     {
  1119.       status = GIMP_PDB_CALLING_ERROR;
  1120.     }
  1121.  
  1122.   values[0].data.d_status = status;
  1123. }
  1124.  
  1125. static Object *
  1126. new_object (ObjectType type,
  1127.         Object **objects,
  1128.         const int nobjects)
  1129. {
  1130.   gint i;
  1131.   Object *result = NULL;
  1132.  
  1133.   for (i = 0; i < nobjects; i++)
  1134.     if (objects[i] == NULL)
  1135.       {
  1136.     objects[i] = result = g_new (Object, 1);
  1137.     result->type = type;
  1138.     break;
  1139.       }
  1140.   if (i == nobjects)
  1141.     g_message ("WMF: Creating too many objects");
  1142.  
  1143.   return result;
  1144. }
  1145.  
  1146. static Canvas *
  1147. make_canvas (OrgAndExt *window,
  1148.          OrgAndExt *viewport,
  1149.          gboolean have_bbox,
  1150.          GdkRectangle *bbox,
  1151.          guint units_per_in)
  1152. {
  1153.   Canvas *canvas = g_new (Canvas, 1);
  1154.  
  1155.   if (!window->valid)
  1156.     {
  1157. #ifdef DEBUG
  1158.       g_print ("make_canvas: !window->valid\n");
  1159. #endif
  1160.       if (have_bbox)
  1161.     {
  1162. #ifdef DEBUG
  1163.       g_print ("make_canvas: have_bbox\n");
  1164. #endif
  1165.       window->org_x = bbox->x;
  1166.       window->ext_x = bbox->width;
  1167.       window->org_y = bbox->y;
  1168.       window->ext_y = bbox->height;
  1169.     }
  1170.       else
  1171.     {
  1172.       window->org_x = window->org_y = 0;
  1173.       /* Just pick a size. */
  1174.       window->ext_x = units_per_in * 4;
  1175.       window->ext_y = units_per_in * 3;
  1176.     }
  1177.       window->valid = TRUE;
  1178.     }
  1179.  
  1180.   canvas->scalex = canvas->scaley = load_vals.scale;
  1181.   
  1182.   if (!viewport->valid)
  1183.     {
  1184. #ifdef DEBUG
  1185.       g_print ("make_canvas: !viewport->valid\n");
  1186. #endif
  1187.       viewport->org_x = viewport->org_y = 0;
  1188.       viewport->ext_x = canvas->scalex * fabs (window->ext_x) / units_per_in * pixs_per_in;
  1189.       viewport->ext_y = canvas->scaley * fabs (window->ext_y) / units_per_in * pixs_per_in;
  1190.       viewport->valid = TRUE;
  1191.     }
  1192. #ifdef DEBUG
  1193.   g_print ("make_canvas: w: (%d,%d)--(%d,%d), vp: (%d,%d)--(%d,%d)\n",
  1194.        window->org_x, window->org_y, window->org_x + window->ext_x, window->org_y + window->ext_y, 
  1195.        viewport->org_x, viewport->org_y,
  1196.        viewport->org_x + viewport->ext_x, viewport->org_y + viewport->ext_y);
  1197. #endif
  1198.  
  1199.   canvas->colormap = gdk_colormap_get_system ();
  1200.  
  1201.   canvas->width = viewport->ext_x;
  1202.   canvas->height = viewport->ext_y;
  1203.  
  1204.   canvas->pixmap = gdk_pixmap_new (NULL, viewport->ext_x, viewport->ext_y,
  1205.                    gdk_visual_get_system ()->depth);
  1206.  
  1207.   canvas->dc.gc = gdk_gc_new (canvas->pixmap);
  1208.  
  1209.   canvas->dc.bg.red =
  1210.     canvas->dc.bg.green =
  1211.     canvas->dc.bg.blue = 0xFFFF;
  1212.   gdk_color_alloc (canvas->colormap, &canvas->dc.bg);
  1213.  
  1214.   canvas->dc.brush = g_new (BrushObject, 1);
  1215.   canvas->dc.brush->invisible = FALSE;
  1216.   canvas->dc.brush->color.red =
  1217.     canvas->dc.brush->color.green =
  1218.     canvas->dc.brush->color.blue = 0xFFFF;
  1219.   gdk_color_alloc (canvas->colormap, &canvas->dc.brush->color);
  1220.  
  1221.   canvas->dc.pen = g_new (PenObject, 1);
  1222.   canvas->dc.pen->invisible = FALSE;
  1223.   canvas->dc.pen->color.red =
  1224.     canvas->dc.pen->color.green =
  1225.     canvas->dc.pen->color.blue = 0;
  1226.   gdk_color_alloc (canvas->colormap, &canvas->dc.pen->color);
  1227.  
  1228.   canvas->dc.font = g_new (FontObject, 1);
  1229.   canvas->dc.font->font = gdk_font_load ("-adobe-helvetica-medium-r-normal--*-120-*-*-*-*-*-*");
  1230.  
  1231.   canvas->dc.textColor.red =
  1232.     canvas->dc.textColor.green =
  1233.     canvas->dc.textColor.blue = 0;
  1234.   gdk_color_alloc (canvas->colormap, &canvas->dc.textColor);
  1235.  
  1236.   canvas->dc_stack = g_slist_alloc ();
  1237.  
  1238.   gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.brush->color);
  1239.   gdk_draw_rectangle (canvas->pixmap, canvas->dc.gc, TRUE, 0, 0,
  1240.               viewport->ext_x, viewport->ext_y);
  1241.  
  1242.   canvas->curx = canvas->cury = 0.0;
  1243.  
  1244.   return canvas;
  1245. }
  1246.  
  1247. static void
  1248. set_color (WORD *params,
  1249.        GdkColor *color)
  1250. {
  1251.   color->red = ((GUINT16_FROM_LE (params[0]) & 0x00FF) * 65535) / 255;
  1252.   color->green = (((GUINT16_FROM_LE (params[0]) & 0xFF00) >> 8) * 65535) / 255;
  1253.   color->blue = ((GUINT16_FROM_LE (params[1]) & 0x00FF) * 65535) / 255;
  1254. }
  1255.  
  1256. static gint32
  1257. load_image (char *filename)
  1258. {
  1259.   FILE *fp;
  1260.   char *name_buf;
  1261.   guchar buffer[100];
  1262.   gboolean warned_unhandled = FALSE;
  1263.   gboolean warned_opaque = FALSE;
  1264.   gboolean warned_orientation = FALSE;
  1265.   WMFHEAD wmf_head;
  1266.   PLACEABLEMETAHEADER apm_head;
  1267.   WMFRECORD record;
  1268.   WORD params[NPARMWORDS];
  1269.   Object **objects, *objp = NULL;
  1270.   guint nobjects;
  1271.   guint units_per_in;
  1272.  
  1273.   guint i, j, jj, k;
  1274.   gint ix;
  1275.   guchar *string;
  1276.   guint record_counter = 0;
  1277.   GdkRectangle bbox;
  1278.   gboolean have_bbox = FALSE;
  1279.   OrgAndExt window, viewport;
  1280.  
  1281. #define XSCALE(value) ((value) * (double) viewport.ext_x / window.ext_x)
  1282. #define YSCALE(value) ((value) * (double) viewport.ext_y / window.ext_y)
  1283.  
  1284. #define XMAPPAR(param) (XSCALE (GINT16_FROM_LE (param) - window.org_x) + viewport.org_x)
  1285. #define YMAPPAR(param) (YSCALE (GINT16_FROM_LE (param) - window.org_y) + viewport.org_y)
  1286. #define XMAPPARPLUS1(param) (XSCALE ((GINT16_FROM_LE (param) + 1) - window.org_x) + viewport.org_x)
  1287. #define YMAPPARPLUS1(param) (YSCALE ((GINT16_FROM_LE (param) + 1) - window.org_y) + viewport.org_y)
  1288.  
  1289. #define XIMAPPAR(param) ((gint) XMAPPAR (param))
  1290. #define YIMAPPAR(param) ((gint) YMAPPAR (param))
  1291. #define XIMAPPARPLUS1(param) ((gint) XMAPPARPLUS1 (param))
  1292. #define YIMAPPARPLUS1(param) ((gint) YMAPPARPLUS1 (param))
  1293.  
  1294.   Canvas *canvas = NULL;
  1295.   GdkGCValues gc_values;
  1296.   DC *dc;
  1297.   GdkVisual *visual;
  1298.   GdkPoint *points;
  1299.   double x, y;
  1300.   guint npoints;
  1301.   guint npolys;
  1302.   guint *nppoints;
  1303.   GdkImage *image;
  1304.   guint options;
  1305.  
  1306.   GimpPixelRgn pixel_rgn;
  1307.   gint32 image_ID = -1;
  1308.   gint32 layer_ID;
  1309.   GimpDrawable *drawable;
  1310.   guchar *pixelp;
  1311.   gulong pixel;
  1312.   guint start, end, scanlines;
  1313.   guchar *buf, *bufp;
  1314.   GdkColor *colors;
  1315.   guchar *rtbl, *gtbl, *btbl;
  1316.   guint rmask, gmask, bmask, rshift, gshift, bshift;
  1317.  
  1318.   int argc;
  1319.   char **argv;
  1320.  
  1321.   argc = 1;
  1322.   argv = g_new (char*, 1);
  1323.   argv[0] = g_strdup ("wmf");
  1324.  
  1325.   gdk_init (&argc, &argv);
  1326.  
  1327.   fp = fopen (filename, "rb");
  1328.   if (!fp)
  1329.     {
  1330.       g_message ("WMF: can't open \"%s\"", filename);
  1331.       return -1;
  1332.     }
  1333.  
  1334.   name_buf = g_strdup_printf ( _("Interpreting %s:"), filename);
  1335.   gimp_progress_init (name_buf);
  1336.   g_free (name_buf);
  1337.  
  1338.   if (!ReadOK (fp, buffer, SIZE_WMFHEAD))
  1339.     {
  1340.       g_message ("WMF: Failed to read metafile header");
  1341.       return -1;
  1342.     }
  1343.  
  1344.   g_memmove (&apm_head.Key, buffer, 4);
  1345.   
  1346.   if (GUINT32_FROM_LE (apm_head.Key) == 0x9ac6cdd7)
  1347.     {
  1348.       if (!ReadOK (fp, buffer + SIZE_WMFHEAD,
  1349.            SIZE_PLACEABLEMETAHEADER - SIZE_WMFHEAD))
  1350.     {
  1351.       g_message ("WMF: Failed to read placeable metafile header");
  1352.       return -1;
  1353.     }
  1354.       g_memmove (&apm_head.Left, buffer + 6, 2);
  1355.       g_memmove (&apm_head.Top, buffer + 8, 2);
  1356.       g_memmove (&apm_head.Right, buffer + 10, 2);
  1357.       g_memmove (&apm_head.Bottom, buffer + 12, 2);
  1358.       g_memmove (&apm_head.Inch, buffer + 14, 2);
  1359.       bbox.x = GINT16_FROM_LE (apm_head.Left);
  1360.       bbox.y = GINT16_FROM_LE (apm_head.Top);
  1361.       bbox.width = GUINT16_FROM_LE (apm_head.Right) - bbox.x;
  1362.       bbox.height = GUINT16_FROM_LE (apm_head.Bottom) - bbox.y;
  1363.       have_bbox = TRUE;
  1364.       units_per_in = GUINT16_FROM_LE (apm_head.Inch);
  1365.  
  1366. #ifdef DEBUG
  1367.       g_print ("placeable metafile header: (%d,%d)--(%d,%d), bbox: %dx%d@+%d+%d\n",
  1368.            apm_head.Left, apm_head.Top, apm_head.Right, apm_head.Bottom,
  1369.            bbox.width, bbox.height, bbox.x, bbox.y);
  1370.       g_print ("units_per_in: %d\n", units_per_in);
  1371. #endif
  1372.       if (!ReadOK (fp, buffer, SIZE_WMFHEAD))
  1373.     {
  1374.       g_message ("WMF: Failed to read metafile header");
  1375.       return -1;
  1376.     }
  1377.     }
  1378.   else
  1379.     {
  1380.       units_per_in = 1440;
  1381.     }
  1382.   viewport.org_x = viewport.org_y = 0;
  1383.   viewport.valid = FALSE;
  1384.   window.org_x = window.org_y = 0;
  1385.   window.valid = FALSE;
  1386.  
  1387. #ifdef GTK_HAVE_FEATURES_1_1_2
  1388.   pixs_per_in = (int) (25.4 * gdk_screen_width () / gdk_screen_width_mm ());
  1389. #else
  1390.   pixs_per_in = 72;
  1391. #endif
  1392. #ifdef DEBUG
  1393.   g_print ("pixs_per_in: %d\n", pixs_per_in);
  1394. #endif
  1395.   g_memmove (&wmf_head.Version, buffer + 4, 2);
  1396.   g_memmove (&wmf_head.FileSize, buffer + 6, 4);
  1397.   g_memmove (&wmf_head.NumOfObjects, buffer + 10, 2);
  1398.  
  1399.   if (GUINT16_FROM_LE (wmf_head.Version) != 0x0300)
  1400.     {
  1401.       g_message ("WMF: Metafile has wrong version, got %#x, expected 0x300",
  1402.          GUINT16_FROM_LE (wmf_head.Version));
  1403.       return -1;
  1404.     }
  1405.  
  1406.   nobjects = GUINT16_FROM_LE (wmf_head.NumOfObjects);
  1407.   objects = g_new (Object*, nobjects);
  1408.   for (i = 0; i < nobjects; i++)
  1409.     objects[i] = NULL;
  1410.  
  1411.   while (1)
  1412.     {
  1413.       if (!ReadOK (fp, buffer, SIZE_WMFRECORD))
  1414.     {
  1415.       g_message ("WMF: Failed to read metafile record");
  1416.       return -1;
  1417.     }
  1418.       g_memmove (&record.Size, buffer, 4);
  1419.       g_memmove (&record.Function, buffer + 4, 2);
  1420.       record_counter++;
  1421. #ifdef DEBUG
  1422.       g_print ("%#x %d\n", GUINT16_FROM_LE (record.Function), GUINT32_FROM_LE (record.Size));
  1423. #endif
  1424.       switch (GUINT16_FROM_LE (record.Function))
  1425.     {
  1426.     case SetWindowOrg:
  1427.       if (!readparams (record.Size, 2, fp, params))
  1428.         return -1;
  1429.       window.org_y = GINT16_FROM_LE (params[0]);
  1430.       window.org_x = GINT16_FROM_LE (params[1]);
  1431.       sync_record (record.Size, 2, fp);
  1432.       break;
  1433.  
  1434.     case SetViewportOrg:
  1435.       if (!readparams (record.Size, 2, fp, params))
  1436.         return -1;
  1437.       viewport.org_y = GINT16_FROM_LE (params[0]);
  1438.       viewport.org_x = GINT16_FROM_LE (params[1]);
  1439.       sync_record (record.Size, 2, fp);
  1440.       break;
  1441.  
  1442.     case SetWindowExt:
  1443.       if (!readparams (record.Size, 2, fp, params))
  1444.         return -1;
  1445.       window.ext_y = GINT16_FROM_LE (params[0]);
  1446.       window.ext_x = GINT16_FROM_LE (params[1]);
  1447.       window.valid = TRUE;
  1448.       sync_record (record.Size, 2, fp);
  1449.       break;
  1450.  
  1451.     case SetViewportExt:
  1452.       if (!readparams (record.Size, 2, fp, params))
  1453.         return -1;
  1454.       viewport.ext_y = GINT16_FROM_LE (params[0]);
  1455.       viewport.ext_x = GINT16_FROM_LE (params[1]);
  1456.       viewport.valid = TRUE;
  1457.       sync_record (record.Size, 2, fp);
  1458.       break;
  1459.  
  1460.     case IntersectClipRect:
  1461.       if (!readparams (record.Size, 4, fp, params))
  1462.         return -1;
  1463.       /* XXX */
  1464.       sync_record (record.Size, 4, fp);
  1465.       break;
  1466.       
  1467.     case SaveDC:
  1468.       dc = g_new (DC, 1);
  1469.       if (canvas == NULL)
  1470.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1471.       *dc = canvas->dc;
  1472.       dc->gc = gdk_gc_new (canvas->pixmap);
  1473.       dc->tag = saved_dc_tag++;
  1474.       gdk_gc_copy (dc->gc, canvas->dc.gc);
  1475.       gdk_font_ref (dc->font->font);
  1476.       canvas->dc_stack = g_slist_prepend (canvas->dc_stack, dc);
  1477.       sync_record (record.Size, 0, fp);
  1478.       break;
  1479.  
  1480.     case RestoreDC:
  1481.       if (!readparams (record.Size, 1, fp, params))
  1482.         return -1;
  1483.       ix = GINT16_FROM_LE (params[0]);
  1484.       if (ix >= 0)
  1485.         {
  1486.           fclose (fp);
  1487.           g_message ("WMF: RestoreDC with positive argument (%d)?", ix);
  1488.           return -1;
  1489.         }
  1490.       while (ix++ < 0)
  1491.         {
  1492.           if (canvas->dc_stack == NULL)
  1493.         {
  1494.           fclose (fp);
  1495.           g_message ("WMF: DC stack underflow");
  1496.           return -1;
  1497.         }
  1498.           gdk_gc_unref (canvas->dc.gc);
  1499.           gdk_font_unref (canvas->dc.font->font);
  1500.           canvas->dc = *((DC *) canvas->dc_stack->data);
  1501.           canvas->dc_stack = g_slist_next (canvas->dc_stack);
  1502.         }
  1503.       sync_record (record.Size, 1, fp);
  1504.       break;
  1505.  
  1506.     case SetBkColor:
  1507.       if (!readparams (record.Size, 2, fp, params))
  1508.         return -1;
  1509.       if (canvas == NULL)
  1510.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1511.       set_color (params + 0, &canvas->dc.bg);
  1512. #ifdef DEBUG
  1513.       g_print ("SetBkColor: %d %d %d\n", canvas->dc.bg.red,
  1514.            canvas->dc.bg.green, canvas->dc.bg.blue);
  1515. #endif
  1516.       if (!gdk_color_alloc (canvas->colormap, &canvas->dc.bg))
  1517.         {
  1518.           fclose (fp);
  1519.           g_message ("WMF: Couldn't allocate color");
  1520.           return -1;
  1521.         }
  1522. #ifdef DEBUG
  1523.       g_print ("...allocated color %#.06lx\n", canvas->dc.bg.pixel);
  1524. #endif
  1525.       sync_record (record.Size, 2, fp);
  1526.       break;
  1527.  
  1528.     case SetBkMode:
  1529.       if (!readparams (record.Size, 1, fp, params))
  1530.         return -1;
  1531.       switch (GINT16_FROM_LE (params[0]))
  1532.         {
  1533.         case TRANSPARENT:
  1534.           break;
  1535.         case OPAQUE:
  1536.           if (!warned_opaque)
  1537.         {
  1538.           g_message ("The WMF file contains SetBkMode (OPAQUE).\n"
  1539.                  "This is not supported, sorry. The resulting\n"
  1540.                  "image might not look quite right.");
  1541.           warned_opaque = TRUE;
  1542.         }
  1543.           break;
  1544.         default:
  1545.           fclose (fp);
  1546.           g_message ("WMF: Invalid case %d at line %d",
  1547.              GINT16_FROM_LE (params[0]), __LINE__);
  1548.           break;
  1549.         }
  1550.       sync_record (record.Size, 1, fp);
  1551.       break;
  1552.  
  1553.     case SetTextColor:
  1554.       if (!readparams (record.Size, 2, fp, params))
  1555.         return -1;
  1556.       if (canvas == NULL)
  1557.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1558.       set_color (params + 0, &canvas->dc.textColor);
  1559. #ifdef DEBUG
  1560.       g_print ("SetTextColor: %d %d %d\n", canvas->dc.textColor.red,
  1561.            canvas->dc.textColor.green, canvas->dc.textColor.blue);
  1562. #endif
  1563.       if (!gdk_color_alloc (canvas->colormap, &canvas->dc.textColor))
  1564.         {
  1565.           fclose (fp);
  1566.           g_message ("WMF: Couldn't allocate color");
  1567.           return -1;
  1568.         }
  1569. #ifdef DEBUG
  1570.       g_print ("...allocated color %#.06lx\n", canvas->dc.textColor.pixel);
  1571. #endif
  1572.       sync_record (record.Size, 2, fp);
  1573.       break;
  1574.  
  1575.     case SetTextAlign:
  1576.       if (!readparams (record.Size, 1, fp, params))
  1577.         return -1;
  1578.       /* XXX */
  1579.       sync_record (record.Size, 1, fp);
  1580.       break;
  1581.  
  1582.     case SetROP2:
  1583.       if (!readparams (record.Size, 1, fp, params))
  1584.         return -1;
  1585.       if (canvas == NULL)
  1586.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1587.       switch (GUINT16_FROM_LE (params[0]))
  1588.         {
  1589.         case R2_COPYPEN:
  1590.           gdk_gc_set_function (canvas->dc.gc, GDK_COPY); break;
  1591.         case R2_NOT:
  1592.           gdk_gc_set_function (canvas->dc.gc, GDK_INVERT); break;
  1593.         case R2_XORPEN:
  1594.           gdk_gc_set_function (canvas->dc.gc, GDK_XOR); break;
  1595. #ifdef GDK_CLEAR        /* Other ROPs not in gdk 1.0 */
  1596.         case R2_BLACK:
  1597.           gdk_gc_set_function (canvas->dc.gc, GDK_CLEAR); break;
  1598.         case R2_MASKPEN:
  1599.           gdk_gc_set_function (canvas->dc.gc, GDK_AND); break;
  1600.         case R2_MASKPENNOT:
  1601.           gdk_gc_set_function (canvas->dc.gc, GDK_AND_REVERSE); break;
  1602.         case R2_MASKNOTPEN:
  1603.           gdk_gc_set_function (canvas->dc.gc, GDK_AND_INVERT); break;
  1604.         case R2_NOP:
  1605.           gdk_gc_set_function (canvas->dc.gc, GDK_NOOP); break;
  1606.         case R2_MERGEPEN:
  1607.           gdk_gc_set_function (canvas->dc.gc, GDK_OR); break;
  1608.         case R2_NOTXORPEN:
  1609.           gdk_gc_set_function (canvas->dc.gc, GDK_EQUIV); break;
  1610.         case R2_MERGEPENNOT:
  1611.           gdk_gc_set_function (canvas->dc.gc, GDK_OR_REVERSE); break;
  1612.         case R2_NOTCOPYPEN:
  1613.           gdk_gc_set_function (canvas->dc.gc, GDK_COPY_INVERT); break;
  1614.         case R2_MERGENOTPEN:
  1615.           gdk_gc_set_function (canvas->dc.gc, GDK_OR_INVERT); break;
  1616.         case R2_NOTMASKPEN:
  1617.           gdk_gc_set_function (canvas->dc.gc, GDK_NAND); break;
  1618.         case R2_WHITE:
  1619.           gdk_gc_set_function (canvas->dc.gc, GDK_SET); break;
  1620. #endif
  1621.         default:
  1622.           fclose (fp);
  1623.           g_message ("Invalid ROP2");
  1624.           return -1;
  1625.         }
  1626.       sync_record (record.Size, 1, fp);
  1627.       break;
  1628.  
  1629.     case SetStretchBltMode:
  1630.       if (!readparams (record.Size, 1, fp, params))
  1631.         return -1;
  1632.       /* XXX */
  1633.       sync_record (record.Size, 1, fp);
  1634.       break;
  1635.  
  1636.     case SetPolyFillMode:
  1637.       if (!readparams (record.Size, 1, fp, params))
  1638.         return -1;
  1639.       /* GDK has no way to set the fill rule of a GdkGC! */
  1640.       /* XXX */
  1641.       sync_record (record.Size, 1, fp);
  1642.       break;
  1643.  
  1644.     case SetMapMode:
  1645.       if (!readparams (record.Size, 1, fp, params))
  1646.         return -1;
  1647.       switch (GUINT16_FROM_LE (params[0]))
  1648.         {
  1649.         case MM_ANISOTROPIC:
  1650.         case MM_ISOTROPIC:
  1651.           break;
  1652.  
  1653.         case MM_HIENGLISH:
  1654.           units_per_in = 1000;
  1655.           goto set_window_and_viewport;
  1656.  
  1657.         case MM_HIMETRIC:
  1658.           units_per_in = 2540;
  1659.           goto set_window_and_viewport;
  1660.  
  1661.         case MM_LOENGLISH:
  1662.           units_per_in = 100;
  1663.           goto set_window_and_viewport;
  1664.  
  1665.         case MM_LOMETRIC:
  1666.           units_per_in = 254;
  1667.           goto set_window_and_viewport;
  1668.           
  1669.         case MM_TEXT:
  1670.           units_per_in = pixs_per_in;
  1671.           goto set_window_and_viewport;
  1672.  
  1673.         case MM_TWIPS:
  1674.           units_per_in = 1440;
  1675.  
  1676.         set_window_and_viewport:
  1677.           window.valid = TRUE;
  1678.           viewport.valid = TRUE;
  1679.           window.org_x = window.org_y =
  1680.         viewport.org_x = viewport.org_y = 0;
  1681.           window.ext_x = units_per_in * 4;
  1682.           window.ext_y = units_per_in * 3;
  1683.           viewport.ext_x = load_vals.scale * fabs (window.ext_x) / units_per_in * pixs_per_in;
  1684.           viewport.ext_y = load_vals.scale * fabs (window.ext_y) / units_per_in * pixs_per_in;
  1685.           break;
  1686.  
  1687.         default:
  1688.           fclose (fp);
  1689.           g_message ("WMF: Invalid case %d at line %d",
  1690.              GUINT16_FROM_LE (params[0]), __LINE__);
  1691.           return -1;
  1692.         }
  1693.       sync_record (record.Size, 1, fp);
  1694.       break;
  1695.  
  1696.     case SetRelabs:
  1697.       if (!readparams (record.Size, 1, fp, params))
  1698.         return -1;
  1699.       /* XXX */
  1700.       sync_record (record.Size, 1, fp);
  1701.       break;
  1702.  
  1703.     case CreatePenIndirect:
  1704.       if (!readparams (record.Size, 5, fp, params))
  1705.         return -1;
  1706.       if ((objp = new_object (OBJ_PEN, objects, nobjects)) == NULL)
  1707.         {
  1708.           fclose (fp);
  1709.           return -1;
  1710.         }
  1711.       objp->u.pen.invisible = FALSE;
  1712.       switch (GUINT16_FROM_LE (params[0]))
  1713.         {
  1714.         case PS_SOLID:
  1715.         case PS_INSIDEFRAME:
  1716.           objp->u.pen.style = GDK_LINE_SOLID;
  1717.           break;
  1718.           
  1719.         case PS_DASH:
  1720.         case PS_DOT:
  1721.         case PS_DASHDOT:
  1722.         case PS_DASHDOTDOT:
  1723.           objp->u.pen.style = GDK_LINE_ON_OFF_DASH;
  1724.           break;
  1725.  
  1726.         case PS_NULL:
  1727.           objp->u.pen.style = GDK_LINE_SOLID;
  1728.           objp->u.pen.invisible = TRUE;
  1729.           break;
  1730.  
  1731.         default:
  1732.           g_message ("WMF: Unrecognized pen style %#x",
  1733.              GUINT16_FROM_LE (params[0]));
  1734.           fclose (fp);
  1735.           return -1;
  1736.         }
  1737.       if (canvas == NULL)
  1738.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1739.       objp->u.pen.width = (int) XSCALE (GUINT16_FROM_LE (params[1]) + (GUINT16_FROM_LE (params[2]) << 16));
  1740.       set_color (params+3, &objp->u.pen.color);
  1741. #ifdef DEBUG
  1742.       g_print ("CreatePenIndirect: %#x width %d%s %s color: %d %d %d\n",
  1743.            objp,
  1744.            objp->u.pen.width,
  1745.            (objp->u.pen.invisible ? " invisible" : ""),
  1746.            (objp->u.pen.style == GDK_LINE_SOLID ? "solid" :
  1747.             (objp->u.pen.style == GDK_LINE_ON_OFF_DASH ? "on-off-dash" :
  1748.              (objp->u.pen.style == GDK_LINE_DOUBLE_DASH ? "double-dash" :
  1749.               "???"))),
  1750.            objp->u.pen.color.red,
  1751.            objp->u.pen.color.green,
  1752.            objp->u.pen.color.blue); 
  1753. #endif
  1754.       if (!gdk_color_alloc (canvas->colormap, &objp->u.pen.color))
  1755.         {
  1756.           g_message ("WMF: Couldn't allocate color");
  1757.           fclose (fp);
  1758.           return -1;
  1759.         }
  1760. #ifdef DEBUG
  1761.       g_print ("...allocated color %#.06lx\n", objp->u.pen.color.pixel);
  1762. #endif
  1763.       /* CreatePenIndirect records sometimes have junk padding? */
  1764.       sync_record (record.Size, 5, fp);
  1765.       break;
  1766.  
  1767.     case CreateBrushIndirect:
  1768.       if (!readparams (record.Size, 4, fp, params))
  1769.         return -1;
  1770.       if ((objp = new_object (OBJ_BRUSH, objects, nobjects)) == NULL)
  1771.         {
  1772.           fclose (fp);
  1773.           return -1;
  1774.         }
  1775.       objp->u.brush.style = GUINT16_FROM_LE (params[0]);
  1776.       objp->u.brush.invisible = FALSE;
  1777.       if (objp->u.brush.style == BS_NULL)
  1778.         objp->u.brush.invisible = TRUE;
  1779.       set_color (params+1, &objp->u.brush.color);
  1780. #ifdef DEBUG
  1781.       g_print ("CreateBrushIndirect: %#x%s color: %d %d %d\n",
  1782.            objp,
  1783.            (objp->u.brush.invisible ? " invisible" : ""),
  1784.            objp->u.brush.color.red,
  1785.            objp->u.brush.color.green,
  1786.            objp->u.brush.color.blue); 
  1787. #endif
  1788.       if (canvas == NULL)
  1789.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1790.       if (!gdk_color_alloc (canvas->colormap, &objp->u.brush.color))
  1791.         {
  1792.           g_message ("WMF: Couldn't allocate color");
  1793.           fclose (fp);
  1794.           return -1;
  1795.         }
  1796. #ifdef DEBUG
  1797.       g_print ("...allocated color %#.06lx\n", objp->u.brush.color.pixel);
  1798. #endif
  1799.       objp->u.brush.hatch = GUINT16_FROM_LE (params[3]);
  1800.       sync_record (record.Size, 4, fp);
  1801.       break;
  1802.       
  1803.     case DibCreatePatternBrush:
  1804.       if ((objp = new_object (OBJ_PATTERNBRUSH, objects, nobjects)) == NULL)
  1805.         {
  1806.           fclose (fp);
  1807.           return -1;
  1808.         }
  1809. #ifdef DEBUG
  1810.       g_print ("DibCreatePatternBrush: %#x\n", objp);
  1811. #endif
  1812.       /* Ignored for now */
  1813.       sync_record (record.Size, 0, fp);
  1814.       break;
  1815.       
  1816.     case CreatePalette:
  1817.       if ((objp = new_object (OBJ_PALETTE, objects, nobjects)) == NULL)
  1818.         {
  1819.           fclose (fp);
  1820.           return -1;
  1821.         }
  1822. #ifdef DEBUG
  1823.       g_print ("CreatePalette: %#x\n", objp);
  1824. #endif
  1825.       /* XXX */
  1826.       sync_record (record.Size, 0, fp);
  1827.       break;
  1828.       
  1829.     case CreateFontIndirect:
  1830.       if (!readparams (record.Size, 9, fp, params))
  1831.         return -1;
  1832.       if ((objp = new_object (OBJ_FONT, objects, nobjects)) == NULL)
  1833.         {
  1834.           fclose (fp);
  1835.           return -1;
  1836.         }
  1837.       if (canvas == NULL)
  1838.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1839.       {
  1840.         gint height, orientation, weight, italic, pitch_family;
  1841.         char *pitch, *slant, *fontname, *name, *name2;
  1842.  
  1843.         height = ABS (GINT16_FROM_LE (params[0]));
  1844.         if (height == 0)
  1845.           height = 12;
  1846.         /* Orientation ignored for now. GDK doesn't support
  1847.          * tilted text anyway. We could of course rotate it by hand.
  1848.          */
  1849.         orientation = GUINT16_FROM_LE (params[2]);
  1850.         if (orientation != 0 && !warned_orientation)
  1851.           {
  1852.         g_message ("The WMF file contains non-horizontal fonts.\n"
  1853.                "This is not supported, sorry. The resulting\n"
  1854.                "image will not look quite right.");
  1855.         warned_orientation = TRUE;
  1856.           }
  1857.         weight = GUINT16_FROM_LE (params[4]);
  1858.         italic = (GUINT16_FROM_LE (params[5]) & 0xFF);
  1859. #if 0
  1860.         pitch_family = ((GUINT16_FROM_LE (params[8]) >> 8) & 0xFF);
  1861. #else
  1862.         pitch_family = (GUINT16_FROM_LE (params[8]) & 0xFF);
  1863. #endif
  1864.         if ((pitch_family & 0x03) == 1)
  1865.           pitch = "m";
  1866.         else if ((pitch_family & 0x03) == 2)
  1867.           pitch = "p";
  1868.         else
  1869.           pitch = "*";
  1870.  
  1871.         if (italic)
  1872.           {
  1873.         if ((pitch_family & 0x3) == 1)
  1874.           slant = "o";
  1875.         else
  1876.           slant = "i";
  1877.           }
  1878.         else
  1879.           slant = "r";
  1880.  
  1881.         k = GUINT32_FROM_LE (record.Size) - 9 - WORDSIZE_WMFRECORD;
  1882.         name = g_malloc (k*2 + 1);
  1883.         for (i = 0; i < k*2; i++)
  1884.           {
  1885.         if ((i & 1) == 0)
  1886.           {
  1887.             if (!readparams (0, 1, fp, params))
  1888.               return -1;
  1889.             name[i] = (params[0] & 0xFF);
  1890.           }
  1891.         else
  1892.           name[i] = ((params[0] >> 8) & 0xFF);
  1893.           }
  1894.         name[k*2] = '\0';
  1895.  
  1896. #ifdef DEBUG
  1897.         g_print ("CreateFontIndirect: %#x %s\n", objp, name);
  1898. #endif
  1899.         /* Very rough mapping from typical Windows fonts to
  1900.          * typical X11 fonts. If you run GIMP on Win32,
  1901.          * they will be mapped back to typical Windows
  1902.          * fonts, sigh...
  1903.          */
  1904.         g_strdown (name);
  1905.         if (strcmp (name, "system") == 0
  1906.         || strcmp (name, "fixedsys") == 0)
  1907.           name2 = "courier";
  1908.         else if (strncmp (name, "arial", 5) == 0)
  1909.           name2 = "helvetica";
  1910.         else if (strncmp (name, "courier", 7) == 0)
  1911.           name2 = "courier";
  1912.         else
  1913.           name2 = name;
  1914.         fontname = 
  1915.           g_strdup_printf ("-*-%s-%s-%s-%s-*-%d-*-*-*-%s-*-*-*",
  1916.                    name2,
  1917.                    (weight >= 700 ? "bold" :
  1918.                 (weight >= 400 ? "medium" :
  1919.                  "*")),
  1920.                    slant,
  1921.                    "*",
  1922.                    (int) YSCALE (height),
  1923.                    pitch);
  1924. #ifdef DEBUG
  1925.         g_print ("...XLFD font: %s\n", fontname);
  1926. #endif
  1927.         objp->u.font.font = gdk_font_load (fontname);
  1928.         if (objp->u.font.font == NULL)
  1929.           {
  1930.         g_free (fontname);
  1931.         fontname =
  1932.           g_strdup_printf ("-*-%s-%s-%s-%s-*-%d-*-*-*-%s-*-*-*",
  1933.                    "*",
  1934.                    (weight >= 700 ? "bold" :
  1935.                     (weight >= 400 ? "medium" :
  1936.                      "*")),
  1937.                    "*",
  1938.                    "*",
  1939.                    (int) YSCALE (height),
  1940.                    "*");
  1941. #ifdef DEBUG
  1942.         g_print ("...another XLFD font: %s\n", fontname);
  1943. #endif
  1944.         objp->u.font.font = gdk_font_load (fontname);
  1945.         if (objp->u.font.font == NULL)
  1946.           {
  1947.             fclose (fp);
  1948.             g_message ("WMF: Cannot load suitable font, not even %s",
  1949.                    fontname);
  1950.             return -1;
  1951.           }
  1952.           }
  1953.         g_free (name);
  1954.         g_free (fontname);
  1955.       }
  1956.       break;
  1957.       
  1958.     case SelectObject:
  1959.       if (!readparams (record.Size, 1, fp, params))
  1960.         return -1;
  1961.       k = GUINT16_FROM_LE (params[0]);
  1962.       if (k >= nobjects)
  1963.         {
  1964.           fclose (fp);
  1965.           g_message ("WMF: Selecting out of bounds object index");
  1966.           return -1;
  1967.         }
  1968.       objp = objects[k];
  1969.       if (objp == NULL)
  1970.         {
  1971.           fclose (fp);
  1972.           g_message ("WMF: Selecting NULL object");
  1973.           return -1;
  1974.         }
  1975. #ifdef DEBUG
  1976.       g_print ("SelectObject: %#x %s\n",
  1977.            objp,
  1978.            (objp->type == OBJ_BRUSH ? "brush" :
  1979.             (objp->type == OBJ_PEN ? "pen" :
  1980.              (objp->type == OBJ_PATTERNBRUSH ? "patternbrush" :
  1981.               (objp->type == OBJ_FONT ? "font" :
  1982.                "???")))));
  1983. #endif
  1984.       switch (objp->type)
  1985.         {
  1986.         case OBJ_BRUSH:
  1987.           if (canvas == NULL)
  1988.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1989.           canvas->dc.brush = &objp->u.brush;
  1990.           break;
  1991.  
  1992.         case OBJ_PEN:
  1993.           if (canvas == NULL)
  1994.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1995.           canvas->dc.pen = &objp->u.pen;
  1996.           gdk_gc_get_values (canvas->dc.gc, &gc_values);
  1997.           gdk_gc_set_line_attributes
  1998.         (canvas->dc.gc, objp->u.pen.width, objp->u.pen.style,
  1999.          gc_values.cap_style, gc_values.join_style);
  2000.           break;
  2001.  
  2002.         case OBJ_PATTERNBRUSH:
  2003.           /* XXX */
  2004.           break;
  2005.  
  2006.         case OBJ_FONT:
  2007.           gdk_font_unref (canvas->dc.font->font);
  2008.           canvas->dc.font = &objp->u.font;
  2009.           gdk_font_ref (canvas->dc.font->font);
  2010.           break;
  2011.  
  2012.         default:
  2013.           fclose (fp);
  2014.           g_message ("WMF: Unhandled case %d at line %d",
  2015.              objp->type, __LINE__);
  2016.           return -1;
  2017.         }
  2018.       sync_record (record.Size, 1, fp);
  2019.       break;
  2020.  
  2021.     case SelectPalette:
  2022.       if (!readparams (record.Size, 1, fp, params))
  2023.         return -1;
  2024.       k = GUINT16_FROM_LE (params[0]);
  2025.       if (k >= nobjects)
  2026.         {
  2027.           fclose (fp);
  2028.           g_message ("WMF: Selecting out of bounds palette index");
  2029.           return -1;
  2030.         }
  2031.       objp = objects[k];
  2032.       if (objp == NULL)
  2033.         {
  2034.           fclose (fp);
  2035.           g_message ("WMF: Selecting NULL palette");
  2036.           return -1;
  2037.         }
  2038.       if (objp->type != OBJ_PALETTE)
  2039.         {
  2040.           fclose (fp);
  2041.           g_message ("WMF: SelectPalette selects non-palette");
  2042.           return -1;
  2043.         }
  2044.       /* XXX */
  2045.       sync_record (record.Size, 1, fp);
  2046.       break;
  2047.  
  2048.     case RealizePalette:
  2049.       /* XXX */
  2050.       sync_record (record.Size, 0, fp);
  2051.       break;
  2052.  
  2053.     case DeleteObject:
  2054.       if (!readparams (record.Size, 1, fp, params))
  2055.         return -1;
  2056.       k = GUINT16_FROM_LE (params[0]);
  2057.       if (k >= nobjects)
  2058.         {
  2059.           fclose (fp);
  2060.           g_message ("WMF: Deleting out of bounds object index");
  2061.           return -1;
  2062.         }
  2063.       objp = objects[k];
  2064.       if (objp == NULL)
  2065.         {
  2066.           fclose (fp);
  2067.           g_message ("WMF: Deleting already deleted object");
  2068.           return -1;
  2069.         }
  2070.       if (objp->type == OBJ_FONT)
  2071.         gdk_font_unref (objp->u.font.font);
  2072.       g_free (objp);
  2073.       objects[k] = NULL;
  2074.       break;
  2075.       
  2076.     case MoveTo:
  2077.       if (!readparams (record.Size, 2, fp, params))
  2078.         return -1;
  2079.       if (canvas == NULL)
  2080.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  2081.       canvas->curx = XMAPPAR (params[1]);
  2082.       canvas->cury = YMAPPAR (params[0]);
  2083.       sync_record (record.Size, 2, fp);
  2084.       break;
  2085.  
  2086.     case LineTo:
  2087.       if (!readparams (record.Size, 2, fp, params))
  2088.         return -1;
  2089.       if (canvas == NULL)
  2090.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  2091.       x = XMAPPAR (params[1]);
  2092.       y = YMAPPAR (params[0]);
  2093. #ifdef DEBUG
  2094.       g_print ("LineTo: (%d,%d)--(%d,%d)\n", 
  2095.            (gint) canvas->curx, (gint) canvas->cury,
  2096.            (gint) x, (gint) y);
  2097. #endif
  2098.       gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.pen->color);
  2099.       gdk_draw_line (canvas->pixmap, canvas->dc.gc,
  2100.              (gint) canvas->curx, (gint) canvas->cury,
  2101.              (gint) x, (gint) y);
  2102.       canvas->curx = x;
  2103.       canvas->cury = y;
  2104.       sync_record (record.Size, 2, fp);
  2105.       break;
  2106.  
  2107.     case Polyline:
  2108.       if (!readparams (record.Size, 1, fp, params))
  2109.         return -1;
  2110.       npoints = GUINT16_FROM_LE (params[0]);
  2111.       points = g_new (GdkPoint, npoints);
  2112.       for (i = 0; i < npoints; i++)
  2113.         {
  2114.           if (!readparams (0, 2, fp, params))
  2115.         return -1;
  2116.           points[i].x = XIMAPPAR (params[0]);
  2117.           points[i].y = YIMAPPAR (params[1]);
  2118.         }
  2119.       if (canvas == NULL)
  2120.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  2121.       gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.pen->color);
  2122.       gdk_draw_lines (canvas->pixmap, canvas->dc.gc, points, npoints);
  2123.       g_free (points);
  2124.       break;
  2125.       
  2126.     case Rectangle:
  2127.       if (!readparams (record.Size, 4, fp, params))
  2128.         return -1;
  2129.       if (canvas == NULL)
  2130.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  2131.       if (!canvas->dc.brush->invisible)
  2132.         {
  2133.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.brush->color);
  2134.           gdk_draw_rectangle (canvas->pixmap, canvas->dc.gc, TRUE,
  2135.                   XIMAPPAR (params[3]),
  2136.                   YIMAPPAR (params[2]),
  2137.                   XIMAPPARPLUS1 (params[1]) - XIMAPPAR (params[3]),
  2138.                   YIMAPPARPLUS1 (params[0]) - YIMAPPAR (params[2]));
  2139.         }
  2140.       if (!canvas->dc.pen->invisible)
  2141.         {
  2142.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.pen->color);
  2143.           gdk_draw_rectangle (canvas->pixmap, canvas->dc.gc, FALSE,
  2144.                   XIMAPPAR (params[3]),
  2145.                   YIMAPPAR (params[2]),
  2146.                   XIMAPPARPLUS1 (params[1]) - XIMAPPAR (params[3]),
  2147.                   YIMAPPARPLUS1 (params[0]) - YIMAPPAR (params[2]));
  2148.         }
  2149.       sync_record (record.Size, 4, fp);
  2150.       break;
  2151.  
  2152.     case Ellipse:
  2153.       if (!readparams (record.Size, 4, fp, params))
  2154.         return -1;
  2155.       if (canvas == NULL)
  2156.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  2157.       if (!canvas->dc.brush->invisible)
  2158.         {
  2159.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.brush->color);
  2160.           gdk_draw_arc (canvas->pixmap, canvas->dc.gc, TRUE,
  2161.                 XIMAPPAR (params[3]),
  2162.                 YIMAPPAR (params[2]),
  2163.                 XIMAPPARPLUS1 (params[1]) - XIMAPPAR (params[3]),
  2164.                 YIMAPPARPLUS1 (params[0]) - YIMAPPAR (params[2]),
  2165.                 0, 360 * 64);
  2166.         }
  2167.       if (!canvas->dc.pen->invisible)
  2168.         {
  2169.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.pen->color);
  2170.           gdk_draw_arc (canvas->pixmap, canvas->dc.gc, FALSE,
  2171.                 XIMAPPAR (params[3]),
  2172.                 YIMAPPAR (params[2]),
  2173.                 XIMAPPARPLUS1 (params[1]) - XIMAPPAR (params[3]),
  2174.                 YIMAPPARPLUS1 (params[0]) - YIMAPPAR (params[2]),
  2175.                 0, 360 * 64);
  2176.         }
  2177.       sync_record (record.Size, 4, fp);
  2178.       break;
  2179.  
  2180.     case Polygon:
  2181.       if (!readparams (record.Size, 1, fp, params))
  2182.         return -1;
  2183.       npoints = GUINT16_FROM_LE (params[0]);
  2184.       points = g_new (GdkPoint, npoints);
  2185.       for (i = 0; i < npoints; i++)
  2186.         {
  2187.           if (!readparams (0, 2, fp, params))
  2188.         return -1;
  2189.           points[i].x = XIMAPPAR (params[0]);
  2190.           points[i].y = YIMAPPAR (params[1]);
  2191.         }
  2192.       if (canvas == NULL)
  2193.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  2194.       if (!canvas->dc.brush->invisible)
  2195.         {
  2196.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.brush->color);
  2197.           gdk_draw_polygon (canvas->pixmap, canvas->dc.gc, TRUE, points, npoints);
  2198.         }
  2199.       if (!canvas->dc.pen->invisible)
  2200.         {
  2201.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.pen->color);
  2202.           gdk_draw_polygon (canvas->pixmap, canvas->dc.gc, FALSE, points, npoints);
  2203.         }
  2204.       g_free (points);
  2205.       break;
  2206.  
  2207.     case PolyPolygon:
  2208.       if (!readparams (record.Size, 1, fp, params))
  2209.         return -1;
  2210.       if (canvas == NULL)
  2211.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  2212.       /* Number of polygons */
  2213.       npolys = GUINT16_FROM_LE (params[0]);
  2214.       nppoints = g_new (guint, npolys);
  2215.       for (i = 0; i < npolys; i++)
  2216.         {
  2217.           if (!readparams (0, 1, fp, params))
  2218.         return -1;
  2219.           nppoints[i] = GUINT16_FROM_LE (params[0]);
  2220.         }
  2221.       for (i = 0; i < npolys; i++)
  2222.         {
  2223.           points = g_new (GdkPoint, nppoints[i]);
  2224.           for (j = 0; j < nppoints[i]; j++)
  2225.         {
  2226.           if (!readparams (0, 2, fp, params))
  2227.             return -1;
  2228.           points[j].x = XIMAPPAR (params[0]);
  2229.           points[j].y = YIMAPPAR (params[1]);
  2230.         }
  2231.           if (!canvas->dc.brush->invisible)
  2232.         {
  2233.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.brush->color);
  2234.           gdk_draw_polygon (canvas->pixmap, canvas->dc.gc,
  2235.                     TRUE, points, nppoints[i]);
  2236.         }
  2237.           if (!canvas->dc.pen->invisible)
  2238.         {
  2239.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.pen->color);
  2240.           gdk_draw_polygon (canvas->pixmap, canvas->dc.gc,
  2241.                     TRUE, points, nppoints[i]);
  2242.         }
  2243.           g_free (points);
  2244.         }
  2245.       g_free (nppoints);
  2246.       break;
  2247.  
  2248.     case TextOut:
  2249.       if (!readparams (record.Size, 1, fp, params))
  2250.         return -1;
  2251.       k = GUINT16_FROM_LE (params[0]);
  2252.       string = g_malloc (k);
  2253.       for (i = 0; i < k; i++)
  2254.         {
  2255.           if ((i & 1) == 0)
  2256.         {
  2257.           if (!readparams (0, 1, fp, params))
  2258.             return -1;
  2259.           j++;
  2260.           string[i] = (params[0] & 0xFF);
  2261.         }
  2262.           else
  2263.         string[i] = ((params[0] >> 8) & 0xFF);
  2264.         }
  2265.       if (!readparams (0, 2, fp, params))
  2266.         return -1;
  2267.       x = XMAPPAR (params[1]);
  2268.       y = YMAPPAR (params[0]);
  2269.       gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.textColor);
  2270.       gdk_draw_text (canvas->pixmap, canvas->dc.font->font,
  2271.              canvas->dc.gc, (gint) x, (gint) y, string, k);
  2272.       g_free (string);
  2273.       break;
  2274.  
  2275.     case ExtTextOut:
  2276.       if (!readparams (record.Size, 4, fp, params))
  2277.         return -1;
  2278.       /* Count extra words read */
  2279.       j = 4;
  2280.       x = XMAPPAR (params[1]);
  2281.       y = YMAPPAR (params[0]);
  2282.       /* String length */
  2283.       k = GUINT16_FROM_LE (params[2]);
  2284.       options = GUINT16_FROM_LE (params[3]);
  2285.       /* Clipping or opaquing? */
  2286.       if ((options & 0x04) || (options & 0x02))
  2287.         {
  2288.           GdkRectangle r;
  2289.           if (!readparams (0, 4, fp, params))
  2290.         return -1;
  2291.           j += 4;
  2292.           r.x = XIMAPPARPLUS1 (params[0]);
  2293.           r.y = YIMAPPARPLUS1 (params[1]);
  2294.           r.width = XIMAPPAR (params[2]) - r.x;
  2295.           r.height = YIMAPPARPLUS1 (params[3]) - r.y;
  2296.           if (options & 0x04)
  2297.         gdk_gc_set_clip_rectangle (canvas->dc.gc, &r);
  2298.         }
  2299.       string = g_malloc (k);
  2300.       for (i = 0; i < k; i++)
  2301.         {
  2302.           if ((i & 1) == 0)
  2303.         {
  2304.           if (!readparams (0, 1, fp, params))
  2305.             return -1;
  2306.           j++;
  2307.           string[i] = (params[0] & 0xFF);
  2308.         }
  2309.           else
  2310.         string[i] = ((params[0] >> 8) & 0xFF);
  2311.         }
  2312.       gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.textColor);
  2313. #if 0      /* ExtTextOut records can have an optional list of distances
  2314.        * between characters. But as we don't have the exact same font
  2315.        * metrics anyway, we ignore it.
  2316.        */
  2317.       if (j < GUINT16_FROM_LE (record.Size))
  2318.         for (i = 0; i < k; i++)
  2319.           {
  2320.         gdk_draw_text (canvas->pixmap, canvas->dc.font->font,
  2321.                    canvas->dc.gc, (gint) x, (gint) y,
  2322.                    string + i, 1);
  2323.         if (j < GUINT16_FROM_LE (record.Size))
  2324.           {
  2325.             if (!readparams (0, 1, fp, params))
  2326.               return -1;
  2327.             j++;
  2328.           }
  2329.         x += XSCALE (GINT16_FROM_LE (params[0]));
  2330.           }
  2331.       else
  2332. #endif
  2333.         gdk_draw_text (canvas->pixmap, canvas->dc.font->font,
  2334.                canvas->dc.gc, (gint) x, (gint) y + canvas->dc.font->font->ascent, string, k);
  2335.       g_free (string);
  2336.       if (options & 0x04)
  2337.         gdk_gc_set_clip_rectangle (canvas->dc.gc, NULL);
  2338.       sync_record (record.Size, j, fp);
  2339.       break;
  2340.           
  2341.     case EndOfFile:
  2342.       fclose (fp);
  2343.       gimp_progress_update (1.0);
  2344.       
  2345.       if (canvas->height >= 100)
  2346.         gimp_progress_init (_("Transferring image"));
  2347.       
  2348.       image_ID = gimp_image_new (canvas->width, canvas->height, GIMP_RGB);
  2349.       gimp_image_set_filename (image_ID, filename);
  2350.       layer_ID = gimp_layer_new (image_ID, _("Background"),
  2351.                      canvas->width, canvas->height, GIMP_RGB_IMAGE,
  2352.                      100, GIMP_NORMAL_MODE);
  2353.       gimp_image_add_layer (image_ID, layer_ID, 0);
  2354.       drawable = gimp_drawable_get (layer_ID);
  2355.       image = gdk_image_get (canvas->pixmap, 0, 0,
  2356.                  canvas->width, canvas->height);
  2357.       gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
  2358.                    drawable->width, drawable->height,
  2359.                    TRUE, FALSE);
  2360.       if (pixel_rgn.bpp != 3)
  2361.         abort ();
  2362.       visual = gdk_visual_get_system ();
  2363.       switch (visual->type)
  2364.         {
  2365.         case GDK_VISUAL_PSEUDO_COLOR:
  2366.           buf = g_malloc (gimp_tile_height() * canvas->width * 3);
  2367.           colors = canvas->colormap->colors;
  2368.           for (j = 0; j < canvas->height;)
  2369.         {
  2370.           start = j;
  2371.           end = MIN (j + gimp_tile_height (), canvas->height);
  2372.           scanlines = end - start;
  2373.           bufp = buf;
  2374.  
  2375.           for (jj = 0; jj < scanlines; jj++)
  2376.             {
  2377.               pixelp = ((guchar *) image->mem) + (j + jj) * image->bpl;
  2378.               for (i = 0; i < canvas->width; i++)
  2379.             {
  2380.               *bufp++ = colors[*pixelp].red >> 8;
  2381.               *bufp++ = colors[*pixelp].green >> 8;
  2382.               *bufp++ = colors[*pixelp].blue >> 8;
  2383.               pixelp++;
  2384.             }
  2385.             }
  2386.           
  2387.           gimp_pixel_rgn_set_rect (&pixel_rgn, buf, 0, j, canvas->width, scanlines);
  2388.           if (canvas->height >= 100)
  2389.             gimp_progress_update ((double) j / canvas->height);
  2390.           j += scanlines;
  2391.         }
  2392.           if (canvas->height >= 100)
  2393.         gimp_progress_update (1.0);
  2394.           g_free (buf);
  2395.           break;
  2396.  
  2397.         case GDK_VISUAL_TRUE_COLOR:
  2398.           buf = g_malloc (gimp_tile_height () * canvas->width * 3);
  2399.  
  2400.           /* Set up mappings from subfield ranges to full 0..255 range */
  2401.           k = 1 << visual->red_prec;
  2402.           rtbl = g_malloc (k);
  2403.           for (i = 0; i < k; i++)
  2404.         rtbl[i] = (i * 255) / (k-1);
  2405.           k = 1 << visual->green_prec;
  2406.           gtbl = g_malloc (k);
  2407.           for (i = 0; i < k; i++)
  2408.         gtbl[i] = (i * 255) / (k-1);
  2409.           k = 1 << visual->blue_prec;
  2410.           btbl = g_malloc (k);
  2411.           for (i = 0; i < k; i++)
  2412.         btbl[i] = (i * 255) / (k-1);
  2413. #if 0
  2414.           g_print ("R: %.08x, %d, %d\n", visual->red_mask, visual->red_shift, visual->red_prec);
  2415.           g_print ("G: %.08x, %d, %d\n", visual->green_mask, visual->green_shift, visual->green_prec);
  2416.           g_print ("B: %.08x, %d, %d\n", visual->blue_mask, visual->blue_shift, visual->blue_prec);
  2417.           g_print ("byte order: %s\n", (visual->byte_order == GDK_LSB_FIRST ? "LSB_FIRST" : (visual->byte_order == GDK_MSB_FIRST ? "MSB_FIRST" : "???")));
  2418. #endif
  2419.           rmask = visual->red_mask;
  2420.           gmask = visual->green_mask;
  2421.           bmask = visual->blue_mask;
  2422.           rshift = visual->red_shift;
  2423.           gshift = visual->green_shift;
  2424.           bshift = visual->blue_shift;
  2425.           
  2426.           if ((image->depth > 8 && image->bpp == 1)
  2427.           || image->bpp > 4)
  2428.         {
  2429.           /* Workaround for bugs in GDK */
  2430.           if (image->bpp > 4)
  2431.             /* GDK has set image->bpp to bits-per-pixel,
  2432.              * correct it to bytes-per-pixel.
  2433.              */
  2434.             image->bpp = (image->bpp + 7) / 8;
  2435.           else if (image->depth > 24)
  2436.             image->bpp = 4;
  2437.           else if (image->depth > 16)
  2438.             image->bpp = 3;
  2439.           else
  2440.             image->bpp = 2;
  2441.         }
  2442.  
  2443.           for (j = 0; j < canvas->height;)
  2444.         {
  2445.           start = j;
  2446.           end = MIN (j + gimp_tile_height (), canvas->height);
  2447.           scanlines = end - start;
  2448.           bufp = buf;
  2449.           for (jj = 0; jj < scanlines; jj++)
  2450.             {
  2451.               pixelp = ((guchar *) image->mem) + (j + jj) * image->bpl;
  2452.               for (i = 0; i < canvas->width; i++)
  2453.             {
  2454.               pixel = 0;
  2455.               if (visual->byte_order == GDK_LSB_FIRST)
  2456. #if 1
  2457.                 {
  2458.                   k = image->bpp - 1;
  2459.                   switch (k)
  2460.                 {
  2461.                 case 3:
  2462.                   pixel |= (pixelp[3] << 24);
  2463.                   /* Fallthrough on purpose */
  2464.                 case 2:
  2465.                   pixel |= (pixelp[2] << 16);
  2466.                   /* ditto */
  2467.                 case 1:
  2468.                   pixel |= (pixelp[1] << 8);
  2469.                   /* ditto */
  2470.                 case 0:
  2471.                   pixel |= (pixelp[0]);
  2472.                 }
  2473.                 }
  2474. #else
  2475.                 for (k = 0; k < image->bpp; k++)
  2476.                   pixel |= (pixelp[k] << (k*8));
  2477. #endif
  2478.               else
  2479.                 for (k = 0; k < image->bpp; k++)
  2480.                   pixel |= (pixelp[image->bpp - k - 1] << (k*8));
  2481.               
  2482.               *bufp++ = rtbl[(pixel & rmask) >> rshift];
  2483.               *bufp++ = gtbl[(pixel & gmask) >> gshift];
  2484.               *bufp++ = btbl[(pixel & bmask) >> bshift];
  2485.               pixelp += image->bpp;
  2486.             }
  2487.             }
  2488.           gimp_pixel_rgn_set_rect (&pixel_rgn, buf, 0, j, canvas->width, scanlines);
  2489.           if (canvas->height >= 100)
  2490.             gimp_progress_update ((double) j / canvas->height);
  2491.           j += scanlines;
  2492.         }
  2493.           if (canvas->height >= 100)
  2494.         gimp_progress_update (1.0);
  2495.           g_free (buf);
  2496.           g_free (rtbl);
  2497.           g_free (gtbl);
  2498.           g_free (btbl);
  2499.           break;
  2500.  
  2501.         default:
  2502.           g_message ("Unsupported image visual");
  2503.           return -1;
  2504.         }
  2505.       gimp_drawable_flush (drawable);
  2506.       
  2507.       return image_ID;
  2508.  
  2509.     default:
  2510.       if (!warned_unhandled)
  2511.         {
  2512.           g_message ("WMF: Unhandled operation %#x. Check the web page\n"
  2513.              "http://www.iki.fi/tml/gimp/wmf/ for a possible new\n"
  2514.              "version of the wmf plug-in. (This is version %s).\n"
  2515.              "If you already have the latest version, please send\n"
  2516.              "the WMF file you tried to load to the wmf plug-in\n"
  2517.              "author, Tor Lillqvist <tml@iki.fi>, and he might\n"
  2518.              "try to add the missing feature. No promise that\n"
  2519.              "he has any interest any longer, of course.",
  2520.              GUINT16_FROM_LE (record.Function),
  2521.              VERSION);
  2522.           warned_unhandled = TRUE;
  2523.         }
  2524.       sync_record (record.Size, 0, fp);
  2525.     }
  2526.  
  2527.       if (record_counter % 10 == 0)
  2528.     gimp_progress_update (((double) ftell (fp) / 2)
  2529.                   / GUINT32_FROM_LE (wmf_head.FileSize));
  2530.     }
  2531.  
  2532.   /*NOTREACHED*/
  2533.   fclose (fp);
  2534.   return image_ID;
  2535. }
  2536.  
  2537. static gint
  2538. readparams (DWORD size,
  2539.         guint nparams,
  2540.         FILE *fp,
  2541.         WORD *params)
  2542. {
  2543.   gulong nwords;
  2544.  
  2545.   if (size != 0)
  2546.     {
  2547.       nwords = GUINT32_FROM_LE (size) - WORDSIZE_WMFRECORD;
  2548.       
  2549.       if (nwords < nparams)
  2550.     {
  2551.       fclose (fp);
  2552.       g_message ("WMF: too small record?");
  2553.       return 0;
  2554.     }
  2555.     }
  2556.  
  2557.   if (nparams > NPARMWORDS)
  2558.     {
  2559.       fclose (fp);
  2560.       g_message ("WMF: too large record?");
  2561.       return 0;
  2562.     }
  2563.       
  2564.   if (nparams > 0 && !ReadOK (fp, params, nparams  * sizeof (WORD)))
  2565.     {
  2566.       fclose (fp);
  2567.       g_message ("WMF: Read failed");
  2568.       return 0;
  2569.     }
  2570.  
  2571.   return 1;
  2572. }
  2573.  
  2574. static void
  2575. sync_record (DWORD size,
  2576.          guint nparams,
  2577.          FILE *fp)
  2578. {
  2579.   gulong nwords;
  2580.  
  2581.   nwords = GUINT32_FROM_LE (size) - WORDSIZE_WMFRECORD;
  2582.   if (nwords > nparams)
  2583.     fseek (fp, (nwords - nparams) * 2, SEEK_CUR);
  2584. }
  2585.