home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tk / win / tkWinDraw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-08  |  31.8 KB  |  1,259 lines

  1. /* 
  2.  * tkWinDraw.c --
  3.  *
  4.  *    This file contains the Xlib emulation functions pertaining to
  5.  *    actually drawing objects on a window.
  6.  *
  7.  * Copyright (c) 1995 Sun Microsystems, Inc.
  8.  * Copyright (c) 1994 Software Research Associates, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * SCCS: @(#) tkWinDraw.c 1.18 96/03/01 17:43:41
  14.  */
  15.  
  16. #include "tkWinInt.h"
  17.  
  18. /*
  19.  * These macros convert between X's bizarre angle units to radians.
  20.  */
  21.  
  22. #define PI 3.14159265358979
  23. #define XAngleToRadians(a) ((double)(a) / 64 * PI / 180);
  24.  
  25. /*
  26.  * Translation table between X gc functions and Win32 raster op modes.
  27.  */
  28.  
  29. static int ropModes[] = {
  30.     R2_BLACK,            /* GXclear */
  31.     R2_MASKPEN,            /* GXand */
  32.     R2_MASKPENNOT,        /* GXandReverse */
  33.     R2_COPYPEN,            /* GXcopy */
  34.     R2_MASKNOTPEN,        /* GXandInverted */
  35.     R2_NOT,            /* GXnoop */
  36.     R2_XORPEN,            /* GXxor */
  37.     R2_MERGEPEN,        /* GXor */
  38.     R2_NOTMERGEPEN,        /* GXnor */
  39.     R2_NOTXORPEN,        /* GXequiv */
  40.     R2_NOT,            /* GXinvert */
  41.     R2_MERGEPENNOT,        /* GXorReverse */
  42.     R2_NOTCOPYPEN,        /* GXcopyInverted */
  43.     R2_MERGENOTPEN,        /* GXorInverted */
  44.     R2_NOTMASKPEN,        /* GXnand */
  45.     R2_WHITE            /* GXset */
  46. };
  47.  
  48. /*
  49.  * Translation table between X gc functions and Win32 BitBlt op modes.  Some
  50.  * of the operations defined in X don't have names, so we have to construct
  51.  * new opcodes for those functions.  This is arcane and probably not all that
  52.  * useful, but at least it's accurate.
  53.  */
  54.  
  55. #define NOTSRCAND    (DWORD)0x00220326 /* dest = (NOT source) AND dest */
  56. #define NOTSRCINVERT    (DWORD)0x00990066 /* dest = (NOT source) XOR dest */
  57. #define SRCORREVERSE    (DWORD)0x00DD0228 /* dest = source OR (NOT dest) */
  58. #define SRCNAND        (DWORD)0x007700E6 /* dest = NOT (source AND dest) */
  59.  
  60. static int bltModes[] = {
  61.     BLACKNESS,            /* GXclear */
  62.     SRCAND,            /* GXand */
  63.     SRCERASE,            /* GXandReverse */
  64.     SRCCOPY,            /* GXcopy */
  65.     NOTSRCAND,            /* GXandInverted */
  66.     PATCOPY,            /* GXnoop */
  67.     SRCINVERT,            /* GXxor */
  68.     SRCPAINT,            /* GXor */
  69.     NOTSRCERASE,        /* GXnor */
  70.     NOTSRCINVERT,        /* GXequiv */
  71.     DSTINVERT,            /* GXinvert */
  72.     SRCORREVERSE,        /* GXorReverse */
  73.     NOTSRCCOPY,            /* GXcopyInverted */
  74.     MERGEPAINT,            /* GXorInverted */
  75.     SRCNAND,            /* GXnand */
  76.     WHITENESS            /* GXset */
  77. };
  78.  
  79. /*
  80.  * The following raster op uses the source bitmap as a mask for the
  81.  * pattern.  This is used to draw in a foreground color but leave the
  82.  * background color transparent.
  83.  */
  84.  
  85. #define MASKPAT        0x00E20746 /* dest = (src & pat) | (!src & dst) */
  86.  
  87. /*
  88.  * The following two raster ops are used to copy the foreground and background
  89.  * bits of a source pattern as defined by a stipple used as the pattern.
  90.  */
  91.  
  92. #define COPYFG        0x00CA0749 /* dest = (pat & src) | (!pat & dst) */
  93. #define COPYBG        0x00AC0744 /* dest = (!pat & src) | (pat & dst) */
  94.  
  95. /*
  96.  * Macros used later in the file.
  97.  */
  98.  
  99. #define MIN(a,b)    ((a>b) ? b : a)
  100. #define MAX(a,b)    ((a<b) ? b : a)
  101.  
  102. /*
  103.  * The followng typedef is used to pass Windows GDI drawing functions.
  104.  */
  105.  
  106. typedef WINGDIAPI BOOL (WINAPI *WinDrawFunc) _ANSI_ARGS_((HDC dc,
  107.                 CONST POINT* points, int npoints));
  108.  
  109. /*
  110.  * Forward declarations for procedures defined in this file:
  111.  */
  112.  
  113. static POINT *        ConvertPoints _ANSI_ARGS_((XPoint *points, int npoints,
  114.                 int mode, RECT *bbox));
  115. static void        DrawOrFillArc _ANSI_ARGS_((Display *display,
  116.                 Drawable d, GC gc, int x, int y,
  117.                 unsigned int width, unsigned int height,
  118.                 int angle1, int angle2, int fill));
  119. static void        RenderObject _ANSI_ARGS_((HDC dc, GC gc,
  120.                 XPoint* points, int npoints, int mode, HPEN pen,
  121.                 WinDrawFunc func));
  122.  
  123. /*
  124.  *----------------------------------------------------------------------
  125.  *
  126.  * TkWinGetDrawableDC --
  127.  *
  128.  *    Retrieve the DC from a drawable.
  129.  *
  130.  * Results:
  131.  *    Returns the window DC for windows.  Returns a new memory DC
  132.  *    for pixmaps.
  133.  *
  134.  * Side effects:
  135.  *    Sets up the palette for the device context, and saves the old
  136.  *    device context state in the passed in TkWinDCState structure.
  137.  *
  138.  *----------------------------------------------------------------------
  139.  */
  140.  
  141. HDC
  142. TkWinGetDrawableDC(display, d, state)
  143.     Display *display;
  144.     Drawable d;
  145.     TkWinDCState* state;
  146. {
  147.     HDC dc;
  148.     TkWinDrawable *twdPtr = (TkWinDrawable *)d;
  149.     Colormap cmap;
  150.  
  151.     if (twdPtr->type != TWD_BITMAP) {
  152.     TkWindow *winPtr = twdPtr->window.winPtr;
  153.     
  154.      dc = GetDC(twdPtr->window.handle);
  155.     if (winPtr == NULL) {
  156.         cmap = DefaultColormap(display, DefaultScreen(display));
  157.     } else {
  158.         cmap = winPtr->atts.colormap;
  159.     }
  160.     } else {
  161.     HDC dcMem;
  162.     dc = GetDC(NULL);
  163.     dcMem = CreateCompatibleDC(dc);
  164.     ReleaseDC(NULL, dc);
  165.     SelectObject(dcMem, twdPtr->bitmap.handle);
  166.     dc = dcMem;
  167.     cmap = twdPtr->bitmap.colormap;
  168.     }
  169.     state->palette = TkWinSelectPalette(dc, cmap);
  170.     return dc;
  171. }
  172.  
  173. /*
  174.  *----------------------------------------------------------------------
  175.  *
  176.  * TkWinReleaseDrawableDC --
  177.  *
  178.  *    Frees the resources associated with a drawable's DC.
  179.  *
  180.  * Results:
  181.  *    None.
  182.  *
  183.  * Side effects:
  184.  *    Restores the old bitmap handle to the memory DC for pixmaps.
  185.  *
  186.  *----------------------------------------------------------------------
  187.  */
  188.  
  189. void
  190. TkWinReleaseDrawableDC(d, dc, state)
  191.     Drawable d;
  192.     HDC dc;
  193.     TkWinDCState *state;
  194. {
  195.     TkWinDrawable *twdPtr = (TkWinDrawable *)d;
  196.     SelectPalette(dc, state->palette, TRUE);
  197.     RealizePalette(dc);
  198.     if (twdPtr->type != TWD_BITMAP) {
  199.     ReleaseDC(TkWinGetHWND(d), dc);
  200.     } else {
  201.     DeleteDC(dc);
  202.     }
  203. }
  204.  
  205. /*
  206.  *----------------------------------------------------------------------
  207.  *
  208.  * ConvertPoints --
  209.  *
  210.  *    Convert an array of X points to an array of Win32 points.
  211.  *
  212.  * Results:
  213.  *    Returns the converted array of POINTs.
  214.  *
  215.  * Side effects:
  216.  *    Allocates a block of memory that should not be freed.
  217.  *
  218.  *----------------------------------------------------------------------
  219.  */
  220.  
  221. static POINT *
  222. ConvertPoints(points, npoints, mode, bbox)
  223.     XPoint *points;
  224.     int npoints;
  225.     int mode;            /* CoordModeOrigin or CoordModePrevious. */
  226.     RECT *bbox;            /* Bounding box of points. */
  227. {
  228.     static POINT *winPoints = NULL; /* Array of points that is reused. */
  229.     static int nWinPoints = -1;        /* Current size of point array. */
  230.     int i;
  231.  
  232.     /*
  233.      * To avoid paying the cost of a malloc on every drawing routine,
  234.      * we reuse the last array if it is large enough.
  235.      */
  236.  
  237.     if (npoints > nWinPoints) {
  238.     if (winPoints != NULL) {
  239.         ckfree((char *) winPoints);
  240.     }
  241.     winPoints = (POINT *) ckalloc(sizeof(POINT) * npoints);
  242.     if (winPoints == NULL) {
  243.         nWinPoints = -1;
  244.         return NULL;
  245.     }
  246.     nWinPoints = npoints;
  247.     }
  248.  
  249.     bbox->left = bbox->right = points[0].x;
  250.     bbox->top = bbox->bottom = points[0].y;
  251.     
  252.     if (mode == CoordModeOrigin) {
  253.     for (i = 0; i < npoints; i++) {
  254.         winPoints[i].x = points[i].x;
  255.         winPoints[i].y = points[i].y;
  256.         bbox->left = MIN(bbox->left, winPoints[i].x);
  257.         bbox->right = MAX(bbox->right, winPoints[i].x);
  258.         bbox->top = MIN(bbox->top, winPoints[i].y);
  259.         bbox->bottom = MAX(bbox->bottom, winPoints[i].y);
  260.     }
  261.     } else {
  262.     winPoints[0].x = points[0].x;
  263.     winPoints[0].y = points[0].y;
  264.     for (i = 1; i < npoints; i++) {
  265.         winPoints[i].x = winPoints[i-1].x + points[i].x;
  266.         winPoints[i].y = winPoints[i-1].y + points[i].y;
  267.         bbox->left = MIN(bbox->left, winPoints[i].x);
  268.         bbox->right = MAX(bbox->right, winPoints[i].x);
  269.         bbox->top = MIN(bbox->top, winPoints[i].y);
  270.         bbox->bottom = MAX(bbox->bottom, winPoints[i].y);
  271.     }
  272.     }
  273.     return winPoints;
  274. }
  275.  
  276. /*
  277.  *----------------------------------------------------------------------
  278.  *
  279.  * XCopyArea --
  280.  *
  281.  *    Copies data from one drawable to another using block transfer
  282.  *    routines.
  283.  *
  284.  * Results:
  285.  *    None.
  286.  *
  287.  * Side effects:
  288.  *    Data is moved from a window or bitmap to a second window or
  289.  *    bitmap.
  290.  *
  291.  *----------------------------------------------------------------------
  292.  */
  293.  
  294. void
  295. XCopyArea(display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y)
  296.     Display* display;
  297.     Drawable src;
  298.     Drawable dest;
  299.     GC gc;
  300.     int src_x, src_y;
  301.     unsigned int width, height;
  302.     int dest_x, dest_y;
  303. {
  304.     HDC srcDC, destDC;
  305.     TkWinDCState srcState, destState;
  306.  
  307.     srcDC = TkWinGetDrawableDC(display, src, &srcState);
  308.  
  309.     if (src != dest) {
  310.     destDC = TkWinGetDrawableDC(display, dest, &destState);
  311.     } else {
  312.     destDC = srcDC;
  313.     }
  314.  
  315.     BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
  316.         bltModes[gc->function]);
  317.  
  318.     if (src != dest) {
  319.     TkWinReleaseDrawableDC(dest, destDC, &destState);
  320.     }
  321.     TkWinReleaseDrawableDC(src, srcDC, &srcState);
  322. }
  323.  
  324. /*
  325.  *----------------------------------------------------------------------
  326.  *
  327.  * XCopyPlane --
  328.  *
  329.  *    Copies a bitmap from a source drawable to a destination
  330.  *    drawable.  The plane argument specifies which bit plane of
  331.  *    the source contains the bitmap.  Note that this implementation
  332.  *    ignores the gc->function.
  333.  *
  334.  * Results:
  335.  *    None.
  336.  *
  337.  * Side effects:
  338.  *    Changes the destination drawable.
  339.  *
  340.  *----------------------------------------------------------------------
  341.  */
  342.  
  343. void
  344. XCopyPlane(display, src, dest, gc, src_x, src_y, width, height, dest_x,
  345.     dest_y, plane)
  346.     Display* display;
  347.     Drawable src;
  348.     Drawable dest;
  349.     GC gc;
  350.     int src_x, src_y;
  351.     unsigned int width, height;
  352.     int dest_x, dest_y;
  353.     unsigned long plane;
  354. {
  355.     HDC srcDC, destDC;
  356.     TkWinDCState srcState, destState;
  357.     HBRUSH bgBrush, fgBrush, oldBrush;
  358.  
  359.     display->request++;
  360.  
  361.     if (plane != 1) {
  362.     panic("Unexpected plane specified for XCopyPlane");
  363.     }
  364.  
  365.     srcDC = TkWinGetDrawableDC(display, src, &srcState);
  366.  
  367.     if (src != dest) {
  368.     destDC = TkWinGetDrawableDC(display, dest, &destState);
  369.     } else {
  370.     destDC = srcDC;
  371.     }
  372.  
  373.     if (gc->clip_mask == src) {
  374.  
  375.     /*
  376.      * Case 1: transparent bitmaps are handled by setting the
  377.      * destination to the foreground color whenever the source
  378.      * pixel is set.
  379.      */
  380.  
  381.     fgBrush = CreateSolidBrush(gc->foreground);
  382.     oldBrush = SelectObject(destDC, fgBrush);
  383.     BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
  384.         MASKPAT);
  385.     SelectObject(destDC, oldBrush);
  386.     DeleteObject(fgBrush);
  387.     } else if (gc->clip_mask == None) {
  388.  
  389.     /*
  390.      * Case 2: opaque bitmaps.  Windows handles the conversion
  391.      * from one bit to multiple bits by setting 0 to the
  392.      * foreground color, and 1 to the background color (seems
  393.      * backwards, but there you are).
  394.      */
  395.  
  396.     SetBkMode(destDC, OPAQUE);
  397.     SetBkColor(destDC, gc->foreground);
  398.     SetTextColor(destDC, gc->background);
  399.     BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
  400.         SRCCOPY);
  401.     } else {
  402.  
  403.     /*
  404.      * Case 3: two arbitrary bitmaps.  Copy the source rectangle
  405.      * into a color pixmap.  Use the result as a brush when
  406.      * copying the clip mask into the destination.     
  407.      */
  408.  
  409.     HDC memDC, maskDC;
  410.     HBITMAP bitmap;
  411.     TkWinDCState maskState;
  412.  
  413.     fgBrush = CreateSolidBrush(gc->foreground);
  414.     bgBrush = CreateSolidBrush(gc->background);
  415.     maskDC = TkWinGetDrawableDC(display, gc->clip_mask, &maskState);
  416.     memDC = CreateCompatibleDC(destDC);
  417.     bitmap = CreateBitmap(width, height, 1, 1, NULL);
  418.     SelectObject(memDC, bitmap);
  419.  
  420.     /*
  421.      * Set foreground bits.  We create a new bitmap containing
  422.      * (source AND mask), then use it to set the foreground color
  423.      * into the destination.
  424.      */
  425.  
  426.     BitBlt(memDC, 0, 0, width, height, srcDC, src_x, src_y, SRCCOPY);
  427.     BitBlt(memDC, 0, 0, width, height, maskDC, dest_x - gc->clip_x_origin,
  428.         dest_y - gc->clip_y_origin, SRCAND);
  429.     oldBrush = SelectObject(destDC, fgBrush);
  430.     BitBlt(destDC, dest_x, dest_y, width, height, memDC, 0, 0, MASKPAT);
  431.  
  432.     /*
  433.      * Set background bits.  Same as foreground, except we use
  434.      * ((NOT source) AND mask) and the background brush.
  435.      */
  436.  
  437.     BitBlt(memDC, 0, 0, width, height, srcDC, src_x, src_y, NOTSRCCOPY);
  438.     BitBlt(memDC, 0, 0, width, height, maskDC, dest_x - gc->clip_x_origin,
  439.         dest_y - gc->clip_y_origin, SRCAND);
  440.     SelectObject(destDC, bgBrush);
  441.     BitBlt(destDC, dest_x, dest_y, width, height, memDC, 0, 0, MASKPAT);
  442.     
  443.  
  444.     TkWinReleaseDrawableDC(gc->clip_mask, maskDC, &maskState);
  445.     SelectObject(destDC, oldBrush);
  446.     DeleteDC(memDC);
  447.     DeleteObject(bitmap);
  448.     DeleteObject(fgBrush);
  449.     DeleteObject(bgBrush);
  450.     }
  451.     if (src != dest) {
  452.     TkWinReleaseDrawableDC(dest, destDC, &destState);
  453.     }
  454.     TkWinReleaseDrawableDC(src, srcDC, &srcState);
  455. }
  456.  
  457. /*
  458.  *----------------------------------------------------------------------
  459.  *
  460.  * TkPutImage --
  461.  *
  462.  *    Copies a subimage from an in-memory image to a rectangle of
  463.  *    of the specified drawable.
  464.  *
  465.  * Results:
  466.  *    None.
  467.  *
  468.  * Side effects:
  469.  *    Draws the image on the specified drawable.
  470.  *
  471.  *----------------------------------------------------------------------
  472.  */
  473.  
  474. void
  475. TkPutImage(colors, ncolors, display, d, gc, image, src_x, src_y, dest_x,
  476.     dest_y, width, height)
  477.     unsigned long *colors;        /* Array of pixel values used by this
  478.                      * image.  May be NULL. */
  479.     int ncolors;            /* Number of colors used, or 0. */
  480.     Display* display;
  481.     Drawable d;                /* Destination drawable. */
  482.     GC gc;
  483.     XImage* image;            /* Source image. */
  484.     int src_x, src_y;            /* Offset of subimage. */      
  485.     int dest_x, dest_y;            /* Position of subimage origin in
  486.                      * drawable.  */
  487.     unsigned int width, height;        /* Dimensions of subimage. */
  488. {
  489.     HDC dc, dcMem;
  490.     TkWinDCState state;
  491.     BITMAPINFO *infoPtr;
  492.     HBITMAP bitmap;
  493.     char *data;
  494.  
  495.     display->request++;
  496.  
  497.     dc = TkWinGetDrawableDC(display, d, &state);
  498.     SetROP2(dc, ropModes[gc->function]);
  499.     dcMem = CreateCompatibleDC(dc);
  500.  
  501.     if (image->bits_per_pixel == 1) {
  502.     data = TkAlignImageData(image, sizeof(WORD), MSBFirst);
  503.     bitmap = CreateBitmap(width, height, 1, 1, data);
  504.     SetTextColor(dc, gc->foreground);
  505.     SetBkColor(dc, gc->background);
  506.     ckfree(data);
  507.     } else {    
  508.     int i, usePalette;
  509.  
  510.     /*
  511.      * Do not use a palette for TrueColor images.
  512.      */
  513.     
  514.     usePalette = (image->bits_per_pixel < 24);
  515.     
  516.     if (usePalette) {
  517.         infoPtr = (BITMAPINFO*) ckalloc(sizeof(BITMAPINFOHEADER)
  518.             + sizeof(RGBQUAD)*ncolors);
  519.     } else {
  520.         infoPtr = (BITMAPINFO*) ckalloc(sizeof(BITMAPINFOHEADER));
  521.     }
  522.     
  523.     infoPtr->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  524.     infoPtr->bmiHeader.biWidth = image->width;
  525.  
  526.     /*
  527.      * The following code works around a bug in Win32s.  CreateDIBitmap
  528.      * fails under Win32s for top-down images.  So we have to reverse the
  529.      * order of the scanlines.  If we are not running under Win32s, we can
  530.      * just declare the image to be top-down.
  531.      */
  532.  
  533.     if ((GetVersion() & 0x80000000)) {
  534.         int y;
  535.         char *srcPtr, *dstPtr, *temp;
  536.  
  537.         temp = ckalloc((unsigned) image->bytes_per_line);
  538.         srcPtr = image->data;
  539.         dstPtr = image->data+(image->bytes_per_line * (image->height - 1));
  540.         for (y = 0; y < (image->height/2); y++) {
  541.         memcpy(temp, srcPtr, image->bytes_per_line);
  542.         memcpy(srcPtr, dstPtr, image->bytes_per_line);
  543.         memcpy(dstPtr, temp, image->bytes_per_line);
  544.         srcPtr += image->bytes_per_line;
  545.         dstPtr -= image->bytes_per_line;
  546.         }
  547.         ckfree(temp);
  548.         infoPtr->bmiHeader.biHeight = image->height; /* Bottom-up order */
  549.     } else {
  550.         infoPtr->bmiHeader.biHeight = -image->height; /* Top-down order */
  551.     }
  552.     infoPtr->bmiHeader.biPlanes = 1;
  553.     infoPtr->bmiHeader.biBitCount = image->bits_per_pixel;
  554.     infoPtr->bmiHeader.biCompression = BI_RGB;
  555.     infoPtr->bmiHeader.biSizeImage = 0;
  556.     infoPtr->bmiHeader.biXPelsPerMeter = 0;
  557.     infoPtr->bmiHeader.biYPelsPerMeter = 0;
  558.     infoPtr->bmiHeader.biClrImportant = 0;
  559.  
  560.     if (usePalette) {
  561.         infoPtr->bmiHeader.biClrUsed = ncolors;
  562.         for (i = 0; i < ncolors; i++) {
  563.         infoPtr->bmiColors[i].rgbBlue = GetBValue(colors[i]);
  564.         infoPtr->bmiColors[i].rgbGreen = GetGValue(colors[i]);
  565.         infoPtr->bmiColors[i].rgbRed = GetRValue(colors[i]);
  566.         infoPtr->bmiColors[i].rgbReserved = 0;
  567.         }
  568.     } else {
  569.         infoPtr->bmiHeader.biClrUsed = 0;
  570.     }
  571.     bitmap = CreateDIBitmap(dc, &infoPtr->bmiHeader, CBM_INIT,
  572.         image->data, infoPtr, DIB_RGB_COLORS);
  573.     ckfree(infoPtr);
  574.     }
  575.     bitmap = SelectObject(dcMem, bitmap);
  576.     BitBlt(dc, dest_x, dest_y, width, height, dcMem, src_x, src_y, SRCCOPY);
  577.     DeleteObject(SelectObject(dcMem, bitmap));
  578.     DeleteObject(dcMem);
  579.     TkWinReleaseDrawableDC(d, dc, &state);
  580. }
  581.  
  582. /*
  583.  *----------------------------------------------------------------------
  584.  *
  585.  * XDrawString --
  586.  *
  587.  *    Draw a single string in the current font.
  588.  *
  589.  * Results:
  590.  *    None.
  591.  *
  592.  * Side effects:
  593.  *    Renders the specified string in the drawable.
  594.  *
  595.  *----------------------------------------------------------------------
  596.  */
  597.  
  598. void
  599. XDrawString(display, d, gc, x, y, string, length)
  600.     Display* display;
  601.     Drawable d;
  602.     GC gc;
  603.     int x;
  604.     int y;
  605.     _Xconst char* string;
  606.     int length;
  607. {
  608.     HDC dc;
  609.     HFONT oldFont;
  610.     TkWinDCState state;
  611.  
  612.     display->request++;
  613.  
  614.     if (d == None) {
  615.     return;
  616.     }
  617.  
  618.     dc = TkWinGetDrawableDC(display, d, &state);
  619.     SetROP2(dc, ropModes[gc->function]);
  620.  
  621.     if ((gc->fill_style == FillStippled
  622.         || gc->fill_style == FillOpaqueStippled)
  623.         && gc->stipple != None) {
  624.     TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple;
  625.     HBRUSH oldBrush, stipple;
  626.     HBITMAP oldBitmap, bitmap;
  627.     HDC dcMem;
  628.     TEXTMETRIC tm;
  629.     SIZE size;
  630.  
  631.     if (twdPtr->type != TWD_BITMAP) {
  632.         panic("unexpected drawable type in stipple");
  633.     }
  634.  
  635.     /*
  636.      * Select stipple pattern into destination dc.
  637.      */
  638.     
  639.     dcMem = CreateCompatibleDC(dc);
  640.  
  641.     stipple = CreatePatternBrush(twdPtr->bitmap.handle);
  642.     SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL);
  643.     oldBrush = SelectObject(dc, stipple);
  644.  
  645.     SetTextAlign(dcMem, TA_LEFT | TA_TOP);
  646.     SetTextColor(dcMem, gc->foreground);
  647.     SetBkMode(dcMem, TRANSPARENT);
  648.     SetBkColor(dcMem, RGB(0, 0, 0));
  649.  
  650.     if (gc->font != None) {
  651.         oldFont = SelectObject(dcMem, (HFONT)gc->font);
  652.     }
  653.  
  654.     /*
  655.      * Compute the bounding box and create a compatible bitmap.
  656.      */
  657.  
  658.     GetTextExtentPoint(dcMem, string, length, &size);
  659.     GetTextMetrics(dcMem, &tm);
  660.     size.cx -= tm.tmOverhang;
  661.     bitmap = CreateCompatibleBitmap(dc, size.cx, size.cy);
  662.     oldBitmap = SelectObject(dcMem, bitmap);
  663.  
  664.     /*
  665.      * The following code is tricky because fonts are rendered in multiple
  666.      * colors.  First we draw onto a black background and copy the white
  667.      * bits.  Then we draw onto a white background and copy the black bits.
  668.      * Both the foreground and background bits of the font are ANDed with
  669.      * the stipple pattern as they are copied.
  670.      */
  671.  
  672.     PatBlt(dcMem, 0, 0, size.cx, size.cy, BLACKNESS);
  673.     TextOut(dcMem, 0, 0, string, length);
  674.     BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem,
  675.         0, 0, 0xEA02E9);
  676.     PatBlt(dcMem, 0, 0, size.cx, size.cy, WHITENESS);
  677.     TextOut(dcMem, 0, 0, string, length);
  678.     BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem,
  679.         0, 0, 0x8A0E06);
  680.  
  681.     /*
  682.      * Destroy the temporary bitmap and restore the device context.
  683.      */
  684.  
  685.     if (gc->font != None) {
  686.         SelectObject(dcMem, oldFont);
  687.     }
  688.     SelectObject(dcMem, oldBitmap);
  689.     DeleteObject(bitmap);
  690.     DeleteDC(dcMem);
  691.     SelectObject(dc, oldBrush);
  692.     DeleteObject(stipple);
  693.     } else {
  694.     SetTextAlign(dc, TA_LEFT | TA_BASELINE);
  695.     SetTextColor(dc, gc->foreground);
  696.     SetBkMode(dc, TRANSPARENT);
  697.     if (gc->font != None) {
  698.         oldFont = SelectObject(dc, (HFONT)gc->font);
  699.     }
  700.     TextOut(dc, x, y, string, length);
  701.     if (gc->font != None) {
  702.         SelectObject(dc, oldFont);
  703.     }
  704.     }
  705.     TkWinReleaseDrawableDC(d, dc, &state);
  706. }
  707.  
  708. /*
  709.  *----------------------------------------------------------------------
  710.  *
  711.  * XFillRectangles --
  712.  *
  713.  *    Fill multiple rectangular areas in the given drawable.
  714.  *
  715.  * Results:
  716.  *    None.
  717.  *
  718.  * Side effects:
  719.  *    Draws onto the specified drawable.
  720.  *
  721.  *----------------------------------------------------------------------
  722.  */
  723.  
  724. void
  725. XFillRectangles(display, d, gc, rectangles, nrectangles)
  726.     Display* display;
  727.     Drawable d;
  728.     GC gc;
  729.     XRectangle* rectangles;
  730.     int nrectangles;
  731. {
  732.     HDC dc;
  733.     HBRUSH brush;
  734.     int i;
  735.     RECT rect;
  736.     TkWinDCState state;
  737.  
  738.     if (d == None) {
  739.     return;
  740.     }
  741.  
  742.     dc = TkWinGetDrawableDC(display, d, &state);
  743.     SetROP2(dc, ropModes[gc->function]);
  744.     brush = CreateSolidBrush(gc->foreground);
  745.  
  746.     if ((gc->fill_style == FillStippled
  747.         || gc->fill_style == FillOpaqueStippled)
  748.         && gc->stipple != None) {
  749.     TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple;
  750.     HBRUSH oldBrush, stipple;
  751.     HBITMAP oldBitmap, bitmap;
  752.     HDC dcMem;
  753.     HBRUSH bgBrush = CreateSolidBrush(gc->background);
  754.  
  755.     if (twdPtr->type != TWD_BITMAP) {
  756.         panic("unexpected drawable type in stipple");
  757.     }
  758.  
  759.     /*
  760.      * Select stipple pattern into destination dc.
  761.      */
  762.     
  763.     stipple = CreatePatternBrush(twdPtr->bitmap.handle);
  764.     SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL);
  765.     oldBrush = SelectObject(dc, stipple);
  766.     dcMem = CreateCompatibleDC(dc);
  767.  
  768.     /*
  769.      * For each rectangle, create a drawing surface which is the size of
  770.      * the rectangle and fill it with the background color.  Then merge the
  771.      * result with the stipple pattern.
  772.      */
  773.  
  774.     for (i = 0; i < nrectangles; i++) {
  775.         bitmap = CreateCompatibleBitmap(dc, rectangles[i].width,
  776.             rectangles[i].height);
  777.         oldBitmap = SelectObject(dcMem, bitmap);
  778.         rect.left = 0;
  779.         rect.top = 0;
  780.         rect.right = rectangles[i].width;
  781.         rect.bottom = rectangles[i].height;
  782.         FillRect(dcMem, &rect, brush);
  783.         BitBlt(dc, rectangles[i].x, rectangles[i].y, rectangles[i].width,
  784.             rectangles[i].height, dcMem, 0, 0, COPYFG);
  785.         if (gc->fill_style == FillOpaqueStippled) {
  786.         FillRect(dcMem, &rect, bgBrush);
  787.         BitBlt(dc, rectangles[i].x, rectangles[i].y,
  788.             rectangles[i].width, rectangles[i].height, dcMem,
  789.             0, 0, COPYBG);
  790.         }
  791.         SelectObject(dcMem, oldBitmap);
  792.         DeleteObject(bitmap);
  793.     }
  794.     
  795.     DeleteDC(dcMem);
  796.     SelectObject(dc, oldBrush);
  797.     DeleteObject(stipple);
  798.     } else {
  799.     for (i = 0; i < nrectangles; i++) {
  800.         rect.left = rectangles[i].x;
  801.         rect.top = rectangles[i].y;
  802.         rect.right = rect.left + rectangles[i].width;
  803.         rect.bottom = rect.top + rectangles[i].height;
  804.         FillRect(dc, &rect, brush);
  805.     }
  806.     }
  807.     DeleteObject(brush);
  808.     TkWinReleaseDrawableDC(d, dc, &state);
  809. }
  810.  
  811. /*
  812.  *----------------------------------------------------------------------
  813.  *
  814.  * RenderObject --
  815.  *
  816.  *    This function draws a shape using a list of points, a
  817.  *    stipple pattern, and the specified drawing function.
  818.  *
  819.  * Results:
  820.  *    None.
  821.  *
  822.  * Side effects:
  823.  *    None.
  824.  *
  825.  *----------------------------------------------------------------------
  826.  */
  827.  
  828. static void
  829. RenderObject(dc, gc, points, npoints, mode, pen, func)
  830.     HDC dc;
  831.     GC gc;
  832.     XPoint* points;
  833.     int npoints;
  834.     int mode;
  835.     HPEN pen;
  836.     WinDrawFunc func;
  837. {
  838.     RECT rect;
  839.     HPEN oldPen;
  840.     HBRUSH oldBrush;
  841.     POINT *winPoints = ConvertPoints(points, npoints, mode, &rect);
  842.     
  843.     if ((gc->fill_style == FillStippled
  844.         || gc->fill_style == FillOpaqueStippled)
  845.         && gc->stipple != None) {
  846.  
  847.     TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple;
  848.     HDC dcMem;
  849.     LONG width, height;
  850.     HBITMAP oldBitmap;
  851.     int i;
  852.     HBRUSH oldMemBrush;
  853.     
  854.     if (twdPtr->type != TWD_BITMAP) {
  855.         panic("unexpected drawable type in stipple");
  856.     }
  857.  
  858.     
  859.     width = rect.right - rect.left;
  860.     height = rect.bottom - rect.top;
  861.  
  862.     /*
  863.      * Select stipple pattern into destination dc.
  864.      */
  865.     
  866.     oldBrush = SelectObject(dc, CreatePatternBrush(twdPtr->bitmap.handle));
  867.     SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL);
  868.  
  869.     /*
  870.      * Create temporary drawing surface containing a copy of the
  871.      * destination equal in size to the bounding box of the object.
  872.      */
  873.     
  874.     dcMem = CreateCompatibleDC(dc);
  875.     oldBitmap = SelectObject(dcMem, CreateCompatibleBitmap(dc, width,
  876.         height));
  877.     oldPen = SelectObject(dcMem, pen);
  878.     BitBlt(dcMem, 0, 0, width, height, dc, rect.left, rect.top, SRCCOPY);
  879.  
  880.     /*
  881.      * Translate the object to 0,0 for rendering in the temporary drawing
  882.      * surface. 
  883.      */
  884.  
  885.     for (i = 0; i < npoints; i++) {
  886.         winPoints[i].x -= rect.left;
  887.         winPoints[i].y -= rect.top;
  888.     }
  889.  
  890.     /*
  891.      * Draw the object in the foreground color and copy it to the
  892.      * destination wherever the pattern is set.
  893.      */
  894.  
  895.     SetPolyFillMode(dcMem, (gc->fill_rule == EvenOddRule) ? ALTERNATE
  896.         : WINDING);
  897.     oldMemBrush = SelectObject(dcMem, CreateSolidBrush(gc->foreground));
  898.     (*func)(dcMem, winPoints, npoints);
  899.     BitBlt(dc, rect.left, rect.top, width, height, dcMem, 0, 0, COPYFG);
  900.  
  901.     /*
  902.      * If we are rendering an opaque stipple, then draw the polygon in the
  903.      * background color and copy it to the destination wherever the pattern
  904.      * is clear.
  905.      */
  906.  
  907.     if (gc->fill_style == FillOpaqueStippled) {
  908.         DeleteObject(SelectObject(dcMem,
  909.             CreateSolidBrush(gc->background)));
  910.         (*func)(dcMem, winPoints, npoints);
  911.         BitBlt(dc, rect.left, rect.top, width, height, dcMem, 0, 0,
  912.             COPYBG);
  913.     }
  914.  
  915.     SelectObject(dcMem, oldPen);
  916.     DeleteObject(SelectObject(dcMem, oldMemBrush));
  917.     DeleteObject(SelectObject(dcMem, oldBitmap));
  918.     DeleteDC(dcMem);
  919.     } else {
  920.     oldPen = SelectObject(dc, pen);
  921.     oldBrush = SelectObject(dc, CreateSolidBrush(gc->foreground));
  922.     SetROP2(dc, ropModes[gc->function]);
  923.  
  924.     SetPolyFillMode(dc, (gc->fill_rule == EvenOddRule) ? ALTERNATE
  925.         : WINDING);
  926.  
  927.     (*func)(dc, winPoints, npoints);
  928.  
  929.     SelectObject(dc, oldPen);
  930.     }
  931.     DeleteObject(SelectObject(dc, oldBrush));
  932. }
  933.  
  934. /*
  935.  *----------------------------------------------------------------------
  936.  *
  937.  * XDrawLines --
  938.  *
  939.  *    Draw connected lines.
  940.  *
  941.  * Results:
  942.  *    None.
  943.  *
  944.  * Side effects:
  945.  *    Renders a series of connected lines.
  946.  *
  947.  *----------------------------------------------------------------------
  948.  */
  949.  
  950. void
  951. XDrawLines(display, d, gc, points, npoints, mode)
  952.     Display* display;
  953.     Drawable d;
  954.     GC gc;
  955.     XPoint* points;
  956.     int npoints;
  957.     int mode;
  958. {
  959.     HPEN pen;
  960.     TkWinDCState state;
  961.     HDC dc;
  962.     
  963.     if (d == None) {
  964.     return;
  965.     }
  966.  
  967.     dc = TkWinGetDrawableDC(display, d, &state);
  968.  
  969.     pen = CreatePen(PS_SOLID, gc->line_width, gc->foreground);
  970.     RenderObject(dc, gc, points, npoints, mode, pen, Polyline);
  971.     DeleteObject(pen);
  972.     
  973.     TkWinReleaseDrawableDC(d, dc, &state);
  974. }
  975.  
  976. /*
  977.  *----------------------------------------------------------------------
  978.  *
  979.  * XFillPolygon --
  980.  *
  981.  *    Draws a filled polygon.
  982.  *
  983.  * Results:
  984.  *    None.
  985.  *
  986.  * Side effects:
  987.  *    Draws a filled polygon on the specified drawable.
  988.  *
  989.  *----------------------------------------------------------------------
  990.  */
  991.  
  992. void
  993. XFillPolygon(display, d, gc, points, npoints, shape, mode)
  994.     Display* display;
  995.     Drawable d;
  996.     GC gc;
  997.     XPoint* points;
  998.     int npoints;
  999.     int shape;
  1000.     int mode;
  1001. {
  1002.     HPEN pen;
  1003.     TkWinDCState state;
  1004.     HDC dc;
  1005.  
  1006.     if (d == None) {
  1007.     return;
  1008.     }
  1009.  
  1010.     dc = TkWinGetDrawableDC(display, d, &state);
  1011.  
  1012.     pen = GetStockObject(NULL_PEN);
  1013.     RenderObject(dc, gc, points, npoints, mode, pen, Polygon);
  1014.  
  1015.     TkWinReleaseDrawableDC(d, dc, &state);
  1016. }
  1017.  
  1018. /*
  1019.  *----------------------------------------------------------------------
  1020.  *
  1021.  * XDrawRectangle --
  1022.  *
  1023.  *    Draws a rectangle.
  1024.  *
  1025.  * Results:
  1026.  *    None.
  1027.  *
  1028.  * Side effects:
  1029.  *    Draws a rectangle on the specified drawable.
  1030.  *
  1031.  *----------------------------------------------------------------------
  1032.  */
  1033.  
  1034. void
  1035. XDrawRectangle(display, d, gc, x, y, width, height)
  1036.     Display* display;
  1037.     Drawable d;
  1038.     GC gc;
  1039.     int x;
  1040.     int y;
  1041.     unsigned int width;
  1042.     unsigned int height;
  1043. {
  1044.     HPEN pen, oldPen;
  1045.     TkWinDCState state;
  1046.     HBRUSH oldBrush;
  1047.     HDC dc;
  1048.  
  1049.     if (d == None) {
  1050.     return;
  1051.     }
  1052.  
  1053.     dc = TkWinGetDrawableDC(display, d, &state);
  1054.  
  1055.     pen = CreatePen(PS_SOLID, gc->line_width, gc->foreground);
  1056.     oldPen = SelectObject(dc, pen);
  1057.     oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
  1058.     SetROP2(dc, ropModes[gc->function]);
  1059.  
  1060.     Rectangle(dc, x, y, x+width+1, y+height+1);
  1061.  
  1062.     DeleteObject(SelectObject(dc, oldPen));
  1063.     SelectObject(dc, oldBrush);
  1064.     TkWinReleaseDrawableDC(d, dc, &state);
  1065. }
  1066.  
  1067. /*
  1068.  *----------------------------------------------------------------------
  1069.  *
  1070.  * XDrawArc --
  1071.  *
  1072.  *    Draw an arc.
  1073.  *
  1074.  * Results:
  1075.  *    None.
  1076.  *
  1077.  * Side effects:
  1078.  *    Draws an arc on the specified drawable.
  1079.  *
  1080.  *----------------------------------------------------------------------
  1081.  */
  1082.  
  1083. void
  1084. XDrawArc(display, d, gc, x, y, width, height, angle1, angle2)
  1085.     Display* display;
  1086.     Drawable d;
  1087.     GC gc;
  1088.     int x;
  1089.     int y;
  1090.     unsigned int width;
  1091.     unsigned int height;
  1092.     int angle1;
  1093.     int angle2;
  1094. {
  1095.     display->request++;
  1096.  
  1097.     DrawOrFillArc(display, d, gc, x, y, width, height, angle1, angle2, 0);
  1098. }
  1099.  
  1100. /*
  1101.  *----------------------------------------------------------------------
  1102.  *
  1103.  * XFillArc --
  1104.  *
  1105.  *    Draw a filled arc.
  1106.  *
  1107.  * Results:
  1108.  *    None.
  1109.  *
  1110.  * Side effects:
  1111.  *    Draws a filled arc on the specified drawable.
  1112.  *
  1113.  *----------------------------------------------------------------------
  1114.  */
  1115.  
  1116. void
  1117. XFillArc(display, d, gc, x, y, width, height, angle1, angle2)
  1118.     Display* display;
  1119.     Drawable d;
  1120.     GC gc;
  1121.     int x;
  1122.     int y;
  1123.     unsigned int width;
  1124.     unsigned int height;
  1125.     int angle1;
  1126.     int angle2;
  1127. {
  1128.     display->request++;
  1129.  
  1130.     DrawOrFillArc(display, d, gc, x, y, width, height, angle1, angle2, 1);
  1131. }
  1132.  
  1133. /*
  1134.  *----------------------------------------------------------------------
  1135.  *
  1136.  * DrawOrFillArc --
  1137.  *
  1138.  *    This procedure handles the rendering of drawn or filled
  1139.  *    arcs and chords.
  1140.  *
  1141.  * Results:
  1142.  *    None.
  1143.  *
  1144.  * Side effects:
  1145.  *    Renders the requested arc.
  1146.  *
  1147.  *----------------------------------------------------------------------
  1148.  */
  1149.  
  1150. static void
  1151. DrawOrFillArc(display, d, gc, x, y, width, height, angle1, angle2, fill)
  1152.     Display *display;
  1153.     Drawable d;
  1154.     GC gc;
  1155.     int x, y;            /* left top */
  1156.     unsigned int width, height;
  1157.     int angle1;            /* angle1: three-o'clock (deg*64) */
  1158.     int angle2;            /* angle2: relative (deg*64) */
  1159.     int fill;            /* ==0 draw, !=0 fill */
  1160. {
  1161.     HDC dc;
  1162.     HBRUSH brush, oldBrush;
  1163.     HPEN pen, oldPen;
  1164.     TkWinDCState state;
  1165.     int xr, yr, xstart, ystart, xend, yend;
  1166.     double radian_start, radian_end, radian_tmp;
  1167.  
  1168.     if (d == None) {
  1169.     return;
  1170.     }
  1171.  
  1172.     dc = TkWinGetDrawableDC(display, d, &state);
  1173.  
  1174.     SetROP2(dc, ropModes[gc->function]);
  1175.  
  1176.     /*
  1177.      * Convert the X arc description to a Win32 arc description.
  1178.      */
  1179.  
  1180.     xr = (width % 2) ? (width / 2) : ((width - 1) / 2);
  1181.     yr = (height % 2) ? (height / 2) : ((height - 1) / 2);
  1182.  
  1183.     radian_start = XAngleToRadians(angle1);
  1184.     radian_end = XAngleToRadians(angle1+angle2);
  1185.     if( angle2 < 0 ) {
  1186.     radian_tmp = radian_start;
  1187.     radian_start = radian_end;
  1188.     radian_end = radian_tmp;
  1189.     }
  1190.  
  1191.     xstart = x + (int) ((double)xr * (1+cos(radian_start)));
  1192.     ystart = y + (int) ((double)yr * (1-sin(radian_start)));
  1193.     xend = x + (int) ((double)xr * (1+cos(radian_end)));
  1194.     yend = y + (int) ((double)yr * (1-sin(radian_end)));
  1195.  
  1196.     /*
  1197.      * Now draw a filled or open figure.
  1198.      */
  1199.  
  1200.     if (!fill) {
  1201.     pen = CreatePen(PS_SOLID, gc->line_width, gc->foreground);
  1202.     oldPen = SelectObject(dc, pen);
  1203.     oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
  1204.     Arc(dc, x, y, x + width, y + height, xstart, ystart, xend, yend);
  1205.     DeleteObject(SelectObject(dc, oldPen));
  1206.     SelectObject(dc, oldBrush);
  1207.     } else {
  1208.     brush = CreateSolidBrush(gc->foreground);
  1209.     oldBrush = SelectObject(dc, brush);
  1210.     oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
  1211.     if (gc->arc_mode == ArcChord) {
  1212.         Chord(dc, x, y, x + width, y + height, xstart, ystart, xend, yend);
  1213.     } else if ( gc->arc_mode == ArcPieSlice ) {
  1214.         Pie(dc, x, y, x + width, y + height, xstart, ystart, xend, yend);
  1215.     }
  1216.     DeleteObject(SelectObject(dc, oldBrush));
  1217.     SelectObject(dc, oldPen);
  1218.     }
  1219.     TkWinReleaseDrawableDC(d, dc, &state);
  1220. }
  1221.  
  1222. /*
  1223.  *----------------------------------------------------------------------
  1224.  *
  1225.  * TkScrollWindow --
  1226.  *
  1227.  *    Scroll a rectangle of the specified window and accumulate
  1228.  *    a damage region.
  1229.  *
  1230.  * Results:
  1231.  *    Returns 0 if the scroll genereated no additional damage.
  1232.  *    Otherwise, sets the region that needs to be repainted after
  1233.  *    scrolling and returns 1.
  1234.  *
  1235.  * Side effects:
  1236.  *    Scrolls the bits in the window.
  1237.  *
  1238.  *----------------------------------------------------------------------
  1239.  */
  1240.  
  1241. int
  1242. TkScrollWindow(tkwin, gc, x, y, width, height, dx, dy, damageRgn)
  1243.     Tk_Window tkwin;        /* The window to be scrolled. */
  1244.     GC gc;            /* GC for window to be scrolled. */
  1245.     int x, y, width, height;    /* Position rectangle to be scrolled. */
  1246.     int dx, dy;            /* Distance rectangle should be moved. */
  1247.     TkRegion damageRgn;        /* Region to accumulate damage in. */
  1248. {
  1249.     HWND hwnd = TkWinGetHWND(Tk_WindowId(tkwin));
  1250.     RECT scrollRect;
  1251.  
  1252.     scrollRect.left = x;
  1253.     scrollRect.top = y;
  1254.     scrollRect.right = x + width;
  1255.     scrollRect.bottom = y + height;
  1256.     return (ScrollWindowEx(hwnd, dx, dy, &scrollRect, NULL, (HRGN) damageRgn,
  1257.         NULL, 0) == NULLREGION) ? 0 : 1;
  1258. }
  1259.