diff options
Diffstat (limited to 'src/win32/wmf_emf.c')
-rw-r--r-- | src/win32/wmf_emf.c | 2121 |
1 files changed, 2121 insertions, 0 deletions
diff --git a/src/win32/wmf_emf.c b/src/win32/wmf_emf.c new file mode 100644 index 0000000..36aeed0 --- /dev/null +++ b/src/win32/wmf_emf.c @@ -0,0 +1,2121 @@ +/** \file + * \brief EMF and WMF Play + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> +#include <io.h> +#include <fcntl.h> +#include <math.h> + +#include "cdwin.h" +#include "cdwmf.h" +#include "cdemf.h" + +/* placeable metafile data definitions */ +#define ALDUSKEY 0x9AC6CDD7 + +#ifndef PS_JOIN_MASK +#define PS_JOIN_MASK 0x0000F000 +#endif + +/* +%F Definicao do header do APM. Ver comentario no final deste arquivo. +*/ +typedef struct _APMFILEHEADER +{ + WORD key1, + key2, + hmf, + bleft, btop, bright, bbottom, + inch, + reserved1, + reserved2, + checksum; +} APMFILEHEADER; + + +/* coordinates convertion */ + +static double wmf_xfactor = 1; +static double wmf_yfactor = -1; /* negative because top-down orientation */ +static int wmf_xmin = 0; +static int wmf_ymin = 0; +static int wmf_left = 0; +static int wmf_bottom = 0; /* bottom and right are not included */ +static int wmf_top = 0; +static int wmf_right = 0; + +static int sScaleX(int x) +{ + return cdRound((x - wmf_left) * wmf_xfactor + wmf_xmin); +} + +static int sScaleY(int y) +{ + return cdRound((y - (wmf_bottom-1)) * wmf_yfactor + wmf_ymin); +} + +static int sScaleW(int w) +{ + int s = (int)(w * fabs(wmf_xfactor) + 0.5); + return s > 0? s: 1; +} + +static int sScaleH(int h) +{ + int s = (int)(h * fabs(wmf_yfactor) + 0.5); + return s > 0? s: 1; +} + +static void sCalcSizeX(int x) +{ + if (x < wmf_left) + { + wmf_left = x; + return; + } + + if (x+1 > wmf_right) + { + wmf_right = x+1; + return; + } +} + +static void sCalcSizeY(int y) +{ + if (y < wmf_top) + { + wmf_top = y; + return; + } + + if (y+1 > wmf_bottom) + { + wmf_bottom = y+1; + return; + } +} + +static int CALLBACK CalcSizeEMFEnumProc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData) +{ + switch (lpEMFR->iType) + { + case EMR_POLYGON: + { + EMRPOLYGON* data = (EMRPOLYGON*)lpEMFR; + int i; + for (i = 0; i < (int)data->cptl; i++) + { + sCalcSizeX(data->aptl[i].x); + sCalcSizeY(data->aptl[i].y); + } + + break; + } + case EMR_POLYLINE: + { + EMRPOLYLINE* data = (EMRPOLYLINE*)lpEMFR; + int i; + for (i = 0; i < (int)data->cptl; i++) + { + sCalcSizeX(data->aptl[i].x); + sCalcSizeY(data->aptl[i].y); + } + + break; + } + case EMR_POLYLINETO: + { + EMRPOLYLINETO* data = (EMRPOLYLINETO*)lpEMFR; + int i; + for (i = 0; i < (int)data->cptl; i++) + { + sCalcSizeX(data->aptl[i].x); + sCalcSizeY(data->aptl[i].y); + } + + break; + } + case EMR_POLYPOLYLINE: + { + EMRPOLYPOLYLINE* data = (EMRPOLYPOLYLINE*)lpEMFR; + POINTL* aptl = (POINTL*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->aptl can not be used if count greater than 1 */ + for (c = 0; c < (int)data->nPolys; c++) + { + for (i = 0; i < (int)data->aPolyCounts[c]; i++, aptl++) + { + sCalcSizeX(aptl->x); + sCalcSizeY(aptl->y); + } + } + break; + } + case EMR_POLYPOLYGON: + { + EMRPOLYPOLYGON* data = (EMRPOLYPOLYGON*)lpEMFR; + POINTL* aptl = (POINTL*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->aptl can not be used if count greater than 1 */ + for (c = 0; c < (int)data->nPolys; c++) + { + for (i = 0; i < (int)data->aPolyCounts[c]; i++, aptl++) + { + sCalcSizeX(aptl->x); + sCalcSizeY(aptl->y); + } + } + break; + } + case EMR_SETPIXELV: + { + EMRSETPIXELV* data = (EMRSETPIXELV*)lpEMFR; + sCalcSizeX(data->ptlPixel.x); + sCalcSizeY(data->ptlPixel.y); + break; + } + case EMR_MOVETOEX: + { + EMRMOVETOEX* data = (EMRMOVETOEX*)lpEMFR; + sCalcSizeX(data->ptl.x); + sCalcSizeY(data->ptl.y); + break; + } + case EMR_ANGLEARC: + { + EMRANGLEARC* data = (EMRANGLEARC*)lpEMFR; + int x, y; + + x = (int)(data->nRadius * cos(CD_DEG2RAD * data->eStartAngle + data->eSweepAngle)); + y = (int)(data->nRadius * sin(CD_DEG2RAD * data->eStartAngle + data->eSweepAngle)); + + sCalcSizeX(data->ptlCenter.x); + sCalcSizeY(data->ptlCenter.y); + sCalcSizeX(x); + sCalcSizeY(y); + break; + } + case EMR_ELLIPSE: + { + EMRELLIPSE* data = (EMRELLIPSE*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.top); + sCalcSizeY(data->rclBox.bottom); + break; + } + case EMR_RECTANGLE: + { + EMRRECTANGLE* data = (EMRRECTANGLE*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.bottom); + sCalcSizeY(data->rclBox.top); + break; + } + case EMR_ROUNDRECT: + { + EMRROUNDRECT* data = (EMRROUNDRECT*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.bottom); + sCalcSizeY(data->rclBox.top); + break; + } + case EMR_ARC: + { + EMRARC* data = (EMRARC*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.top); + sCalcSizeY(data->rclBox.bottom); + break; + } + case EMR_CHORD: + { + EMRCHORD* data = (EMRCHORD*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.top); + sCalcSizeY(data->rclBox.bottom); + break; + } + case EMR_PIE: + { + EMRPIE* data = (EMRPIE*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.top); + sCalcSizeY(data->rclBox.bottom); + break; + } + case EMR_LINETO: + { + EMRLINETO* data = (EMRLINETO*)lpEMFR; + sCalcSizeX(data->ptl.x); + sCalcSizeY(data->ptl.y); + break; + } + case EMR_ARCTO: + { + EMRARCTO* data = (EMRARCTO*)lpEMFR; + sCalcSizeX(data->rclBox.left); + sCalcSizeX(data->rclBox.right); + sCalcSizeY(data->rclBox.top); + sCalcSizeY(data->rclBox.bottom); + break; + } + case EMR_POLYDRAW: + { + int p; + EMRPOLYDRAW* data = (EMRPOLYDRAW*)lpEMFR; + + for(p = 0; p < (int)data->cptl; p++) + { + switch (data->abTypes[p]) + { + case PT_MOVETO: + { + sCalcSizeX(data->aptl[p].x); + sCalcSizeY(data->aptl[p].y); + break; + } + case PT_LINETO: + { + sCalcSizeX(data->aptl[p].x); + sCalcSizeY(data->aptl[p].y); + break; + } + } + } + break; + } + case EMR_BITBLT: + { + EMRBITBLT* data = (EMRBITBLT*)lpEMFR; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + sCalcSizeX(data->xDest); + sCalcSizeY(data->yDest); + sCalcSizeX(data->xDest + dib.w); + sCalcSizeY(data->yDest + abs(dib.h)); + break; + } + case EMR_STRETCHBLT: + { + EMRSTRETCHBLT* data = (EMRSTRETCHBLT*)lpEMFR; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + sCalcSizeX(data->xDest); + sCalcSizeY(data->yDest); + sCalcSizeX(data->xDest + data->cxDest); + sCalcSizeY(data->yDest + data->cyDest); + break; + } + case EMR_MASKBLT: + { + EMRMASKBLT* data = (EMRMASKBLT*)lpEMFR; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + sCalcSizeX(data->xDest); + sCalcSizeY(data->yDest); + sCalcSizeX(data->xDest + dib.w); + sCalcSizeY(data->yDest + abs(dib.h)); + break; + } + case EMR_SETDIBITSTODEVICE: + { + EMRSETDIBITSTODEVICE* data = (EMRSETDIBITSTODEVICE*)lpEMFR; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + sCalcSizeX(data->xDest); + sCalcSizeY(data->yDest); + sCalcSizeX(data->xDest + dib.w); + sCalcSizeY(data->yDest + abs(dib.h)); + break; + } + case EMR_STRETCHDIBITS: + { + EMRSTRETCHDIBITS* data = (EMRSTRETCHDIBITS*)lpEMFR; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + sCalcSizeX(data->xDest); + sCalcSizeY(data->yDest); + sCalcSizeX(data->xDest + data->cxDest); + sCalcSizeY(data->yDest + data->cyDest); + break; + } + case EMR_EXTTEXTOUTA: + { + EMREXTTEXTOUTA* data = (EMREXTTEXTOUTA*)lpEMFR; + sCalcSizeX(data->emrtext.ptlReference.x); + sCalcSizeY(data->emrtext.ptlReference.y); + break; + } + case EMR_EXTTEXTOUTW: + { + EMREXTTEXTOUTW* data = (EMREXTTEXTOUTW*)lpEMFR; + sCalcSizeX(data->emrtext.ptlReference.x); + sCalcSizeY(data->emrtext.ptlReference.y); + break; + } + case EMR_POLYGON16: + { + EMRPOLYGON16* data = (EMRPOLYGON16*)lpEMFR; + int i; + for (i = 0; i < (int)data->cpts; i++) + { + sCalcSizeX(data->apts[i].x); + sCalcSizeY(data->apts[i].y); + } + break; + } + case EMR_POLYLINE16: + { + EMRPOLYLINE16* data = (EMRPOLYLINE16*)lpEMFR; + int i; + for (i = 0; i < (int)data->cpts; i++) + { + sCalcSizeX(data->apts[i].x); + sCalcSizeY(data->apts[i].y); + } + break; + } + case EMR_POLYLINETO16: + { + EMRPOLYLINETO16* data = (EMRPOLYLINETO16*)lpEMFR; + int i; + for (i = 0; i < (int)data->cpts; i++) + { + sCalcSizeX(data->apts[i].x); + sCalcSizeY(data->apts[i].y); + } + break; + } + case EMR_POLYPOLYLINE16: + { + EMRPOLYPOLYLINE16* data = (EMRPOLYPOLYLINE16*)lpEMFR; + POINTS* apts = (POINTS*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->apts can not be used if count greater than 1 */ + for (c = 0; c < (int)data->nPolys; c++) + { + for (i = 0; i < (int)data->aPolyCounts[c]; i++, apts++) + { + sCalcSizeX(apts->x); + sCalcSizeY(apts->y); + } + } + break; + } + case EMR_POLYPOLYGON16: + { + EMRPOLYPOLYGON16* data = (EMRPOLYPOLYGON16*)lpEMFR; + POINTS* apts = (POINTS*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->apts can not be used if count greater than 1 */ + for (c = 0; c < (int)data->nPolys; c++) + { + for (i = 0; i < (int)data->aPolyCounts[c]; i++, apts++) + { + sCalcSizeX(apts->x); + sCalcSizeY(apts->y); + } + } + break; + } + case EMR_POLYDRAW16: + { + EMRPOLYDRAW16* data = (EMRPOLYDRAW16*)lpEMFR; + int p; + for(p = 0; p < (int)data->cpts; p++) + { + switch (data->abTypes[p]) + { + case PT_MOVETO: + { + sCalcSizeX(data->apts[p].x); + sCalcSizeY(data->apts[p].y); + break; + } + case PT_LINETO: + { + sCalcSizeX(data->apts[p].x); + sCalcSizeY(data->apts[p].y); + break; + } + } + } + break; + } + case EMR_POLYTEXTOUTA: + { + EMRPOLYTEXTOUTA* data = (EMRPOLYTEXTOUTA*)lpEMFR; + int t; + for (t = 0; t < data->cStrings; t++) + { + sCalcSizeX(data->aemrtext[t].ptlReference.x); + sCalcSizeY(data->aemrtext[t].ptlReference.y); + } + break; + } + case EMR_POLYTEXTOUTW: + { + EMRPOLYTEXTOUTW* data = (EMRPOLYTEXTOUTW*)lpEMFR; + int t; + for (t = 0; t < data->cStrings; t++) + { + sCalcSizeX(data->aemrtext[t].ptlReference.x); + sCalcSizeY(data->aemrtext[t].ptlReference.y); + } + break; + } + } + + return 1; +} + +static int CALLBACK EMFEnumProc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData) +{ + static int curx = 0, cury = 0; + static int upd_xy = 0; + cdCanvas* canvas = (cdCanvas*)lpData; + + switch (lpEMFR->iType) + { + case EMR_SETWORLDTRANSFORM: + { + double matrix[6]; + EMRSETWORLDTRANSFORM* data = (EMRSETWORLDTRANSFORM*)lpEMFR; + matrix[0] = data->xform.eM11; + matrix[1] = data->xform.eM12; + matrix[2] = data->xform.eM21; + matrix[3] = data->xform.eM22; + matrix[4] = data->xform.eDx; + matrix[5] = data->xform.eDy; + cdCanvasTransform(canvas, matrix); + break; + } + case EMR_MODIFYWORLDTRANSFORM: + { + EMRMODIFYWORLDTRANSFORM* data = (EMRMODIFYWORLDTRANSFORM*)lpEMFR; + if (data->iMode == MWT_IDENTITY) + cdCanvasTransform(canvas, NULL); + else if (data->iMode == MWT_LEFTMULTIPLY) + { + double matrix[6]; + matrix[0] = data->xform.eM11; + matrix[1] = data->xform.eM12; + matrix[2] = data->xform.eM21; + matrix[3] = data->xform.eM22; + matrix[4] = data->xform.eDx; + matrix[5] = data->xform.eDy; + cdCanvasTransformMultiply(canvas, matrix); + } + break; + } + case EMR_POLYGON: + { + EMRPOLYGON* data = (EMRPOLYGON*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_FILL); + + for (i = 0; i < (int)data->cptl; i++) + cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y)); + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYLINE: + { + EMRPOLYLINE* data = (EMRPOLYLINE*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_OPEN_LINES); + + for (i = 0; i < (int)data->cptl; i++) + cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y)); + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYBEZIER: + { + EMRPOLYBEZIER* data = (EMRPOLYBEZIER*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_BEZIER); + + for (i = 0; i < (int)data->cptl; i++) + cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y)); + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYLINETO: + { + EMRPOLYLINETO* data = (EMRPOLYLINETO*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_OPEN_LINES); + + for (i = 0; i < (int)data->cptl; i++) + cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y)); + + curx = data->aptl[data->cptl - 1].x; + cury = data->aptl[data->cptl - 1].y; + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYBEZIERTO: + { + EMRPOLYBEZIERTO* data = (EMRPOLYBEZIERTO*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_BEZIER); + + for (i = 0; i < (int)data->cptl; i++) + cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y)); + + curx = data->aptl[data->cptl - 1].x; + cury = data->aptl[data->cptl - 1].y; + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYPOLYLINE: + { + EMRPOLYPOLYLINE* data = (EMRPOLYPOLYLINE*)lpEMFR; + POINTL* aptl = (POINTL*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->aptl can not be used if count greater than 1 */ + + for (c = 0; c < (int)data->nPolys; c++) + { + cdCanvasBegin(canvas, CD_OPEN_LINES); + + for (i = 0; i < (int)data->aPolyCounts[c]; i++, aptl++) + cdCanvasVertex(canvas, sScaleX(aptl->x), sScaleY(aptl->y)); + + cdCanvasEnd(canvas); + } + break; + } + case EMR_POLYPOLYGON: + { + EMRPOLYPOLYGON* data = (EMRPOLYPOLYGON*)lpEMFR; + POINTL* aptl = (POINTL*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->aptl can not be used if count greater than 1 */ + + for (c = 0; c < (int)data->nPolys; c++) + { + cdCanvasBegin(canvas, CD_FILL); + + for (i = 0; i < (int)data->aPolyCounts[c]; i++, aptl++) + cdCanvasVertex(canvas, sScaleX(aptl->x), sScaleY(aptl->y)); + + cdCanvasEnd(canvas); + } + break; + } + case EMR_SETPIXELV: + { + EMRSETPIXELV* data = (EMRSETPIXELV*)lpEMFR; + cdCanvasPixel(canvas, sScaleX(data->ptlPixel.x), sScaleY(data->ptlPixel.y), cdEncodeColor(GetRValue(data->crColor),GetGValue(data->crColor),GetBValue(data->crColor))); + break; + } + case EMR_SETBKMODE: + { + EMRSETBKMODE* data = (EMRSETBKMODE*)lpEMFR; + cdCanvasBackOpacity(canvas, data->iMode == TRANSPARENT? CD_TRANSPARENT: CD_OPAQUE); + break; + } + case EMR_SETROP2: + { + EMRSETROP2* data = (EMRSETROP2*)lpEMFR; + cdCanvasWriteMode(canvas, data->iMode == R2_NOTXORPEN? CD_NOT_XOR: (data->iMode == R2_XORPEN? CD_XOR: CD_REPLACE)); + break; + } + case EMR_SETTEXTALIGN: + { + EMRSETTEXTALIGN* data = (EMRSETTEXTALIGN*)lpEMFR; + upd_xy = 0; + + if (data->iMode & TA_UPDATECP) + { + upd_xy = 1; + data->iMode &= ~TA_UPDATECP; + } + + switch (data->iMode) + { + case 0: /* top-left */ + cdCanvasTextAlignment(canvas, CD_NORTH_WEST); + break; + case 2: /* top-right */ + cdCanvasTextAlignment(canvas, CD_NORTH_EAST); + break; + case 6: /* top-center */ + cdCanvasTextAlignment(canvas, CD_NORTH); + break; + case 8: /* bottom-left */ + cdCanvasTextAlignment(canvas, CD_SOUTH_WEST); + break; + case 10: /* bottom-right */ + cdCanvasTextAlignment(canvas, CD_SOUTH_EAST); + break; + case 14: /* bottom-center */ + cdCanvasTextAlignment(canvas, CD_SOUTH); + break; + case 24: /* baseline-left */ + cdCanvasTextAlignment(canvas, CD_BASE_LEFT); + break; + case 26: /* baseline-right */ + cdCanvasTextAlignment(canvas, CD_BASE_RIGHT); + break; + case 30: /* baseline-center */ + cdCanvasTextAlignment(canvas, CD_BASE_CENTER); + break; + } + + break; + } + case EMR_SETTEXTCOLOR: + { + EMRSETTEXTCOLOR* data = (EMRSETTEXTCOLOR*)lpEMFR; + cdCanvasSetForeground(canvas, cdEncodeColor(GetRValue(data->crColor),GetGValue(data->crColor),GetBValue(data->crColor))); + break; + } + case EMR_SETBKCOLOR: + { + EMRSETBKCOLOR* data = (EMRSETBKCOLOR*)lpEMFR; + cdCanvasSetBackground(canvas, cdEncodeColor(GetRValue(data->crColor),GetGValue(data->crColor),GetBValue(data->crColor))); + break; + } + case EMR_MOVETOEX: + { + EMRMOVETOEX* data = (EMRMOVETOEX*)lpEMFR; + curx = data->ptl.x; + cury = data->ptl.y; + break; + } + case EMR_CREATEPEN: + { + EMRCREATEPEN* data = (EMRCREATEPEN*)lpEMFR; + int style; + + switch (data->lopn.lopnStyle) + { + case PS_SOLID: + style = CD_CONTINUOUS; + break; + case PS_DASH: + style = CD_DASHED; + break; + case PS_DOT: + style = CD_DOTTED; + break; + case PS_DASHDOT: + style = CD_DASH_DOT; + break; + case PS_DASHDOTDOT: + style = CD_DASH_DOT_DOT; + break; + case PS_NULL: + style = -1; + break; + default: + style = CD_CONTINUOUS; + break; + } + + if (style != -1) + { + cdCanvasLineStyle(canvas, style); + cdCanvasLineWidth(canvas, sScaleW(data->lopn.lopnWidth.x == 0? 1: data->lopn.lopnWidth.x)); + cdCanvasSetForeground(canvas, cdEncodeColor(GetRValue(data->lopn.lopnColor),GetGValue(data->lopn.lopnColor),GetBValue(data->lopn.lopnColor))); + } + break; + } + case EMR_EXTCREATEPEN: + { + EMREXTCREATEPEN* data = (EMREXTCREATEPEN*)lpEMFR; + int style; + + switch (data->elp.elpPenStyle & PS_STYLE_MASK) + { + case PS_SOLID: + style = CD_CONTINUOUS; + break; + case PS_DASH: + style = CD_DASHED; + break; + case PS_DOT: + style = CD_DOTTED; + break; + case PS_DASHDOT: + style = CD_DASH_DOT; + break; + case PS_DASHDOTDOT: + style = CD_DASH_DOT_DOT; + break; + case PS_NULL: + style = -1; + break; + case PS_USERSTYLE: + style = CD_CUSTOM; + cdCanvasLineStyleDashes(canvas, (int*)data->elp.elpStyleEntry, data->elp.elpNumEntries); + break; + default: + style = CD_CONTINUOUS; + break; + } + + if (style != -1) + { + switch (data->elp.elpPenStyle & PS_ENDCAP_MASK) + { + case PS_ENDCAP_FLAT: + cdCanvasLineCap(canvas, CD_CAPFLAT); + break; + case PS_ENDCAP_ROUND: + cdCanvasLineCap(canvas, CD_CAPROUND); + break; + case PS_ENDCAP_SQUARE: + cdCanvasLineCap(canvas, CD_CAPSQUARE); + break; + } + + switch (data->elp.elpPenStyle & PS_JOIN_MASK) + { + case PS_JOIN_MITER: + cdCanvasLineJoin(canvas, CD_MITER); + break; + case PS_JOIN_BEVEL: + cdCanvasLineJoin(canvas, CD_BEVEL); + break; + case PS_JOIN_ROUND: + cdCanvasLineJoin(canvas, CD_ROUND); + break; + } + + cdCanvasLineStyle(canvas, style); + cdCanvasLineWidth(canvas, sScaleW(data->elp.elpWidth == 0? 1: data->elp.elpWidth)); + cdCanvasSetForeground(canvas, cdEncodeColor(GetRValue(data->elp.elpColor),GetGValue(data->elp.elpColor),GetBValue(data->elp.elpColor))); + } + break; + } + case EMR_CREATEBRUSHINDIRECT: + { + EMRCREATEBRUSHINDIRECT* data = (EMRCREATEBRUSHINDIRECT*)lpEMFR; + cdCanvasSetForeground(canvas, cdEncodeColor(GetRValue(data->lb.lbColor),GetGValue(data->lb.lbColor),GetBValue(data->lb.lbColor))); + + switch (data->lb.lbStyle) + { + case BS_HATCHED: + { + int hatch = 0; + + switch (data->lb.lbHatch) + { + case HS_BDIAGONAL: + hatch = CD_BDIAGONAL; + break; + case HS_CROSS: + hatch = CD_CROSS; + break; + case HS_DIAGCROSS: + hatch = CD_DIAGCROSS; + break; + case HS_FDIAGONAL: + hatch = CD_FDIAGONAL; + break; + case HS_HORIZONTAL: + hatch = CD_HORIZONTAL; + break; + case HS_VERTICAL: + hatch = CD_VERTICAL; + break; + } + + cdCanvasHatch(canvas, hatch); + cdCanvasInteriorStyle(canvas, CD_HATCH); + break; + } + case BS_SOLID: + cdCanvasInteriorStyle(canvas, CD_SOLID); + break; + case BS_NULL: + cdCanvasInteriorStyle(canvas, CD_HOLLOW); + break; + default: + break; + } + break; + } + case EMR_ANGLEARC: + { + EMRANGLEARC* data = (EMRANGLEARC*)lpEMFR; + int x, y; + + x = (int)(data->nRadius * cos(CD_DEG2RAD * data->eStartAngle + data->eSweepAngle)); + y = (int)(data->nRadius * sin(CD_DEG2RAD * data->eStartAngle + data->eSweepAngle)); + + cdCanvasLine(canvas, sScaleX(data->ptlCenter.x), sScaleY(data->ptlCenter.y), sScaleX(x), sScaleY(y)); + cdCanvasArc(canvas, data->ptlCenter.x, data->ptlCenter.y, 2 * data->nRadius, 2 * data->nRadius, data->eStartAngle, data->eStartAngle + data->eSweepAngle); + break; + } + case EMR_ELLIPSE: + { + EMRELLIPSE* data = (EMRELLIPSE*)lpEMFR; + int xc, yc, w, h; + + xc = sScaleX((data->rclBox.left + data->rclBox.right - 1) / 2); + w = sScaleW(data->rclBox.right - data->rclBox.left - 1); + yc = sScaleY((data->rclBox.top + data->rclBox.bottom - 1) / 2); + h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1); + + cdCanvasSector(canvas, xc, yc, w, h, 0, 360); + break; + } + case EMR_RECTANGLE: + { + EMRRECTANGLE* data = (EMRRECTANGLE*)lpEMFR; + cdCanvasBox (canvas, sScaleX(data->rclBox.left), sScaleX(data->rclBox.right-2), sScaleY(data->rclBox.bottom-2), sScaleY(data->rclBox.top)); + break; + } + case EMR_ROUNDRECT: + { + EMRROUNDRECT* data = (EMRROUNDRECT*)lpEMFR; + cdCanvasBox (canvas, sScaleX(data->rclBox.left), sScaleX(data->rclBox.right-2), sScaleY(data->rclBox.bottom-2), sScaleY(data->rclBox.top)); + break; + } + case EMR_ARC: + { + EMRARC* data = (EMRARC*)lpEMFR; + int xc, yc, w, h; + double angle1, angle2; + + xc = (data->rclBox.left + data->rclBox.right - 1) / 2; + yc = (data->rclBox.top + data->rclBox.bottom - 1) / 2; + + w = sScaleW(data->rclBox.right - data->rclBox.left - 1); + h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1); + + angle1 = atan2((yc - data->ptlStart.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlStart.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + angle2 = atan2((yc - data->ptlEnd.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlEnd.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + + if (angle1 == angle2) + angle2+=360; + + xc = sScaleX(xc); + yc = sScaleY(yc); + + cdCanvasArc(canvas, xc, yc, w, h, angle1, angle2); + break; + } + case EMR_CHORD: + { + EMRCHORD* data = (EMRCHORD*)lpEMFR; + int xc, yc, w, h; + double angle1, angle2; + + xc = (data->rclBox.left + data->rclBox.right - 1) / 2; + yc = (data->rclBox.top + data->rclBox.bottom - 1) / 2; + + w = sScaleW(data->rclBox.right - data->rclBox.left - 1); + h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1); + + angle1 = atan2((yc - data->ptlStart.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlStart.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + angle2 = atan2((yc - data->ptlEnd.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlEnd.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + + if (angle1 == angle2) + angle2+=360; + + xc = sScaleX(xc); + yc = sScaleY(yc); + + cdCanvasChord(canvas, xc, yc, w, h, angle1, angle2); + break; + } + case EMR_PIE: + { + EMRPIE* data = (EMRPIE*)lpEMFR; + int xc, yc, w, h; + double angle1, angle2; + + xc = (data->rclBox.left + data->rclBox.right - 1) / 2; + yc = (data->rclBox.top + data->rclBox.bottom - 1) / 2; + + w = sScaleW(data->rclBox.right - data->rclBox.left - 1); + h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1); + + angle1 = atan2((yc - data->ptlStart.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlStart.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + angle2 = atan2((yc - data->ptlEnd.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlEnd.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + + if (angle1 == angle2) + angle2+=360; + + xc = sScaleX(xc); + yc = sScaleY(yc); + + cdCanvasSector(canvas, xc, yc, w, h, angle1, angle2); + break; + } + case EMR_CREATEPALETTE: + { + int k; + EMRCREATEPALETTE* data = (EMRCREATEPALETTE*)lpEMFR; + long palette[256]; + + for (k=0; k < data->lgpl.palNumEntries; k++) + palette[k] = cdEncodeColor(data->lgpl.palPalEntry[k].peRed, data->lgpl.palPalEntry[k].peGreen, data->lgpl.palPalEntry[k].peBlue); + + cdCanvasPalette(canvas, data->lgpl.palNumEntries, palette, CD_POLITE); + break; + } + case EMR_LINETO: + { + EMRLINETO* data = (EMRLINETO*)lpEMFR; + cdCanvasLine(canvas, sScaleX(curx), sScaleY(cury), sScaleX(data->ptl.x), sScaleY(data->ptl.y)); + curx = data->ptl.x; + cury = data->ptl.y; + break; + } + case EMR_ARCTO: + { + EMRARCTO* data = (EMRARCTO*)lpEMFR; + int xc, yc, w, h; + double angle1, angle2; + + xc = (data->rclBox.left + data->rclBox.right - 1) / 2; + yc = (data->rclBox.top + data->rclBox.bottom - 1) / 2; + + w = sScaleW(data->rclBox.right - data->rclBox.left - 1); + h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1); + + angle1 = atan2((yc - data->ptlStart.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlStart.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + angle2 = atan2((yc - data->ptlEnd.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlEnd.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD; + + if (angle1 == angle2) + angle2+=360; + + xc = sScaleX(xc); + yc = sScaleY(yc); + + cdCanvasArc(canvas, xc, yc, w, h, angle1, angle2); + + curx = data->ptlEnd.x; /* isto nao esta' certo mas e' a minha melhor aproximacao */ + cury = data->ptlEnd.y; + break; + } + case EMR_POLYDRAW: + { + int p; + EMRPOLYDRAW* data = (EMRPOLYDRAW*)lpEMFR; + + for(p = 0; p < (int)data->cptl; p++) + { + switch (data->abTypes[p]) + { + case PT_MOVETO: + { + curx = data->aptl[p].x; + cury = data->aptl[p].y; + break; + } + case PT_LINETO: + { + cdCanvasLine(canvas, sScaleX(curx), sScaleY(cury), sScaleX(data->aptl[p].x), sScaleY(data->aptl[p].y)); + curx = data->aptl[p].x; + cury = data->aptl[p].y; + break; + } + } + } + break; + } + case EMR_BITBLT: + { + EMRBITBLT* data = (EMRBITBLT*)lpEMFR; + int size; + cdwDIB dib; + int old_write_mode; + + if (data->dwRop == SRCINVERT) + old_write_mode = cdCanvasWriteMode(canvas, CD_XOR); + else + old_write_mode = cdCanvasWriteMode(canvas, CD_REPLACE); + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0); + + free(index); + free(colors); + } + + cdCanvasWriteMode(canvas, old_write_mode); + break; + } + case EMR_STRETCHBLT: + { + EMRSTRETCHBLT* data = (EMRSTRETCHBLT*)lpEMFR; + int size; + cdwDIB dib; + int old_write_mode; + + if (data->dwRop == SRCINVERT) + old_write_mode = cdCanvasWriteMode(canvas, CD_XOR); + else + old_write_mode = cdCanvasWriteMode(canvas, CD_REPLACE); + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), sScaleW(data->cxDest), sScaleH(data->cyDest), 0, 0, 0, 0); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), sScaleW(data->cxDest), sScaleH(data->cyDest), 0, 0, 0, 0); + + free(index); + free(colors); + } + + cdCanvasWriteMode(canvas, old_write_mode); + break; + } + case EMR_MASKBLT: + { + EMRMASKBLT* data = (EMRMASKBLT*)lpEMFR; + int size; + cdwDIB dib; + int old_write_mode; + + if (data->dwRop == SRCINVERT) + old_write_mode = cdCanvasWriteMode(canvas, CD_XOR); + else + old_write_mode = cdCanvasWriteMode(canvas, CD_REPLACE); + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0); + + free(index); + free(colors); + } + + cdCanvasWriteMode(canvas, old_write_mode); + break; + } + case EMR_SETDIBITSTODEVICE: + { + EMRSETDIBITSTODEVICE* data = (EMRSETDIBITSTODEVICE*)lpEMFR; + int size; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0); + + free(index); + free(colors); + } + break; + } + case EMR_STRETCHDIBITS: + { + EMRSTRETCHDIBITS* data = (EMRSTRETCHDIBITS*)lpEMFR; + int size; + cdwDIB dib; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), sScaleW(data->cxDest), sScaleH(data->cyDest), 0, 0, 0, 0); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), sScaleW(data->cxDest), sScaleH(data->cyDest), 0, 0, 0, 0); + + free(index); + free(colors); + } + break; + } + case EMR_EXTCREATEFONTINDIRECTW: + { + EMREXTCREATEFONTINDIRECTW* data = (EMREXTCREATEFONTINDIRECTW*)lpEMFR; + int style, size; + char type_face[256]; + + style = CD_PLAIN; + + if (data->elfw.elfLogFont.lfWeight >= FW_BOLD) + style = CD_BOLD; + + if (data->elfw.elfLogFont.lfItalic == 1) + style = CD_ITALIC; + + if (data->elfw.elfLogFont.lfWeight >= FW_BOLD && data->elfw.elfLogFont.lfItalic == 1) + style = CD_BOLD_ITALIC; + + if (data->elfw.elfLogFont.lfUnderline) + style |= CD_UNDERLINE; + + if (data->elfw.elfLogFont.lfStrikeOut) + style |= CD_STRIKEOUT; + + WideCharToMultiByte(CP_ACP, 0, data->elfw.elfLogFont.lfFaceName, LF_FACESIZE, type_face, 256, NULL, NULL); + + size = sScaleH(abs(data->elfw.elfLogFont.lfHeight)); + if (size < 5) size = 5; + + if (data->elfw.elfLogFont.lfOrientation) + cdCanvasTextOrientation(canvas, data->elfw.elfLogFont.lfOrientation/10); + + cdCanvasFont(canvas, type_face, style, -size); + break; + } + case EMR_EXTTEXTOUTA: + { + EMREXTTEXTOUTA* data = (EMREXTTEXTOUTA*)lpEMFR; + + char* str = malloc(data->emrtext.nChars + 1); + memcpy(str, ((unsigned char*)data) + data->emrtext.offString, data->emrtext.nChars + 1); + str[data->emrtext.nChars] = 0; + + cdCanvasText(canvas, sScaleX(data->emrtext.ptlReference.x), sScaleY(data->emrtext.ptlReference.y), str); + + if (upd_xy == 1) + { + curx = data->emrtext.ptlReference.x; + cury = data->emrtext.ptlReference.y; + } + + free(str); + break; + } + case EMR_EXTTEXTOUTW: + { + EMREXTTEXTOUTW* data = (EMREXTTEXTOUTW*)lpEMFR; + char str[256]; + + WideCharToMultiByte(CP_ACP, 0, (unsigned short*)(((unsigned char*)data) + data->emrtext.offString), data->emrtext.nChars, str, 256, NULL, NULL); + + str[data->emrtext.nChars] = 0; + + cdCanvasText(canvas, sScaleX(data->emrtext.ptlReference.x), sScaleY(data->emrtext.ptlReference.y), str); + + if (upd_xy == 1) + { + curx = data->emrtext.ptlReference.x; + cury = data->emrtext.ptlReference.y; + } + break; + } + case EMR_SETPOLYFILLMODE: + { + EMRSETPOLYFILLMODE* data = (EMRSETPOLYFILLMODE*)lpEMFR; + if (data->iMode == ALTERNATE) + cdCanvasFillMode(canvas, CD_EVENODD); + else + cdCanvasFillMode(canvas, CD_WINDING); + break; + } + case EMR_POLYGON16: + { + EMRPOLYGON16* data = (EMRPOLYGON16*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_FILL); + + for (i = 0; i < (int)data->cpts; i++) + cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y)); + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYLINE16: + { + EMRPOLYLINE16* data = (EMRPOLYLINE16*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_OPEN_LINES); + + for (i = 0; i < (int)data->cpts; i++) + cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y)); + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYLINETO16: + { + EMRPOLYLINETO16* data = (EMRPOLYLINETO16*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_OPEN_LINES); + + for (i = 0; i < (int)data->cpts; i++) + cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y)); + + curx = data->apts[data->cpts - 1].x; + cury = data->apts[data->cpts - 1].y; + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYBEZIER16: + { + EMRPOLYBEZIER16* data = (EMRPOLYBEZIER16*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_BEZIER); + + for (i = 0; i < (int)data->cpts; i++) + cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y)); + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYBEZIERTO16: + { + EMRPOLYBEZIERTO16* data = (EMRPOLYBEZIERTO16*)lpEMFR; + int i; + + cdCanvasBegin(canvas, CD_BEZIER); + + for (i = 0; i < (int)data->cpts; i++) + cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y)); + + curx = data->apts[data->cpts - 1].x; + cury = data->apts[data->cpts - 1].y; + + cdCanvasEnd(canvas); + break; + } + case EMR_POLYPOLYLINE16: + { + EMRPOLYPOLYLINE16* data = (EMRPOLYPOLYLINE16*)lpEMFR; + POINTS* apts = (POINTS*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->apts can not be used if count greater than 1 */ + + for (c = 0; c < (int)data->nPolys; c++) + { + cdCanvasBegin(canvas, CD_OPEN_LINES); + + for (i = 0; i < (int)data->aPolyCounts[c]; i++, apts++) + cdCanvasVertex(canvas, sScaleX(apts->x), sScaleY(apts->y)); + + cdCanvasEnd(canvas); + } + break; + } + case EMR_POLYPOLYGON16: + { + EMRPOLYPOLYGON16* data = (EMRPOLYPOLYGON16*)lpEMFR; + POINTS* apts = (POINTS*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */ + int c, i; /* data->apts can not be used if count greater than 1 */ + + for (c = 0; c < (int)data->nPolys; c++) + { + cdCanvasBegin(canvas, CD_FILL); + + for (i = 0; i < (int)data->aPolyCounts[c]; i++, apts++) + cdCanvasVertex(canvas, sScaleX(apts->x), sScaleY(apts->y)); + + cdCanvasEnd(canvas); + } + break; + } + case EMR_POLYDRAW16: + { + int p; + EMRPOLYDRAW16* data = (EMRPOLYDRAW16*)lpEMFR; + + for(p = 0; p < (int)data->cpts; p++) + { + switch (data->abTypes[p]) + { + case PT_MOVETO: + { + curx = data->apts[p].x; + cury = data->apts[p].y; + break; + } + case PT_LINETO: + { + cdCanvasLine(canvas, sScaleX(curx), sScaleY(cury), sScaleX(data->apts[p].x), sScaleY(data->apts[p].y)); + curx = data->apts[p].x; + cury = data->apts[p].y; + break; + } + } + } + break; + } + case EMR_CREATEMONOBRUSH: + { + EMRCREATEMONOBRUSH* data = (EMRCREATEMONOBRUSH*)lpEMFR; + int size, i; + cdwDIB dib; + long *pattern; + unsigned char *stipple; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmi, ((BYTE*)data) + data->offBits); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.bmih->biBitCount == 1) + stipple = malloc(size); + else + pattern = (long*)malloc(size*sizeof(long)); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + for (i = 0; i < size; i++) + pattern[i] = cdEncodeColor(r[i], g[i], b[i]); + + free(r); + free(g); + free(b); + } + else + { + unsigned char *index; + long *colors; + + index = (unsigned char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + if (dib.bmih->biBitCount == 1) + { + for (i = 0; i < size; i++) + stipple[i] = index[i]? 0: 1; + } + else + { + for (i = 0; i < size; i++) + pattern[i] = colors[index[i]]; + } + + free(index); + free(colors); + } + + if (dib.bmih->biBitCount == 1) + { + cdCanvasStipple(canvas, dib.w, abs(dib.h), stipple); + free(stipple); + } + else + { + cdCanvasPattern(canvas, dib.w, abs(dib.h), pattern); + free(pattern); + } + break; + } + case EMR_CREATEDIBPATTERNBRUSHPT: + { + EMRCREATEDIBPATTERNBRUSHPT* data = (EMRCREATEDIBPATTERNBRUSHPT*)lpEMFR; + int size, i; + cdwDIB dib; + long *pattern; + unsigned char *stipple; + + cdwDIBReference(&dib, ((BYTE*)data) + data->offBmi, ((BYTE*)data) + data->offBits); + + if (dib.type == -1) + break; + + size = dib.w*abs(dib.h); + + if (dib.bmih->biBitCount == 1) + stipple = malloc(size); + else + pattern = malloc(size*sizeof(long)); + + if (dib.type == 0) + { + char *r, *g, *b; + + r = (char*)malloc(size); + g = (char*)malloc(size); + b = (char*)malloc(size); + + cdwDIBDecodeRGB(&dib, r, g, b); + + for (i = 0; i < size; i++) + pattern[i] = cdEncodeColor(r[i], g[i], b[i]); + + free(r); + free(g); + free(b); + } + else + { + char *index; + long *colors; + + index = (char*)malloc(size); + colors = (long*)malloc(256*sizeof(long)); + + cdwDIBDecodeMap(&dib, index, colors); + + if (dib.bmih->biBitCount == 1) + { + for (i = 0; i < size; i++) + stipple[i] = index[i]? 0: 1; + } + else + { + for (i = 0; i < size; i++) + pattern[i] = colors[index[i]]; + } + + free(index); + free(colors); + } + + if (dib.bmih->biBitCount == 1) + { + cdCanvasStipple(canvas, dib.w, abs(dib.h), stipple); + free(stipple); + } + else + { + cdCanvasPattern(canvas, dib.w, abs(dib.h), pattern); + free(pattern); + } + break; + } + case EMR_POLYTEXTOUTA: + { + int t; + EMRPOLYTEXTOUTA* data = (EMRPOLYTEXTOUTA*)lpEMFR; + + for (t = 0; t < data->cStrings; t++) + { + char* str = malloc(data->aemrtext[t].nChars + 1); + memcpy(str, ((unsigned char*)data) + data->aemrtext[t].offString, data->aemrtext[t].nChars + 1); + str[data->aemrtext[t].nChars] = 0; + + cdCanvasText(canvas, sScaleX(data->aemrtext[t].ptlReference.x), sScaleY(data->aemrtext[t].ptlReference.y), str); + + free(str); + } + break; + } + case EMR_POLYTEXTOUTW: + { + int t; + EMRPOLYTEXTOUTW* data = (EMRPOLYTEXTOUTW*)lpEMFR; + char str[256]; + + for (t = 0; t < data->cStrings; t++) + { + WideCharToMultiByte(CP_ACP, 0, (unsigned short*)(((unsigned char*)data) + data->aemrtext[t].offString), data->aemrtext[t].nChars, str, 256, NULL, NULL); + str[data->aemrtext[t].nChars] = 0; + cdCanvasText(canvas, sScaleX(data->aemrtext[t].ptlReference.x), sScaleY(data->aemrtext[t].ptlReference.y), str); + } + break; + } + } + + return 1; +} + + +static cdSizeCB cdsizecbWMF = NULL; + +int cdregistercallbackWMF(int cb, cdCallback func) +{ + switch (cb) + { + case CD_SIZECB: + cdsizecbWMF = (cdSizeCB)func; + return CD_OK; + } + + return CD_ERROR; +} + + +/*********************************************************************** +Read the metafile bits, metafile header and placeable +metafile header of a placeable metafile. +************************************************************************/ + +static HANDLE GetPlaceableMetaFile(int fh) +{ + HANDLE hMF; + HANDLE hMem; + LPSTR lpMem; + int wBytesRead; + APMFILEHEADER aldusMFHeader; + METAHEADER mfHeader; + + /* seek to beginning of file and read aldus header */ + lseek(fh, 0, 0); + + /* read the placeable header */ + wBytesRead = read(fh, (LPSTR)&aldusMFHeader, sizeof(APMFILEHEADER)); + + /* if there is an error, return */ + if(wBytesRead == -1 || wBytesRead < sizeof(APMFILEHEADER)) + return NULL; + + /* read the metafile header */ + wBytesRead = read(fh, (LPSTR)&mfHeader, sizeof(METAHEADER)); + + /* if there is an error return */ + if( wBytesRead == -1 || wBytesRead < sizeof(METAHEADER) ) + return NULL; + + /* allocate memory for the metafile bits */ + if (!(hMem = GlobalAlloc(GHND, mfHeader.mtSize * 2L))) + return NULL; + + /* lock the memory */ + if (!(lpMem = GlobalLock(hMem))) + { + GlobalFree(hMem); + return NULL; + } + + /* seek to the metafile bits */ + lseek(fh, sizeof(APMFILEHEADER), 0); + + /* read metafile bits */ + wBytesRead = read(fh, lpMem, (WORD)(mfHeader.mtSize * 2L)); + + /* if there was an error */ + if( wBytesRead == -1 ) + { + GlobalUnlock(hMem); + GlobalFree(hMem); + return NULL; + } + + if (!(hMF = SetMetaFileBitsEx(mfHeader.mtSize * 2L, lpMem))) + return NULL; + + GlobalUnlock(hMem); + GlobalFree(hMem); + + return hMF; +} + + +/* +%F cdPlay para WMF. +Interpreta os dados do WMF. +*/ +int cdplayWMF(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data) +{ + char* filename = (char*)data; + int fh; + int wBytesRead; + DWORD dwIsAldus; + HANDLE hMF; + HENHMETAFILE hEMF; + ENHMETAHEADER emh; + BYTE* buffer; + int size; + + /* try to open the file. */ + fh = open(filename, O_BINARY | O_RDONLY); + + /* if opened failed */ + if (fh == -1) + return CD_ERROR; + + /* read the first dword of the file to see if it is a placeable wmf */ + wBytesRead = read(fh,(LPSTR)&dwIsAldus, sizeof(dwIsAldus)); + if (wBytesRead == -1 || wBytesRead < sizeof(dwIsAldus)) + { + close(fh); + return CD_ERROR; + } + + /* if this is windows metafile, not a placeable wmf */ + if (dwIsAldus != ALDUSKEY) + { + METAHEADER mfHeader; + + /* seek to the beginning of the file */ + lseek(fh, 0, 0); + + /* read the wmf header */ + wBytesRead = read(fh, (LPSTR)&mfHeader, sizeof(METAHEADER)); + + /* done with file so close it */ + close(fh); + + /* if read failed */ + if (wBytesRead == -1 || wBytesRead < sizeof(METAHEADER)) + return CD_ERROR; + + hMF = GetMetaFile(filename); + } + else /* this is a placeable metafile */ + { + /* convert the placeable format into something that can + be used with GDI metafile functions */ + hMF = GetPlaceableMetaFile(fh); + + /* close the file */ + close(fh); + } + + if (!hMF) + return CD_ERROR; + + size = GetMetaFileBitsEx(hMF, 0, NULL); + + buffer = malloc(size); + + GetMetaFileBitsEx(hMF, size, buffer); + + hEMF = SetWinMetaFileBits(size, buffer, NULL, NULL); + + GetEnhMetaFileHeader(hEMF, sizeof(ENHMETAHEADER), &emh); + + /* when converted from WMF, only rclBounds is available */ + wmf_bottom = emh.rclBounds.bottom; + wmf_left = emh.rclBounds.left; + wmf_top = emh.rclBounds.top; + wmf_right = emh.rclBounds.right; + + if ((xmax-xmin+1)>1 && (ymax-ymin+1)>1) /* always update wmf_rect when scaling */ + EnumEnhMetaFile(NULL, hEMF, CalcSizeEMFEnumProc, NULL, NULL); + + if ((wmf_bottom-wmf_top)>1 && + (wmf_right-wmf_left)>1 && + (xmax-xmin+1)>1 && + (ymax-ymin+1)>1) + { + wmf_yfactor = ((double)(ymax-ymin+1)) / (double)(wmf_top-wmf_bottom); /* negative because top-down orientation */ + wmf_xfactor = ((double)(xmax-xmin+1)) / (double)(wmf_right-wmf_left); + wmf_xmin = xmin; + wmf_ymin = ymin; + } + else + { + wmf_yfactor = -1; /* negative because top-down orientation */ + wmf_xfactor = 1; + wmf_xmin = 0; + wmf_ymin = 0; + } + + free(buffer); + + if (cdsizecbWMF && dwIsAldus == ALDUSKEY) + { + int err; + err = cdsizecbWMF(canvas, wmf_right-wmf_left, wmf_bottom-wmf_top, 0, 0); + if (err) + { + DeleteEnhMetaFile (hEMF); + return CD_ERROR; + } + } + + EnumEnhMetaFile(NULL, hEMF, EMFEnumProc, canvas, NULL); + + DeleteEnhMetaFile (hEMF); + + DeleteMetaFile (hMF); + + return CD_OK; +} + + +static cdSizeCB cdsizecbEMF = NULL; + +int cdregistercallbackEMF(int cb, cdCallback func) +{ + switch (cb) + { + case CD_SIZECB: + cdsizecbEMF = (cdSizeCB)func; + return CD_OK; + } + + return CD_ERROR; +} + + +int cdplayEMF(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data) +{ + char* filename = (char*)data; + HENHMETAFILE hEMF; + ENHMETAHEADER emh; + double xres, yres; + + hEMF = GetEnhMetaFile(filename); + + GetEnhMetaFileHeader(hEMF, sizeof(ENHMETAHEADER), &emh); + + /* this is obtained from the hdcRef of CreateEnhMetaFile */ + xres = ((double)emh.szlDevice.cx) / emh.szlMillimeters.cx; + yres = ((double)emh.szlDevice.cy) / emh.szlMillimeters.cy; + + /* this is the same as used in RECT of CreateEnhMetaFile */ + wmf_bottom = (int)((emh.rclFrame.bottom * yres) / 100); + wmf_left = (int)((emh.rclFrame.left * xres) / 100); + wmf_top = (int)((emh.rclFrame.top * yres) / 100); + wmf_right = (int)((emh.rclFrame.right * xres) / 100); + + if ((xmax-xmin+1)>1 && (ymax-ymin+1)>1) /* always update wmf_rect when scaling */ + EnumEnhMetaFile(NULL, hEMF, CalcSizeEMFEnumProc, NULL, NULL); + + if ((wmf_bottom-wmf_top)>1 && + (wmf_right-wmf_left)>1 && + (xmax-xmin+1)>1 && + (ymax-ymin+1)>1) + { + wmf_yfactor = ((double)(ymax-ymin+1)) / (double)(wmf_top-wmf_bottom); /* negative because top-down orientation */ + wmf_xfactor = ((double)(xmax-xmin+1)) / (double)(wmf_right-wmf_left); + wmf_xmin = xmin; + wmf_ymin = ymin; + } + else + { + wmf_yfactor = -1; /* negative because top-down orientation */ + wmf_xfactor = 1; + wmf_xmin = 0; + wmf_ymin = 0; + } + + if (cdsizecbEMF) + { + int err; + err = cdsizecbEMF(canvas, wmf_right-wmf_left, wmf_bottom-wmf_top, 0, 0); + if (err) + { + DeleteEnhMetaFile (hEMF); + return CD_ERROR; + } + } + + EnumEnhMetaFile(NULL, hEMF, EMFEnumProc, canvas, NULL); + + DeleteEnhMetaFile (hEMF); + + return CD_OK; +} + +/* +%F Calculo do CheckSum. +*/ +static WORD sAPMChecksum(APMFILEHEADER* papm) +{ + WORD* pw = (WORD*)papm; + WORD wSum = 0; + int i; + + /* The checksum in a Placeable Metafile header is calculated */ + /* by XOR-ing the first 10 words of the header. */ + + for (i = 0; i < 10; i++) + wSum ^= *pw++; + + return wSum; +} + + + +/* +Aldus placeable metafile format + + DWORD key; + HANDLE hmf; + RECT bbox; + WORD inch; + DWORD reserved; + WORD checksum; + char metafileData[]; + + These fields have the following meanings: + + Field Definition + + key Binary key that uniquely identifies this + file type. This must be 0x9AC6CDD7L. + + hmf Unused; must be zero. + + bbox The coordinates of a rectangle that tightly + bounds the picture. These coordinates are in + metafile units as defined below. + + inch The number of metafile units to the inch. To + avoid numeric overflow in PageMaker, this value + should be less than 1440. + + reserved A reserved double word. Must be zero. + + checksum A checksum of the 10 words that precede it, + calculated by XORing zero with these 10 words + and putting the result in the checksum field. + + metafileData The actual content of the Windows metafile + retrieved by copying the data returned by + GetMetafileBits to the file. The number of + bytes should be equal to the MS-DOS file length + minus 22. The content of a PageMaker placeable + metafile cannot currently exceed 64K (this may + have changed in 4.0). +*/ + +/* +%F Cria um APM em arquivo a partir de um WMF em memoria. +*/ +void wmfMakePlaceableMetafile(HMETAFILE hmf, char* filename, int w, int h) +{ + int fh, nSize; + LPSTR lpData; + APMFILEHEADER APMHeader; + + fh = open(filename, O_CREAT | O_BINARY | O_WRONLY); + + APMHeader.key1 = 0xCDD7; + APMHeader.key2 = 0x9AC6; + APMHeader.hmf = 0; + APMHeader.bleft = 0; + APMHeader.btop = 0; + APMHeader.bright = (short)w; + APMHeader.bbottom = (short)h; + APMHeader.inch = 100; /* this number works fine in Word, etc.. */ + APMHeader.reserved1 = 0; + APMHeader.reserved2 = 0; + APMHeader.checksum = sAPMChecksum(&APMHeader); + + write(fh, (LPSTR)&APMHeader, sizeof(APMFILEHEADER)); + + nSize = GetMetaFileBitsEx(hmf, 0, NULL); + lpData = malloc(nSize); + GetMetaFileBitsEx(hmf, nSize, lpData); + + write(fh, lpData, nSize); + free(lpData); + + close(fh); +} + +void wmfWritePlacebleFile(HANDLE hFile, char* buffer, DWORD dwSize, LONG mm, LONG xExt, LONG yExt) +{ + DWORD nBytesWrite; + APMFILEHEADER APMHeader; + int w = xExt, h = yExt; + + if (mm == MM_ANISOTROPIC || mm == MM_ISOTROPIC) + { + int res = 30; + w = xExt / res; + h = yExt / res; + } + + APMHeader.key1 = 0xCDD7; + APMHeader.key2 = 0x9AC6; + APMHeader.hmf = 0; + APMHeader.bleft = 0; + APMHeader.btop = 0; + APMHeader.bright = (short)w; + APMHeader.bbottom = (short)h; + APMHeader.inch = 100; /* this number works fine in Word, etc.. */ + APMHeader.reserved1 = 0; + APMHeader.reserved2 = 0; + APMHeader.checksum = sAPMChecksum(&APMHeader); + + WriteFile(hFile, (LPSTR)&APMHeader, sizeof(APMFILEHEADER), &nBytesWrite, NULL); + WriteFile(hFile, buffer, dwSize, &nBytesWrite, NULL); +} + |