source: trunk/kitgen/8.x/blt/win/bltWinDraw.c@ 187

Last change on this file since 187 was 175, checked in by demin, 12 years ago

initial commit

File size: 69.9 KB
RevLine 
[175]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 */
37typedef 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
68static 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
103static 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))
124typedef void *Tcl_Encoding; /* Make up dummy type for encoding. */
125#else
126static Tcl_Encoding systemEncoding = NULL;
127#endif
128
129HPALETTE
130Blt_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 */
168HFONT
169CreateRotatedFont(
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 */
288unsigned char *
289Blt_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 */
365void
366Blt_EmulateXFree(void *ptr)
367{
368 Blt_Free(ptr);
369}
370
371/*
372 *----------------------------------------------------------------------
373 *
374 * XMaxRequestSize --
375 *
376 *----------------------------------------------------------------------
377 */
378long
379Blt_EmulateXMaxRequestSize(Display *display)
380{
381 return (SHRT_MAX / 4);
382}
383
384/*
385 *----------------------------------------------------------------------
386 *
387 * XLowerWindow --
388 *
389 *----------------------------------------------------------------------
390 */
391void
392Blt_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 */
410void
411Blt_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 */
429void
430Blt_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 */
462void
463Blt_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
485static Blt_HashTable gcTable;
486static int gcInitialized = FALSE;
487#endif
488
489typedef struct {
490 HDC dc;
491 int count;
492 COLORREF color;
493 int offset, nBits;
494} DashInfo;
495
496void
497Blt_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
508static int
509GetDashInfo(
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
538void
539Blt_SetROP2(HDC dc, int function)
540{
541 SetROP2(dc, tkpWinRopModes[function]);
542}
543
544static XGCValuesEx *
545CreateGC()
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 */
595GC
596Blt_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 */
731HPEN
732Blt_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 */
871void
872Blt_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
919static int arcus0[1] =
920{
921 BOTH
922};
923static int arcus1[4] =
924{
925 BOTH, BOTH,
926 BOTH, BOTH
927};
928
929static int arcus2[9] =
930{
931 NEITHER, OUTLINE, NEITHER,
932 OUTLINE, FILL, OUTLINE,
933 NEITHER, OUTLINE, NEITHER
934};
935
936static 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
944static 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
953static int *arcis[MINIARCS] =
954{
955 arcus0, arcus1, arcus2, arcus3, arcus4
956};
957
958static void
959DrawMiniArc(
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 */
1006static void
1007DrawArc(
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 */
1112void
1113Blt_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 */
1160void
1161Blt_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 *
1197 * XDrawLines --
1198 *
1199 * Draw connected lines.
1200 *
1201 * Results:
1202 * None.
1203 *
1204 * Side effects:
1205 * Renders a series of connected lines.
1206 *
1207 *----------------------------------------------------------------------
1208 */
1209
1210static void CALLBACK
1211DrawDot(
1212 int x, int y, /* Coordinates of point */
1213 LPARAM clientData)
1214{ /* Line information */
1215 DashInfo *infoPtr = (DashInfo *) clientData;
1216 int count;
1217
1218 infoPtr->count++;
1219 count = (infoPtr->count + infoPtr->offset) / infoPtr->nBits;
1220 if (count & 0x1) {
1221 SetPixelV(infoPtr->dc, x, y, infoPtr->color);
1222 }
1223}
1224
1225
1226void
1227Blt_EmulateXDrawLine(
1228 Display *display,
1229 Drawable drawable,
1230 GC gc,
1231 int x1, int y1,
1232 int x2, int y2)
1233{
1234 TkWinDCState state;
1235 HDC dc;
1236
1237 if (drawable == None) {
1238 return;
1239 }
1240 dc = TkWinGetDrawableDC(display, drawable, &state);
1241 SetROP2(dc, tkpWinRopModes[gc->function]);
1242 if (gc->line_style != LineSolid) {
1243 /* Handle dotted lines specially */
1244 DashInfo info;
1245
1246 if (!GetDashInfo(dc, gc, &info)) {
1247 goto solidLine;
1248 }
1249 LineDDA(x1, y1, x2, y2, DrawDot, (LPARAM)&info);
1250 } else {
1251 HPEN pen, oldPen;
1252 HBRUSH brush, oldBrush;
1253
1254 solidLine:
1255 pen = Blt_GCToPen(dc, gc);
1256 oldPen = SelectPen(dc, pen);
1257 brush = CreateSolidBrush(gc->foreground);
1258 oldBrush = SelectBrush(dc, brush);
1259 MoveToEx(dc, x1, y1, (LPPOINT)NULL);
1260 LineTo(dc, x2, y2);
1261 DeletePen(SelectPen(dc, oldPen));
1262 DeleteBrush(SelectBrush(dc, oldBrush));
1263 }
1264 TkWinReleaseDrawableDC(drawable, dc, &state);
1265}
1266
1267static void
1268DrawLine(
1269 Display *display,
1270 Drawable drawable,
1271 GC gc,
1272 POINT *points,
1273 int nPoints)
1274{
1275 TkWinDCState state;
1276 HDC dc;
1277 register int i, n;
1278 int start, extra, size;
1279 HPEN pen, oldPen;
1280 HBRUSH brush, oldBrush;
1281
1282 if (drawable == None) {
1283 return;
1284 }
1285 dc = TkWinGetDrawableDC(display, drawable, &state);
1286 pen = Blt_GCToPen(dc, gc);
1287 oldPen = SelectPen(dc, pen);
1288 brush = CreateSolidBrush(gc->foreground);
1289 oldBrush = SelectBrush(dc, brush);
1290 SetROP2(dc, tkpWinRopModes[gc->function]);
1291
1292 start = extra = 0;
1293 /*
1294 * Depending if the line is wide (> 1 pixel), arbitrarily break
1295 * the line in sections of 100 points. This bit of weirdness has
1296 * to do with wide geometric pens. The longer the polyline, the
1297 * slower it draws. The trade off is that we lose dash and
1298 * cap uniformity for unbearably slow polyline draws.
1299 */
1300 if (gc->line_width > 1) {
1301 size = 100;
1302 } else {
1303 size = nPoints;
1304 }
1305 for (i = nPoints; i > 0; i -= size) {
1306 n = MIN(i, size);
1307 Polyline(dc, points + start, n + extra);
1308 start += (n - 1);
1309 extra = 1;
1310 }
1311 DeletePen(SelectPen(dc, oldPen));
1312 DeleteBrush(SelectBrush(dc, oldBrush));
1313 TkWinReleaseDrawableDC(drawable, dc, &state);
1314}
1315
1316void
1317Blt_EmulateXDrawLines(
1318 Display *display,
1319 Drawable drawable,
1320 GC gc,
1321 XPoint *pointArr,
1322 int nPoints,
1323 int mode)
1324{
1325 if (drawable == None) {
1326 return;
1327 }
1328 if (gc->line_style != LineSolid) { /* Handle dotted lines specially */
1329 DashInfo info;
1330 TkWinDCState state;
1331 HDC dc;
1332 int result;
1333
1334 dc = TkWinGetDrawableDC(display, drawable, &state);
1335 SetROP2(dc, tkpWinRopModes[gc->function]);
1336 result = GetDashInfo(dc, gc, &info);
1337 if (result) {
1338 register XPoint *p1, *p2;
1339 register int i;
1340
1341 p1 = pointArr;
1342 p2 = p1 + 1;
1343 for (i = 1; i < nPoints; i++, p1++, p2++) {
1344 LineDDA(p1->x, p1->y, p2->x, p2->y, DrawDot, (LPARAM)&info);
1345 }
1346 result = TCL_OK;
1347 }
1348 TkWinReleaseDrawableDC(drawable, dc, &state);
1349 if (result) {
1350 return;
1351 }
1352 } else {
1353 POINT *points, *destPtr;
1354 XPoint *srcPtr, *endPtr;
1355
1356 points = Blt_Malloc(sizeof(POINT) * nPoints);
1357 if (points == NULL) {
1358 return;
1359 }
1360 endPtr = pointArr + nPoints;
1361 if (mode == CoordModeOrigin) {
1362 destPtr = points;
1363 for (srcPtr = pointArr; srcPtr < endPtr; srcPtr++) {
1364 destPtr->x = (int)srcPtr->x;
1365 destPtr->y = (int)srcPtr->y;
1366 destPtr++;
1367 }
1368 } else {
1369 POINT *lastPtr;
1370
1371 srcPtr = pointArr;
1372 destPtr = points;
1373 destPtr->x = (int)srcPtr->x;
1374 destPtr->y = (int)srcPtr->y;
1375 lastPtr = destPtr;
1376 srcPtr++, destPtr++;
1377 for (/*empty*/; srcPtr < endPtr; srcPtr++) {
1378 destPtr->x = lastPtr->x + (int)srcPtr->x;
1379 destPtr->y = lastPtr->y + (int)srcPtr->y;
1380 lastPtr = destPtr;
1381 destPtr++;
1382 }
1383 }
1384 DrawLine(display, drawable, gc, points, nPoints);
1385 Blt_Free(points);
1386 }
1387}
1388
1389
1390
1391/*
1392 *----------------------------------------------------------------------
1393 *
1394 * Blt_EmultateXDrawSegments --
1395 *
1396 * Draws multiple, unconnected lines. For each segment, draws a
1397 * line between (x1, y1) and (x2, y2). It draws the lines in the
1398 * order listed in the array of XSegment structures and does not
1399 * perform joining at coincident endpoints. For any given line,
1400 * does not draw a pixel more than once. If lines intersect, the
1401 * intersecting pixels are drawn multiple times.
1402 *
1403 * Results:
1404 * None.
1405 *
1406 * Side effects:
1407 * Draws unconnected line segments on the specified drawable.
1408 *
1409 *----------------------------------------------------------------------
1410 */
1411void
1412Blt_EmulateXDrawSegments(
1413 Display *display,
1414 Drawable drawable,
1415 GC gc,
1416 XSegment *segArr,
1417 int nSegments)
1418{
1419 HDC dc;
1420 register XSegment *segPtr, *endPtr;
1421 TkWinDCState state;
1422
1423 display->request++;
1424 if (drawable == None) {
1425 return;
1426 }
1427 dc = TkWinGetDrawableDC(display, drawable, &state);
1428 SetROP2(dc, tkpWinRopModes[gc->function]);
1429 if (gc->line_style != LineSolid) {
1430 /* Handle dotted lines specially */
1431 DashInfo info;
1432
1433 if (!GetDashInfo(dc, gc, &info)) {
1434 goto solidLine;
1435 }
1436 endPtr = segArr + nSegments;
1437 for (segPtr = segArr; segPtr < endPtr; segPtr++) {
1438 info.count = 0; /* Reset dash counter after every segment. */
1439 LineDDA(segPtr->x1, segPtr->y1, segPtr->x2, segPtr->y2, DrawDot,
1440 (LPARAM)&info);
1441 }
1442 } else {
1443 HPEN pen, oldPen;
1444
1445 solidLine:
1446 pen = Blt_GCToPen(dc, gc);
1447 oldPen = SelectPen(dc, pen);
1448 endPtr = segArr + nSegments;
1449 for (segPtr = segArr; segPtr < endPtr; segPtr++) {
1450 MoveToEx(dc, segPtr->x1, segPtr->y1, (LPPOINT)NULL);
1451 LineTo(dc, segPtr->x2, segPtr->y2);
1452 }
1453 DeletePen(SelectPen(dc, oldPen));
1454 }
1455 TkWinReleaseDrawableDC(drawable, dc, &state);
1456}
1457
1458/*
1459 *----------------------------------------------------------------------
1460 *
1461 * Blt_EmultateXDrawRectangle --
1462 *
1463 * Draws the outlines of the specified rectangle as if a
1464 * five-point PolyLine protocol request were specified for each
1465 * rectangle:
1466 *
1467 * [x,y] [x+width,y] [x+width,y+height] [x,y+height]
1468 * [x,y]
1469 *
1470 * Results:
1471 * None.
1472 *
1473 * Side effects:
1474 * Draws a rectangle on the specified drawable.
1475 *
1476 *----------------------------------------------------------------------
1477 */
1478void
1479Blt_EmulateXDrawRectangle(
1480 Display *display,
1481 Drawable drawable,
1482 GC gc,
1483 int x, int y,
1484 unsigned int width,
1485 unsigned int height)
1486{
1487 TkWinDCState state;
1488 HPEN pen, oldPen;
1489 HBRUSH brush, oldBrush;
1490 HDC dc;
1491
1492 if (drawable == None) {
1493 return;
1494 }
1495 dc = TkWinGetDrawableDC(display, drawable, &state);
1496 pen = Blt_GCToPen(dc, gc);
1497 brush = GetStockObject(NULL_BRUSH);
1498 oldPen = SelectPen(dc, pen);
1499 oldBrush = SelectBrush(dc, brush);
1500 SetROP2(dc, tkpWinRopModes[gc->function]);
1501 if (gc->line_style != LineSolid) {
1502 /* Handle dotted lines specially */
1503 register int x2, y2;
1504 DashInfo info;
1505
1506 if (!GetDashInfo(dc, gc, &info)) {
1507 goto solidLine;
1508 }
1509 x2 = x + width;
1510 y2 = y + height;
1511 LineDDA(x, y, x2, y, DrawDot, (LPARAM)&info);
1512 LineDDA(x2, y, x2, y2, DrawDot, (LPARAM)&info);
1513 LineDDA(x2, y2, x, y2, DrawDot, (LPARAM)&info);
1514 LineDDA(x, y2, x, y, DrawDot, (LPARAM)&info);
1515 } else {
1516 solidLine:
1517 Rectangle(dc, x, y, x + width + 1, y + height + 1);
1518 }
1519 DeletePen(SelectPen(dc, oldPen));
1520 DeleteBrush(SelectBrush(dc, oldBrush));
1521 TkWinReleaseDrawableDC(drawable, dc, &state);
1522}
1523
1524/*
1525 *----------------------------------------------------------------------
1526 *
1527 * Blt_EmulateXDrawPoints --
1528 *
1529 * Uses the foreground pixel and function components of the GC to
1530 * draw a multiple points into the specified drawable.
1531 * CoordModeOrigin treats all coordinates as relative to the
1532 * origin, and CoordModePrevious treats all coordinates after
1533 * the first as relative to the previous point.
1534 *
1535 * Results:
1536 * None.
1537 *
1538 * Side effects:
1539 * Draws points on the specified drawable.
1540 *
1541 *----------------------------------------------------------------------
1542 */
1543void
1544Blt_EmulateXDrawPoints(
1545 Display *display,
1546 Drawable drawable,
1547 GC gc,
1548 XPoint *pointArr,
1549 int nPoints,
1550 int mode)
1551{ /* Ignored. CoordModeOrigin is assumed. */
1552 HDC dc;
1553 register XPoint *pointPtr, *endPtr;
1554 TkWinDCState state;
1555
1556 display->request++;
1557 if (drawable == None) {
1558 return;
1559 }
1560 dc = TkWinGetDrawableDC(display, drawable, &state);
1561 SetROP2(dc, tkpWinRopModes[gc->function]);
1562 endPtr = pointArr + nPoints;
1563 for (pointPtr = pointArr; pointPtr < endPtr; pointPtr++) {
1564 SetPixelV(dc, pointPtr->x, pointPtr->y, gc->foreground);
1565 }
1566 TkWinReleaseDrawableDC(drawable, dc, &state);
1567}
1568
1569/*
1570 *----------------------------------------------------------------------
1571 *
1572 * Blt_EmultateXReparentWindow --
1573 *
1574 * If the specified window is mapped, automatically performs an
1575 * UnmapWindow request on it, removes it from its current
1576 * position in the hierarchy, and inserts it as the child of the
1577 * specified parent. The window is placed in the stacking order
1578 * on top with respect to sibling windows.
1579 *
1580 * Note: In WIN32 you can't reparent to/from another application.
1581 *
1582 * Results:
1583 * None.
1584 *
1585 * Side effects:
1586 * Reparents the specified window.
1587 *
1588 *----------------------------------------------------------------------
1589 */
1590void
1591Blt_EmulateXReparentWindow(
1592 Display *display,
1593 Window window,
1594 Window parent,
1595 int x,
1596 int y)
1597{
1598 HWND child, newParent;
1599
1600 child = Tk_GetHWND(window);
1601 newParent = Tk_GetHWND(parent);
1602 SetParent(child, newParent);
1603 SetWindowLong(child, GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN |
1604 WS_CLIPSIBLINGS);
1605
1606 XMoveWindow(display, window, x, y);
1607 XRaiseWindow(display, window);
1608 XMapWindow(display, window);
1609}
1610
1611void
1612Blt_EmulateXSetDashes(
1613 Display *display,
1614 GC gc,
1615 int dashOffset,
1616 _Xconst char *dashList,
1617 int n)
1618{
1619 gc->dashes = (unsigned char)strlen(dashList);
1620 gc->dash_offset = (int)dashList;
1621}
1622
1623/*
1624 *----------------------------------------------------------------------
1625 *
1626 * Blt_EmultateXDrawString --
1627 *
1628 * Draw a single string in the current font.
1629 *
1630 * Results:
1631 * None.
1632 *
1633 * Side effects:
1634 * Renders the specified string in the drawable.
1635 *
1636 *----------------------------------------------------------------------
1637 */
1638void
1639Blt_EmulateXDrawString(
1640 Display *display,
1641 Drawable drawable,
1642 GC gc,
1643 int x,
1644 int y,
1645 _Xconst char *string,
1646 int length)
1647{
1648 if (drawable == None) {
1649 return;
1650 }
1651 Tk_DrawChars(display, drawable, gc, (Tk_Font)gc->font, string, length,
1652 x, y);
1653}
1654
1655static void
1656TileArea(destDC, srcDC, tileOriginX, tileOriginY, tileWidth, tileHeight,
1657 x, y, width, height)
1658 HDC destDC, srcDC;
1659 int tileOriginX, tileOriginY, tileWidth, tileHeight;
1660 int x, y, width, height;
1661{
1662 int destX, destY;
1663 int destWidth, destHeight;
1664 int srcX, srcY;
1665 int xOrigin, yOrigin;
1666 int delta;
1667 int left, top, right, bottom;
1668
1669 xOrigin = x, yOrigin = y;
1670 if (x < tileOriginX) {
1671 delta = (tileOriginX - x) % tileWidth;
1672 if (delta > 0) {
1673 xOrigin -= (tileWidth - delta);
1674 }
1675 } else if (x > tileOriginX) {
1676 delta = (x - tileOriginX) % tileWidth;
1677 if (delta > 0) {
1678 xOrigin -= delta;
1679 }
1680 }
1681 if (y < tileOriginY) {
1682 delta = (tileOriginY - y) % tileHeight;
1683 if (delta > 0) {
1684 yOrigin -= (tileHeight - delta);
1685 }
1686 } else if (y >= tileOriginY) {
1687 delta = (y - tileOriginY) % tileHeight;
1688 if (delta > 0) {
1689 yOrigin -= delta;
1690 }
1691 }
1692#ifdef notdef
1693 PurifyPrintf("tile is (%d,%d,%d,%d)\n", tileOriginX, tileOriginY,
1694 tileWidth, tileHeight);
1695 PurifyPrintf("region is (%d,%d,%d,%d)\n", x, y, width, height);
1696 PurifyPrintf("starting at %d,%d\n", xOrigin, yOrigin);
1697#endif
1698 left = x;
1699 right = x + width;
1700 top = y;
1701 bottom = y + height;
1702 for (y = yOrigin; y < bottom; y += tileHeight) {
1703 srcY = 0;
1704 destY = y;
1705 destHeight = tileHeight;
1706 if (y < top) {
1707 srcY = (top - y);
1708 destHeight = tileHeight - srcY;
1709 destY = top;
1710 }
1711 if ((destY + destHeight) > bottom) {
1712 destHeight = (bottom - destY);
1713 }
1714 for (x = xOrigin; x < right; x += tileWidth) {
1715 srcX = 0;
1716 destX = x;
1717 destWidth = tileWidth;
1718 if (x < left) {
1719 srcX = (left - x);
1720 destWidth = tileWidth - srcX;
1721 destX = left;
1722 }
1723 if ((destX + destWidth) > right) {
1724 destWidth = (right - destX);
1725 }
1726#ifdef notdef
1727 PurifyPrintf("drawing pattern (%d,%d,%d,%d) at %d,%d\n",
1728 srcX , srcY, destWidth, destHeight, destX, destY);
1729#endif
1730 BitBlt(destDC, destX, destY, destWidth, destHeight,
1731 srcDC, srcX, srcY, SRCCOPY);
1732 }
1733 }
1734}
1735
1736/*
1737 *----------------------------------------------------------------------
1738 *
1739 * Blt_EmultateXFillRectangles --
1740 *
1741 * Fill multiple rectangular areas in the given drawable.
1742 * Handles tiling.
1743 *
1744 * Results:
1745 * None.
1746 *
1747 * Side effects:
1748 * Draws onto the specified drawable.
1749 *
1750 *----------------------------------------------------------------------
1751 */
1752
1753void
1754Blt_EmulateXFillRectangles(
1755 Display *display,
1756 Drawable drawable,
1757 GC gc,
1758 XRectangle *rectArr,
1759 int nRectangles)
1760{
1761 BITMAP bm;
1762 HBITMAP oldBitmap, hBitmap;
1763 HBRUSH oldBrush, hFgBrush, hBgBrush, hBrush;
1764 HDC hDC;
1765 HDC memDC;
1766 RECT rect;
1767 TkWinDCState state;
1768 TkWinDrawable *twdPtr;
1769 register XRectangle *rectPtr, *endPtr;
1770
1771 if (drawable == None) {
1772 return;
1773 }
1774 hDC = TkWinGetDrawableDC(display, drawable, &state);
1775 SetROP2(hDC, tkpWinRopModes[gc->function]);
1776
1777 switch(gc->fill_style) {
1778 case FillTiled:
1779 if (gc->tile == None) {
1780 goto fillSolid;
1781 }
1782#ifdef notdef
1783 if ((GetDeviceCaps(hDC, RASTERCAPS) & RC_BITBLT) == 0) {
1784 goto fillSolid;
1785 }
1786#endif
1787 twdPtr = (TkWinDrawable *)gc->tile;
1788 GetObject(twdPtr->bitmap.handle, sizeof(BITMAP), &bm);
1789 memDC = CreateCompatibleDC(hDC);
1790 oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle);
1791 endPtr = rectArr + nRectangles;
1792 for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) {
1793 TileArea(hDC, memDC, gc->ts_x_origin, gc->ts_y_origin, bm.bmWidth,
1794 bm.bmHeight, (int)rectPtr->x, (int)rectPtr->y,
1795 (int)rectPtr->width, (int)rectPtr->height);
1796 }
1797 SelectBitmap(memDC, oldBitmap);
1798 DeleteDC(memDC);
1799 break;
1800
1801 case FillOpaqueStippled:
1802 case FillStippled:
1803 if (gc->stipple == None) {
1804 goto fillSolid;
1805 }
1806 twdPtr = (TkWinDrawable *)gc->stipple;
1807 if (twdPtr->type != TWD_BITMAP) {
1808 panic("unexpected drawable type in stipple");
1809 }
1810 hBrush = CreatePatternBrush(twdPtr->bitmap.handle);
1811 SetBrushOrgEx(hDC, gc->ts_x_origin, gc->ts_y_origin, NULL);
1812 oldBrush = SelectBrush(hDC, hBrush);
1813 memDC = CreateCompatibleDC(hDC);
1814
1815 /*
1816 * For each rectangle, create a drawing surface which is the size of
1817 * the rectangle and fill it with the background color. Then merge the
1818 * result with the stipple pattern.
1819 */
1820 hFgBrush = CreateSolidBrush(gc->foreground);
1821 hBgBrush = CreateSolidBrush(gc->background);
1822 endPtr = rectArr + nRectangles;
1823 for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) {
1824 hBitmap = CreateCompatibleBitmap(hDC, rectPtr->width,
1825 rectPtr->height);
1826 oldBitmap = SelectObject(memDC, hBitmap);
1827 rect.left = rect.top = 0;
1828 rect.right = rectPtr->width;
1829 rect.bottom = rectPtr->height;
1830 FillRect(memDC, &rect, hFgBrush);
1831 BitBlt(hDC, rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height,
1832 memDC, 0, 0, COPYBG);
1833 if (gc->fill_style == FillOpaqueStippled) {
1834 FillRect(memDC, &rect, hBgBrush);
1835 BitBlt(hDC, rectPtr->x, rectPtr->y, rectPtr->width,
1836 rectPtr->height, memDC, 0, 0, COPYFG);
1837 }
1838 SelectObject(memDC, oldBitmap);
1839 DeleteObject(hBitmap);
1840 }
1841 DeleteBrush(hFgBrush);
1842 DeleteBrush(hBgBrush);
1843 DeleteDC(memDC);
1844 SelectBrush(hDC, oldBrush);
1845 DeleteBrush(hBrush);
1846 break;
1847
1848 case FillSolid:
1849 fillSolid:
1850 memDC = CreateCompatibleDC(hDC);
1851 hFgBrush = CreateSolidBrush(gc->foreground);
1852 endPtr = rectArr + nRectangles;
1853 for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) {
1854 hBitmap = CreateCompatibleBitmap(hDC, rectPtr->width,
1855 rectPtr->height);
1856 oldBitmap = SelectObject(memDC, hBitmap);
1857 rect.left = rect.top = 0;
1858 rect.right = rectPtr->width;
1859 rect.bottom = rectPtr->height;
1860 FillRect(memDC, &rect, hFgBrush);
1861 BitBlt(hDC, rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height,
1862 memDC, 0, 0, SRCCOPY);
1863 SelectObject(memDC, oldBitmap);
1864 DeleteObject(hBitmap);
1865 }
1866 DeleteBrush(hFgBrush);
1867 DeleteDC(memDC);
1868 break;
1869 }
1870 TkWinReleaseDrawableDC(drawable, hDC, &state);
1871}
1872
1873void
1874Blt_EmulateXFillRectangle(
1875 Display *display,
1876 Drawable drawable,
1877 GC gc,
1878 int x,
1879 int y,
1880 unsigned int width,
1881 unsigned int height)
1882{
1883 HDC hDC;
1884 RECT rect;
1885 TkWinDCState state;
1886
1887 if (drawable == None) {
1888 return;
1889 }
1890 hDC = TkWinGetDrawableDC(display, drawable, &state);
1891 SetROP2(hDC, tkpWinRopModes[gc->function]);
1892 rect.left = rect.top = 0;
1893 rect.right = width;
1894 rect.bottom = height;
1895
1896 switch(gc->fill_style) {
1897 case FillTiled:
1898 {
1899 TkWinDrawable *twdPtr;
1900 HBITMAP oldBitmap;
1901 HDC memDC;
1902 BITMAP bm;
1903
1904 if (gc->tile == None) {
1905 goto fillSolid;
1906 }
1907#ifdef notdef
1908 if ((GetDeviceCaps(hDC, RASTERCAPS) & RC_BITBLT) == 0) {
1909 goto fillSolid;
1910 }
1911#endif
1912 twdPtr = (TkWinDrawable *)gc->tile;
1913 /* The tiling routine needs to know the size of the bitmap */
1914 GetObject(twdPtr->bitmap.handle, sizeof(BITMAP), &bm);
1915
1916 memDC = CreateCompatibleDC(hDC);
1917 oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle);
1918 TileArea(hDC, memDC, gc->ts_x_origin, gc->ts_y_origin, bm.bmWidth,
1919 bm.bmHeight, x, y, width, height);
1920 SelectBitmap(memDC, oldBitmap);
1921 DeleteDC(memDC);
1922 }
1923 break;
1924
1925 case FillOpaqueStippled:
1926 case FillStippled:
1927 {
1928 TkWinDrawable *twdPtr;
1929 HBRUSH oldBrush, hBrush;
1930 HBRUSH hBrushFg, hBrushBg;
1931 HBITMAP oldBitmap, hBitmap;
1932 HDC memDC;
1933
1934 if (gc->stipple == None) {
1935 goto fillSolid;
1936 }
1937 twdPtr = (TkWinDrawable *)gc->stipple;
1938 if (twdPtr->type != TWD_BITMAP) {
1939 panic("unexpected drawable type in stipple");
1940 }
1941 hBrush = CreatePatternBrush(twdPtr->bitmap.handle);
1942 SetBrushOrgEx(hDC, gc->ts_x_origin, gc->ts_y_origin, NULL);
1943 oldBrush = SelectBrush(hDC, hBrush);
1944 memDC = CreateCompatibleDC(hDC);
1945
1946 hBrushFg = CreateSolidBrush(gc->foreground);
1947 hBrushBg = CreateSolidBrush(gc->background);
1948 hBitmap = CreateCompatibleBitmap(hDC, width, height);
1949 oldBitmap = SelectObject(memDC, hBitmap);
1950 FillRect(memDC, &rect, hBrushFg);
1951 SetBkMode(hDC, TRANSPARENT);
1952 BitBlt(hDC, x, y, width, height, memDC, 0, 0, COPYFG);
1953 if (gc->fill_style == FillOpaqueStippled) {
1954 FillRect(memDC, &rect, hBrushBg);
1955 BitBlt(hDC, x, y, width, height, memDC, 0, 0, COPYBG);
1956 }
1957 SelectBrush(hDC, oldBrush);
1958 SelectBitmap(memDC, oldBitmap);
1959 DeleteBrush(hBrushFg);
1960 DeleteBrush(hBrushBg);
1961 DeleteBrush(hBrush);
1962 DeleteBitmap(hBitmap);
1963 DeleteDC(memDC);
1964 }
1965 break;
1966
1967 case FillSolid:
1968 {
1969 HBRUSH hBrush;
1970 HBITMAP oldBitmap, hBitmap;
1971 HDC memDC;
1972
1973 fillSolid:
1974 /* TkWinFillRect(hDC, x, y, width, height, gc->foreground); */
1975 memDC = CreateCompatibleDC(hDC);
1976 hBrush = CreateSolidBrush(gc->foreground);
1977 hBitmap = CreateCompatibleBitmap(hDC, width, height);
1978 oldBitmap = SelectBitmap(memDC, hBitmap);
1979 rect.left = rect.top = 0;
1980 rect.right = width;
1981 rect.bottom = height;
1982 FillRect(memDC, &rect, hBrush);
1983 BitBlt(hDC, x, y, width, height, memDC, 0, 0, SRCCOPY);
1984 SelectObject(memDC, oldBitmap);
1985 DeleteBitmap(hBitmap);
1986 DeleteBrush(hBrush);
1987 DeleteDC(memDC);
1988 }
1989 break;
1990 }
1991 TkWinReleaseDrawableDC(drawable, hDC, &state);
1992}
1993
1994static BOOL
1995DrawChars(HDC dc, int x, int y, char *string, int length)
1996{
1997 BOOL result;
1998
1999#if (TCL_VERSION_NUMBER >= _VERSION(8,1,0))
2000 if (systemEncoding == NULL) {
2001 result = TextOutA(dc, x, y, string, length);
2002 } else {
2003 const unsigned short *wstring;
2004 Tcl_DString dString;
2005
2006 Tcl_DStringInit(&dString);
2007 Tcl_UtfToExternalDString(systemEncoding, string, length, &dString);
2008 length = Tcl_NumUtfChars(string, -1);
2009 wstring = (const unsigned short *)Tcl_DStringValue(&dString);
2010 result = TextOutW(dc, x, y, wstring, length);
2011 Tcl_DStringFree(&dString);
2012 }
2013#else
2014 result = TextOutA(dc, x, y, string, length);
2015#endif /* TCL_VERSION_NUMBER >= 8.1.0 */
2016 return result;
2017}
2018
2019int
2020Blt_DrawRotatedText(
2021 Display *display,
2022 Drawable drawable,
2023 int x, int y,
2024 double theta,
2025 TextStyle *tsPtr,
2026 TextLayout *textPtr)
2027{
2028 HFONT hFont, oldFont;
2029 TkWinDCState state;
2030 HDC hDC;
2031 int isActive;
2032 int bbWidth, bbHeight;
2033 double rotWidth, rotHeight;
2034 double sinTheta, cosTheta;
2035 Point2D p, q, center;
2036 register TextFragment *fragPtr, *endPtr;
2037#if (TCL_VERSION_NUMBER >= _VERSION(8,1,0))
2038 static int initialized = 0;
2039
2040 if (!initialized) {
2041 if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) {
2042 /*
2043 * If running NT, then we will be calling some Unicode functions
2044 * explictly. So, even if the Tcl system encoding isn't Unicode,
2045 * make sure we convert to/from the Unicode char set.
2046 */
2047 systemEncoding = Tcl_GetEncoding(NULL, "unicode");
2048 }
2049 initialized = 1;
2050 }
2051#endif
2052 hFont = CreateRotatedFont(tsPtr->gc->font, theta);
2053 if (hFont == NULL) {
2054 return FALSE;
2055 }
2056 isActive = (tsPtr->state & STATE_ACTIVE);
2057 hDC = TkWinGetDrawableDC(display, drawable, &state);
2058 SetROP2(hDC, tsPtr->gc->function);
2059 oldFont = SelectFont(hDC, hFont);
2060
2061 Blt_GetBoundingBox(textPtr->width, textPtr->height, theta, &rotWidth,
2062 &rotHeight, (Point2D *)NULL);
2063 bbWidth = ROUND(rotWidth);
2064 bbHeight = ROUND(rotHeight);
2065 Blt_TranslateAnchor(x, y, bbWidth, bbHeight, tsPtr->anchor, &x, &y);
2066 center.x = (double)textPtr->width * -0.5;
2067 center.y = (double)textPtr->height * -0.5;
2068 theta = (-theta / 180.0) * M_PI;
2069 sinTheta = sin(theta), cosTheta = cos(theta);
2070
2071 endPtr = textPtr->fragArr + textPtr->nFrags;
2072
2073 for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
2074 p.x = center.x + (double)fragPtr->x;
2075 p.y = center.y + (double)fragPtr->y;
2076 q.x = x + (p.x * cosTheta) - (p.y * sinTheta) + (bbWidth * 0.5);
2077 q.y = y + (p.x * sinTheta) + (p.y * cosTheta) + (bbHeight * 0.5);
2078 fragPtr->sx = ROUND(q.x);
2079 fragPtr->sy = ROUND(q.y);
2080 }
2081 SetBkMode(hDC, TRANSPARENT);
2082 SetTextAlign(hDC, TA_LEFT | TA_BASELINE);
2083
2084 if (tsPtr->state & (STATE_DISABLED | STATE_EMPHASIS)) {
2085 TkBorder *borderPtr = (TkBorder *) tsPtr->border;
2086 XColor *color1, *color2;
2087
2088 color1 = borderPtr->lightColor, color2 = borderPtr->darkColor;
2089 if (tsPtr->state & STATE_EMPHASIS) {
2090 XColor *hold;
2091
2092 hold = color1, color1 = color2, color2 = hold;
2093 }
2094 if (color1 != NULL) {
2095 SetTextColor(hDC, color1->pixel);
2096 for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
2097 DrawChars(hDC, fragPtr->sx, fragPtr->sy, fragPtr->text,
2098 fragPtr->count);
2099 }
2100 }
2101 if (color2 != NULL) {
2102 SetTextColor(hDC, color2->pixel);
2103 for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
2104 DrawChars(hDC, fragPtr->sx + 1, fragPtr->sy + 1, fragPtr->text,
2105 fragPtr->count);
2106 }
2107 }
2108 goto done; /* Done */
2109 }
2110 SetBkMode(hDC, TRANSPARENT);
2111 if ((tsPtr->shadow.offset > 0) && (tsPtr->shadow.color != NULL)) {
2112 SetTextColor(hDC, tsPtr->shadow.color->pixel);
2113 for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
2114 DrawChars(hDC, fragPtr->sx + tsPtr->shadow.offset,
2115 fragPtr->sy + tsPtr->shadow.offset, fragPtr->text,
2116 fragPtr->count);
2117 }
2118 }
2119 if (isActive) {
2120 SetTextColor(hDC, tsPtr->activeColor->pixel);
2121 } else {
2122 SetTextColor(hDC, tsPtr->color->pixel);
2123 }
2124
2125 for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) {
2126 DrawChars(hDC, fragPtr->sx, fragPtr->sy, fragPtr->text,
2127 fragPtr->count);
2128 }
2129
2130 if (isActive) {
2131 SetTextColor(hDC, tsPtr->color->pixel);
2132 }
2133 done:
2134 SelectFont(hDC, oldFont);
2135 DeleteFont(hFont);
2136 TkWinReleaseDrawableDC(drawable, hDC, &state);
2137 return TRUE;
2138}
2139
2140static void
2141DrawPixel(
2142 HDC hDC,
2143 int x,
2144 int y,
2145 COLORREF color)
2146{
2147 HDC memDC;
2148 HBRUSH hBrushFg;
2149 HBITMAP oldBitmap, hBitmap;
2150 RECT rect;
2151 int size;
2152
2153 size = 1;
2154 memDC = CreateCompatibleDC(hDC);
2155 hBrushFg = CreateSolidBrush(color);
2156 hBitmap = CreateCompatibleBitmap(hDC, size, size);
2157 oldBitmap = SelectObject(memDC, hBitmap);
2158 rect.left = rect.top = 0;
2159 rect.right = rect.bottom = size;
2160 FillRect(memDC, &rect, hBrushFg);
2161 BitBlt(hDC, x, y, size, size, memDC, 0, 0, SRCCOPY);
2162 SelectObject(memDC, oldBitmap);
2163 DeleteObject(hBitmap);
2164 DeleteBrush(hBrushFg);
2165 DeleteDC(memDC);
2166}
2167
2168/*
2169 *----------------------------------------------------------------------
2170 *
2171 * PixelateBitmap --
2172 *
2173 * Draws a masked bitmap in given device (should be printer)
2174 * context. Bit operations on print devices usually fail because
2175 * there's no way to read back from the device surface to get the
2176 * previous pixel values, rendering BitBlt useless. The bandaid
2177 * solution here is to draw 1x1 pixel rectangles at each
2178 * coordinate as directed by the the mask and source bitmaps.
2179 *
2180 * Results:
2181 * None.
2182 *
2183 * Side effects:
2184 * Draws onto the specified drawable.
2185 *
2186 *----------------------------------------------------------------------
2187 */
2188static void
2189PixelateBitmap(
2190 Display *display,
2191 Drawable drawable,
2192 Pixmap srcBitmap,
2193 Pixmap maskBitmap,
2194 int width,
2195 int height,
2196 GC gc,
2197 int destX,
2198 int destY)
2199{
2200 register int x, y;
2201 register int dx, dy;
2202 int pixel;
2203 unsigned char *srcBits;
2204 register unsigned char *srcPtr;
2205 int bitPos, bytesPerRow;
2206 HDC hDC;
2207 TkWinDCState state;
2208
2209 srcBits = Blt_GetBitmapData(display, srcBitmap, width, height,
2210 &bytesPerRow);
2211 if (srcBits == NULL) {
2212 return;
2213 }
2214 hDC = TkWinGetDrawableDC(display, drawable, &state);
2215 if (maskBitmap != None) {
2216 register unsigned char *maskPtr;
2217 unsigned char *maskBits;
2218 maskBits = Blt_GetBitmapData(display, maskBitmap, width, height,
2219 &bytesPerRow);
2220 bytesPerRow = ((width + 31) & ~31) / 8;
2221 for (dy = destY, y = height - 1; y >= 0; y--, dy++) {
2222 maskPtr = maskBits + (bytesPerRow * y);
2223 srcPtr = srcBits + (bytesPerRow * y);
2224 for (dx = destX, x = 0; x < width; x++, dx++) {
2225 bitPos = x % 8;
2226 pixel = (*maskPtr & (0x80 >> bitPos));
2227 if (pixel) {
2228 pixel = (*srcPtr & (0x80 >> bitPos));
2229 DrawPixel(hDC, dx, dy,
2230 (pixel) ? gc->foreground : gc->background);
2231 }
2232 if (bitPos == 7) {
2233 srcPtr++, maskPtr++;
2234 }
2235 } /* x */
2236 }
2237 Blt_Free(maskBits);
2238 } else {
2239 bytesPerRow = ((width + 31) & ~31) / 8;
2240 for (dy = destY, y = height - 1; y >= 0; y--, dy++) {
2241 srcPtr = srcBits + (bytesPerRow * y);
2242 for (dx = destX, x = 0; x < width; x++, dx++) {
2243 bitPos = x % 8;
2244 pixel = (*srcPtr & (0x80 >> bitPos));
2245 DrawPixel(hDC, dx, dy,
2246 (pixel) ? gc->foreground : gc->background);
2247 if (bitPos == 7) {
2248 srcPtr++;
2249 }
2250 }
2251 }
2252 }
2253 TkWinReleaseDrawableDC(drawable, hDC, &state);
2254 Blt_Free(srcBits);
2255}
2256
2257/*
2258 *----------------------------------------------------------------------
2259 *
2260 * Blt_EmulateXCopyPlane --
2261 *
2262 * Simplified version of XCopyPlane. Right now it ignores
2263 * function,
2264 * clip_x_origin,
2265 * clip_y_origin
2266 *
2267 * The plane argument must always be 1.
2268 *
2269 * This routine differs from the Tk version in how it handles
2270 * transparency. It uses a different method of drawing transparent
2271 * bitmaps that doesn't copy the background or use brushes. The
2272 * second change is to call a special routine when the destDC is
2273 * a printer. Stippling is done by a very slow brute-force
2274 * method of drawing 1x1 rectangles for each pixel (bleech).
2275 *
2276 * Results:
2277 * None.
2278 *
2279 * Side effects:
2280 * Changes the destination drawable.
2281 *
2282 *----------------------------------------------------------------------
2283 */
2284void
2285Blt_EmulateXCopyPlane(
2286 Display *display,
2287 Drawable src,
2288 Drawable dest,
2289 GC gc,
2290 int srcX,
2291 int srcY,
2292 unsigned int width,
2293 unsigned int height,
2294 int destX,
2295 int destY,
2296 unsigned long plane)
2297{
2298 HDC srcDC, destDC;
2299 TkWinDCState srcState, destState;
2300 TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask;
2301
2302 display->request++;
2303
2304 if (plane != 1) {
2305 panic("Unexpected plane specified for XCopyPlane");
2306 }
2307 srcDC = TkWinGetDrawableDC(display, src, &srcState);
2308
2309 if (src != dest) {
2310 destDC = TkWinGetDrawableDC(display, dest, &destState);
2311 } else {
2312 destDC = srcDC;
2313 }
2314 if ((clipPtr == NULL) || (clipPtr->type == TKP_CLIP_REGION)) {
2315 /*
2316 * Case 1: opaque bitmaps. Windows handles the conversion
2317 * from one bit to multiple bits by setting 0 to the
2318 * foreground color, and 1 to the background color (seems
2319 * backwards, but there you are).
2320 */
2321 if ((clipPtr != NULL) && (clipPtr->type == TKP_CLIP_REGION)) {
2322 SelectClipRgn(destDC, (HRGN) clipPtr->value.region);
2323 OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin);
2324 }
2325 SetBkMode(destDC, OPAQUE);
2326 SetBkColor(destDC, gc->foreground);
2327 SetTextColor(destDC, gc->background);
2328 BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY,
2329 SRCCOPY);
2330
2331 SelectClipRgn(destDC, NULL);
2332
2333 } else if (clipPtr->type == TKP_CLIP_PIXMAP) {
2334 Drawable mask;
2335 /*
2336 * Case 2: transparent bitmaps are handled by setting the
2337 * destination to the foreground color whenever the source
2338 * pixel is set.
2339 */
2340 /*
2341 * Case 3: two arbitrary bitmaps. Copy the source rectangle
2342 * into a color pixmap. Use the result as a brush when
2343 * copying the clip mask into the destination.
2344 */
2345 mask = clipPtr->value.pixmap;
2346
2347#if WINDEBUG
2348 PurifyPrintf("mask %s src\n", (mask == src) ? "==" : "!=");
2349 PurifyPrintf("GetDeviceCaps=%x\n",
2350 GetDeviceCaps(destDC, TECHNOLOGY) & DT_RASDISPLAY);
2351#endif
2352 {
2353 HDC maskDC;
2354 TkWinDCState maskState;
2355
2356 if (mask != src) {
2357 maskDC = TkWinGetDrawableDC(display, mask, &maskState);
2358 } else {
2359 maskDC = srcDC;
2360 }
2361 SetBkMode(destDC, OPAQUE);
2362 SetTextColor(destDC, gc->background);
2363 SetBkColor(destDC, gc->foreground);
2364 BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY,
2365 SRCINVERT);
2366 /*
2367 * Make sure we treat the mask as a monochrome bitmap.
2368 * We can get alpha-blending with non-black/white fg/bg
2369 * color selections.
2370 */
2371 SetTextColor(destDC, RGB(255,255,255));
2372 SetBkColor(destDC, RGB(0,0,0));
2373
2374 /* FIXME: Handle gc->clip_?_origin's */
2375 BitBlt(destDC, destX, destY, width, height, maskDC, 0, 0, SRCAND);
2376
2377 SetTextColor(destDC, gc->background);
2378 SetBkColor(destDC, gc->foreground);
2379 BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY,
2380 SRCINVERT);
2381 if (mask != src) {
2382 TkWinReleaseDrawableDC(mask, maskDC, &maskState);
2383 }
2384 }
2385 }
2386 if (src != dest) {
2387 TkWinReleaseDrawableDC(dest, destDC, &destState);
2388 }
2389 TkWinReleaseDrawableDC(src, srcDC, &srcState);
2390}
2391
2392/*
2393 *----------------------------------------------------------------------
2394 *
2395 * Blt_EmulateXCopyArea --
2396 *
2397 * Copies data from one drawable to another using block transfer
2398 * routines. The small enhancement over the version in Tk is
2399 * that it doesn't assume that the source and destination devices
2400 * have the same resolution. This isn't true when the destination
2401 * device is a printer.
2402 *
2403 * FIXME: not true anymore. delete this routine.
2404 *
2405 * Results:
2406 * None.
2407 *
2408 * Side effects:
2409 * Data is moved from a window or bitmap to a second window,
2410 * bitmap, or printer.
2411 *
2412 *----------------------------------------------------------------------
2413 */
2414void
2415Blt_EmulateXCopyArea(
2416 Display *display,
2417 Drawable src,
2418 Drawable dest,
2419 GC gc,
2420 int srcX, /* Source X-coordinate */
2421 int srcY, /* Source Y-coordinate. */
2422 unsigned int width, /* Width of area. */
2423 unsigned int height, /* Height of area. */
2424 int destX, /* Destination X-coordinate (in screen
2425 * coordinates). */
2426 int destY) /* Destination Y-coordinate (in screen
2427 * coordinates). */
2428{
2429 HDC srcDC, destDC;
2430 TkWinDCState srcState, destState;
2431 TkpClipMask *clipPtr;
2432
2433 srcDC = TkWinGetDrawableDC(display, src, &srcState);
2434 if (src != dest) {
2435 destDC = TkWinGetDrawableDC(display, dest, &destState);
2436 } else {
2437 destDC = srcDC;
2438 }
2439 clipPtr = (TkpClipMask *)gc->clip_mask;
2440 if ((clipPtr != NULL) && (clipPtr->type == TKP_CLIP_REGION)) {
2441 SelectClipRgn(destDC, (HRGN)clipPtr->value.region);
2442 OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin);
2443 }
2444
2445 BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY,
2446 bltModes[gc->function]);
2447 SelectClipRgn(destDC, NULL);
2448
2449 if (src != dest) {
2450 TkWinReleaseDrawableDC(dest, destDC, &destState);
2451 }
2452 TkWinReleaseDrawableDC(src, srcDC, &srcState);
2453}
2454
2455static void
2456StippleRegion(
2457 Display *display,
2458 HDC hDC, /* Device context: For polygons, clip
2459 * region will be installed. */
2460 GC gc,
2461 int x, int y,
2462 int width, int height)
2463{
2464 BITMAP bm;
2465 HBITMAP oldBitmap;
2466 HDC maskDC, memDC;
2467 Pixmap mask;
2468 TkWinDCState maskState;
2469 TkWinDrawable *twdPtr;
2470 int destX, destY, destWidth, destHeight;
2471 int dx, dy;
2472 int left, top, right, bottom;
2473 int srcX, srcY;
2474 int startX, startY; /* Starting upper left corner of region. */
2475
2476 twdPtr = (TkWinDrawable *)gc->stipple;
2477 GetObject(twdPtr->bitmap.handle, sizeof(BITMAP), &bm);
2478
2479 startX = x;
2480 if (x < gc->ts_x_origin) {
2481 dx = (gc->ts_x_origin - x) % bm.bmWidth;
2482 if (dx > 0) {
2483 startX -= (bm.bmWidth - dx);
2484 }
2485 } else if (x > gc->ts_x_origin) {
2486 dx = (x - gc->ts_x_origin) % bm.bmWidth;
2487 if (dx > 0) {
2488 startX -= dx;
2489 }
2490 }
2491 startY = y;
2492 if (y < gc->ts_y_origin) {
2493 dy = (gc->ts_y_origin - y) % bm.bmHeight;
2494 if (dy > 0) {
2495 startY -= (bm.bmHeight - dy);
2496 }
2497 } else if (y >= gc->ts_y_origin) {
2498 dy = (y - gc->ts_y_origin) % bm.bmHeight;
2499 if (dy > 0) {
2500 startY -= dy;
2501 }
2502 }
2503#ifdef notdef
2504 PurifyPrintf("tile is (%d,%d,%d,%d)\n", gc->ts_x_origin, gc->ts_y_origin,
2505 bm.bmWidth, bm.bmHeight);
2506 PurifyPrintf("region is (%d,%d,%d,%d)\n", x, y, width, height);
2507 PurifyPrintf("starting at %d,%d\n", startX, startY);
2508#endif
2509 left = x;
2510 right = x + width;
2511 top = y;
2512 bottom = y + height;
2513
2514 maskDC = memDC = CreateCompatibleDC(hDC);
2515 oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle);
2516 mask = gc->stipple;
2517 if (gc->fill_style == FillStippled) { /* With transparency. */
2518 if (gc->clip_mask != None) {
2519 TkpClipMask *clipPtr;
2520
2521 mask = gc->stipple;
2522 clipPtr = (TkpClipMask *)gc->clip_mask;
2523 if (clipPtr->type == TKP_CLIP_PIXMAP) {
2524 mask = clipPtr->value.pixmap;
2525 }
2526 }
2527 if (mask != gc->stipple) {
2528 maskDC = TkWinGetDrawableDC(display, mask, &maskState);
2529 }
2530 }
2531
2532 for (y = startY; y < bottom; y += bm.bmHeight) {
2533 srcY = 0;
2534 destY = y;
2535 destHeight = bm.bmHeight;
2536 if (y < top) {
2537 srcY = (top - y);
2538 destHeight = bm.bmHeight - srcY;
2539 destY = top;
2540 }
2541 if ((destY + destHeight) > bottom) {
2542 destHeight = (bottom - destY);
2543 }
2544 for (x = startX; x < right; x += bm.bmWidth) {
2545 srcX = 0;
2546 destX = x;
2547 destWidth = bm.bmWidth;
2548 if (x < left) {
2549 srcX = (left - x);
2550 destWidth = bm.bmWidth - srcX;
2551 destX = left;
2552 }
2553 if ((destX + destWidth) > right) {
2554 destWidth = (right - destX);
2555 }
2556#ifdef notdef
2557 PurifyPrintf("drawing pattern (%d,%d,%d,%d) at %d,%d\n",
2558 srcX , srcY, destWidth, destHeight, destX, destY);
2559#endif
2560 if (gc->fill_style == FillStippled) { /* With transparency. */
2561 SetBkMode(hDC, OPAQUE);
2562 SetTextColor(hDC, gc->background);
2563 SetBkColor(hDC, gc->foreground);
2564 BitBlt(hDC, destX, destY, destWidth, destHeight, memDC,
2565 srcX, srcY, SRCINVERT);
2566 SetTextColor(hDC, RGB(255,255,255));
2567 SetBkColor(hDC, RGB(0,0,0));
2568 BitBlt(hDC, destX, destY, destWidth, destHeight, maskDC,
2569 srcX, srcY, SRCAND);
2570 SetTextColor(hDC, gc->background);
2571 SetBkColor(hDC, gc->foreground);
2572 BitBlt(hDC, destX, destY, destWidth, destHeight, memDC,
2573 srcX, srcY, SRCINVERT);
2574 } else if (gc->fill_style == FillOpaqueStippled) { /* Opaque. */
2575 SetBkColor(hDC, gc->foreground);
2576 SetTextColor(hDC, gc->background);
2577 BitBlt(hDC, destX, destY, destWidth, destHeight, memDC,
2578 srcX, srcY, SRCCOPY);
2579 }
2580 }
2581 }
2582 SelectBitmap(memDC, oldBitmap);
2583 if (maskDC != memDC) {
2584 TkWinReleaseDrawableDC(mask, maskDC, &maskState);
2585 }
2586 DeleteDC(memDC);
2587}
2588
2589/*
2590 *----------------------------------------------------------------------
2591 *
2592 * Blt_EmulateXFillPolygon --
2593 *
2594 * This differs from Tk's XFillPolygon in that it works around
2595 * deficencies in Windows 95/98:
2596 * 1. Stippling bitmap is limited to 8x8.
2597 * 2. No tiling (with or without mask).
2598 * Results:
2599 * None.
2600 *
2601 *----------------------------------------------------------------------
2602 */
2603void
2604Blt_EmulateXFillPolygon(
2605 Display *display,
2606 Drawable drawable,
2607 GC gc,
2608 XPoint *pointPtr,
2609 int nPoints,
2610 int shape,
2611 int mode)
2612{
2613 HDC hDC;
2614 HRGN hRgn;
2615 POINT *p, *winPts, *endPtr;
2616 Region2D bbox;
2617 TkWinDCState state;
2618 int fillMode;
2619
2620 if (drawable == None) {
2621 return;
2622 }
2623
2624 /* Determine the bounding box of the polygon. */
2625 bbox.left = bbox.right = pointPtr->x;
2626 bbox.top = bbox.bottom = pointPtr->y;
2627
2628 hDC = TkWinGetDrawableDC(display, drawable, &state);
2629
2630 /* Allocate array of POINTS to create the polygon's path. */
2631 winPts = Blt_Malloc(sizeof(POINT) * nPoints);
2632 endPtr = winPts + nPoints;
2633 for (p = winPts; p < endPtr; p++) {
2634 if (pointPtr->x < bbox.left) {
2635 bbox.left = pointPtr->x;
2636 }
2637 if (pointPtr->x > bbox.right) {
2638 bbox.right = pointPtr->x;
2639 }
2640 if (pointPtr->y < bbox.top) {
2641 bbox.top = pointPtr->y;
2642 }
2643 if (pointPtr->y > bbox.bottom) {
2644 bbox.bottom = pointPtr->y;
2645 }
2646 p->x = pointPtr->x;
2647 p->y = pointPtr->y;
2648 pointPtr++;
2649 }
2650
2651 SetROP2(hDC, tkpWinRopModes[gc->function]);
2652 fillMode = (gc->fill_rule == EvenOddRule) ? ALTERNATE : WINDING;
2653
2654 if ((gc->fill_style == FillStippled) ||
2655 (gc->fill_style == FillOpaqueStippled)) {
2656 int width, height;
2657
2658 /* Points are offsets within the bounding box. */
2659 for (p = winPts; p < endPtr; p++) {
2660 p->x -= bbox.left;
2661 p->y -= bbox.top;
2662 }
2663 /* Use the polygon as a clip path. */
2664 LPtoDP(hDC, winPts, nPoints);
2665 hRgn = CreatePolygonRgn(winPts, nPoints, fillMode);
2666 SelectClipRgn(hDC, hRgn);
2667 OffsetClipRgn(hDC, bbox.left, bbox.top);
2668
2669 /* Tile the bounding box. */
2670 width = bbox.right - bbox.left + 1;
2671 height = bbox.bottom - bbox.top + 1;
2672 StippleRegion(display, hDC, gc, bbox.left, bbox.top, width, height);
2673
2674 SelectClipRgn(hDC, NULL);
2675 DeleteRgn(hRgn);
2676 } else {
2677 HPEN oldPen;
2678 HBRUSH oldBrush;
2679
2680 /*
2681 * FIXME: Right now, we're assuming that it's solid or
2682 * stippled and ignoring tiling. I'll merge the bits from
2683 * Blt_TilePolygon later.
2684 */
2685 oldPen = SelectPen(hDC, GetStockObject(NULL_PEN));
2686 oldBrush = SelectBrush(hDC, CreateSolidBrush(gc->foreground));
2687 SetPolyFillMode(hDC, fillMode);
2688 Polygon(hDC, winPts, nPoints);
2689 SelectPen(hDC, oldPen);
2690 DeleteBrush(SelectBrush(hDC, oldBrush));
2691 }
2692 Blt_Free(winPts);
2693 TkWinReleaseDrawableDC(drawable, hDC, &state);
2694}
Note: See TracBrowser for help on using the repository browser.