1 #include "apricot.h"
2 #include "Drawable.h"
3 #include "Icon.h"
4 #include "Region.h"
5 #include <Drawable.inc>
6
7 #ifdef __cplusplus
8 extern "C" {
9 #endif
10
11
12 #undef my
13 #define inherited CComponent->
14 #define my ((( PDrawable) self)-> self)
15 #define var (( PDrawable) self)
16
17 #define gpARGS Bool inPaint = opt_InPaint
18 #define gpENTER(fail) if ( !inPaint) if ( !my-> begin_paint_info( self)) return (fail)
19 #define gpLEAVE if ( !inPaint) my-> end_paint_info( self)
20
21 #define CHECK_GP(ret) \
22 if ( !is_opt(optSystemDrawable)) { \
23 warn("This method is not available because %s is not a system Drawable object. You need to implement your own (ref:%d)", my->className, __LINE__);\
24 return ret; \
25 }
26
27 void
Drawable_init(Handle self,HV * profile)28 Drawable_init( Handle self, HV * profile)
29 {
30 dPROFILE;
31 inherited init( self, profile);
32 apc_gp_init( self);
33 var-> w = var-> h = 0;
34 my-> set_alpha ( self, pget_i ( alpha));
35 my-> set_antialias ( self, pget_B ( antialias));
36 my-> set_color ( self, pget_i ( color));
37 my-> set_backColor ( self, pget_i ( backColor));
38 my-> set_fillMode ( self, pget_i ( fillMode));
39 my-> set_fillPattern ( self, pget_sv( fillPattern));
40 my-> set_lineEnd ( self, pget_i ( lineEnd));
41 my-> set_lineJoin ( self, pget_i ( lineJoin));
42 my-> set_linePattern ( self, pget_sv( linePattern));
43 my-> set_lineWidth ( self, pget_f ( lineWidth));
44 my-> set_miterLimit ( self, pget_i ( miterLimit));
45 my-> set_region ( self, pget_H ( region));
46 my-> set_rop ( self, pget_i ( rop));
47 my-> set_rop2 ( self, pget_i ( rop2));
48 my-> set_textOpaque ( self, pget_B ( textOpaque));
49 my-> set_textOutBaseline( self, pget_B ( textOutBaseline));
50 if ( pexist( translate))
51 {
52 AV * av;
53 Point tr;
54 SV ** holder, *sv;
55
56 sv = pget_sv( translate);
57 if ( sv && SvOK(sv) && SvROK(sv) && SvTYPE(av = (AV*)SvRV(sv)) == SVt_PVAV && av_len(av) == 1) {
58 tr.x = tr.y = 0;
59 holder = av_fetch( av, 0, 0);
60 if ( holder) tr.x = SvIV( *holder); else warn("Array panic on 'translate'");
61 holder = av_fetch( av, 1, 0);
62 if ( holder) tr.y = SvIV( *holder); else warn("Array panic on 'translate'");
63 my-> set_translate( self, tr);
64 } else
65 warn("Array panic on 'translate'");
66
67 sv = pget_sv( fillPatternOffset);
68 if ( sv && SvOK(sv) && SvROK(sv) && SvTYPE(av = (AV*)SvRV(sv)) == SVt_PVAV && av_len(av) == 1) {
69 tr.x = tr.y = 0;
70 holder = av_fetch( av, 0, 0);
71 if ( holder) tr.x = SvIV( *holder); else warn("Array panic on 'fillPatternOffset'");
72 holder = av_fetch( av, 1, 0);
73 if ( holder) tr.y = SvIV( *holder); else warn("Array panic on 'fillPatternOffset'");
74 my-> set_fillPatternOffset( self, tr );
75 } else
76 warn("Array panic on 'fillPatternOffset'");
77 }
78 SvHV_Font( pget_sv( font), &Font_buffer, "Drawable::init");
79 my-> set_font( self, Font_buffer);
80 my-> set_palette( self, pget_sv( palette));
81 CORE_INIT_TRANSIENT(Drawable);
82 }
83
84 static void
clear_font_abc_caches(Handle self)85 clear_font_abc_caches( Handle self)
86 {
87 PList u;
88 if (( u = var-> font_abc_glyphs)) {
89 int i;
90 for ( i = 0; i < u-> count; i += 2)
91 free(( void*) u-> items[ i + 1]);
92 plist_destroy( u);
93 var-> font_abc_glyphs = NULL;
94 }
95 if (( u = var-> font_abc_unicode)) {
96 int i;
97 for ( i = 0; i < u-> count; i += 2)
98 free(( void*) u-> items[ i + 1]);
99 plist_destroy( u);
100 var-> font_abc_unicode = NULL;
101 }
102 if ( var-> font_abc_ascii) {
103 free( var-> font_abc_ascii);
104 var-> font_abc_ascii = NULL;
105 }
106 if ( var-> font_abc_glyphs_ranges ) {
107 free(var-> font_abc_glyphs_ranges);
108 var-> font_abc_glyphs_ranges = NULL;
109 var-> font_abc_glyphs_n_ranges = 0;
110 }
111 }
112
113 void
Drawable_done(Handle self)114 Drawable_done( Handle self)
115 {
116 clear_font_abc_caches( self);
117 apc_gp_done( self);
118 inherited done( self);
119 }
120
121 void
Drawable_cleanup(Handle self)122 Drawable_cleanup( Handle self)
123 {
124 if ( is_opt( optInDrawInfo))
125 my-> end_paint_info( self);
126 if ( is_opt( optInDraw))
127 my-> end_paint( self);
128 inherited cleanup( self);
129 }
130
131 Bool
Drawable_begin_paint(Handle self)132 Drawable_begin_paint( Handle self)
133 {
134 if ( var-> stage > csFrozen) return false;
135 if ( is_opt( optInDrawInfo)) my-> end_paint_info( self);
136 opt_set( optInDraw);
137 return true;
138 }
139
140 void
Drawable_end_paint(Handle self)141 Drawable_end_paint( Handle self)
142 {
143 clear_font_abc_caches( self);
144 opt_clear( optInDraw);
145 }
146
147 Bool
Drawable_begin_paint_info(Handle self)148 Drawable_begin_paint_info( Handle self)
149 {
150 if ( var-> stage > csFrozen) return false;
151 if ( is_opt( optInDraw)) return true;
152 if ( is_opt( optInDrawInfo)) return false;
153 opt_set( optInDrawInfo);
154 return true;
155 }
156
157 void
Drawable_end_paint_info(Handle self)158 Drawable_end_paint_info( Handle self)
159 {
160 clear_font_abc_caches( self);
161 opt_clear( optInDrawInfo);
162 }
163
164 void
Drawable_set(Handle self,HV * profile)165 Drawable_set( Handle self, HV * profile)
166 {
167 dPROFILE;
168 if ( pexist( font))
169 {
170 SvHV_Font( pget_sv( font), &Font_buffer, "Drawable::set");
171 my-> set_font( self, Font_buffer);
172 pdelete( font);
173 }
174 if ( pexist( translate))
175 {
176 AV * av = ( AV *) SvRV( pget_sv( translate));
177 Point tr = {0,0};
178 SV ** holder = av_fetch( av, 0, 0);
179 if ( holder) tr.x = SvIV( *holder); else warn("Array panic on 'translate'");
180 holder = av_fetch( av, 1, 0);
181 if ( holder) tr.y = SvIV( *holder); else warn("Array panic on 'translate'");
182 my-> set_translate( self, tr);
183 pdelete( translate);
184 }
185 if ( pexist( width) && pexist( height)) {
186 Point size;
187 size. x = pget_i( width);
188 size. y = pget_i( height);
189 my-> set_size( self, size);
190 pdelete( width);
191 pdelete( height);
192 }
193 if ( pexist( fillPatternOffset))
194 {
195 AV * av = ( AV *) SvRV( pget_sv( fillPatternOffset));
196 Point fpo = {0,0};
197 SV ** holder = av_fetch( av, 0, 0);
198 if ( holder) fpo.x = SvIV( *holder); else warn("Array panic on 'fillPatternOffset'");
199 holder = av_fetch( av, 1, 0);
200 if ( holder) fpo.y = SvIV( *holder); else warn("Array panic on 'fillPatternOffset'");
201 my-> set_fillPatternOffset( self, fpo);
202 pdelete( fillPatternOffset);
203 }
204 inherited set( self, profile);
205 }
206
207
208 Font *
Drawable_font_match(char * dummy,Font * source,Font * dest,Bool pick)209 Drawable_font_match( char * dummy, Font * source, Font * dest, Bool pick)
210 {
211 if ( pick)
212 apc_font_pick( NULL_HANDLE, source, dest);
213 else
214 Drawable_font_add( NULL_HANDLE, source, dest);
215 return dest;
216 }
217
218 Bool
Drawable_font_add(Handle self,Font * source,Font * dest)219 Drawable_font_add( Handle self, Font * source, Font * dest)
220 {
221 Bool useHeight = !source-> undef. height;
222 Bool useWidth = !source-> undef. width;
223 Bool useSize = !source-> undef. size;
224 Bool usePitch = !source-> undef. pitch;
225 Bool useStyle = !source-> undef. style;
226 Bool useDir = !source-> undef. direction;
227 Bool useName = !source-> undef. name;
228 Bool useVec = !source-> undef. vector;
229 Bool useEnc = !source-> undef. encoding;
230
231 /* assignning values */
232 if ( dest != source) {
233 dest-> undef = source-> undef;
234 if ( useHeight) dest-> height = source-> height;
235 if ( useWidth ) dest-> width = source-> width;
236 if ( useDir ) dest-> direction = source-> direction;
237 if ( useStyle ) dest-> style = source-> style;
238 if ( usePitch ) dest-> pitch = source-> pitch;
239 if ( useSize ) dest-> size = source-> size;
240 if ( useVec ) dest-> vector = source-> vector;
241 if ( useName ) {
242 strcpy( dest-> name, source-> name);
243 dest->is_utf8.name = source->is_utf8.name;
244 }
245 if ( useEnc ) {
246 strcpy( dest-> encoding, source-> encoding);
247 dest->is_utf8.encoding = source->is_utf8.encoding;
248 }
249 }
250
251 /* nulling dependencies */
252 if ( !useHeight && useSize)
253 dest-> height = 0;
254 if ( !useWidth && ( usePitch || useHeight || useName || useSize || useDir || useStyle))
255 dest-> width = 0;
256 if ( !usePitch && ( useStyle || useName || useDir || useWidth))
257 dest-> pitch = fpDefault;
258 if ( useHeight)
259 dest-> size = 0;
260 if ( !useHeight && !useSize && ( dest-> height <= 0 || dest-> height > 16383))
261 useSize = 1;
262
263 /* validating entries */
264 if ( dest-> height <= 0) dest-> height = 1;
265 else if ( dest-> height > 16383 ) dest-> height = 16383;
266 if ( dest-> width < 0) dest-> width = 1;
267 else if ( dest-> width > 16383 ) dest-> width = 16383;
268 if ( dest-> size <= 0) dest-> size = 1;
269 else if ( dest-> size > 16383 ) dest-> size = 16383;
270 if ( dest-> name[0] == 0) {
271 strcpy( dest-> name, "Default");
272 dest->is_utf8.name = false;
273 }
274 if ( dest-> undef.pitch || dest-> pitch < fpDefault || dest-> pitch > fpFixed)
275 dest-> pitch = fpDefault;
276 if ( dest-> undef. direction )
277 dest-> direction = 0;
278 if ( dest-> undef. style )
279 dest-> style = 0;
280 if ( dest-> undef. vector || dest-> vector < fvBitmap || dest-> vector > fvDefault)
281 dest-> vector = fvDefault;
282 if ( dest-> undef. encoding )
283 dest-> encoding[0] = 0;
284 memset(&dest->undef, 0, sizeof(dest->undef));
285
286 return useSize && !useHeight;
287 }
288
289 int
Drawable_get_bpp(Handle self)290 Drawable_get_bpp( Handle self)
291 {
292 gpARGS;
293 int ret;
294 CHECK_GP(0);
295 gpENTER(0);
296 ret = apc_gp_get_bpp( self);
297 gpLEAVE;
298 return ret;
299 }
300
301 int
Drawable_get_paint_state(Handle self)302 Drawable_get_paint_state( Handle self)
303 {
304 if ( is_opt( optInDraw))
305 return psEnabled;
306 else if ( is_opt( optInDrawInfo))
307 return psInformation;
308 else
309 return psDisabled;
310 }
311
312 Color
Drawable_get_nearest_color(Handle self,Color color)313 Drawable_get_nearest_color( Handle self, Color color)
314 {
315 gpARGS;
316 CHECK_GP(0);
317 gpENTER(clInvalid);
318 color = apc_gp_get_nearest_color( self, color);
319 gpLEAVE;
320 return color;
321 }
322
323 SV *
Drawable_get_physical_palette(Handle self)324 Drawable_get_physical_palette( Handle self)
325 {
326 gpARGS;
327 int i, nCol;
328 AV * av = newAV();
329 PRGBColor r;
330
331 CHECK_GP(NULL_SV);
332 gpENTER(newRV_noinc(( SV *) av));
333 r = apc_gp_get_physical_palette( self, &nCol);
334 gpLEAVE;
335
336 for ( i = 0; i < nCol; i++) {
337 av_push( av, newSViv( r[ i].b));
338 av_push( av, newSViv( r[ i].g));
339 av_push( av, newSViv( r[ i].r));
340 }
341 free( r);
342 return newRV_noinc(( SV *) av);
343 }
344
345 SV *
Drawable_get_font_abcdef(Handle self,int first,int last,int flags,PFontABC (* func)(Handle,int,int,int))346 Drawable_get_font_abcdef( Handle self, int first, int last, int flags, PFontABC (*func)(Handle, int, int, int))
347 {
348 int i;
349 AV * av;
350 PFontABC abc;
351
352 if ( first < 0) first = 0;
353 if ( last < 0) last = 255;
354
355 if ( flags & toGlyphs )
356 flags &= ~toUTF8;
357 else if ( !(flags & toUTF8)) {
358 if ( first > 255) first = 255;
359 if ( last > 255) last = 255;
360 }
361
362 if ( first > last)
363 abc = NULL;
364 else {
365 gpARGS;
366 gpENTER( newRV_noinc(( SV *) newAV()));
367 abc = func( self, first, last, flags );
368 gpLEAVE;
369 }
370
371 av = newAV();
372 if ( abc != NULL) {
373 for ( i = 0; i <= last - first; i++) {
374 av_push( av, newSVnv( abc[ i]. a));
375 av_push( av, newSVnv( abc[ i]. b));
376 av_push( av, newSVnv( abc[ i]. c));
377 }
378 free( abc);
379 }
380 return newRV_noinc(( SV *) av);
381 }
382
383 SV *
Drawable_get_font_abc(Handle self,int first,int last,int flags)384 Drawable_get_font_abc( Handle self, int first, int last, int flags)
385 {
386 CHECK_GP(NULL_SV);
387 return Drawable_get_font_abcdef( self, first, last, flags, apc_gp_get_font_abc);
388 }
389
390 SV *
Drawable_get_font_def(Handle self,int first,int last,int flags)391 Drawable_get_font_def( Handle self, int first, int last, int flags)
392 {
393 CHECK_GP(NULL_SV);
394 return Drawable_get_font_abcdef( self, first, last, flags, apc_gp_get_font_def);
395 }
396
397 SV *
Drawable_get_font_languages(Handle self)398 Drawable_get_font_languages( Handle self)
399 {
400 char *buf, *p;
401 AV * av = newAV();
402 gpARGS;
403
404 CHECK_GP(NULL_SV);
405 gpENTER( newRV_noinc(( SV *) av));
406 p = buf = apc_gp_get_font_languages( self);
407 gpLEAVE;
408 if (p) {
409 while (*p) {
410 int len = strlen(p);
411 av_push(av, newSVpv(p, len));
412 p += len + 1;
413 }
414 free(buf);
415 }
416 return newRV_noinc(( SV *) av);
417 }
418
419 SV *
Drawable_get_font_ranges(Handle self)420 Drawable_get_font_ranges( Handle self)
421 {
422 int count = 0;
423 unsigned long * ret;
424 AV * av = newAV();
425 gpARGS;
426
427 CHECK_GP(NULL_SV);
428 gpENTER( newRV_noinc(( SV *) av));
429 ret = apc_gp_get_font_ranges( self, &count);
430 gpLEAVE;
431 if ( ret) {
432 int i;
433 for ( i = 0; i < count; i++)
434 av_push( av, newSViv( ret[i]));
435 free( ret);
436 }
437 return newRV_noinc(( SV *) av);
438 }
439
440
441 SV *
Drawable_get_handle(Handle self)442 Drawable_get_handle( Handle self)
443 {
444 char buf[ 256];
445 CHECK_GP(NULL_SV);
446 snprintf( buf, 256, PR_HANDLE_FMT, apc_gp_get_handle( self));
447 return newSVpv( buf, 0);
448 }
449
450 int
Drawable_height(Handle self,Bool set,int height)451 Drawable_height( Handle self, Bool set, int height)
452 {
453 Point p = my-> get_size( self);
454 if ( !set)
455 return p. y;
456 p. y = height;
457 my-> set_size( self, p);
458 return height;
459 }
460
461 Point
Drawable_resolution(Handle self,Bool set,Point resolution)462 Drawable_resolution( Handle self, Bool set, Point resolution)
463 {
464 CHECK_GP(resolution);
465 if ( set)
466 croak("Attempt to write read-only property %s", "Drawable::resolution");
467 return apc_gp_get_resolution( self);
468 }
469
470 Point
Drawable_size(Handle self,Bool set,Point size)471 Drawable_size ( Handle self, Bool set, Point size)
472 {
473 if ( set)
474 croak("Attempt to write read-only property %s", "Drawable::size");
475 size. x = var-> w;
476 size. y = var-> h;
477 return size;
478 }
479
480 int
Drawable_width(Handle self,Bool set,int width)481 Drawable_width( Handle self, Bool set, int width)
482 {
483 Point p = my-> get_size( self);
484 if ( !set)
485 return p. x;
486 p. x = width;
487 my-> set_size( self, p);
488 return width;
489 }
490
491 Bool
Drawable_put_image_indirect(Handle self,Handle image,int x,int y,int xFrom,int yFrom,int xDestLen,int yDestLen,int xLen,int yLen,int rop)492 Drawable_put_image_indirect( Handle self, Handle image, int x, int y, int xFrom, int yFrom, int xDestLen, int yDestLen, int xLen, int yLen, int rop)
493 {
494 Bool ok;
495 CHECK_GP(false);
496 if ( image == NULL_HANDLE) return false;
497 if ( !(PObject(image)-> options.optSystemDrawable)) {
498 warn("This method is not available on this class because it is not a system Drawable object. You need to implement your own");
499 return false;
500 }
501 if ( xLen == xDestLen && yLen == yDestLen)
502 ok = apc_gp_put_image( self, image, x, y, xFrom, yFrom, xLen, yLen, rop);
503 else
504 ok = apc_gp_stretch_image( self, image, x, y, xFrom, yFrom, xDestLen, yDestLen, xLen, yLen, rop);
505 if ( !ok) perl_error();
506 return ok;
507 }
508
509 static Bool
primitive(Handle self,Bool fill,char * method,...)510 primitive( Handle self, Bool fill, char * method, ...)
511 {
512 Bool r;
513 SV * ret;
514 char format[256];
515 va_list args;
516 va_start( args, method);
517 ENTER;
518 SAVETMPS;
519 strcpy(format, "<");
520 strncat(format, method, 255);
521 ret = call_perl_indirect( self, fill ? "fill_aa_primitive" : "stroke_aa_primitive", format, true, false, args);
522 va_end( args);
523 r = ret ? SvTRUE( ret) : false;
524 FREETMPS;
525 LEAVE;
526 return r;
527 }
528
529 #define IS_AA (var->antialias || (var->alpha < 255))
530 #define TRUNC(x) x=trunc(x)
531 #define TRUNC2(x,y) {TRUNC(x);TRUNC(y);}
532 #define TRUNC4(x,y,z,t) {TRUNC(x);TRUNC(y);TRUNC(z);TRUNC(t);}
533
534
535 Bool
Drawable_arc(Handle self,double x,double y,double dX,double dY,double startAngle,double endAngle)536 Drawable_arc( Handle self, double x, double y, double dX, double dY, double startAngle, double endAngle)
537 {
538 CHECK_GP(false);
539 while ( startAngle > endAngle ) endAngle += 360.0;
540 return IS_AA ?
541 primitive( self, 0, "snnnnnn", "arc", x, y, dX-1, dY-1, startAngle, endAngle) :
542 apc_gp_arc(self, x, y, dX, dY, startAngle, endAngle);
543 }
544
545 Bool
Drawable_chord(Handle self,double x,double y,double dX,double dY,double startAngle,double endAngle)546 Drawable_chord( Handle self, double x, double y, double dX, double dY, double startAngle, double endAngle)
547 {
548 CHECK_GP(false);
549 return IS_AA ?
550 primitive( self, 0, "snnnnnn", "chord", x, y, dX-1, dY-1, startAngle, endAngle) :
551 apc_gp_chord(self, x, y, dX, dY, startAngle, endAngle);
552 }
553
554 Bool
Drawable_ellipse(Handle self,double x,double y,double dX,double dY)555 Drawable_ellipse( Handle self, double x, double y, double dX, double dY)
556 {
557 CHECK_GP(false);
558 return IS_AA ?
559 primitive( self, 0, "snnnn", "ellipse", x, y, dX-1, dY-1) :
560 apc_gp_ellipse(self, x, y, dX, dY);
561 }
562
563 Bool
Drawable_bar(Handle self,double x1,double y1,double x2,double y2)564 Drawable_bar( Handle self, double x1, double y1, double x2, double y2)
565 {
566 CHECK_GP(false);
567
568 if ( !var->antialias ) TRUNC4(x1,y1,x2,y2);
569
570 if (IS_AA) {
571 NPoint r[5] = { {x1,y1}, {x2,y1}, {x2,y2}, {x1,y2}, {x1,y1} };
572 return apc_gp_aa_fill_poly( self, 5, r);
573 } else
574 return apc_gp_bar(self, x1, y1, x2, y2);
575 }
576
577 Bool
Drawable_bars(Handle self,SV * rects)578 Drawable_bars( Handle self, SV * rects)
579 {
580 int count;
581 Rect * p;
582 Bool ret = false, do_free;
583 CHECK_GP(false);
584 if (( p = prima_read_array( rects, "Drawable::bars",
585 IS_AA ? 'd' : 'i',
586 4, 0, -1, &count, &do_free)) == NULL)
587 return false;
588
589 if ( IS_AA ) {
590 int i;
591 NRect *r;
592 for ( i = 0, r = (NRect*)p; i < count; i++, r++) {
593 NPoint xr[5] = {
594 {r->left,r->bottom},
595 {r->left,r->top},
596 {r->right,r->top},
597 {r->right,r->bottom},
598 {r->left,r->bottom}
599 };
600 if ( !var->antialias) {
601 int j;
602 for ( j = 0; j < 5; j++)
603 TRUNC2(xr[j].x,xr[j].y);
604 }
605 if ( !( ret = apc_gp_aa_fill_poly( self, 5, xr)))
606 break;
607 }
608 } else
609 ret = apc_gp_bars( self, count, p);
610 if ( !ret) perl_error();
611 if ( do_free ) free( p);
612 return ret;
613 }
614
615 Bool
Drawable_clear(Handle self,double x1,double y1,double x2,double y2)616 Drawable_clear( Handle self, double x1, double y1, double x2, double y2)
617 {
618 Bool full;
619 CHECK_GP(false);
620
621 full = x1 < 0 && y1 < 0 && x2 < 0 && y2 < 0;
622 if ( !var->antialias ) TRUNC4(x1,y1,x2,y2);
623 if ( !full && IS_AA) {
624 Bool ok;
625 Color color;
626 FillPattern fp;
627 NPoint r[5] = { {x1,y1}, {x2,y1}, {x2,y2}, {x1,y2}, {x1,y1} };
628 color = apc_gp_get_color(self);
629 memcpy(&fp, apc_gp_get_fill_pattern(self), sizeof(FillPattern));
630 apc_gp_set_color(self, apc_gp_get_back_color(self));
631 apc_gp_set_fill_pattern(self, fillPatterns[fpSolid]);
632 ok = apc_gp_aa_fill_poly( self, 5, r);
633 apc_gp_set_fill_pattern(self, fp);
634 apc_gp_set_color(self, color);
635 return ok;
636 } else return apc_gp_clear(self,
637 x1,y1,x2,y2
638 );
639 }
640
641 Bool
Drawable_fill_chord(Handle self,double x,double y,double dX,double dY,double startAngle,double endAngle)642 Drawable_fill_chord( Handle self, double x, double y, double dX, double dY, double startAngle, double endAngle)
643 {
644 CHECK_GP(false);
645 if (IS_AA) {
646 return primitive( self, 1, "snnnnnn", "chord", x, y, dX, dY, startAngle, endAngle);
647 } else return apc_gp_fill_chord(self,
648 x, y, dX, dY, startAngle, endAngle
649 );
650 }
651
652 Bool
Drawable_fill_ellipse(Handle self,double x,double y,double dX,double dY)653 Drawable_fill_ellipse( Handle self, double x, double y, double dX, double dY)
654 {
655 if (IS_AA) {
656 return primitive( self, 1, "snnnn", "ellipse", x, y, dX, dY);
657 } else return apc_gp_fill_ellipse(self,
658 x, y, dX, dY
659 );
660 }
661
662 Bool
Drawable_fill_sector(Handle self,double x,double y,double dX,double dY,double startAngle,double endAngle)663 Drawable_fill_sector( Handle self, double x, double y, double dX, double dY, double startAngle, double endAngle)
664 {
665 CHECK_GP(false);
666 if (IS_AA) {
667 return primitive( self, 1, "snnnnnn", "sector", x, y, dX, dY, startAngle, endAngle);
668 } else return apc_gp_fill_sector(self,
669 x, y, dX, dY, startAngle, endAngle
670 );
671 }
672
673 Bool
Drawable_fillpoly(Handle self,SV * points)674 Drawable_fillpoly(Handle self, SV * points)
675 {
676 int count;
677 void *p;
678 Bool ret = false;
679 Bool do_free = true;
680 CHECK_GP(false);
681
682 if (( p = prima_read_array(
683 points, "fillpoly",
684 IS_AA ? 'd' : 'i',
685 2, 2, -1, &count,
686 (var->alpha < 255 && !var->antialias) ? NULL : &do_free
687 )) == NULL)
688 return false;
689
690 if ( var->alpha < 255 && !var->antialias ) {
691 int i;
692 NPoint *pp = (NPoint*)p;
693 for ( i = 0; i < count; i++, pp++) TRUNC2(pp->x,pp->y);
694 }
695
696 ret = IS_AA ?
697 apc_gp_aa_fill_poly( self, count, (NPoint*) p) :
698 apc_gp_fill_poly( self, count, (Point*) p);
699 if ( !ret) perl_error();
700 if ( do_free ) free(p);
701
702 return ret;
703 }
704
705 Bool
Drawable_line(Handle self,double x1,double y1,double x2,double y2)706 Drawable_line(Handle self, double x1, double y1, double x2, double y2)
707 {
708 CHECK_GP(false);
709 if (IS_AA)
710 return primitive( self, 0, "snnnn", "line", x1, y1, x2, y2);
711 else return apc_gp_line(self,
712 x1, y1, x2, y2
713 );
714 }
715
716 static Bool
read_polypoints(Handle self,SV * points,char * procName,int min,Bool (* procPtr)(Handle,int,Point *))717 read_polypoints( Handle self, SV * points, char * procName, int min, Bool (*procPtr)(Handle,int,Point*))
718 {
719 int count;
720 Point * p;
721 Bool ret = false;
722 Bool do_free;
723 if (( p = (Point*) prima_read_array( points, procName, 'i', 2, min, -1, &count, &do_free)) != NULL) {
724 ret = procPtr( self, count, p);
725 if ( !ret) perl_error();
726 if ( do_free ) free(p);
727 }
728 return ret;
729 }
730
731 Bool
Drawable_lines(Handle self,SV * lines)732 Drawable_lines(Handle self, SV * lines)
733 {
734 CHECK_GP(false);
735
736 if (IS_AA)
737 return primitive( self, 0, "sS", "lines", lines);
738 else
739 return read_polypoints( self, lines, "Drawable::lines", 2, apc_gp_draw_poly2);
740 }
741
742 Bool
Drawable_polyline(Handle self,SV * lines)743 Drawable_polyline(Handle self, SV * lines)
744 {
745 CHECK_GP(false);
746
747 if (IS_AA)
748 return primitive( self, 0, "sS", "line", lines);
749 else
750 return read_polypoints( self, lines, "Drawable::polyline", 2, apc_gp_draw_poly);
751 }
752
753 Bool
Drawable_rectangle(Handle self,double x1,double y1,double x2,double y2)754 Drawable_rectangle( Handle self, double x1, double y1, double x2, double y2)
755 {
756 CHECK_GP(false);
757 return IS_AA ?
758 primitive( self, 0, "snnnn", "rectangle", x1,y1,x2,y2) :
759 apc_gp_rectangle(self, x1, y1, x2, y2);
760 }
761
762 SV *
Drawable_render_glyph(Handle self,int index,HV * profile)763 Drawable_render_glyph( Handle self, int index, HV * profile)
764 {
765 int flags, *buffer, count;
766 SV * ret;
767 dPROFILE;
768 gpARGS;
769 CHECK_GP(NULL_SV);
770 gpENTER(NULL_SV);
771
772 flags = ggoUseHints;
773 if ( pexist(glyph) && pget_B(glyph)) flags |= ggoGlyphIndex;
774 if ( pexist(hints) && !pget_B(hints)) flags &= ~ggoUseHints;
775 if ( pexist(unicode) && pget_B(unicode)) flags |= ggoUnicode;
776 count = apc_gp_get_glyph_outline( self, index, flags, &buffer);
777 hv_clear(profile); /* old gencls bork */
778 gpLEAVE;
779
780 if ( count < 0 ) return NULL_SV;
781 ret = prima_array_new(sizeof(int) * count);
782 memcpy( prima_array_get_storage(ret), buffer, sizeof(int) * count);
783 if ( buffer ) free( buffer );
784 return prima_array_tie( ret, sizeof(int), "i");
785 }
786
787 /*
788
789 Render B-spline
790
791 thanks to :
792
793 Marcel Steinbeck for tinyspline.c
794 Thibaut Séguy for bspline.js
795 Carl-Wilhelm Reinhold de Boor for the rendering algorithm
796
797 */
798
799 /* fill default set of knots for curve */
800 static double *
default_knots(int n_points,int degree,Bool clamped)801 default_knots( int n_points, int degree, Bool clamped )
802 {
803 double * ret, * ptr;
804 int i, n_knots, order;
805
806 order = degree + 1;
807 n_knots = n_points + order;
808 if ( !( ret = malloc( sizeof(double) * n_knots )))
809 return NULL;
810 ptr = ret;
811
812 if ( clamped ) {
813 int slope = n_knots - order * 2;
814 double fac = 1.0 / (n_knots - 2 * degree - 1);
815 for ( i = 0; i < order; i++, ptr++) *ptr = 0.0;
816 for ( i = 0; i < slope; i++, ptr++) *ptr = fac * (i + 1);
817 for ( i = 0; i < order; i++, ptr++) *ptr = 1.0;
818 } else {
819 for ( i = 0; i < n_knots; i++, ptr++) *ptr = (double) i;
820 }
821
822 return ret;
823 }
824
825 /* render single point on a spline with de Boor's algorithm */
826 static Bool
render_point(double t,int degree,int n_points,int dimensions,double * v,double * knots,int * last_found_knot,Point * result,NPoint * nresult)827 render_point(
828 double t,
829 int degree, int n_points, int dimensions, double * v,
830 double * knots, int * last_found_knot, Point * result, NPoint * nresult
831 ) {
832 double lo, hi;
833 int l, i, n_knots = n_points + degree + 1, s, found = false;
834
835 lo = knots[degree];
836 hi = knots[n_knots - degree - 1];
837 t = t * ( hi - lo ) + lo;
838
839 /* find which pair of knots t belongs to */
840 s = ( *last_found_knot < 0 ) ? degree : *last_found_knot;
841 for ( ; s < n_points; s++ ) {
842 if ( t >= knots[s] && t <= knots[s + 1] ) {
843 *last_found_knot = s;
844 found = true;
845 break;
846 }
847 }
848 if ( !found ) {
849 warn("badly formed knot vector: outside curve definition");
850 return false;
851 }
852
853 for ( l = 1; l <= degree + 1; l++) {
854 for ( i = s; i > s - degree - 1 + l; i-- ) {
855 int j, ix;
856 double dkt, a, a_hat;
857 dkt = knots[i + degree + 1 - l] - knots[i];
858 if ( dkt == 0.0 ) {
859 warn("badly formed knot vector: not increasing");
860 return false;
861 }
862 a = ( t - knots[i] ) / dkt;
863 a_hat = 1.0 - a;
864 ix = i * 3;
865 /* interpolate each component */
866 for ( j = 0; j < dimensions; j++, ix++)
867 v[ix] = a_hat * v[ix - 3] + a * v[ix];
868 }
869 }
870
871 /* convert back to cartesian and return */
872 s *= 3;
873 if ( dimensions == 3 ) {
874 double f;
875 f = v[s] / v[s+2];
876 if ( result )
877 result-> x = ( f < 0 ) ? (f - .5) : (f + .5);
878 else
879 nresult-> x = f;
880 f = v[s+1] / v[s+2];
881 if ( result )
882 result-> y = ( f < 0 ) ? (f - .5) : (f + .5);
883 else
884 nresult-> y = f;
885 } else if ( result ) {
886 result-> x = (v[s] < 0) ? (v[s] - .5) : (v[s] + .5);
887 result-> y = (v[s+1] < 0) ? (v[s+1] - .5) : (v[s+1] + .5);
888 } else {
889 nresult-> x = v[s];
890 nresult-> y = v[s+1];
891 }
892
893 return true;
894 }
895
896 static int
tangent_detect(Point * a,Point * b)897 tangent_detect( Point * a, Point * b)
898 {
899 register int x = a->x - b->x;
900 register int y = a->y - b->y;
901 if ( x == 0 ) {
902 if ( y == 0) return 0;
903 if ( y == -1) return 1;
904 if ( y == 1) return 2;
905 } else if ( y == 0 ) {
906 if ( x == -1) return 3;
907 if ( x == 1) return 4;
908 } else if ( x < 2 && x > -2 && y < 2 && y > -2 )
909 return (x * 10) + y;
910 return -1;
911 }
912
913 static void
tangent_apply(int tangent,Point * b)914 tangent_apply( int tangent, Point * b)
915 {
916 switch(tangent) {
917 case 1:
918 b->y++;
919 break;
920 case 2:
921 b->y--;
922 break;
923 case 3:
924 b->x++;
925 break;
926 case 4:
927 b->x--;
928 break;
929 case 10 - 1:
930 b->x--;
931 b->y++;
932 break;
933 case 10 + 1:
934 b->x--;
935 b->y--;
936 break;
937 case - 10 - 1:
938 b->x++;
939 b->y++;
940 break;
941 case - 10 + 1:
942 b->x++;
943 b->y--;
944 break;
945 }
946 }
947
948 static Bool
cut_corner(int t2,int t1,Point * p2,Point * p1)949 cut_corner( int t2, int t1, Point * p2, Point * p1)
950 {
951 switch (t2 * 10 + t1) {
952 /*
953 >xxa xx is tangent 3
954 ab> aa is tangent 1
955 bb is something not 1
956
957 corner is detected when (aa) is exactly 1px high,
958 and is cut so that (ab) becomes (b)
959 */
960 case 13: case 14: return p2->y + 1 == p1->y;
961 case 23: case 24: return p2->y - 1 == p1->y;
962 case 31: case 32: return p2->x + 1 == p1->x;
963 case 41: case 42: return p2->x - 1 == p1->x;
964 }
965 return false;
966 }
967
968 SV *
Drawable_render_spline(SV * obj,SV * points,HV * profile)969 Drawable_render_spline( SV * obj, SV * points, HV * profile)
970 {
971 dPROFILE;
972 NPoint *p, *pp;
973 Point *rendered, *storage;
974 NPoint *nrendered, *nstorage;
975 SV *ret;
976 Bool ok, closed, as_integer;
977 int i, j, degree, precision, n_points, final_size, k, dim, n_add_points, temp_size,
978 tangent, last_tangent;
979 double *knots, *weights, t, dt, *weighted, *temp;
980
981 knots = weights = weighted = NULL;
982 p = NULL;
983 ret = NULL;
984 ok = false;
985
986 /* parse input */
987 if ( pexist( degree )) {
988 degree = pget_i(degree);
989 if ( degree < 2 ) {
990 warn("degree must be at least 2");
991 goto EXIT;
992 }
993 } else
994 degree = 2;
995
996 if ( pexist( precision )) {
997 precision = pget_i(precision);
998 if ( precision < 2 || precision > 1024 ) {
999 warn("precision must be at least 2 and max 1024");
1000 goto EXIT;
1001 }
1002 } else
1003 precision = 24;
1004
1005 as_integer = pexist(integer) ? pget_B( integer ) : true;
1006
1007 p = (NPoint*) prima_read_array( points, "Drawable::render_spline", 'd', 2, degree + 1, -1, &n_points, NULL);
1008 if ( !p) goto EXIT;
1009
1010 /* closed curve will need at least one extra point and unclamped default knot set */
1011 if ( pexist( closed )) {
1012 SV * sv = pget_sv(closed);
1013 if ( SvTYPE(sv) == SVt_NULL ) goto DETECT_SHAPE;
1014 closed = SvTRUE(sv);
1015 }
1016 else {
1017 DETECT_SHAPE:
1018 closed = p[0].x == p[n_points-1].x && p[0].y == p[n_points-1].y;
1019 }
1020 n_add_points = closed ? degree - 1 : 0;
1021 n_points += n_add_points;
1022
1023 if ( pexist( knots )) {
1024 knots = (double*) prima_read_array( pget_sv(knots), "knots", 'd', 1,
1025 n_points + degree + 1, n_points + degree + 1, NULL, NULL);
1026 if (!knots) goto EXIT;
1027 } else
1028 knots = default_knots(n_points, degree, !closed);
1029
1030 if ( pexist( weights )) {
1031 weights = (double*) prima_read_array(pget_sv(weights), "weights", 'd', 1,
1032 n_points, n_points, NULL, NULL);
1033 if (!weights) goto EXIT;
1034 dim = 3;
1035 } else {
1036 weights = NULL; /* all ones */
1037 dim = 2;
1038 }
1039
1040 /* allocate result storage */
1041 precision *= n_points - n_add_points;
1042 ret = prima_array_new(( precision + 1) * (as_integer ? sizeof(Point) : sizeof(NPoint)) );
1043
1044 temp_size = sizeof(double) * 3 * n_points;
1045 if ( !(weighted = malloc( 2 * temp_size ))) {
1046 warn("not enough memory");
1047 goto EXIT;
1048 }
1049
1050 /* convert to weighted points */
1051 for ( i = j = 0, pp = p; i < n_points; i++, pp++) {
1052 register double w = weights ? weights[i] : 1.0;
1053 weighted[j++] = pp->x * w;
1054 weighted[j++] = pp->y * w;
1055 weighted[j++] = w;
1056 if ( i == n_points - n_add_points - 1 ) pp = p;
1057 }
1058 temp = weighted + 3 * n_points;
1059
1060 /* render */
1061 final_size = 0;
1062 if ( as_integer ) {
1063 nrendered = nstorage = NULL;
1064 rendered = storage = (Point*) prima_array_get_storage(ret);
1065 } else {
1066 rendered = storage = NULL;
1067 nrendered = nstorage = (NPoint*) prima_array_get_storage(ret);
1068 }
1069 k = -1;
1070 last_tangent = -1;
1071 for ( i = 0, t = 0.0, dt = 1.0 / precision; i < precision - 1; i++, t += dt) {
1072 memcpy( temp, weighted, temp_size);
1073 if (!render_point(t, degree, n_points, dim, temp, knots, &k, rendered, nrendered))
1074 goto EXIT;
1075 if ( as_integer && i > 0 ) {
1076 /* primitive line detection */
1077 tangent = tangent_detect( rendered-1, rendered);
1078 if ( tangent == 0 ) continue;
1079 if ( final_size > 1 && tangent > 0 && tangent == last_tangent) {
1080 tangent_apply( tangent, rendered-1);
1081 continue;
1082 } else if ( final_size > 1 && cut_corner(last_tangent, tangent, rendered-2, rendered-1)) {
1083 /* primitive corner detection - convert 4-connectivity into 8- */
1084 *(rendered-1) = *rendered;
1085 tangent = -1;
1086 rendered--;
1087 final_size--;
1088 continue;
1089 } else
1090 last_tangent = tangent;
1091 }
1092 final_size++;
1093 if ( as_integer )
1094 rendered++;
1095 else
1096 nrendered++;
1097 }
1098 memcpy( temp, weighted, temp_size);
1099 if ( !render_point(1.0, degree, n_points, dim, temp, knots, &k, rendered, nrendered))
1100 goto EXIT;
1101 final_size++;
1102 rendered++;
1103 nrendered++;
1104
1105 /* looks good */
1106 ok = true;
1107 if ( closed ) {
1108 final_size++;
1109 if ( as_integer ) {
1110 *rendered = storage[0];
1111 rendered++;
1112 } else {
1113 *nrendered = nstorage[0];
1114 nrendered++;
1115 }
1116 }
1117 if ( final_size == 1 ) {
1118 final_size = 2;
1119 if ( as_integer )
1120 storage[1] = storage[0];
1121 else
1122 nstorage[1] = nstorage[0];
1123 }
1124 prima_array_truncate( ret, final_size * (as_integer ? sizeof( Point) : sizeof(NPoint)) );
1125
1126 EXIT:
1127 hv_clear(profile); /* old gencls bork */
1128 if (weighted) free(weighted);
1129 if (p) free(p);
1130 if (knots) free(knots);
1131 if (weights) free(weights);
1132 if ( ok ) {
1133 return prima_array_tie( ret,
1134 as_integer ? sizeof(int) : sizeof(double),
1135 as_integer ? "i" : "d"
1136 );
1137 } else {
1138 if (ret) sv_free(ret);
1139 return newRV_noinc(( SV *) newAV());
1140 }
1141 }
1142
1143 SV *
Drawable_render_polyline(SV * obj,SV * points,HV * profile)1144 Drawable_render_polyline( SV * obj, SV * points, HV * profile)
1145 {
1146 dPROFILE;
1147 int count;
1148 Bool free_input = false, free_buffer = false, as_integer = false;
1149 double *input = NULL, *buffer = NULL, box[4];
1150 SV * ret;
1151 void * storage;
1152
1153 if (( input = (double*) prima_read_array( points, "render_polyline", 'd', 2, 1, -1, &count, &free_input)) == NULL)
1154 goto FAIL;
1155
1156 if ( pexist(integer)) as_integer = pget_B(integer);
1157
1158 if ( pexist(matrix) ) {
1159 int i;
1160 double *src, *dst, *cmatrix;
1161 if (( cmatrix = (double*) prima_read_array(
1162 pget_sv(matrix),
1163 "render_polyline.matrix", 'd', 1, 6, 6, NULL, NULL)
1164 ) == NULL)
1165 goto FAIL;
1166 if ( !( buffer = malloc(sizeof(double) * 2 * count))) {
1167 free(cmatrix);
1168 warn("Not enough memory");
1169 goto FAIL;
1170 }
1171 free_buffer = true;
1172
1173 for ( i = 0, src = input, dst = buffer; i < count; i++) {
1174 double x,y;
1175 x = *(src++);
1176 y = *(src++);
1177 *(dst++) = cmatrix[0] * x + cmatrix[2] * y + cmatrix[4];
1178 *(dst++) = cmatrix[1] * x + cmatrix[3] * y + cmatrix[5];
1179 }
1180 free(cmatrix);
1181 } else {
1182 buffer = input;
1183 free_buffer = false;
1184 }
1185
1186 if ( pexist(box) && pget_B(box)) {
1187 int i;
1188 double *src;
1189 box[0] = box[2] = buffer[0];
1190 box[1] = box[3] = buffer[1];
1191 for ( i = 1, src = buffer + 2; i < count; i++) {
1192 double x,y;
1193 x = *(src++);
1194 y = *(src++);
1195 if ( box[0] > x ) box[0] = x;
1196 if ( box[1] > y ) box[1] = y;
1197 if ( box[2] < x ) box[2] = x;
1198 if ( box[3] < y ) box[3] = y;
1199 }
1200 box[2] -= box[0] - 1;
1201 box[3] -= box[1] - 1;
1202 if ( as_integer ) {
1203 box[0] = floor(box[0]);
1204 box[1] = floor(box[1]);
1205 }
1206 if ( free_buffer ) free(buffer);
1207 free_buffer = false;
1208 buffer = box;
1209 count = 2;
1210 }
1211
1212 ret = prima_array_new(count * 2 * (as_integer ? sizeof(int) : sizeof(double)));
1213 storage = prima_array_get_storage(ret);
1214 if ( as_integer ) {
1215 int i, *dst;
1216 double *src;
1217 for ( i = 0, src = buffer, dst = (int*)storage; i < count; i++) {
1218 register double x;
1219 x = *(src++);
1220 *(dst++) = x + ((x < 0) ? -.5 : +.5);
1221 x = *(src++);
1222 *(dst++) = x + ((x < 0) ? -.5 : +.5);
1223 }
1224 } else
1225 memcpy(storage, buffer, count * 2 * sizeof(double));
1226
1227 if ( free_buffer ) free( buffer );
1228 if ( free_input ) free(input);
1229 hv_clear(profile); /* old gencls bork */
1230
1231 return prima_array_tie( ret,
1232 as_integer ? sizeof(int) : sizeof(double),
1233 as_integer ? "i" : "d");
1234
1235 FAIL:
1236 if ( free_buffer ) free( buffer );
1237 if ( free_input ) free(input);
1238 hv_clear(profile); /* old gencls bork */
1239 return NULL_SV;
1240 }
1241
1242 PRGBColor
prima_read_palette(int * palSize,SV * palette)1243 prima_read_palette( int * palSize, SV * palette)
1244 {
1245 AV * av;
1246 int i, count;
1247 Byte * buf;
1248
1249 if ( !SvROK( palette) || ( SvTYPE( SvRV( palette)) != SVt_PVAV)) {
1250 *palSize = 0;
1251 return NULL;
1252 }
1253 av = (AV *) SvRV( palette);
1254 count = av_len( av) + 1;
1255 *palSize = count / 3;
1256 count = *palSize * 3;
1257 if ( count == 0) return NULL;
1258
1259 if ( !( buf = allocb( count))) return NULL;
1260
1261 for ( i = 0; i < count; i++)
1262 {
1263 SV **itemHolder = av_fetch( av, i, 0);
1264 if ( itemHolder == NULL)
1265 return ( PRGBColor) buf;
1266 buf[ i] = SvIV( *itemHolder);
1267 }
1268
1269 return ( PRGBColor) buf;
1270 }
1271
1272 Bool
Drawable_sector(Handle self,double x,double y,double dX,double dY,double startAngle,double endAngle)1273 Drawable_sector( Handle self, double x, double y, double dX, double dY, double startAngle, double endAngle)
1274 {
1275 CHECK_GP(false);
1276 return IS_AA ?
1277 primitive( self, 0, "snnnnnn", "sector", x, y, dX-1, dY-1, startAngle, endAngle) :
1278 apc_gp_sector(self, x, y, dX, dY, startAngle, endAngle);
1279 }
1280
1281 /* Properties */
1282
1283 int
Drawable_alpha(Handle self,Bool set,int alpha)1284 Drawable_alpha( Handle self, Bool set, int alpha)
1285 {
1286 if (!set) return apc_gp_get_alpha( self);
1287 if ( alpha < 0 ) alpha = 0;
1288 if ( alpha > 255 ) alpha = 255;
1289 apc_gp_set_alpha( self, alpha);
1290 return var->alpha = apc_gp_get_alpha(self);
1291 }
1292
1293 Bool
Drawable_antialias(Handle self,Bool set,Bool aa)1294 Drawable_antialias( Handle self, Bool set, Bool aa)
1295 {
1296 if (set) apc_gp_set_antialias( self, aa );
1297 return var->antialias = apc_gp_get_antialias( self );
1298 }
1299
1300 Color
Drawable_backColor(Handle self,Bool set,Color color)1301 Drawable_backColor( Handle self, Bool set, Color color)
1302 {
1303 if (!set) return apc_gp_get_back_color( self);
1304 apc_gp_set_back_color( self, color);
1305 return color;
1306 }
1307
1308 Color
Drawable_color(Handle self,Bool set,Color color)1309 Drawable_color( Handle self, Bool set, Color color)
1310 {
1311 if (!set) return apc_gp_get_color( self);
1312 apc_gp_set_color( self, color);
1313 return color;
1314 }
1315
1316 Rect
Drawable_clipRect(Handle self,Bool set,Rect clipRect)1317 Drawable_clipRect( Handle self, Bool set, Rect clipRect)
1318 {
1319 if ( !set)
1320 return apc_gp_get_clip_rect( self);
1321 apc_gp_set_clip_rect( self, clipRect);
1322 return clipRect;
1323 }
1324
1325 int
Drawable_fillMode(Handle self,Bool set,int fillMode)1326 Drawable_fillMode( Handle self, Bool set, int fillMode)
1327 {
1328 if (!set) return apc_gp_get_fill_mode( self);
1329 apc_gp_set_fill_mode( self, fillMode);
1330 return fillMode;
1331 }
1332
1333 SV *
Drawable_fillPattern(Handle self,Bool set,SV * svpattern)1334 Drawable_fillPattern( Handle self, Bool set, SV * svpattern)
1335 {
1336 int i;
1337 if ( !set) {
1338 AV * av;
1339 FillPattern * fp = apc_gp_get_fill_pattern( self);
1340 if ( !fp) return NULL_SV;
1341 av = newAV();
1342 for ( i = 0; i < 8; i++) av_push( av, newSViv(( int) (*fp)[i]));
1343 return newRV_noinc(( SV *) av);
1344 } else {
1345 if ( SvROK( svpattern) && ( SvTYPE( SvRV( svpattern)) == SVt_PVAV)) {
1346 FillPattern fp;
1347 AV * av = ( AV *) SvRV( svpattern);
1348 if ( av_len( av) != 7) {
1349 warn("Illegal fillPattern passed to Drawable::fillPattern");
1350 return NULL_SV;
1351 }
1352 for ( i = 0; i < 8; i++) {
1353 SV ** holder = av_fetch( av, i, 0);
1354 if ( !holder) {
1355 warn("Array panic on Drawable::fillPattern");
1356 return NULL_SV;
1357 }
1358 fp[ i] = SvIV( *holder);
1359 }
1360 apc_gp_set_fill_pattern( self, fp);
1361 } else {
1362 int id = SvIV( svpattern);
1363 if (( id < 0) || ( id > fpMaxId)) {
1364 warn("fillPattern index out of range passed to Drawable::fillPattern");
1365 return NULL_SV;
1366 }
1367 apc_gp_set_fill_pattern( self, fillPatterns[ id]);
1368 }
1369 }
1370 return NULL_SV;
1371 }
1372
1373 Point
Drawable_fillPatternOffset(Handle self,Bool set,Point fpo)1374 Drawable_fillPatternOffset( Handle self, Bool set, Point fpo)
1375 {
1376 if (!set) return apc_gp_get_fill_pattern_offset( self);
1377 fpo. x %= 8;
1378 fpo. y %= 8;
1379 apc_gp_set_fill_pattern_offset( self, fpo);
1380 return fpo;
1381 }
1382
1383 Font
Drawable_get_font(Handle self)1384 Drawable_get_font( Handle self)
1385 {
1386 return var-> font;
1387 }
1388
1389 void
Drawable_set_font(Handle self,Font font)1390 Drawable_set_font( Handle self, Font font)
1391 {
1392 clear_font_abc_caches( self);
1393 apc_font_pick( self, &font, &var-> font);
1394 apc_gp_set_font( self, &var-> font);
1395 }
1396
1397
1398 int
Drawable_lineEnd(Handle self,Bool set,int lineEnd)1399 Drawable_lineEnd( Handle self, Bool set, int lineEnd)
1400 {
1401 if (!set) return apc_gp_get_line_end( self);
1402 apc_gp_set_line_end( self, lineEnd);
1403 return lineEnd;
1404 }
1405
1406 int
Drawable_lineJoin(Handle self,Bool set,int lineJoin)1407 Drawable_lineJoin( Handle self, Bool set, int lineJoin)
1408 {
1409 if (!set) return apc_gp_get_line_join( self);
1410 apc_gp_set_line_join( self, lineJoin);
1411 return lineJoin;
1412 }
1413
1414 SV *
Drawable_linePattern(Handle self,Bool set,SV * pattern)1415 Drawable_linePattern( Handle self, Bool set, SV * pattern)
1416 {
1417 if ( set) {
1418 STRLEN len;
1419 unsigned char *pat = ( unsigned char *) SvPV( pattern, len);
1420 if ( len > 255) len = 255;
1421 apc_gp_set_line_pattern( self, pat, len);
1422 } else {
1423 unsigned char ret[ 256];
1424 int len = apc_gp_get_line_pattern( self, ret);
1425 return newSVpvn((char*) ret, len);
1426 }
1427 return NULL_SV;
1428 }
1429
1430
1431 double
Drawable_lineWidth(Handle self,Bool set,double lineWidth)1432 Drawable_lineWidth( Handle self, Bool set, double lineWidth)
1433 {
1434 if (!set) return apc_gp_get_line_width( self);
1435 if ( lineWidth < 0.0 ) lineWidth = 0.0;
1436 apc_gp_set_line_width( self, lineWidth);
1437 return lineWidth;
1438 }
1439
1440 double
Drawable_miterLimit(Handle self,Bool set,double miterLimit)1441 Drawable_miterLimit( Handle self, Bool set, double miterLimit)
1442 {
1443 if (!set) return apc_gp_get_miter_limit( self);
1444 apc_gp_set_miter_limit( self, miterLimit);
1445 return miterLimit;
1446 }
1447
1448 SV *
Drawable_palette(Handle self,Bool set,SV * palette)1449 Drawable_palette( Handle self, Bool set, SV * palette)
1450 {
1451 int colors;
1452 if ( var-> stage > csFrozen) return NULL_SV;
1453 colors = var-> palSize;
1454 if ( set) {
1455 free( var-> palette);
1456 var-> palette = prima_read_palette( &var-> palSize, palette);
1457 if ( colors == 0 && var-> palSize == 0) return NULL_SV; /* do not bother apc */
1458 apc_gp_set_palette( self);
1459 } else {
1460 AV * av = newAV();
1461 int i;
1462 Byte * pal = ( Byte*) var-> palette;
1463 for ( i = 0; i < colors * 3; i++) av_push( av, newSViv( pal[ i]));
1464 return newRV_noinc(( SV *) av);
1465 }
1466 return NULL_SV;
1467 }
1468
1469 SV *
Drawable_pixel(Handle self,Bool set,int x,int y,SV * color)1470 Drawable_pixel( Handle self, Bool set, int x, int y, SV * color)
1471 {
1472 CHECK_GP(0);
1473 if (!set)
1474 return newSViv( apc_gp_get_pixel( self, x, y));
1475 apc_gp_set_pixel( self, x, y, SvIV( color));
1476 return NULL_SV;
1477 }
1478
1479 Handle
Drawable_region(Handle self,Bool set,Handle mask)1480 Drawable_region( Handle self, Bool set, Handle mask)
1481 {
1482 if ( var-> stage > csFrozen) return NULL_HANDLE;
1483 if ( !is_opt(optSystemDrawable))
1484 return NULL_HANDLE;
1485
1486 if ( set) {
1487 if ( mask && kind_of( mask, CRegion)) {
1488 apc_gp_set_region( self, mask);
1489 return NULL_HANDLE;
1490 }
1491
1492 if ( mask && !kind_of( mask, CImage)) {
1493 warn("Illegal object reference passed to Drawable::region");
1494 return NULL_HANDLE;
1495 }
1496
1497 if ( mask ) {
1498 Handle region;
1499 HV * profile = newHV();
1500
1501 pset_H( image, mask );
1502 region = Object_create("Prima::Region", profile);
1503 sv_free(( SV *) profile);
1504
1505 apc_gp_set_region(self, region);
1506 Object_destroy(region);
1507
1508 } else
1509 apc_gp_set_region(self, NULL_HANDLE);
1510
1511 } else if ( apc_gp_get_region( self, NULL_HANDLE)) {
1512 HV * profile = newHV();
1513 Handle i = Object_create( "Prima::Region", profile);
1514 sv_free(( SV *) profile);
1515 apc_gp_get_region( self, i);
1516 --SvREFCNT( SvRV((( PAnyObject) i)-> mate));
1517 return i;
1518 }
1519
1520 return NULL_HANDLE;
1521 }
1522
1523 int
Drawable_rop(Handle self,Bool set,int rop)1524 Drawable_rop( Handle self, Bool set, int rop)
1525 {
1526 if (!set) return apc_gp_get_rop( self);
1527 apc_gp_set_rop( self, rop);
1528 return rop;
1529 }
1530
1531 int
Drawable_rop2(Handle self,Bool set,int rop2)1532 Drawable_rop2( Handle self, Bool set, int rop2)
1533 {
1534 if (!set) return apc_gp_get_rop2( self);
1535 apc_gp_set_rop2( self, rop2);
1536 return rop2;
1537 }
1538
1539 Bool
Drawable_textOpaque(Handle self,Bool set,Bool opaque)1540 Drawable_textOpaque( Handle self, Bool set, Bool opaque)
1541 {
1542 if (!set) return apc_gp_get_text_opaque( self);
1543 apc_gp_set_text_opaque( self, opaque);
1544 return opaque;
1545 }
1546
1547 Bool
Drawable_textOutBaseline(Handle self,Bool set,Bool textOutBaseline)1548 Drawable_textOutBaseline( Handle self, Bool set, Bool textOutBaseline)
1549 {
1550 if (!set) return apc_gp_get_text_out_baseline( self);
1551 apc_gp_set_text_out_baseline( self, textOutBaseline);
1552 return textOutBaseline;
1553 }
1554
1555 Point
Drawable_translate(Handle self,Bool set,Point translate)1556 Drawable_translate( Handle self, Bool set, Point translate)
1557 {
1558 if (!set) return apc_gp_get_transform( self);
1559 apc_gp_set_transform( self, translate. x, translate. y);
1560 return translate;
1561 }
1562
1563 #ifdef __cplusplus
1564 }
1565 #endif
1566