1 /***********************************************************/
2 /*                                                         */
3 /*  System dependent graphics (unix, x11)                  */
4 /*                                                         */
5 /***********************************************************/
6 
7 #include "unix/guts.h"
8 #include "Image.h"
9 
10 #define SORT(a,b)	{ int swp; if ((a) > (b)) { swp=(a); (a)=(b); (b)=swp; }}
11 #define REVERT(a)	(XX-> size. y - (a) - 1)
12 #define SHIFT(a,b)	{ (a) += XX-> gtransform. x + XX-> btransform. x; \
13 									(b) += XX-> gtransform. y + XX-> btransform. y; }
14 #define RANGE(a)        { if ((a) < -16383) (a) = -16383; else if ((a) > 16383) a = 16383; }
15 #define RANGE2(a,b)     RANGE(a) RANGE(b)
16 #define RANGE4(a,b,c,d) RANGE(a) RANGE(b) RANGE(c) RANGE(d)
17 #define REVERSE_BYTES_32(x) ((((x)&0xff)<<24) | (((x)&0xff00)<<8) | (((x)&0xff0000)>>8) | (((x)&0xff000000)>>24))
18 #define REVERSE_BYTES_24(x) ((((x)&0xff)<<16) | ((x)&0xff00) | (((x)&0xff0000)>>8))
19 #define REVERSE_BYTES_16(x) ((((x)&0xff)<<8 ) | (((x)&0xff00)>>8))
20 
21 #define COLOR_R16(x) (((x)>>8)&0xFF00)
22 #define COLOR_G16(x) ((x)&0xFF00)
23 #define COLOR_B16(x) (((x)<<8)&0xFF00)
24 
25 static int rop_map[] = {
26 	GXcopy	/* ropCopyPut */,		/* dest  = src */
27 	GXxor	/* ropXorPut */,		/* dest ^= src */
28 	GXand	/* ropAndPut */,		/* dest &= src */
29 	GXor		/* ropOrPut */,			/* dest |= src */
30 	GXcopyInverted /* ropNotPut */,		/* dest = !src */
31 	GXinvert	/* ropInvert */,		/* dest = !dest */
32 	GXclear	/* ropBlackness */,		/* dest = 0 */
33 	GXandReverse	/* ropNotDestAnd */,		/* dest = (!dest) & src */
34 	GXorReverse	/* ropNotDestOr */,		/* dest = (!dest) | src */
35 	GXset	/* ropWhiteness */,		/* dest = 1 */
36 	GXandInverted /* ropNotSrcAnd */,		/* dest &= !src */
37 	GXorInverted	/* ropNotSrcOr */,		/* dest |= !src */
38 	GXequiv	/* ropNotXor */,		/* dest ^= !src */
39 	GXnand	/* ropNotAnd */,		/* dest = !(src & dest) */
40 	GXnor	/* ropNotOr */,			/* dest = !(src | dest) */
41 	GXnoop	/* ropNoOper */			/* dest = dest */
42 };
43 
44 int
prima_rop_map(int rop)45 prima_rop_map( int rop)
46 {
47 	if ( rop < 0 || rop >= sizeof( rop_map)/sizeof(int))
48 		return GXnoop;
49 	else
50 		return rop_map[ rop];
51 }
52 
53 void
prima_get_gc(PDrawableSysData selfxx)54 prima_get_gc( PDrawableSysData selfxx)
55 {
56 	XGCValues gcv;
57 	Bool bitmap, layered;
58 	struct gc_head *gc_pool;
59 
60 	if ( XX-> gc && XX-> gcl) return;
61 
62 	if ( XX-> gc || XX-> gcl) {
63 		warn( "UAG_010: internal error");
64 		return;
65 	}
66 
67 	bitmap = XT_IS_BITMAP(XX) ? true : false;
68 	layered = XF_LAYERED(XX) ? true : false;
69 	gc_pool = bitmap ? &guts.bitmap_gc_pool : ( layered ? &guts.argb_gc_pool : &guts.screen_gc_pool );
70 	XX->gcl = TAILQ_FIRST(gc_pool);
71 	if (XX->gcl)
72 		TAILQ_REMOVE(gc_pool, XX->gcl, gc_link);
73 	if (!XX->gcl) {
74 		gcv. graphics_exposures = false;
75 		XX-> gc = XCreateGC( DISP, (bitmap || layered) ? XX-> gdrawable : guts. root, GCGraphicsExposures, &gcv);
76 		XCHECKPOINT;
77 		if (( XX->gcl = alloc1z( GCList)))
78 			XX->gcl->gc = XX-> gc;
79 	}
80 	if ( XX-> gcl) XX->gc = XX->gcl->gc;
81 }
82 
83 void
prima_release_gc(PDrawableSysData selfxx)84 prima_release_gc( PDrawableSysData selfxx)
85 {
86 	Bool bitmap, layered;
87 	struct gc_head *gc_pool;
88 
89 	if ( XX-> gc) {
90 		if ( XX-> gcl == NULL)
91 			warn( "UAG_011: internal error");
92 		bitmap = XT_IS_BITMAP(XX) ? true : false;
93 		layered = XF_LAYERED(XX) ? true : false;
94 		gc_pool = bitmap ? &guts.bitmap_gc_pool : ( layered ? &guts.argb_gc_pool : &guts.screen_gc_pool );
95 		if ( XX-> gcl)
96 			TAILQ_INSERT_HEAD(gc_pool, XX->gcl, gc_link);
97 		XX->gcl = NULL;
98 		XX->gc = NULL;
99 	} else {
100 		if ( XX-> gcl) {
101 			warn( "UAG_012: internal error");
102 			return;
103 		}
104 	}
105 }
106 
107 /*
108 	macros to multiply line pattern entries to line width in
109 	a more-less aestethic fashion :-)
110 */
111 #define MAX_DASH_LEN 2048
112 #define dDASH_FIX(line_width,source,length) \
113 	int df_i, df_lw = line_width + .5, df_len = length; \
114 	char df_list[MAX_DASH_LEN], *df_src = (char*)source, *df_dst = df_list
115 #define DASH_FIX \
116 	if ( df_lw > 1) {\
117 		int on = 0;\
118 		if ( df_len > MAX_DASH_LEN) df_len = MAX_DASH_LEN;\
119 		for ( df_i = 0; df_i < df_len; df_i++) {\
120 			unsigned int w = *((unsigned char*)df_src++);\
121 			if (( on = !on)) {\
122 				if ( w > 1) w *= df_lw;\
123 			} else {\
124 				w = w * df_lw + 1;\
125 			}\
126 			if ( w > 255) w = 255;\
127 			*((unsigned char*)df_dst++) = w;\
128 		}\
129 		df_src = df_list;\
130 	}
131 #define DASHES df_src, df_len
132 
133 void
prima_prepare_drawable_for_painting(Handle self,Bool inside_on_paint)134 prima_prepare_drawable_for_painting( Handle self, Bool inside_on_paint)
135 {
136 	DEFXX;
137 	unsigned long mask = VIRGIN_GC_MASK;
138 	int w, h;
139 	XRectangle r;
140 
141 	XF_IN_PAINT(XX) = true;
142 	XX-> btransform. x = XX-> btransform. y = 0;
143 	XX-> gcv. ts_x_origin = XX-> gcv. ts_y_origin = 0;
144 	if ( inside_on_paint && XX-> udrawable && is_opt( optBuffered) && !is_opt( optInDrawInfo) ) {
145 		if ( XX-> invalid_region) {
146 			XClipBox( XX-> invalid_region, &r);
147 			XX-> bsize. x = w = r. width;
148 			XX-> bsize. y = h = r. height;
149 			XX-> btransform. x = - r. x;
150 			XX-> btransform. y = r. y;
151 		} else {
152 			r. x = r. y = 0;
153 			XX-> bsize. x = w = XX-> size. x;
154 			XX-> bsize. y = h = XX-> size. y;
155 		}
156 		if ( w <= 0 || h <= 0) goto Unbuffered;
157 		XX-> gdrawable = XCreatePixmap( DISP, XX-> udrawable, w, h, XX->visual->depth);
158 		XCHECKPOINT;
159 		if (!XX-> gdrawable) goto Unbuffered;
160 		XX-> gcv. ts_x_origin = -r.x;
161 		XX-> gcv. ts_y_origin = -r.y;
162 	} else if ( XX-> udrawable && !XX-> gdrawable) {
163 Unbuffered:
164 		XX-> gdrawable = XX-> udrawable;
165 	}
166 
167 	XX-> paint_rop = XX-> rop;
168 	XX-> paint_rop2 = XX-> rop2;
169 	XX-> paint_alpha = XX-> alpha;
170 	XX-> paint_line_width = XX-> line_width;
171 	XX-> flags. paint_base_line = XX-> flags. base_line;
172 	XX-> flags. paint_opaque    = XX-> flags. opaque;
173 	XX-> saved_font = PDrawable( self)-> font;
174 	XX-> gcv. clip_mask = None;
175 	XX-> gtransform = XX-> transform;
176 	XX-> fill_mode = XX->saved_fill_mode;
177 
178 	prima_get_gc( XX);
179 	XX-> gcv. subwindow_mode = (XX->flags.clip_by_children ? ClipByChildren : IncludeInferiors);
180 
181 	XChangeGC( DISP, XX-> gc, mask, &XX-> gcv);
182 	XCHECKPOINT;
183 
184 	if ( XX-> dashes) {
185 		dDASH_FIX( XX-> paint_line_width, XX-> dashes, XX-> ndashes);
186 		DASH_FIX;
187 		XSetDashes( DISP, XX-> gc, 0, DASHES);
188 		XX-> paint_ndashes = XX-> ndashes;
189 		if (( XX-> paint_dashes = malloc( XX-> ndashes)))
190 			memcpy( XX-> paint_dashes, XX-> dashes, XX-> ndashes);
191 		XX-> line_style = ( XX-> paint_rop2 == ropCopyPut) ? LineDoubleDash : LineOnOffDash;
192 	} else {
193 		XX-> paint_dashes = malloc(1);
194 		if ( XX-> ndashes < 0) {
195 			XX-> paint_dashes[0] = '\0';
196 			XX-> paint_ndashes = 0;
197 		} else {
198 			XX-> paint_dashes[0] = '\1';
199 			XX-> paint_ndashes = 1;
200 		}
201 		XX-> line_style = LineSolid;
202 	}
203 
204 	XX-> clip_rect. x = 0;
205 	XX-> clip_rect. y = 0;
206 	XX-> clip_rect. width = XX-> size.x;
207 	XX-> clip_rect. height = XX-> size.y;
208 	if ( XX-> invalid_region && inside_on_paint && !is_opt( optInDrawInfo)) {
209 		if ( XX-> flags. kill_current_region) {
210 			XDestroyRegion( XX-> current_region);
211 			XX-> flags. kill_current_region = 0;
212 		}
213 		if ( XX-> btransform. x != 0 || XX-> btransform. y != 0) {
214 			Region r = XCreateRegion();
215 			XUnionRegion( r, XX-> invalid_region, r);
216 			XOffsetRegion( r, XX-> btransform. x, -XX-> btransform. y);
217 			XSetRegion( DISP, XX-> gc, r);
218 			XX-> current_region = r;
219 			XX-> flags. kill_current_region = 1;
220 		} else {
221 			XSetRegion( DISP, XX-> gc, XX-> invalid_region);
222 			XX-> current_region = XX-> invalid_region;
223 			XX-> flags. kill_current_region = 0;
224 		}
225 		XX-> paint_region = XX-> invalid_region;
226 		XX-> invalid_region = NULL;
227 	}
228 	XX-> clip_mask_extent. x = XX-> clip_mask_extent. y = 0;
229 	XX-> flags. xft_clip = 0;
230 
231 	apc_gp_set_antialias( self, XX-> flags.saved_antialias);
232 	apc_gp_set_color( self, XX-> saved_fore);
233 	apc_gp_set_back_color( self, XX-> saved_back);
234 	memcpy( XX-> saved_fill_pattern, XX-> fill_pattern, sizeof( FillPattern));
235 	XX-> fill_pattern[0]++; /* force  */
236 	apc_gp_set_fill_pattern( self, XX-> saved_fill_pattern);
237 	XX-> saved_fill_pattern_offset = XX-> fill_pattern_offset;
238 	apc_gp_set_fill_pattern_offset( self, XX-> saved_fill_pattern_offset);
239 
240 	if ( !XX-> flags. reload_font && XX-> font && XX-> font-> id) {
241 		XSetFont( DISP, XX-> gc, XX-> font-> id);
242 		XCHECKPOINT;
243 	} else {
244 		apc_gp_set_font( self, &PDrawable( self)-> font);
245 		XX-> flags. reload_font = false;
246 	}
247 }
248 
249 void
prima_cleanup_drawable_after_painting(Handle self)250 prima_cleanup_drawable_after_painting( Handle self)
251 {
252 	DEFXX;
253 	DELETE_ARGB_PICTURE(XX->argb_picture);
254 #ifdef USE_XFT
255 	prima_xft_gp_destroy( self );
256 #endif
257 	if ( XX-> flags. kill_current_region) {
258 		XDestroyRegion( XX-> current_region);
259 		XX-> flags. kill_current_region = 0;
260 	}
261 	XX-> current_region = 0;
262 	XX-> flags. xft_clip = 0;
263 	if ( XX-> udrawable && XX-> udrawable != XX-> gdrawable && XX-> gdrawable && !is_opt( optInDrawInfo)) {
264 		if ( XX-> paint_region) {
265 			XSetRegion( DISP, XX-> gc, XX-> paint_region);
266 		} else {
267 			Region region = XCreateRegion();
268 			XRectangle r;
269 			r. x = -XX-> btransform. x;
270 			r. y = XX-> btransform. y;
271 			r. width = XX->bsize.x;
272 			r. height = XX->bsize.y;
273 			XUnionRectWithRegion( &r, region, region);
274 			XSetRegion( DISP, XX-> gc, region);
275 			XDestroyRegion( region);
276 		}
277 		XCHECKPOINT;
278 		XSetFunction( DISP, XX-> gc, GXcopy);
279 		XCopyArea( DISP, XX-> gdrawable, XX-> udrawable, XX-> gc,
280 					0, 0,
281 					XX-> bsize.x, XX-> bsize.y,
282 					-XX-> btransform. x, XX-> btransform. y);
283 		XCHECKPOINT;
284 		XFreePixmap( DISP, XX-> gdrawable);
285 		XCHECKPOINT;
286 		XX-> gdrawable = XX-> udrawable;
287 		XX-> btransform. x = XX-> btransform. y = 0;
288 	}
289 	prima_release_gc(XX);
290 	memcpy( XX-> fill_pattern, XX-> saved_fill_pattern, sizeof( FillPattern));
291 	XX-> fill_pattern_offset = XX-> saved_fill_pattern_offset;
292 	if ( XX-> font && ( --XX-> font-> refCnt <= 0)) {
293 		prima_free_rotated_entry( XX-> font);
294 		XX-> font-> refCnt = 0;
295 	}
296 	if ( XX-> paint_dashes) {
297 		free(XX->paint_dashes);
298 		XX-> paint_dashes = NULL;
299 	}
300 	XX-> paint_ndashes = 0;
301 	XF_IN_PAINT(XX) = false;
302 	PDrawable( self)-> font = XX-> saved_font;
303 	if ( XX-> paint_region) {
304 		XDestroyRegion( XX-> paint_region);
305 		XX-> paint_region = NULL;
306 	}
307 	XFlush(DISP);
308 }
309 
310 #define PURE_FOREGROUND if (!XX->flags.brush_fore) {\
311 	XSetForeground( DISP, XX-> gc, XX-> fore. primary);\
312 	XX->flags.brush_fore=1;\
313 }\
314 if (!XX->flags.brush_back && XX-> paint_rop2 == ropCopyPut) {\
315 	XSetBackground( DISP, XX-> gc, XX-> back. primary);\
316 	XX->flags.brush_back=1;\
317 }\
318 XSetFillStyle( DISP, XX-> gc, FillSolid);\
319 
320 Bool
prima_make_brush(DrawableSysData * XX,int colorIndex)321 prima_make_brush( DrawableSysData * XX, int colorIndex)
322 {
323 	Pixmap p;
324 	if ( XT_IS_BITMAP(XX) || ( guts. idepth == 1)) {
325 		int i;
326 		FillPattern mix, *p1, *p2;
327 		if ( colorIndex > 0) return false;
328 		p1 = &guts. ditherPatterns[ 64 - (XX-> fore. primary ? 64 : XX-> fore. balance)];
329 		p2 = &guts. ditherPatterns[ 64 - (XX-> back. primary ? 64 : XX-> back. balance)];
330 		for ( i = 0; i < sizeof( FillPattern); i++)
331 			mix[i] = ((*p1)[i] & XX-> fill_pattern[i]) | ((*p2)[i] & ~XX-> fill_pattern[i]);
332 		XSetForeground( DISP, XX-> gc, 1);
333 		XSetBackground( DISP, XX-> gc, 0);
334 		XX-> flags. brush_fore = 0;
335 		XX-> flags. brush_back = 0;
336 		if (
337 			( memcmp( mix, fillPatterns[ fpSolid], sizeof( FillPattern)) != 0) &&
338 			( p = prima_get_hatch( &mix))
339 			) {
340 			XSetStipple( DISP, XX-> gc, p);
341 			XSetFillStyle( DISP, XX-> gc, FillOpaqueStippled);
342 		} else
343 			XSetFillStyle( DISP, XX-> gc, FillSolid);
344 	} else if ( XX-> flags. brush_null_hatch) {
345 		if ( colorIndex > 0) return false;
346 		if ( XX-> fore. balance) {
347 			p = prima_get_hatch( &guts. ditherPatterns[ XX-> fore. balance]);
348 			if ( p) {
349 				XSetStipple( DISP, XX-> gc, p);
350 				XSetFillStyle( DISP, XX-> gc, FillOpaqueStippled);
351 				XSetBackground( DISP, XX-> gc, XX-> fore. secondary);
352 				XX-> flags. brush_back = 0;
353 			} else /* failure */
354 				XSetFillStyle( DISP, XX-> gc, FillSolid);
355 		} else
356 			XSetFillStyle( DISP, XX-> gc, FillSolid);
357 		if (!XX->flags.brush_fore) {
358 			XSetForeground( DISP, XX-> gc, XX-> fore. primary);
359 			XX->flags.brush_fore = 1;
360 		}
361 	} else if ( XX->fore.balance == 0 && XX->back.balance == 0) {
362 		if ( colorIndex > 0) return false;
363 
364 		p = prima_get_hatch( &XX-> fill_pattern);
365 		XSetFillStyle( DISP, XX-> gc, p ? FillOpaqueStippled : FillSolid);
366 		if ( p) XSetStipple( DISP, XX-> gc, p);
367 		if (!XX->flags.brush_fore) {
368 			XSetForeground( DISP, XX-> gc, XX-> fore. primary);
369 			XX->flags.brush_fore = 1;
370 		}
371 		if (p && !XX->flags.brush_back) {
372 			XSetBackground( DISP, XX-> gc, XX-> back. primary);
373 			XX->flags.brush_back = 1;
374 		}
375 	} else {
376 		switch ( colorIndex) {
377 		case 0: /* back mix */
378 			if ( XX-> back. balance) {
379 				p = prima_get_hatch( &guts. ditherPatterns[ XX-> back. balance]);
380 				if ( p) {
381 					XSetStipple( DISP, XX-> gc, p);
382 					XSetFillStyle( DISP, XX-> gc, FillOpaqueStippled);
383 					XSetBackground( DISP, XX-> gc, XX-> back. secondary);
384 				} else  /* failure */
385 					XSetFillStyle( DISP, XX-> gc, FillSolid);
386 			} else
387 				XSetFillStyle( DISP, XX-> gc, FillSolid);
388 			XSetForeground( DISP, XX-> gc, XX-> back. primary);
389 			XX-> flags. brush_back = 0;
390 			break;
391 		case 1: /* fore mix */
392 			if ( memcmp( XX-> fill_pattern, fillPatterns[fpEmpty], sizeof(FillPattern))==0)
393 				return false;
394 			if ( XX-> fore. balance) {
395 				int i;
396 				FillPattern fp;
397 				memcpy( &fp, &guts. ditherPatterns[ XX-> fore. balance], sizeof(FillPattern));
398 				for ( i = 0; i < 8; i++)
399 					fp[i] &= XX-> fill_pattern[i];
400 				p = prima_get_hatch( &fp);
401 			} else
402 				p = prima_get_hatch( &XX-> fill_pattern);
403 			if ( !p) return false;
404 			XSetStipple( DISP, XX-> gc, p);
405 			XSetFillStyle( DISP, XX-> gc, FillStippled);
406 			if ( !XX-> flags. brush_fore) {
407 				XSetForeground( DISP, XX-> gc, XX-> fore. primary);
408 				XX-> flags. brush_fore = 1;
409 			}
410 			break;
411 		case 2: /* fore mix with fill pattern */
412 			if ( memcmp( XX-> fill_pattern, fillPatterns[fpEmpty], sizeof(FillPattern))==0)
413 				return false;
414 			if ( XX-> fore. balance ) {
415 				int i;
416 				FillPattern fp;
417 				memcpy( &fp, &guts. ditherPatterns[ XX-> fore. balance], sizeof(FillPattern));
418 				for ( i = 0; i < 8; i++)
419 					fp[i] = (~fp[i]) & XX-> fill_pattern[i];
420 				p = prima_get_hatch( &fp);
421 				if ( !p) return false;
422 				XSetStipple( DISP, XX-> gc, p);
423 				XSetFillStyle( DISP, XX-> gc, FillStippled);
424 				XSetForeground( DISP, XX-> gc, XX-> fore. secondary);
425 				XX-> flags. brush_fore = 0;
426 				break;
427 			} else
428 				return false;
429 		default:
430 			return false;
431 		}
432 	}
433 	return true;
434 }
435 
436 Bool
apc_gp_init(Handle self)437 apc_gp_init( Handle self)
438 {
439 	if ( guts. dynamicColors && !prima_palette_alloc( self)) return false;
440 	return true;
441 }
442 
443 Bool
apc_gp_done(Handle self)444 apc_gp_done( Handle self)
445 {
446 	DEFXX;
447 	if (!XX) return false;
448 	if ( XX-> dashes) {
449 		free(XX-> dashes);
450 		XX-> dashes = NULL;
451 	}
452 	XX-> ndashes = 0;
453 	if ( guts. dynamicColors) {
454 		prima_palette_free( self, true);
455 		free(XX-> palette);
456 	}
457 	prima_release_gc(XX);
458 	return true;
459 }
460 
461 static int
arc_completion(double * angleStart,double * angleEnd,int * needFigure)462 arc_completion( double * angleStart, double * angleEnd, int * needFigure)
463 {
464 	int max;
465 	long diff = (long)( fabs( *angleEnd - *angleStart) * 64 + 0.5);
466 
467 	if ( diff == 0) {
468 		*needFigure = false;
469 		return 0;
470 	}
471 	diff /= 64;
472 
473 	while ( *angleStart > *angleEnd)
474 		*angleEnd += 360;
475 
476 	while ( *angleStart < 0) {
477 		*angleStart += 360;
478 		*angleEnd   += 360;
479 	}
480 
481 	while ( *angleStart >= 360) {
482 		*angleStart -= 360;
483 		*angleEnd   -= 360;
484 	}
485 
486 	while ( *angleEnd >= *angleStart + 360)
487 		*angleEnd -= 360;
488 
489 	if ( diff < 360) {
490 		*needFigure = true;
491 		return 0;
492 	}
493 
494 	max = (int)(diff / 360);
495 	*needFigure = ( max * 360) != diff;
496 	return ( max % 2) ? 1 : 2;
497 }
498 
499 static void
calculate_ellipse_divergence(void)500 calculate_ellipse_divergence(void)
501 {
502 	static Bool init = false;
503 	if ( !init) {
504 		XGCValues gcv;
505 		Pixmap px = XCreatePixmap( DISP, guts.root, 4, 4, 1);
506 		GC gc = XCreateGC( DISP, px, 0, &gcv);
507 		XImage *xi;
508 		XSetForeground( DISP, gc, 0);
509 		XFillRectangle( DISP, px, gc, 0, 0, 5, 5);
510 		XSetForeground( DISP, gc, 1);
511 		XDrawArc( DISP, px, gc, 0, 0, 4, 4, 0, 360 * 64);
512 		if (( xi = XGetImage( DISP, px, 0, 0, 4, 4, 1, XYPixmap))) {
513 			int i;
514 			Byte *data[4];
515 			if ( xi-> bitmap_bit_order == LSBFirst)
516 				prima_mirror_bytes(( Byte*) xi-> data, xi-> bytes_per_line * 4);
517 			for ( i = 0; i < 4; i++) data[i] = (Byte*)xi-> data + i * xi-> bytes_per_line;
518 #define PIX(x,y) ((data[y][0] & (0x80>>(x)))!=0)
519 			if (  PIX(2,1) && !PIX(3,1)) guts. ellipseDivergence.x = -1; else
520 			if ( !PIX(2,1) && !PIX(3,1)) guts. ellipseDivergence.x = 1;
521 			if (  PIX(1,2) && !PIX(1,3)) guts. ellipseDivergence.y = -1; else
522 			if ( !PIX(1,2) && !PIX(1,3)) guts. ellipseDivergence.y = 1;
523 #undef PIX
524 			XDestroyImage( xi);
525 		}
526 		XFreeGC( DISP, gc);
527 		XFreePixmap( DISP, px);
528 		init = true;
529 	}
530 }
531 
532 #define ELLIPSE_RECT x - ( dX + 1) / 2 + 1, y - dY / 2, dX-guts.ellipseDivergence.x, dY-guts.ellipseDivergence.y
533 #define FILL_ANTIDEFECT_REPAIRABLE (((XX->fill_mode & fmOverlay) != 0) && \
534 		( rop_map[XX-> paint_rop] == GXcopy ||\
535 		rop_map[XX-> paint_rop] == GXset  ||\
536 		rop_map[XX-> paint_rop] == GXclear))
537 #define FILL_ANTIDEFECT_OPEN {\
538 XGCValues gcv;\
539 gcv. line_width = 1;\
540 gcv. line_style = LineSolid;\
541 XChangeGC( DISP, XX-> gc, GCLineWidth, &gcv);\
542 }
543 #define FILL_ANTIDEFECT_CLOSE {\
544 XGCValues gcv;\
545 gcv. line_width = XX-> paint_line_width + .5;\
546 XChangeGC( DISP, XX-> gc, GCLineWidth, &gcv);\
547 }
548 
549 Bool
apc_gp_arc(Handle self,int x,int y,int dX,int dY,double angleStart,double angleEnd)550 apc_gp_arc( Handle self, int x, int y, int dX, int dY, double angleStart, double angleEnd)
551 {
552 	DEFXX;
553 	int compl, needf;
554 
555 	if ( PObject( self)-> options. optInDrawInfo) return false;
556 	if ( !XF_IN_PAINT(XX)) return false;
557 	if ( dX <= 0 || dY <= 0) return false;
558 	RANGE4(x, y, dX, dY);
559 
560 	SHIFT( x, y);
561 	y = REVERT( y);
562 	PURE_FOREGROUND;
563 	calculate_ellipse_divergence();
564 	compl = arc_completion( &angleStart, &angleEnd, &needf);
565 	while ( compl--)
566 		XDrawArc( DISP, XX-> gdrawable, XX-> gc, ELLIPSE_RECT, 0, 360 * 64);
567 	if ( needf)
568 		XDrawArc( DISP, XX-> gdrawable, XX-> gc, ELLIPSE_RECT,
569 			angleStart * 64, ( angleEnd - angleStart) * 64);
570 	XFLUSH;
571 	return true;
572 }
573 
574 Bool
apc_gp_bar(Handle self,int x1,int y1,int x2,int y2)575 apc_gp_bar( Handle self, int x1, int y1, int x2, int y2)
576 {
577 	DEFXX;
578 	int mix = 0;
579 
580 	if ( PObject( self)-> options. optInDrawInfo) return false;
581 	if ( !XF_IN_PAINT(XX)) return false;
582 
583 	SHIFT( x1, y1); SHIFT( x2, y2);
584 	SORT( x1, x2); SORT( y1, y2);
585 	RANGE4( x1, y1, x2, y2);
586 	while ( prima_make_brush( XX, mix++))
587 		XFillRectangle( DISP, XX-> gdrawable, XX-> gc, x1, REVERT( y2), x2 - x1 + 1, y2 - y1 + 1);
588 	XCHECKPOINT;
589 	XFLUSH;
590 	return true;
591 }
592 
593 Bool
apc_gp_bars(Handle self,int nr,Rect * rr)594 apc_gp_bars( Handle self, int nr, Rect *rr)
595 {
596 	DEFXX;
597 	XRectangle *r, *rp;
598 	int i, mix = 0;
599 
600 	if ( PObject( self)-> options. optInDrawInfo) return false;
601 	if ( !XF_IN_PAINT(XX)) return false;
602 	if ((r = malloc( sizeof( XRectangle)*nr)) == NULL) return false;
603 
604 	for ( i = 0, rp = r; i < nr; i++, rr++, rp++) {
605 		SHIFT( rr->left,rr-> bottom); SHIFT( rr->right, rr->top);
606 		SORT( rr->left, rr->right); SORT( rr->bottom, rr->top);
607 		RANGE4( rr->left, rr->bottom, rr->right, rr->top);
608 		rp->x = rr->left;
609 		rp->y = REVERT(rr->top);
610 		rp->width = rr->right - rr->left + 1;
611 		rp->height = rr->top - rr->bottom + 1;
612 	}
613 
614 	while ( prima_make_brush( XX, mix++))
615 		XFillRectangles( DISP, XX-> gdrawable, XX-> gc, r, nr);
616 
617 	XCHECKPOINT;
618 	XFLUSH;
619 	free( r);
620 	return true;
621 }
622 
623 Bool
apc_gp_alpha(Handle self,int alpha,int x1,int y1,int x2,int y2)624 apc_gp_alpha( Handle self, int alpha, int x1, int y1, int x2, int y2)
625 {
626 	DEFXX;
627 	int pixel;
628 
629 	if ( PObject( self)-> options. optInDrawInfo) return false;
630 	if ( !XF_IN_PAINT(XX)) return false;
631 	if ( !XF_LAYERED(XX)) return false;
632 	if ( XT_IS_WIDGET(XX) && !XX->flags. layered_requested) return false;
633 
634 	if ( x1 < 0 && y1 < 0 && x2 < 0 && y2 < 0) {
635 		x1 = 0; y1 = 0;
636 		x2 = XX-> size. x - 1;
637 		y2 = XX-> size. y - 1;
638 	}
639 	SHIFT( x1, y1); SHIFT( x2, y2);
640 	SORT( x1, x2); SORT( y1, y2);
641 	RANGE4( x1, y1, x2, y2);
642 
643 	pixel = ((alpha << guts. argb_bits. alpha_range) >> 8) << guts. argb_bits. alpha_shift;
644 	XSetForeground( DISP, XX-> gc, pixel);
645 	XX-> flags. brush_fore = 0;
646 	XSetPlaneMask( DISP, XX-> gc, guts. argb_bits. alpha_mask);
647 	XFillRectangle( DISP, XX-> gdrawable, XX-> gc, x1, REVERT( y2), x2 - x1 + 1, y2 - y1 + 1);
648 	XSetPlaneMask( DISP, XX-> gc, AllPlanes);
649 	XFLUSH;
650 
651 	return true;
652 }
653 
654 Bool
apc_gp_can_draw_alpha(Handle self)655 apc_gp_can_draw_alpha( Handle self)
656 {
657 	DEFXX;
658 	if (XT_IS_BITMAP(XX) || (( XT_IS_PIXMAP(XX) || XT_IS_APPLICATION(XX)) && guts.depth==1))
659 		return false;
660 	else
661 		return
662 			guts.render_extension
663 #ifdef WITH_COCOA
664 			&& !prima_cocoa_is_x11_local()
665 #endif
666 		;
667 }
668 
669 Bool
apc_gp_clear(Handle self,int x1,int y1,int x2,int y2)670 apc_gp_clear( Handle self, int x1, int y1, int x2, int y2)
671 {
672 	DEFXX;
673 
674 	if ( PObject( self)-> options. optInDrawInfo) return false;
675 	if ( !XF_IN_PAINT(XX)) return false;
676 
677 	if ( x1 < 0 && y1 < 0 && x2 < 0 && y2 < 0) {
678 		x1 = 0; y1 = 0;
679 		x2 = XX-> size. x - 1;
680 		y2 = XX-> size. y - 1;
681 	}
682 	SHIFT( x1, y1); SHIFT( x2, y2);
683 	SORT( x1, x2); SORT( y1, y2);
684 	RANGE4( x1, y1, x2, y2);
685 
686 	/* clean color entries, leave just background & foreground. XXX */
687 	if ( guts. dynamicColors && x1 <= 0 && x2 > XX-> size.x && y1 <= 0 && y2 >= XX-> size.y) {
688 		prima_palette_free(self,false);
689 		apc_gp_set_color(self, XX-> fore. color);
690 		apc_gp_set_back_color(self, XX-> back. color);
691 	}
692 
693 	XSetForeground( DISP, XX-> gc, XX-> back. primary);
694 	if ( XX-> back. balance > 0) {
695 		Pixmap p = prima_get_hatch( &guts. ditherPatterns[ XX-> back. balance]);
696 		if ( p) {
697 			XSetFillStyle( DISP, XX-> gc, FillOpaqueStippled);
698 			XSetStipple( DISP, XX-> gc, p);
699 			XSetBackground( DISP, XX-> gc, XX-> back. secondary);
700 		} else
701 			XSetFillStyle( DISP, XX-> gc, FillSolid);
702 	} else
703 		XSetFillStyle( DISP, XX-> gc, FillSolid);
704 	XX-> flags. brush_fore = 0;
705 	XFillRectangle( DISP, XX-> gdrawable, XX-> gc, x1, REVERT( y2), x2 - x1 + 1, y2 - y1 + 1);
706 	XFLUSH;
707 
708 	return true;
709 }
710 
711 #define GRAD 57.29577951
712 
713 Bool
apc_gp_chord(Handle self,int x,int y,int dX,int dY,double angleStart,double angleEnd)714 apc_gp_chord( Handle self, int x, int y, int dX, int dY, double angleStart, double angleEnd)
715 {
716 	int compl, needf;
717 	DEFXX;
718 
719 	if ( PObject( self)-> options. optInDrawInfo) return false;
720 	if ( !XF_IN_PAINT(XX)) return false;
721 	if ( dX <= 0 || dY <= 0) return false;
722 	RANGE4(x, y, dX, dY);
723 
724 	SHIFT( x, y);
725 	y = REVERT( y);
726 	PURE_FOREGROUND;
727 	compl = arc_completion( &angleStart, &angleEnd, &needf);
728 	calculate_ellipse_divergence();
729 	while ( compl--)
730 		XDrawArc( DISP, XX-> gdrawable, XX-> gc, ELLIPSE_RECT, 0, 360 * 64);
731 	if ( !needf) return true;
732 	XDrawArc( DISP, XX-> gdrawable, XX-> gc, ELLIPSE_RECT,
733 		angleStart * 64, ( angleEnd - angleStart) * 64);
734 	XDrawLine( DISP, XX-> gdrawable, XX-> gc,
735 		x + cos( angleStart / GRAD) * dX / 2, y - sin( angleStart / GRAD) * dY / 2,
736 		x + cos( angleEnd / GRAD) * dX / 2,   y - sin( angleEnd / GRAD) * dY / 2);
737 	XFLUSH;
738 	return true;
739 }
740 
741 Bool
apc_gp_draw_poly(Handle self,int n,Point * pp)742 apc_gp_draw_poly( Handle self, int n, Point *pp)
743 {
744 	DEFXX;
745 	int i;
746 	int x = XX-> gtransform. x + XX-> btransform. x;
747 	int y = XX-> size. y - 1 - XX-> gtransform. y - XX-> btransform. y;
748 	XPoint *p;
749 
750 	if ( PObject( self)-> options. optInDrawInfo) return false;
751 	if ( !XF_IN_PAINT(XX)) return false;
752 
753 	if ((p = malloc( sizeof( XPoint)*n)) == NULL)
754 		return false;
755 
756 	for ( i = 0; i < n; i++) {
757 		p[i].x = pp[i].x + x;
758 		p[i].y = y - pp[i].y;
759 		RANGE2(p[i].x, p[i].y);
760 	}
761 
762 	PURE_FOREGROUND;
763 	XDrawLines( DISP, XX-> gdrawable, XX-> gc, p, n, CoordModeOrigin);
764 
765 	free( p);
766 	XFLUSH;
767 	return true;
768 }
769 
770 Bool
apc_gp_draw_poly2(Handle self,int np,Point * pp)771 apc_gp_draw_poly2( Handle self, int np, Point *pp)
772 {
773 	DEFXX;
774 	int i;
775 	int x = XX-> gtransform. x + XX-> btransform. x;
776 	int y = XX-> size. y - 1 - XX-> gtransform. y - XX-> btransform. y;
777 	XSegment *s;
778 	int n = np / 2;
779 
780 	if ( PObject( self)-> options. optInDrawInfo) return false;
781 	if ( !XF_IN_PAINT(XX)) return false;
782 
783 	if ((s = malloc( sizeof( XSegment)*n)) == NULL) return false;
784 
785 	for ( i = 0; i < n; i++) {
786 		s[i].x1 = pp[i*2].x + x;
787 		s[i].y1 = y - pp[i*2].y;
788 		s[i].x2 = pp[i*2+1].x + x;
789 		s[i].y2 = y - pp[i*2+1].y;
790 		RANGE4(s[i].x1, s[i].y1, s[i].x2, s[i].y2);
791 	}
792 
793 	PURE_FOREGROUND;
794 	XDrawSegments( DISP, XX-> gdrawable, XX-> gc, s, n);
795 
796 	free( s);
797 	XFLUSH;
798 	return true;
799 }
800 
801 Bool
apc_gp_ellipse(Handle self,int x,int y,int dX,int dY)802 apc_gp_ellipse( Handle self, int x, int y, int dX, int dY)
803 {
804 	DEFXX;
805 
806 	if ( dX == 1 || dY == 1 ) /* Xorg bug */
807 		return apc_gp_rectangle( self, x - dX / 2, y - dY / 2, x + dX / 2, y + dY / 2);
808 
809 	if ( PObject( self)-> options. optInDrawInfo) return false;
810 	if ( !XF_IN_PAINT(XX)) return false;
811 	if ( dX <= 0 || dY <= 0) return false;
812 	RANGE4(x, y, dX, dY);
813 
814 	SHIFT( x, y);
815 	y = REVERT( y);
816 	PURE_FOREGROUND;
817 	calculate_ellipse_divergence();
818 	XDrawArc( DISP, XX-> gdrawable, XX-> gc, ELLIPSE_RECT, 0, 64*360);
819 	XFLUSH;
820 	return true;
821 }
822 
823 Bool
apc_gp_fill_chord(Handle self,int x,int y,int dX,int dY,double angleStart,double angleEnd)824 apc_gp_fill_chord( Handle self, int x, int y, int dX, int dY, double angleStart, double angleEnd)
825 {
826 	DEFXX;
827 	int compl, needf, mix = 0;
828 
829 	if ( PObject( self)-> options. optInDrawInfo) return false;
830 	if ( !XF_IN_PAINT(XX)) return false;
831 	if ( dX <= 0 || dY <= 0) return false;
832 	RANGE4(x, y, dX, dY);
833 
834 	SHIFT( x, y);
835 	y = REVERT( y);
836 
837 	XSetArcMode( DISP, XX-> gc, ArcChord);
838 	FILL_ANTIDEFECT_OPEN;
839 
840 	while ( prima_make_brush( XX, mix++)) {
841 		compl = arc_completion( &angleStart, &angleEnd, &needf);
842 		while ( compl--) {
843 			XFillArc( DISP, XX-> gdrawable, XX-> gc, x - ( dX + 1) / 2 + 1, y - dY / 2, dX, dY, 0, 64*360);
844 			if ( FILL_ANTIDEFECT_REPAIRABLE)
845 				XDrawArc( DISP, XX-> gdrawable, XX-> gc, x - ( dX + 1) / 2 + 1, y - dY / 2, dX-1, dY-1, 0, 64*360);
846 		}
847 
848 		if ( needf) {
849 			XFillArc( DISP, XX-> gdrawable, XX-> gc, x - ( dX + 1) / 2 + 1, y - dY / 2, dX, dY,
850 				angleStart * 64, ( angleEnd - angleStart) * 64);
851 			if ( FILL_ANTIDEFECT_REPAIRABLE)
852 				XDrawArc( DISP, XX-> gdrawable, XX-> gc, x - ( dX + 1) / 2 + 1, y - dY / 2, dX-1, dY-1,
853 					angleStart * 64, ( angleEnd - angleStart) * 64);
854 		}
855 	}
856 	FILL_ANTIDEFECT_CLOSE;
857 	XFLUSH;
858 	return true;
859 }
860 
861 Bool
apc_gp_fill_ellipse(Handle self,int x,int y,int dX,int dY)862 apc_gp_fill_ellipse( Handle self, int x, int y,  int dX, int dY)
863 {
864 	DEFXX;
865 	int mix = 0;
866 
867 	if ( dX == 1 || dY == 1 ) /* Xorg bug */
868 		return apc_gp_bar( self, x - dX / 2, y - dY / 2, x + dX / 2, y + dY / 2);
869 
870 	if ( PObject( self)-> options. optInDrawInfo) return false;
871 	if ( !XF_IN_PAINT(XX)) return false;
872 	if ( dX <= 0 || dY <= 0) return false;
873 	RANGE4(x, y, dX, dY);
874 	SHIFT( x, y);
875 	y = REVERT( y);
876 
877 	FILL_ANTIDEFECT_OPEN;
878 	while ( prima_make_brush( XX, mix++)) {
879 		XFillArc( DISP, XX-> gdrawable, XX-> gc, x - ( dX + 1) / 2 + 1, y - dY / 2, dX, dY, 0, 64*360);
880 		if ( FILL_ANTIDEFECT_REPAIRABLE)
881 			XDrawArc( DISP, XX-> gdrawable, XX-> gc, x - ( dX + 1) / 2 + 1, y - dY / 2, dX-1, dY-1, 0, 64*360);
882 	}
883 	FILL_ANTIDEFECT_CLOSE;
884 	XFLUSH;
885 	return true;
886 }
887 
888 Bool
apc_gp_fill_poly(Handle self,int numPts,Point * points)889 apc_gp_fill_poly( Handle self, int numPts, Point *points)
890 {
891 	/* XXX - beware, current implementation will not deal correctly with different rops and tiles */
892 	XPoint *p;
893 	DEFXX;
894 	int i, mix = 0;
895 
896 	if ( PObject( self)-> options. optInDrawInfo) return false;
897 	if ( !XF_IN_PAINT(XX)) return false;
898 
899 	if ( !( p = malloc(( numPts + 1) * sizeof( XPoint)))) return false;
900 
901 	for ( i = 0; i < numPts; i++) {
902 		p[i]. x = (short)points[i]. x + XX-> gtransform. x + XX-> btransform. x;
903 		p[i]. y = (short)REVERT(points[i]. y + XX-> gtransform. y + XX-> btransform. y);
904 		RANGE2(p[i].x, p[i].y);
905 	}
906 	p[numPts]. x = (short)points[0]. x + XX-> gtransform. x + XX-> btransform. x;
907 	p[numPts]. y = (short)REVERT(points[0]. y + XX-> gtransform. y + XX-> btransform. y);
908 	RANGE2(p[numPts].x, p[numPts].y);
909 
910 	FILL_ANTIDEFECT_OPEN;
911 	if ( guts. limits. XFillPolygon >= numPts) {
912 		while ( prima_make_brush( XX, mix++)) {
913 			XFillPolygon( DISP, XX-> gdrawable, XX-> gc, p, numPts, ComplexShape, CoordModeOrigin);
914 			if ( FILL_ANTIDEFECT_REPAIRABLE) {
915 				XDrawLines( DISP, XX-> gdrawable, XX-> gc, p, numPts+1, CoordModeOrigin);
916 			}
917 		}
918 		XCHECKPOINT;
919 	} else
920 		warn( "Prima::Drawable::fill_poly: too many points");
921 	FILL_ANTIDEFECT_CLOSE;
922 	free( p);
923 	XFLUSH;
924 	return true;
925 }
926 
927 Bool
apc_gp_fill_sector(Handle self,int x,int y,int dX,int dY,double angleStart,double angleEnd)928 apc_gp_fill_sector( Handle self, int x, int y, int dX, int dY, double angleStart, double angleEnd)
929 {
930 	DEFXX;
931 	int compl, needf, mix = 0;
932 
933 	if ( PObject( self)-> options. optInDrawInfo) return false;
934 	if ( !XF_IN_PAINT(XX)) return false;
935 	if ( dX <= 0 || dY <= 0) return false;
936 	RANGE4(x, y, dX, dY);
937 
938 	SHIFT( x, y);
939 	y = REVERT( y);
940 	XSetArcMode( DISP, XX-> gc, ArcPieSlice);
941 
942 	FILL_ANTIDEFECT_OPEN;
943 	while ( prima_make_brush( XX, mix++)) {
944 		compl = arc_completion( &angleStart, &angleEnd, &needf);
945 		while ( compl--) {
946 			XFillArc( DISP, XX-> gdrawable, XX-> gc, x - ( dX + 1) / 2 + 1, y - dY / 2, dX, dY, 0, 64*360);
947 			if ( FILL_ANTIDEFECT_REPAIRABLE)
948 				XDrawArc( DISP, XX-> gdrawable, XX-> gc, x - ( dX + 1) / 2 + 1, y - dY / 2, dX-1, dY-1, 0, 64*360);
949 		}
950 
951 		if ( needf) {
952 			XFillArc( DISP, XX-> gdrawable, XX-> gc, x - ( dX + 1) / 2 + 1, y - dY / 2, dX, dY,
953 				angleStart * 64, ( angleEnd - angleStart) * 64);
954 			if ( FILL_ANTIDEFECT_REPAIRABLE)
955 				XDrawArc( DISP, XX-> gdrawable, XX-> gc, x - ( dX + 1) / 2 + 1, y - dY / 2, dX-1, dY-1,
956 					angleStart * 64, ( angleEnd - angleStart) * 64);
957 		}
958 	}
959 	FILL_ANTIDEFECT_CLOSE;
960 	XFLUSH;
961 	return true;
962 }
963 
964 static int
get_pixel_depth(int depth)965 get_pixel_depth( int depth)
966 {
967 	if ( depth ==  1) return  1; else
968 	if ( depth <=  4) return  4; else
969 	if ( depth <=  8) return  8; else
970 	if ( depth <= 16) return 16; else
971 	if ( depth <= 24) return 24; else
972 	return 32;
973 }
974 
975 
976 static uint32_t
color_to_pixel(Handle self,Color color,int depth)977 color_to_pixel( Handle self, Color color, int depth)
978 {
979 	uint32_t pv;
980 
981 	if ( depth == 1) {
982 		pv = color ? 1 : 0;
983 	} else if ( guts.palSize > 0 ) {
984 		pv = prima_color_find( self, color, -1, NULL, RANK_FREE);
985 	} else {
986 		PRGBABitDescription bd = GET_RGBA_DESCRIPTION;
987 		switch ( depth) {
988 		case 16:
989 		case 24:
990 		case 32:
991 			pv =
992 				(((COLOR_R(color) << bd-> red_range  ) >> 8) << bd->   red_shift) |
993 				(((COLOR_G(color) << bd-> green_range) >> 8) << bd-> green_shift) |
994 				(((COLOR_B(color) << bd-> blue_range ) >> 8) << bd->  blue_shift);
995 			if ( guts.machine_byte_order != guts.byte_order)
996 				switch( depth) {
997 				case 16:
998 					pv = REVERSE_BYTES_16( pv);
999 					break;
1000 				case 24:
1001 					pv = REVERSE_BYTES_24( pv);
1002 					break;
1003 				case 32:
1004 					pv = REVERSE_BYTES_32( pv);
1005 					break;
1006 				}
1007 			break;
1008 		default:
1009 			warn("UAG_005: Not supported pixel depth");
1010 			return 0;
1011 		}
1012 	}
1013 	return pv;
1014 }
1015 
1016 typedef struct {
1017 	XImage *  i;
1018 	Rect      clip;
1019 	uint32_t  color;
1020 	int       depth;
1021 	int       y;
1022 	Bool      singleBorder;
1023 	XDrawable drawable;
1024 	GC        gc;
1025 	int       first;
1026 	PList  *  lists;
1027 } FillSession;
1028 
1029 static Bool
fs_get_pixel(FillSession * fs,int x,int y)1030 fs_get_pixel( FillSession * fs, int x, int y)
1031 {
1032 	if ( x < fs-> clip. left || x > fs-> clip. right || y < fs-> clip. top || y > fs-> clip. bottom)  {
1033 		return false;
1034 	}
1035 
1036 	if ( fs-> lists[ y - fs-> first]) {
1037 		PList l = fs-> lists[ y - fs-> first];
1038 		int i;
1039 		for ( i = 0; i < l-> count; i+=2) {
1040 			if (((int) l-> items[i+1] >= x) && ((int)l->items[i] <= x))
1041 				return false;
1042 		}
1043 	}
1044 
1045 	if ( !fs-> i || y != fs-> y) {
1046 		XCHECKPOINT;
1047 		if ( fs-> i) XDestroyImage( fs-> i);
1048 		XCHECKPOINT;
1049 		fs-> i = XGetImage( DISP, fs-> drawable, fs-> clip. left, y,
1050 								fs-> clip. right - fs-> clip. left + 1, 1,
1051 								( fs-> depth == 1) ? 1 : AllPlanes,
1052 								( fs-> depth == 1) ? XYPixmap : ZPixmap);
1053 		XCHECKPOINT;
1054 		if ( !fs-> i) {
1055 			return false;
1056 		}
1057 		fs-> y = y;
1058 	}
1059 
1060 	x -= fs-> clip. left;
1061 
1062 	switch( fs-> depth) {
1063 	case 1:
1064 		{
1065 			Byte xz = *((Byte*)(fs->i->data) + (x >> 3));
1066 			uint32_t v = ( guts.bit_order == MSBFirst) ?
1067 				( xz & ( 0x80 >> ( x & 7)) ? 1 : 0) :
1068 				( xz & ( 0x01 << ( x & 7)) ? 1 : 0);
1069 			return fs-> singleBorder ?
1070 				( v == fs-> color) : ( v != fs-> color);
1071 		}
1072 		break;
1073 	case 4:
1074 		{
1075 			Byte xz = *((Byte*)(fs->i->data) + (x >> 1));
1076 			uint32_t v = ( x & 1) ? ( xz & 0xF) : ( xz >> 4);
1077 			return fs-> singleBorder ?
1078 				( v == fs-> color) : ( v != fs-> color);
1079 		}
1080 		break;
1081 	case 8:
1082 	return fs-> singleBorder ?
1083 		( fs-> color == *((Byte*)(fs->i->data) + x)) :
1084 		( fs-> color != *((Byte*)(fs->i->data) + x));
1085 	case 16:
1086 	return fs-> singleBorder ?
1087 		( fs-> color == *((uint16_t*)(fs->i->data) + x)):
1088 		( fs-> color != *((uint16_t*)(fs->i->data) + x));
1089 	case 24:
1090 		return fs-> singleBorder ?
1091 		( memcmp(( Byte*)(fs->i->data) + x, &fs->color, 3) == 0) :
1092 		( memcmp(( Byte*)(fs->i->data) + x, &fs->color, 3) != 0);
1093 	case 32:
1094 		return fs-> singleBorder ?
1095 		( fs-> color == *((uint32_t*)(fs->i->data) + x)):
1096 		( fs-> color != *((uint32_t*)(fs->i->data) + x));
1097 	}
1098 	return false;
1099 }
1100 
1101 static void
hline(FillSession * fs,int x1,int y,int x2)1102 hline( FillSession * fs, int x1, int y, int x2)
1103 {
1104 	XFillRectangle( DISP, fs-> drawable, fs-> gc, x1, y, x2 - x1 + 1, 1);
1105 
1106 	if ( y == fs-> y && fs-> i) {
1107 		XDestroyImage( fs-> i);
1108 		fs-> i = NULL;
1109 	}
1110 
1111 	y -= fs-> first;
1112 
1113 	if ( fs-> lists[y] == NULL)
1114 		fs-> lists[y] = plist_create( 32, 128);
1115 	list_add( fs-> lists[y], ( Handle) x1);
1116 	list_add( fs-> lists[y], ( Handle) x2);
1117 }
1118 
1119 static int
fill(FillSession * fs,int sx,int sy,int d,int pxl,int pxr)1120 fill( FillSession * fs, int sx, int sy, int d, int pxl, int pxr)
1121 {
1122 	int x, xr = sx;
1123 	while ( sx > fs-> clip. left  && fs_get_pixel( fs, sx - 1, sy)) sx--;
1124 	while ( xr < fs-> clip. right && fs_get_pixel( fs, xr + 1, sy)) xr++;
1125 	hline( fs, sx, sy, xr);
1126 
1127 	if ( sy + d >= fs-> clip. top && sy + d <= fs-> clip. bottom) {
1128 		x = sx;
1129 		while ( x <= xr) {
1130 			if ( fs_get_pixel( fs, x, sy + d)) {
1131 				x = fill( fs, x, sy + d, d, sx, xr);
1132 			}
1133 			x++;
1134 		}
1135 	}
1136 
1137 	if ( sy - d >= fs-> clip. top && sy - d <= fs-> clip. bottom) {
1138 		x = sx;
1139 		while ( x < pxl) {
1140 			if ( fs_get_pixel( fs, x, sy - d)) {
1141 				x = fill( fs, x, sy - d, -d, sx, xr);
1142 			}
1143 			x++;
1144 		}
1145 		x = pxr;
1146 		while ( x <= xr) {
1147 			if ( fs_get_pixel( fs, x, sy - d)) {
1148 				x = fill( fs, x, sy - d, -d, sx, xr);
1149 			}
1150 			x++;
1151 		}
1152 	}
1153 	return xr;
1154 }
1155 
1156 Bool
apc_gp_flood_fill(Handle self,int x,int y,Color color,Bool singleBorder)1157 apc_gp_flood_fill( Handle self, int x, int y, Color color, Bool singleBorder)
1158 {
1159 	DEFXX;
1160 	Bool ret = false;
1161 	XRectangle cr;
1162 	FillSession s;
1163 	int mix = 0, hint;
1164 
1165 	if ( !opt_InPaint) return false;
1166 
1167 	s. singleBorder = singleBorder;
1168 	s. drawable     = XX-> gdrawable;
1169 	s. gc           = XX-> gc;
1170 	SHIFT( x, y);
1171 	y = REVERT( y);
1172 	color = prima_map_color( color, &hint);
1173 	prima_gp_get_clip_rect( self, &cr, 1);
1174 
1175 	s. clip. left   = cr. x;
1176 	s. clip. top    = cr. y;
1177 	s. clip. right  = cr. x + cr. width  - 1;
1178 	s. clip. bottom = cr. y + cr. height - 1;
1179 	if ( cr. width <= 0 || cr. height <= 0) return false;
1180 	s. i = NULL;
1181 	s. depth = XT_IS_BITMAP(X(self)) ? 1 : guts. idepth;
1182 	s. depth = get_pixel_depth( s. depth);
1183 	s. color = hint ?
1184 		(( hint == COLORHINT_BLACK) ? LOGCOLOR_BLACK : LOGCOLOR_WHITE)
1185 		: color_to_pixel( self, color, s.depth);
1186 
1187 	s. first = s. clip. top;
1188 	if ( !( s. lists = malloc(( s. clip. bottom - s. clip. top + 1) * sizeof( void*))))
1189 		return false;
1190 	bzero( s. lists, ( s. clip. bottom - s. clip. top + 1) * sizeof( void*));
1191 
1192 	prima_make_brush( XX, mix++);
1193 	if ( fs_get_pixel( &s, x, y)) {
1194 		fill( &s, x, y, -1, x, x);
1195 		ret = true;
1196 	}
1197 
1198 	while ( prima_make_brush( XX, mix++)) {
1199 		for ( y = 0; y < s. clip. bottom - s. clip. top + 1; y++)
1200 			if ( s. lists[y])
1201 				for ( x = 0; x < s.lists[y]-> count; x += 2)
1202 					XFillRectangle( DISP, s.drawable, s.gc,
1203 						(int)s.lists[y]->items[x], y,
1204 						(int)s.lists[y]->items[x+1] - (int)s.lists[y]->items[x], 1);
1205 	}
1206 
1207 	if ( s. i) XDestroyImage( s. i);
1208 
1209 	for ( x = 0; x < s. clip. bottom - s. clip. top + 1; x++)
1210 		if ( s. lists[x])
1211 			plist_destroy( s.lists[x]);
1212 	free( s. lists);
1213 	XFLUSH;
1214 
1215 	return ret;
1216 }
1217 
1218 Color
apc_gp_get_pixel(Handle self,int x,int y)1219 apc_gp_get_pixel( Handle self, int x, int y)
1220 {
1221 	DEFXX;
1222 	Color c = 0;
1223 	XImage *im;
1224 	Bool pixmap;
1225 	uint32_t p32 = 0;
1226 
1227 	if ( !opt_InPaint) return clInvalid;
1228 	SHIFT( x, y);
1229 
1230 	if ( x < 0 || x >= XX-> size.x || y < 0 || y >= XX-> size.y)
1231 		return clInvalid;
1232 
1233 	if ( XT_IS_DBM(XX)) {
1234 		pixmap = XT_IS_PIXMAP(XX) ? true : false;
1235 	} else if ( XT_IS_BITMAP(XX)) {
1236 		pixmap = 0;
1237 	} else {
1238 		pixmap = guts. idepth > 1;
1239 	}
1240 
1241 	im = XGetImage( DISP, XX-> gdrawable, x, XX-> size.y - y - 1, 1, 1,
1242 						pixmap ? AllPlanes : 1,
1243 						pixmap ? ZPixmap   : XYPixmap);
1244 	XCHECKPOINT;
1245 	if ( !im) return clInvalid;
1246 
1247 	if ( pixmap) {
1248 		if ( guts. palSize > 0) {
1249 			int pixel;
1250 			if ( guts. idepth <= 8)
1251 				pixel = (*( U8*)( im-> data)) & (( 1 << guts.idepth) - 1);
1252 			else
1253 				pixel = (*( U16*)( im-> data)) & (( 1 << guts.idepth) - 1);
1254 			if ( guts.palette[pixel]. rank == RANK_FREE) {
1255 				XColor xc;
1256 				xc.pixel = pixel;
1257 				XQueryColors( DISP, guts. defaultColormap, &xc, 1);
1258 				c = RGB_COMPOSITE(xc.red>>8,xc.green>>8,xc.blue>>8);
1259 			} else
1260 				c = guts.palette[pixel]. composite;
1261 		} else {
1262 			PRGBABitDescription bd = GET_RGBA_DESCRIPTION;
1263 			int r, g, b, rmax, gmax, bmax, depth;
1264 			rmax = gmax = bmax = 0xff;
1265 			depth = XF_LAYERED(XX) ? guts. argb_visual. depth : guts. idepth;
1266 			switch ( depth) {
1267 			case 16:
1268 				p32 = *(( uint16_t*)(im-> data));
1269 				if ( guts.machine_byte_order != guts.byte_order)
1270 					p32 = REVERSE_BYTES_16(p32);
1271 				rmax = 0xff & ( 0xff << ( 8 - bd-> red_range));
1272 				gmax = 0xff & ( 0xff << ( 8 - bd-> green_range));
1273 				bmax = 0xff & ( 0xff << ( 8 - bd-> blue_range));
1274 				goto COMP;
1275 			case 24:
1276 				p32 = (im-> data[0] << 16) | (im-> data[1] << 8) | im-> data[2];
1277 				if ( guts.machine_byte_order != guts.byte_order)
1278 					p32 = REVERSE_BYTES_24(p32);
1279 				goto COMP;
1280 			case 32:
1281 				p32 = *(( uint32_t*)(im-> data));
1282 				if ( guts.machine_byte_order != guts.byte_order)
1283 					p32 = REVERSE_BYTES_32(p32);
1284 			COMP:
1285 				r = ((((p32 & bd-> red_mask)   >> bd->red_shift) << 8)   >> bd-> red_range) & 0xff;
1286 				g = ((((p32 & bd-> green_mask) >> bd->green_shift) << 8) >> bd-> green_range) & 0xff;
1287 				b = ((((p32 & bd-> blue_mask)  >> bd->blue_shift) << 8)  >> bd-> blue_range) & 0xff;
1288 				if ( r == rmax ) r = 0xff;
1289 				if ( g == gmax ) g = 0xff;
1290 				if ( b == bmax ) b = 0xff;
1291 				c = b | ( g << 8 ) | ( r << 16);
1292 				break;
1293 			default:
1294 				warn("UAG_009: get_pixel not implemented for %d depth", guts.idepth);
1295 			}
1296 		}
1297 	} else {
1298 		c = ( im-> data[0] & ((guts.bit_order == MSBFirst) ? 0x80 : 1))
1299 			? 0xffffff : 0;
1300 	}
1301 
1302 	XDestroyImage( im);
1303 	return c;
1304 }
1305 
1306 Color
apc_gp_get_nearest_color(Handle self,Color color)1307 apc_gp_get_nearest_color( Handle self, Color color)
1308 {
1309 	if ( guts. palSize > 0)
1310 		return guts. palette[ prima_color_find( self, color, -1, NULL, RANK_FREE)]. composite;
1311 	if ( guts. visualClass == TrueColor || guts. visualClass == DirectColor) {
1312 		XColor xc;
1313 		xc. red   = COLOR_R16(color);
1314 		xc. green = COLOR_G16(color);
1315 		xc. blue  = COLOR_B16(color);
1316 		if ( XAllocColor( DISP, guts. defaultColormap, &xc)) {
1317 			XFreeColors( DISP, guts. defaultColormap, &xc. pixel, 1, 0);
1318 			return
1319 				(( xc. red   & 0xFF00) << 8) |
1320 				(( xc. green & 0xFF00)) |
1321 				(( xc. blue  & 0xFF00) >> 8);
1322 		}
1323 	}
1324 	return color;
1325 }
1326 
1327 PRGBColor
apc_gp_get_physical_palette(Handle self,int * colors)1328 apc_gp_get_physical_palette( Handle self, int * colors)
1329 {
1330 	int i;
1331 	PRGBColor p;
1332 	XColor * xc;
1333 
1334 	*colors = 0;
1335 
1336 	if ( guts. palSize == 0) return NULL;
1337 	if ( !( p = malloc( guts. palSize * sizeof( RGBColor))))
1338 		return NULL;
1339 	if ( !( xc = malloc( guts. palSize * sizeof( XColor)))) {
1340 		free( p);
1341 		return NULL;
1342 	}
1343 	for ( i = 0; i < guts. palSize; i++) xc[i]. pixel = i;
1344 	XQueryColors( DISP, guts. defaultColormap, xc, guts. palSize);
1345 	XCHECKPOINT;
1346 	for ( i = 0; i < guts. palSize; i++) {
1347 		p[i]. r = xc[i]. red   >> 8;
1348 		p[i]. g = xc[i]. green >> 8;
1349 		p[i]. b = xc[i]. blue  >> 8;
1350 	}
1351 	free( xc);
1352 	*colors = guts. palSize;
1353 	return p;
1354 }
1355 
1356 Bool
apc_gp_line(Handle self,int x1,int y1,int x2,int y2)1357 apc_gp_line( Handle self, int x1, int y1, int x2, int y2)
1358 {
1359 	DEFXX;
1360 
1361 	if ( PObject( self)-> options. optInDrawInfo) return false;
1362 	if ( !XF_IN_PAINT(XX)) return false;
1363 
1364 	SHIFT( x1, y1); SHIFT( x2, y2);
1365 	RANGE4(x1, y1, x2, y2); /* not really correct */
1366 	PURE_FOREGROUND;
1367 	if (((int)(XX-> paint_line_width + .5) == 0) && (x1 == x2 || y1 == y2)) {
1368 		XGCValues gcv;
1369 		gcv. line_width = 1;
1370 		XChangeGC( DISP, XX-> gc, GCLineWidth, &gcv);
1371 	}
1372 	XDrawLine( DISP, XX-> gdrawable, XX-> gc, x1, REVERT( y1), x2, REVERT( y2));
1373 	if (((int)(XX-> paint_line_width + .5) == 0) && (x1 == x2 || y1 == y2)) {
1374 		XGCValues gcv;
1375 		gcv. line_width = 0;
1376 		XChangeGC( DISP, XX-> gc, GCLineWidth, &gcv);
1377 	}
1378 	XFLUSH;
1379 	return true;
1380 }
1381 
1382 Bool
apc_gp_rectangle(Handle self,int x1,int y1,int x2,int y2)1383 apc_gp_rectangle( Handle self, int x1, int y1, int x2, int y2)
1384 {
1385 	DEFXX;
1386 	int lw = XX-> paint_line_width + .5;
1387 
1388 	if ( PObject( self)-> options. optInDrawInfo) return false;
1389 	if ( !XF_IN_PAINT(XX)) return false;
1390 
1391 	SHIFT( x1, y1); SHIFT( x2, y2);
1392 	SORT( x1, x2); SORT( y1, y2);
1393 	RANGE4(x1, y1, x2, y2);
1394 	PURE_FOREGROUND;
1395 	if ( lw > 0 && (lw % 2) == 0) {
1396 		y2--;
1397 		y1--;
1398 	}
1399 	XDrawRectangle( DISP, XX-> gdrawable, XX-> gc, x1, REVERT( y2), x2 - x1, y2 - y1);
1400 	XCHECKPOINT;
1401 	XFLUSH;
1402 	return true;
1403 }
1404 
1405 Bool
apc_gp_sector(Handle self,int x,int y,int dX,int dY,double angleStart,double angleEnd)1406 apc_gp_sector( Handle self, int x, int y,  int dX, int dY, double angleStart, double angleEnd)
1407 {
1408 	int compl, needf;
1409 	DEFXX;
1410 
1411 	if ( PObject( self)-> options. optInDrawInfo) return false;
1412 	if ( !XF_IN_PAINT(XX)) return false;
1413 	if ( dX <= 0 || dY <= 0) return false;
1414 	RANGE4(x, y, dX, dY);
1415 
1416 	SHIFT( x, y);
1417 	y = REVERT( y);
1418 
1419 	compl = arc_completion( &angleStart, &angleEnd, &needf);
1420 	PURE_FOREGROUND;
1421 	calculate_ellipse_divergence();
1422 	while ( compl--)
1423 		XDrawArc( DISP, XX-> gdrawable, XX-> gc, ELLIPSE_RECT,
1424 			0, 360 * 64);
1425 	if ( !needf) return true;
1426 	XDrawArc( DISP, XX-> gdrawable, XX-> gc, ELLIPSE_RECT,
1427 		angleStart * 64, ( angleEnd - angleStart) * 64);
1428 	XDrawLine( DISP, XX-> gdrawable, XX-> gc,
1429 		x + cos( angleStart / GRAD) * dX / 2, y - sin( angleStart / GRAD) * dY / 2,
1430 		x, y
1431 	);
1432 	XDrawLine( DISP, XX-> gdrawable, XX-> gc,
1433 		x, y,
1434 		x + cos( angleEnd / GRAD) * dX / 2, y - sin( angleEnd / GRAD) * dY / 2
1435 	);
1436 	XFLUSH;
1437 	return true;
1438 }
1439 
1440 Bool
apc_gp_set_palette(Handle self)1441 apc_gp_set_palette( Handle self)
1442 {
1443 	if ( XT_IS_WIDGET(X(self))) return true;
1444 	return prima_palette_replace( self, false);
1445 }
1446 
1447 Bool
apc_gp_set_pixel(Handle self,int x,int y,Color color)1448 apc_gp_set_pixel( Handle self, int x, int y, Color color)
1449 {
1450 	DEFXX;
1451 
1452 	if ( PObject( self)-> options. optInDrawInfo) return false;
1453 	if ( !XF_IN_PAINT(XX)) return false;
1454 
1455 	SHIFT( x, y);
1456 	XSetForeground( DISP, XX-> gc, prima_allocate_color( self, color, NULL));
1457 	XDrawPoint( DISP, XX-> gdrawable, XX-> gc, x, REVERT( y));
1458 	XX-> flags. brush_fore = 0;
1459 	XFLUSH;
1460 	return true;
1461 }
1462 
1463 /* gpi settings */
1464 int
apc_gp_get_alpha(Handle self)1465 apc_gp_get_alpha( Handle self)
1466 {
1467 	DEFXX;
1468 	if ( XF_IN_PAINT(XX)) {
1469 		return XX-> paint_alpha;
1470 	} else {
1471 		return XX-> alpha;
1472 	}
1473 }
1474 
1475 Bool
apc_gp_get_antialias(Handle self)1476 apc_gp_get_antialias( Handle self)
1477 {
1478 	DEFXX;
1479 	return XF_IN_PAINT(XX) ? XX-> flags.antialias : XX->flags.saved_antialias;
1480 }
1481 
1482 Color
apc_gp_get_back_color(Handle self)1483 apc_gp_get_back_color( Handle self)
1484 {
1485 	DEFXX;
1486 	return ( XF_IN_PAINT(XX)) ? XX-> back. color : prima_map_color( XX-> saved_back, NULL);
1487 }
1488 
1489 int
apc_gp_get_bpp(Handle self)1490 apc_gp_get_bpp( Handle self)
1491 {
1492 	DEFXX;
1493 	if ( XT_IS_BITMAP(XX)) return 1;
1494 	if ( XF_LAYERED(XX)) return guts. argb_depth;
1495 	return guts. depth;
1496 }
1497 
1498 Color
apc_gp_get_color(Handle self)1499 apc_gp_get_color( Handle self)
1500 {
1501 	DEFXX;
1502 	return ( XF_IN_PAINT(XX)) ? XX-> fore. color : prima_map_color(XX-> saved_fore, NULL);
1503 }
1504 
1505 unsigned long *
apc_gp_get_font_ranges(Handle self,int * count)1506 apc_gp_get_font_ranges( Handle self, int * count)
1507 {
1508 	DEFXX;
1509 	unsigned long * ret = NULL;
1510 	XFontStruct * fs;
1511 #ifdef USE_XFT
1512 	if ( XX-> font-> xft)
1513 		return prima_xft_get_font_ranges( self, count);
1514 #endif
1515 	fs = XX-> font-> fs;
1516 	*count = (fs-> max_byte1 - fs-> min_byte1 + 1) * 2;
1517 	if (( ret = malloc( sizeof( unsigned long) * ( *count)))) {
1518 		int i;
1519 		for ( i = fs-> min_byte1; i <= fs-> max_byte1; i++) {
1520 			ret[(i - fs-> min_byte1) * 2 + 0] = i * 256 + fs-> min_char_or_byte2;
1521 			ret[(i - fs-> min_byte1) * 2 + 1] = i * 256 + fs-> max_char_or_byte2;
1522 		}
1523 	}
1524 	return ret;
1525 }
1526 
1527 char *
apc_gp_get_font_languages(Handle self)1528 apc_gp_get_font_languages( Handle self)
1529 {
1530 	DEFXX;
1531 	char * ret;
1532 #ifdef USE_XFT
1533 	if ( XX-> font-> xft)
1534 		return prima_xft_get_font_languages(self);
1535 #endif
1536 	if ( XX-> font-> flags.funky )
1537 		return NULL;
1538 	if ( !( ret = malloc(4)))
1539 		return NULL;
1540 	memcpy(ret, "en\0\0", 4);
1541 	return ret;
1542 }
1543 
1544 int
apc_gp_get_fill_mode(Handle self)1545 apc_gp_get_fill_mode( Handle self)
1546 {
1547 	DEFXX;
1548 	return XF_IN_PAINT(XX) ? XX->fill_mode : XX->saved_fill_mode;
1549 }
1550 
1551 FillPattern *
apc_gp_get_fill_pattern(Handle self)1552 apc_gp_get_fill_pattern( Handle self)
1553 {
1554 	return &(X(self)-> fill_pattern);
1555 }
1556 
1557 Point
apc_gp_get_fill_pattern_offset(Handle self)1558 apc_gp_get_fill_pattern_offset( Handle self)
1559 {
1560 	return X(self)-> fill_pattern_offset;
1561 }
1562 
1563 int
apc_gp_get_line_end(Handle self)1564 apc_gp_get_line_end( Handle self)
1565 {
1566 	DEFXX;
1567 	int cap;
1568 	XGCValues gcv;
1569 
1570 	if ( XF_IN_PAINT(XX)) {
1571 		if ( XGetGCValues( DISP, XX-> gc, GCCapStyle, &gcv) == 0) {
1572 			warn( "UAG_006: error querying GC values");
1573 			cap = CapButt;
1574 		} else {
1575 			cap = gcv. cap_style;
1576 		}
1577 	} else {
1578 		cap = XX-> gcv. cap_style;
1579 	}
1580 	if ( cap == CapRound)
1581 		return leRound;
1582 	else if ( cap == CapProjecting)
1583 		return leSquare;
1584 	return leFlat;
1585 }
1586 
1587 int
apc_gp_get_line_join(Handle self)1588 apc_gp_get_line_join( Handle self)
1589 {
1590 	DEFXX;
1591 	int join;
1592 	XGCValues gcv;
1593 
1594 	if ( XF_IN_PAINT(XX)) {
1595 		if ( XGetGCValues( DISP, XX-> gc, GCJoinStyle, &gcv) == 0) {
1596 			warn( "UAG_006: error querying GC values");
1597 			join = JoinRound;
1598 		} else {
1599 			join = gcv. join_style;
1600 		}
1601 	} else {
1602 		join = XX-> gcv. join_style;
1603 	}
1604 	if ( join == JoinMiter)
1605 		return ljMiter;
1606 	else if ( join == JoinBevel)
1607 		return ljBevel;
1608 	return ljRound;
1609 }
1610 
1611 float
apc_gp_get_line_width(Handle self)1612 apc_gp_get_line_width( Handle self)
1613 {
1614 	DEFXX;
1615 	return XF_IN_PAINT(XX) ? XX-> paint_line_width : XX-> line_width;
1616 }
1617 
1618 int
apc_gp_get_line_pattern(Handle self,unsigned char * dashes)1619 apc_gp_get_line_pattern( Handle self, unsigned char *dashes)
1620 {
1621 	DEFXX;
1622 	int n;
1623 	if ( XF_IN_PAINT(XX)) {
1624 		n = XX-> paint_ndashes;
1625 		if ( XX-> paint_dashes)
1626 			memcpy( dashes, XX-> paint_dashes, n);
1627 		else
1628 			bzero( dashes, n);
1629 	} else {
1630 		n = XX-> ndashes;
1631 		if ( n < 0) {
1632 			n = 0;
1633 			strcpy(( char*) dashes, "");
1634 		} else if ( n == 0) {
1635 			n = 1;
1636 			strcpy(( char*) dashes, "\1");
1637 		} else {
1638 			memcpy( dashes, XX-> dashes, n);
1639 		}
1640 	}
1641 	return n;
1642 }
1643 
1644 float
apc_gp_get_miter_limit(Handle self)1645 apc_gp_get_miter_limit( Handle self)
1646 {
1647 	DEFXX;
1648 	/* xorg.miArcJoin: don't miter arcs with less than 11 degrees between them */
1649 	if ( XF_IN_PAINT(XX) ) return 1.0 / sin((11.0 * 3.14159265358 / 180) / 2);
1650 	return XX->miter_limit;
1651 }
1652 
1653 Point
apc_gp_get_resolution(Handle self)1654 apc_gp_get_resolution( Handle self)
1655 {
1656 	return guts. resolution;
1657 }
1658 
1659 int
apc_gp_get_rop(Handle self)1660 apc_gp_get_rop( Handle self)
1661 {
1662 	DEFXX;
1663 	if ( XF_IN_PAINT(XX)) {
1664 		return XX-> paint_rop;
1665 	} else {
1666 		return XX-> rop;
1667 	}
1668 }
1669 
1670 int
apc_gp_get_rop2(Handle self)1671 apc_gp_get_rop2( Handle self)
1672 {
1673 	DEFXX;
1674 	if ( XF_IN_PAINT(XX))
1675 		return XX-> paint_rop2;
1676 	else
1677 		return XX-> rop2;
1678 }
1679 
1680 Point
apc_gp_get_transform(Handle self)1681 apc_gp_get_transform( Handle self)
1682 {
1683 	DEFXX;
1684 	if ( XF_IN_PAINT(XX)) {
1685 		return XX-> gtransform;
1686 	} else {
1687 		return XX-> transform;
1688 	}
1689 }
1690 
1691 Bool
apc_gp_get_text_opaque(Handle self)1692 apc_gp_get_text_opaque( Handle self)
1693 {
1694 	DEFXX;
1695 	if ( XF_IN_PAINT(XX)) {
1696 		return XX-> flags. paint_opaque ? true : false;
1697 	} else {
1698 		return XX-> flags. opaque ? true : false;
1699 	}
1700 }
1701 
1702 Bool
apc_gp_get_text_out_baseline(Handle self)1703 apc_gp_get_text_out_baseline( Handle self)
1704 {
1705 	DEFXX;
1706 	if ( XF_IN_PAINT(XX)) {
1707 		return XX-> flags. paint_base_line ? true : false;
1708 	} else {
1709 		return XX-> flags. base_line ? true : false;
1710 	}
1711 }
1712 
1713 Bool
apc_gp_set_alpha(Handle self,int alpha)1714 apc_gp_set_alpha( Handle self, int alpha)
1715 {
1716 	DEFXX;
1717 
1718 	if (XT_IS_BITMAP(XX) || (( XT_IS_PIXMAP(XX) || XT_IS_APPLICATION(XX)) && guts.depth==1))
1719 		alpha = 255;
1720 	if ( !guts.render_extension)
1721 		alpha = 255;
1722 
1723 	if ( XF_IN_PAINT(XX)) {
1724 		if ( XX-> paint_alpha == alpha)
1725 			return true;
1726 		XX-> paint_alpha = alpha;
1727 		guts.xrender_pen_dirty = true;
1728 	} else {
1729 		XX-> alpha = alpha;
1730 	}
1731 	return true;
1732 }
1733 
1734 Bool
apc_gp_set_antialias(Handle self,Bool antialias)1735 apc_gp_set_antialias( Handle self, Bool antialias )
1736 {
1737 	DEFXX;
1738 	if ( antialias ) {
1739 		if (XT_IS_BITMAP(XX) || (( XT_IS_PIXMAP(XX) || XT_IS_APPLICATION(XX)) && guts.depth==1))
1740 			return false;
1741 		if ( !guts.render_extension)
1742 			return false;
1743 	}
1744 	if ( XF_IN_PAINT(XX) ) {
1745 		XX-> flags.antialias = antialias;
1746 	} else {
1747 		XX-> flags.saved_antialias = antialias;
1748 	}
1749 	return true;
1750 }
1751 
1752 Bool
apc_gp_set_back_color(Handle self,Color color)1753 apc_gp_set_back_color( Handle self, Color color)
1754 {
1755 	DEFXX;
1756 	if ( XF_IN_PAINT(XX)) {
1757 		prima_allocate_color( self, color, &XX-> back);
1758 		XX-> flags. brush_back = 0;
1759 		if ( !XX-> flags. brush_null_hatch)
1760 			guts.xrender_pen_dirty = true;
1761 	} else
1762 		XX-> saved_back = color;
1763 	return true;
1764 }
1765 
1766 Bool
apc_gp_set_color(Handle self,Color color)1767 apc_gp_set_color( Handle self, Color color)
1768 {
1769 	DEFXX;
1770 	if ( XF_IN_PAINT(XX)) {
1771 		prima_allocate_color( self, color, &XX-> fore);
1772 		XX-> flags. brush_fore = 0;
1773 		guts.xrender_pen_dirty = true;
1774 	} else
1775 		XX-> saved_fore = color;
1776 	return true;
1777 }
1778 
1779 Bool
apc_gp_set_fill_mode(Handle self,int fillMode)1780 apc_gp_set_fill_mode( Handle self, int fillMode)
1781 {
1782 	DEFXX;
1783 	int fill_rule;
1784 	XGCValues gcv;
1785 
1786 	fill_rule = ((fillMode & fmWinding) == fmAlternate) ? EvenOddRule : WindingRule;
1787 	if ( XF_IN_PAINT(XX)) {
1788 		gcv. fill_rule = fill_rule;
1789 		XX-> fill_mode = fillMode;
1790 		XChangeGC( DISP, XX-> gc, GCFillRule, &gcv);
1791 		XCHECKPOINT;
1792 	} else {
1793 		XX-> gcv. fill_rule = fill_rule;
1794 		XX-> saved_fill_mode = fillMode;
1795 	}
1796 	return true;
1797 }
1798 
1799 Bool
apc_gp_set_fill_pattern(Handle self,FillPattern pattern)1800 apc_gp_set_fill_pattern( Handle self, FillPattern pattern)
1801 {
1802 	DEFXX;
1803 	if ( memcmp( pattern, XX-> fill_pattern, sizeof(FillPattern)) == 0)
1804 		return true;
1805 	XX-> flags. brush_null_hatch =
1806 	( memcmp( pattern, fillPatterns[fpSolid], sizeof(FillPattern)) == 0);
1807 	memcpy( XX-> fill_pattern, pattern, sizeof( FillPattern));
1808 	if ( XF_IN_PAINT(XX))
1809 		guts.xrender_pen_dirty = true;
1810 	return true;
1811 }
1812 
1813 Bool
apc_gp_set_fill_pattern_offset(Handle self,Point fpo)1814 apc_gp_set_fill_pattern_offset( Handle self, Point fpo)
1815 {
1816 	DEFXX;
1817 	XGCValues gcv;
1818 
1819 	fpo. y = 8 - fpo.y;
1820 	XX-> fill_pattern_offset = fpo;
1821 
1822 	if ( XF_IN_PAINT(XX)) {
1823 		gcv. ts_x_origin = fpo. x;
1824 		gcv. ts_y_origin = fpo. y;
1825 		XChangeGC( DISP, XX-> gc, GCTileStipXOrigin | GCTileStipYOrigin, &gcv);
1826 		XCHECKPOINT;
1827 		if ( !XX-> flags. brush_null_hatch)
1828 			guts.xrender_pen_dirty = true;
1829 	} else {
1830 		XX-> gcv. ts_x_origin = fpo. x;
1831 		XX-> gcv. ts_y_origin = fpo. y;
1832 	}
1833 	return true;
1834 }
1835 
1836 /*- see apc_font.c
1837 void
1838 apc_gp_set_font( Handle self, PFont font)
1839 */
1840 
1841 Bool
apc_gp_set_line_end(Handle self,int lineEnd)1842 apc_gp_set_line_end( Handle self, int lineEnd)
1843 {
1844 	DEFXX;
1845 	int cap = CapButt;
1846 	XGCValues gcv;
1847 
1848 	if ( lineEnd == leFlat)
1849 		cap = CapButt;
1850 	else if ( lineEnd == leSquare)
1851 		cap = CapProjecting;
1852 	else if ( lineEnd == leRound)
1853 		cap = CapRound;
1854 
1855 	if ( XF_IN_PAINT(XX)) {
1856 		gcv. cap_style = cap;
1857 		XChangeGC( DISP, XX-> gc, GCCapStyle, &gcv);
1858 		XCHECKPOINT;
1859 	} else {
1860 		XX-> gcv. cap_style = cap;
1861 	}
1862 	return true;
1863 }
1864 
1865 Bool
apc_gp_set_line_join(Handle self,int lineJoin)1866 apc_gp_set_line_join( Handle self, int lineJoin)
1867 {
1868 	DEFXX;
1869 	int join = JoinRound;
1870 	XGCValues gcv;
1871 
1872 	if ( lineJoin == ljRound)
1873 		join = JoinRound;
1874 	else if ( lineJoin == ljBevel)
1875 		join = JoinBevel;
1876 	else if ( lineJoin == ljMiter)
1877 		join = JoinMiter;
1878 
1879 	if ( XF_IN_PAINT(XX)) {
1880 		gcv. join_style = join;
1881 		XChangeGC( DISP, XX-> gc, GCJoinStyle, &gcv);
1882 		XCHECKPOINT;
1883 	} else {
1884 		XX-> gcv. join_style = join;
1885 	}
1886 	return true;
1887 }
1888 
1889 Bool
apc_gp_set_line_width(Handle self,float line_width)1890 apc_gp_set_line_width( Handle self, float line_width)
1891 {
1892 	DEFXX;
1893 	XGCValues gcv;
1894 
1895 	if ( XF_IN_PAINT(XX)) {
1896 		XX-> paint_line_width = line_width;
1897 		gcv. line_width = line_width +.5;
1898 		if ( !( XX-> paint_ndashes == 0 || (XX-> paint_ndashes == 1 && XX-> paint_dashes[0] == 1))) {
1899 			dDASH_FIX( line_width, XX-> paint_dashes, XX-> paint_ndashes);
1900 			DASH_FIX;
1901 			XSetDashes( DISP, XX-> gc, 0, DASHES);
1902 		}
1903 		XChangeGC( DISP, XX-> gc, GCLineWidth, &gcv);
1904 		XCHECKPOINT;
1905 	} else {
1906 		XX-> gcv. line_width = line_width + .5;
1907 		XX-> line_width = line_width;
1908 	}
1909 	return true;
1910 }
1911 
1912 Bool
apc_gp_set_line_pattern(Handle self,unsigned char * pattern,int len)1913 apc_gp_set_line_pattern( Handle self, unsigned char *pattern, int len)
1914 {
1915 	DEFXX;
1916 	XGCValues gcv;
1917 
1918 	if ( XF_IN_PAINT(XX)) {
1919 		if ( len == 0 || (len == 1 && pattern[0] == 1)) {
1920 			gcv. line_style = LineSolid;
1921 			XChangeGC( DISP, XX-> gc, GCLineStyle, &gcv);
1922 		} else {
1923 			dDASH_FIX(XX-> line_width, pattern, len);
1924 			DASH_FIX;
1925 			gcv. line_style = ( XX-> paint_rop2 == ropNoOper) ? LineOnOffDash : LineDoubleDash;
1926 			XSetDashes( DISP, XX-> gc, 0, DASHES);
1927 			XChangeGC( DISP, XX-> gc, GCLineStyle, &gcv);
1928 		}
1929 		XX-> line_style = gcv. line_style;
1930 		free(XX->paint_dashes);
1931 		if (( XX-> paint_dashes = malloc( len)))
1932 			memcpy( XX-> paint_dashes, pattern, len);
1933 		XX-> paint_ndashes = len;
1934 	} else {
1935 		free( XX-> dashes);
1936 		if ( len == 0) {					/* lpNull */
1937 			XX-> dashes = NULL;
1938 			XX-> ndashes = -1;
1939 			XX-> gcv. line_style = LineSolid;
1940 		} else if ( len == 1 && pattern[0] == 1) {	/* lpSolid */
1941 			XX-> dashes = NULL;
1942 			XX-> ndashes = 0;
1943 			XX-> gcv. line_style = LineSolid;
1944 		} else {						/* the rest */
1945 			XX-> dashes = malloc( len);
1946 			memcpy( XX-> dashes, pattern, len);
1947 			XX-> ndashes = len;
1948 			XX-> gcv. line_style = ( XX-> rop2 == ropNoOper) ? LineOnOffDash : LineDoubleDash;
1949 		}
1950 	}
1951 	return true;
1952 }
1953 
1954 Bool
apc_gp_set_miter_limit(Handle self,float miter_limit)1955 apc_gp_set_miter_limit( Handle self, float miter_limit)
1956 {
1957 	DEFXX;
1958 	if ( XF_IN_PAINT(XX)) return false;
1959 	XX-> miter_limit = miter_limit;
1960 	return true;
1961 }
1962 
1963 Bool
apc_gp_set_rop(Handle self,int rop)1964 apc_gp_set_rop( Handle self, int rop)
1965 {
1966 	DEFXX;
1967 	int function;
1968 
1969 	if ( rop < 0 || rop >= sizeof( rop_map)/sizeof(int))
1970 		function = GXnoop;
1971 	else
1972 		function = rop_map[ rop];
1973 
1974 	if ( XF_IN_PAINT(XX)) {
1975 		if ( rop < 0 || rop >= sizeof( rop_map)/sizeof(int))
1976 			rop = ropNoOper;
1977 		XX-> paint_rop = rop;
1978 		XSetFunction( DISP, XX-> gc, function);
1979 		guts.xrender_pen_dirty = true;
1980 		XCHECKPOINT;
1981 	} else {
1982 		XX-> gcv. function = function;
1983 		XX-> rop = rop;
1984 	}
1985 	return true;
1986 }
1987 
1988 Bool
apc_gp_set_rop2(Handle self,int rop)1989 apc_gp_set_rop2( Handle self, int rop)
1990 {
1991 	DEFXX;
1992 	if ( XF_IN_PAINT(XX)) {
1993 		if ( XX-> paint_rop2 == rop) return true;
1994 		XX-> paint_rop2 = ( rop == ropCopyPut) ? ropCopyPut : ropNoOper;
1995 		if ( XX-> line_style != LineSolid) {
1996 			XGCValues gcv;
1997 			gcv. line_style = ( rop == ropCopyPut) ? LineDoubleDash : LineOnOffDash;
1998 			XChangeGC( DISP, XX-> gc, GCLineStyle, &gcv);
1999 		}
2000 		guts.xrender_pen_dirty = true;
2001 	} else {
2002 		XX-> rop2 = rop;
2003 		if ( XX-> gcv. line_style != LineSolid)
2004 			XX-> gcv. line_style = ( rop == ropCopyPut) ? LineDoubleDash : LineOnOffDash;
2005 	}
2006 	return true;
2007 }
2008 
2009 Bool
apc_gp_set_transform(Handle self,int x,int y)2010 apc_gp_set_transform( Handle self, int x, int y)
2011 {
2012 	DEFXX;
2013 	if ( XF_IN_PAINT(XX)) {
2014 		XX-> gtransform. x = x;
2015 		XX-> gtransform. y = y;
2016 	} else {
2017 		XX-> transform. x = x;
2018 		XX-> transform. y = y;
2019 	}
2020 	return true;
2021 }
2022 
2023 Bool
apc_gp_set_text_opaque(Handle self,Bool opaque)2024 apc_gp_set_text_opaque( Handle self, Bool opaque)
2025 {
2026 	DEFXX;
2027 	if ( XF_IN_PAINT(XX)) {
2028 		XX-> flags. paint_opaque = !!opaque;
2029 	} else {
2030 		XX-> flags. opaque = !!opaque;
2031 	}
2032 	return true;
2033 }
2034 
2035 Bool
apc_gp_set_text_out_baseline(Handle self,Bool baseline)2036 apc_gp_set_text_out_baseline( Handle self, Bool baseline)
2037 {
2038 	DEFXX;
2039 	if ( XF_IN_PAINT(XX)) {
2040 		XX-> flags. paint_base_line = !!baseline;
2041 	} else {
2042 		XX-> flags. base_line = !!baseline;
2043 	}
2044 	return true;
2045 }
2046 
2047 ApiHandle
apc_gp_get_handle(Handle self)2048 apc_gp_get_handle( Handle self)
2049 {
2050 	return ( ApiHandle) X(self)-> gdrawable;
2051 }
2052 
2053