/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwindraw.c
ViewVC logotype

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwindraw.c

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25