/[gnustep]/gnustep/core/back/Source/xlib/XGGState.m
ViewVC logotype

Contents of /gnustep/core/back/Source/xlib/XGGState.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.18 - (show annotations) (download)
Sun Sep 21 03:19:17 2003 UTC (20 years, 7 months ago) by fedor
Branch: MAIN
CVS Tags: back-0_9_0
Changes since 1.17: +97 -0 lines
Add GSReadRect support to xlib backend

1 /* XGGState - Implements graphic state drawing for Xlib
2
3 Copyright (C) 1998 Free Software Foundation, Inc.
4
5 Written by: Adam Fedor <fedor@gnu.org>
6 Date: Nov 1998
7
8 This file is part of the GNU Objective C User Interface Library.
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Library General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
14
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Library General Public License for more details.
19
20 You should have received a copy of the GNU Library General Public
21 License along with this library; if not, write to the Free
22 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
23 */
24
25 #include "config.h"
26 #include <Foundation/NSObjCRuntime.h>
27 #include <AppKit/NSBezierPath.h>
28 #include <AppKit/NSFont.h>
29 #include <AppKit/NSGraphics.h>
30
31 #include "xlib/XGGeometry.h"
32 #include "xlib/XGContext.h"
33 #include "xlib/XGGState.h"
34 #include "xlib/XGContext.h"
35 #include "xlib/XGPrivate.h"
36 #include "math.h"
37
38 #define XDPY (((RContext *)context)->dpy)
39
40 static BOOL shouldDrawAlpha = YES;
41
42 #define CHECK_GC \
43 if (!xgcntxt) \
44 [self createGraphicContext]
45
46 #define COPY_GC_ON_CHANGE \
47 CHECK_GC; \
48 if (sharedGC == YES) \
49 [self copyGraphicContext]
50
51
52 u_long
53 xrRGBToPixel(RContext* context, device_color_t color)
54 {
55 XColor cc;
56 RColor rcolor;
57 rcolor.red = 255. * color.field[0];
58 rcolor.green = 255. * color.field[1];
59 rcolor.blue = 255. * color.field[2];
60 rcolor.alpha = 0;
61 RGetClosestXColor(context, &rcolor, &cc);
62 return cc.pixel;
63 }
64
65 @interface XGGState (Private)
66 - (void) _alphaBuffer: (gswindow_device_t *)dest_win;
67 - (void) _paintPath: (ctxt_object_t) drawType;
68 - (void) createGraphicContext;
69 - (void) copyGraphicContext;
70 - (void) setAlphaColor: (float)color;
71 @end
72
73 @implementation XGGState
74
75 static Region emptyRegion;
76
77 + (void) initialize
78 {
79 static BOOL beenHere = NO;
80
81 if (beenHere == NO)
82 {
83 XPoint pts[5];
84 id obj = [[NSUserDefaults standardUserDefaults]
85 stringForKey: @"GraphicCompositing"];
86 if (obj)
87 shouldDrawAlpha = [obj boolValue];
88
89 beenHere = YES;
90 pts[0].x = 0; pts[0].y = 0;
91 pts[1].x = 0; pts[1].y = 0;
92 pts[2].x = 0; pts[2].y = 0;
93 pts[3].x = 0; pts[3].y = 0;
94 pts[4].x = 0; pts[4].y = 0;
95 emptyRegion = XPolygonRegion(pts, 5, WindingRule);
96 NSAssert(XEmptyRegion(emptyRegion), NSInternalInconsistencyException);
97 }
98 }
99
100 /* Designated initializer. */
101 - initWithDrawContext: (GSContext *)drawContext
102 {
103 [super initWithDrawContext: drawContext];
104
105 drawMechanism = -1;
106 draw = 0;
107 alpha_buffer = 0;
108 xgcntxt = None;
109 agcntxt = None;
110 return self;
111 }
112
113 - (void) dealloc
114 {
115 if ( sharedGC == NO && xgcntxt )
116 {
117 XFreeGC(XDPY, xgcntxt);
118 }
119 if (agcntxt)
120 XFreeGC(XDPY, agcntxt);
121 if (clipregion)
122 XDestroyRegion(clipregion);
123 [super dealloc];
124 }
125
126 - (id) deepen
127 {
128 [super deepen];
129
130 // Copy the GC
131 if (draw != 0)
132 [self copyGraphicContext];
133
134 /* Force a new one to be created */
135 agcntxt = None;
136
137 // Copy the clipregion
138 if (clipregion)
139 {
140 Region region = XCreateRegion();
141
142 XIntersectRegion(clipregion, clipregion, region);
143 self->clipregion = region;
144 }
145
146 return self;
147 }
148
149 - (void) setWindowDevice: (void *)device
150 {
151 XGServer *srv;
152 gswindow_device_t *gs_win;
153
154 gs_win = (gswindow_device_t *)windevice = device;
155 draw = GET_XDRAWABLE(gs_win);
156 [self setGraphicContext: gs_win->gc];
157 alpha_buffer = 0;
158 drawingAlpha = NO;
159
160 /* We know the current server sent us this */
161 srv = (XGServer *)GSCurrentServer();
162 context = [srv xrContextForScreen: gs_win->screen];
163 drawMechanism = [srv drawMechanismForScreen: gs_win->screen];
164
165 if (gs_win != NULL && gs_win->alpha_buffer != 0)
166 {
167 alpha_buffer = gs_win->alpha_buffer;
168 if (shouldDrawAlpha)
169 drawingAlpha = YES;
170 }
171 }
172
173 - (void) setDrawable: (Drawable)theDrawable;
174 {
175 draw = theDrawable;
176 }
177
178 - (void) setGraphicContext: (GC)xGraphicContext
179 {
180 GC source;
181 unsigned long mask;
182 BOOL old_shared;
183
184 source = xgcntxt;
185 old_shared = sharedGC;
186 if (xGraphicContext == None)
187 return;
188 if (xGraphicContext == xgcntxt)
189 return;
190
191 xgcntxt = xGraphicContext;
192 sharedGC = YES; /* Not sure if we really own the GC */
193 /* Update the GC to reflect our settings */
194 if (source == None)
195 return;
196 mask = GCForeground | GCFont | GCFunction | GCFillRule |
197 GCBackground | GCCapStyle | GCJoinStyle | GCLineWidth |
198 GCLineStyle | GCDashOffset | GCDashList;
199 XCopyGC(XDPY, source, mask, xgcntxt);
200
201 if (source != None && old_shared == NO)
202 XFreeGC(XDPY, source);
203 }
204
205 /* Set various characteristics of the graphic context */
206 - (void) setGCValues: (XGCValues)values withMask: (int)mask
207 {
208 COPY_GC_ON_CHANGE;
209 if (xgcntxt == 0)
210 return;
211 XChangeGC(XDPY, xgcntxt, mask, &values);
212 }
213
214 /* Set the GC clipmask. */
215 - (void) setClipMask
216 {
217 COPY_GC_ON_CHANGE;
218 if (xgcntxt == 0)
219 return;
220 if (!clipregion)
221 {
222 XSetClipMask(XDPY, xgcntxt, None);
223 return;
224 }
225
226 XSetRegion(XDPY, xgcntxt, clipregion);
227 }
228
229 /* Returns the clip region, which must be freed by the caller */
230 - (Region) xClipRegion
231 {
232 Region region = XCreateRegion();
233
234 if (clipregion)
235 XIntersectRegion(clipregion, clipregion, region);
236 else
237 XIntersectRegion(emptyRegion, emptyRegion, region);
238
239 return region;
240 }
241
242 - (void) setColor: (device_color_t *)color state: (color_state_t)cState
243 {
244 device_color_t c;
245 [super setColor: color state: cState];
246 if (context == NULL)
247 {
248 /* Window device isn't set yet */
249 return;
250 }
251 c = *color;
252 gsColorToRGB(&c);
253 gcv.foreground = xrRGBToPixel(context, c);
254 [self setGCValues: gcv withMask: GCForeground];
255 }
256
257 - (void) setAlphaColor: (float)value
258 {
259 device_color_t color;
260 if (context == NULL)
261 {
262 /* Window device isn't set yet */
263 return;
264 }
265 gsMakeColor(&color, rgb_colorspace, value, value, value, 0);
266 gcv.foreground = xrRGBToPixel(context, color);
267 if (agcntxt == None)
268 agcntxt = XCreateGC(XDPY, draw, GCForeground, &gcv);
269 else
270 XChangeGC(XDPY, agcntxt, GCForeground, &gcv);
271 }
272
273 - (void) copyGraphicContext
274 {
275 GC source;
276 unsigned long mask;
277
278 if (draw == 0)
279 {
280 DPS_ERROR(DPSinvalidid, @"Copying a GC with no Drawable defined");
281 return;
282 }
283
284 source = xgcntxt;
285 mask = 0xffffffff; /* Copy everything (Hopefully) */
286 xgcntxt = XCreateGC(XDPY, draw, 0, NULL);
287 XCopyGC(XDPY, source, mask, xgcntxt);
288 sharedGC = NO;
289 return;
290 }
291
292 // Create a default graphics context.
293 - (void) createGraphicContext
294 {
295 if (draw == 0)
296 {
297 /* This could happen with a defered window */
298 DPS_WARN(DPSinvalidid, @"Creating a GC with no Drawable defined");
299 return;
300 }
301 gcv.function = GXcopy;
302 gcv.background = ((RContext *)context)->white;
303 gcv.foreground = ((RContext *)context)->black;
304 gcv.plane_mask = AllPlanes;
305 gcv.line_style = LineSolid;
306 gcv.fill_style = FillSolid;
307 gcv.fill_rule = WindingRule;
308 xgcntxt = XCreateGC(XDPY, draw,
309 GCFunction | GCForeground | GCBackground | GCPlaneMask
310 | GCFillStyle | GCFillRule| GCLineStyle,
311 &gcv);
312 [self setClipMask];
313 sharedGC = NO;
314 return;
315 }
316
317 - (NSRect)clipRect
318 {
319 XRectangle r;
320 r.width = 0; r.height = 0;
321 if (clipregion)
322 XClipBox(clipregion, &r);
323 return NSMakeRect(r.x, r.y, r.width-1, r.height-1);
324 }
325
326 - (BOOL) hasGraphicContext
327 {
328 return (xgcntxt) ? YES : NO;
329 }
330
331 - (BOOL) hasDrawable
332 {
333 return (draw ? YES : NO);
334 }
335
336 - (void *) windevice
337 {
338 return windevice;
339 }
340
341 - (Drawable) drawable
342 {
343 return draw;
344 }
345
346 - (GC) graphicContext
347 {
348 return xgcntxt;
349 }
350
351 - (void) copyBits: (XGGState*)source fromRect: (NSRect)aRect
352 toPoint: (NSPoint)aPoint
353 {
354 XRectangle dst;
355 XRectangle src;
356 NSRect flushRect;
357 Drawable from;
358
359 CHECK_GC;
360 if (draw == 0)
361 {
362 DPS_WARN(DPSinvalidid, @"No Drawable defined for copyBits");
363 return;
364 }
365 from = source->draw;
366 if (from == 0)
367 {
368 DPS_ERROR(DPSinvalidid, @"No source Drawable defined for copyBits");
369 return;
370 }
371
372 src = XGViewRectToX(source, aRect);
373 flushRect.size = aRect.size;
374 flushRect.origin = aPoint;
375 dst = XGViewRectToX(self, flushRect);
376 if (source->ctm->matrix.m22 < 0 && ctm->matrix.m22 > 0) dst.y += src.height;
377 if (source->ctm->matrix.m22 > 0 && ctm->matrix.m22 < 0) dst.y -= src.height;
378 NSDebugLLog(@"XGGraphics", @"Copy area from %@ to %@",
379 NSStringFromRect(aRect), NSStringFromPoint(aPoint));
380 XCopyArea(XDPY, from, draw, xgcntxt,
381 src.x, src.y, src.width, src.height, dst.x, dst.y);
382 }
383
384 - (void) _alphaBuffer: (gswindow_device_t *)dest_win
385 {
386 if (dest_win->alpha_buffer == 0
387 && dest_win->type != NSBackingStoreNonretained)
388 {
389 dest_win->alpha_buffer = XCreatePixmap(XDPY, draw,
390 NSWidth(dest_win->xframe),
391 NSHeight(dest_win->xframe),
392 dest_win->depth);
393
394 /* Fill alpha also (opaque by default) */
395 [self setAlphaColor: 1];
396 XFillRectangle(XDPY, dest_win->alpha_buffer, agcntxt, 0, 0,
397 NSWidth(dest_win->xframe), NSHeight(dest_win->xframe));
398 }
399 if (shouldDrawAlpha && dest_win->alpha_buffer != 0)
400 {
401 alpha_buffer = dest_win->alpha_buffer;
402 drawingAlpha = YES;
403 }
404 }
405
406 - (void) _compositeGState: (XGGState *) source
407 fromRect: (NSRect) fromRect
408 toPoint: (NSPoint) toPoint
409 op: (NSCompositingOperation) op
410 fraction: (float)delta
411 {
412 XRectangle srect;
413 XRectangle drect;
414
415 XPoint toXPoint;
416
417 RXImage *source_im;
418 RXImage *source_alpha;
419
420 RXImage *dest_im;
421 RXImage *dest_alpha;
422
423 gswindow_device_t *source_win;
424 gswindow_device_t *dest_win;
425
426
427 // --- get source information --------------------------------------------------
428 NSDebugLLog(@"XGGraphics", @"Composite from %@ to %@",
429 NSStringFromRect(fromRect), NSStringFromPoint(toPoint));
430
431 if (!source)
432 source = self;
433
434 source_win = (gswindow_device_t *)source->windevice;
435 if (!source_win)
436 {
437 DPS_ERROR(DPSinvalidid, @"Invalid composite source gstate");
438 return;
439 }
440
441 if (source_win->buffer == 0 && source_win->map_state != IsViewable)
442 {
443 /* Can't get pixel information from a window that isn't mapped */
444 DPS_ERROR(DPSinvalidaccess, @"Invalid gstate buffer");
445 return;
446 }
447
448
449 // --- get destination information ----------------------------------------------
450
451 dest_win = (gswindow_device_t *)windevice;
452 if (!dest_win)
453 {
454 DPS_ERROR(DPSinvalidid, @"Invalid composite gstate");
455 return;
456 }
457
458 if (dest_win->buffer == 0 && dest_win->map_state != IsViewable)
459 {
460 /* Why bother drawing? */
461 return;
462 }
463
464
465 // --- determine region to draw --------------------------------------
466
467 {
468 NSRect flushRect; // destination rectangle
469 // in View coordinates
470
471 flushRect.size = fromRect.size;
472 flushRect.origin = toPoint;
473
474 flushRect.origin = [ctm pointInMatrixSpace: flushRect.origin];
475 drect = XGWindowRectToX(self, flushRect);
476 if (source->ctm->matrix.m22 < 0) drect.y += drect.height;
477
478 toXPoint.x = drect.x;
479 toXPoint.y = drect.y;
480
481 srect = XGViewRectToX (source, fromRect);
482
483 clipXRectsForCopying (source_win, &srect, dest_win, &drect);
484
485 if (XGIsEmptyRect(drect))
486 return;
487
488 }
489
490 // --- get destination XImage ----------------------------------------
491
492 if (draw == dest_win->ident && dest_win->visibility < 0)
493 {
494 /* Non-backingstore window isn't visible, so just make up the image */
495 dest_im = RCreateXImage(context, dest_win->depth,
496 XGWidth(drect), XGHeight(drect));
497 }
498 else
499 {
500 dest_im = RGetXImage(context, draw, XGMinX(drect), XGMinY (drect),
501 XGWidth (drect), XGHeight (drect));
502 }
503
504 if (dest_im->image == 0)
505 {//FIXME: Should not happen,
506 DPS_ERROR (DPSinvalidaccess, @"unable to fetch destination image");
507 return;
508 }
509
510
511 // --- get source XImage ---------------------------------------------
512
513 source_im = RGetXImage ((RContext *)context,
514 GET_XDRAWABLE (source_win),
515 XGMinX(srect), XGMinY(srect),
516 XGWidth(srect), XGHeight(srect));
517
518 // --- create alpha XImage -------------------------------------------
519 /* Force creation of our alpha buffer */
520 [self _alphaBuffer: dest_win];
521
522 /* Composite it */
523 source_alpha = RGetXImage((RContext *)context, source_win->alpha_buffer,
524 XGMinX(srect), XGMinY(srect),
525 XGWidth(srect), XGHeight(srect));
526
527 if (alpha_buffer)
528 {
529 dest_alpha = RGetXImage((RContext *)context, alpha_buffer,
530 XGMinX(drect), XGMinY(drect),
531 XGWidth(drect), XGHeight(drect));
532 }
533 else
534 {
535 dest_alpha = NULL;
536 }
537
538 // --- THE REAL WORK IS DONE HERE! -----------------------------------
539
540 {
541 XRectangle xdrect = { 0, 0, XGWidth (drect), XGHeight (drect) };
542
543 _pixmap_combine_alpha((RContext *)context, source_im, source_alpha,
544 dest_im, dest_alpha, xdrect,
545 op, drawMechanism, delta);
546 }
547
548
549 // --- put result back in the drawable -------------------------------
550
551 RPutXImage((RContext *)context, draw, xgcntxt, dest_im, 0, 0,
552 XGMinX(drect), XGMinY(drect), XGWidth(drect), XGHeight(drect));
553
554 if (dest_alpha)
555 {
556 RPutXImage((RContext *)context, dest_win->alpha_buffer,
557 xgcntxt, dest_alpha, 0, 0,
558 XGMinX(drect), XGMinY(drect),
559 XGWidth(drect), XGHeight(drect));
560 RDestroyXImage((RContext *)context, dest_alpha);
561 }
562
563 // --- clean up ------------------------------------------------------
564
565 RDestroyXImage((RContext *)context, dest_im);
566 RDestroyXImage((RContext *)context, source_im);
567 if (source_alpha)
568 RDestroyXImage((RContext *)context, source_alpha);
569 }
570
571 - (void) compositeGState: (GSGState *)source
572 fromRect: (NSRect)aRect
573 toPoint: (NSPoint)aPoint
574 op: (NSCompositingOperation)op
575 {
576 BOOL do_copy, source_alpha;
577 XGCValues comp_gcv;
578
579 if (!source)
580 source = self;
581
582 /* If we have no drawable, we can't proceed. */
583 if (draw == 0)
584 {
585 DPS_WARN(DPSinvalidid, @"No Drawable defined for composite");
586 return;
587 }
588
589 /* Check alpha */
590 #define CHECK_ALPHA \
591 do { \
592 gswindow_device_t *source_win; \
593 source_win = (gswindow_device_t *)[(XGGState *)source windevice]; \
594 source_alpha = (source_win && source_win->alpha_buffer); \
595 } while (0)
596
597 do_copy = NO;
598 switch (op)
599 {
600 case NSCompositeClear:
601 do_copy = YES;
602 comp_gcv.function = GXclear;
603 break;
604 case NSCompositeCopy:
605 do_copy = YES;
606 comp_gcv.function = GXcopy;
607 break;
608 case NSCompositeSourceOver:
609 CHECK_ALPHA;
610 if (source_alpha == NO)
611 do_copy = YES;
612 else
613 do_copy = NO;
614 comp_gcv.function = GXcopy;
615 break;
616 case NSCompositeSourceIn:
617 CHECK_ALPHA;
618 if (source_alpha == NO && drawingAlpha == NO)
619 do_copy = YES;
620 else
621 do_copy = NO;
622 comp_gcv.function = GXcopy;
623 break;
624 case NSCompositeSourceOut:
625 do_copy = NO;
626 comp_gcv.function = GXcopy;
627 break;
628 case NSCompositeSourceAtop:
629 CHECK_ALPHA;
630 if (source_alpha == NO && drawingAlpha == NO)
631 do_copy = YES;
632 else
633 do_copy = NO;
634 comp_gcv.function = GXcopy;
635 break;
636 case NSCompositeDestinationOver:
637 CHECK_ALPHA;
638 if (drawingAlpha == NO)
639 return;
640 else
641 do_copy = NO;
642 comp_gcv.function = GXcopy;
643 break;
644 case NSCompositeDestinationIn:
645 CHECK_ALPHA;
646 if (source_alpha == NO && drawingAlpha == NO)
647 return;
648 else
649 do_copy = NO;
650 comp_gcv.function = GXcopy;
651 break;
652 case NSCompositeDestinationOut:
653 do_copy = NO;
654 comp_gcv.function = GXcopy;
655 break;
656 case NSCompositeDestinationAtop:
657 CHECK_ALPHA;
658 if (source_alpha == NO && drawingAlpha == NO)
659 return;
660 else
661 do_copy = NO;
662 comp_gcv.function = GXcopy;
663 break;
664 case NSCompositeXOR:
665 do_copy = NO;
666 comp_gcv.function = GXxor;
667 break;
668 case NSCompositePlusDarker:
669 do_copy = NO;
670 comp_gcv.function = GXcopy;
671 break;
672 case NSCompositeHighlight:
673 do_copy = NO;
674 comp_gcv.function = GXxor;
675 break;
676 case NSCompositePlusLighter:
677 do_copy = NO;
678 comp_gcv.function = GXcopy;
679 break;
680 }
681
682 if (comp_gcv.function != GXcopy)
683 [self setGCValues: comp_gcv withMask: GCFunction];
684
685 if (shouldDrawAlpha == NO)
686 do_copy = YES;
687
688 if (do_copy)
689 {
690 [self copyBits: (XGGState *)source fromRect: aRect toPoint: aPoint];
691 }
692 else
693 {
694 [self _compositeGState: (XGGState *)source
695 fromRect: aRect
696 toPoint: aPoint
697 op: op
698 fraction: 1];
699 }
700
701
702 if (comp_gcv.function != GXcopy)
703 {
704 comp_gcv.function = GXcopy;
705 [self setGCValues: comp_gcv withMask: GCFunction];
706 }
707 }
708
709 - (void) dissolveGState: (GSGState *)source
710 fromRect: (NSRect)aRect
711 toPoint: (NSPoint)aPoint
712 delta: (float)delta
713 {
714 /* If we have no drawable, we can't proceed. */
715 if (draw == 0)
716 {
717 DPS_WARN(DPSinvalidid, @"No Drawable defined for dissolve");
718 return;
719 }
720
721 if (shouldDrawAlpha == NO)
722 {
723 /* No alpha buffers */
724 [self copyBits: (XGGState *)source fromRect: aRect toPoint: aPoint];
725 }
726 else
727 {
728 [self _compositeGState: (XGGState *)source
729 fromRect: aRect
730 toPoint: aPoint
731 op: NSCompositeSourceOver
732 fraction: delta];
733 }
734
735 }
736
737 - (void) compositerect: (NSRect)aRect
738 op: (NSCompositingOperation)op
739 {
740 float gray;
741
742 [self DPScurrentgray: &gray];
743 if (fabs(gray - 0.667) < 0.005)
744 [self DPSsetgray: 0.333];
745 else
746 [self DPSsetrgbcolor: 0.121 : 0.121 : 0];
747
748 /* FIXME: Really need alpha dithering to do this right - combine with
749 XGBitmapImageRep code? */
750 switch (op)
751 {
752 case NSCompositeClear:
753 gcv.function = GXclear;
754 break;
755 case NSCompositeCopy:
756 gcv.function = GXcopy;
757 break;
758 case NSCompositeSourceOver:
759 gcv.function = GXcopy;
760 break;
761 case NSCompositeSourceIn:
762 gcv.function = GXcopy;
763 break;
764 case NSCompositeSourceOut:
765 gcv.function = GXcopy;
766 break;
767 case NSCompositeSourceAtop:
768 gcv.function = GXcopy;
769 break;
770 case NSCompositeDestinationOver:
771 gcv.function = GXcopy;
772 break;
773 case NSCompositeDestinationIn:
774 gcv.function = GXcopy;
775 break;
776 case NSCompositeDestinationOut:
777 gcv.function = GXcopy;
778 break;
779 case NSCompositeDestinationAtop:
780 gcv.function = GXcopy;
781 break;
782 case NSCompositeXOR:
783 gcv.function = GXcopy;
784 break;
785 case NSCompositePlusDarker:
786 gcv.function = GXcopy;
787 break;
788 case NSCompositeHighlight:
789 gcv.function = GXxor;
790 break;
791 case NSCompositePlusLighter:
792 gcv.function = GXcopy;
793 break;
794 default:
795 gcv.function = GXcopy;
796 break;
797 }
798 [self setGCValues: gcv withMask: GCFunction];
799 [self DPSrectfill: NSMinX(aRect) : NSMinY(aRect)
800 : NSWidth(aRect) : NSHeight(aRect)];
801
802 if (gcv.function != GXcopy)
803 {
804 gcv.function = GXcopy;
805 [self setGCValues: gcv withMask: GCFunction];
806 }
807 [self DPSsetgray: gray];
808 }
809
810 /* Paint the current path using Xlib calls. All coordinates should already
811 have been transformed to device coordinates. */
812 - (void) _doPath: (XPoint*)pts : (int)count draw: (ctxt_object_t)type
813 {
814 int fill_rule;
815
816 COPY_GC_ON_CHANGE;
817 if (draw == 0)
818 {
819 DPS_WARN(DPSinvalidid, @"No Drawable defined for path");
820 return;
821 }
822 fill_rule = WindingRule;
823 switch (type)
824 {
825 case path_stroke:
826 // Hack: Only draw when alpha is not zero
827 if (drawingAlpha == NO || strokeColor.field[AINDEX] != 0.0)
828 XDrawLines(XDPY, draw, xgcntxt, pts, count, CoordModeOrigin);
829 if (drawingAlpha)
830 {
831 NSAssert(alpha_buffer, NSInternalInconsistencyException);
832
833 [self setAlphaColor: strokeColor.field[AINDEX]];
834 XDrawLines(XDPY, alpha_buffer, agcntxt, pts, count, CoordModeOrigin);
835 }
836 break;
837 case path_eofill:
838 gcv.fill_rule = EvenOddRule;
839 [self setGCValues: gcv withMask: GCFillRule];
840 /* NO BREAK */
841 case path_fill:
842 // Hack: Only draw when alpha is not zero
843 if (drawingAlpha == NO || fillColor.field[AINDEX] != 0.0)
844 XFillPolygon(XDPY, draw, xgcntxt, pts, count, Complex,
845 CoordModeOrigin);
846 if (drawingAlpha)
847 {
848 NSAssert(alpha_buffer, NSInternalInconsistencyException);
849
850 [self setAlphaColor: fillColor.field[AINDEX]];
851 XFillPolygon(XDPY, alpha_buffer, agcntxt, pts, count, Complex,
852 CoordModeOrigin);
853 }
854
855 if (gcv.fill_rule == EvenOddRule)
856 {
857 gcv.fill_rule = WindingRule;
858 [self setGCValues: gcv withMask: GCFillRule];
859 }
860 break;
861 case path_eoclip:
862 fill_rule = EvenOddRule;
863 /* NO BREAK */
864 case path_clip:
865 {
866 Region region, new_region;
867 region = XPolygonRegion(pts, count, fill_rule);
868 if (clipregion)
869 {
870 new_region=XCreateRegion();
871 XIntersectRegion(clipregion, region, new_region);
872 XDestroyRegion(region);
873 XDestroyRegion(clipregion);
874 } else
875 new_region = region;
876 clipregion = new_region;
877 [self setClipMask];
878 }
879 break;
880 default:
881 break;
882 }
883 }
884
885 /* fill a complex path. All coordinates should already have been
886 transformed to device coordinates. */
887 - (void) _doComplexPath: (XPoint*)pts
888 : (int*)types
889 : (int)count
890 ll: (XPoint)ll
891 ur: (XPoint)ur
892 draw: (ctxt_object_t)type
893 {
894 int x, y, i, j, cnt, nseg = 0;
895 XSegment segments[count];
896 Window root_rtn;
897 unsigned int width, height, b_rtn, d_rtn;
898
899 COPY_GC_ON_CHANGE;
900 if (draw == 0)
901 {
902 DPS_WARN (DPSinvalidid, @"No Drawable defined for path");
903 return;
904 }
905
906 XGetGeometry (XDPY, draw, &root_rtn, &x, &y, &width, &height,
907 &b_rtn, &d_rtn);
908 if (ur.x < x || ll.x > x + (int)width)
909 {
910 return;
911 }
912
913 if (ll.y < y)
914 {
915 ll.y = y;
916 }
917 if (ur.y > y + (int)height)
918 {
919 ur.y = y + height;
920 }
921
922 /* draw horizontal lines from the bottom to the top of the path */
923 for (y = ll.y; y <= ur.y; y++)
924 {
925 int x[count], w[count], y0, y1;
926 int yh = y * 2 + 1; // shift y of horizontal line
927 XPoint lastP, p1;
928
929 /* intersect horizontal line with path */
930 for (i = 0, cnt = 0; i < count - 1; i++)
931 {
932 if (types[i] == 0) // move (new subpath)
933 {
934 lastP = pts[i];
935 }
936 if (types[i+1] == 0) // last line of subpath
937 {
938 if (lastP.y == pts[i].y)
939 {
940 continue;
941 }
942 p1 = lastP; // close subpath
943 }
944 else
945 {
946 p1 = pts[i+1];
947 }
948 y0 = pts[i].y * 2;
949 y1 = p1.y * 2;
950 if ((y0 < yh && yh < y1) || (y1 < yh && yh < y0) )
951 {
952 int dy = yh - pts[i].y * 2;
953 int ldy = y1 - y0;
954 int ldx = (p1.x - pts[i].x) * 2;
955
956 x[cnt] = pts[i].x + (ldx * dy / ldy) / 2;
957 /* sum up winding directions */
958 if (type == path_fill)
959 {
960 w[cnt] = ((cnt) ? w[cnt-1] : 0) + (y0 < y1) ? -1 : 1;
961 }
962 cnt++;
963 }
964 }
965
966 /* sort intersections */
967 for (i = 0; i < cnt-1; i++)
968 {
969 for (j=i+1; j<cnt; j++)
970 {
971 if (x[j] < x[i])
972 {
973 x[i] ^= x[j];
974 x[j] ^= x[i];
975 x[i] ^= x[j];
976 }
977 }
978 }
979
980 /* draw lines between intersections */
981 for (i = 0; i < cnt-1; i++)
982 {
983 /* eofill -> start line on odd intersection count
984 * winding fill -> start line on odd winding count
985 */
986 if ((type == path_eofill && !(i%2)) || (type == path_fill && w[i]))
987 {
988 segments[nseg].x1 = x[i];
989 segments[nseg].x2 = x[i+1];
990 segments[nseg].y1 = segments[nseg].y2 = y;
991 nseg++;
992 }
993 }
994
995 // Hack: Only draw when alpha is not zero
996 if (drawingAlpha == NO || fillColor.field[AINDEX] != 0.0)
997 XDrawSegments (XDPY, draw, xgcntxt, segments, nseg);
998 if (drawingAlpha)
999 {
1000 NSAssert (alpha_buffer, NSInternalInconsistencyException);
1001
1002 [self setAlphaColor: fillColor.field[AINDEX]];
1003 XDrawSegments (XDPY, alpha_buffer, agcntxt, segments, nseg);
1004 }
1005 nseg = 0;
1006 } // for y
1007 }
1008
1009 - (void) _paintPath: (ctxt_object_t) drawType
1010 {
1011 unsigned count;
1012 NSBezierPath *flatPath;
1013 XPoint ll, ur;
1014
1015 if (!path)
1016 {
1017 return;
1018 }
1019
1020 ll.x = ll.y = 0x7FFF;
1021 ur.x = ur.y = 0;
1022 flatPath = [path bezierPathByFlatteningPath];
1023 count = [flatPath elementCount];
1024 if (count)
1025 {
1026 XPoint pts[count];
1027 int ts[count];
1028 unsigned j, i = 0;
1029 NSBezierPathElement type;
1030 NSPoint points[3];
1031 BOOL first = YES;
1032 NSPoint p, last_p;
1033 BOOL doit;
1034 BOOL complex = NO;
1035
1036 for(j = 0; j < count; j++)
1037 {
1038 doit = NO;
1039 type = [flatPath elementAtIndex: j associatedPoints: points];
1040 switch(type)
1041 {
1042 case NSMoveToBezierPathElement:
1043 if (drawType != path_eofill && drawType != path_fill)
1044 {
1045 if (i > 1)
1046 {
1047 [self _doPath: pts : i draw: drawType];
1048 }
1049 i = 0;
1050 }
1051 else if (i > 1)
1052 {
1053 complex = YES;
1054 }
1055 last_p = p = points[0];
1056 ts[i] = 0;
1057 first = NO;
1058 break;
1059 case NSLineToBezierPathElement:
1060 p = points[0];
1061 ts[i] = 1;
1062 if (first)
1063 {
1064 last_p = points[0];
1065 first = NO;
1066 }
1067 break;
1068 case NSCurveToBezierPathElement:
1069 // This should not happen, as we flatten the path
1070 p = points[2];
1071 ts[i] = 1;
1072 if (first)
1073 {
1074 last_p = points[2];
1075 first = NO;
1076 }
1077 break;
1078 case NSClosePathBezierPathElement:
1079 p = last_p;
1080 ts[i] = 1;
1081 doit = YES;
1082 break;
1083 default:
1084 break;
1085 }
1086 pts[i] = XGWindowPointToX (self, p);
1087 if (pts[i].x < ll.x)
1088 {
1089 ll.x = pts[i].x;
1090 }
1091 if (pts[i].y > ur.x)
1092 {
1093 ur.x = pts[i].x;
1094 }
1095 if (pts[i].y < ll.y)
1096 {
1097 ll.y = pts[i].y;
1098 }
1099 if (pts[i].y > ur.y)
1100 {
1101 ur.y = pts[i].y;
1102 }
1103 i++;
1104
1105 if (doit && i > 1)
1106 {
1107 if (complex)
1108 {
1109 [self _doComplexPath: pts : ts : i
1110 ll: ll ur: ur draw: drawType];
1111 }
1112 else
1113 {
1114 [self _doPath: pts : i draw: drawType];
1115 }
1116 i = 0;
1117 }
1118 } /* for */
1119
1120 if (i > 1)
1121 {
1122 if (complex)
1123 {
1124 [self _doComplexPath: pts : ts : i
1125 ll: ll ur: ur draw: drawType];
1126 }
1127 else
1128 {
1129 [self _doPath: pts : i draw: drawType];
1130 }
1131 }
1132 }
1133
1134 /*
1135 * clip does not delete the current path, so we only clear the path if the
1136 * operation was not a clipping operation.
1137 */
1138 if ((drawType != path_clip) && (drawType != path_eoclip))
1139 {
1140 [path removeAllPoints];
1141 }
1142 }
1143
1144 - (XPoint) viewPointToX: (NSPoint)aPoint
1145 {
1146 return XGViewPointToX(self, aPoint);
1147 }
1148
1149 - (XRectangle) viewRectToX: (NSRect)aRect
1150 {
1151 return XGViewRectToX(self, aRect);
1152 }
1153
1154 - (XPoint) windowPointToX: (NSPoint)aPoint
1155 {
1156 return XGWindowPointToX(self, aPoint);
1157 }
1158
1159 - (XRectangle) windowRectToX: (NSRect)aRect
1160 {
1161 return XGWindowRectToX(self, aRect);
1162 }
1163
1164 @end
1165
1166 @implementation XGGState (Ops)
1167
1168 - (void) DPSsetalpha: (float)a
1169 {
1170 gswindow_device_t *gs_win;
1171 [super DPSsetalpha: a];
1172 gs_win = (gswindow_device_t *)windevice;
1173 if (!gs_win)
1174 return;
1175 if (fillColor.field[AINDEX] < 1.0)
1176 [self _alphaBuffer: gs_win];
1177 }
1178
1179 /* ----------------------------------------------------------------------- */
1180 /* Text operations */
1181 /* ----------------------------------------------------------------------- */
1182 typedef enum {
1183 show_delta, show_array_x, show_array_y, show_array_xy
1184 } show_array_t;
1185
1186 /* Omnibus show string routine that combines that characteristics of
1187 ashow, awidthshow, widthshow, xshow, xyshow, and yshow */
1188 - (void) _showString: (const char *)s
1189 xCharAdj: (float)cx
1190 yCharAdj: (float)cy
1191 char: (char)c
1192 adjArray: (const float *)arr
1193 arrType: (show_array_t)type
1194 isRelative: (BOOL)relative;
1195 {
1196 int i;
1197 int len;
1198 int width;
1199 NSSize scale;
1200 NSPoint point = [path currentPoint];
1201
1202 if (font == nil)
1203 {
1204 NSLog(@"DPS (xgps): no font set\n");
1205 return;
1206 }
1207
1208 COPY_GC_ON_CHANGE;
1209 if (draw == 0)
1210 {
1211 DPS_WARN(DPSinvalidid, @"No Drawable defined for show");
1212 return;
1213 }
1214
1215 if ((cstate & COLOR_FILL) == 0)
1216 [self setColor: &fillColor state: COLOR_FILL];
1217
1218 /* Use only delta transformations (no offset) */
1219 len = strlen(s);
1220 scale = [ctm sizeInMatrixSpace: NSMakeSize(1,1)];
1221 for (i = 0; i < len; i++)
1222 {
1223 NSPoint delta;
1224 XPoint xp;
1225
1226 // FIXME: We should put this line before the loop
1227 // and do all computation in display space.
1228 xp = XGWindowPointToX(self, point);
1229 width = [(XGFontInfo *)font widthOf: s+i lenght: 1];
1230 // Hack: Only draw when alpha is not zero
1231 if (drawingAlpha == NO || fillColor.field[AINDEX] != 0.0)
1232 [(XGFontInfo *)font draw: s+i lenght: 1
1233 onDisplay: XDPY drawable: draw
1234 with: xgcntxt at: xp];
1235
1236 if (drawingAlpha)
1237 {
1238 NSAssert(alpha_buffer, NSInternalInconsistencyException);
1239
1240 [self setAlphaColor: fillColor.field[AINDEX]];
1241 [(XGFontInfo *)font draw: s+i lenght: 1
1242 onDisplay: XDPY drawable: alpha_buffer
1243 with: agcntxt at: xp];
1244 }
1245 /* Note we update the current point according to the current
1246 transformation scaling, although the text isn't currently
1247 scaled (FIXME). */
1248 if (type == show_array_xy)
1249 {
1250 delta.x = arr[2*i]; delta.y = arr[2*i+1];
1251 }
1252 else if (type == show_array_x)
1253 {
1254 delta.x = arr[i]; delta.y = 0;
1255 }
1256 else if (type == show_array_y)
1257 {
1258 delta.x = 0; delta.y = arr[i];
1259 }
1260 else
1261 {
1262 delta.x = arr[0]; delta.y = arr[1];
1263 }
1264 delta = [ctm deltaPointInMatrixSpace: delta];
1265 if (relative == YES)
1266 {
1267 delta.x += width * scale.width;
1268 delta.y += [font ascender] * scale.height;
1269 }
1270 if (c && *(s+i) == c)
1271 {
1272 NSPoint cdelta;
1273 cdelta.x = cx; cdelta.y = cy;
1274 cdelta = [ctm deltaPointInMatrixSpace: cdelta];
1275 delta.x += cdelta.x; delta.y += cdelta.y;
1276 }
1277 point.x += delta.x;
1278 if (type != show_delta)
1279 point.y += delta.y;
1280 }
1281 // FIXME: Should we set the current point now?
1282 }
1283
1284 - (void)DPSashow: (float)x : (float)y : (const char *)s
1285 {
1286 float arr[2];
1287
1288 arr[0] = x; arr[1] = y;
1289 [self _showString: s
1290 xCharAdj: 0 yCharAdj: 0 char: 0 adjArray: arr arrType: show_delta
1291 isRelative: YES];
1292 }
1293
1294 - (void)DPSawidthshow: (float)cx : (float)cy : (int)c : (float)ax : (float)ay : (const char *)s
1295 {
1296 float arr[2];
1297
1298 arr[0] = ax; arr[1] = ay;
1299 [self _showString: s
1300 xCharAdj: cx yCharAdj: cy char: c adjArray: arr arrType: show_delta
1301 isRelative: YES];
1302 }
1303
1304 - (void)DPSshow: (const char *)s
1305 {
1306 int len;
1307 int width;
1308 NSSize scale;
1309 XPoint xp;
1310
1311 if (font == nil)
1312 {
1313 NSLog(@"DPS (xgps): no font set\n");
1314 return;
1315 }
1316
1317 COPY_GC_ON_CHANGE;
1318 if (draw == 0)
1319 {
1320 DPS_WARN(DPSinvalidid, @"No Drawable defined for show");
1321 return;
1322 }
1323
1324 if ((cstate & COLOR_FILL) == 0)
1325 [self setColor: &fillColor state: COLOR_FILL];
1326
1327 len = strlen(s);
1328 width = [(XGFontInfo *)font widthOf: s lenght: len];
1329 xp = XGWindowPointToX(self, [path currentPoint]);
1330 // Hack: Only draw when alpha is not zero
1331 if (drawingAlpha == NO || fillColor.field[AINDEX] != 0.0)
1332 [(XGFontInfo *)font draw: s lenght: len
1333 onDisplay: XDPY drawable: draw
1334 with: xgcntxt at: xp];
1335
1336 if (drawingAlpha)
1337 {
1338 NSAssert(alpha_buffer, NSInternalInconsistencyException);
1339
1340 [self setAlphaColor: fillColor.field[AINDEX]];
1341 [(XGFontInfo *)font draw: s lenght: len
1342 onDisplay: XDPY drawable: alpha_buffer
1343 with: agcntxt at: xp];
1344 }
1345 /* Note we update the current point according to the current
1346 transformation scaling, although the text isn't currently
1347 scaled (FIXME). */
1348 scale = [ctm sizeInMatrixSpace: NSMakeSize(1, 1)];
1349 //scale = NSMakeSize(1, 1);
1350 [path relativeMoveToPoint: NSMakePoint(width * scale.width, 0)];
1351 }
1352
1353
1354 - (void) GSShowGlyphs: (const NSGlyph *)glyphs : (size_t) length
1355 {
1356 int width;
1357 NSSize scale;
1358 XPoint xp;
1359
1360 if (font == nil)
1361 {
1362 NSLog(@"DPS (xgps): no font set\n");
1363 return;
1364 }
1365
1366 COPY_GC_ON_CHANGE;
1367 if (draw == 0)
1368 {
1369 DPS_WARN(DPSinvalidid, @"No Drawable defined for show");
1370 return;
1371 }
1372
1373 if ((cstate & COLOR_FILL) == 0)
1374 [self setColor: &fillColor state: COLOR_FILL];
1375
1376 width = [(XGFontInfo *)font widthOfGlyphs: glyphs lenght: length];
1377 xp = XGWindowPointToX(self, [path currentPoint]);
1378 // Hack: Only draw when alpha is not zero
1379 if (drawingAlpha == NO || fillColor.field[AINDEX] != 0.0)
1380 [(XGFontInfo *)font drawGlyphs: glyphs lenght: length
1381 onDisplay: XDPY drawable: draw
1382 with: xgcntxt at: xp];
1383
1384 if (drawingAlpha)
1385 {
1386 NSAssert(alpha_buffer, NSInternalInconsistencyException);
1387
1388 [self setAlphaColor: fillColor.field[AINDEX]];
1389 [(XGFontInfo *)font drawGlyphs: glyphs lenght: length
1390 onDisplay: XDPY drawable: alpha_buffer
1391 with: agcntxt at: xp];
1392 }
1393 /* Note we update the current point according to the current
1394 transformation scaling, although the text isn't currently
1395 scaled (FIXME). */
1396 scale = [ctm sizeInMatrixSpace: NSMakeSize(1, 1)];
1397 //scale = NSMakeSize(1, 1);
1398 [path relativeMoveToPoint: NSMakePoint(width * scale.width, 0)];
1399 }
1400
1401 - (void)DPSwidthshow: (float)x : (float)y : (int)c : (const char *)s
1402 {
1403 float arr[2];
1404
1405 arr[0] = 0; arr[1] = 0;
1406 [self _showString: s
1407 xCharAdj: x yCharAdj: y char: c adjArray: arr arrType: show_delta
1408 isRelative: YES];
1409 }
1410
1411 - (void)DPSxshow: (const char *)s : (const float *)numarray : (int)size
1412 {
1413 [self _showString: s
1414 xCharAdj: 0 yCharAdj: 0 char: 0 adjArray: numarray arrType: show_array_x
1415 isRelative: NO];
1416 }
1417
1418 - (void)DPSxyshow: (const char *)s : (const float *)numarray : (int)size
1419 {
1420 [self _showString: s
1421 xCharAdj: 0 yCharAdj: 0 char: 0 adjArray: numarray arrType: show_array_xy
1422 isRelative: NO];
1423 }
1424
1425 - (void)DPSyshow: (const char *)s : (const float *)numarray : (int)size
1426 {
1427 [self _showString: s
1428 xCharAdj: 0 yCharAdj: 0 char: 0 adjArray: numarray arrType: show_array_y
1429 isRelative: NO];
1430 }
1431
1432 - (void) GSSetFont: (GSFontInfo *)newFont
1433 {
1434 if (font == newFont)
1435 return;
1436 [super GSSetFont: newFont];
1437
1438 COPY_GC_ON_CHANGE;
1439 if (xgcntxt == 0)
1440 return;
1441
1442 [(XGFontInfo *)font setActiveFor: XDPY gc: xgcntxt];
1443 }
1444
1445 /* ----------------------------------------------------------------------- */
1446 /* Gstate operations */
1447 /* ----------------------------------------------------------------------- */
1448 - (void)DPScurrentlinecap: (int *)linecap
1449 {
1450 *linecap = gcv.cap_style - CapButt;
1451 }
1452
1453 - (void)DPScurrentlinejoin: (int *)linejoin
1454 {
1455 *linejoin = gcv.join_style - JoinMiter;
1456 }
1457
1458 - (void)DPScurrentlinewidth: (float *)width
1459 {
1460 *width = gcv.line_width;
1461 }
1462
1463 - (void)DPSinitgraphics
1464 {
1465 [super DPSinitgraphics];
1466 if (clipregion)
1467 XDestroyRegion(clipregion);
1468 clipregion = 0;
1469 }
1470
1471 - (void)DPSsetdash: (const float *)pat : (int)size : (float)pat_offset
1472 {
1473 int dash_offset;
1474 char dash_list[size];
1475 int i;
1476
1477 if ((pat == NULL) || (size == 0))
1478 {
1479 gcv.line_style = LineSolid;
1480 [self setGCValues: gcv withMask: GCLineStyle];
1481 return;
1482 }
1483
1484 gcv.line_style = LineOnOffDash;
1485 [self setGCValues: gcv withMask: GCLineStyle];
1486
1487 // FIXME: How to convert those values?
1488 dash_offset = (int)pat_offset;
1489 for (i = 0; i < size; i++)
1490 dash_list[i] = (char)pat[i];
1491
1492 // We can only set the dash pattern, if xgcntxt exists.
1493 if (xgcntxt == 0)
1494 return;
1495 XSetDashes(XDPY, xgcntxt, dash_offset, dash_list, size);
1496 }
1497
1498 - (void)DPSsetlinecap: (int)linecap
1499 {
1500 gcv.cap_style = linecap + CapButt;
1501 [self setGCValues: gcv withMask: GCCapStyle];
1502 }
1503
1504 - (void)DPSsetlinejoin: (int)linejoin
1505 {
1506 gcv.join_style = linejoin + JoinMiter;
1507 [self setGCValues: gcv withMask: GCJoinStyle];
1508 }
1509
1510 - (void)DPSsetlinewidth: (float)width
1511 {
1512 int w;
1513 NSSize ws;
1514
1515 ws = [ctm sizeInMatrixSpace: NSMakeSize(width,width)];
1516 width = (ws.width + ws.height) / 2;
1517
1518 /*
1519 * Evil hack to get drawing to work - with a line thickness of 1, the
1520 * rectangles we draw seem to lose their bottom right corners irrespective
1521 * of the join/cap settings - but with a thickness of zero things work.
1522 */
1523 if (width < 1.5)
1524 width = 0.0;
1525
1526 w = (int)width;
1527 if (gcv.line_width != w)
1528 {
1529 gcv.line_width = w;
1530 [self setGCValues: gcv withMask: GCLineWidth];
1531 }
1532 }
1533
1534 - (void) DPSsetmiterlimit: (float)limit
1535 {
1536 /* Do nothing. X11 does its own thing and doesn't give us a choice */
1537 }
1538
1539 /* ----------------------------------------------------------------------- */
1540 /* Paint operations */
1541 /* ----------------------------------------------------------------------- */
1542 - (void)DPSclip
1543 {
1544 [self _paintPath: path_clip];
1545 }
1546
1547 - (void)DPSeoclip
1548 {
1549 [self _paintPath: path_eoclip];
1550 }
1551
1552 - (void)DPSeofill
1553 {
1554 if ((cstate & COLOR_FILL) == 0)
1555 [self setColor: &fillColor state: COLOR_FILL];
1556
1557 [self _paintPath: path_eofill];
1558 }
1559
1560 - (void)DPSfill
1561 {
1562 if ((cstate & COLOR_FILL) == 0)
1563 [self setColor: &fillColor state: COLOR_FILL];
1564
1565 [self _paintPath: path_fill];
1566 }
1567
1568 - (void)DPSinitclip
1569 {
1570 if (clipregion)
1571 XDestroyRegion(clipregion);
1572 clipregion = 0;
1573 [self setClipMask];
1574 }
1575
1576 - (void)DPSrectclip: (float)x : (float)y : (float)w : (float)h
1577 {
1578 XRectangle xrect;
1579
1580 CHECK_GC;
1581
1582 xrect = XGViewRectToX(self, NSMakeRect(x, y, w, h));
1583
1584 if (clipregion == 0)
1585 {
1586 clipregion = XCreateRegion();
1587 XUnionRectWithRegion(&xrect, clipregion, clipregion);
1588 }
1589 else
1590 {
1591 Region region;
1592 region = XCreateRegion();
1593 XUnionRectWithRegion(&xrect, region, region);
1594 XIntersectRegion(clipregion, region, clipregion);
1595 XDestroyRegion(region);
1596 }
1597 [self setClipMask];
1598 }
1599
1600 - (void)DPSrectfill: (float)x : (float)y : (float)w : (float)h
1601 {
1602 XRectangle bounds;
1603
1604 CHECK_GC;
1605 if (draw == 0)
1606 {
1607 DPS_WARN(DPSinvalidid, @"No Drawable defined for drawing");
1608 return;
1609 }
1610
1611 if ((cstate & COLOR_FILL) == 0)
1612 [self setColor: &fillColor state: COLOR_FILL];
1613
1614 bounds = XGViewRectToX(self, NSMakeRect(x, y, w, h));
1615 // Hack: Only draw when alpha is not zero
1616 if (drawingAlpha == NO || fillColor.field[AINDEX] != 0.0)
1617 XFillRectangle(XDPY, draw, xgcntxt,
1618 bounds.x, bounds.y, bounds.width, bounds.height);
1619
1620 if (drawingAlpha)
1621 {
1622 /* Fill alpha also */
1623 NSAssert(alpha_buffer, NSInternalInconsistencyException);
1624
1625 [self setAlphaColor: fillColor.field[AINDEX]];
1626 XFillRectangle(XDPY, alpha_buffer, agcntxt,
1627 bounds.x, bounds.y, bounds.width, bounds.height);
1628 }
1629 }
1630
1631 - (void)DPSrectstroke: (float)x : (float)y : (float)w : (float)h
1632 {
1633 XRectangle bounds;
1634
1635 CHECK_GC;
1636 if (draw == 0)
1637 {
1638 DPS_WARN(DPSinvalidid, @"No Drawable defined for drawing");
1639 return;
1640 }
1641
1642 if ((cstate & COLOR_STROKE) == 0)
1643 [self setColor: &fillColor state: COLOR_STROKE];
1644
1645 bounds = XGViewRectToX(self, NSMakeRect(x, y, w, h));
1646 if (bounds.width > 0)
1647 bounds.width--;
1648 if (bounds.height > 0)
1649 bounds.height--;
1650 // Hack: Only draw when alpha is not zero
1651 if (drawingAlpha == NO || strokeColor.field[AINDEX] != 0.0)
1652 XDrawRectangle(XDPY, draw, xgcntxt,
1653 bounds.x, bounds.y, bounds.width, bounds.height);
1654
1655 if (drawingAlpha)
1656 {
1657 /* Fill alpha also */
1658 NSAssert(alpha_buffer, NSInternalInconsistencyException);
1659
1660 [self setAlphaColor: strokeColor.field[AINDEX]];
1661 XDrawRectangle(XDPY, alpha_buffer, agcntxt,
1662 bounds.x, bounds.y, bounds.width, bounds.height);
1663 }
1664 }
1665
1666 - (void)DPSstroke
1667 {
1668 if ((cstate & COLOR_STROKE) == 0)
1669 [self setColor: &fillColor state: COLOR_STROKE];
1670
1671 [self _paintPath: path_stroke];
1672 }
1673
1674 /* ----------------------------------------------------------------------- */
1675 /* NSGraphics Ops */
1676 /* ----------------------------------------------------------------------- */
1677 - (void)DPSimage: (NSAffineTransform*) matrix : (int) pixelsWide : (int) pixelsHigh
1678 : (int) bitsPerSample : (int) samplesPerPixel
1679 : (int) bitsPerPixel : (int) bytesPerRow : (BOOL) isPlanar
1680 : (BOOL) hasAlpha : (NSString *) colorSpaceName
1681 : (const unsigned char *const [5]) data
1682 {
1683 BOOL one_is_black, fast_min;
1684 NSRect rect;
1685 XRectangle sr, dr, cr;
1686 RXImage *dest_im, *dest_alpha;
1687 gswindow_device_t *dest_win;
1688 int cspace;
1689 NSAffineTransform *old_ctm = nil;
1690
1691 // FIXME for now we hard code the minification behaviour
1692 fast_min = YES;
1693
1694 rect = NSZeroRect;
1695 one_is_black = NO;
1696 cspace = rgb_colorspace;
1697 rect.size.width = (float) pixelsWide;
1698 rect.size.height = (float) pixelsHigh;
1699
1700 // default is 8 bit grayscale
1701 if (!bitsPerSample)
1702 bitsPerSample = 8;
1703 if (!samplesPerPixel)
1704 samplesPerPixel = 1;
1705
1706 // FIXME - does this work if we are passed a planar image but no hints ?
1707 if (!bitsPerPixel)
1708 bitsPerPixel = bitsPerSample * samplesPerPixel;
1709 if (!bytesPerRow)
1710 bytesPerRow = (bitsPerPixel * pixelsWide) / 8;
1711
1712 /* make sure its sane - also handles row padding if hint missing */
1713 while((bytesPerRow * 8) < (bitsPerPixel * pixelsWide))
1714 bytesPerRow++;
1715
1716 /* get the colour space */
1717 if (colorSpaceName)
1718 {
1719 if ([colorSpaceName isEqualToString: NSDeviceRGBColorSpace])
1720 cspace = rgb_colorspace;
1721 else if([colorSpaceName isEqualToString: NSDeviceCMYKColorSpace])
1722 cspace = cmyk_colorspace;
1723 else if([colorSpaceName isEqualToString: NSDeviceWhiteColorSpace])
1724 cspace = gray_colorspace;
1725 else if([colorSpaceName isEqualToString: NSDeviceBlackColorSpace])
1726 {
1727 cspace = gray_colorspace;
1728 one_is_black = YES;
1729 }
1730 else
1731 {
1732 // if we dont recognise the name use RGB or greyscale as appropriate
1733 NSLog(@"XGContext (DPSImage): Unknown colour space %@", colorSpaceName);
1734 if(samplesPerPixel > 2)
1735 cspace = rgb_colorspace;
1736 else
1737 cspace = gray_colorspace;
1738 }
1739 }
1740
1741 // Apply the additional transformation
1742 if (matrix)
1743 {
1744 old_ctm = [ctm copy];
1745 [ctm appendTransform: matrix];
1746 }
1747
1748 // --- Get our drawable info -----------------------------------------
1749 dest_win = (gswindow_device_t *)windevice;
1750 if (!dest_win)
1751 {
1752 DPS_ERROR(DPSinvalidid, @"Invalid image gstate");
1753 return;
1754 }
1755
1756
1757 // --- Determine screen coverage --------------------------------------
1758 sr = [self viewRectToX: rect];
1759
1760 // --- Determine region to draw --------------------------------------
1761 if (clipregion)
1762 XClipBox (clipregion, &cr);
1763 else
1764 cr = sr;
1765
1766 dr = XGIntersectionRect (sr, cr);
1767
1768
1769 // --- If there is nothing to draw return ----------------------------
1770 if (XGIsEmptyRect (dr))
1771 {
1772 if (old_ctm != nil)
1773 {
1774 RELEASE(ctm);
1775 // old_ctm is already retained
1776 ctm = old_ctm;
1777 }
1778 return;
1779 }
1780
1781 if (dest_win->buffer == 0 && dest_win->map_state != IsViewable)
1782 {
1783 if (old_ctm != nil)
1784 {
1785 RELEASE(ctm);
1786 // old_ctm is already retained
1787 ctm = old_ctm;
1788 }
1789 return;
1790 }
1791
1792
1793 // --- Get the destination images ------------------------------------
1794 dest_im = RGetXImage ((RContext *)context, draw, XGMinX (dr), XGMinY (dr),
1795 XGWidth (dr), XGHeight (dr));
1796
1797 // Force creation of our alpha buffer
1798 if (hasAlpha)
1799 {
1800 [self _alphaBuffer: dest_win];
1801 }
1802
1803 // Composite it
1804 if (alpha_buffer != 0)
1805 {
1806 dest_alpha = RGetXImage ((RContext *)context, alpha_buffer,
1807 XGMinX (dr), XGMinY (dr),
1808 XGWidth (dr), XGHeight (dr));
1809 }
1810 else
1811 {
1812 dest_alpha = 0;
1813 }
1814
1815
1816 if (hasAlpha && alpha_buffer &&
1817 (dest_alpha == 0 || dest_alpha->image == 0))
1818 {
1819 NSLog(@"XGContext (DPSimage): Cannot create alpha image\n");
1820 if (old_ctm != nil)
1821 {
1822 RELEASE(ctm);
1823 // old_ctm is already retained
1824 ctm = old_ctm;
1825 }
1826 return;
1827 }
1828
1829 // --- The real work is done HERE ------------------------------------
1830 _bitmap_combine_alpha((RContext *)context, (unsigned char **)data,
1831 pixelsWide, pixelsHigh,
1832 bitsPerSample, samplesPerPixel,
1833 bitsPerPixel, bytesPerRow,
1834 cspace, one_is_black,
1835 isPlanar, hasAlpha, fast_min,
1836 dest_im, dest_alpha, sr, dr,
1837 0, drawMechanism);
1838
1839 /* Draw into the window/buffer */
1840 RPutXImage((RContext *)context, draw, xgcntxt, dest_im, 0, 0,
1841 XGMinX (dr), XGMinY (dr), XGWidth (dr), XGHeight (dr));
1842 if (dest_alpha)
1843 {
1844 RPutXImage((RContext *)context, dest_win->alpha_buffer,
1845 xgcntxt, dest_alpha, 0, 0,
1846 XGMinX (dr), XGMinY (dr), XGWidth (dr), XGHeight (dr));
1847
1848 RDestroyXImage((RContext *)context, dest_alpha);
1849 }
1850 RDestroyXImage((RContext *)context, dest_im);
1851
1852 if (old_ctm != nil)
1853 {
1854 RELEASE(ctm);
1855 // old_ctm is already retained
1856 ctm = old_ctm;
1857 }
1858 }
1859
1860 - (NSDictionary *) GSReadRect: (NSRect)rect
1861 {
1862 NSSize ssize;
1863 XRectangle srect;
1864 RXImage *source_im;
1865 RXImage *source_alpha;
1866 gswindow_device_t *source_win;
1867 NSMutableDictionary *dict;
1868 NSData *data;
1869
1870 source_win = (gswindow_device_t *)windevice;
1871 if (!source_win)
1872 {
1873 DPS_ERROR(DPSinvalidid, @"Invalid read gstate");
1874 return nil;
1875 }
1876
1877 if (source_win->buffer == 0 && source_win->map_state != IsViewable)
1878 {
1879 /* Can't read anything */
1880 DPS_ERROR(DPSinvalidid, @"Invalid window not readable");
1881 return nil;
1882 }
1883
1884 dict = [NSMutableDictionary dictionary];
1885
1886 // --- determine region to read --------------------------------------
1887
1888 rect.origin = [ctm pointInMatrixSpace: rect.origin];
1889 srect = XGWindowRectToX(self, rect);
1890 srect = XGIntersectionRect (srect, accessibleRectForWindow (source_win));
1891 ssize.width = srect.width;
1892 ssize.height = srect.height;
1893 [dict setObject: [NSValue valueWithSize: ssize] forKey: @"ImageSize"];
1894
1895 if (XGIsEmptyRect(srect))
1896 return dict;
1897
1898 [dict setObject: [NSNumber numberWithUnsignedInt: source_win->depth]
1899 forKey: @"ImageDepth"];
1900
1901 // --- get source XImage ----------------------------------------
1902
1903 if (draw == source_win->ident && source_win->visibility < 0)
1904 {
1905 /* Non-backingstore window isn't visible, so just make up the image */
1906 NSLog(@"Focused view window not readable");
1907 source_im = RCreateXImage(context, source_win->depth,
1908 XGWidth(srect), XGHeight(srect));
1909 }
1910 else
1911 {
1912 source_im = RGetXImage(context, draw, XGMinX(srect), XGMinY (srect),
1913 XGWidth (srect), XGHeight (srect));
1914 }
1915
1916 if (source_im->image == 0)
1917 {
1918 // Should not happen,
1919 DPS_ERROR (DPSinvalidaccess, @"unable to fetch source image");
1920 return dict;
1921 }
1922
1923 [self _alphaBuffer: source_win];
1924 if (alpha_buffer)
1925 {
1926 source_alpha = RGetXImage((RContext *)context, alpha_buffer,
1927 XGMinX(srect), XGMinY(srect),
1928 XGWidth(srect), XGHeight(srect));
1929 [dict setObject: [NSNumber numberWithUnsignedInt: 4]
1930 forKey: @"ImageSPP"];
1931 [dict setObject: [NSNumber numberWithUnsignedInt: 1]
1932 forKey: @"ImageAlpha"];
1933 }
1934 else
1935 {
1936 source_alpha = NULL;
1937 [dict setObject: [NSNumber numberWithUnsignedInt: 3]
1938 forKey: @"ImageSPP"];
1939 [dict setObject: [NSNumber numberWithUnsignedInt: 0]
1940 forKey: @"ImageAlpha"];
1941 }
1942
1943 data = _pixmap_read_alpha(context, source_im, source_alpha, srect,
1944 drawMechanism);
1945 [dict setObject: data forKey: @"ImageData"];
1946 /* Pixmap routine always returns image in same format (FIXME?). */
1947 [dict setObject: NSDeviceRGBColorSpace forKey: @"ImageColorSpace"];
1948 [dict setObject: [NSNumber numberWithUnsignedInt: 8] forKey: @"ImageBPS"];
1949
1950 // --- clean up ------------------------------------------------------
1951
1952 RDestroyXImage((RContext *)context, source_im);
1953 RDestroyXImage((RContext *)context, source_alpha);
1954 return dict;
1955 }
1956
1957 @end
1958
1959

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26