summaryrefslogtreecommitdiff
path: root/blt/src/bltWinDraw.c
diff options
context:
space:
mode:
Diffstat (limited to 'blt/src/bltWinDraw.c')
-rw-r--r--blt/src/bltWinDraw.c2716
1 files changed, 2716 insertions, 0 deletions
diff --git a/blt/src/bltWinDraw.c b/blt/src/bltWinDraw.c
new file mode 100644
index 00000000000..9628a8c56a4
--- /dev/null
+++ b/blt/src/bltWinDraw.c
@@ -0,0 +1,2716 @@
+/*
+ * bltWinDraw.c --
+ *
+ * This module contains WIN32 routines not included in the Tcl/Tk
+ * libraries.
+ *
+ * Copyright 1998 by Bell Labs Innovations for Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and warranty
+ * disclaimer appear in supporting documentation, and that the names
+ * of Lucent Technologies any of their entities not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ *
+ * Lucent Technologies disclaims all warranties with regard to this
+ * software, including all implied warranties of merchantability and
+ * fitness. In no event shall Lucent Technologies be liable for any
+ * special, indirect or consequential damages or any damages
+ * whatsoever resulting from loss of use, data or profits, whether in
+ * an action of contract, negligence or other tortuous action, arising
+ * out of or in connection with the use or performance of this
+ * software.
+ */
+
+#include <bltInt.h>
+#include <X11/Xutil.h>
+#include <X11/Xlib.h>
+
+#define WINDEBUG 0
+
+/*
+ * Data structure for setting graphics context.
+ */
+typedef struct {
+ int function; /* logical operation */
+ unsigned long plane_mask; /* plane mask */
+ unsigned long foreground; /* foreground pixel */
+ unsigned long background; /* background pixel */
+ int line_width; /* line width */
+ int line_style; /* LineSolid, LineOnOffDash, LineDoubleDash */
+ int cap_style; /* CapNotLast, CapButt,
+ CapRound, CapProjecting */
+ int join_style; /* JoinMiter, JoinRound, JoinBevel */
+ int fill_style; /* FillSolid, FillTiled,
+ FillStippled, FillOpaeueStippled */
+ int fill_rule; /* EvenOddRule, WindingRule */
+ int arc_mode; /* ArcChord, ArcPieSlice */
+ Pixmap tile; /* tile pixmap for tiling operations */
+ Pixmap stipple; /* stipple 1 plane pixmap for stipping */
+ int ts_x_origin; /* offset for tile or stipple operations */
+ int ts_y_origin;
+ Font font; /* default text font for text operations */
+ int subwindow_mode; /* ClipByChildren, IncludeInferiors */
+ Bool graphics_exposures; /* boolean, should exposures be generated */
+ int clip_x_origin; /* origin for clipping */
+ int clip_y_origin;
+ Pixmap clip_mask; /* bitmap clipping; other calls for rects */
+ int dash_offset; /* patterned/dashed line information */
+ char dashes; /* If -1, indicates that the extended
+ * information below is available. */
+ int nDashValues;
+ char dashValues[12];
+} XGCValuesEx;
+
+static int tkpWinRopModes[] =
+{
+ R2_BLACK, /* GXclear */
+ R2_MASKPEN, /* GXand */
+ R2_MASKPENNOT, /* GXandReverse */
+ R2_COPYPEN, /* GXcopy */
+ R2_MASKNOTPEN, /* GXandInverted */
+ R2_NOT, /* GXnoop */
+ R2_XORPEN, /* GXxor */
+ R2_MERGEPEN, /* GXor */
+ R2_NOTMERGEPEN, /* GXnor */
+ R2_NOTXORPEN, /* GXequiv */
+ R2_NOT, /* GXinvert */
+ R2_MERGEPENNOT, /* GXorReverse */
+ R2_NOTCOPYPEN, /* GXcopyInverted */
+ R2_MERGENOTPEN, /* GXorInverted */
+ R2_NOTMASKPEN, /* GXnand */
+ R2_WHITE /* GXset */
+};
+#define MASKPAT 0x00E20746 /* dest = (src & pat) | (!src & dst) */
+#define COPYFG 0x00CA0749 /* dest = (pat & src) | (!pat & dst) */
+#define COPYBG 0x00AC0744 /* dest = (!pat & src) | (pat & dst) */
+/*
+ * Translation table between X gc functions and Win32 BitBlt op modes. Some
+ * of the operations defined in X don't have names, so we have to construct
+ * new opcodes for those functions. This is arcane and probably not all that
+ * useful, but at least it's accurate.
+ */
+
+#define NOTSRCAND (DWORD)0x00220326 /* dest = (NOT src) AND dest */
+#define NOTSRCINVERT (DWORD)0x00990066 /* dest = (NOT src) XOR dest */
+#define SRCORREVERSE (DWORD)0x00DD0228 /* dest = src OR (NOT dest) */
+#define SRCNAND (DWORD)0x007700E6 /* dest = NOT (src AND dest) */
+
+static int bltModes[] =
+{
+ BLACKNESS, /* GXclear */
+ SRCAND, /* GXand */
+ SRCERASE, /* GXandReverse */
+ SRCCOPY, /* GXcopy */
+ NOTSRCAND, /* GXandInverted */
+ PATCOPY, /* GXnoop */
+ SRCINVERT, /* GXxor */
+ SRCPAINT, /* GXor */
+ NOTSRCERASE, /* GXnor */
+ NOTSRCINVERT, /* GXequiv */
+ DSTINVERT, /* GXinvert */
+ SRCORREVERSE, /* GXorReverse */
+ NOTSRCCOPY, /* GXcopyInverted */
+ MERGEPAINT, /* GXorInverted */
+ SRCNAND, /* GXnand */
+ WHITENESS /* GXset */
+};
+
+#if (TCL_VERSION_NUMBER < _VERSION(8,1,0))
+typedef void *Tcl_Encoding; /* Make up dummy type for encoding. */
+#endif
+static Tcl_Encoding systemEncoding = NULL;
+
+HPALETTE
+Blt_GetSystemPalette(void)
+{
+ HDC hDC;
+ HPALETTE hPalette;
+ DWORD flags;
+
+ hPalette = NULL;
+ hDC = GetDC(NULL); /* Get the desktop device context */
+ flags = GetDeviceCaps(hDC, RASTERCAPS);
+ if (flags & RC_PALETTE) {
+ LOGPALETTE *palettePtr;
+
+ palettePtr = (LOGPALETTE *)
+ GlobalAlloc(GPTR, sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY));
+ palettePtr->palVersion = 0x300;
+ palettePtr->palNumEntries = 256;
+ GetSystemPaletteEntries(hDC, 0, 256, palettePtr->palPalEntry);
+ hPalette = CreatePalette(palettePtr);
+ GlobalFree(palettePtr);
+ }
+ ReleaseDC(NULL, hDC);
+ return hPalette;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CreateRotatedFont --
+ *
+ * Creates a rotated copy of the given font. This only works
+ * for TrueType fonts.
+ *
+ * Results:
+ * Returns the newly create font or NULL if the font could not
+ * be created.
+ *
+ *----------------------------------------------------------------------
+ */
+HFONT
+CreateRotatedFont(
+ unsigned long fontId, /* Font identifier (actually a Tk_Font) */
+ double theta)
+{ /* Number of degrees to rotate font */
+ TkFontAttributes *faPtr; /* Set of attributes to match. */
+ TkFont *fontPtr;
+ HFONT hFont;
+ LOGFONTW lf;
+
+ fontPtr = (TkFont *) fontId;
+ faPtr = &fontPtr->fa;
+ ZeroMemory(&lf, sizeof(LOGFONT));
+ lf.lfHeight = -faPtr->pointsize;
+ if (lf.lfHeight < 0) {
+ HDC dc;
+
+ dc = GetDC(NULL);
+ lf.lfHeight = -MulDiv(faPtr->pointsize,
+ GetDeviceCaps(dc, LOGPIXELSY), 72);
+ ReleaseDC(NULL, dc);
+ }
+ lf.lfWidth = 0;
+ lf.lfEscapement = lf.lfOrientation = ROUND(theta * 10.0);
+#define TK_FW_NORMAL 0
+ lf.lfWeight = (faPtr->weight == TK_FW_NORMAL) ? FW_NORMAL : FW_BOLD;
+ lf.lfItalic = faPtr->slant;
+ lf.lfUnderline = faPtr->underline;
+ lf.lfStrikeOut = faPtr->overstrike;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfQuality = DEFAULT_QUALITY;
+ lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+
+ hFont = NULL;
+ if (faPtr->family == NULL) {
+ lf.lfFaceName[0] = '\0';
+ } else {
+#if (TCL_VERSION_NUMBER >= _VERSION(8,1,0))
+ Tcl_DString dString;
+
+ Tcl_UtfToExternalDString(systemEncoding, faPtr->family, -1, &dString);
+
+ if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) {
+ Tcl_UniChar *src, *dst;
+
+ /*
+ * We can only store up to LF_FACESIZE wide characters
+ */
+ if (Tcl_DStringLength(&dString) >= (LF_FACESIZE * sizeof(WCHAR))) {
+ Tcl_DStringSetLength(&dString, LF_FACESIZE);
+ }
+ src = (Tcl_UniChar *)Tcl_DStringValue(&dString);
+ dst = (Tcl_UniChar *)lf.lfFaceName;
+ while (*src != '\0') {
+ *dst++ = *src++;
+ }
+ *dst = '\0';
+ hFont = CreateFontIndirectW((LOGFONTW *)&lf);
+ } else {
+ /*
+ * We can only store up to LF_FACESIZE characters
+ */
+ if (Tcl_DStringLength(&dString) >= LF_FACESIZE) {
+ Tcl_DStringSetLength(&dString, LF_FACESIZE);
+ }
+ strcpy((char *)lf.lfFaceName, Tcl_DStringValue(&dString));
+ hFont = CreateFontIndirectA((LOGFONTA *)&lf);
+ }
+ Tcl_DStringFree(&dString);
+#else
+ strncpy((char *)lf.lfFaceName, faPtr->family, LF_FACESIZE - 1);
+ lf.lfFaceName[LF_FACESIZE] = '\0';
+#endif /* TCL_VERSION_NUMBER >= 8.1.0 */
+ }
+
+ if (hFont == NULL) {
+#if WINDEBUG
+ PurifyPrintf("can't create font: %s\n", Blt_LastError());
+#endif
+ } else {
+ HFONT oldFont;
+ TEXTMETRIC tm;
+ HDC hRefDC;
+ int result;
+
+ /* Check if the rotated font is really a TrueType font. */
+
+ hRefDC = GetDC(NULL); /* Get the desktop device context */
+ oldFont = SelectFont(hRefDC, hFont);
+ result = ((GetTextMetrics(hRefDC, &tm)) &&
+ (tm.tmPitchAndFamily & TMPF_TRUETYPE));
+ SelectFont(hRefDC, oldFont);
+ ReleaseDC(NULL, hRefDC);
+ if (!result) {
+#if WINDEBUG
+ PurifyPrintf("not a true type font");
+#endif
+ DeleteFont(hFont);
+ return NULL;
+ }
+ }
+ return hFont;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Blt_GetBitmapData --
+ *
+ * Returns the DIB bits from a bitmap.
+ *
+ * Results:
+ * Returns a byte array of bitmap data or NULL if an error
+ * occurred. The parameter pitchPtr returns the number
+ * of bytes per row.
+ *
+ *----------------------------------------------------------------------
+ */
+unsigned char *
+Blt_GetBitmapData(
+ Display *display, /* Display of bitmap */
+ Pixmap bitmap, /* Bitmap to query */
+ int width, /* Width of bitmap */
+ int height, /* Height of bitmap */
+ int *pitchPtr) /* (out) Number of bytes per row */
+{
+ TkWinDCState state;
+ HDC dc;
+ int result;
+ unsigned char *bits;
+ unsigned int size;
+ HBITMAP hBitmap;
+ BITMAPINFOHEADER *bmiPtr;
+ HANDLE hMem, hMem2;
+ int bytesPerRow, imageSize;
+
+ size = sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD);
+ hMem = GlobalAlloc(GHND, size);
+ bmiPtr = (BITMAPINFOHEADER *)GlobalLock(hMem);
+ bmiPtr->biSize = sizeof(BITMAPINFOHEADER);
+ bmiPtr->biPlanes = 1;
+ bmiPtr->biBitCount = 1;
+ bmiPtr->biCompression = BI_RGB;
+ bmiPtr->biWidth = width;
+ bmiPtr->biHeight = height;
+
+ hBitmap = ((TkWinDrawable *)bitmap)->bitmap.handle;
+ dc = TkWinGetDrawableDC(display, bitmap, &state);
+ result = GetDIBits(dc, hBitmap, 0, height, (LPVOID)NULL,
+ (BITMAPINFO *)bmiPtr, DIB_RGB_COLORS);
+ TkWinReleaseDrawableDC(bitmap, dc, &state);
+ if (!result) {
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ return NULL;
+ }
+ imageSize = bmiPtr->biSizeImage;
+ GlobalUnlock(hMem);
+ bytesPerRow = ((width + 31) & ~31) / 8;
+ if (imageSize == 0) {
+ imageSize = bytesPerRow * height;
+ }
+ hMem2 = GlobalReAlloc(hMem, size + imageSize, 0);
+ if (hMem2 == NULL) {
+ GlobalFree(hMem);
+ return NULL;
+ }
+ hMem = hMem2;
+ bmiPtr = (LPBITMAPINFOHEADER)GlobalLock(hMem);
+ dc = TkWinGetDrawableDC(display, bitmap, &state);
+ result = GetDIBits(dc, hBitmap, 0, height, (unsigned char *)bmiPtr + size,
+ (BITMAPINFO *)bmiPtr, DIB_RGB_COLORS);
+ TkWinReleaseDrawableDC(bitmap, dc, &state);
+ bits = NULL;
+ if (!result) {
+ OutputDebugString("GetDIBits failed\n");
+ } else {
+ bits = Blt_Malloc(imageSize);
+ if (bits != NULL) {
+ memcpy (bits, (unsigned char *)bmiPtr + size, imageSize);
+ }
+ }
+ *pitchPtr = bytesPerRow;
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ return bits;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XFree --
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXFree(void *ptr)
+{
+ Blt_Free(ptr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XMaxRequestSize --
+ *
+ *----------------------------------------------------------------------
+ */
+long
+Blt_EmulateXMaxRequestSize(Display *display)
+{
+ return (SHRT_MAX / 4);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XLowerWindow --
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXLowerWindow(
+ Display *display,
+ Window window)
+{
+ HWND hWnd;
+
+ hWnd = Tk_GetHWND(window);
+ display->request++;
+ SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XRaiseWindow --
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXRaiseWindow(
+ Display *display,
+ Window window)
+{
+ HWND hWnd;
+
+ hWnd = Tk_GetHWND(window);
+ display->request++;
+ SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XUnmapWindow --
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXUnmapWindow(
+ Display *display,
+ Window window)
+{
+ HWND hWnd;
+
+ hWnd = Tk_GetHWND(window);
+ display->request++;
+ ShowWindow(hWnd, SW_HIDE);
+ /* SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XWarpPointer --
+ *
+ * If destWindow is None, moves the pointer by the offsets (destX,
+ * destY) relative to the current position of the pointer.
+ * If destWindow is a window, moves the pointer to the offsets
+ * (destX, destY) relative to the origin of destWindow. However,
+ * if srcWindow is a window, the move only takes place if the window
+ * srcWindow contains the pointer and if the specified rectangle of
+ * srcWindow contains the pointer.
+ *
+ * The srcX and srcY coordinates are relative to the origin of
+ * srcWindow. If srcHeight is zero, it is replaced with the current
+ * height of srcWindow minus srcY. If srcWidth is zero, it is
+ * replaced with the current width of srcWindow minus srcX.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXWarpPointer(
+ Display *display,
+ Window srcWindow,
+ Window destWindow,
+ int srcX,
+ int srcY,
+ unsigned int srcWidth,
+ unsigned int srcHeight,
+ int destX,
+ int destY)
+{
+ HWND hWnd;
+ POINT point;
+
+ hWnd = Tk_GetHWND(destWindow);
+ point.x = destX, point.y = destY;
+ if (ClientToScreen(hWnd, &point)) {
+ SetCursorPos(point.x, point.y);
+ }
+}
+
+static Blt_HashTable gcTable;
+static int gcInitialized = FALSE;
+
+typedef struct {
+ HDC dc;
+ int count;
+ COLORREF color;
+ int offset, nBits;
+} DashInfo;
+
+void
+Blt_SetDashes(Display *display, GC gc, Blt_Dashes *dashesPtr)
+{
+ XGCValuesEx *gcPtr = (XGCValuesEx *)gc;
+
+ /* This must be used only with a privately created GC */
+ assert((int)gcPtr->dashes == -1);
+ gcPtr->nDashValues = strlen(dashesPtr->values);
+ gcPtr->dash_offset = dashesPtr->offset;
+ strcpy(gcPtr->dashValues, dashesPtr->values);
+}
+
+static int
+GetDashInfo(
+ HDC dc,
+ GC gc,
+ DashInfo *infoPtr)
+{
+ int dashOffset, dashValue;
+
+ dashValue = 0;
+ dashOffset = gc->dash_offset;
+ if ((int)gc->dashes == -1) {
+ XGCValuesEx *gcPtr = (XGCValuesEx *)gc;
+
+ if (gcPtr->nDashValues == 1) {
+ dashValue = gcPtr->dashValues[0];
+ }
+ } else if (gc->dashes > 0) {
+ dashValue = (int)gc->dashes;
+ }
+ if (dashValue == 0) {
+ return FALSE;
+ }
+ infoPtr->dc = dc;
+ infoPtr->nBits = dashValue;
+ infoPtr->offset = dashOffset;
+ infoPtr->count = 0;
+ infoPtr->color = gc->foreground;
+ return TRUE;
+}
+
+void
+Blt_SetROP2(HDC dc, int function)
+{
+ SetROP2(dc, tkpWinRopModes[function]);
+}
+
+static XGCValuesEx *
+CreateGC()
+{
+ XGCValuesEx *gcPtr;
+
+ gcPtr = Blt_Malloc(sizeof(XGCValuesEx));
+ if (gcPtr == NULL) {
+ return NULL;
+ }
+ gcPtr->arc_mode = ArcPieSlice;
+ gcPtr->background = 0xffffff;
+ gcPtr->cap_style = CapNotLast;
+ gcPtr->clip_mask = None;
+ gcPtr->clip_x_origin = gcPtr->clip_y_origin = 0;
+ gcPtr->dash_offset = 0;
+ gcPtr->fill_rule = WindingRule;
+ gcPtr->fill_style = FillSolid;
+ gcPtr->font = None;
+ gcPtr->foreground = 0;
+ gcPtr->function = GXcopy;
+ gcPtr->graphics_exposures = True;
+ gcPtr->join_style = JoinMiter;
+ gcPtr->line_style = LineSolid;
+ gcPtr->line_width = 0;
+ gcPtr->plane_mask = ~0;
+ gcPtr->stipple = None;
+ gcPtr->subwindow_mode = ClipByChildren;
+ gcPtr->tile = None;
+ gcPtr->ts_x_origin = gcPtr->ts_y_origin = 0;
+
+ gcPtr->dashes = -1; /* Mark that this an extended GC */
+ gcPtr->nDashValues = 0;
+
+ return gcPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Blt_EmulateXCreateGC --
+ *
+ * Allocate a new extended GC, and initialize the specified fields.
+ *
+ * Results:
+ * Returns a newly allocated GC.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+GC
+Blt_EmulateXCreateGC(
+ Display *display,
+ Drawable drawable,
+ unsigned long mask,
+ XGCValues *srcPtr)
+{
+ XGCValuesEx *destPtr;
+
+ destPtr = CreateGC();
+ if (destPtr == NULL) {
+ return None;
+ }
+ if (mask & GCFunction) {
+ destPtr->function = srcPtr->function;
+ }
+ if (mask & GCPlaneMask) {
+ destPtr->plane_mask = srcPtr->plane_mask;
+ }
+ if (mask & GCForeground) {
+ destPtr->foreground = srcPtr->foreground;
+ }
+ if (mask & GCBackground) {
+ destPtr->background = srcPtr->background;
+ }
+ if (mask & GCLineWidth) {
+ destPtr->line_width = srcPtr->line_width;
+ }
+ if (mask & GCLineStyle) {
+ destPtr->line_style = srcPtr->line_style;
+ }
+ if (mask & GCCapStyle) {
+ destPtr->cap_style = srcPtr->cap_style;
+ }
+ if (mask & GCJoinStyle) {
+ destPtr->join_style = srcPtr->join_style;
+ }
+ if (mask & GCFillStyle) {
+ destPtr->fill_style = srcPtr->fill_style;
+ }
+ if (mask & GCFillRule) {
+ destPtr->fill_rule = srcPtr->fill_rule;
+ }
+ if (mask & GCArcMode) {
+ destPtr->arc_mode = srcPtr->arc_mode;
+ }
+ if (mask & GCTile) {
+ destPtr->tile = srcPtr->tile;
+ }
+ if (mask & GCStipple) {
+ destPtr->stipple = srcPtr->stipple;
+ }
+ if (mask & GCTileStipXOrigin) {
+ destPtr->ts_x_origin = srcPtr->ts_x_origin;
+ }
+ if (mask & GCTileStipXOrigin) {
+ destPtr->ts_y_origin = srcPtr->ts_y_origin;
+ }
+ if (mask & GCFont) {
+ destPtr->font = srcPtr->font;
+ }
+ if (mask & GCSubwindowMode) {
+ destPtr->subwindow_mode = srcPtr->subwindow_mode;
+ }
+ if (mask & GCGraphicsExposures) {
+ destPtr->graphics_exposures = srcPtr->graphics_exposures;
+ }
+ if (mask & GCClipXOrigin) {
+ destPtr->clip_x_origin = srcPtr->clip_x_origin;
+ }
+ if (mask & GCClipYOrigin) {
+ destPtr->clip_y_origin = srcPtr->clip_y_origin;
+ }
+ if (mask & GCDashOffset) {
+ destPtr->dash_offset = srcPtr->dash_offset;
+ }
+ if (mask & GCDashList) {
+ destPtr->dashes = srcPtr->dashes;
+ }
+ if (mask & GCClipMask) {
+ struct ClipMask {
+ int type; /* TKP_CLIP_PIXMAP or TKP_CLIP_REGION */
+ Pixmap pixmap;
+ } *clipPtr;
+
+ clipPtr = Blt_Malloc(sizeof(struct ClipMask));
+#define TKP_CLIP_PIXMAP 0
+ clipPtr->type = TKP_CLIP_PIXMAP;
+ clipPtr->pixmap = srcPtr->clip_mask;
+ destPtr->clip_mask = (Pixmap) clipPtr;
+ }
+ return (GC)destPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Blt_GCToPen --
+ *
+ * Set up the graphics port from the given GC.
+ *
+ * Geometric and cosmetic pens available under both 95 and NT.
+ * Geometric pens differ from cosmetic pens in that they can
+ * 1. Draw in world units (can have thick lines: line width > 1).
+ * 2. Under NT, allow arbitrary line style.
+ * 3. Can have caps and join (needed for thick lines).
+ * 4. Draw very, very slowly.
+ *
+ * Cosmetic pens are single line width only.
+ *
+ * 95 98 NT
+ * PS_SOLID c,g c,g c,g
+ * PS_DASH c,g c,g c,g
+ * PS_DOT c c c,g
+ * PS_DASHDOT c - c,g
+ * PS_DASHDOTDOT c - c,g
+ * PS_USERSTYLE - - c,g
+ * PS_ALTERNATE - - c
+ *
+ * Geometric only for 95/98
+ *
+ * PS_ENDCAP_ROUND
+ * PS_ENDCAP_SQUARE
+ * PS_ENDCAP_FLAT
+ * PS_JOIN_BEVEL
+ * PS_JOIN_ROUND
+ * PS_JOIN_MITER
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The current port is adjusted.
+ *
+ *----------------------------------------------------------------------
+ */
+HPEN
+Blt_GCToPen(HDC dc, GC gc)
+{
+ DWORD lineAttrs, lineStyle;
+ DWORD dashArr[12];
+ DWORD *dashPtr;
+ int nValues, lineWidth;
+ LOGBRUSH lBrush;
+ HPEN pen;
+
+ nValues = 0;
+ lineWidth = (gc->line_width < 1) ? 1 : gc->line_width;
+ if ((gc->line_style == LineOnOffDash) ||
+ (gc->line_style == LineDoubleDash)) {
+ XGCValuesEx *gcPtr = (XGCValuesEx *)gc;
+
+ if ((int)gc->dashes == -1) {
+ register int i;
+
+ nValues = strlen(gcPtr->dashValues);
+ for (i = 0; i < nValues; i++) {
+ dashArr[i] = (DWORD)gcPtr->dashValues[i];
+ }
+ if (nValues == 1) {
+ dashArr[1] = dashArr[0];
+ nValues = 2;
+ }
+ } else {
+ dashArr[1] = dashArr[0] = (DWORD) gc->dashes;
+ nValues = 2;
+ gc->dashes = -1;
+ }
+ }
+
+ switch (nValues) {
+ case 0:
+ lineStyle = PS_SOLID;
+ break;
+ case 3:
+ lineStyle = PS_DASHDOT;
+ break;
+ case 4:
+ lineStyle = PS_DASHDOTDOT;
+ break;
+ case 2:
+ default:
+ /* PS_DASH style dash length is too long. */
+ lineStyle = PS_DOT;
+ break;
+ }
+
+ lBrush.lbStyle = BS_SOLID;
+ lBrush.lbColor = gc->foreground;
+ lBrush.lbHatch = 0; /* Value is ignored when style is BS_SOLID. */
+
+ lineAttrs = 0;
+ switch (gc->cap_style) {
+ case CapNotLast:
+ case CapButt:
+ lineAttrs |= PS_ENDCAP_FLAT;
+ break;
+ case CapRound:
+ lineAttrs |= PS_ENDCAP_ROUND;
+ break;
+ default:
+ lineAttrs |= PS_ENDCAP_SQUARE;
+ break;
+ }
+ switch (gc->join_style) {
+ case JoinMiter:
+ lineAttrs |= PS_JOIN_MITER;
+ break;
+ case JoinBevel:
+ lineAttrs |= PS_JOIN_BEVEL;
+ break;
+ case JoinRound:
+ default:
+ lineAttrs |= PS_JOIN_ROUND;
+ break;
+ }
+ pen = NULL;
+ SetBkMode(dc, TRANSPARENT);
+
+ if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) {
+ /* Windows NT. */
+ if (nValues > 0) {
+ lineStyle = PS_USERSTYLE;
+ dashPtr = dashArr;
+ } else {
+ dashPtr = NULL;
+ }
+ if (lineWidth > 1) {
+ /* Limit the use of geometric pens to thick lines. */
+ pen = ExtCreatePen(PS_GEOMETRIC | lineAttrs | lineStyle, lineWidth,
+ &lBrush, nValues, dashPtr);
+ } else {
+ /* Cosmetic pens are much faster. */
+ pen = ExtCreatePen(PS_COSMETIC | lineAttrs | lineStyle, 1, &lBrush,
+ nValues, dashPtr);
+ }
+ } else {
+ /* Windows 95. */
+ if ((lineStyle == PS_SOLID) && (lineWidth > 1)) {
+ /* Use geometric pens with solid, thick lines only. */
+ pen = ExtCreatePen(PS_GEOMETRIC | lineAttrs | lineStyle, lineWidth,
+ &lBrush, 0, NULL);
+ } else {
+ /* Otherwise sacrifice thick lines for dashes. */
+ pen = ExtCreatePen(PS_COSMETIC | lineStyle, 1, &lBrush, 0, NULL);
+ }
+ }
+ assert(pen != NULL);
+ return pen;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XDrawRectangles --
+ *
+ * Draws the outlines of the specified rectangles as if a
+ * five-point PolyLine protocol request were specified for each
+ * rectangle:
+ *
+ * [x,y] [x+width,y] [x+width,y+height] [x,y+height]
+ * [x,y]
+ *
+ * For the specified rectangles, these functions do not draw a
+ * pixel more than once. XDrawRectangles draws the rectangles in
+ * the order listed in the array. If rectangles intersect, the
+ * intersecting pixels are drawn multiple times. Draws a
+ * rectangle.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Draws rectangles on the specified drawable.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXDrawRectangles(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ XRectangle *rectArr,
+ int nRects)
+{
+ HPEN pen, oldPen;
+ TkWinDCState state;
+ HBRUSH brush, oldBrush;
+ HDC dc;
+ register XRectangle *rectPtr;
+ register int i;
+
+ if (drawable == None) {
+ return;
+ }
+ dc = TkWinGetDrawableDC(display, drawable, &state);
+ pen = Blt_GCToPen(dc, gc);
+ brush = GetStockObject(NULL_BRUSH);
+ oldPen = SelectPen(dc, pen);
+ oldBrush = SelectBrush(dc, brush);
+ SetROP2(dc, tkpWinRopModes[gc->function]);
+ rectPtr = rectArr;
+ for (i = 0; i < nRects; i++, rectPtr++) {
+ Rectangle(dc, (int)rectPtr->x, (int)rectPtr->y,
+ (int)(rectPtr->x + rectPtr->width + 1),
+ (int)(rectPtr->y + rectPtr->height + 1));
+ }
+ DeletePen(SelectPen(dc, oldPen));
+ DeleteBrush(SelectBrush(dc, oldBrush));
+ TkWinReleaseDrawableDC(drawable, dc, &state);
+}
+
+#ifdef notdef
+/*
+ * Implements the "pixeling" of small arcs, because GDI-performance
+ * for this is awful
+ * was made especially for BLT, graph4 demo now runs 4x faster
+ *
+ */
+/* O-outer , I-inner, B-both */
+#define NEITHER_ 0
+#define OUTLINE 1
+#define FILL 2
+#define BOTH (OUTLINE|FILL)
+#define MINIARCS 5
+static int arcus0[1] =
+{
+ BOTH
+};
+static int arcus1[4] =
+{
+ BOTH, BOTH,
+ BOTH, BOTH
+};
+
+static int arcus2[9] =
+{
+ NEITHER, OUTLINE, NEITHER,
+ OUTLINE, FILL, OUTLINE,
+ NEITHER, OUTLINE, NEITHER
+};
+
+static int arcus3[16] =
+{
+ NEITHER, OUTLINE, OUTLINE, NEITHER,
+ OUTLINE, FILL, FILL, OUTLINE,
+ OUTLINE, FILL, FILL, OUTLINE,
+ NEITHER, OUTLINE, OUTLINE, NEITHER
+};
+
+static int arcus4[25] =
+{
+ NEITHER, OUTLINE, OUTLINE, OUTLINE, NEITHER,
+ OUTLINE, FILL, FILL, FILL, OUTLINE,
+ OUTLINE, FILL, FILL, FILL, OUTLINE,
+ OUTLINE, FILL, FILL, FILL, OUTLINE,
+ NEITHER, OUTLINE, OUTLINE, OUTLINE, NEITHER
+};
+
+static int *arcis[MINIARCS] =
+{
+ arcus0, arcus1, arcus2, arcus3, arcus4
+};
+
+static void
+DrawMiniArc(
+ HDC dc,
+ int width,
+ int x,
+ int y,
+ int mask,
+ COLORREF inner,
+ COLORREF outer)
+{
+ int *arc;
+ int i, j;
+
+ if (width > MINIARCS) {
+ return;
+ }
+ arc = arcis[width];
+ for (i = 0; i <= width; i++) {
+ for (j = 0; j <= width; j++) {
+ bit = (mask & *arc);
+ if (bit & OUTLINE) {
+ SetPixelV(dc, x + i, y + j, outer);
+ } else if (bit & FILL) {
+ SetPixelV(dc, x + i, y + j, inner);
+ }
+ arc++;
+ }
+ }
+}
+
+#endif
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DrawArc --
+ *
+ * This procedure handles the rendering of drawn or filled
+ * arcs and chords.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Renders the requested arcs.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+DrawArc(
+ HDC dc,
+ int arcMode, /* Mode: either ArcChord or ArcPieSlice */
+ XArc *arcPtr,
+ HPEN pen,
+ HBRUSH brush)
+{
+ int start, extent, clockwise;
+ int xstart, ystart, xend, yend;
+ double radian_start, radian_end, xr, yr;
+ double dx, dy;
+
+ if ((arcPtr->angle1 == 0) && (arcPtr->angle2 == 23040)) {
+ /* Handle special case of circle or ellipse */
+ Ellipse(dc, arcPtr->x, arcPtr->y, arcPtr->x + arcPtr->width + 1,
+ arcPtr->y + arcPtr->height + 1);
+ return;
+ }
+ start = arcPtr->angle1, extent = arcPtr->angle2;
+ clockwise = (extent < 0); /* Non-zero if clockwise */
+
+ /*
+ * Compute the absolute starting and ending angles in normalized radians.
+ * Swap the start and end if drawing clockwise.
+ */
+ start = start % (64 * 360);
+ if (start < 0) {
+ start += (64 * 360);
+ }
+ extent = (start + extent) % (64 * 360);
+ if (extent < 0) {
+ extent += (64 * 360);
+ }
+ if (clockwise) {
+ int tmp = start;
+ start = extent;
+ extent = tmp;
+ }
+#define XAngleToRadians(a) ((double)(a) / 64 * M_PI / 180);
+ radian_start = XAngleToRadians(start);
+ radian_end = XAngleToRadians(extent);
+
+ /*
+ * Now compute points on the radial lines that define the starting and
+ * ending angles. Be sure to take into account that the y-coordinate
+ * system is inverted.
+ */
+ dx = arcPtr->width * 0.5;
+ dy = arcPtr->height * 0.5;
+
+ xr = arcPtr->x + dx;
+ yr = arcPtr->y + dy;
+ xstart = (int)((xr + cos(radian_start) * dx) + 0.5);
+ ystart = (int)((yr + sin(-radian_start) * dy) + 0.5);
+ xend = (int)((xr + cos(radian_end) * dx) + 0.5);
+ yend = (int)((yr + sin(-radian_end) * dy) + 0.5);
+
+ /*
+ * Now draw a filled or open figure. Note that we have to
+ * increase the size of the bounding box by one to account for the
+ * difference in pixel definitions between X and Windows.
+ */
+
+ if (brush == 0) {
+ /*
+ * Note that this call will leave a gap of one pixel at the
+ * end of the arc for thin arcs. We can't use ArcTo because
+ * it's only supported under Windows NT.
+ */
+ Arc(dc, arcPtr->x, arcPtr->y, arcPtr->x + arcPtr->width + 1,
+ arcPtr->y + arcPtr->height + 1, xstart, ystart, xend, yend);
+ /* FIXME: */
+ } else {
+ if (arcMode == ArcChord) {
+ Chord(dc, arcPtr->x, arcPtr->y, arcPtr->x + arcPtr->width + 1,
+ arcPtr->y + arcPtr->height + 1, xstart, ystart, xend, yend);
+ } else if (arcMode == ArcPieSlice) {
+ Pie(dc, arcPtr->x, arcPtr->y, arcPtr->x + arcPtr->width + 1,
+ arcPtr->y + arcPtr->height + 1, xstart, ystart, xend, yend);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XDrawArcs --
+ *
+ * Draws multiple circular or elliptical arcs. Each arc is
+ * specified by a rectangle and two angles. The center of the
+ * circle or ellipse is the center of the rect- angle, and the
+ * major and minor axes are specified by the width and height.
+ * Positive angles indicate counterclock- wise motion, and
+ * negative angles indicate clockwise motion. If the magnitude
+ * of angle2 is greater than 360 degrees, XDrawArcs truncates it
+ * to 360 degrees.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Draws an arc for each array element on the specified drawable.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXDrawArcs(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ XArc *arcArr,
+ int nArcs)
+{
+ HPEN pen, oldPen;
+ HBRUSH brush, oldBrush;
+ HDC dc;
+ TkWinDCState state;
+ register XArc *arcPtr, *endPtr;
+
+ display->request++;
+ if (drawable == None) {
+ return;
+ }
+ dc = TkWinGetDrawableDC(display, drawable, &state);
+ SetROP2(dc, tkpWinRopModes[gc->function]);
+ pen = Blt_GCToPen(dc, gc);
+ oldPen = SelectPen(dc, pen);
+ brush = GetStockBrush(NULL_BRUSH);
+ oldBrush = SelectBrush(dc, brush);
+ endPtr = arcArr + nArcs;
+ for (arcPtr = arcArr; arcPtr < endPtr; arcPtr++) {
+ DrawArc(dc, gc->arc_mode, arcPtr, pen, 0);
+ }
+ DeleteBrush(SelectBrush(dc, oldBrush));
+ DeletePen(SelectPen(dc, oldPen));
+ TkWinReleaseDrawableDC(drawable, dc, &state);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XFillArcs --
+ *
+ * Draw a filled arc.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Draws a filled arc for each array element on the specified drawable.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXFillArcs(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ XArc *arcArr,
+ int nArcs)
+{
+ HBRUSH brush, oldBrush;
+ HPEN pen, oldPen;
+ HDC dc;
+ register XArc *arcPtr, *endPtr;
+ TkWinDCState state;
+
+ display->request++;
+ if (drawable == None) {
+ return;
+ }
+ dc = TkWinGetDrawableDC(display, drawable, &state);
+ SetROP2(dc, tkpWinRopModes[gc->function]);
+ pen = Blt_GCToPen(dc, gc);
+ oldPen = SelectPen(dc, pen);
+ brush = CreateSolidBrush(gc->foreground);
+ oldBrush = SelectBrush(dc, brush);
+ endPtr = arcArr + nArcs;
+ for (arcPtr = arcArr; arcPtr < endPtr; arcPtr++) {
+ DrawArc(dc, gc->arc_mode, arcPtr, pen, brush);
+ }
+ DeleteBrush(SelectBrush(dc, oldBrush));
+ DeletePen(SelectPen(dc, oldPen));
+ TkWinReleaseDrawableDC(drawable, dc, &state);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XDrawLines --
+ *
+ * Draw connected lines.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Renders a series of connected lines.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void CALLBACK
+DrawDot(
+ int x, int y, /* Coordinates of point */
+ LPARAM clientData)
+{ /* Line information */
+ DashInfo *infoPtr = (DashInfo *) clientData;
+ int count;
+
+ infoPtr->count++;
+ count = (infoPtr->count + infoPtr->offset) / infoPtr->nBits;
+ if (count & 0x1) {
+ SetPixelV(infoPtr->dc, x, y, infoPtr->color);
+ }
+}
+
+
+void
+Blt_EmulateXDrawLine(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ int x1, int y1,
+ int x2, int y2)
+{
+ TkWinDCState state;
+ HDC dc;
+
+ if (drawable == None) {
+ return;
+ }
+ dc = TkWinGetDrawableDC(display, drawable, &state);
+ SetROP2(dc, tkpWinRopModes[gc->function]);
+ if (gc->line_style != LineSolid) {
+ /* Handle dotted lines specially */
+ DashInfo info;
+
+ if (!GetDashInfo(dc, gc, &info)) {
+ goto solidLine;
+ }
+ LineDDA(x1, y1, x2, y2, DrawDot, (LPARAM) & info);
+ } else {
+ HPEN pen, oldPen;
+ HBRUSH brush, oldBrush;
+
+ solidLine:
+ pen = Blt_GCToPen(dc, gc);
+ oldPen = SelectPen(dc, pen);
+ brush = CreateSolidBrush(gc->foreground);
+ oldBrush = SelectBrush(dc, brush);
+ MoveToEx(dc, x1, y1, (LPPOINT) NULL);
+ LineTo(dc, x2, y2);
+ DeletePen(SelectPen(dc, oldPen));
+ DeleteBrush(SelectBrush(dc, oldBrush));
+ }
+ TkWinReleaseDrawableDC(drawable, dc, &state);
+}
+
+static void
+DrawLine(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ POINT *points,
+ int nPoints)
+{
+ TkWinDCState state;
+ HDC dc;
+ register int i, n;
+ int start, extra, size;
+ HPEN pen, oldPen;
+ HBRUSH brush, oldBrush;
+
+ if (drawable == None) {
+ return;
+ }
+ dc = TkWinGetDrawableDC(display, drawable, &state);
+ pen = Blt_GCToPen(dc, gc);
+ oldPen = SelectPen(dc, pen);
+ brush = CreateSolidBrush(gc->foreground);
+ oldBrush = SelectBrush(dc, brush);
+ SetROP2(dc, tkpWinRopModes[gc->function]);
+
+ start = extra = 0;
+ /*
+ * Depending if the line is wide (> 1 pixel), arbitrarily break
+ * the line in sections of 100 points. This bit of weirdness has
+ * to do with wide geometric pens. The longer the polyline, the
+ * slower it draws. The trade off is that we lose dash and
+ * cap uniformity for unbearably slow polyline draws.
+ */
+ if (gc->line_width > 1) {
+ size = 100;
+ } else {
+ size = nPoints;
+ }
+ for (i = nPoints; i > 0; i -= size) {
+ n = MIN(i, size);
+ Polyline(dc, points + start, n + extra);
+ start += (n - 1);
+ extra = 1;
+ }
+ DeletePen(SelectPen(dc, oldPen));
+ DeleteBrush(SelectBrush(dc, oldBrush));
+ TkWinReleaseDrawableDC(drawable, dc, &state);
+}
+
+void
+Blt_DrawPoint2DLine(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ Point2D *screenPts,
+ int nScreenPts)
+{
+ POINT *points;
+ Point2D *srcPtr, *endPtr;
+ register POINT *destPtr; /* Array of points. */
+
+ if (drawable == None) {
+ return;
+ }
+ points = Blt_Malloc(sizeof(POINT) * nScreenPts);
+ if (points == NULL) {
+ return;
+ }
+ destPtr = points;
+ endPtr = screenPts + nScreenPts;
+ for (srcPtr = screenPts; srcPtr < endPtr; srcPtr++) {
+ destPtr->x = (int)srcPtr->x;
+ destPtr->y = (int)srcPtr->y;
+ destPtr++;
+ }
+ DrawLine(display, drawable, gc, points, nScreenPts);
+ Blt_Free(points);
+}
+
+void
+Blt_EmulateXDrawLines(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ XPoint *pointArr,
+ int nPoints,
+ int mode)
+{
+ if (drawable == None) {
+ return;
+ }
+ if (gc->line_style != LineSolid) { /* Handle dotted lines specially */
+ DashInfo info;
+ TkWinDCState state;
+ HDC dc;
+ int result;
+
+ dc = TkWinGetDrawableDC(display, drawable, &state);
+ SetROP2(dc, tkpWinRopModes[gc->function]);
+ result = GetDashInfo(dc, gc, &info);
+ if (result) {
+ register XPoint *p1, *p2;
+ register int i;
+
+ p1 = pointArr;
+ p2 = p1 + 1;
+ for (i = 1; i < nPoints; i++, p1++, p2++) {
+ LineDDA(p1->x, p1->y, p2->x, p2->y, DrawDot, (LPARAM) & info);
+ }
+ result = TCL_OK;
+ }
+ TkWinReleaseDrawableDC(drawable, dc, &state);
+ if (result) {
+ return;
+ }
+ } else {
+ POINT *points, *destPtr;
+ XPoint *srcPtr, *endPtr;
+
+ points = Blt_Malloc(sizeof(POINT) * nPoints);
+ if (points == NULL) {
+ return;
+ }
+ endPtr = pointArr + nPoints;
+ if (mode == CoordModeOrigin) {
+ destPtr = points;
+ for (srcPtr = pointArr; srcPtr < endPtr; srcPtr++) {
+ destPtr->x = (int)srcPtr->x;
+ destPtr->y = (int)srcPtr->y;
+ destPtr++;
+ }
+ } else {
+ POINT *lastPtr;
+
+ srcPtr = pointArr;
+ destPtr = points;
+ destPtr->x = (int)srcPtr->x;
+ destPtr->y = (int)srcPtr->y;
+ lastPtr = destPtr;
+ srcPtr++, destPtr++;
+ for (/*empty*/; srcPtr < endPtr; srcPtr++) {
+ destPtr->x = lastPtr->x + (int)srcPtr->x;
+ destPtr->y = lastPtr->y + (int)srcPtr->y;
+ lastPtr = destPtr;
+ destPtr++;
+ }
+ }
+ DrawLine(display, drawable, gc, points, nPoints);
+ Blt_Free(points);
+ }
+}
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Blt_EmultateXDrawSegments --
+ *
+ * Draws multiple, unconnected lines. For each segment, draws a
+ * line between (x1, y1) and (x2, y2). It draws the lines in the
+ * order listed in the array of XSegment structures and does not
+ * perform joining at coincident endpoints. For any given line,
+ * does not draw a pixel more than once. If lines intersect, the
+ * intersecting pixels are drawn multiple times.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Draws unconnected line segments on the specified drawable.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXDrawSegments(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ XSegment *segArr,
+ int nSegments)
+{
+ HDC dc;
+ register XSegment *segPtr, *endPtr;
+ TkWinDCState state;
+
+ display->request++;
+ if (drawable == None) {
+ return;
+ }
+ dc = TkWinGetDrawableDC(display, drawable, &state);
+ SetROP2(dc, tkpWinRopModes[gc->function]);
+ if (gc->line_style != LineSolid) {
+ /* Handle dotted lines specially */
+ DashInfo info;
+
+ if (!GetDashInfo(dc, gc, &info)) {
+ goto solidLine;
+ }
+ endPtr = segArr + nSegments;
+ for (segPtr = segArr; segPtr < endPtr; segPtr++) {
+ info.count = 0; /* Reset dash counter after every segment. */
+ LineDDA(segPtr->x1, segPtr->y1, segPtr->x2, segPtr->y2, DrawDot,
+ (LPARAM)&info);
+ }
+ } else {
+ HPEN pen, oldPen;
+
+ solidLine:
+ pen = Blt_GCToPen(dc, gc);
+ oldPen = SelectPen(dc, pen);
+ endPtr = segArr + nSegments;
+ for (segPtr = segArr; segPtr < endPtr; segPtr++) {
+ MoveToEx(dc, segPtr->x1, segPtr->y1, (LPPOINT) NULL);
+ LineTo(dc, segPtr->x2, segPtr->y2);
+ }
+ DeletePen(SelectPen(dc, oldPen));
+ }
+ TkWinReleaseDrawableDC(drawable, dc, &state);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Blt_EmultateXDrawRectangle --
+ *
+ * Draws the outlines of the specified rectangle as if a
+ * five-point PolyLine protocol request were specified for each
+ * rectangle:
+ *
+ * [x,y] [x+width,y] [x+width,y+height] [x,y+height]
+ * [x,y]
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Draws a rectangle on the specified drawable.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXDrawRectangle(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ int x, int y,
+ unsigned int width,
+ unsigned int height)
+{
+ TkWinDCState state;
+ HPEN pen, oldPen;
+ HBRUSH brush, oldBrush;
+ HDC dc;
+
+ if (drawable == None) {
+ return;
+ }
+ dc = TkWinGetDrawableDC(display, drawable, &state);
+ pen = Blt_GCToPen(dc, gc);
+ brush = GetStockObject(NULL_BRUSH);
+ oldPen = SelectPen(dc, pen);
+ oldBrush = SelectBrush(dc, brush);
+ SetROP2(dc, tkpWinRopModes[gc->function]);
+ if (gc->line_style != LineSolid) {
+ /* Handle dotted lines specially */
+ register int x2, y2;
+ DashInfo info;
+
+ if (!GetDashInfo(dc, gc, &info)) {
+ goto solidLine;
+ }
+ x2 = x + width;
+ y2 = y + height;
+ LineDDA(x, y, x2, y, DrawDot, (LPARAM)&info);
+ LineDDA(x2, y, x2, y2, DrawDot, (LPARAM)&info);
+ LineDDA(x2, y2, x, y2, DrawDot, (LPARAM)&info);
+ LineDDA(x, y2, x, y, DrawDot, (LPARAM)&info);
+ } else {
+ solidLine:
+ Rectangle(dc, x, y, x + width + 1, y + height + 1);
+ }
+ DeletePen(SelectPen(dc, oldPen));
+ DeleteBrush(SelectBrush(dc, oldBrush));
+ TkWinReleaseDrawableDC(drawable, dc, &state);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Blt_EmulateXDrawPoints --
+ *
+ * Uses the foreground pixel and function components of the GC to
+ * draw a multiple points into the specified drawable.
+ * CoordModeOrigin treats all coordinates as relative to the
+ * origin, and CoordModePrevious treats all coordinates after
+ * the first as relative to the previous point.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Draws points on the specified drawable.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXDrawPoints(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ XPoint *pointArr,
+ int nPoints,
+ int mode)
+{ /* Ignored. CoordModeOrigin is assumed. */
+ HDC dc;
+ register XPoint *pointPtr, *endPtr;
+ TkWinDCState state;
+
+ display->request++;
+ if (drawable == None) {
+ return;
+ }
+ dc = TkWinGetDrawableDC(display, drawable, &state);
+ SetROP2(dc, tkpWinRopModes[gc->function]);
+ endPtr = pointArr + nPoints;
+ for (pointPtr = pointArr; pointPtr < endPtr; pointPtr++) {
+ SetPixelV(dc, pointPtr->x, pointPtr->y, gc->foreground);
+ }
+ TkWinReleaseDrawableDC(drawable, dc, &state);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Blt_EmultateXReparentWindow --
+ *
+ * If the specified window is mapped, automatically performs an
+ * UnmapWindow request on it, removes it from its current
+ * position in the hierarchy, and inserts it as the child of the
+ * specified parent. The window is placed in the stacking order
+ * on top with respect to sibling windows.
+ *
+ * Note: In WIN32 you can't reparent to/from another application.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Reparents the specified window.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXReparentWindow(
+ Display *display,
+ Window window,
+ Window parent,
+ int x,
+ int y)
+{
+ HWND child, newParent;
+
+ child = Tk_GetHWND(window);
+ newParent = Tk_GetHWND(parent);
+ SetParent(child, newParent);
+ SetWindowLong(child, GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN |
+ WS_CLIPSIBLINGS);
+
+ XMoveWindow(display, window, x, y);
+ XRaiseWindow(display, window);
+ XMapWindow(display, window);
+}
+
+void
+Blt_EmulateXSetDashes(
+ Display *display,
+ GC gc,
+ int dashOffset,
+ _Xconst char *dashList,
+ int n)
+{
+ gc->dashes = (unsigned char)strlen(dashList);
+ gc->dash_offset = (int)dashList;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Blt_EmultateXDrawString --
+ *
+ * Draw a single string in the current font.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Renders the specified string in the drawable.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXDrawString(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ int x,
+ int y,
+ _Xconst char *string,
+ int length)
+{
+ if (drawable == None) {
+ return;
+ }
+ Tk_DrawChars(display, drawable, gc, (Tk_Font)gc->font, string, length,
+ x, y);
+}
+
+static void
+TileArea(destDC, srcDC, tileOriginX, tileOriginY, tileWidth, tileHeight,
+ x, y, width, height)
+ HDC destDC, srcDC;
+ int tileOriginX, tileOriginY, tileWidth, tileHeight;
+ int x, y, width, height;
+{
+ int destX, destY;
+ int destWidth, destHeight;
+ int srcX, srcY;
+ int xOrigin, yOrigin;
+ int delta;
+ int left, top, right, bottom;
+
+ xOrigin = x, yOrigin = y;
+ if (x < tileOriginX) {
+ delta = (tileOriginX - x) % tileWidth;
+ if (delta > 0) {
+ xOrigin -= (tileWidth - delta);
+ }
+ } else if (x > tileOriginX) {
+ delta = (x - tileOriginX) % tileWidth;
+ if (delta > 0) {
+ xOrigin -= delta;
+ }
+ }
+ if (y < tileOriginY) {
+ delta = (tileOriginY - y) % tileHeight;
+ if (delta > 0) {
+ yOrigin -= (tileHeight - delta);
+ }
+ } else if (y >= tileOriginY) {
+ delta = (y - tileOriginY) % tileHeight;
+ if (delta > 0) {
+ yOrigin -= delta;
+ }
+ }
+#ifdef notdef
+ PurifyPrintf("tile is (%d,%d,%d,%d)\n", tileOriginX, tileOriginY,
+ tileWidth, tileHeight);
+ PurifyPrintf("region is (%d,%d,%d,%d)\n", x, y, width, height);
+ PurifyPrintf("starting at %d,%d\n", xOrigin, yOrigin);
+#endif
+ left = x;
+ right = x + width;
+ top = y;
+ bottom = y + height;
+ for (y = yOrigin; y < bottom; y += tileHeight) {
+ srcY = 0;
+ destY = y;
+ destHeight = tileHeight;
+ if (y < top) {
+ srcY = (top - y);
+ destHeight = tileHeight - srcY;
+ destY = top;
+ }
+ if ((destY + destHeight) > bottom) {
+ destHeight = (bottom - destY);
+ }
+ for (x = xOrigin; x < right; x += tileWidth) {
+ srcX = 0;
+ destX = x;
+ destWidth = tileWidth;
+ if (x < left) {
+ srcX = (left - x);
+ destWidth = tileWidth - srcX;
+ destX = left;
+ }
+ if ((destX + destWidth) > right) {
+ destWidth = (right - destX);
+ }
+#ifdef notdef
+ PurifyPrintf("drawing pattern (%d,%d,%d,%d) at %d,%d\n",
+ srcX , srcY, destWidth, destHeight, destX, destY);
+#endif
+ BitBlt(destDC, destX, destY, destWidth, destHeight,
+ srcDC, srcX, srcY, SRCCOPY);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Blt_EmultateXFillRectangles --
+ *
+ * Fill multiple rectangular areas in the given drawable.
+ * Handles tiling.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Draws onto the specified drawable.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Blt_EmulateXFillRectangles(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ XRectangle *rectArr,
+ int nRectangles)
+{
+ BITMAP bm;
+ HBITMAP oldBitmap, hBitmap;
+ HBRUSH oldBrush, hFgBrush, hBgBrush, hBrush;
+ HDC hDC;
+ HDC memDC;
+ RECT rect;
+ TkWinDCState state;
+ TkWinDrawable *twdPtr;
+ register XRectangle *rectPtr, *endPtr;
+
+ if (drawable == None) {
+ return;
+ }
+ hDC = TkWinGetDrawableDC(display, drawable, &state);
+ SetROP2(hDC, tkpWinRopModes[gc->function]);
+
+ switch(gc->fill_style) {
+ case FillTiled:
+ if (gc->tile == None) {
+ goto fillSolid;
+ }
+#ifdef notdef
+ if ((GetDeviceCaps(hDC, RASTERCAPS) & RC_BITBLT) == 0) {
+ goto fillSolid;
+ }
+#endif
+ twdPtr = (TkWinDrawable *)gc->tile;
+ GetObject(twdPtr->bitmap.handle, sizeof(BITMAP), &bm);
+ memDC = CreateCompatibleDC(hDC);
+ oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle);
+ endPtr = rectArr + nRectangles;
+ for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) {
+ TileArea(hDC, memDC, gc->ts_x_origin, gc->ts_y_origin, bm.bmWidth,
+ bm.bmHeight, (int)rectPtr->x, (int)rectPtr->y,
+ (int)rectPtr->width, (int)rectPtr->height);
+ }
+ SelectBitmap(memDC, oldBitmap);
+ DeleteDC(memDC);
+ break;
+
+ case FillOpaqueStippled:
+ case FillStippled:
+ if (gc->stipple == None) {
+ goto fillSolid;
+ }
+ twdPtr = (TkWinDrawable *)gc->stipple;
+ if (twdPtr->type != TWD_BITMAP) {
+ panic("unexpected drawable type in stipple");
+ }
+ hBrush = CreatePatternBrush(twdPtr->bitmap.handle);
+ SetBrushOrgEx(hDC, gc->ts_x_origin, gc->ts_y_origin, NULL);
+ oldBrush = SelectBrush(hDC, hBrush);
+ memDC = CreateCompatibleDC(hDC);
+
+ /*
+ * For each rectangle, create a drawing surface which is the size of
+ * the rectangle and fill it with the background color. Then merge the
+ * result with the stipple pattern.
+ */
+ hFgBrush = CreateSolidBrush(gc->foreground);
+ hBgBrush = CreateSolidBrush(gc->background);
+ endPtr = rectArr + nRectangles;
+ for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) {
+ hBitmap = CreateCompatibleBitmap(hDC, rectPtr->width,
+ rectPtr->height);
+ oldBitmap = SelectObject(memDC, hBitmap);
+ rect.left = rect.top = 0;
+ rect.right = rectPtr->width;
+ rect.bottom = rectPtr->height;
+ FillRect(memDC, &rect, hFgBrush);
+ BitBlt(hDC, rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height,
+ memDC, 0, 0, COPYBG);
+ if (gc->fill_style == FillOpaqueStippled) {
+ FillRect(memDC, &rect, hBgBrush);
+ BitBlt(hDC, rectPtr->x, rectPtr->y, rectPtr->width,
+ rectPtr->height, memDC, 0, 0, COPYFG);
+ }
+ SelectObject(memDC, oldBitmap);
+ DeleteObject(hBitmap);
+ }
+ DeleteBrush(hFgBrush);
+ DeleteBrush(hBgBrush);
+ DeleteDC(memDC);
+ SelectBrush(hDC, oldBrush);
+ DeleteBrush(hBrush);
+ break;
+
+ case FillSolid:
+ fillSolid:
+ memDC = CreateCompatibleDC(hDC);
+ hFgBrush = CreateSolidBrush(gc->foreground);
+ endPtr = rectArr + nRectangles;
+ for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) {
+ hBitmap = CreateCompatibleBitmap(hDC, rectPtr->width,
+ rectPtr->height);
+ oldBitmap = SelectObject(memDC, hBitmap);
+ rect.left = rect.top = 0;
+ rect.right = rectPtr->width;
+ rect.bottom = rectPtr->height;
+ FillRect(memDC, &rect, hFgBrush);
+ BitBlt(hDC, rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height,
+ memDC, 0, 0, SRCCOPY);
+ SelectObject(memDC, oldBitmap);
+ DeleteObject(hBitmap);
+ }
+ DeleteBrush(hFgBrush);
+ DeleteDC(memDC);
+ break;
+ }
+ TkWinReleaseDrawableDC(drawable, hDC, &state);
+}
+
+void
+Blt_EmulateXFillRectangle(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height)
+{
+ HDC hDC;
+ RECT rect;
+ TkWinDCState state;
+
+ if (drawable == None) {
+ return;
+ }
+ hDC = TkWinGetDrawableDC(display, drawable, &state);
+ SetROP2(hDC, tkpWinRopModes[gc->function]);
+ rect.left = rect.top = 0;
+ rect.right = width;
+ rect.bottom = height;
+
+ switch(gc->fill_style) {
+ case FillTiled:
+ {
+ TkWinDrawable *twdPtr;
+ HBITMAP oldBitmap;
+ HDC memDC;
+ BITMAP bm;
+
+ if (gc->tile == None) {
+ goto fillSolid;
+ }
+#ifdef notdef
+ if ((GetDeviceCaps(hDC, RASTERCAPS) & RC_BITBLT) == 0) {
+ goto fillSolid;
+ }
+#endif
+ twdPtr = (TkWinDrawable *)gc->tile;
+ /* The tiling routine needs to know the size of the bitmap */
+ GetObject(twdPtr->bitmap.handle, sizeof(BITMAP), &bm);
+
+ memDC = CreateCompatibleDC(hDC);
+ oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle);
+ TileArea(hDC, memDC, gc->ts_x_origin, gc->ts_y_origin, bm.bmWidth,
+ bm.bmHeight, x, y, width, height);
+ SelectBitmap(memDC, oldBitmap);
+ DeleteDC(memDC);
+ }
+ break;
+
+ case FillOpaqueStippled:
+ case FillStippled:
+ {
+ TkWinDrawable *twdPtr;
+ HBRUSH oldBrush, hBrush;
+ HBRUSH hBrushFg, hBrushBg;
+ HBITMAP oldBitmap, hBitmap;
+ HDC memDC;
+
+ if (gc->stipple == None) {
+ goto fillSolid;
+ }
+ twdPtr = (TkWinDrawable *)gc->stipple;
+ if (twdPtr->type != TWD_BITMAP) {
+ panic("unexpected drawable type in stipple");
+ }
+ hBrush = CreatePatternBrush(twdPtr->bitmap.handle);
+ SetBrushOrgEx(hDC, gc->ts_x_origin, gc->ts_y_origin, NULL);
+ oldBrush = SelectBrush(hDC, hBrush);
+ memDC = CreateCompatibleDC(hDC);
+
+ hBrushFg = CreateSolidBrush(gc->foreground);
+ hBrushBg = CreateSolidBrush(gc->background);
+ hBitmap = CreateCompatibleBitmap(hDC, width, height);
+ oldBitmap = SelectObject(memDC, hBitmap);
+ FillRect(memDC, &rect, hBrushFg);
+ SetBkMode(hDC, TRANSPARENT);
+ BitBlt(hDC, x, y, width, height, memDC, 0, 0, COPYFG);
+ if (gc->fill_style == FillOpaqueStippled) {
+ FillRect(memDC, &rect, hBrushBg);
+ BitBlt(hDC, x, y, width, height, memDC, 0, 0, COPYBG);
+ }
+ SelectBrush(hDC, oldBrush);
+ SelectBitmap(memDC, oldBitmap);
+ DeleteBrush(hBrushFg);
+ DeleteBrush(hBrushBg);
+ DeleteBrush(hBrush);
+ DeleteBitmap(hBitmap);
+ DeleteDC(memDC);
+ }
+ break;
+
+ case FillSolid:
+ {
+ HBRUSH hBrush;
+ HBITMAP oldBitmap, hBitmap;
+ HDC memDC;
+
+ fillSolid:
+ /* TkWinFillRect(hDC, x, y, width, height, gc->foreground); */
+ memDC = CreateCompatibleDC(hDC);
+ hBrush = CreateSolidBrush(gc->foreground);
+ hBitmap = CreateCompatibleBitmap(hDC, width, height);
+ oldBitmap = SelectBitmap(memDC, hBitmap);
+ rect.left = rect.top = 0;
+ rect.right = width;
+ rect.bottom = height;
+ FillRect(memDC, &rect, hBrush);
+ BitBlt(hDC, x, y, width, height, memDC, 0, 0, SRCCOPY);
+ SelectObject(memDC, oldBitmap);
+ DeleteBitmap(hBitmap);
+ DeleteBrush(hBrush);
+ DeleteDC(memDC);
+ }
+ break;
+ }
+ TkWinReleaseDrawableDC(drawable, hDC, &state);
+}
+
+static BOOL
+DrawChars(HDC dc, int x, int y, char *string, int length)
+{
+ BOOL result;
+
+#if (TCL_VERSION_NUMBER >= _VERSION(8,1,0))
+ if (systemEncoding == NULL) {
+ result = TextOutA(dc, x, y, string, length);
+ } else {
+ const unsigned short *wstring;
+ Tcl_DString dString;
+
+ Tcl_DStringInit(&dString);
+ Tcl_UtfToExternalDString(systemEncoding, string, length, &dString);
+ length = Tcl_NumUtfChars(string, -1);
+ wstring = (const unsigned short *)Tcl_DStringValue(&dString);
+ result = TextOutW(dc, x, y, wstring, length);
+ Tcl_DStringFree(&dString);
+ }
+#else
+ result = TextOutA(dc, x, y, string, length);
+#endif /* TCL_VERSION_NUMBER >= 8.1.0 */
+ return result;
+}
+
+int
+Blt_DrawRotatedText(
+ Display *display,
+ Drawable drawable,
+ int x, int y,
+ double theta,
+ TextStyle *tsPtr,
+ TextLayout *textPtr)
+{
+ HFONT hFont, oldFont;
+ TkWinDCState state;
+ HDC hDC;
+ int isActive;
+ int bbWidth, bbHeight;
+ double sinTheta, cosTheta;
+ Point2D p, q, center;
+ register TextFragment *fragPtr, *endPtr;
+ static int initialized = 0;
+
+#if (TCL_VERSION_NUMBER >= _VERSION(8,1,0))
+ if (!initialized) {
+ if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) {
+ /*
+ * If running NT, then we will be calling some Unicode functions
+ * explictly. So, even if the Tcl system encoding isn't Unicode,
+ * make sure we convert to/from the Unicode char set.
+ */
+ systemEncoding = Tcl_GetEncoding(NULL, "unicode");
+ }
+ initialized = 1;
+ }
+#endif
+ hFont = CreateRotatedFont(tsPtr->gc->font, theta);
+ if (hFont == NULL) {
+ return FALSE;
+ }
+ isActive = (tsPtr->state & STATE_ACTIVE);
+ hDC = TkWinGetDrawableDC(display, drawable, &state);
+ SetROP2(hDC, tsPtr->gc->function);
+ oldFont = SelectFont(hDC, hFont);
+
+ Blt_GetBoundingBox(textPtr->width, textPtr->height, theta, &bbWidth,
+ &bbHeight, (Point2D *)NULL);
+ Blt_TranslateAnchor(x, y, bbWidth, bbHeight, tsPtr->anchor, &x, &y);
+ center.x = (double)textPtr->width * -0.5;
+ center.y = (double)textPtr->height * -0.5;
+ theta = (-theta / 180.0) * M_PI;
+ sinTheta = sin(theta), cosTheta = cos(theta);
+
+ endPtr = textPtr->fragArr + textPtr->nFrags;
+
+ for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
+ p.x = center.x + (double)fragPtr->x;
+ p.y = center.y + (double)fragPtr->y;
+ q.x = x + (p.x * cosTheta) - (p.y * sinTheta) + (bbWidth * 0.5);
+ q.y = y + (p.x * sinTheta) + (p.y * cosTheta) + (bbHeight * 0.5);
+ fragPtr->sx = ROUND(q.x);
+ fragPtr->sy = ROUND(q.y);
+ }
+ SetBkMode(hDC, TRANSPARENT);
+ SetTextAlign(hDC, TA_LEFT | TA_BASELINE);
+
+ if (tsPtr->state & (STATE_DISABLED | STATE_EMPHASIS)) {
+ TkBorder *borderPtr = (TkBorder *) tsPtr->border;
+ XColor *color1, *color2;
+
+ color1 = borderPtr->lightColor, color2 = borderPtr->darkColor;
+ if (tsPtr->state & STATE_EMPHASIS) {
+ XColor *hold;
+
+ hold = color1, color1 = color2, color2 = hold;
+ }
+ if (color1 != NULL) {
+ SetTextColor(hDC, color1->pixel);
+ for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
+ DrawChars(hDC, fragPtr->sx, fragPtr->sy, fragPtr->text,
+ fragPtr->count);
+ }
+ }
+ if (color2 != NULL) {
+ SetTextColor(hDC, color2->pixel);
+ for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
+ DrawChars(hDC, fragPtr->sx + 1, fragPtr->sy + 1, fragPtr->text,
+ fragPtr->count);
+ }
+ }
+ goto done; /* Done */
+ }
+ SetBkMode(hDC, TRANSPARENT);
+ if ((tsPtr->shadow.offset > 0) && (tsPtr->shadow.color != NULL)) {
+ SetTextColor(hDC, tsPtr->shadow.color->pixel);
+ for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
+ DrawChars(hDC, fragPtr->sx + tsPtr->shadow.offset,
+ fragPtr->sy + tsPtr->shadow.offset, fragPtr->text,
+ fragPtr->count);
+ }
+ }
+ if (isActive) {
+ SetTextColor(hDC, tsPtr->activeColor->pixel);
+ } else {
+ SetTextColor(hDC, tsPtr->color->pixel);
+ }
+
+ for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
+ DrawChars(hDC, fragPtr->sx, fragPtr->sy, fragPtr->text,
+ fragPtr->count);
+ }
+
+ if (isActive) {
+ SetTextColor(hDC, tsPtr->color->pixel);
+ }
+ done:
+ SelectFont(hDC, oldFont);
+ DeleteFont(hFont);
+ TkWinReleaseDrawableDC(drawable, hDC, &state);
+ return TRUE;
+}
+
+static void
+DrawPixel(
+ HDC hDC,
+ int x,
+ int y,
+ COLORREF color)
+{
+ HDC memDC;
+ HBRUSH hBrushFg;
+ HBITMAP oldBitmap, hBitmap;
+ RECT rect;
+ int size;
+
+ size = 1;
+ memDC = CreateCompatibleDC(hDC);
+ hBrushFg = CreateSolidBrush(color);
+ hBitmap = CreateCompatibleBitmap(hDC, size, size);
+ oldBitmap = SelectObject(memDC, hBitmap);
+ rect.left = rect.top = 0;
+ rect.right = rect.bottom = size;
+ FillRect(memDC, &rect, hBrushFg);
+ BitBlt(hDC, x, y, size, size, memDC, 0, 0, SRCCOPY);
+ SelectObject(memDC, oldBitmap);
+ DeleteObject(hBitmap);
+ DeleteBrush(hBrushFg);
+ DeleteDC(memDC);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * PixelateBitmap --
+ *
+ * Draws a masked bitmap in given device (should be printer)
+ * context. Bit operations on print devices usually fail because
+ * there's no way to read back from the device surface to get the
+ * previous pixel values, rendering BitBlt useless. The bandaid
+ * solution here is to draw 1x1 pixel rectangles at each
+ * coordinate as directed by the the mask and source bitmaps.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Draws onto the specified drawable.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+PixelateBitmap(
+ Display *display,
+ Drawable drawable,
+ Pixmap srcBitmap,
+ Pixmap maskBitmap,
+ int width,
+ int height,
+ GC gc,
+ int destX,
+ int destY)
+{
+ register int x, y;
+ register int dx, dy;
+ int pixel;
+ unsigned char *srcBits;
+ register unsigned char *srcPtr;
+ int bitPos, bytesPerRow;
+ HDC hDC;
+ TkWinDCState state;
+
+ srcBits = Blt_GetBitmapData(display, srcBitmap, width, height,
+ &bytesPerRow);
+ if (srcBits == NULL) {
+ return;
+ }
+ hDC = TkWinGetDrawableDC(display, drawable, &state);
+ if (maskBitmap != None) {
+ register unsigned char *maskPtr;
+ unsigned char *maskBits;
+ maskBits = Blt_GetBitmapData(display, maskBitmap, width, height,
+ &bytesPerRow);
+ bytesPerRow = ((width + 31) & ~31) / 8;
+ for (dy = destY, y = height - 1; y >= 0; y--, dy++) {
+ maskPtr = maskBits + (bytesPerRow * y);
+ srcPtr = srcBits + (bytesPerRow * y);
+ for (dx = destX, x = 0; x < width; x++, dx++) {
+ bitPos = x % 8;
+ pixel = (*maskPtr & (0x80 >> bitPos));
+ if (pixel) {
+ pixel = (*srcPtr & (0x80 >> bitPos));
+ DrawPixel(hDC, dx, dy,
+ (pixel) ? gc->foreground : gc->background);
+ }
+ if (bitPos == 7) {
+ srcPtr++, maskPtr++;
+ }
+ } /* x */
+ }
+ Blt_Free(maskBits);
+ } else {
+ bytesPerRow = ((width + 31) & ~31) / 8;
+ for (dy = destY, y = height - 1; y >= 0; y--, dy++) {
+ srcPtr = srcBits + (bytesPerRow * y);
+ for (dx = destX, x = 0; x < width; x++, dx++) {
+ bitPos = x % 8;
+ pixel = (*srcPtr & (0x80 >> bitPos));
+ DrawPixel(hDC, dx, dy,
+ (pixel) ? gc->foreground : gc->background);
+ if (bitPos == 7) {
+ srcPtr++;
+ }
+ }
+ }
+ }
+ TkWinReleaseDrawableDC(drawable, hDC, &state);
+ Blt_Free(srcBits);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Blt_EmulateXCopyPlane --
+ *
+ * Simplified version of XCopyPlane. Right now it ignores
+ * function,
+ * clip_x_origin,
+ * clip_y_origin
+ *
+ * The plane argument must always be 1.
+ *
+ * This routine differs from the Tk version in how it handles
+ * transparency. It uses a different method of drawing transparent
+ * bitmaps that doesn't copy the background or use brushes. The
+ * second change is to call a special routine when the destDC is
+ * a printer. Stippling is done by a very slow brute-force
+ * method of drawing 1x1 rectangles for each pixel (bleech).
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Changes the destination drawable.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXCopyPlane(
+ Display *display,
+ Drawable src,
+ Drawable dest,
+ GC gc,
+ int srcX,
+ int srcY,
+ unsigned int width,
+ unsigned int height,
+ int destX,
+ int destY,
+ unsigned long plane)
+{
+ HDC srcDC, destDC;
+ TkWinDCState srcState, destState;
+ TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask;
+
+ display->request++;
+
+ if (plane != 1) {
+ panic("Unexpected plane specified for XCopyPlane");
+ }
+ srcDC = TkWinGetDrawableDC(display, src, &srcState);
+
+ if (src != dest) {
+ destDC = TkWinGetDrawableDC(display, dest, &destState);
+ } else {
+ destDC = srcDC;
+ }
+ if ((clipPtr == NULL) || (clipPtr->type == TKP_CLIP_REGION)) {
+ /*
+ * Case 1: opaque bitmaps. Windows handles the conversion
+ * from one bit to multiple bits by setting 0 to the
+ * foreground color, and 1 to the background color (seems
+ * backwards, but there you are).
+ */
+ if ((clipPtr != NULL) && (clipPtr->type == TKP_CLIP_REGION)) {
+ SelectClipRgn(destDC, (HRGN) clipPtr->value.region);
+ OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin);
+ }
+ SetBkMode(destDC, OPAQUE);
+ SetBkColor(destDC, gc->foreground);
+ SetTextColor(destDC, gc->background);
+ BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY,
+ SRCCOPY);
+
+ SelectClipRgn(destDC, NULL);
+
+ } else if (clipPtr->type == TKP_CLIP_PIXMAP) {
+ Drawable mask;
+ /*
+ * Case 2: transparent bitmaps are handled by setting the
+ * destination to the foreground color whenever the source
+ * pixel is set.
+ */
+ /*
+ * Case 3: two arbitrary bitmaps. Copy the source rectangle
+ * into a color pixmap. Use the result as a brush when
+ * copying the clip mask into the destination.
+ */
+ mask = clipPtr->value.pixmap;
+
+#if WINDEBUG
+ PurifyPrintf("mask %s src", (mask == src) ? "==" : "!=");
+ PurifyPrintf("GetDeviceCaps=%x",
+ GetDeviceCaps(destDC, TECHNOLOGY) & DT_RASDISPLAY);
+#endif
+ {
+ HDC maskDC;
+ TkWinDCState maskState;
+
+ if (mask != src) {
+ maskDC = TkWinGetDrawableDC(display, mask, &maskState);
+ } else {
+ maskDC = srcDC;
+ }
+ SetBkMode(destDC, OPAQUE);
+ SetTextColor(destDC, gc->background);
+ SetBkColor(destDC, gc->foreground);
+ BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY,
+ SRCINVERT);
+ /*
+ * Make sure we treat the mask as a monochrome bitmap.
+ * We can get alpha-blending with non-black/white fg/bg
+ * color selections.
+ */
+ SetTextColor(destDC, RGB(255,255,255));
+ SetBkColor(destDC, RGB(0,0,0));
+
+ /* FIXME: Handle gc->clip_?_origin's */
+ BitBlt(destDC, destX, destY, width, height, maskDC, 0, 0, SRCAND);
+
+ SetTextColor(destDC, gc->background);
+ SetBkColor(destDC, gc->foreground);
+ BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY,
+ SRCINVERT);
+ if (mask != src) {
+ TkWinReleaseDrawableDC(mask, maskDC, &maskState);
+ }
+ }
+ }
+ if (src != dest) {
+ TkWinReleaseDrawableDC(dest, destDC, &destState);
+ }
+ TkWinReleaseDrawableDC(src, srcDC, &srcState);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Blt_EmulateXCopyArea --
+ *
+ * Copies data from one drawable to another using block transfer
+ * routines. The small enhancement over the version in Tk is
+ * that it doesn't assume that the source and destination devices
+ * have the same resolution. This isn't true when the destination
+ * device is a printer.
+ *
+ * FIXME: not true anymore. delete this routine.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Data is moved from a window or bitmap to a second window,
+ * bitmap, or printer.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXCopyArea(
+ Display *display,
+ Drawable src,
+ Drawable dest,
+ GC gc,
+ int srcX, /* Source X-coordinate */
+ int srcY, /* Source Y-coordinate. */
+ unsigned int width, /* Width of area. */
+ unsigned int height, /* Height of area. */
+ int destX, /* Destination X-coordinate (in screen
+ * coordinates). */
+ int destY) /* Destination Y-coordinate (in screen
+ * coordinates). */
+{
+ HDC srcDC, destDC;
+ TkWinDCState srcState, destState;
+ TkpClipMask *clipPtr;
+
+ srcDC = TkWinGetDrawableDC(display, src, &srcState);
+ if (src != dest) {
+ destDC = TkWinGetDrawableDC(display, dest, &destState);
+ } else {
+ destDC = srcDC;
+ }
+ clipPtr = (TkpClipMask *)gc->clip_mask;
+ if ((clipPtr != NULL) && (clipPtr->type == TKP_CLIP_REGION)) {
+ SelectClipRgn(destDC, (HRGN) clipPtr->value.region);
+ OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin);
+ }
+
+ BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY,
+ bltModes[gc->function]);
+ SelectClipRgn(destDC, NULL);
+
+ if (src != dest) {
+ TkWinReleaseDrawableDC(dest, destDC, &destState);
+ }
+ TkWinReleaseDrawableDC(src, srcDC, &srcState);
+}
+
+static void
+StippleRegion(
+ Display *display,
+ HDC hDC, /* Device context: For polygons, clip
+ * region will be installed. */
+ GC gc,
+ int x, int y,
+ int width, int height)
+{
+ BITMAP bm;
+ HBITMAP oldBitmap;
+ HDC maskDC, memDC;
+ Pixmap mask;
+ TkWinDCState maskState;
+ TkWinDrawable *twdPtr;
+ int destX, destY, destWidth, destHeight;
+ int dx, dy;
+ int left, top, right, bottom;
+ int srcX, srcY;
+ int startX, startY; /* Starting upper left corner of region. */
+
+ twdPtr = (TkWinDrawable *)gc->stipple;
+ GetObject(twdPtr->bitmap.handle, sizeof(BITMAP), &bm);
+
+ startX = x;
+ if (x < gc->ts_x_origin) {
+ dx = (gc->ts_x_origin - x) % bm.bmWidth;
+ if (dx > 0) {
+ startX -= (bm.bmWidth - dx);
+ }
+ } else if (x > gc->ts_x_origin) {
+ dx = (x - gc->ts_x_origin) % bm.bmWidth;
+ if (dx > 0) {
+ startX -= dx;
+ }
+ }
+ startY = y;
+ if (y < gc->ts_y_origin) {
+ dy = (gc->ts_y_origin - y) % bm.bmHeight;
+ if (dy > 0) {
+ startY -= (bm.bmHeight - dy);
+ }
+ } else if (y >= gc->ts_y_origin) {
+ dy = (y - gc->ts_y_origin) % bm.bmHeight;
+ if (dy > 0) {
+ startY -= dy;
+ }
+ }
+#ifdef notdef
+ PurifyPrintf("tile is (%d,%d,%d,%d)\n", gc->ts_x_origin, gc->ts_y_origin,
+ bm.bmWidth, bm.bmHeight);
+ PurifyPrintf("region is (%d,%d,%d,%d)\n", x, y, width, height);
+ PurifyPrintf("starting at %d,%d\n", startX, startY);
+#endif
+ left = x;
+ right = x + width;
+ top = y;
+ bottom = y + height;
+
+ memDC = CreateCompatibleDC(hDC);
+ oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle);
+ if (gc->fill_style == FillStippled) { /* With transparency. */
+ mask = gc->stipple;
+ if (gc->clip_mask != None) {
+ TkpClipMask *clipPtr;
+
+ clipPtr = (TkpClipMask *)gc->clip_mask;
+ if (clipPtr->type == TKP_CLIP_PIXMAP) {
+ mask = clipPtr->value.pixmap;
+ }
+ }
+ if (mask != gc->stipple) {
+ maskDC = TkWinGetDrawableDC(display, mask, &maskState);
+ } else {
+ maskDC = memDC;
+ }
+ }
+
+ for (y = startY; y < bottom; y += bm.bmHeight) {
+ srcY = 0;
+ destY = y;
+ destHeight = bm.bmHeight;
+ if (y < top) {
+ srcY = (top - y);
+ destHeight = bm.bmHeight - srcY;
+ destY = top;
+ }
+ if ((destY + destHeight) > bottom) {
+ destHeight = (bottom - destY);
+ }
+ for (x = startX; x < right; x += bm.bmWidth) {
+ srcX = 0;
+ destX = x;
+ destWidth = bm.bmWidth;
+ if (x < left) {
+ srcX = (left - x);
+ destWidth = bm.bmWidth - srcX;
+ destX = left;
+ }
+ if ((destX + destWidth) > right) {
+ destWidth = (right - destX);
+ }
+#ifdef notdef
+ PurifyPrintf("drawing pattern (%d,%d,%d,%d) at %d,%d\n",
+ srcX , srcY, destWidth, destHeight, destX, destY);
+#endif
+ if (gc->fill_style == FillStippled) { /* With transparency. */
+ SetBkMode(hDC, OPAQUE);
+ SetTextColor(hDC, gc->background);
+ SetBkColor(hDC, gc->foreground);
+ BitBlt(hDC, destX, destY, destWidth, destHeight, memDC,
+ srcX, srcY, SRCINVERT);
+ SetTextColor(hDC, RGB(255,255,255));
+ SetBkColor(hDC, RGB(0,0,0));
+ BitBlt(hDC, destX, destY, destWidth, destHeight, maskDC,
+ srcX, srcY, SRCAND);
+ SetTextColor(hDC, gc->background);
+ SetBkColor(hDC, gc->foreground);
+ BitBlt(hDC, destX, destY, destWidth, destHeight, memDC,
+ srcX, srcY, SRCINVERT);
+ } else if (gc->fill_style == FillOpaqueStippled) { /* Opaque. */
+ SetBkColor(hDC, gc->foreground);
+ SetTextColor(hDC, gc->background);
+ BitBlt(hDC, destX, destY, destWidth, destHeight, memDC,
+ srcX, srcY, SRCCOPY);
+ }
+ }
+ }
+ SelectBitmap(memDC, oldBitmap);
+ if ((gc->fill_style == FillStippled) && (mask != gc->stipple)) {
+ TkWinReleaseDrawableDC(mask, maskDC, &maskState);
+ }
+ DeleteDC(memDC);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Blt_EmulateXFillPolygon --
+ *
+ * This differs from Tk's XFillPolygon in that it works around
+ * deficencies in Windows 95/98:
+ * 1. Stippling bitmap is limited to 8x8.
+ * 2. No tiling (with or without mask).
+ * Results:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Blt_EmulateXFillPolygon(
+ Display *display,
+ Drawable drawable,
+ GC gc,
+ XPoint *pointPtr,
+ int nPoints,
+ int shape,
+ int mode)
+{
+ HDC hDC;
+ HRGN hRgn;
+ POINT *p, *winPts, *endPtr;
+ Region2D bbox;
+ TkWinDCState state;
+ int fillMode;
+
+ if (drawable == None) {
+ return;
+ }
+
+ /* Determine the bounding box of the polygon. */
+ bbox.left = bbox.right = pointPtr->x;
+ bbox.top = bbox.bottom = pointPtr->y;
+
+ /* Allocate array of POINTS to create the polygon's path. */
+ winPts = Blt_Malloc(sizeof(POINT) * nPoints);
+ endPtr = winPts + nPoints;
+ for (p = winPts; p < endPtr; p++) {
+ if (pointPtr->x < bbox.left) {
+ bbox.left = pointPtr->x;
+ }
+ if (pointPtr->x > bbox.right) {
+ bbox.right = pointPtr->x;
+ }
+ if (pointPtr->y < bbox.top) {
+ bbox.top = pointPtr->y;
+ }
+ if (pointPtr->y > bbox.bottom) {
+ bbox.bottom = pointPtr->y;
+ }
+ p->x = pointPtr->x;
+ p->y = pointPtr->y;
+ pointPtr++;
+ }
+
+ hDC = TkWinGetDrawableDC(display, drawable, &state);
+ SetROP2(hDC, tkpWinRopModes[gc->function]);
+ fillMode = (gc->fill_rule == EvenOddRule) ? ALTERNATE : WINDING;
+
+ if ((gc->fill_style == FillStippled) ||
+ (gc->fill_style == FillOpaqueStippled)) {
+ int width, height;
+
+ /* Points are offsets within the bounding box. */
+ for (p = winPts; p < endPtr; p++) {
+ p->x -= bbox.left;
+ p->y -= bbox.top;
+ }
+ /* Use the polygon as a clip path. */
+ hRgn = CreatePolygonRgn(winPts, nPoints, fillMode);
+ SelectClipRgn(hDC, hRgn);
+ OffsetClipRgn(hDC, bbox.left, bbox.top);
+
+ /* Tile the bounding box. */
+ width = bbox.right - bbox.left + 1;
+ height = bbox.bottom - bbox.top + 1;
+ StippleRegion(display, hDC, gc, bbox.left, bbox.top, width, height);
+
+ SelectClipRgn(hDC, NULL);
+ DeleteRgn(hRgn);
+ } else {
+ HPEN oldPen;
+ HBRUSH oldBrush;
+
+ /*
+ * FIXME: Right now, we're assuming that it's solid or
+ * stippled and ignoring tiling. I'll merge the bits from
+ * Blt_TilePolygon later.
+ */
+ oldPen = SelectPen(hDC, GetStockObject(NULL_PEN));
+ oldBrush = SelectBrush(hDC, CreateSolidBrush(gc->foreground));
+ SetPolyFillMode(hDC, fillMode);
+ Polygon(hDC, winPts, nPoints);
+ SelectPen(hDC, oldPen);
+ DeleteBrush(SelectBrush(hDC, oldBrush));
+ }
+ Blt_Free(winPts);
+ TkWinReleaseDrawableDC(drawable, hDC, &state);
+}