home *** CD-ROM | disk | FTP | other *** search
/ Software Collection (I) / TOOLS.iso / b05 / 6.img / PSCRIPT / GRAPH.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-11  |  39.6 KB  |  1,221 lines

  1. /**[f******************************************************************
  2.  * graph.c -
  3.  *
  4.  * Copyright (C) 1988 Aldus Corporation.  All rights reserved.
  5.  * Copyright (C) 1989 Microsoft Corporation.
  6.  * Company confidential.
  7.  *
  8.  **f]*****************************************************************/
  9.  
  10. /***************************************************************************
  11.  * ??Jan87      sjp             Fixed box,ellipse and arc drawing.
  12.  * 12Jun87      sjp             Started round rect support.
  13.  * 18Jun87      sjp             Finished round rect support.
  14.  ***************************************************************************/
  15.  
  16. #include "pscript.h"
  17. #include "channel.h"
  18. #include "utils.h"
  19. #include "debug.h"
  20. #include "graph.h"
  21. #include "mgesc.h"
  22. #include "gdidm.h"
  23. #include "driver.h"
  24. #include "psdata.h"
  25.  
  26.  
  27. // postscript is limited to 1500 polygon points.  each x and y of a moveto
  28. // is one (2 per pair).  for a curveto each x,y is 2 (4 per pair).
  29.  
  30. #define PATH_LIMIT      1200
  31.  
  32. extern char MoveCmd;
  33. extern int XformLevel;
  34.  
  35. /* note: these defs are duplicated in the postscript code
  36.  * that does the filling. */
  37.  
  38. #define FM_NONE         0x0000  /* do no filling */
  39. #define FM_FILL         0x0100  /* fill with fill color */
  40. #define FM_HATCH        0x0200  /* do hatch (possibly over fill) */
  41. #define FM_PATTERN      0x0400  /* do pattern (possibly over fill) */
  42.  
  43.  
  44.  
  45.  
  46. typedef int     FAR *LPINT;
  47.  
  48. #define RGB_WHITE 0x00FFFFFFL
  49. #define RGB_BLACK 0x00000000L
  50. #define CODEFAULT RGB_WHITE     /* The default RGB color */
  51.  
  52.  
  53. /* these include only pure colors (assuming a 3 plane device like the
  54.  * QMS 100).  Enumerating non pure colors gives things like
  55.  * narrow pens uglyness and some apps depend on the fact that pens
  56.  * only come in pure colors. */
  57.  
  58. #define MAX_GRAYS 2
  59. DWORD grGrays[MAX_GRAYS] = {
  60.         RGB_BLACK,
  61.         RGB_WHITE
  62. };
  63.  
  64. /* all pure colors (assuming a 3 plane device like the QMS 100)
  65.  * (less black and white which are in the grays) */
  66.  
  67. #define MAX_COLORS 6
  68. DWORD grColors[MAX_COLORS] = {
  69.         0x000000FF,             /* pure red */
  70.         0x0000FF00,             /* pure green */
  71.         0x00FF0000,             /* pure blue */
  72.         0x0000FFFF,             /* red green */
  73.         0x00FFFF00,             /* green blue */
  74.         0x00FF00FF              /* blue red */
  75. };
  76.  
  77. /*-------------------------- local functions -----------------------------*/
  78.  
  79.  
  80. short   PASCAL  PenWidth(LPPEN);
  81. BOOL    PASCAL  Polygon(LPDV, int, BOOL, LPPOINT, int);
  82. BOOL    PASCAL  SetPattern(LPDV, LPBR);
  83. DWORD   PASCAL  RGBtoGray(DWORD rgb);
  84. void    PASCAL  CurveToChannel(LPDV, LPPOINT, int);
  85. void    PASCAL  PointsToChannel(LPDV, LPPOINT, int);
  86.  
  87.  
  88. void FAR PASCAL FillDraw(LPDV lpdv, BOOL Fill, BOOL Draw, int style)
  89. {
  90.  
  91.         if (Fill && (lpdv->FillMode != FM_NONE)) {
  92.                 PrintChannel(lpdv, "%d F\n", style);
  93.         }
  94.  
  95.         if (Draw && (lpdv->pen.lopn.lopnStyle != LS_NOLINE)) {
  96.                 PrintChannel(lpdv, "S\n");
  97.         }
  98.         if (Fill || Draw)
  99.                 PrintChannel(lpdv, "n\n");      /* newpath */
  100. }
  101.  
  102.  
  103.  
  104. /* added by Aldus Corporation--22 Jan 87--sjp */
  105.  
  106.  
  107. /****************************************************************
  108.  * Name: EnumObj()
  109.  *
  110.  * Action: This routine is used to enumerate pens and brushes
  111.  *        available on the device.  For each object belonging
  112.  *        to the given style (pen or brush), the callback function
  113.  *        is called with the information for that object.  The
  114.  *        callback function is called until there are no more
  115.  *        objects or until the callback function returns zero.
  116.  *
  117.  *****************************************************************/
  118.  
  119. BOOL FAR PASCAL EnumObj(lpdv, iStyle, lpfn, lpb)
  120. LPDV    lpdv;       /* Far ptr to the device descriptor */
  121. int     iStyle;     /* The style (brush or pen) */
  122. FARPROC lpfn;       /* Far ptr to the callback function */
  123. LPSTR   lpb;        /* Far ptr to the client data (passed to callback) */
  124. {
  125.  
  126.         LOGPEN lopn;    /* The logical pen */
  127.         LOGBRUSH lb;    /* The logical brush */
  128.         int     i;
  129.  
  130.         ASSERT(lpdv);
  131.         ASSERT(lpfn);
  132.         ASSERT(iStyle == OBJ_PEN || iStyle == OBJ_BRUSH);
  133.  
  134.         DBMSG((">EnumObj()\n"));
  135.  
  136.         switch (iStyle) {
  137.         case OBJ_PEN:
  138.                 DBMSG((">EnumObj() OBJ_PEN\n"));
  139.                 lopn.lopnWidth.x = lopn.lopnWidth.y = 1;
  140.  
  141.                 /* Enumerate each pen style for all possible pen colors */
  142.                 for (lopn.lopnStyle = 0; lopn.lopnStyle < MaxLineStyle; ++lopn.lopnStyle) {
  143.  
  144.                         for (i = 0; i < MAX_GRAYS; ++i) {
  145.                                 lopn.lopnColor = grGrays[i];
  146.  
  147.                                 if (!(*lpfn)((LPLOGPEN)&lopn, lpb))
  148.                                         goto DONE;
  149.                         }
  150.  
  151.                         if (lpdv->fColor) {
  152.                                 for (i = 0; i < MAX_COLORS; ++i) {
  153.                                         lopn.lopnColor = grColors[i];
  154.  
  155.                                         if (!(*lpfn)((LPLOGPEN)&lopn, lpb))
  156.                                                 goto DONE;
  157.                                 }
  158.                         }
  159.                 }
  160.                 break;
  161.  
  162.         case OBJ_BRUSH:
  163.                 DBMSG((">EnumObj() OBJ_BRUSH:\n"));
  164.  
  165.                 lb.lbBkColor = RGB_WHITE;
  166.  
  167.                 /* Enumerate the hollow brush */
  168.                 lb.lbStyle = BS_HOLLOW;
  169.                 lb.lbColor = RGB_WHITE;
  170.                 /* lb.lbBkColor = RGB_WHITE; not used */
  171.                 lb.lbHatch = 0;
  172.  
  173.                 DBMSG((">EnumObj() BS_HOLLOW:\n"));
  174.  
  175.                 if ((!(*lpfn)((LPLOGBRUSH) &lb, lpb)))
  176.                         goto DONE;
  177.  
  178.                 /* Enumerate all possible hatch brushes for black on white */
  179.                 lb.lbStyle = BS_HATCHED;
  180.                 lb.lbColor = RGB_BLACK;
  181.                 /* lb.lbBkColor = RGB_WHITE; not used */
  182.  
  183.                 DBMSG((">EnumObj() BS_HATCHED:\n"));
  184.  
  185.                 for (lb.lbHatch = 0; lb.lbHatch <= MaxHatchStyle; ++lb.lbHatch)
  186.                         if (!(*lpfn)((LPLOGBRUSH) &lb, lpb))
  187.                                 goto DONE;
  188.  
  189.                 /* Enumerate all the possible colors for a solid brush */
  190.                 lb.lbStyle = BS_SOLID;
  191.  
  192.                 DBMSG((">EnumObj() BS_SOLID (grays):\n"));
  193.  
  194.                 for (i = 0; i < MAX_GRAYS; ++i) {
  195.                         lb.lbColor = grGrays[i];
  196.                         if (!(*lpfn)((LPLOGBRUSH)&lb, lpb))
  197.                                 goto DONE;
  198.                 }
  199.  
  200.                 if (lpdv->fColor) {
  201.  
  202.                         DBMSG((">EnumObj() BS_SOLID (colors):\n"));
  203.  
  204.                         for (i = 0; i < MAX_COLORS; ++i) {
  205.                                 lb.lbColor = grColors[i];
  206.                                 if (!(*lpfn)((LPLOGBRUSH)&lb, lpb))
  207.                                         goto DONE;
  208.                         }
  209.                 }
  210.  
  211.  
  212.                 if (lpdv->fColor) {
  213.  
  214.                         DBMSG((">EnumObj() BS_PATTERN (colors):\n"));
  215.  
  216.                         for (i = 0; i < MAX_COLORS; ++i) {
  217.                                 lb.lbColor = grColors[i];
  218.                                 if (!(*lpfn)((LPLOGBRUSH)&lb, lpb))
  219.                                         goto DONE;
  220.                         }
  221.                 }
  222.  
  223.                 break;
  224.         }
  225.  
  226.         /* Control comes here if all callbacks returned TRUE */
  227.         return TRUE;
  228. DONE:
  229.         return FALSE;
  230. }
  231.  
  232.  
  233. /**********************************************************
  234. * Name: PenWidth()
  235. *
  236. * Action: Calculate the PostScript pen width from the pen
  237. *         X and Y dimensions that GDI specifies in the
  238. *         logical pen (GDI only passes X down, Y is ignored).
  239. *
  240. * to avoid problem with clipping a zero width pen we make
  241. * the min width 1.  (zero width pen in PS is defined as
  242. * the thinest line possible).  Zero width pens clip randomly
  243. * (behave differen in protrat vs landscape)
  244. *
  245. *
  246. ***********************************************************/
  247.  
  248. short PASCAL PenWidth(LPPEN lppen)
  249. {
  250.         if (lppen->lopn.lopnWidth.x == 0)
  251.                 return 1;
  252.         else
  253.                 return lppen->lopn.lopnWidth.x;
  254. }
  255.  
  256.  
  257.  
  258.  
  259.  
  260. /***********************************************************
  261.  * Name: PointsToChannel()
  262.  *
  263.  * Action: Pass a number of points to PostScript by printing
  264.  *        them on the output channel.
  265.  *
  266.  ************************************************************/
  267.  
  268. void PASCAL PointsToChannel(lpdv, lppt, cpt)
  269. LPDV    lpdv;
  270. LPPOINT lppt;
  271. int     cpt;
  272. {
  273.         int     i;
  274.         int     cptT;           /* temp point count */
  275.         LPPOINT lpptT;          /* temp point pointer */
  276.  
  277.  
  278.         /* M == moveto path start */
  279.  
  280.         PrintChannel(lpdv, "%d %d %c ", lppt->x, lppt->y, MoveCmd);
  281.         ++lppt;
  282.         --cpt;
  283.  
  284.  
  285.         while (cpt > 0) {
  286.                 cptT = (cpt > 20) ? 20 : cpt;
  287.                 lpptT = lppt + cptT;
  288.  
  289.                 /* Push the points onto the PostScript stack in reverse order */
  290.                 for (i = 0; i < cptT; ++i) {
  291.                         --lpptT;
  292.                         PrintChannel(lpdv, "%d %d ",
  293.                                 lpptT->x - (lpptT-1)->x,
  294.                                 lpptT->y - (lpptT-1)->y);
  295.                 }
  296.  
  297.                 /* PP == PolyPoints */
  298.                 PrintChannel(lpdv, "%d PP\n", cptT);
  299.                 cpt -= cptT;
  300.                 lppt += cptT;
  301.         }
  302. }
  303.  
  304.  
  305. /***********************************************************
  306.  * Name: CurveToChannel()
  307.  *
  308.  * this is used by the MG SET_POLY_MODE escape.
  309.  *
  310.  * it seems that designer will not use this escape unless
  311.  * all of the other exotic MG escapes have been
  312.  * implemented.  if thats the way they want to be...
  313.  *
  314.  ************************************************************/
  315.  
  316.  
  317. void PASCAL CurveToChannel(lpdv, lppt, cpt)
  318. LPDV    lpdv;
  319. LPPOINT lppt;
  320. int     cpt;
  321. {
  322.         int     i;
  323.         POINT   pt0;            /* x0, y0 for rcurveto stuff */
  324.  
  325.         ASSERT(cpt);            /* must be some points */
  326.  
  327.         /* M == moveto path start */
  328.  
  329.         PrintChannel(lpdv, "%d %d %c ", lppt->x, lppt->y, MoveCmd);
  330.         lppt++;
  331.         cpt--;
  332.  
  333.  
  334.         while (cpt >= 3) {
  335.  
  336.                 pt0 = *(lppt-1);
  337.  
  338.                 for (i = 0; i < 3; i++) {
  339.                         PrintChannel(lpdv, "%d %d ",
  340.                                 lppt->x - pt0.x,
  341.                                 lppt->y - pt0.y);
  342.                         lppt++;
  343.                 }
  344.  
  345.                 PrintChannel(lpdv, "rct\n");
  346.                 cpt -= 3;
  347.         }
  348.  
  349.         if (cpt == 1)
  350.                 PrintChannel(lpdv, "%d %d rlt\n",
  351.                         lppt->x - (lppt-1)->x,
  352.                         lppt->y - (lppt-1)->y);
  353.         else if (cpt == 2) {
  354.                 pt0 = *(lppt-1);
  355.                 PrintChannel(lpdv, "%d %d %d %d %d %d rct\n",
  356.                         lppt->x - pt0.x,
  357.                         lppt->y - pt0.y,
  358.                         lppt->x - pt0.x,
  359.                         lppt->y - pt0.y,
  360.                         (lppt+1)->x - pt0.x,
  361.                         (lppt+1)->y - pt0.y);
  362.         }
  363.  
  364. }
  365.  
  366.  
  367. /****************************************************************************
  368.  * Polygon() and Polyline()
  369.  *
  370.  * Action: Draw a polygon on the display surface.  The perimiter
  371.  *        of the polygon is stroked with the current pen and
  372.  *        the interior is filled with the current brush.
  373.  *
  374.  * new strategy (borrowed from MGXPS).  we will use rlineto instead
  375.  * of lineto because the delta # are smaller than absolute #.
  376.  *
  377.  * returns:
  378.  *      1       success
  379.  *      0       failure
  380.  *      -1      request GDI to simulate.
  381.  *              NOTE: GDI simulation produces tons of data. this is very bad
  382.  *              so avoid at all costs.
  383.  *
  384.  ****************************************************************************/
  385.  
  386. BOOL PASCAL Polygon(lpdv, FillStyle, bFill, lppt, cpt)
  387. LPDV    lpdv;           /* A far ptr to the device descriptor */
  388. int     FillStyle;      /* The filling type (if Polygon) */
  389. BOOL    bFill;          /* fill or not (this is a polygon) */
  390. LPPOINT lppt;           /* A far ptr to an array of points on the perimeter */
  391. int     cpt;            /* The number of points */
  392. {
  393.         int point_limit;
  394.  
  395.         ASSERT(lpdv);
  396.         ASSERT(lppt);
  397.  
  398.         // we have to punt if we are defining a path larger than the PS limit
  399.  
  400.         if (lpdv->PolyMode == PM_BEZIER)
  401.                 point_limit = PATH_LIMIT / 4;   // curveto takes 4 per point
  402.         else
  403.                 point_limit = PATH_LIMIT / 2;   // moveto takes 2
  404.  
  405.         // for fills with patterns or hatches we reduce the number of points
  406.         // by 2 because we have to create a clipping path as well as
  407.         // a filling path.
  408.  
  409.         if (bFill && (lpdv->FillMode & (FM_PATTERN | FM_HATCH)))
  410.                 point_limit /= 2;
  411.  
  412.         if (cpt >= point_limit) {
  413.  
  414.                 DBMSG(("Too many points, make GDI simulate!\n"));
  415.                 return FALSE;   // make GDI simulate
  416.         }
  417.  
  418.         DBMSG(("point_limit %d  num points %d\n", point_limit, cpt));
  419.  
  420.         // ok, we can do this
  421.  
  422.         if (lpdv->PolyMode == PM_BEZIER)
  423.                 CurveToChannel(lpdv, lppt, cpt);
  424.         else
  425.                 PointsToChannel(lpdv, lppt, cpt);
  426.  
  427.  
  428.         if (lpdv->PathLevel <= 0)
  429.                 FillDraw(lpdv, bFill, TRUE, FillStyle == OS_ALTPOLYGON);
  430.  
  431.         return TRUE;
  432. }
  433.  
  434.  
  435.  
  436. /***************************************************************
  437. * Name: Output()
  438. *
  439. * Action: This routine draws geometric shapes on the display
  440. *         surface.  The output style determines the type of
  441. *         shape to be drawn and whether or not it should be
  442. *         filled, etc.
  443. *
  444. * Returns: 1 = success
  445. *          0 = failure for any reason
  446. *         -1 = request GDI to simulate the output primitive
  447. *
  448. * note:
  449. *       we do everything GDI asks or pass things on the the brute
  450. *       routines (dmBitBlt etc).
  451. *
  452. *****************************************************************/
  453.  
  454. int FAR PASCAL Output(lpdv, iStyle, cpt, lppt, lppen, lpbr, lpdm, lprcClip)
  455. LPDV    lpdv;           /* Far ptr to the device descriptor */
  456. int     iStyle;         /* The output style (rectangle, elipse, etc) */
  457. int     cpt;            /* The count of points in the point list */
  458. LPPOINT lppt;           /* Far ptr to a list of points */
  459. LPPEN   lppen;          /* Far ptr to the pen to use */
  460. LPBR    lpbr;           /* Far ptr to the brush to use */
  461. LPDRAWMODE lpdm;        /* Far ptr to the draw mode (bacground color, etc.) */
  462. LPRECT  lprcClip;       /* Far ptr to the clipping rectangle */
  463. {
  464.         int     cxPen;      /* The pen width */
  465.         int     cyPen;      /* The pen height */
  466.         int     iy;         /* The vertical position */
  467.         int     i, x, y;
  468.         BOOL    Draw;           /* draw with the pen */
  469.         BOOL    Fill;           /* fill with brush */
  470.         int     x_center, y_center;
  471.         int     x0, y0, x1, y1, x2, y2, x3, y3;
  472.  
  473.  
  474.         ASSERT(lpdv);
  475.         DBMSG1((">Output(): iStyle=%d cpt=%d\n", iStyle, cpt));
  476.  
  477.         if (!lpdv->iType) {
  478.                 return dmOutput(lpdv, iStyle, cpt, lppt, lppen, lpbr, lpdm, lprcClip);
  479.         }
  480.  
  481. #ifdef PS_IGNORE
  482.         if (lpdv->fSupressOutput)
  483.                 return TRUE;
  484. #endif
  485.  
  486.         /* if lpdv->PathLevel > 0 then we are inside a BEGIN_PATH escape.
  487.          * in this mode we do not do output until the END_PATH
  488.          * escape is seen */
  489.  
  490.         if (lpdv->PathLevel <= 0) {
  491.  
  492.                 /* not inside a PATH escape. do everything normally */
  493.  
  494.                 /* Select the pen if it exists */
  495.                 if (lppen) {
  496.                         /* Potential problem area?  The round pen flag is set only
  497.                         * if NOT rectangle.  With round rects of very small radius
  498.                         * corners this could be a problem.  However, a point of
  499.                         * interest is with a square pen drawing a round corner the
  500.                         * cross section of the radius could be up to sqrt(2) times
  501.                         * the cross section of the vertical or horizontal pieces.
  502.                         */
  503.                         lppen->fRound = iStyle != OS_RECTANGLE;
  504.                         cxPen = lppen->lopn.lopnWidth.x;
  505.                         cyPen = lppen->lopn.lopnWidth.y;
  506.  
  507.                         if (iStyle == OS_SCANLINES) {
  508.                                 /* Scan-lines must use a 1 X 1 pixel pen */
  509.                                 lppen->lopn.lopnWidth.x = 1;
  510.                                 lppen->lopn.lopnWidth.y = 1;
  511.                                 SelectPen(lpdv, lppen);
  512.                                 lppen->lopn.lopnWidth.x = cxPen;
  513.                                 lppen->lopn.lopnWidth.y = cyPen;
  514.                         } else {
  515.                                 SelectPen(lpdv, lppen);
  516.                         }
  517.                         Draw = TRUE;    /* default: draw all outlines */
  518.                 } else {
  519.  
  520.                         /* does lppen == NULL imply NULL pen??
  521.                          * the header sets up the default pen as NULL (NOLINE style) */
  522.  
  523.                         cxPen = 0;
  524.                         cyPen = 0;
  525.                         Draw = FALSE;   /* no pen, don't draw */
  526.                 }
  527.  
  528.                 if (iStyle != OS_POLYLINE) {    /* polyline does not use a brush */
  529.                         SelectBrush(lpdv, lpbr, lpdm);
  530.                 }
  531.  
  532.                 /* note, this does a "gsave" */
  533.                 /* be sure to select pens and brushes before we do this */
  534.  
  535.                 if (!XformLevel && lprcClip)
  536.                         ClipBox(lpdv, lprcClip);
  537.  
  538.                 Fill = TRUE;    /* default: fill all objects */
  539.         }
  540.  
  541.         switch (iStyle) {
  542.  
  543.         case OS_ARC:
  544.  
  545.                 DBMSG1((" Output(): OS_ARC (pie)\n"));
  546.                 Fill = FALSE;
  547.  
  548.                 /* PostScript & GDI have differing ideas about what an arc
  549.                  * with starting and ending endpoints looks like.  PostScript
  550.                  * says it is an empty circle; postscript says it's a 
  551.                  * complete circle.  So, if the endpoints match turn output
  552.                  * call into an ellipse call.
  553.                  */
  554.                 if (lppt[2].x == lppt[3].x && lppt[2].y == lppt[3].y) {
  555.                         iStyle = OS_ELLIPSE;
  556.                         goto do_ellipse;
  557.                 }
  558.  
  559.                 /* fall through... */
  560.  
  561.         case OS_PIE:
  562.                 DBMSG1((" Output(): OS_PIE\n"));
  563.  
  564.                 x0 = lppt->x;
  565.                 y0 = lppt->y;
  566.  
  567.                 x1 = (lppt+1)->x;
  568.                 y1 = (lppt+1)->y;
  569.  
  570.                 x2 = (lppt+2)->x;
  571.                 y2 = (lppt+2)->y;
  572.  
  573.                 x3 = (lppt+3)->x;
  574.                 y3 = (lppt+3)->y;
  575.  
  576.                 x_center = (x0 + x1) / 2;
  577.                 y_center = (y0 + y1) / 2;
  578.  
  579.                 if (x3 == x_center && y3 == y_center) {
  580.                         lppt->x = x_center;
  581.                         lppt->y = y_center;
  582.                         (lppt+1)->x = x2;
  583.                         (lppt+1)->y = y2;
  584.                         goto DO_RECT;
  585.                 }
  586.  
  587.                 if (x2 == x_center && y2 == y_center) {
  588.                         lppt->x = x_center;
  589.                         lppt->y = y_center;
  590.                         (lppt+1)->x = x3;
  591.                         (lppt+1)->y = y3;
  592.                         goto DO_RECT;
  593.                 }
  594.  
  595.  
  596.                 // take care of degenerate cases
  597.  
  598.                 if (x0 == x1) {
  599.                         if (y2 <= y3) {
  600.                                 x2 = x_center + 1;      // 0 to 90
  601.                                 y2 = y_center;
  602.                                 x3 = x_center;
  603.                                 y3 = y_center - 1;
  604.                         } else {
  605.                                 x2 = x_center;          // 270 to 360
  606.                                 y2 = y_center + 1;
  607.                                 x3 = x_center + 1;
  608.                                 y3 = y_center;
  609.                         }
  610.                 }
  611.  
  612.                 if (y0 == y1) {
  613.                         if (x2 <= x3) {
  614.                                 x2 = x_center;          // 90 to 180
  615.                                 y2 = y_center - 1;
  616.                                 x3 = x_center - 1;
  617.                                 y3 = y_center;
  618.                         } else {
  619.                                 x2 = x_center + 1;      // 0 to 90
  620.                                 y2 = y_center;
  621.                                 x3 = x_center;
  622.                                 y3 = y_center - 1;
  623.                         }
  624.                 }
  625.  
  626.                 PrintChannel(lpdv, "0 0 1 %d %d %d %d %d %d %d %d %c\n",
  627.                         y2 - y_center,
  628.                         x2 - x_center,
  629.                         y3 - y_center,
  630.                         x3 - x_center,
  631.                         (x1 - x0 + 1) / 2,      // scale
  632.                         (y1 - y0 + 1) / 2,      // scale
  633.                         x_center, y_center,
  634.                         iStyle == OS_ARC ? 'A' : 'P');
  635.                 break;
  636.  
  637.         case OS_ELLIPSE:
  638. do_ellipse:
  639.                 DBMSG1((" Output(): OS_ELLIPSE\n"));
  640.  
  641.                 // do this like this for now.
  642.         // this bug's for you Aldus.
  643.  
  644.                 x = (lppt->x)/2 + (lppt+1)->x / 2;
  645.                 y = (lppt->y)/2 + (lppt+1)->y / 2;
  646.  
  647.                 PrintChannel(lpdv, "%d %d %d %d E\n",
  648.                         (lppt+1)->x/2 - lppt->x/2,
  649.             (lppt+1)->y/2 - lppt->y/2, /* dx dy */
  650.                         x, y);  /* x y */
  651.                 break;
  652.  
  653.         case OS_SCANLINES:
  654.  
  655.                 Fill = FALSE;
  656.                 Draw = FALSE;   /* done inside SL */
  657.  
  658.                 DBMSG1((" Output(): OS_SCANLINES\n"));
  659.  
  660.                 if (--cpt > 0) {
  661.                         iy = (lppt++)->y;
  662.  
  663.                         /* Loop once for each line segment */
  664.                         for (i = 0; i < cpt; ++i) {
  665.  
  666.                                 if (lpbr) {
  667.                                         // do scanline with the brush
  668.                                         // create a box to fill
  669.                                         PrintChannel(lpdv, "%d .5 %d %d B 1 F n\n",
  670.                                                 lppt->y - lppt->x,
  671.                                                 lppt->x, iy);
  672.                                 } else {
  673.                                         // do scanline with the pen
  674.                                         // draw a line
  675.                                         PrintChannel(lpdv, "%d %d M %d 0 rlt S n\n",
  676.                                                 lppt->x, iy,
  677.                                                 lppt->y - lppt->x);
  678.                                 }
  679.  
  680.                                 ++lppt;
  681.                         }
  682.                 }
  683.                 break;
  684.  
  685.         case OS_RECTANGLE:
  686.  
  687. DO_RECT:
  688.  
  689.                 DBMSG1((" Output(): OS_RECTANGLE\n"));
  690.  
  691.                 if (lpbr && (lpbr->lb.lbStyle == BS_PATTERN ||
  692.                              lpbr->lb.lbStyle == BS_HATCHED))
  693.         {
  694.  
  695.                         // apply the same trick here as with scan lines
  696.                         // for hatched and pattern things we clip to the
  697.                         // path we define.  this means it has to have
  698.                         // some finite width.  so we add .5 to all the dx dy
  699.                         // parts of the box
  700.             // due to bug 13470 we must ensure min dimensions
  701.             // of box at least 1.0
  702.  
  703.             int  dx, dy;
  704.  
  705.             dx = (lppt+1)->x - lppt->x - 1;
  706.             dy = (lppt+1)->y - lppt->y - 1;
  707.  
  708.             if(dx < 1)
  709.                 dx = 1;
  710.             if(dy < 1)
  711.                 dy = 1;
  712.  
  713.                         PrintChannel(lpdv, "%d %d %d %d B\n",
  714.                                 dx, dy, lppt->x, lppt->y);
  715.  
  716.                 } else {
  717.                         PrintChannel(lpdv, "%d %d %d %d B\n",
  718.                                 (lppt+1)->x - lppt->x - 1, (lppt+1)->y - lppt->y - 1,
  719.                                 lppt->x, lppt->y);
  720.                 }
  721.  
  722.                 break;
  723.  
  724.         case OS_ROUNDRECT:
  725.  
  726.         DBMSG1((" Output(): OS_ROUNDRECT\n"));
  727.     {
  728.         int  dx, dy, rx, ry;
  729.  
  730.         dx =  (lppt+1)->x - lppt->x;
  731.         if(dx < 0)
  732.             dx *= -1;
  733.         dy =  (lppt+1)->y  -  lppt->y;
  734.         if(dy < 0)
  735.             dy *= -1;
  736.         rx = (lppt+2)->x;
  737.         ry = (lppt+2)->y;
  738.  
  739.         if(rx > dx)
  740.             rx = dx;
  741.         if(ry > dy)
  742.             ry = dy;
  743.         
  744.         PrintChannel(lpdv, "%d %d %d %d %d %d RR\n",
  745.             lppt->x, lppt->y,            /* ul corner */
  746.             (lppt+1)->x, (lppt+1)->y,        /* lr corner */
  747.             rx/2, ry/2);    /* x y dim radii */
  748.         break;
  749.     }
  750.  
  751.         case OS_POLYLINE:
  752.         case OS_ALTPOLYGON:     /* eofill */
  753.         case OS_WINDPOLYGON:    /* fill */
  754.  
  755.                 DBMSG1((" Output(): OS_POLYLINE\n"));
  756.                 DBMSG1((" Output(): OS_POLYGON: cpt=%d\n", cpt));
  757.  
  758.                 Fill = FALSE;   /* NOTE: fill and stroke are performed */
  759.                 Draw = FALSE;   /* inside Polygon() and Polyline() */
  760.  
  761.                 if (!Polygon(lpdv, iStyle, iStyle != OS_POLYLINE, lppt, cpt)) {
  762.                         if (lprcClip)
  763.                                 ClipBox(lpdv, NULL);
  764.                         return -1;      // GDI simulate!
  765.                 }
  766.                 break;
  767.  
  768.         default:
  769.                 Draw = FALSE;
  770.                 Fill = FALSE;
  771.         }
  772.  
  773.  
  774.         /* if lpdv->PathLevel > 0 then we are inside a BEGIN_PATH escape.
  775.          * in this mode we do not do output until the END_PATH
  776.          * escape is seen */
  777.  
  778.         if (lpdv->PathLevel <= 0) {
  779.  
  780.                 FillDraw(lpdv, Fill, Draw, 1);
  781.  
  782.                 if (!XformLevel && lprcClip)
  783.                         ClipBox(lpdv, NULL);
  784.         } else {
  785.  
  786.                 /* when inside a path we redfine the move operator (M) to
  787.                  * connect paths (using lineto) instead of moving to
  788.                  * a new point (and starting a new subpath). */
  789.  
  790.                 if (MoveCmd == 'M') {
  791.                         MoveCmd = 'L';
  792.                 }
  793.         }
  794.  
  795.         return TRUE;
  796. }
  797.  
  798.  
  799.  
  800. /************************************************************
  801. * Name: Pixel()
  802. *
  803. * Action: This routine sets or retrieves the color of a given
  804. *         pixel.
  805. *
  806. **************************************************************/
  807.  
  808. CO FAR PASCAL Pixel(lpdv, ix, iy, co, lpdm)
  809. LPDV    lpdv;       /* Far ptr to the device descriptor */
  810. int     ix;         /* The horizontal device coordinate */
  811. int     iy;         /* The vertical device coordinate */
  812. CO      co;         /* The physical color */
  813. LPDRAWMODE lpdm;    /* ptr to DRAWMODE (includes raster op, etc.) */
  814. {
  815.         ASSERT(lpdv);
  816.  
  817.         if (!lpdv->iType)
  818.                 return dmPixel(lpdv, ix, iy, co, lpdm);
  819.  
  820. #ifdef PS_IGNORE
  821.         if (lpdv->fSupressOutput)
  822.                 return 1;
  823. #endif
  824.         if (lpdm) {
  825.                 #define R2_NOP 11       // No Op, just move the current position
  826.  
  827.                 if (lpdm->Rop2 == R2_NOP) {
  828.                         PrintChannel(lpdv, "%d %d M\n", ix, iy);
  829.                 } else {
  830.  
  831.                         PrintChannel(lpdv, "%d %d %d sc %d %d M %d %d L st\n",
  832.                         GetRComponent(lpdv, co),
  833.                         GetGComponent(lpdv, co),
  834.                         GetBComponent(lpdv, co),
  835.                         ix, iy, ix + 1, iy);
  836.                 }
  837.         } else
  838.                 co = CODEFAULT;
  839.  
  840.         return co;
  841. }
  842.  
  843.  
  844.  
  845.  
  846.  
  847. /*******************************************************************
  848. * Name: ScanLR()
  849. *
  850. * Action: This routine is used to scan a single horizontal scan line
  851. *         on the device's display surface for a pixel having ( or not
  852. *         having a given color.  The direction of scan can be left or
  853. *         right from the specified starting position.
  854. *
  855. * Note: We can't support this call for Postscript since the
  856. *       bitmap is down in the printer and there is no way to access it.
  857. *       So the best thing that we can do is return the starting position
  858. *       as the location of the boundary. This will cause flood-fill to
  859. *       generally do the wrong thig, but this is one of those ugly facts
  860. *       of life.
  861. *
  862. *********************************************************************/
  863.  
  864. int     FAR PASCAL ScanLR(lpdv, ix, iy, co, iStyle)
  865. LPDV    lpdv;       /* Far ptr to the device descriptor */
  866. int     ix;         /* The starting horizontal device coordinate */
  867. int     iy;         /* The starting vertical device coordinate */
  868. CO      co;         /* The physical color to search for */
  869. int     iStyle;     /* The direction of scan, etc. */
  870. {
  871.         if (!lpdv->iType)
  872.                 return dmScanLR(lpdv, ix, iy, co, iStyle);
  873.         return (ix);    /* punt */
  874. }
  875.  
  876.  
  877.  
  878.  
  879.  
  880.  
  881. /****************************************************************
  882.  * DWORD FAR PASCAL ColorInfo(LPDV lpdv, DWORD rgb, LPCO lpco)
  883.  *
  884.  * convert between logical RGB color representation and the
  885.  * device's physical color representation and return closest color.
  886.  *
  887.  * in:
  888.  *      rgb     logical RGB color to convert or get info on
  889.  *      lpco    pointer to physical color to fill in if not NULL
  890.  *
  891.  * out:
  892.  *      *lpco gets the nearest RGB (this actually goes into the
  893.  *      DRAWMODE struct for future TextOut or SetPixel calls)
  894.  *
  895.  * return:
  896.  *      the nearest solid color (that can be represented by a pixel)
  897.  *      for black and white we convert to black and white, for
  898.  *      color we keep the hi bit of each color component.
  899.  *
  900.  *******************************************************************/
  901.  
  902. DWORD FAR PASCAL ColorInfo(LPDV lpdv, DWORD rgb, LPCO lpco)
  903. {
  904.         if (!lpdv->iType)       /* is this our PDEVICE? */
  905.                 return dmColorInfo(lpdv, rgb, lpco);
  906.  
  907.         // are we converting logical to physical?
  908.  
  909.         if (lpco)
  910.                 *lpco = (CO)rgb;        // store pcolor (same as logical)
  911.  
  912.  
  913.         if (lpdv->fColor) {
  914.                 DWORD color = RGB_BLACK;
  915.                 if (GetRComponent(lpdv, rgb) > 127)
  916.                         color |= 0xFF;
  917.                 if (GetGComponent(lpdv, rgb) > 127)
  918.                         color |= 0xFF00;
  919.                 if (GetBComponent(lpdv, rgb) > 127)
  920.                         color |= 0xFF0000;
  921.                 return color;
  922.         } else {
  923.  
  924.                 // mono black and white type device
  925.  
  926.                 if (INTENSITY(GetRComponent(lpdv, rgb),GetGComponent(lpdv, rgb),GetBComponent(lpdv, rgb)) > 127)
  927.                         return RGB_WHITE;
  928.                 else
  929.                         return RGB_BLACK;
  930.         }
  931. }
  932.  
  933.  
  934. /*********************************************************************
  935. * Name: SelectBrush()
  936. *
  937. * Action: This routine is called to establish a new brush pattern by
  938. *         all output routines that use brushes (Output and BitBlt).
  939. *
  940. * This code is ugly because it tries to output only the minimal
  941. * amount of information necessary to define the current brush.  that
  942. * is it keeps track of what parts of the brush have already been
  943. * defined and does not repeat downloading that data.
  944. ***********************************************************************/
  945.  
  946. void FAR PASCAL SelectBrush(lpdv, lpbr, lpdm)
  947. LPDV lpdv;
  948. LPBR lpbr;              /* physical brush */
  949. LPDRAWMODE lpdm;                /* has fg and bg color for patterns */
  950. {
  951.         LPSTR   lpb;
  952.         DWORD   FillColor, HatPatColor;
  953.         WORD    fm;             /* fill mode */
  954.         int     i;
  955.  
  956.         ASSERT(lpdv);
  957.         if (!lpbr || (lpbr->lb.lbStyle == BS_HOLLOW)) {
  958.                 lpdv->FillMode = FM_NONE;
  959.                 return;
  960.         }
  961.  
  962.         switch (lpbr->lb.lbStyle) {
  963.         case BS_SOLID:
  964.                 FillColor = lpbr->lb.lbColor;
  965.                 fm = FM_FILL;
  966.                 break;
  967.  
  968.         case BS_HATCHED:
  969.  
  970.                 FillColor = lpbr->lb.lbBkColor;
  971.                 HatPatColor = lpbr->lb.lbColor;
  972.  
  973.                 fm = FM_HATCH | lpbr->lb.lbHatch;
  974.  
  975.                 if (lpdm->bkMode == OPAQUE)
  976.                         fm |= FM_FILL;
  977.                 break;
  978.  
  979.  
  980.         case BS_PATTERN:
  981.  
  982.                 // we should check the pattern for all 0s or 1s and
  983.                 // replace the pattern fill with a solid fill to speed
  984.                 // things up (pattern filling can be slow)
  985.         {
  986.             BOOL  SnowWhite = TRUE, PitchBlack = TRUE;
  987.             WORD  i ;
  988.  
  989.             for(i = 0 ; i < sizeof(lpbr->rgbPat) ; i++)
  990.             {
  991.                 if(lpbr->rgbPat[i] != 0xFF)
  992.                     SnowWhite = FALSE;
  993.                 if(lpbr->rgbPat[i])
  994.                     PitchBlack = FALSE;
  995.                 if(!(SnowWhite || PitchBlack))
  996.                     break;
  997.             }
  998.  
  999.             if(SnowWhite || PitchBlack)
  1000.             {
  1001.                     lpbr->lb.lbStyle = BS_SOLID;
  1002.                         fm = FM_FILL;
  1003.  
  1004.                 if(SnowWhite)
  1005.                         FillColor = lpdm->bkColor;
  1006.                 else  //  must then be PitchBlack
  1007.                         FillColor = lpdm->TextColor;
  1008.  
  1009.                         lpbr->lb.lbColor = FillColor & (DWORD)0x00ffffff;
  1010.                 break;
  1011.             }
  1012.         }
  1013.  
  1014.  
  1015.                 // use the currently active text and bk colors
  1016.                 // for mono bitmaps (there is no color info in the bitmap)
  1017.  
  1018.                 FillColor = lpdm->bkColor;
  1019.                 HatPatColor = lpdm->TextColor;
  1020.  
  1021.  
  1022.                 fm = FM_PATTERN;
  1023.  
  1024.                 // pattern brushes are always OPAQUE!
  1025.  
  1026.                 // if (lpdm->bkMode == OPAQUE)
  1027.                         fm |= FM_FILL;
  1028.  
  1029.                 break;
  1030.         }
  1031.  
  1032.         /* this applies to cases that fill (solid, opaque pats and hatches) */
  1033.  
  1034.         /* is this the first time we have done a fill or is the fill color
  1035.          * different */
  1036.  
  1037.         if ((fm & FM_FILL)  &&
  1038.             (!(lpdv->FillMode & FM_FILL) || lpdv->FillColor != FillColor)) {
  1039.                 PrintChannel(lpdv, "%d %d %d fC\n",
  1040.                         GetRComponent(lpdv, FillColor),
  1041.                         GetGComponent(lpdv, FillColor),
  1042.                         GetBComponent(lpdv, FillColor));
  1043.                 lpdv->FillColor = FillColor;            /* save the color */
  1044.         }
  1045.  
  1046.         /* this applies to both pattern and hatch */
  1047.  
  1048.         if (fm & (FM_HATCH | FM_PATTERN)) {
  1049.  
  1050.                 /* is this the first time we set hC or are the colors different */
  1051.  
  1052.                 if (!(lpdv->FillMode & (FM_HATCH | FM_PATTERN)) ||
  1053.                     lpdv->HatchColor != HatPatColor) {
  1054.                         PrintChannel(lpdv, "%d %d %d hC\n",
  1055.                                 GetRComponent(lpdv, HatPatColor),
  1056.                                 GetGComponent(lpdv, HatPatColor),
  1057.                                 GetBComponent(lpdv, HatPatColor));
  1058.                         lpdv->HatchColor = HatPatColor; /* save the color */
  1059.  
  1060.                 }
  1061.  
  1062.         }
  1063.  
  1064.         /* update the filling mode if it has changed */
  1065.  
  1066.         if (lpdv->FillMode != fm)
  1067.  
  1068.                 PrintChannel(lpdv, "/fm %d def\n", fm);
  1069.  
  1070.  
  1071.         /* update the fill pattern if:
  1072.         *       we are pattern filling now
  1073.         *       AND
  1074.         *       the last fillmode did not use a pattern (this gets the
  1075.         *       initial case)
  1076.         *       OR
  1077.         *       the the fill pattern has changed */
  1078.  
  1079.         if ((fm & FM_PATTERN) &&
  1080.         (!(lpdv->FillMode & FM_PATTERN) ||
  1081.         !lmemIsEqual(lpdv->br.rgbPat, lpbr->rgbPat,
  1082.                         sizeof(lpbr->rgbPat)))) {
  1083.                 WriteChannelChar(lpdv, '<');
  1084.                 lpb = lpbr->rgbPat;
  1085.                 for (i = 0; i < sizeof(lpbr->rgbPat); i++)
  1086.                         PrintChannel(lpdv, hex, *lpb++);
  1087.                 PrintChannel(lpdv, "> p\n");
  1088.  
  1089.                 /* save the pattern */
  1090.                 lmemcpy(lpdv->br.rgbPat, lpbr->rgbPat, sizeof(lpbr->rgbPat));
  1091.         }
  1092.  
  1093.  
  1094.         lpdv->FillMode = fm;    /* do this last, code above depends on this */
  1095. }
  1096.  
  1097.  
  1098.  
  1099.  
  1100. /*******************************************************************
  1101.  * Name: SelectPen()
  1102.  *
  1103.  * Action: This routine is called to establish a new pen by
  1104.  *        all routines that use a pen for output.
  1105.  *
  1106.  *********************************************************************/
  1107.  
  1108. void FAR PASCAL SelectPen(lpdv, lppen)
  1109. LPDV    lpdv;   /* Far ptr to the device */
  1110. LPPEN   lppen;  /* Far ptr to the pen */
  1111. {
  1112.         int     iLineCap;
  1113.         int     iLineJoin;
  1114.  
  1115.         if (!lppen || (lppen->lopn.lopnStyle == LS_NOLINE)) {
  1116.                 lpdv->pen.lopn.lopnStyle = LS_NOLINE;
  1117.                 return;
  1118.         }
  1119.  
  1120.         iLineCap  = lpdv->iNewLineCap;
  1121.         iLineJoin = lpdv->iNewLineJoin;
  1122.  
  1123.  
  1124.         /* Fix up the line caps if we are defaulting to GDI's style */
  1125.         if (iLineCap == -1)
  1126.                 if (lppen->fRound)
  1127.                         iLineCap = 1;
  1128.                 else
  1129.                         iLineCap = 0;
  1130.  
  1131.  
  1132.         /* Fix up the line join if we are defaulting to GDI's style */
  1133.         if (iLineJoin == -1)
  1134.                 if (lppen->fRound)
  1135.                         iLineJoin = 1;
  1136.                 else
  1137.                         iLineJoin = 0;
  1138.  
  1139.         /* Set the line cap if it has changed */
  1140.         if (lpdv->iCurLineCap != iLineCap) {
  1141.                 PrintChannel(lpdv, "%d lc\n", iLineCap);
  1142.                 lpdv->iCurLineCap = iLineCap;
  1143.         }
  1144.  
  1145.         /* Set the line join if it has changed */
  1146.         if (lpdv->iCurLineJoin != iLineJoin) {
  1147.                 PrintChannel(lpdv, "%d lj\n", iLineJoin);
  1148.                 lpdv->iCurLineJoin = iLineJoin;
  1149.         }
  1150.  
  1151.         /* Update the miter limit */
  1152.         if (lpdv->iCurMiterLimit != lpdv->iNewMiterLimit) {
  1153.                 PrintChannel(lpdv, "%d ml\n",
  1154.                     lpdv->iNewMiterLimit);
  1155.                 lpdv->iCurMiterLimit = lpdv->iNewMiterLimit;
  1156.         }
  1157.  
  1158.         /* Change pen color if necessary */
  1159.  
  1160.         if (!lpdv->fPenSelected || lppen->lopn.lopnColor != lpdv->pen.lopn.lopnColor) {
  1161.                 PrintChannel(lpdv, "%d %d %d pC\n",
  1162.                         GetRComponent(lpdv, lppen->lopn.lopnColor),
  1163.                         GetGComponent(lpdv, lppen->lopn.lopnColor),
  1164.                         GetBComponent(lpdv, lppen->lopn.lopnColor));
  1165.  
  1166.                 lpdv->pen.lopn.lopnColor = lppen->lopn.lopnColor;
  1167.         }
  1168.  
  1169.         /* change width and style (dashed or not) */
  1170.  
  1171.         if (!lpdv->fPenSelected || PenWidth(lppen) != PenWidth(&lpdv->pen) ||
  1172.             lppen->lopn.lopnStyle != lpdv->pen.lopn.lopnStyle) {
  1173.  
  1174.                 /* SP == set pen */
  1175.                 PrintChannel(lpdv, "%d %d SP\n", lppen->lopn.lopnStyle, PenWidth(lppen));
  1176.  
  1177.                 /* Save the current pen parameters */
  1178.                 lpdv->pen = *lppen;
  1179.         }
  1180.  
  1181.         lpdv->fPenSelected = TRUE;
  1182. }
  1183.  
  1184.  
  1185. int FAR PASCAL GetRComponent(LPDV lpdv, DWORD dwRGB)
  1186. {
  1187.     int r;
  1188.  
  1189.     r = GetRValue(dwRGB);
  1190.     if (lpdv->bColorToBlack
  1191.         && ((dwRGB & RGB(255,255,255)) != RGB(255,255,255)))
  1192.         r = 0;
  1193.  
  1194.     return r;
  1195. }
  1196.  
  1197. int FAR PASCAL GetGComponent(LPDV lpdv, DWORD dwRGB)
  1198. {
  1199.     int g;
  1200.  
  1201.     g = GetGValue(dwRGB);
  1202.     if (lpdv->bColorToBlack
  1203.         && ((dwRGB & RGB(255,255,255)) != RGB(255,255,255)))
  1204.         g = 0;
  1205.  
  1206.     return g;
  1207. }
  1208.  
  1209. int FAR PASCAL GetBComponent(LPDV lpdv, DWORD dwRGB)
  1210. {
  1211.     int b;
  1212.  
  1213.     b = GetBValue(dwRGB);
  1214.     if (lpdv->bColorToBlack
  1215.         && ((dwRGB & RGB(255,255,255)) != RGB(255,255,255)))
  1216.         b = 0;
  1217.  
  1218.     return b;
  1219. }
  1220.  
  1221.