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