1 /*
2  * bltWinDraw.c --
3  *
4  *	This module contains WIN32 routines not included in the Tcl/Tk
5  *	libraries.
6  *
7  * Copyright 1998 by Bell Labs Innovations for Lucent Technologies.
8  *
9  * Permission to use, copy, modify, and distribute this software and
10  * its documentation for any purpose and without fee is hereby
11  * granted, provided that the above copyright notice appear in all
12  * copies and that both that the copyright notice and warranty
13  * disclaimer appear in supporting documentation, and that the names
14  * of Lucent Technologies any of their entities not be used in
15  * advertising or publicity pertaining to distribution of the software
16  * without specific, written prior permission.
17  *
18  * Lucent Technologies disclaims all warranties with regard to this
19  * software, including all implied warranties of merchantability and
20  * fitness.  In no event shall Lucent Technologies be liable for any
21  * special, indirect or consequential damages or any damages
22  * whatsoever resulting from loss of use, data or profits, whether in
23  * an action of contract, negligence or other tortuous action, arising
24  * out of or in connection with the use or performance of this
25  * software.
26  */
27 
28 #include <bltInt.h>
29 #include <X11/Xutil.h>
30 #include <X11/Xlib.h>
31 
32 #define WINDEBUG 0
33 
34 /*
35  * Data structure for setting graphics context.
36  */
37 typedef struct {
38     int function;		/* logical operation */
39     unsigned long plane_mask;	/* plane mask */
40     unsigned long foreground;	/* foreground pixel */
41     unsigned long background;	/* background pixel */
42     int line_width;		/* line width */
43     int line_style;		/* LineSolid, LineOnOffDash, LineDoubleDash */
44     int cap_style;		/* CapNotLast, CapButt,
45 				   CapRound, CapProjecting */
46     int join_style;		/* JoinMiter, JoinRound, JoinBevel */
47     int fill_style;		/* FillSolid, FillTiled,
48 				   FillStippled, FillOpaeueStippled */
49     int fill_rule;		/* EvenOddRule, WindingRule */
50     int arc_mode;		/* ArcChord, ArcPieSlice */
51     Pixmap tile;		/* tile pixmap for tiling operations */
52     Pixmap stipple;		/* stipple 1 plane pixmap for stipping */
53     int ts_x_origin;		/* offset for tile or stipple operations */
54     int ts_y_origin;
55     Font font;			/* default text font for text operations */
56     int subwindow_mode;		/* ClipByChildren, IncludeInferiors */
57     Bool graphics_exposures;	/* boolean, should exposures be generated */
58     int clip_x_origin;		/* origin for clipping */
59     int clip_y_origin;
60     Pixmap clip_mask;		/* bitmap clipping; other calls for rects */
61     int dash_offset;		/* patterned/dashed line information */
62     char dashes;		/* If -1, indicates that the extended
63 				 * information below is available. */
64     int nDashValues;
65     char dashValues[12];
66 } XGCValuesEx;
67 
68 static int tkpWinRopModes[] =
69 {
70     R2_BLACK,			/* GXclear */
71     R2_MASKPEN,			/* GXand */
72     R2_MASKPENNOT,		/* GXandReverse */
73     R2_COPYPEN,			/* GXcopy */
74     R2_MASKNOTPEN,		/* GXandInverted */
75     R2_NOT,			/* GXnoop */
76     R2_XORPEN,			/* GXxor */
77     R2_MERGEPEN,		/* GXor */
78     R2_NOTMERGEPEN,		/* GXnor */
79     R2_NOTXORPEN,		/* GXequiv */
80     R2_NOT,			/* GXinvert */
81     R2_MERGEPENNOT,		/* GXorReverse */
82     R2_NOTCOPYPEN,		/* GXcopyInverted */
83     R2_MERGENOTPEN,		/* GXorInverted */
84     R2_NOTMASKPEN,		/* GXnand */
85     R2_WHITE			/* GXset */
86 };
87 
88 #define MASKPAT		0x00E20746 /* dest = (src & pat) | (!src & dst) */
89 #define COPYFG		0x00CA0749 /* dest = (pat & src) | (!pat & dst) */
90 #define COPYBG		0x00AC0744 /* dest = (!pat & src) | (pat & dst) */
91 /*
92  * Translation table between X gc functions and Win32 BitBlt op modes.  Some
93  * of the operations defined in X don't have names, so we have to construct
94  * new opcodes for those functions.  This is arcane and probably not all that
95  * useful, but at least it's accurate.
96  */
97 
98 #define NOTSRCAND	(DWORD)0x00220326 /* dest = (NOT src) AND dest */
99 #define NOTSRCINVERT	(DWORD)0x00990066 /* dest = (NOT src) XOR dest */
100 #define SRCORREVERSE	(DWORD)0x00DD0228 /* dest = src OR (NOT dest) */
101 #define SRCNAND		(DWORD)0x007700E6 /* dest = NOT (src AND dest) */
102 
103 static int bltModes[] =
104 {
105     BLACKNESS,			/* GXclear */
106     SRCAND,			/* GXand */
107     SRCERASE,			/* GXandReverse */
108     SRCCOPY,			/* GXcopy */
109     NOTSRCAND,			/* GXandInverted */
110     PATCOPY,			/* GXnoop */
111     SRCINVERT,			/* GXxor */
112     SRCPAINT,			/* GXor */
113     NOTSRCERASE,		/* GXnor */
114     NOTSRCINVERT,		/* GXequiv */
115     DSTINVERT,			/* GXinvert */
116     SRCORREVERSE,		/* GXorReverse */
117     NOTSRCCOPY,			/* GXcopyInverted */
118     MERGEPAINT,			/* GXorInverted */
119     SRCNAND,			/* GXnand */
120     WHITENESS			/* GXset */
121 };
122 
123 #if (TCL_VERSION_NUMBER <  _VERSION(8,1,0))
124 typedef void *Tcl_Encoding;	/* Make up dummy type for encoding.  */
125 #else
126 static Tcl_Encoding systemEncoding = NULL;
127 #endif
128 
129 HPALETTE
Blt_GetSystemPalette(void)130 Blt_GetSystemPalette(void)
131 {
132     HDC hDC;
133     HPALETTE hPalette;
134     DWORD flags;
135 
136     hPalette = NULL;
137     hDC = GetDC(NULL);		/* Get the desktop device context */
138     flags = GetDeviceCaps(hDC, RASTERCAPS);
139     if (flags & RC_PALETTE) {
140 	LOGPALETTE *palettePtr;
141 
142 	palettePtr = (LOGPALETTE *)
143 	    GlobalAlloc(GPTR, sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY));
144 	palettePtr->palVersion = 0x300;
145 	palettePtr->palNumEntries = 256;
146 	GetSystemPaletteEntries(hDC, 0, 256, palettePtr->palPalEntry);
147 	hPalette = CreatePalette(palettePtr);
148 	GlobalFree(palettePtr);
149     }
150     ReleaseDC(NULL, hDC);
151     return hPalette;
152 }
153 
154 /*
155  *----------------------------------------------------------------------
156  *
157  * CreateRotatedFont --
158  *
159  *	Creates a rotated copy of the given font.  This only works
160  *	for TrueType fonts.
161  *
162  * Results:
163  *	Returns the newly create font or NULL if the font could not
164  *	be created.
165  *
166  *----------------------------------------------------------------------
167  */
168 HFONT
CreateRotatedFont(unsigned long fontId,double theta)169 CreateRotatedFont(
170     unsigned long fontId,	/* Font identifier (actually a Tk_Font) */
171     double theta)
172 {				/* Number of degrees to rotate font */
173     TkFontAttributes *faPtr;	/* Set of attributes to match. */
174     TkFont *fontPtr;
175     HFONT hFont;
176     LOGFONTW lf;
177 
178     fontPtr = (TkFont *) fontId;
179     faPtr = &fontPtr->fa;
180     ZeroMemory(&lf, sizeof(LOGFONT));
181     lf.lfHeight = -faPtr->pointsize;
182     if (lf.lfHeight < 0) {
183 	HDC dc;
184 
185 	dc = GetDC(NULL);
186 	lf.lfHeight = -MulDiv(faPtr->pointsize,
187 	    GetDeviceCaps(dc, LOGPIXELSY), 72);
188 	ReleaseDC(NULL, dc);
189     }
190     lf.lfWidth = 0;
191     lf.lfEscapement = lf.lfOrientation = ROUND(theta * 10.0);
192 #define TK_FW_NORMAL	0
193     lf.lfWeight = (faPtr->weight == TK_FW_NORMAL) ? FW_NORMAL : FW_BOLD;
194     lf.lfItalic = faPtr->slant;
195     lf.lfUnderline = faPtr->underline;
196     lf.lfStrikeOut = faPtr->overstrike;
197     lf.lfCharSet = DEFAULT_CHARSET;
198     lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
199     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
200     lf.lfQuality = DEFAULT_QUALITY;
201     lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
202 
203     hFont = NULL;
204     if (faPtr->family == NULL) {
205 	lf.lfFaceName[0] = '\0';
206     } else {
207 #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0))
208 	Tcl_DString dString;
209 
210 	Tcl_UtfToExternalDString(systemEncoding, faPtr->family, -1, &dString);
211 
212 	if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) {
213 	    Tcl_UniChar *src, *dst;
214 
215 	    /*
216 	     * We can only store up to LF_FACESIZE wide characters
217 	     */
218 	    if (Tcl_DStringLength(&dString) >= (LF_FACESIZE * sizeof(WCHAR))) {
219 		Tcl_DStringSetLength(&dString, LF_FACESIZE);
220 	    }
221 	    src = (Tcl_UniChar *)Tcl_DStringValue(&dString);
222 	    dst = (Tcl_UniChar *)lf.lfFaceName;
223 	    while (*src != '\0') {
224 		*dst++ = *src++;
225 	    }
226 	    *dst = '\0';
227 	    hFont = CreateFontIndirectW((LOGFONTW *)&lf);
228 	} else {
229 	    /*
230 	     * We can only store up to LF_FACESIZE characters
231 	     */
232 	    if (Tcl_DStringLength(&dString) >= LF_FACESIZE) {
233 		Tcl_DStringSetLength(&dString, LF_FACESIZE);
234 	    }
235 	    strcpy((char *)lf.lfFaceName, Tcl_DStringValue(&dString));
236 	    hFont = CreateFontIndirectA((LOGFONTA *)&lf);
237 	}
238 	Tcl_DStringFree(&dString);
239 #else
240 	strncpy((char *)lf.lfFaceName, faPtr->family, LF_FACESIZE - 1);
241 	lf.lfFaceName[LF_FACESIZE] = '\0';
242 #endif /* TCL_VERSION_NUMBER >= 8.1.0 */
243     }
244 
245     if (hFont == NULL) {
246 #if WINDEBUG
247 	PurifyPrintf("can't create font: %s\n", Blt_LastError());
248 #endif
249     } else {
250 	HFONT oldFont;
251 	TEXTMETRIC tm;
252 	HDC hRefDC;
253 	int result;
254 
255 	/* Check if the rotated font is really a TrueType font. */
256 
257 	hRefDC = GetDC(NULL);		/* Get the desktop device context */
258 	oldFont = SelectFont(hRefDC, hFont);
259 	result = ((GetTextMetrics(hRefDC, &tm)) &&
260 		  (tm.tmPitchAndFamily & TMPF_TRUETYPE));
261 	SelectFont(hRefDC, oldFont);
262 	ReleaseDC(NULL, hRefDC);
263 	if (!result) {
264 #if WINDEBUG
265 	    PurifyPrintf("not a true type font\n");
266 #endif
267 	    DeleteFont(hFont);
268 	    return NULL;
269 	}
270     }
271     return hFont;
272 }
273 
274 /*
275  *----------------------------------------------------------------------
276  *
277  * Blt_GetBitmapData --
278  *
279  *	Returns the DIB bits from a bitmap.
280  *
281  * Results:
282  *	Returns a byte array of bitmap data or NULL if an error
283  *	occurred.  The parameter pitchPtr returns the number
284  *	of bytes per row.
285  *
286  *----------------------------------------------------------------------
287  */
288 unsigned char *
Blt_GetBitmapData(Display * display,Pixmap bitmap,int width,int height,int * pitchPtr)289 Blt_GetBitmapData(
290     Display *display,		/* Display of bitmap */
291     Pixmap bitmap,		/* Bitmap to query */
292     int width,			/* Width of bitmap */
293     int height,			/* Height of bitmap */
294     int *pitchPtr)		/* (out) Number of bytes per row */
295 {
296     TkWinDCState state;
297     HDC dc;
298     int result;
299     unsigned char *bits;
300     unsigned int size;
301     HBITMAP hBitmap;
302     BITMAPINFOHEADER *bmiPtr;
303     HANDLE hMem, hMem2;
304     int bytesPerRow, imageSize;
305 
306     size = sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD);
307     hMem = GlobalAlloc(GHND, size);
308     bmiPtr = (BITMAPINFOHEADER *)GlobalLock(hMem);
309     bmiPtr->biSize = sizeof(BITMAPINFOHEADER);
310     bmiPtr->biPlanes = 1;
311     bmiPtr->biBitCount = 1;
312     bmiPtr->biCompression = BI_RGB;
313     bmiPtr->biWidth = width;
314     bmiPtr->biHeight = height;
315 
316     hBitmap = ((TkWinDrawable *)bitmap)->bitmap.handle;
317     dc = TkWinGetDrawableDC(display, bitmap, &state);
318     result = GetDIBits(dc, hBitmap, 0, height, (LPVOID)NULL,
319 	(BITMAPINFO *)bmiPtr, DIB_RGB_COLORS);
320     TkWinReleaseDrawableDC(bitmap, dc, &state);
321     if (!result) {
322 	GlobalUnlock(hMem);
323 	GlobalFree(hMem);
324 	return NULL;
325     }
326     imageSize = bmiPtr->biSizeImage;
327     GlobalUnlock(hMem);
328     bytesPerRow = ((width + 31) & ~31) / 8;
329     if (imageSize == 0) {
330          imageSize = bytesPerRow * height;
331     }
332     hMem2 = GlobalReAlloc(hMem, size + imageSize, 0);
333     if (hMem2 == NULL) {
334 	GlobalFree(hMem);
335         return NULL;
336     }
337     hMem = hMem2;
338     bmiPtr = (LPBITMAPINFOHEADER)GlobalLock(hMem);
339     dc = TkWinGetDrawableDC(display, bitmap, &state);
340     result = GetDIBits(dc, hBitmap, 0, height, (unsigned char *)bmiPtr + size,
341         (BITMAPINFO *)bmiPtr, DIB_RGB_COLORS);
342     TkWinReleaseDrawableDC(bitmap, dc, &state);
343     bits = NULL;
344     if (!result) {
345 	OutputDebugString("GetDIBits failed\n");
346     } else {
347 	bits = Blt_Malloc(imageSize);
348 	if (bits != NULL) {
349 	    memcpy (bits, (unsigned char *)bmiPtr + size, imageSize);
350 	}
351     }
352     *pitchPtr = bytesPerRow;
353     GlobalUnlock(hMem);
354     GlobalFree(hMem);
355     return bits;
356 }
357 
358 /*
359  *----------------------------------------------------------------------
360  *
361  * XFree --
362  *
363  *----------------------------------------------------------------------
364  */
365 void
Blt_EmulateXFree(void * ptr)366 Blt_EmulateXFree(void *ptr)
367 {
368     Blt_Free(ptr);
369 }
370 
371 /*
372  *----------------------------------------------------------------------
373  *
374  * XMaxRequestSize --
375  *
376  *----------------------------------------------------------------------
377  */
378 long
Blt_EmulateXMaxRequestSize(Display * display)379 Blt_EmulateXMaxRequestSize(Display *display)
380 {
381     return (SHRT_MAX / 4);
382 }
383 
384 /*
385  *----------------------------------------------------------------------
386  *
387  * XLowerWindow --
388  *
389  *----------------------------------------------------------------------
390  */
391 void
Blt_EmulateXLowerWindow(Display * display,Window window)392 Blt_EmulateXLowerWindow(
393     Display *display,
394     Window window)
395 {
396     HWND hWnd;
397 
398     hWnd = Tk_GetHWND(window);
399     display->request++;
400     SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
401 }
402 
403 /*
404  *----------------------------------------------------------------------
405  *
406  * XRaiseWindow --
407  *
408  *----------------------------------------------------------------------
409  */
410 void
Blt_EmulateXRaiseWindow(Display * display,Window window)411 Blt_EmulateXRaiseWindow(
412     Display *display,
413     Window window)
414 {
415     HWND hWnd;
416 
417     hWnd = Tk_GetHWND(window);
418     display->request++;
419     SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
420 }
421 
422 /*
423  *----------------------------------------------------------------------
424  *
425  * XUnmapWindow --
426  *
427  *----------------------------------------------------------------------
428  */
429 void
Blt_EmulateXUnmapWindow(Display * display,Window window)430 Blt_EmulateXUnmapWindow(
431     Display *display,
432     Window window)
433 {
434     HWND hWnd;
435 
436     hWnd = Tk_GetHWND(window);
437     display->request++;
438     ShowWindow(hWnd, SW_HIDE);
439     /* SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); */
440 }
441 
442 /*
443  *----------------------------------------------------------------------
444  *
445  * XWarpPointer --
446  *
447  *	If destWindow is None, moves the pointer by the offsets (destX,
448  *	destY) relative to the current position of the pointer.
449  *	If destWindow is a window, moves the pointer to the offsets
450  *	(destX, destY) relative to the origin of destWindow.  However,
451  *	if srcWindow is a window, the move only takes place if the window
452  *	srcWindow contains the pointer and if the specified rectangle of
453  *	srcWindow contains the pointer.
454  *
455  *	The srcX and srcY coordinates are relative to the origin of
456  *	srcWindow.  If srcHeight is zero, it is replaced with the current
457  *	height of srcWindow minus srcY.  If srcWidth is zero, it is
458  *	replaced with the current width of srcWindow minus srcX.
459  *
460  *----------------------------------------------------------------------
461  */
462 void
Blt_EmulateXWarpPointer(Display * display,Window srcWindow,Window destWindow,int srcX,int srcY,unsigned int srcWidth,unsigned int srcHeight,int destX,int destY)463 Blt_EmulateXWarpPointer(
464     Display *display,
465     Window srcWindow,
466     Window destWindow,
467     int srcX,
468     int srcY,
469     unsigned int srcWidth,
470     unsigned int srcHeight,
471     int destX,
472     int destY)
473 {
474     HWND hWnd;
475     POINT point;
476 
477     hWnd = Tk_GetHWND(destWindow);
478     point.x = destX, point.y = destY;
479     if (ClientToScreen(hWnd, &point)) {
480 	SetCursorPos(point.x, point.y);
481     }
482 }
483 
484 #ifdef notdef
485 static Blt_HashTable gcTable;
486 static int gcInitialized = FALSE;
487 #endif
488 
489 typedef struct {
490     HDC dc;
491     int count;
492     COLORREF color;
493     int offset, nBits;
494 } DashInfo;
495 
496 void
Blt_SetDashes(Display * display,GC gc,Blt_Dashes * dashesPtr)497 Blt_SetDashes(Display *display, GC gc, Blt_Dashes *dashesPtr)
498 {
499     XGCValuesEx *gcPtr = (XGCValuesEx *)gc;
500 
501     /* This must be used only with a privately created GC */
502     assert((int)gcPtr->dashes == -1);
503     gcPtr->nDashValues = strlen(dashesPtr->values);
504     gcPtr->dash_offset = dashesPtr->offset;
505     strcpy(gcPtr->dashValues, dashesPtr->values);
506 }
507 
508 static int
GetDashInfo(HDC dc,GC gc,DashInfo * infoPtr)509 GetDashInfo(
510     HDC dc,
511     GC gc,
512     DashInfo *infoPtr)
513 {
514     int dashOffset, dashValue;
515 
516     dashValue = 0;
517     dashOffset = gc->dash_offset;
518     if ((int)gc->dashes == -1) {
519 	XGCValuesEx *gcPtr = (XGCValuesEx *)gc;
520 
521 	if (gcPtr->nDashValues == 1) {
522 	    dashValue = gcPtr->dashValues[0];
523 	}
524     } else if (gc->dashes > 0) {
525 	dashValue = (int)gc->dashes;
526     }
527     if (dashValue == 0) {
528 	return FALSE;
529     }
530     infoPtr->dc = dc;
531     infoPtr->nBits = dashValue;
532     infoPtr->offset = dashOffset;
533     infoPtr->count = 0;
534     infoPtr->color = gc->foreground;
535     return TRUE;
536 }
537 
538 void
Blt_SetROP2(HDC dc,int function)539 Blt_SetROP2(HDC dc, int function)
540 {
541     SetROP2(dc, tkpWinRopModes[function]);
542 }
543 
544 static XGCValuesEx *
CreateGC()545 CreateGC()
546 {
547     XGCValuesEx *gcPtr;
548 
549     gcPtr = Blt_Malloc(sizeof(XGCValuesEx));
550     if (gcPtr == NULL) {
551 	return NULL;
552     }
553     gcPtr->arc_mode = ArcPieSlice;
554     gcPtr->background = 0xffffff;
555     gcPtr->cap_style = CapNotLast;
556     gcPtr->clip_mask = None;
557     gcPtr->clip_x_origin = gcPtr->clip_y_origin = 0;
558     gcPtr->dash_offset	= 0;
559     gcPtr->fill_rule = WindingRule;
560     gcPtr->fill_style = FillSolid;
561     gcPtr->font = None;
562     gcPtr->foreground = 0;
563     gcPtr->function = GXcopy;
564     gcPtr->graphics_exposures = True;
565     gcPtr->join_style = JoinMiter;
566     gcPtr->line_style = LineSolid;
567     gcPtr->line_width = 0;
568     gcPtr->plane_mask = ~0;
569     gcPtr->stipple = None;
570     gcPtr->subwindow_mode = ClipByChildren;
571     gcPtr->tile = None;
572     gcPtr->ts_x_origin = gcPtr->ts_y_origin = 0;
573 
574     gcPtr->dashes = -1;    /* Mark that this an extended GC */
575     gcPtr->nDashValues	= 0;
576 
577     return gcPtr;
578 }
579 
580 /*
581  *----------------------------------------------------------------------
582  *
583  * Blt_EmulateXCreateGC --
584  *
585  *	Allocate a new extended GC, and initialize the specified fields.
586  *
587  * Results:
588  *	Returns a newly allocated GC.
589  *
590  * Side effects:
591  *	None.
592  *
593  *----------------------------------------------------------------------
594  */
595 GC
Blt_EmulateXCreateGC(Display * display,Drawable drawable,unsigned long mask,XGCValues * srcPtr)596 Blt_EmulateXCreateGC(
597     Display *display,
598     Drawable drawable,
599     unsigned long mask,
600     XGCValues *srcPtr)
601 {
602     XGCValuesEx *destPtr;
603 
604     destPtr = CreateGC();
605     if (destPtr == NULL) {
606 	return None;
607     }
608     if (mask & GCFunction) {
609         destPtr->function = srcPtr->function;
610     }
611     if (mask & GCPlaneMask) {
612 	destPtr->plane_mask = srcPtr->plane_mask;
613     }
614     if (mask & GCForeground) {
615 	destPtr->foreground = srcPtr->foreground;
616     }
617     if (mask & GCBackground) {
618         destPtr->background = srcPtr->background;
619     }
620     if (mask & GCLineWidth) {
621 	destPtr->line_width = srcPtr->line_width;
622     }
623     if (mask & GCLineStyle) {
624 	destPtr->line_style = srcPtr->line_style;
625     }
626     if (mask & GCCapStyle) {
627 	destPtr->cap_style = srcPtr->cap_style;
628     }
629     if (mask & GCJoinStyle) {
630 	destPtr->join_style = srcPtr->join_style;
631     }
632     if (mask & GCFillStyle) {
633 	destPtr->fill_style = srcPtr->fill_style;
634     }
635     if (mask & GCFillRule) {
636         destPtr->fill_rule = srcPtr->fill_rule;
637     }
638     if (mask & GCArcMode) {
639         destPtr->arc_mode = srcPtr->arc_mode;
640     }
641     if (mask & GCTile) {
642 	destPtr->tile = srcPtr->tile;
643     }
644     if (mask & GCStipple) {
645         destPtr->stipple = srcPtr->stipple;
646     }
647     if (mask & GCTileStipXOrigin) {
648 	destPtr->ts_x_origin = srcPtr->ts_x_origin;
649     }
650     if (mask & GCTileStipXOrigin) {
651 	destPtr->ts_y_origin = srcPtr->ts_y_origin;
652     }
653     if (mask & GCFont) {
654         destPtr->font = srcPtr->font;
655     }
656     if (mask & GCSubwindowMode) {
657 	destPtr->subwindow_mode = srcPtr->subwindow_mode;
658     }
659     if (mask & GCGraphicsExposures) {
660 	destPtr->graphics_exposures = srcPtr->graphics_exposures;
661     }
662     if (mask & GCClipXOrigin) {
663 	destPtr->clip_x_origin = srcPtr->clip_x_origin;
664     }
665     if (mask & GCClipYOrigin) {
666 	destPtr->clip_y_origin = srcPtr->clip_y_origin;
667     }
668     if (mask & GCDashOffset) {
669 	destPtr->dash_offset = srcPtr->dash_offset;
670     }
671     if (mask & GCDashList) {
672         destPtr->dashes = srcPtr->dashes;
673     }
674     if (mask & GCClipMask) {
675 	struct ClipMask {
676 	    int type;		/* TKP_CLIP_PIXMAP or TKP_CLIP_REGION */
677 	    Pixmap pixmap;
678 	} *clipPtr;
679 
680 	clipPtr = Blt_Malloc(sizeof(struct ClipMask));
681 #define TKP_CLIP_PIXMAP 0
682 	clipPtr->type = TKP_CLIP_PIXMAP;
683 	clipPtr->pixmap = srcPtr->clip_mask;
684 	destPtr->clip_mask = (Pixmap) clipPtr;
685     }
686     return (GC)destPtr;
687 }
688 
689 /*
690  *----------------------------------------------------------------------
691  *
692  * Blt_GCToPen --
693  *
694  *	Set up the graphics port from the given GC.
695  *
696  *	Geometric and cosmetic pens available under both 95 and NT.
697  *	Geometric pens differ from cosmetic pens in that they can
698  *	  1. Draw in world units (can have thick lines: line width > 1).
699  *	  2. Under NT, allow arbitrary line style.
700  *	  3. Can have caps and join (needed for thick lines).
701  *	  4. Draw very, very slowly.
702  *
703  *	Cosmetic pens are single line width only.
704  *
705  * 			 95	 98	 NT
706  *	  PS_SOLID	c,g	c,g	c,g
707  *	  PS_DASH		c,g	c,g	c,g
708  *	  PS_DOT		  c	  c	c,g
709  *	  PS_DASHDOT	  c	  - 	c,g
710  *	  PS_DASHDOTDOT	  c	  -	c,g
711  *	  PS_USERSTYLE	  -       -	c,g
712  *	  PS_ALTERNATE	  -	  - 	  c
713  *
714  *	Geometric only for 95/98
715  *
716  *	  PS_ENDCAP_ROUND
717  *	  PS_ENDCAP_SQUARE
718  *	  PS_ENDCAP_FLAT
719  *	  PS_JOIN_BEVEL
720  *	  PS_JOIN_ROUND
721  *	  PS_JOIN_MITER
722  *
723  * Results:
724  *	None.
725  *
726  * Side effects:
727  *	The current port is adjusted.
728  *
729  *----------------------------------------------------------------------
730  */
731 HPEN
Blt_GCToPen(HDC dc,GC gc)732 Blt_GCToPen(HDC dc, GC gc)
733 {
734     DWORD lineAttrs, lineStyle;
735     DWORD dashArr[12];
736     DWORD *dashPtr;
737     int nValues, lineWidth;
738     LOGBRUSH lBrush;
739     HPEN pen;
740 
741     nValues = 0;
742     lineWidth = (gc->line_width < 1) ? 1 : gc->line_width;
743     if ((gc->line_style == LineOnOffDash) ||
744 	(gc->line_style == LineDoubleDash)) {
745 	XGCValuesEx *gcPtr = (XGCValuesEx *)gc;
746 
747 	if ((int)gc->dashes == -1) {
748 	    register int i;
749 
750 	    nValues = strlen(gcPtr->dashValues);
751 	    for (i = 0; i < nValues; i++) {
752 		dashArr[i] = (DWORD)gcPtr->dashValues[i];
753 	    }
754 	    if (nValues == 1) {
755 		dashArr[1] = dashArr[0];
756 		nValues = 2;
757 	    }
758 	} else {
759 	    dashArr[1] = dashArr[0] = (DWORD) gc->dashes;
760 	    nValues = 2;
761 	    gc->dashes = -1;
762 	}
763     }
764 
765     switch (nValues) {
766     case 0:
767 	lineStyle = PS_SOLID;
768 	break;
769     case 3:
770 	lineStyle = PS_DASHDOT;
771 	break;
772     case 4:
773 	lineStyle = PS_DASHDOTDOT;
774 	break;
775     case 2:
776     default:
777 	/* PS_DASH style dash length is too long. */
778 	lineStyle = PS_DOT;
779 	break;
780     }
781 
782     lBrush.lbStyle = BS_SOLID;
783     lBrush.lbColor = gc->foreground;
784     lBrush.lbHatch = 0;		/* Value is ignored when style is BS_SOLID. */
785 
786     lineAttrs = 0;
787     switch (gc->cap_style) {
788     case CapNotLast:
789     case CapButt:
790 	lineAttrs |= PS_ENDCAP_FLAT;
791 	break;
792     case CapRound:
793 	lineAttrs |= PS_ENDCAP_ROUND;
794 	break;
795     default:
796 	lineAttrs |= PS_ENDCAP_SQUARE;
797 	break;
798     }
799     switch (gc->join_style) {
800     case JoinMiter:
801 	lineAttrs |= PS_JOIN_MITER;
802 	break;
803     case JoinBevel:
804 	lineAttrs |= PS_JOIN_BEVEL;
805 	break;
806     case JoinRound:
807     default:
808 	lineAttrs |= PS_JOIN_ROUND;
809 	break;
810     }
811     SetBkMode(dc, TRANSPARENT);
812 
813     if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) {
814 	/* Windows NT/2000/XP. */
815 	if (nValues > 0) {
816 	    lineStyle = PS_USERSTYLE;
817 	    dashPtr = dashArr;
818 	} else {
819 	    dashPtr = NULL;
820 	}
821 	if (lineWidth > 1) {
822 	    /* Limit the use of geometric pens to thick lines. */
823 	    pen = ExtCreatePen(PS_GEOMETRIC | lineAttrs | lineStyle, lineWidth,
824 		       &lBrush, nValues, dashPtr);
825 	} else {
826 	    /* Cosmetic pens are much faster. */
827 	    pen = ExtCreatePen(PS_COSMETIC | lineAttrs | lineStyle, 1, &lBrush,
828 		       nValues, dashPtr);
829 	}
830     } else {
831 	/* Windows 95/98. */
832 	if ((lineStyle == PS_SOLID) && (lineWidth > 1)) {
833 	    /* Use geometric pens with solid, thick lines only. */
834 	    pen = ExtCreatePen(PS_GEOMETRIC | lineAttrs | lineStyle, lineWidth,
835 		       &lBrush, 0, NULL);
836 	} else {
837 	    /* Otherwise sacrifice thick lines for dashes. */
838 	    pen = ExtCreatePen(PS_COSMETIC | lineStyle, 1, &lBrush, 0, NULL);
839 	}
840     }
841     assert(pen != NULL);
842     return pen;
843 }
844 
845 /*
846  *----------------------------------------------------------------------
847  *
848  * XDrawRectangles --
849  *
850  *       Draws the outlines of the specified rectangles as if a
851  *       five-point PolyLine protocol request were specified for each
852  *       rectangle:
853  *
854  *             [x,y] [x+width,y] [x+width,y+height] [x,y+height]
855  *             [x,y]
856  *
857  *      For the specified rectangles, these functions do not draw a
858  *      pixel more than once.  XDrawRectangles draws the rectangles in
859  *      the order listed in the array.  If rectangles intersect, the
860  *      intersecting pixels are drawn multiple times.  Draws a
861  *      rectangle.
862  *
863  * Results:
864  *	None.
865  *
866  * Side effects:
867  *	Draws rectangles on the specified drawable.
868  *
869  *----------------------------------------------------------------------
870  */
871 void
Blt_EmulateXDrawRectangles(Display * display,Drawable drawable,GC gc,XRectangle * rectArr,int nRects)872 Blt_EmulateXDrawRectangles(
873     Display *display,
874     Drawable drawable,
875     GC gc,
876     XRectangle *rectArr,
877     int nRects)
878 {
879     HPEN pen, oldPen;
880     TkWinDCState state;
881     HBRUSH brush, oldBrush;
882     HDC dc;
883     register XRectangle *rectPtr;
884     register int i;
885 
886     if (drawable == None) {
887 	return;
888     }
889     dc = TkWinGetDrawableDC(display, drawable, &state);
890     pen = Blt_GCToPen(dc, gc);
891     brush = GetStockObject(NULL_BRUSH);
892     oldPen = SelectPen(dc, pen);
893     oldBrush = SelectBrush(dc, brush);
894     SetROP2(dc, tkpWinRopModes[gc->function]);
895     rectPtr = rectArr;
896     for (i = 0; i < nRects; i++, rectPtr++) {
897 	Rectangle(dc, (int)rectPtr->x, (int)rectPtr->y,
898 	    (int)(rectPtr->x + rectPtr->width + 1),
899 	    (int)(rectPtr->y + rectPtr->height + 1));
900     }
901     DeletePen(SelectPen(dc, oldPen));
902     DeleteBrush(SelectBrush(dc, oldBrush));
903     TkWinReleaseDrawableDC(drawable, dc, &state);
904 }
905 
906 #ifdef notdef
907 /*
908  * Implements the "pixeling" of small arcs, because GDI-performance
909  * for this is awful
910  * was made especially for BLT, graph4 demo now runs 4x faster
911  *
912  */
913 /* O-outer , I-inner, B-both */
914 #define NEITHER_ 0
915 #define OUTLINE 1
916 #define FILL 2
917 #define BOTH (OUTLINE|FILL)
918 #define MINIARCS 5
919 static int arcus0[1] =
920 {
921     BOTH
922 };
923 static int arcus1[4] =
924 {
925     BOTH, BOTH,
926     BOTH, BOTH
927 };
928 
929 static int arcus2[9] =
930 {
931     NEITHER, OUTLINE, NEITHER,
932     OUTLINE, FILL, OUTLINE,
933     NEITHER, OUTLINE, NEITHER
934 };
935 
936 static int arcus3[16] =
937 {
938     NEITHER, OUTLINE, OUTLINE, NEITHER,
939     OUTLINE, FILL, FILL, OUTLINE,
940     OUTLINE, FILL, FILL, OUTLINE,
941     NEITHER, OUTLINE, OUTLINE, NEITHER
942 };
943 
944 static int arcus4[25] =
945 {
946     NEITHER, OUTLINE, OUTLINE, OUTLINE, NEITHER,
947     OUTLINE, FILL, FILL, FILL, OUTLINE,
948     OUTLINE, FILL, FILL, FILL, OUTLINE,
949     OUTLINE, FILL, FILL, FILL, OUTLINE,
950     NEITHER, OUTLINE, OUTLINE, OUTLINE, NEITHER
951 };
952 
953 static int *arcis[MINIARCS] =
954 {
955     arcus0, arcus1, arcus2, arcus3, arcus4
956 };
957 
958 static void
DrawMiniArc(HDC dc,int width,int x,int y,int mask,COLORREF inner,COLORREF outer)959 DrawMiniArc(
960     HDC dc,
961     int width,
962     int x,
963     int y,
964     int mask,
965     COLORREF inner,
966     COLORREF outer)
967 {
968     int *arc;
969     int i, j;
970 
971     if (width > MINIARCS) {
972 	return;
973     }
974     arc = arcis[width];
975     for (i = 0; i <= width; i++) {
976 	for (j = 0; j <= width; j++) {
977 	    bit = (mask & *arc);
978 	    if (bit & OUTLINE) {
979 		SetPixelV(dc, x + i, y + j, outer);
980 	    } else if (bit & FILL) {
981 		SetPixelV(dc, x + i, y + j, inner);
982 	    }
983 	    arc++;
984 	}
985     }
986 }
987 
988 #endif
989 
990 /*
991  *----------------------------------------------------------------------
992  *
993  * DrawArc --
994  *
995  *	This procedure handles the rendering of drawn or filled
996  *	arcs and chords.
997  *
998  * Results:
999  *	None.
1000  *
1001  * Side effects:
1002  *	Renders the requested arcs.
1003  *
1004  *----------------------------------------------------------------------
1005  */
1006 static void
DrawArc(HDC dc,int arcMode,XArc * arcPtr,HPEN pen,HBRUSH brush)1007 DrawArc(
1008     HDC dc,
1009     int arcMode,		/* Mode: either ArcChord or ArcPieSlice */
1010     XArc *arcPtr,
1011     HPEN pen,
1012     HBRUSH brush)
1013 {
1014     int start, extent, clockwise;
1015     int xstart, ystart, xend, yend;
1016     double radian_start, radian_end, xr, yr;
1017     double dx, dy;
1018 
1019     if ((arcPtr->angle1 == 0) && (arcPtr->angle2 == 23040)) {
1020 	/* Handle special case of circle or ellipse */
1021 	Ellipse(dc, arcPtr->x, arcPtr->y, arcPtr->x + arcPtr->width + 1,
1022 	    arcPtr->y + arcPtr->height + 1);
1023 	return;
1024     }
1025     start = arcPtr->angle1, extent = arcPtr->angle2;
1026     clockwise = (extent < 0);	/* Non-zero if clockwise */
1027 
1028     /*
1029      * Compute the absolute starting and ending angles in normalized radians.
1030      * Swap the start and end if drawing clockwise.
1031      */
1032     start = start % (64 * 360);
1033     if (start < 0) {
1034 	start += (64 * 360);
1035     }
1036     extent = (start + extent) % (64 * 360);
1037     if (extent < 0) {
1038 	extent += (64 * 360);
1039     }
1040     if (clockwise) {
1041 	int tmp = start;
1042 	start = extent;
1043 	extent = tmp;
1044     }
1045 #define XAngleToRadians(a) ((double)(a) / 64 * M_PI / 180);
1046     radian_start = XAngleToRadians(start);
1047     radian_end = XAngleToRadians(extent);
1048 
1049     /*
1050      * Now compute points on the radial lines that define the starting and
1051      * ending angles.  Be sure to take into account that the y-coordinate
1052      * system is inverted.
1053      */
1054     dx = arcPtr->width * 0.5;
1055     dy = arcPtr->height * 0.5;
1056 
1057     xr = arcPtr->x + dx;
1058     yr = arcPtr->y + dy;
1059     xstart = (int)((xr + cos(radian_start) * dx) + 0.5);
1060     ystart = (int)((yr + sin(-radian_start) * dy) + 0.5);
1061     xend = (int)((xr + cos(radian_end) * dx) + 0.5);
1062     yend = (int)((yr + sin(-radian_end) * dy) + 0.5);
1063 
1064     /*
1065      * Now draw a filled or open figure.  Note that we have to
1066      * increase the size of the bounding box by one to account for the
1067      * difference in pixel definitions between X and Windows.
1068      */
1069 
1070     if (brush == 0) {
1071 	/*
1072 	 * Note that this call will leave a gap of one pixel at the
1073 	 * end of the arc for thin arcs.  We can't use ArcTo because
1074 	 * it's only supported under Windows NT.
1075 	 */
1076 	Arc(dc, arcPtr->x, arcPtr->y, arcPtr->x + arcPtr->width + 1,
1077 	    arcPtr->y + arcPtr->height + 1, xstart, ystart, xend, yend);
1078 	/* FIXME: */
1079     } else {
1080 	if (arcMode == ArcChord) {
1081 	    Chord(dc, arcPtr->x, arcPtr->y, arcPtr->x + arcPtr->width + 1,
1082 		arcPtr->y + arcPtr->height + 1, xstart, ystart, xend, yend);
1083 	} else if (arcMode == ArcPieSlice) {
1084 	    Pie(dc, arcPtr->x, arcPtr->y, arcPtr->x + arcPtr->width + 1,
1085 		arcPtr->y + arcPtr->height + 1, xstart, ystart, xend, yend);
1086 	}
1087     }
1088 }
1089 
1090 /*
1091  *----------------------------------------------------------------------
1092  *
1093  * XDrawArcs --
1094  *
1095  *	Draws multiple circular or elliptical arcs.  Each arc is
1096  *	specified by a rectangle and two angles.  The center of the
1097  *	circle or ellipse is the center of the rect- angle, and the
1098  *	major and minor axes are specified by the width and height.
1099  *	Positive angles indicate counterclock- wise motion, and
1100  *	negative angles indicate clockwise motion.  If the magnitude
1101  *	of angle2 is greater than 360 degrees, XDrawArcs truncates it
1102  *	to 360 degrees.
1103  *
1104  * Results:
1105  *	None.
1106  *
1107  * Side effects:
1108  *	Draws an arc for each array element on the specified drawable.
1109  *
1110  *----------------------------------------------------------------------
1111  */
1112 void
Blt_EmulateXDrawArcs(Display * display,Drawable drawable,GC gc,XArc * arcArr,int nArcs)1113 Blt_EmulateXDrawArcs(
1114     Display *display,
1115     Drawable drawable,
1116     GC gc,
1117     XArc *arcArr,
1118     int nArcs)
1119 {
1120     HPEN pen, oldPen;
1121     HBRUSH brush, oldBrush;
1122     HDC dc;
1123     TkWinDCState state;
1124     register XArc *arcPtr, *endPtr;
1125 
1126     display->request++;
1127     if (drawable == None) {
1128 	return;
1129     }
1130     dc = TkWinGetDrawableDC(display, drawable, &state);
1131     SetROP2(dc, tkpWinRopModes[gc->function]);
1132     pen = Blt_GCToPen(dc, gc);
1133     oldPen = SelectPen(dc, pen);
1134     brush = GetStockBrush(NULL_BRUSH);
1135     oldBrush = SelectBrush(dc, brush);
1136     endPtr = arcArr + nArcs;
1137     for (arcPtr = arcArr; arcPtr < endPtr; arcPtr++) {
1138 	DrawArc(dc, gc->arc_mode, arcPtr, pen, 0);
1139     }
1140     DeleteBrush(SelectBrush(dc, oldBrush));
1141     DeletePen(SelectPen(dc, oldPen));
1142     TkWinReleaseDrawableDC(drawable, dc, &state);
1143 }
1144 
1145 /*
1146  *----------------------------------------------------------------------
1147  *
1148  * XFillArcs --
1149  *
1150  *	Draw a filled arc.
1151  *
1152  * Results:
1153  *	None.
1154  *
1155  * Side effects:
1156  *	Draws a filled arc for each array element on the specified drawable.
1157  *
1158  *----------------------------------------------------------------------
1159  */
1160 void
Blt_EmulateXFillArcs(Display * display,Drawable drawable,GC gc,XArc * arcArr,int nArcs)1161 Blt_EmulateXFillArcs(
1162     Display *display,
1163     Drawable drawable,
1164     GC gc,
1165     XArc *arcArr,
1166     int nArcs)
1167 {
1168     HBRUSH brush, oldBrush;
1169     HPEN pen, oldPen;
1170     HDC dc;
1171     register XArc *arcPtr, *endPtr;
1172     TkWinDCState state;
1173 
1174     display->request++;
1175     if (drawable == None) {
1176 	return;
1177     }
1178     dc = TkWinGetDrawableDC(display, drawable, &state);
1179     SetROP2(dc, tkpWinRopModes[gc->function]);
1180     pen = Blt_GCToPen(dc, gc);
1181     oldPen = SelectPen(dc, pen);
1182     brush = CreateSolidBrush(gc->foreground);
1183     oldBrush = SelectBrush(dc, brush);
1184     endPtr = arcArr + nArcs;
1185     for (arcPtr = arcArr; arcPtr < endPtr; arcPtr++) {
1186 	DrawArc(dc, gc->arc_mode, arcPtr, pen, brush);
1187     }
1188     DeleteBrush(SelectBrush(dc, oldBrush));
1189     DeletePen(SelectPen(dc, oldPen));
1190     TkWinReleaseDrawableDC(drawable, dc, &state);
1191 }
1192 
1193 /*
1194  *----------------------------------------------------------------------
1195  *
1196  * XDrawLines --
1197  *
1198  *	Draw connected lines.
1199  *
1200  * Results:
1201  *	None.
1202  *
1203  * Side effects:
1204  *	Renders a series of connected lines.
1205  *
1206  *----------------------------------------------------------------------
1207  */
1208 
1209 static void CALLBACK
DrawDot(int x,int y,LPARAM clientData)1210 DrawDot(
1211     int x, int y,		/* Coordinates of point */
1212     LPARAM clientData)
1213 {				/* Line information */
1214     DashInfo *infoPtr = (DashInfo *) clientData;
1215     int count;
1216 
1217     infoPtr->count++;
1218     count = (infoPtr->count + infoPtr->offset) / infoPtr->nBits;
1219     if (count & 0x1) {
1220 	SetPixelV(infoPtr->dc, x, y, infoPtr->color);
1221     }
1222 }
1223 
1224 
1225 void
Blt_EmulateXDrawLine(Display * display,Drawable drawable,GC gc,int x1,int y1,int x2,int y2)1226 Blt_EmulateXDrawLine(
1227     Display *display,
1228     Drawable drawable,
1229     GC gc,
1230     int x1, int y1,
1231     int x2, int y2)
1232 {
1233     TkWinDCState state;
1234     HDC dc;
1235 
1236     if (drawable == None) {
1237 	return;
1238     }
1239     dc = TkWinGetDrawableDC(display, drawable, &state);
1240     SetROP2(dc, tkpWinRopModes[gc->function]);
1241     if (gc->line_style != LineSolid) {
1242 	/* Handle dotted lines specially */
1243 	DashInfo info;
1244 
1245 	if (!GetDashInfo(dc, gc, &info)) {
1246 	    goto solidLine;
1247 	}
1248 	LineDDA(x1, y1, x2, y2, DrawDot, (LPARAM)&info);
1249     } else {
1250 	HPEN pen, oldPen;
1251 	HBRUSH brush, oldBrush;
1252 
1253       solidLine:
1254 	pen = Blt_GCToPen(dc, gc);
1255 	oldPen = SelectPen(dc, pen);
1256 	brush = CreateSolidBrush(gc->foreground);
1257 	oldBrush = SelectBrush(dc, brush);
1258 	MoveToEx(dc, x1, y1, (LPPOINT)NULL);
1259 	LineTo(dc, x2, y2);
1260 	DeletePen(SelectPen(dc, oldPen));
1261 	DeleteBrush(SelectBrush(dc, oldBrush));
1262     }
1263     TkWinReleaseDrawableDC(drawable, dc, &state);
1264 }
1265 
1266 static void
DrawLine(Display * display,Drawable drawable,GC gc,POINT * points,int nPoints)1267 DrawLine(
1268     Display *display,
1269     Drawable drawable,
1270     GC gc,
1271     POINT *points,
1272     int nPoints)
1273 {
1274     TkWinDCState state;
1275     HDC dc;
1276     register int i, n;
1277     int start, extra, size;
1278     HPEN pen, oldPen;
1279     HBRUSH brush, oldBrush;
1280 
1281     if (drawable == None) {
1282 	return;
1283     }
1284     dc = TkWinGetDrawableDC(display, drawable, &state);
1285     pen = Blt_GCToPen(dc, gc);
1286     oldPen = SelectPen(dc, pen);
1287     brush = CreateSolidBrush(gc->foreground);
1288     oldBrush = SelectBrush(dc, brush);
1289     SetROP2(dc, tkpWinRopModes[gc->function]);
1290 
1291     start = extra = 0;
1292     /*
1293      * Depending if the line is wide (> 1 pixel), arbitrarily break
1294      * the line in sections of 100 points.  This bit of weirdness has
1295      * to do with wide geometric pens.  The longer the polyline, the
1296      * slower it draws.  The trade off is that we lose dash and
1297      * cap uniformity for unbearably slow polyline draws.
1298      */
1299     if (gc->line_width > 1) {
1300 	size = 100;
1301     } else {
1302 	size = nPoints;
1303     }
1304     for (i = nPoints; i > 0; i -= size) {
1305 	n = MIN(i, size);
1306 	Polyline(dc, points + start, n + extra);
1307 	start += (n - 1);
1308 	extra = 1;
1309     }
1310     DeletePen(SelectPen(dc, oldPen));
1311     DeleteBrush(SelectBrush(dc, oldBrush));
1312     TkWinReleaseDrawableDC(drawable, dc, &state);
1313 }
1314 
1315 void
Blt_EmulateXDrawLines(Display * display,Drawable drawable,GC gc,XPoint * pointArr,int nPoints,int mode)1316 Blt_EmulateXDrawLines(
1317     Display *display,
1318     Drawable drawable,
1319     GC gc,
1320     XPoint *pointArr,
1321     int nPoints,
1322     int mode)
1323 {
1324     if (drawable == None) {
1325 	return;
1326     }
1327     if (gc->line_style != LineSolid) { /* Handle dotted lines specially */
1328 	DashInfo info;
1329 	TkWinDCState state;
1330 	HDC dc;
1331 	int result;
1332 
1333 	dc = TkWinGetDrawableDC(display, drawable, &state);
1334 	SetROP2(dc, tkpWinRopModes[gc->function]);
1335 	result = GetDashInfo(dc, gc, &info);
1336 	if (result) {
1337 	    register XPoint *p1, *p2;
1338 	    register int i;
1339 
1340 	    p1 = pointArr;
1341 	    p2 = p1 + 1;
1342 	    for (i = 1; i < nPoints; i++, p1++, p2++) {
1343 		LineDDA(p1->x, p1->y, p2->x, p2->y, DrawDot, (LPARAM)&info);
1344 	    }
1345 	    result = TCL_OK;
1346 	}
1347 	TkWinReleaseDrawableDC(drawable, dc, &state);
1348 	if (result) {
1349 	    return;
1350 	}
1351     } else {
1352 	POINT *points, *destPtr;
1353 	XPoint *srcPtr, *endPtr;
1354 
1355 	points = Blt_Malloc(sizeof(POINT) * nPoints);
1356 	if (points == NULL) {
1357 	    return;
1358 	}
1359 	endPtr = pointArr + nPoints;
1360 	if (mode == CoordModeOrigin) {
1361 	    destPtr = points;
1362 	    for (srcPtr = pointArr; srcPtr < endPtr; srcPtr++) {
1363 		destPtr->x = (int)srcPtr->x;
1364 		destPtr->y = (int)srcPtr->y;
1365 		destPtr++;
1366 	    }
1367 	} else {
1368 	    POINT *lastPtr;
1369 
1370 	    srcPtr = pointArr;
1371 	    destPtr = points;
1372 	    destPtr->x = (int)srcPtr->x;
1373 	    destPtr->y = (int)srcPtr->y;
1374 	    lastPtr = destPtr;
1375 	    srcPtr++, destPtr++;
1376 	    for (/*empty*/; srcPtr < endPtr; srcPtr++) {
1377 		destPtr->x = lastPtr->x + (int)srcPtr->x;
1378 		destPtr->y = lastPtr->y + (int)srcPtr->y;
1379 		lastPtr = destPtr;
1380 		destPtr++;
1381 	    }
1382 	}
1383 	DrawLine(display, drawable, gc, points, nPoints);
1384 	Blt_Free(points);
1385     }
1386 }
1387 
1388 
1389 
1390 /*
1391  *----------------------------------------------------------------------
1392  *
1393  * Blt_EmultateXDrawSegments --
1394  *
1395  *	Draws multiple, unconnected lines. For each segment, draws a
1396  *	line between (x1, y1) and (x2, y2).  It draws the lines in the
1397  *	order listed in the array of XSegment structures and does not
1398  *	perform joining at coincident endpoints.  For any given line,
1399  *	does not draw a pixel more than once. If lines intersect, the
1400  *	intersecting pixels are drawn multiple times.
1401  *
1402  * Results:
1403  *	None.
1404  *
1405  * Side effects:
1406  *	Draws unconnected line segments on the specified drawable.
1407  *
1408  *----------------------------------------------------------------------
1409  */
1410 void
Blt_EmulateXDrawSegments(Display * display,Drawable drawable,GC gc,XSegment * segArr,int nSegments)1411 Blt_EmulateXDrawSegments(
1412     Display *display,
1413     Drawable drawable,
1414     GC gc,
1415     XSegment *segArr,
1416     int nSegments)
1417 {
1418     HDC dc;
1419     register XSegment *segPtr, *endPtr;
1420     TkWinDCState state;
1421 
1422     display->request++;
1423     if (drawable == None) {
1424 	return;
1425     }
1426     dc = TkWinGetDrawableDC(display, drawable, &state);
1427     SetROP2(dc, tkpWinRopModes[gc->function]);
1428     if (gc->line_style != LineSolid) {
1429 	/* Handle dotted lines specially */
1430 	DashInfo info;
1431 
1432 	if (!GetDashInfo(dc, gc, &info)) {
1433 	    goto solidLine;
1434 	}
1435 	endPtr = segArr + nSegments;
1436 	for (segPtr = segArr; segPtr < endPtr; segPtr++) {
1437 	    info.count = 0; /* Reset dash counter after every segment. */
1438 	    LineDDA(segPtr->x1, segPtr->y1, segPtr->x2, segPtr->y2, DrawDot,
1439 		(LPARAM)&info);
1440 	}
1441     } else {
1442 	HPEN pen, oldPen;
1443 
1444       solidLine:
1445 	pen = Blt_GCToPen(dc, gc);
1446 	oldPen = SelectPen(dc, pen);
1447 	endPtr = segArr + nSegments;
1448 	for (segPtr = segArr; segPtr < endPtr; segPtr++) {
1449 	    MoveToEx(dc, segPtr->x1, segPtr->y1, (LPPOINT)NULL);
1450 	    LineTo(dc, segPtr->x2, segPtr->y2);
1451 	}
1452 	DeletePen(SelectPen(dc, oldPen));
1453     }
1454     TkWinReleaseDrawableDC(drawable, dc, &state);
1455 }
1456 
1457 /*
1458  *----------------------------------------------------------------------
1459  *
1460  * Blt_EmultateXDrawRectangle --
1461  *
1462  *       Draws the outlines of the specified rectangle as if a
1463  *       five-point PolyLine protocol request were specified for each
1464  *       rectangle:
1465  *
1466  *             [x,y] [x+width,y] [x+width,y+height] [x,y+height]
1467  *             [x,y]
1468  *
1469  * Results:
1470  *	None.
1471  *
1472  * Side effects:
1473  *	Draws a rectangle on the specified drawable.
1474  *
1475  *----------------------------------------------------------------------
1476  */
1477 void
Blt_EmulateXDrawRectangle(Display * display,Drawable drawable,GC gc,int x,int y,unsigned int width,unsigned int height)1478 Blt_EmulateXDrawRectangle(
1479     Display *display,
1480     Drawable drawable,
1481     GC gc,
1482     int x, int y,
1483     unsigned int width,
1484     unsigned int height)
1485 {
1486     TkWinDCState state;
1487     HPEN pen, oldPen;
1488     HBRUSH brush, oldBrush;
1489     HDC dc;
1490 
1491     if (drawable == None) {
1492 	return;
1493     }
1494     dc = TkWinGetDrawableDC(display, drawable, &state);
1495     pen = Blt_GCToPen(dc, gc);
1496     brush = GetStockObject(NULL_BRUSH);
1497     oldPen = SelectPen(dc, pen);
1498     oldBrush = SelectBrush(dc, brush);
1499     SetROP2(dc, tkpWinRopModes[gc->function]);
1500     if (gc->line_style != LineSolid) {
1501 	/* Handle dotted lines specially */
1502 	register int x2, y2;
1503 	DashInfo info;
1504 
1505 	if (!GetDashInfo(dc, gc, &info)) {
1506 	    goto solidLine;
1507 	}
1508 	x2 = x + width;
1509 	y2 = y + height;
1510 	LineDDA(x, y, x2, y, DrawDot, (LPARAM)&info);
1511 	LineDDA(x2, y, x2, y2, DrawDot, (LPARAM)&info);
1512 	LineDDA(x2, y2, x, y2, DrawDot, (LPARAM)&info);
1513 	LineDDA(x, y2, x, y, DrawDot, (LPARAM)&info);
1514     } else {
1515       solidLine:
1516 	Rectangle(dc, x, y, x + width + 1, y + height + 1);
1517     }
1518     DeletePen(SelectPen(dc, oldPen));
1519     DeleteBrush(SelectBrush(dc, oldBrush));
1520     TkWinReleaseDrawableDC(drawable, dc, &state);
1521 }
1522 
1523 /*
1524  *----------------------------------------------------------------------
1525  *
1526  * Blt_EmulateXDrawPoints --
1527  *
1528  *	Uses the foreground pixel and function components of the GC to
1529  *	draw a multiple points into the specified drawable.
1530  *      CoordModeOrigin treats all coordinates as relative to the
1531  *	origin, and CoordModePrevious treats all coordinates after
1532  *	the first as relative to the previous point.
1533  *
1534  * Results:
1535  *	None.
1536  *
1537  * Side effects:
1538  *	Draws points on the specified drawable.
1539  *
1540  *----------------------------------------------------------------------
1541  */
1542 void
Blt_EmulateXDrawPoints(Display * display,Drawable drawable,GC gc,XPoint * pointArr,int nPoints,int mode)1543 Blt_EmulateXDrawPoints(
1544     Display *display,
1545     Drawable drawable,
1546     GC gc,
1547     XPoint *pointArr,
1548     int nPoints,
1549     int mode)
1550 {				/* Ignored. CoordModeOrigin is assumed. */
1551     HDC dc;
1552     register XPoint *pointPtr, *endPtr;
1553     TkWinDCState state;
1554 
1555     display->request++;
1556     if (drawable == None) {
1557 	return;
1558     }
1559     dc = TkWinGetDrawableDC(display, drawable, &state);
1560     SetROP2(dc, tkpWinRopModes[gc->function]);
1561     endPtr = pointArr + nPoints;
1562     for (pointPtr = pointArr; pointPtr < endPtr; pointPtr++) {
1563 	SetPixelV(dc, pointPtr->x, pointPtr->y, gc->foreground);
1564     }
1565     TkWinReleaseDrawableDC(drawable, dc, &state);
1566 }
1567 
1568 /*
1569  *----------------------------------------------------------------------
1570  *
1571  * Blt_EmultateXReparentWindow --
1572  *
1573  *	If the specified window is mapped, automatically performs an
1574  *	UnmapWindow request on it, removes it from its current
1575  *	position in the hierarchy, and inserts it as the child of the
1576  *	specified parent.  The window is placed in the stacking order
1577  *	on top with respect to sibling windows.
1578  *
1579  *	Note: In WIN32 you can't reparent to/from another application.
1580  *
1581  * Results:
1582  *	None.
1583  *
1584  * Side effects:
1585  *	Reparents the specified window.
1586  *
1587  *----------------------------------------------------------------------
1588  */
1589 void
Blt_EmulateXReparentWindow(Display * display,Window window,Window parent,int x,int y)1590 Blt_EmulateXReparentWindow(
1591     Display *display,
1592     Window window,
1593     Window parent,
1594     int x,
1595     int y)
1596 {
1597     HWND child, newParent;
1598 
1599     child = Tk_GetHWND(window);
1600     newParent = Tk_GetHWND(parent);
1601     SetParent(child, newParent);
1602     SetWindowLong(child, GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN |
1603 	WS_CLIPSIBLINGS);
1604 
1605     XMoveWindow(display, window, x, y);
1606     XRaiseWindow(display, window);
1607     XMapWindow(display, window);
1608 }
1609 
1610 void
Blt_EmulateXSetDashes(Display * display,GC gc,int dashOffset,_Xconst char * dashList,int n)1611 Blt_EmulateXSetDashes(
1612     Display *display,
1613     GC gc,
1614     int dashOffset,
1615     _Xconst char *dashList,
1616     int n)
1617 {
1618     gc->dashes = (unsigned char)strlen(dashList);
1619     gc->dash_offset = (int)dashList;
1620 }
1621 
1622 /*
1623  *----------------------------------------------------------------------
1624  *
1625  * Blt_EmultateXDrawString --
1626  *
1627  *	Draw a single string in the current font.
1628  *
1629  * Results:
1630  *	None.
1631  *
1632  * Side effects:
1633  *	Renders the specified string in the drawable.
1634  *
1635  *----------------------------------------------------------------------
1636  */
1637 void
Blt_EmulateXDrawString(Display * display,Drawable drawable,GC gc,int x,int y,_Xconst char * string,int length)1638 Blt_EmulateXDrawString(
1639     Display *display,
1640     Drawable drawable,
1641     GC gc,
1642     int x,
1643     int y,
1644     _Xconst char *string,
1645     int length)
1646 {
1647     if (drawable == None) {
1648 	return;
1649     }
1650     Tk_DrawChars(display, drawable, gc, (Tk_Font)gc->font, string, length,
1651 	x, y);
1652 }
1653 
1654 static void
TileArea(destDC,srcDC,tileOriginX,tileOriginY,tileWidth,tileHeight,x,y,width,height)1655 TileArea(destDC, srcDC, tileOriginX, tileOriginY, tileWidth, tileHeight,
1656 	 x, y, width, height)
1657     HDC destDC, srcDC;
1658     int tileOriginX, tileOriginY, tileWidth,  tileHeight;
1659     int x, y, width, height;
1660 {
1661     int destX, destY;
1662     int destWidth, destHeight;
1663     int srcX, srcY;
1664     int xOrigin, yOrigin;
1665     int delta;
1666     int left, top, right, bottom;
1667 
1668     xOrigin = x, yOrigin = y;
1669     if (x < tileOriginX) {
1670 	delta = (tileOriginX - x) % tileWidth;
1671 	if (delta > 0) {
1672 	    xOrigin -= (tileWidth - delta);
1673 	}
1674     } else if (x > tileOriginX) {
1675 	delta = (x - tileOriginX) % tileWidth;
1676 	if (delta > 0) {
1677 	    xOrigin -= delta;
1678 	}
1679     }
1680     if (y < tileOriginY) {
1681 	delta = (tileOriginY - y) % tileHeight;
1682 	if (delta > 0) {
1683 	    yOrigin -= (tileHeight - delta);
1684 	}
1685     } else if (y >= tileOriginY) {
1686 	delta = (y - tileOriginY) % tileHeight;
1687 	if (delta > 0) {
1688 	    yOrigin -= delta;
1689 	}
1690     }
1691 #ifdef notdef
1692     PurifyPrintf("tile is (%d,%d,%d,%d)\n", tileOriginX, tileOriginY,
1693 		 tileWidth, tileHeight);
1694     PurifyPrintf("region is (%d,%d,%d,%d)\n", x, y, width, height);
1695     PurifyPrintf("starting at %d,%d\n", xOrigin, yOrigin);
1696 #endif
1697     left = x;
1698     right = x + width;
1699     top = y;
1700     bottom = y + height;
1701     for (y = yOrigin; y < bottom; y += tileHeight) {
1702 	srcY = 0;
1703 	destY = y;
1704 	destHeight = tileHeight;
1705 	if (y < top) {
1706 	    srcY = (top - y);
1707 	    destHeight = tileHeight - srcY;
1708 	    destY = top;
1709 	}
1710 	if ((destY + destHeight) > bottom) {
1711 	    destHeight = (bottom - destY);
1712 	}
1713 	for (x = xOrigin; x < right; x += tileWidth) {
1714 	    srcX = 0;
1715 	    destX = x;
1716 	    destWidth = tileWidth;
1717 	    if (x < left) {
1718 		srcX = (left - x);
1719 		destWidth = tileWidth - srcX;
1720 		destX = left;
1721 	    }
1722 	    if ((destX + destWidth) > right) {
1723 		destWidth = (right - destX);
1724 	    }
1725 #ifdef notdef
1726 	    PurifyPrintf("drawing pattern (%d,%d,%d,%d) at %d,%d\n",
1727 		 srcX , srcY, destWidth, destHeight, destX, destY);
1728 #endif
1729 	    BitBlt(destDC, destX, destY, destWidth, destHeight,
1730 		srcDC, srcX, srcY, SRCCOPY);
1731 	}
1732     }
1733 }
1734 
1735 /*
1736  *----------------------------------------------------------------------
1737  *
1738  * Blt_EmultateXFillRectangles --
1739  *
1740  *	Fill multiple rectangular areas in the given drawable.
1741  *	Handles tiling.
1742  *
1743  * Results:
1744  *	None.
1745  *
1746  * Side effects:
1747  *	Draws onto the specified drawable.
1748  *
1749  *----------------------------------------------------------------------
1750  */
1751 
1752 void
Blt_EmulateXFillRectangles(Display * display,Drawable drawable,GC gc,XRectangle * rectArr,int nRectangles)1753 Blt_EmulateXFillRectangles(
1754     Display *display,
1755     Drawable drawable,
1756     GC gc,
1757     XRectangle *rectArr,
1758     int nRectangles)
1759 {
1760     BITMAP bm;
1761     HBITMAP oldBitmap, hBitmap;
1762     HBRUSH oldBrush, hFgBrush, hBgBrush, hBrush;
1763     HDC hDC;
1764     HDC memDC;
1765     RECT rect;
1766     TkWinDCState state;
1767     TkWinDrawable *twdPtr;
1768     register XRectangle *rectPtr, *endPtr;
1769 
1770     if (drawable == None) {
1771 	return;
1772     }
1773     hDC = TkWinGetDrawableDC(display, drawable, &state);
1774     SetROP2(hDC, tkpWinRopModes[gc->function]);
1775 
1776     switch(gc->fill_style) {
1777     case FillTiled:
1778 	if (gc->tile == None) {
1779 	    goto fillSolid;
1780         }
1781 #ifdef notdef
1782 	if ((GetDeviceCaps(hDC, RASTERCAPS) & RC_BITBLT) == 0) {
1783 	    goto fillSolid;
1784 	}
1785 #endif
1786         twdPtr = (TkWinDrawable *)gc->tile;
1787 	GetObject(twdPtr->bitmap.handle, sizeof(BITMAP), &bm);
1788 	memDC = CreateCompatibleDC(hDC);
1789 	oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle);
1790 	endPtr = rectArr + nRectangles;
1791         for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) {
1792 	    TileArea(hDC, memDC, gc->ts_x_origin, gc->ts_y_origin, bm.bmWidth,
1793 		bm.bmHeight, (int)rectPtr->x, (int)rectPtr->y,
1794 		(int)rectPtr->width, (int)rectPtr->height);
1795         }
1796 	SelectBitmap(memDC, oldBitmap);
1797 	DeleteDC(memDC);
1798         break;
1799 
1800     case FillOpaqueStippled:
1801     case FillStippled:
1802 	if (gc->stipple == None) {
1803 	    goto fillSolid;
1804 	}
1805         twdPtr = (TkWinDrawable *)gc->stipple;
1806 	if (twdPtr->type != TWD_BITMAP) {
1807 	    panic("unexpected drawable type in stipple");
1808 	}
1809 	hBrush = CreatePatternBrush(twdPtr->bitmap.handle);
1810 	SetBrushOrgEx(hDC, gc->ts_x_origin, gc->ts_y_origin, NULL);
1811 	oldBrush = SelectBrush(hDC, hBrush);
1812 	memDC = CreateCompatibleDC(hDC);
1813 
1814 	/*
1815 	 * For each rectangle, create a drawing surface which is the size of
1816 	 * the rectangle and fill it with the background color.  Then merge the
1817 	 * result with the stipple pattern.
1818 	 */
1819         hFgBrush = CreateSolidBrush(gc->foreground);
1820 	hBgBrush = CreateSolidBrush(gc->background);
1821 	endPtr = rectArr + nRectangles;
1822         for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) {
1823 	    hBitmap = CreateCompatibleBitmap(hDC, rectPtr->width,
1824 		rectPtr->height);
1825 	    oldBitmap = SelectObject(memDC, hBitmap);
1826 	    rect.left = rect.top = 0;
1827 	    rect.right = rectPtr->width;
1828 	    rect.bottom = rectPtr->height;
1829 	    FillRect(memDC, &rect, hFgBrush);
1830 	    BitBlt(hDC, rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height,
1831 		memDC, 0, 0, COPYBG);
1832 	    if (gc->fill_style == FillOpaqueStippled) {
1833 		FillRect(memDC, &rect, hBgBrush);
1834 		BitBlt(hDC, rectPtr->x, rectPtr->y, rectPtr->width,
1835 			rectPtr->height, memDC, 0, 0, COPYFG);
1836 	    }
1837 	    SelectObject(memDC, oldBitmap);
1838 	    DeleteObject(hBitmap);
1839 	}
1840 	DeleteBrush(hFgBrush);
1841 	DeleteBrush(hBgBrush);
1842 	DeleteDC(memDC);
1843 	SelectBrush(hDC, oldBrush);
1844 	DeleteBrush(hBrush);
1845  	break;
1846 
1847     case FillSolid:
1848 	fillSolid:
1849 	memDC = CreateCompatibleDC(hDC);
1850         hFgBrush = CreateSolidBrush(gc->foreground);
1851 	endPtr = rectArr + nRectangles;
1852         for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) {
1853 	    hBitmap = CreateCompatibleBitmap(hDC, rectPtr->width,
1854 		rectPtr->height);
1855 	    oldBitmap = SelectObject(memDC, hBitmap);
1856 	    rect.left = rect.top = 0;
1857 	    rect.right = rectPtr->width;
1858 	    rect.bottom = rectPtr->height;
1859 	    FillRect(memDC, &rect, hFgBrush);
1860 	    BitBlt(hDC, rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height,
1861 		   memDC, 0, 0, SRCCOPY);
1862 	    SelectObject(memDC, oldBitmap);
1863 	    DeleteObject(hBitmap);
1864 	}
1865 	DeleteBrush(hFgBrush);
1866 	DeleteDC(memDC);
1867  	break;
1868     }
1869     TkWinReleaseDrawableDC(drawable, hDC, &state);
1870 }
1871 
1872 void
Blt_EmulateXFillRectangle(Display * display,Drawable drawable,GC gc,int x,int y,unsigned int width,unsigned int height)1873 Blt_EmulateXFillRectangle(
1874     Display *display,
1875     Drawable drawable,
1876     GC gc,
1877     int x,
1878     int y,
1879     unsigned int width,
1880     unsigned int height)
1881 {
1882     HDC hDC;
1883     RECT rect;
1884     TkWinDCState state;
1885 
1886     if (drawable == None) {
1887 	return;
1888     }
1889     hDC = TkWinGetDrawableDC(display, drawable, &state);
1890     SetROP2(hDC, tkpWinRopModes[gc->function]);
1891     rect.left = rect.top = 0;
1892     rect.right = width;
1893     rect.bottom = height;
1894 
1895     switch(gc->fill_style) {
1896     case FillTiled:
1897 	{
1898 	    TkWinDrawable *twdPtr;
1899 	    HBITMAP oldBitmap;
1900 	    HDC memDC;
1901 	    BITMAP bm;
1902 
1903 	    if (gc->tile == None) {
1904 		goto fillSolid;
1905 	    }
1906 #ifdef notdef
1907 	    if ((GetDeviceCaps(hDC, RASTERCAPS) & RC_BITBLT) == 0) {
1908 		goto fillSolid;
1909 	    }
1910 #endif
1911 	    twdPtr = (TkWinDrawable *)gc->tile;
1912 	    /* The tiling routine needs to know the size of the bitmap */
1913 	    GetObject(twdPtr->bitmap.handle, sizeof(BITMAP), &bm);
1914 
1915 	    memDC = CreateCompatibleDC(hDC);
1916 	    oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle);
1917 	    TileArea(hDC, memDC, gc->ts_x_origin, gc->ts_y_origin, bm.bmWidth,
1918 		     bm.bmHeight, x, y, width, height);
1919 	    SelectBitmap(memDC, oldBitmap);
1920 	    DeleteDC(memDC);
1921 	}
1922 	break;
1923 
1924     case FillOpaqueStippled:
1925     case FillStippled:
1926 	{
1927 	    TkWinDrawable *twdPtr;
1928 	    HBRUSH oldBrush, hBrush;
1929 	    HBRUSH hBrushFg, hBrushBg;
1930 	    HBITMAP oldBitmap, hBitmap;
1931 	    HDC memDC;
1932 
1933 	    if (gc->stipple == None) {
1934 		goto fillSolid;
1935 	    }
1936 	    twdPtr = (TkWinDrawable *)gc->stipple;
1937 	    if (twdPtr->type != TWD_BITMAP) {
1938 		panic("unexpected drawable type in stipple");
1939 	    }
1940 	    hBrush = CreatePatternBrush(twdPtr->bitmap.handle);
1941 	    SetBrushOrgEx(hDC, gc->ts_x_origin, gc->ts_y_origin, NULL);
1942 	    oldBrush = SelectBrush(hDC, hBrush);
1943 	    memDC = CreateCompatibleDC(hDC);
1944 
1945 	    hBrushFg = CreateSolidBrush(gc->foreground);
1946 	    hBrushBg = CreateSolidBrush(gc->background);
1947 	    hBitmap = CreateCompatibleBitmap(hDC, width, height);
1948 	    oldBitmap = SelectObject(memDC, hBitmap);
1949 	    FillRect(memDC, &rect, hBrushFg);
1950 	    SetBkMode(hDC, TRANSPARENT);
1951 	    BitBlt(hDC, x, y, width, height, memDC, 0, 0, COPYFG);
1952 	    if (gc->fill_style == FillOpaqueStippled) {
1953 		FillRect(memDC, &rect, hBrushBg);
1954 		BitBlt(hDC, x, y, width, height, memDC, 0, 0, COPYBG);
1955 	    }
1956 	    SelectBrush(hDC, oldBrush);
1957 	    SelectBitmap(memDC, oldBitmap);
1958 	    DeleteBrush(hBrushFg);
1959 	    DeleteBrush(hBrushBg);
1960 	    DeleteBrush(hBrush);
1961 	    DeleteBitmap(hBitmap);
1962 	    DeleteDC(memDC);
1963 	}
1964 	break;
1965 
1966     case FillSolid:
1967 	{
1968 	    HBRUSH hBrush;
1969 	    HBITMAP oldBitmap, hBitmap;
1970 	    HDC memDC;
1971 
1972 	fillSolid:
1973 	    /* TkWinFillRect(hDC, x, y, width, height, gc->foreground);  */
1974 	    memDC = CreateCompatibleDC(hDC);
1975 	    hBrush = CreateSolidBrush(gc->foreground);
1976 	    hBitmap = CreateCompatibleBitmap(hDC, width, height);
1977 	    oldBitmap = SelectBitmap(memDC, hBitmap);
1978 	    rect.left = rect.top = 0;
1979 	    rect.right = width;
1980 	    rect.bottom = height;
1981 	    FillRect(memDC, &rect, hBrush);
1982 	    BitBlt(hDC, x, y, width, height, memDC, 0, 0, SRCCOPY);
1983 	    SelectObject(memDC, oldBitmap);
1984 	    DeleteBitmap(hBitmap);
1985 	    DeleteBrush(hBrush);
1986 	    DeleteDC(memDC);
1987 	}
1988 	break;
1989     }
1990     TkWinReleaseDrawableDC(drawable, hDC, &state);
1991 }
1992 
1993 static BOOL
DrawChars(HDC dc,int x,int y,char * string,int length)1994 DrawChars(HDC dc, int x, int y, char *string, int length)
1995 {
1996     BOOL result;
1997 
1998 #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0))
1999     if (systemEncoding == NULL) {
2000 	result = TextOutA(dc, x, y, string, length);
2001     } else {
2002 	const unsigned short *wstring;
2003 	Tcl_DString dString;
2004 
2005 	Tcl_DStringInit(&dString);
2006 	Tcl_UtfToExternalDString(systemEncoding, string, length, &dString);
2007 	length = Tcl_NumUtfChars(string, -1);
2008 	wstring = (const unsigned short *)Tcl_DStringValue(&dString);
2009 	result = TextOutW(dc, x, y, wstring, length);
2010 	Tcl_DStringFree(&dString);
2011     }
2012 #else
2013     result = TextOutA(dc, x, y, string, length);
2014 #endif /* TCL_VERSION_NUMBER >= 8.1.0 */
2015     return result;
2016 }
2017 
2018 int
Blt_DrawRotatedText(Display * display,Drawable drawable,int x,int y,double theta,TextStyle * tsPtr,TextLayout * textPtr)2019 Blt_DrawRotatedText(
2020     Display *display,
2021     Drawable drawable,
2022     int x, int y,
2023     double theta,
2024     TextStyle *tsPtr,
2025     TextLayout *textPtr)
2026 {
2027     HFONT hFont, oldFont;
2028     TkWinDCState state;
2029     HDC hDC;
2030     int isActive;
2031     int bbWidth, bbHeight;
2032     double rotWidth, rotHeight;
2033     double sinTheta, cosTheta;
2034     Point2D p, q, center;
2035     register TextFragment *fragPtr, *endPtr;
2036 #if (TCL_VERSION_NUMBER >=  _VERSION(8,1,0))
2037     static int initialized = 0;
2038 
2039     if (!initialized) {
2040 	if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) {
2041 	    /*
2042 	     * If running NT, then we will be calling some Unicode functions
2043 	     * explictly.  So, even if the Tcl system encoding isn't Unicode,
2044 	     * make sure we convert to/from the Unicode char set.
2045 	     */
2046 	    systemEncoding = Tcl_GetEncoding(NULL, "unicode");
2047 	}
2048 	initialized = 1;
2049     }
2050 #endif
2051     hFont = CreateRotatedFont(tsPtr->gc->font, theta);
2052     if (hFont == NULL) {
2053 	return FALSE;
2054     }
2055     isActive = (tsPtr->state & STATE_ACTIVE);
2056     hDC = TkWinGetDrawableDC(display, drawable, &state);
2057     SetROP2(hDC, tsPtr->gc->function);
2058     oldFont = SelectFont(hDC, hFont);
2059 
2060     Blt_GetBoundingBox(textPtr->width, textPtr->height, theta, &rotWidth,
2061 		       &rotHeight, (Point2D *)NULL);
2062     bbWidth = ROUND(rotWidth);
2063     bbHeight = ROUND(rotHeight);
2064     Blt_TranslateAnchor(x, y, bbWidth, bbHeight, tsPtr->anchor, &x, &y);
2065     center.x = (double)textPtr->width * -0.5;
2066     center.y = (double)textPtr->height * -0.5;
2067     theta = (-theta / 180.0) * M_PI;
2068     sinTheta = sin(theta), cosTheta = cos(theta);
2069 
2070     endPtr = textPtr->fragArr + textPtr->nFrags;
2071 
2072     for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
2073 	p.x = center.x + (double)fragPtr->x;
2074 	p.y = center.y + (double)fragPtr->y;
2075 	q.x = x + (p.x * cosTheta) - (p.y * sinTheta) + (bbWidth * 0.5);
2076 	q.y = y + (p.x * sinTheta) + (p.y * cosTheta) + (bbHeight * 0.5);
2077 	fragPtr->sx = ROUND(q.x);
2078 	fragPtr->sy = ROUND(q.y);
2079     }
2080     SetBkMode(hDC, TRANSPARENT);
2081     SetTextAlign(hDC, TA_LEFT | TA_BASELINE);
2082 
2083     if (tsPtr->state & (STATE_DISABLED | STATE_EMPHASIS)) {
2084 	TkBorder *borderPtr = (TkBorder *) tsPtr->border;
2085 	XColor *color1, *color2;
2086 
2087 	color1 = borderPtr->lightColor, color2 = borderPtr->darkColor;
2088 	if (tsPtr->state & STATE_EMPHASIS) {
2089 	    XColor *hold;
2090 
2091 	    hold = color1, color1 = color2, color2 = hold;
2092 	}
2093 	if (color1 != NULL) {
2094 	    SetTextColor(hDC, color1->pixel);
2095 	    for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
2096 		DrawChars(hDC, fragPtr->sx, fragPtr->sy, fragPtr->text,
2097 			fragPtr->count);
2098 	    }
2099 	}
2100 	if (color2 != NULL) {
2101 	    SetTextColor(hDC, color2->pixel);
2102 	    for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
2103 		DrawChars(hDC, fragPtr->sx + 1, fragPtr->sy + 1, fragPtr->text,
2104 			fragPtr->count);
2105 	    }
2106 	}
2107 	goto done;		/* Done */
2108     }
2109     SetBkMode(hDC, TRANSPARENT);
2110     if ((tsPtr->shadow.offset > 0) && (tsPtr->shadow.color != NULL)) {
2111 	SetTextColor(hDC, tsPtr->shadow.color->pixel);
2112 	for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
2113 	    DrawChars(hDC, fragPtr->sx + tsPtr->shadow.offset,
2114 		    fragPtr->sy + tsPtr->shadow.offset, fragPtr->text,
2115 		    fragPtr->count);
2116 	}
2117     }
2118     if (isActive) {
2119 	SetTextColor(hDC, tsPtr->activeColor->pixel);
2120     } else {
2121 	SetTextColor(hDC, tsPtr->color->pixel);
2122     }
2123 
2124     for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
2125 	DrawChars(hDC, fragPtr->sx, fragPtr->sy, fragPtr->text,
2126 		    fragPtr->count);
2127     }
2128 
2129     if (isActive) {
2130 	SetTextColor(hDC, tsPtr->color->pixel);
2131     }
2132  done:
2133     SelectFont(hDC, oldFont);
2134     DeleteFont(hFont);
2135     TkWinReleaseDrawableDC(drawable, hDC, &state);
2136     return TRUE;
2137 }
2138 
2139 static void
DrawPixel(HDC hDC,int x,int y,COLORREF color)2140 DrawPixel(
2141     HDC hDC,
2142     int x,
2143     int y,
2144     COLORREF color)
2145 {
2146     HDC memDC;
2147     HBRUSH hBrushFg;
2148     HBITMAP oldBitmap, hBitmap;
2149     RECT rect;
2150     int size;
2151 
2152     size = 1;
2153     memDC = CreateCompatibleDC(hDC);
2154     hBrushFg = CreateSolidBrush(color);
2155     hBitmap = CreateCompatibleBitmap(hDC, size, size);
2156     oldBitmap = SelectObject(memDC, hBitmap);
2157     rect.left = rect.top = 0;
2158     rect.right = rect.bottom = size;
2159     FillRect(memDC, &rect, hBrushFg);
2160     BitBlt(hDC, x, y, size, size, memDC, 0, 0, SRCCOPY);
2161     SelectObject(memDC, oldBitmap);
2162     DeleteObject(hBitmap);
2163     DeleteBrush(hBrushFg);
2164     DeleteDC(memDC);
2165 }
2166 
2167 /*
2168  *----------------------------------------------------------------------
2169  *
2170  * PixelateBitmap --
2171  *
2172  *	Draws a masked bitmap in given device (should be printer)
2173  *	context.  Bit operations on print devices usually fail because
2174  *	there's no way to read back from the device surface to get the
2175  *	previous pixel values, rendering BitBlt useless. The bandaid
2176  *	solution here is to draw 1x1 pixel rectangles at each
2177  *	coordinate as directed by the the mask and source bitmaps.
2178  *
2179  * Results:
2180  *	None.
2181  *
2182  * Side effects:
2183  *	Draws onto the specified drawable.
2184  *
2185  *----------------------------------------------------------------------
2186  */
2187 static void
PixelateBitmap(Display * display,Drawable drawable,Pixmap srcBitmap,Pixmap maskBitmap,int width,int height,GC gc,int destX,int destY)2188 PixelateBitmap(
2189     Display *display,
2190     Drawable drawable,
2191     Pixmap srcBitmap,
2192     Pixmap maskBitmap,
2193     int width,
2194     int height,
2195     GC gc,
2196     int destX,
2197     int destY)
2198 {
2199     register int x, y;
2200     register int dx, dy;
2201     int pixel;
2202     unsigned char *srcBits;
2203     register unsigned char *srcPtr;
2204     int bitPos, bytesPerRow;
2205     HDC hDC;
2206     TkWinDCState state;
2207 
2208     srcBits = Blt_GetBitmapData(display, srcBitmap, width, height,
2209 	&bytesPerRow);
2210     if (srcBits == NULL) {
2211 	return;
2212     }
2213     hDC = TkWinGetDrawableDC(display, drawable, &state);
2214     if (maskBitmap != None) {
2215         register unsigned char *maskPtr;
2216         unsigned char *maskBits;
2217         maskBits = Blt_GetBitmapData(display, maskBitmap, width, height,
2218 	    &bytesPerRow);
2219         bytesPerRow = ((width + 31) & ~31) / 8;
2220         for (dy = destY, y = height - 1; y >= 0; y--, dy++) {
2221 	    maskPtr = maskBits + (bytesPerRow * y);
2222 	    srcPtr = srcBits + (bytesPerRow * y);
2223 	    for (dx = destX, x = 0; x < width; x++, dx++) {
2224 	        bitPos = x % 8;
2225 	        pixel = (*maskPtr & (0x80 >> bitPos));
2226 	        if (pixel) {
2227 		    pixel = (*srcPtr & (0x80 >> bitPos));
2228 		    DrawPixel(hDC, dx, dy,
2229 		        (pixel) ? gc->foreground : gc->background);
2230 	        }
2231 	        if (bitPos == 7) {
2232 		    srcPtr++, maskPtr++;
2233 	        }
2234 	    }			/* x */
2235         }
2236         Blt_Free(maskBits);
2237     } else {
2238         bytesPerRow = ((width + 31) & ~31) / 8;
2239         for (dy = destY, y = height - 1; y >= 0; y--, dy++) {
2240 	    srcPtr = srcBits + (bytesPerRow * y);
2241 	    for (dx = destX, x = 0; x < width; x++, dx++) {
2242 	        bitPos = x % 8;
2243 		pixel = (*srcPtr & (0x80 >> bitPos));
2244 		DrawPixel(hDC, dx, dy,
2245 		        (pixel) ? gc->foreground : gc->background);
2246 	        if (bitPos == 7) {
2247 		    srcPtr++;
2248 	        }
2249 	    }
2250 	}
2251     }
2252     TkWinReleaseDrawableDC(drawable, hDC, &state);
2253     Blt_Free(srcBits);
2254 }
2255 
2256 /*
2257  *----------------------------------------------------------------------
2258  *
2259  * Blt_EmulateXCopyPlane --
2260  *
2261  *	Simplified version of XCopyPlane.  Right now it ignores
2262  *		function,
2263  *		clip_x_origin,
2264  *		clip_y_origin
2265  *
2266  *	The plane argument must always be 1.
2267  *
2268  *	This routine differs from the Tk version in how it handles
2269  *	transparency.  It uses a different method of drawing transparent
2270  *	bitmaps that doesn't copy the background or use brushes.  The
2271  *	second change is to call a special routine when the destDC is
2272  *	a printer.   Stippling is done by a very slow brute-force
2273  *	method of drawing 1x1 rectangles for each pixel (bleech).
2274  *
2275  * Results:
2276  *	None.
2277  *
2278  * Side effects:
2279  *	Changes the destination drawable.
2280  *
2281  *----------------------------------------------------------------------
2282  */
2283 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)2284 Blt_EmulateXCopyPlane(
2285     Display *display,
2286     Drawable src,
2287     Drawable dest,
2288     GC gc,
2289     int srcX,
2290     int srcY,
2291     unsigned int width,
2292     unsigned int height,
2293     int destX,
2294     int destY,
2295     unsigned long plane)
2296 {
2297     HDC srcDC, destDC;
2298     TkWinDCState srcState, destState;
2299     TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask;
2300 
2301     display->request++;
2302 
2303     if (plane != 1) {
2304 	panic("Unexpected plane specified for XCopyPlane");
2305     }
2306     srcDC = TkWinGetDrawableDC(display, src, &srcState);
2307 
2308     if (src != dest) {
2309 	destDC = TkWinGetDrawableDC(display, dest, &destState);
2310     } else {
2311 	destDC = srcDC;
2312     }
2313     if ((clipPtr == NULL) || (clipPtr->type == TKP_CLIP_REGION)) {
2314 	/*
2315 	 * Case 1: opaque bitmaps.  Windows handles the conversion
2316 	 * from one bit to multiple bits by setting 0 to the
2317 	 * foreground color, and 1 to the background color (seems
2318 	 * backwards, but there you are).
2319 	 */
2320 	if ((clipPtr != NULL) && (clipPtr->type == TKP_CLIP_REGION)) {
2321 	    SelectClipRgn(destDC, (HRGN) clipPtr->value.region);
2322 	    OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin);
2323 	}
2324 	SetBkMode(destDC, OPAQUE);
2325 	SetBkColor(destDC, gc->foreground);
2326 	SetTextColor(destDC, gc->background);
2327 	BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY,
2328 	    SRCCOPY);
2329 
2330 	SelectClipRgn(destDC, NULL);
2331 
2332     } else if (clipPtr->type == TKP_CLIP_PIXMAP) {
2333 	Drawable mask;
2334 	/*
2335 	 * Case 2: transparent bitmaps are handled by setting the
2336 	 * destination to the foreground color whenever the source
2337 	 * pixel is set.
2338 	 */
2339 	/*
2340 	 * Case 3: two arbitrary bitmaps.  Copy the source rectangle
2341 	 * into a color pixmap.  Use the result as a brush when
2342 	 * copying the clip mask into the destination.
2343 	 */
2344 	mask = clipPtr->value.pixmap;
2345 
2346 #if WINDEBUG
2347 	PurifyPrintf("mask %s src\n", (mask == src) ? "==" : "!=");
2348 	PurifyPrintf("GetDeviceCaps=%x\n",
2349 		GetDeviceCaps(destDC, TECHNOLOGY) & DT_RASDISPLAY);
2350 #endif
2351 	{
2352 	    HDC maskDC;
2353 	    TkWinDCState maskState;
2354 
2355 	    if (mask != src) {
2356 		maskDC = TkWinGetDrawableDC(display, mask, &maskState);
2357 	    } else {
2358 		maskDC = srcDC;
2359 	    }
2360 	    SetBkMode(destDC, OPAQUE);
2361 	    SetTextColor(destDC, gc->background);
2362 	    SetBkColor(destDC, gc->foreground);
2363 	    BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY,
2364 		   SRCINVERT);
2365 	    /*
2366 	     * Make sure we treat the mask as a monochrome bitmap.
2367 	     * We can get alpha-blending with non-black/white fg/bg
2368 	     * color selections.
2369 	     */
2370 	    SetTextColor(destDC, RGB(255,255,255));
2371 	    SetBkColor(destDC, RGB(0,0,0));
2372 
2373 	    /* FIXME: Handle gc->clip_?_origin's */
2374 	    BitBlt(destDC, destX, destY, width, height, maskDC, 0, 0, SRCAND);
2375 
2376 	    SetTextColor(destDC, gc->background);
2377 	    SetBkColor(destDC, gc->foreground);
2378 	    BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY,
2379 		   SRCINVERT);
2380 	    if (mask != src) {
2381 		TkWinReleaseDrawableDC(mask, maskDC, &maskState);
2382 	    }
2383 	}
2384     }
2385     if (src != dest) {
2386 	TkWinReleaseDrawableDC(dest, destDC, &destState);
2387     }
2388     TkWinReleaseDrawableDC(src, srcDC, &srcState);
2389 }
2390 
2391 /*
2392  *----------------------------------------------------------------------
2393  *
2394  * Blt_EmulateXCopyArea --
2395  *
2396  *	Copies data from one drawable to another using block transfer
2397  *	routines.  The small enhancement over the version in Tk is
2398  *	that it doesn't assume that the source and destination devices
2399  *	have the same resolution. This isn't true when the destination
2400  *	device is a printer.
2401  *
2402  *	FIXME: not true anymore.  delete this routine.
2403  *
2404  * Results:
2405  *	None.
2406  *
2407  * Side effects:
2408  *	Data is moved from a window or bitmap to a second window,
2409  *	bitmap, or printer.
2410  *
2411  *----------------------------------------------------------------------
2412  */
2413 void
Blt_EmulateXCopyArea(Display * display,Drawable src,Drawable dest,GC gc,int srcX,int srcY,unsigned int width,unsigned int height,int destX,int destY)2414 Blt_EmulateXCopyArea(
2415     Display *display,
2416     Drawable src,
2417     Drawable dest,
2418     GC gc,
2419     int srcX,			/* Source X-coordinate */
2420     int srcY,			/* Source Y-coordinate. */
2421     unsigned int width,		/* Width of area. */
2422     unsigned int height,	/* Height of area. */
2423     int destX,			/* Destination X-coordinate (in screen
2424 				 * coordinates). */
2425     int destY)			/* Destination Y-coordinate (in screen
2426 				 * coordinates). */
2427 {
2428     HDC srcDC, destDC;
2429     TkWinDCState srcState, destState;
2430     TkpClipMask *clipPtr;
2431 
2432     srcDC = TkWinGetDrawableDC(display, src, &srcState);
2433     if (src != dest) {
2434 	destDC = TkWinGetDrawableDC(display, dest, &destState);
2435     } else {
2436 	destDC = srcDC;
2437     }
2438     clipPtr = (TkpClipMask *)gc->clip_mask;
2439     if ((clipPtr != NULL) && (clipPtr->type == TKP_CLIP_REGION)) {
2440 	SelectClipRgn(destDC, (HRGN)clipPtr->value.region);
2441 	OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin);
2442     }
2443 
2444     BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY,
2445 		bltModes[gc->function]);
2446     SelectClipRgn(destDC, NULL);
2447 
2448     if (src != dest) {
2449 	TkWinReleaseDrawableDC(dest, destDC, &destState);
2450     }
2451     TkWinReleaseDrawableDC(src, srcDC, &srcState);
2452 }
2453 
2454 static void
StippleRegion(Display * display,HDC hDC,GC gc,int x,int y,int width,int height)2455 StippleRegion(
2456     Display *display,
2457     HDC hDC,			/* Device context: For polygons, clip
2458 				 * region will be installed. */
2459     GC gc,
2460     int x, int y,
2461     int width, int height)
2462 {
2463     BITMAP bm;
2464     HBITMAP oldBitmap;
2465     HDC maskDC, memDC;
2466     Pixmap mask;
2467     TkWinDCState maskState;
2468     TkWinDrawable *twdPtr;
2469     int destX, destY, destWidth, destHeight;
2470     int dx, dy;
2471     int left, top, right, bottom;
2472     int srcX, srcY;
2473     int startX, startY;		/* Starting upper left corner of region. */
2474 
2475     twdPtr = (TkWinDrawable *)gc->stipple;
2476     GetObject(twdPtr->bitmap.handle, sizeof(BITMAP), &bm);
2477 
2478     startX = x;
2479     if (x < gc->ts_x_origin) {
2480 	dx = (gc->ts_x_origin - x) % bm.bmWidth;
2481 	if (dx > 0) {
2482 	    startX -= (bm.bmWidth - dx);
2483 	}
2484     } else if (x > gc->ts_x_origin) {
2485 	dx = (x - gc->ts_x_origin) % bm.bmWidth;
2486 	if (dx > 0) {
2487 	    startX -= dx;
2488 	}
2489     }
2490     startY = y;
2491     if (y < gc->ts_y_origin) {
2492 	dy = (gc->ts_y_origin - y) % bm.bmHeight;
2493 	if (dy > 0) {
2494 	    startY -= (bm.bmHeight - dy);
2495 	}
2496     } else if (y >= gc->ts_y_origin) {
2497 	dy = (y - gc->ts_y_origin) % bm.bmHeight;
2498 	if (dy > 0) {
2499 	    startY -= dy;
2500 	}
2501     }
2502 #ifdef notdef
2503     PurifyPrintf("tile is (%d,%d,%d,%d)\n", gc->ts_x_origin, gc->ts_y_origin,
2504 		 bm.bmWidth, bm.bmHeight);
2505     PurifyPrintf("region is (%d,%d,%d,%d)\n", x, y, width, height);
2506     PurifyPrintf("starting at %d,%d\n", startX, startY);
2507 #endif
2508     left = x;
2509     right = x + width;
2510     top = y;
2511     bottom = y + height;
2512 
2513     maskDC = memDC = CreateCompatibleDC(hDC);
2514     oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle);
2515     mask = gc->stipple;
2516     if (gc->fill_style == FillStippled) { /* With transparency. */
2517 	if (gc->clip_mask != None) {
2518 	    TkpClipMask *clipPtr;
2519 
2520 	    mask = gc->stipple;
2521 	    clipPtr = (TkpClipMask *)gc->clip_mask;
2522 	    if  (clipPtr->type == TKP_CLIP_PIXMAP) {
2523 		mask = clipPtr->value.pixmap;
2524 	    }
2525 	}
2526 	if (mask != gc->stipple) {
2527 	    maskDC = TkWinGetDrawableDC(display, mask, &maskState);
2528 	}
2529     }
2530 
2531     for (y = startY; y < bottom; y += bm.bmHeight) {
2532 	srcY = 0;
2533 	destY = y;
2534 	destHeight = bm.bmHeight;
2535 	if (y < top) {
2536 	    srcY = (top - y);
2537 	    destHeight = bm.bmHeight - srcY;
2538 	    destY = top;
2539 	}
2540 	if ((destY + destHeight) > bottom) {
2541 	    destHeight = (bottom - destY);
2542 	}
2543 	for (x = startX; x < right; x += bm.bmWidth) {
2544 	    srcX = 0;
2545 	    destX = x;
2546 	    destWidth = bm.bmWidth;
2547 	    if (x < left) {
2548 		srcX = (left - x);
2549 		destWidth = bm.bmWidth - srcX;
2550 		destX = left;
2551 	    }
2552 	    if ((destX + destWidth) > right) {
2553 		destWidth = (right - destX);
2554 	    }
2555 #ifdef notdef
2556 	    PurifyPrintf("drawing pattern (%d,%d,%d,%d) at %d,%d\n",
2557 		 srcX , srcY, destWidth, destHeight, destX, destY);
2558 #endif
2559 	    if (gc->fill_style == FillStippled) { /* With transparency. */
2560 		SetBkMode(hDC, OPAQUE);
2561 		SetTextColor(hDC, gc->background);
2562 		SetBkColor(hDC, gc->foreground);
2563 		BitBlt(hDC, destX, destY, destWidth, destHeight, memDC,
2564 		       srcX, srcY, SRCINVERT);
2565 		SetTextColor(hDC, RGB(255,255,255));
2566 		SetBkColor(hDC, RGB(0,0,0));
2567 		BitBlt(hDC, destX, destY, destWidth, destHeight, maskDC,
2568 		       srcX, srcY, SRCAND);
2569 		SetTextColor(hDC, gc->background);
2570 		SetBkColor(hDC, gc->foreground);
2571 		BitBlt(hDC, destX, destY, destWidth, destHeight, memDC,
2572 		       srcX, srcY, SRCINVERT);
2573 	    } else if (gc->fill_style == FillOpaqueStippled) { /* Opaque. */
2574 		SetBkColor(hDC, gc->foreground);
2575 		SetTextColor(hDC, gc->background);
2576 	        BitBlt(hDC, destX, destY, destWidth, destHeight, memDC,
2577 			srcX, srcY, SRCCOPY);
2578 	    }
2579 	}
2580     }
2581     SelectBitmap(memDC, oldBitmap);
2582     if (maskDC != memDC) {
2583 	TkWinReleaseDrawableDC(mask, maskDC, &maskState);
2584     }
2585     DeleteDC(memDC);
2586 }
2587 
2588 /*
2589  *----------------------------------------------------------------------
2590  *
2591  * Blt_EmulateXFillPolygon --
2592  *
2593  *	This differs from Tk's XFillPolygon in that it works around
2594  *	deficencies in Windows 95/98:
2595  *		1. Stippling bitmap is limited to 8x8.
2596  *		2. No tiling (with or without mask).
2597  * Results:
2598  *	None.
2599  *
2600  *----------------------------------------------------------------------
2601  */
2602 void
Blt_EmulateXFillPolygon(Display * display,Drawable drawable,GC gc,XPoint * pointPtr,int nPoints,int shape,int mode)2603 Blt_EmulateXFillPolygon(
2604     Display *display,
2605     Drawable drawable,
2606     GC gc,
2607     XPoint *pointPtr,
2608     int nPoints,
2609     int shape,
2610     int mode)
2611 {
2612     HDC hDC;
2613     HRGN hRgn;
2614     POINT *p, *winPts, *endPtr;
2615     Region2D bbox;
2616     TkWinDCState state;
2617     int fillMode;
2618 
2619     if (drawable == None) {
2620 	return;
2621     }
2622 
2623     /* Determine the bounding box of the polygon. */
2624     bbox.left = bbox.right = pointPtr->x;
2625     bbox.top = bbox.bottom = pointPtr->y;
2626 
2627     hDC = TkWinGetDrawableDC(display, drawable, &state);
2628 
2629     /* Allocate array of POINTS to create the polygon's path. */
2630     winPts = Blt_Malloc(sizeof(POINT) * nPoints);
2631     endPtr = winPts + nPoints;
2632     for (p = winPts; p < endPtr; p++) {
2633 	if (pointPtr->x < bbox.left) {
2634 	    bbox.left = pointPtr->x;
2635 	}
2636 	if (pointPtr->x > bbox.right) {
2637 	    bbox.right = pointPtr->x;
2638 	}
2639 	if (pointPtr->y < bbox.top) {
2640 	    bbox.top = pointPtr->y;
2641 	}
2642 	if (pointPtr->y > bbox.bottom) {
2643 	    bbox.bottom = pointPtr->y;
2644 	}
2645 	p->x = pointPtr->x;
2646 	p->y = pointPtr->y;
2647 	pointPtr++;
2648     }
2649 
2650     SetROP2(hDC, tkpWinRopModes[gc->function]);
2651     fillMode = (gc->fill_rule == EvenOddRule) ? ALTERNATE : WINDING;
2652 
2653     if ((gc->fill_style == FillStippled) ||
2654 	(gc->fill_style == FillOpaqueStippled)) {
2655 	int width, height;
2656 
2657 	/* Points are offsets within the bounding box. */
2658 	for (p = winPts; p < endPtr; p++) {
2659 	    p->x -= bbox.left;
2660 	    p->y -= bbox.top;
2661 	}
2662 	/* Use the polygon as a clip path. */
2663 	LPtoDP(hDC, winPts, nPoints);
2664 	hRgn = CreatePolygonRgn(winPts, nPoints, fillMode);
2665 	SelectClipRgn(hDC, hRgn);
2666 	OffsetClipRgn(hDC, bbox.left, bbox.top);
2667 
2668 	/* Tile the bounding box. */
2669 	width = bbox.right - bbox.left + 1;
2670 	height = bbox.bottom - bbox.top + 1;
2671 	StippleRegion(display, hDC, gc, bbox.left, bbox.top, width, height);
2672 
2673 	SelectClipRgn(hDC, NULL);
2674 	DeleteRgn(hRgn);
2675     } else {
2676 	HPEN oldPen;
2677 	HBRUSH oldBrush;
2678 
2679 	/*
2680 	 * FIXME: Right now, we're assuming that it's solid or
2681 	 * stippled and ignoring tiling. I'll merge the bits from
2682 	 * Blt_TilePolygon later.
2683 	 */
2684 	oldPen = SelectPen(hDC, GetStockObject(NULL_PEN));
2685 	oldBrush = SelectBrush(hDC, CreateSolidBrush(gc->foreground));
2686 	SetPolyFillMode(hDC, fillMode);
2687 	Polygon(hDC, winPts, nPoints);
2688 	SelectPen(hDC, oldPen);
2689 	DeleteBrush(SelectBrush(hDC, oldBrush));
2690     }
2691     Blt_Free(winPts);
2692     TkWinReleaseDrawableDC(drawable, hDC, &state);
2693 }
2694