1 #include "img_conv.h"
2 #include "Icon.h"
3
4 #ifdef __cplusplus
5 extern "C" {
6 #endif
7
8
9 typedef void BitBltProc( Byte * src, Byte * dst, int count);
10 typedef BitBltProc *PBitBltProc;
11
12 static void
bitblt_copy(Byte * src,Byte * dst,int count)13 bitblt_copy( Byte * src, Byte * dst, int count)
14 {
15 memcpy( dst, src, count);
16 }
17
18 static void
bitblt_move(Byte * src,Byte * dst,int count)19 bitblt_move( Byte * src, Byte * dst, int count)
20 {
21 memmove( dst, src, count);
22 }
23
24 static void
bitblt_or(Byte * src,Byte * dst,int count)25 bitblt_or( Byte * src, Byte * dst, int count)
26 {
27 while ( count--) *(dst++) |= *(src++);
28 }
29
30 static void
bitblt_and(Byte * src,Byte * dst,int count)31 bitblt_and( Byte * src, Byte * dst, int count)
32 {
33 while ( count--) *(dst++) &= *(src++);
34 }
35
36 static void
bitblt_xor(Byte * src,Byte * dst,int count)37 bitblt_xor( Byte * src, Byte * dst, int count)
38 {
39 while ( count--) *(dst++) ^= *(src++);
40 }
41
42 static void
bitblt_not(Byte * src,Byte * dst,int count)43 bitblt_not( Byte * src, Byte * dst, int count)
44 {
45 while ( count--) *(dst++) = ~(*(src++));
46 }
47
48 static void
bitblt_notdstand(Byte * src,Byte * dst,int count)49 bitblt_notdstand( Byte * src, Byte * dst, int count)
50 {
51 while ( count--) {
52 *dst = ~(*dst) & (*(src++));
53 dst++;
54 }
55 }
56
57 static void
bitblt_notdstor(Byte * src,Byte * dst,int count)58 bitblt_notdstor( Byte * src, Byte * dst, int count)
59 {
60 while ( count--) {
61 *dst = ~(*dst) | (*(src++));
62 dst++;
63 }
64 }
65
66 static void
bitblt_notsrcand(Byte * src,Byte * dst,int count)67 bitblt_notsrcand( Byte * src, Byte * dst, int count)
68 {
69 while ( count--) *(dst++) &= ~(*(src++));
70 }
71
72 static void
bitblt_notsrcor(Byte * src,Byte * dst,int count)73 bitblt_notsrcor( Byte * src, Byte * dst, int count)
74 {
75 while ( count--) *(dst++) |= ~(*(src++));
76 }
77
78 static void
bitblt_notxor(Byte * src,Byte * dst,int count)79 bitblt_notxor( Byte * src, Byte * dst, int count)
80 {
81 while ( count--) {
82 *dst = ~( *(src++) ^ (*dst));
83 dst++;
84 }
85 }
86
87 static void
bitblt_notand(Byte * src,Byte * dst,int count)88 bitblt_notand( Byte * src, Byte * dst, int count)
89 {
90 while ( count--) {
91 *dst = ~( *(src++) & (*dst));
92 dst++;
93 }
94 }
95
96 static void
bitblt_notor(Byte * src,Byte * dst,int count)97 bitblt_notor( Byte * src, Byte * dst, int count)
98 {
99 while ( count--) {
100 *dst = ~( *(src++) | (*dst));
101 dst++;
102 }
103 }
104
105 static void
bitblt_black(Byte * src,Byte * dst,int count)106 bitblt_black( Byte * src, Byte * dst, int count)
107 {
108 memset( dst, 0, count);
109 }
110
111 static void
bitblt_white(Byte * src,Byte * dst,int count)112 bitblt_white( Byte * src, Byte * dst, int count)
113 {
114 memset( dst, 0xff, count);
115 }
116
117 static void
bitblt_invert(Byte * src,Byte * dst,int count)118 bitblt_invert( Byte * src, Byte * dst, int count)
119 {
120 while ( count--) {
121 *dst = ~(*dst);
122 dst++;
123 }
124 }
125
126 static PBitBltProc
find_blt_proc(int rop)127 find_blt_proc( int rop )
128 {
129 PBitBltProc proc = NULL;
130 switch ( rop) {
131 case ropCopyPut:
132 proc = bitblt_copy;
133 break;
134 case ropAndPut:
135 proc = bitblt_and;
136 break;
137 case ropOrPut:
138 proc = bitblt_or;
139 break;
140 case ropXorPut:
141 proc = bitblt_xor;
142 break;
143 case ropNotPut:
144 proc = bitblt_not;
145 break;
146 case ropNotDestAnd:
147 proc = bitblt_notdstand;
148 break;
149 case ropNotDestOr:
150 proc = bitblt_notdstor;
151 break;
152 case ropNotSrcAnd:
153 proc = bitblt_notsrcand;
154 break;
155 case ropNotSrcOr:
156 proc = bitblt_notsrcor;
157 break;
158 case ropNotXor:
159 proc = bitblt_notxor;
160 break;
161 case ropNotAnd:
162 proc = bitblt_notand;
163 break;
164 case ropNotOr:
165 proc = bitblt_notor;
166 break;
167 case ropBlackness:
168 proc = bitblt_black;
169 break;
170 case ropWhiteness:
171 proc = bitblt_white;
172 break;
173 case ropInvert:
174 proc = bitblt_invert;
175 break;
176 default:
177 proc = bitblt_copy;
178 }
179 return proc;
180 }
181
182 static Bool
183 img_put_alpha( Handle dest, Handle src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH, int rop, PBoxRegionRec region);
184
185 static Bool
186 resample_colors( Handle dest, int bpp, PImgPaintContext ctx);
187
188 typedef struct {
189 int srcX;
190 int srcY;
191 int bpp;
192 int srcLS;
193 int dstLS;
194 int dX;
195 int dY;
196 Byte * src;
197 Byte * dst;
198 PBitBltProc proc;
199 } ImgPutCallbackRec;
200
201 static Bool
img_put_single(int x,int y,int w,int h,ImgPutCallbackRec * ptr)202 img_put_single( int x, int y, int w, int h, ImgPutCallbackRec * ptr)
203 {
204 int i, count;
205 Byte *dptr, *sptr;
206 sptr = ptr->src + ptr->srcLS * (ptr->dY + y) + ptr->bpp * (ptr->dX + x);
207 dptr = ptr->dst + ptr->dstLS * y + ptr->bpp * x;
208 count = w * ptr->bpp;
209 for ( i = 0; i < h; i++, sptr += ptr->srcLS, dptr += ptr->dstLS)
210 ptr->proc( sptr, dptr, count);
211 return true;
212 }
213
214 Bool
img_put(Handle dest,Handle src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH,int rop,PBoxRegionRec region,Byte * color)215 img_put(
216 Handle dest, Handle src,
217 int dstX, int dstY, int srcX, int srcY,
218 int dstW, int dstH, int srcW, int srcH,
219 int rop,
220 PBoxRegionRec region, Byte * color
221 ) {
222 Point srcSz, dstSz;
223 int asrcW, asrcH;
224 Bool newObject = false;
225
226 if ( dest == NULL_HANDLE || src == NULL_HANDLE) return false;
227 if ( rop == ropNoOper) return false;
228
229 if ( kind_of( src, CIcon)) {
230 Image dummy;
231 PIcon s = PIcon(src);
232 if ( s-> maskType != imbpp1) {
233 if ( s-> maskType != imbpp8) croak("panic: bad icon mask type");
234 return img_put_alpha( dest, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH, rop, region);
235 }
236 img_fill_dummy( &dummy, s-> w, s-> h, imBW, s-> mask, stdmono_palette);
237 img_put( dest, (Handle) &dummy, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH, ropAndPut, region, color);
238 rop = ropXorPut;
239 } else if ( rop == ropAlphaCopy ) {
240 Bool ok;
241 Image dummy;
242 PIcon i;
243 if ( !kind_of( dest, CIcon )) return false;
244 if ( PImage(src)-> type != imByte ) {
245 Handle dup = CImage(src)->dup(src);
246 CImage(dup)->set_type(src, imByte);
247 ok = img_put( dest, dup, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH, rop, region, color);
248 Object_destroy(dup);
249 return ok;
250 }
251 if ( PIcon(dest)-> maskType != imbpp8) {
252 CIcon(dest)-> set_maskType(dest, imbpp8);
253 ok = img_put( dest, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH, rop, region, color);
254 if ( PIcon(dest)-> options. optPreserveType )
255 CIcon(dest)-> set_maskType(dest, imbpp1);
256 return ok;
257 }
258
259 i = (PIcon) dest;
260 img_fill_dummy( &dummy, i-> w, i-> h, imByte, i-> mask, NULL);
261 return img_put((Handle)&dummy, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH, ropCopyPut, region, color);
262 } else if ( color != NULL ) {
263 Bool ok;
264 Icon dummy;
265 PImage s = PImage(src);
266 Byte * bits;
267 ImgPaintContext ctx;
268 if ( s-> type != imByte ) {
269 Handle dup = CImage(src)->dup(src);
270 CImage(dup)->set_type(src, imByte);
271 ok = img_put( dest, dup, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH, rop, region, color);
272 Object_destroy(dup);
273 return ok;
274 }
275 bzero( &ctx, sizeof(ctx));
276 memcpy( ctx.color, color, MAX_SIZEOF_PIXEL);
277 if ( PImage(dest)-> type & imGrayScale ) {
278 unsigned size = LINE_SIZE(s->w, imByte) * s->h;
279 if ( !( bits = malloc( size )))
280 return false;
281 resample_colors(dest, imbpp8, &ctx);
282 memset(bits, ctx.color[0], size );
283 img_fill_dummy((PImage) &dummy, s-> w, s-> h, imByte, bits, std256gray_palette);
284 } else {
285 Byte * line;
286 int w, linesize = LINE_SIZE(s-> w, imRGB);
287 if ( !( bits = malloc( linesize * s->h )))
288 return false;
289 line = bits;
290 resample_colors(dest, imbpp24, &ctx);
291 for ( w = 0; w < s-> w; w++ ) {
292 *(line++) = ctx.color[0];
293 *(line++) = ctx.color[1];
294 *(line++) = ctx.color[2];
295 }
296 for ( w = 1, line = bits + linesize; w < s-> h; w++, line += linesize)
297 memcpy( line, bits, linesize);
298 img_fill_dummy((PImage) &dummy, s-> w, s-> h, imRGB, bits, NULL);
299 }
300 dummy. self = CIcon;
301 dummy. mask = s-> data;
302 dummy. maskLine = s-> lineSize;
303 dummy. maskSize = s-> dataSize;
304 dummy. maskType = imbpp8;
305 rop &= ~(ropAlphaCopy | ropConstantColor);
306 ok = img_put(dest, (Handle)&dummy, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH, rop, region, NULL);
307 free(bits);
308 return ok;
309 } else if ( rop & ropConstantAlpha )
310 return img_put_alpha( dest, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH, rop, region);
311
312 srcSz. x = PImage(src)-> w;
313 srcSz. y = PImage(src)-> h;
314 dstSz. x = PImage(dest)-> w;
315 dstSz. y = PImage(dest)-> h;
316
317 if ( dstW < 0) {
318 dstW = abs( dstW);
319 srcW = -srcW;
320 }
321 if ( dstH < 0) {
322 dstH = abs( dstH);
323 srcH = -srcH;
324 }
325
326 asrcW = abs( srcW);
327 asrcH = abs( srcH);
328
329 if (
330 srcX >= srcSz. x || srcX + srcW <= 0 ||
331 srcY >= srcSz. y || srcY + srcH <= 0 ||
332 dstX >= dstSz. x || dstX + dstW <= 0 ||
333 dstY >= dstSz. y || dstY + dstH <= 0
334 )
335 return true;
336
337 /* check if we can do it without expensive scalings and extractions */
338 if (
339 ( srcW == dstW) && ( srcH == dstH) &&
340 ( srcX >= 0) && ( srcY >= 0) && ( srcX + srcW <= srcSz. x) && ( srcY + srcH <= srcSz. y)
341 )
342 goto NOSCALE;
343
344 if ( srcX != 0 || srcY != 0 || asrcW != srcSz. x || asrcH != srcSz. y) {
345 /* extract source rectangle */
346 Handle x;
347 int ssx = srcX, ssy = srcY, ssw = asrcW, ssh = asrcH;
348 if ( ssx < 0) {
349 ssw += ssx;
350 ssx = 0;
351 }
352 if ( ssy < 0) {
353 ssh += ssy;
354 ssy = 0;
355 }
356 x = CImage( src)-> extract( src, ssx, ssy, ssw, ssh);
357 if ( !x) return false;
358
359 if ( srcX < 0 || srcY < 0 || srcX + asrcW >= srcSz. x || srcY + asrcH > srcSz. y) {
360 HV * profile;
361 Handle dx;
362 int dsx = 0, dsy = 0, dsw = PImage(x)-> w, dsh = PImage(x)-> h, type = PImage( dest)-> type;
363
364 if ( asrcW != srcW || asrcH != srcH) { /* reverse before application */
365 CImage( x)-> stretch( x, srcW, srcH);
366 srcW = asrcW;
367 srcH = asrcH;
368 if ( PImage(x)-> w != asrcW || PImage(x)-> h != asrcH) {
369 Object_destroy( x);
370 return true;
371 }
372 }
373
374 if (( type & imBPP) < 8) type = imbpp8;
375
376 profile = newHV();
377 pset_i( type, type);
378 pset_i( width, asrcW);
379 pset_i( height, asrcH);
380 pset_i( conversion, PImage( src)-> conversion);
381 dx = Object_create( "Prima::Image", profile);
382 sv_free((SV*)profile);
383 if ( !dx) {
384 Object_destroy( x);
385 return false;
386 }
387 if ( PImage( dx)-> palSize > 0) {
388 PImage( dx)-> palSize = PImage( x)-> palSize;
389 memcpy( PImage( dx)-> palette, PImage( x)-> palette, 768);
390 }
391 memset( PImage( dx)-> data, 0, PImage( dx)-> dataSize);
392
393 if ( srcX < 0) dsx = asrcW - dsw;
394 if ( srcY < 0) dsy = asrcH - dsh;
395 img_put( dx, x, dsx, dsy, 0, 0, dsw, dsh, dsw, dsh, ropCopyPut, region, color);
396 Object_destroy( x);
397 x = dx;
398 }
399
400 src = x;
401 newObject = true;
402 srcX = srcY = 0;
403 }
404
405 if ( srcW != dstW || srcH != dstH) {
406 /* stretch & reverse */
407 if ( !newObject) {
408 src = CImage( src)-> dup( src);
409 if ( !src) goto EXIT;
410 newObject = true;
411 }
412 if ( srcW != asrcW) {
413 dstW = -dstW;
414 srcW = asrcW;
415 }
416 if ( srcH != asrcH) {
417 dstH = -dstH;
418 srcH = asrcH;
419 }
420 CImage(src)-> stretch( src, dstW, dstH);
421 if ( PImage(src)-> w != dstW || PImage(src)-> h != dstH) goto EXIT;
422 dstW = abs( dstW);
423 dstH = abs( dstH);
424 }
425
426 NOSCALE:
427
428 if (( PImage( dest)-> type & imBPP) < 8) {
429 PImage i = ( PImage) dest;
430 int type = i-> type;
431 if (rop != ropCopyPut || i-> conversion == ictNone) {
432 Handle b8 = i-> self-> dup( dest);
433 PImage j = ( PImage) b8;
434 int mask = (1 << (type & imBPP)) - 1;
435 int sz;
436 Byte *dj, *di;
437 Byte colorref[256];
438 j-> self-> reset( b8, imbpp8, NULL, 0);
439 sz = j-> dataSize;
440 dj = j-> data;
441 /* change 0/1 to 0x000/0xfff for correct masking */
442 while ( sz--) {
443 if ( *dj == mask) *dj = 0xff;
444 dj++;
445 }
446 img_put( b8, src, dstX, dstY, 0, 0, dstW, dstH, PImage(src)-> w, PImage(src)-> h, rop, region, color);
447 for ( sz = 0; sz < 256; sz++) colorref[sz] = ( sz > mask) ? mask : sz;
448 dj = j-> data;
449 di = i-> data;
450
451 for ( sz = 0; sz < i-> h; sz++, dj += j-> lineSize, di += i-> lineSize) {
452 if (( type & imBPP) == 1)
453 bc_byte_mono_cr( dj, di, i-> w, colorref);
454 else
455 bc_byte_nibble_cr( dj, di, i-> w, colorref);
456 }
457 Object_destroy( b8);
458 } else {
459 int conv = i-> conversion;
460 i-> conversion = PImage( src)-> conversion;
461 i-> self-> reset( dest, imbpp8, NULL, 0);
462 img_put( dest, src, dstX, dstY, 0, 0, dstW, dstH, PImage(src)-> w, PImage(src)-> h, rop, region, color);
463 i-> self-> reset( dest, type, NULL, 0);
464 i-> conversion = conv;
465 }
466 goto EXIT;
467 }
468
469 if ( PImage( dest)-> type != PImage( src)-> type) {
470 int type = PImage( src)-> type & imBPP;
471 int mask = (1 << type) - 1;
472 /* equalize type */
473 if ( !newObject) {
474 src = CImage( src)-> dup( src);
475 if ( !src) goto EXIT;
476 newObject = true;
477 }
478 CImage( src)-> reset( src, PImage( dest)-> type, NULL, 0);
479 if ( type < 8 && rop != ropCopyPut) {
480 /* change 0/1 to 0x000/0xfff for correct masking */
481 int sz = PImage( src)-> dataSize;
482 Byte * d = PImage( src)-> data;
483 while ( sz--) {
484 if ( *d == mask) *d = 0xff;
485 d++;
486 }
487 memset( PImage( src)-> palette + 255, 0xff, sizeof(RGBColor));
488 }
489 }
490
491 if ( PImage( dest)-> type == imbpp8) {
492 /* equalize palette */
493 Byte colorref[256], *s;
494 int sz, i = PImage( src)-> dataSize;
495 if ( !newObject) {
496 src = CImage( src)-> dup( src);
497 if ( !src) goto EXIT;
498 newObject = true;
499 }
500 cm_fill_colorref(
501 PImage( src)-> palette, PImage( src)-> palSize,
502 PImage( dest)-> palette, PImage( dest)-> palSize,
503 colorref);
504 s = PImage( src)-> data;
505 /* identity transform for padded ( 1->xfff, see above ) pixels */
506 for ( sz = PImage( src)-> palSize; sz < 256; sz++)
507 colorref[sz] = sz;
508 while ( i--) {
509 *s = colorref[ *s];
510 s++;
511 }
512 }
513
514 if ( dstX < 0 || dstY < 0 || dstX + dstW >= dstSz. x || dstY + dstH >= dstSz. y) {
515 /* adjust destination rectangle */
516 if ( dstX < 0) {
517 dstW += dstX;
518 srcX -= dstX;
519 dstX = 0;
520 }
521 if ( dstY < 0) {
522 dstH += dstY;
523 srcY -= dstY;
524 dstY = 0;
525 }
526 if ( dstX + dstW > dstSz. x)
527 dstW = dstSz. x - dstX;
528 if ( dstY + dstH > dstSz. y)
529 dstH = dstSz. y - dstY;
530 }
531
532 /* checks done, do put_image */
533 {
534 ImgPutCallbackRec rec = {
535 /* srcX */ srcX,
536 /* srcY */ srcY,
537 /* bpp */ ( PImage( dest)-> type & imBPP ) / 8,
538 /* srcLS */ PImage( src)-> lineSize,
539 /* dstLS */ PImage( dest)-> lineSize,
540 /* dX */ srcX - dstX,
541 /* dY */ srcY - dstY,
542 /* src */ PImage( src )-> data,
543 /* dst */ PImage( dest )-> data,
544 /* proc */ find_blt_proc(rop)
545 };
546 if ( rec.proc == bitblt_copy && dest == src) /* incredible */
547 rec.proc = bitblt_move;
548 img_region_foreach( region,
549 dstX, dstY, dstW, dstH,
550 (RegionCallbackFunc*)img_put_single, &rec
551 );
552 }
553
554 EXIT:
555 if ( newObject) Object_destroy( src);
556
557 return true;
558 }
559
560 typedef struct {
561 int bpp;
562 int count;
563 int ls;
564 int step;
565 int pat_x_offset;
566 Bool solid;
567 Byte * data;
568 Byte * buf;
569 PBitBltProc proc;
570 } ImgBarCallbackRec;
571
572 #define FILL_PATTERN_SIZE 8
573 #define BLT_BUFSIZE ((MAX_SIZEOF_PIXEL * FILL_PATTERN_SIZE * FILL_PATTERN_SIZE) * 2)
574
575 static Bool
img_bar_single(int x,int y,int w,int h,ImgBarCallbackRec * ptr)576 img_bar_single( int x, int y, int w, int h, ImgBarCallbackRec * ptr)
577 {
578 int j, blt_bytes, blt_step, offset;
579 Byte lmask, rmask;
580 Byte * data, *pat_ptr;
581
582 switch ( ptr->bpp ) {
583 case 1:
584 blt_bytes = (( x + w - 1) >> 3) - (x >> 3) + 1;
585 lmask = ( x & 7 ) ? 255 << ( 8 - (x & 7)) : 0;
586 rmask = (( x + w) & 7 ) ? 255 >> ((x + w) & 7) : 0;
587 offset = x >> 3;
588 break;
589 case 4:
590 blt_bytes = (( x + w - 1) >> 1) - (x >> 1) + 1;
591 lmask = ( x & 1 ) ? 0xf0 : 0;
592 rmask = (( x + w) & 1 ) ? 0x0f : 0;
593 offset = x >> 1;
594 break;
595 case 8:
596 blt_bytes = w;
597 lmask = rmask = 0;
598 offset = x;
599 break;
600 default:
601 blt_bytes = w * ptr->count;
602 lmask = rmask = 0;
603 offset = x * ptr->count;
604 }
605
606 blt_step = ptr->step;
607 if (!ptr->solid && (( ptr-> pat_x_offset % FILL_PATTERN_SIZE ) != (x % FILL_PATTERN_SIZE))) {
608 int dx = (x % FILL_PATTERN_SIZE) - ( ptr-> pat_x_offset % FILL_PATTERN_SIZE );
609 if ( dx < 0 ) dx += FILL_PATTERN_SIZE;
610
611 switch ( ptr->bpp ) {
612 case 1:
613 pat_ptr = ptr->buf;
614 break;
615 case 4:
616 if ( dx > 1 ) {
617 pat_ptr = ptr->buf + dx / 2;
618 if ( dx > 0 || blt_step + FILL_PATTERN_SIZE / 2 > BLT_BUFSIZE )
619 blt_step -= FILL_PATTERN_SIZE / 2;
620 } else
621 pat_ptr = ptr->buf;
622 break;
623 default:
624 pat_ptr = ptr->buf + dx * ptr->bpp / 8;
625 if ( dx > 0 || blt_step + FILL_PATTERN_SIZE * ptr->count > BLT_BUFSIZE )
626 blt_step -= FILL_PATTERN_SIZE * ptr->count;
627 }
628 } else {
629 pat_ptr = ptr->buf;
630 }
631
632 if (blt_bytes < blt_step) blt_step = blt_bytes;
633
634 data = ptr->data + ptr->ls * y + offset;
635
636 for ( j = 0; j < h; j++) {
637 int bytes = blt_bytes;
638 Byte lsave = *data, rsave = data[blt_bytes - 1], *p = data;
639 Byte * src = pat_ptr + ((y + j) % FILL_PATTERN_SIZE) * ptr->step;
640 while ( bytes > 0 ) {
641 ptr->proc( src, p, ( bytes > blt_step ) ? blt_step : bytes );
642 bytes -= blt_step;
643 p += blt_step;
644 }
645 if ( lmask ) *data = (lsave & lmask) | (*data & ~lmask);
646 if ( rmask ) data[blt_bytes-1] = (rsave & rmask) | (data[blt_bytes-1] & ~rmask);
647 data += ptr->ls;
648 }
649 return true;
650 }
651
652 static Bool
653 img_bar_alpha( Handle dest, int x, int y, int w, int h, PImgPaintContext ctx);
654
655 Bool
img_bar(Handle dest,int x,int y,int w,int h,PImgPaintContext ctx)656 img_bar( Handle dest, int x, int y, int w, int h, PImgPaintContext ctx)
657 {
658 PImage i = (PImage) dest;
659 int pixSize = (i->type & imBPP) / 8;
660 Byte blt_buffer[BLT_BUFSIZE];
661 int j, k, blt_bytes, blt_step;
662 Bool solid;
663
664 /* check boundaries */
665 if ( ctx->rop == ropNoOper) return true;
666
667 if ( x < 0 ) {
668 w += x;
669 x = 0;
670 }
671 if ( y < 0 ) {
672 h += y;
673 y = 0;
674 }
675 if ( x + w > i->w ) w = i->w - x;
676 if ( y + h > i->h ) h = i->h - y;
677 if ( w <= 0 || h <= 0 ) return true;
678
679 while ( ctx->patternOffset.x < 0 ) ctx-> patternOffset.x += FILL_PATTERN_SIZE;
680 while ( ctx->patternOffset.y < 0 ) ctx-> patternOffset.y += FILL_PATTERN_SIZE;
681
682
683 if ( ctx-> rop & ropConstantAlpha )
684 return img_bar_alpha(dest, x, y, w, h, ctx);
685
686 if ( memcmp( ctx->pattern, fillPatterns[fpSolid], sizeof(FillPattern)) == 0) {
687 /* do nothing */
688 } else if (memcmp( ctx->pattern, fillPatterns[fpEmpty], sizeof(FillPattern)) == 0) {
689 if ( ctx->transparent ) return true;
690 /* still do nothing */
691 } else if ( ctx->transparent ) {
692 /* transparent stippling: if rop is simple enough, adjust parameters to
693 execute it as another rop with adjusted input. Otherwise make it into
694 two-step operation, such as CopyPut stippling is famously executed by
695 And and Xor rops */
696 #define FILL(who,val) memset( ctx->who, val, MAX_SIZEOF_PIXEL)
697 switch ( ctx-> rop ) {
698 case ropBlackness:
699 FILL(color,0x00);
700 FILL(backColor,0xff);
701 ctx->rop = ropAndPut;
702 break;
703 case ropWhiteness:
704 FILL(color,0xff);
705 FILL(backColor,0x00);
706 ctx->rop = ropOrPut;
707 break;
708 case ropInvert:
709 FILL(color,0xff);
710 FILL(backColor,0x00);
711 ctx->rop = ropXorPut;
712 break;
713 case ropNotSrcAnd:
714 case ropXorPut:
715 FILL(backColor,0x00);
716 break;
717 default: {
718 static int rop1[16] = {
719 ropNotOr, ropXorPut, ropInvert, ropNotOr,
720 ropNotSrcAnd, ropXorPut, ropNotSrcAnd, ropXorPut,
721 ropNotOr, ropNotOr, ropNotSrcAnd, ropInvert,
722 ropInvert, ropXorPut, ropNotSrcAnd, ropInvert
723 };
724 static int rop2[16] = {
725 ropNotDestAnd, ropNoOper, ropNotDestAnd, ropInvert,
726 ropNotSrcOr, ropNotXor, ropAndPut, ropAndPut,
727 ropXorPut, ropNotAnd, ropNoOper, ropNotAnd,
728 ropXorPut, ropNotSrcOr, ropNotXor, ropInvert
729 };
730 int rop = ctx->rop;
731 FILL(backColor,0x00);
732 ctx->rop = rop1[rop];
733 ctx->transparent = false;
734 img_bar( dest, x, y, w, h, ctx);
735 FILL(backColor,0xff);
736 ctx->rop = rop2[rop];
737 break;
738 }}
739 }
740
741 /* render a 8x8xPIXEL matrix with pattern, then horizontally
742 replicate it over blt_buffer as much as possible, to streamline
743 byte operations */
744 switch ( i->type & imBPP) {
745 case imbpp1:
746 blt_bytes = (( x + w - 1) >> 3) - (x >> 3) + 1;
747 if ( blt_bytes < FILL_PATTERN_SIZE ) blt_bytes = FILL_PATTERN_SIZE;
748 break;
749 case imbpp4:
750 blt_bytes = (( x + w - 1) >> 1) - (x >> 1) + 1;
751 if ( blt_bytes < FILL_PATTERN_SIZE / 2 ) blt_bytes = FILL_PATTERN_SIZE / 2;
752 break;
753 default:
754 blt_bytes = w * pixSize;
755 if ( blt_bytes < FILL_PATTERN_SIZE * pixSize ) blt_bytes = FILL_PATTERN_SIZE * pixSize;
756 }
757 blt_bytes *= FILL_PATTERN_SIZE;
758 blt_step = ((blt_bytes > BLT_BUFSIZE) ? BLT_BUFSIZE : blt_bytes) / FILL_PATTERN_SIZE;
759 if ( pixSize > 1 )
760 blt_step = (blt_step / pixSize / FILL_PATTERN_SIZE) * pixSize * FILL_PATTERN_SIZE;
761 solid = (memcmp( ctx->pattern, fillPatterns[fpSolid], sizeof(FillPattern)) == 0);
762 for ( j = 0; j < FILL_PATTERN_SIZE; j++) {
763 unsigned int pat, strip_size;
764 Byte matrix[MAX_SIZEOF_PIXEL * FILL_PATTERN_SIZE], *buffer;
765 if ( solid ) {
766 pat = 0xff;
767 } else {
768 pat = (unsigned int) ctx->pattern[(j + ctx->patternOffset. y) % FILL_PATTERN_SIZE];
769 pat = (((pat << 8) | pat) >> ((ctx->patternOffset. x + 8 - (x % 8)) % FILL_PATTERN_SIZE)) & 0xff;
770 }
771 buffer = blt_buffer + j * blt_step;
772 switch ( i->type & imBPP) {
773 case 1:
774 strip_size = 1;
775 matrix[0] = ctx->color[0] ?
776 (ctx->backColor[0] ? 0xff : pat) :
777 (ctx->backColor[0] ? ~pat : 0);
778 memset( buffer, matrix[0], blt_step);
779 break;
780 case 4:
781 strip_size = FILL_PATTERN_SIZE / 2;
782 for ( k = 0; k < FILL_PATTERN_SIZE; ) {
783 Byte c1 = *((pat & (0x80 >> k++)) ? ctx->color : ctx->backColor);
784 Byte c2 = *((pat & (0x80 >> k++)) ? ctx->color : ctx->backColor);
785 matrix[ (k / 2) - 1] = (c1 << 4) | (c2 & 0xf);
786 }
787 break;
788 case 8:
789 strip_size = FILL_PATTERN_SIZE;
790 for ( k = 0; k < FILL_PATTERN_SIZE; k++)
791 matrix[k] = *((pat & (0x80 >> k)) ? ctx->color : ctx->backColor);
792 break;
793 default:
794 strip_size = FILL_PATTERN_SIZE * pixSize;
795 for ( k = 0; k < FILL_PATTERN_SIZE; k++) {
796 Byte * color = (pat & (0x80 >> k)) ? ctx->color : ctx->backColor;
797 memcpy( matrix + k * pixSize, color, pixSize);
798 }
799 }
800 if ( strip_size > 1 ) {
801 Byte * buf = buffer;
802 for ( k = 0; k < blt_step / strip_size; k++, buf += strip_size)
803 memcpy( buf, matrix, strip_size);
804 if ( blt_step % strip_size != 0)
805 memcpy( buf, matrix, blt_step % strip_size);
806 }
807 }
808 /*
809 printf("pxs:%d step:%d\n", pixSize, blt_step);
810 for ( j = 0; j < 8; j++) {
811 printf("%d: ", j);
812 for ( k = 0; k < blt_step; k++) {
813 printf("%02x", blt_buffer[ j * blt_step + k]);
814 }
815 printf("\n");
816 } */
817 {
818 ImgBarCallbackRec rec = {
819 /* bpp */ (i->type & imBPP),
820 /* count */ (i->type & imBPP) / 8,
821 /* ls */ i->lineSize,
822 /* step */ blt_step,
823 /* pat_x_offset */ x,
824 /* solid */ solid,
825 /* data */ i->data,
826 /* buf */ blt_buffer,
827 /* proc */ find_blt_proc(ctx->rop),
828 };
829 img_region_foreach( ctx->region,
830 x, y, w, h,
831 (RegionCallbackFunc*)img_bar_single, &rec
832 );
833 }
834
835 return true;
836 }
837
838 /* reformat color values to imByte/imRGB */
839 static Bool
resample_colors(Handle dest,int bpp,PImgPaintContext ctx)840 resample_colors( Handle dest, int bpp, PImgPaintContext ctx)
841 {
842 RGBColor fg, bg;
843 int type = PImage(dest)->type;
844 int rbpp = type & imBPP;
845 if (rbpp <= 8 ) {
846 fg = PImage(dest)->palette[*(ctx->color)];
847 bg = PImage(dest)->palette[*(ctx->backColor)];
848 } else switch ( type ) {
849 case imRGB:
850 fg.b = ctx->color[0];
851 fg.g = ctx->color[1];
852 fg.r = ctx->color[2];
853 bg.b = ctx->backColor[0];
854 bg.g = ctx->backColor[1];
855 bg.r = ctx->backColor[2];
856 break;
857 case imShort:
858 fg.b = fg.g = fg.r = *((Short*)(ctx->color));
859 bg.b = bg.g = bg.r = *((Short*)(ctx->backColor));
860 break;
861 case imLong:
862 fg.b = fg.g = fg.r = *((Long*)(ctx->color));
863 bg.b = bg.g = bg.r = *((Long*)(ctx->backColor));
864 break;
865 case imFloat: case imComplex: case imTrigComplex:
866 fg.b = fg.g = fg.r = *((float*)(ctx->color));
867 bg.b = bg.g = bg.r = *((float*)(ctx->backColor));
868 break;
869 case imDouble: case imDComplex: case imTrigDComplex:
870 fg.b = fg.g = fg.r = *((double*)(ctx->color));
871 bg.b = bg.g = bg.r = *((double*)(ctx->backColor));
872 break;
873 default:
874 return false;
875 }
876 if ( bpp == imByte ) {
877 *(ctx->color) = (fg.r + fg.g + fg.b) / 3;
878 *(ctx->backColor) = (bg.r + bg.g + bg.b) / 3;
879 } else {
880 ctx->color[0] = fg.b;
881 ctx->color[1] = fg.g;
882 ctx->color[2] = fg.r;
883 ctx->backColor[0] = bg.b;
884 ctx->backColor[1] = bg.g;
885 ctx->backColor[2] = bg.r;
886 }
887 return true;
888 }
889
890 #define VISIBILITY_NONE 0
891 #define VISIBILITY_CLIPPED 1
892 #define VISIBILITY_UNSURE 2
893 #define VISIBILITY_CLEAR 3
894
895 static void
fill_alpha_buf(Byte * dst,Byte * src,int width,int bpp)896 fill_alpha_buf( Byte * dst, Byte * src, int width, int bpp)
897 {
898 register int x = width;
899 if ( bpp == 3 ) {
900 while (x-- > 0) {
901 register Byte a = *src++;
902 *dst++ = a;
903 *dst++ = a;
904 *dst++ = a;
905 }
906 } else
907 memcpy( dst, src, width * bpp);
908 }
909
910 #define dBLEND_FUNC(name) void name( \
911 const Byte * src, const Byte src_inc, \
912 const Byte * src_a, const Byte src_a_inc,\
913 Byte * dst, \
914 const Byte * dst_a, const Byte dst_a_inc,\
915 int bytes)
916
917 #define dVAL(x) register int32_t s = x
918 #define STORE \
919 *dst++ = ( s > 255 ) ? 255 : s;\
920 src += src_inc;\
921 src_a += src_a_inc;\
922 dst_a += dst_a_inc
923 #define BLEND_LOOP while(bytes-- > 0)
924
925 #define UP(x) ((int32_t)(x) << 8 )
926 #define DOWN(expr) (((expr) + 127) >> 8)
927
928 #define dBLEND_FUNCx(name,expr) \
929 static dBLEND_FUNC(name) \
930 { \
931 BLEND_LOOP {\
932 dVAL(DOWN(expr));\
933 STORE;\
934 }\
935 }
936
937 typedef dBLEND_FUNC(BlendFunc);
938
939 #define S (*src)
940 #define D (*dst)
941 #define SA (*src_a)
942 #define DA (*dst_a)
943 #define INVSA (255 - *src_a)
944 #define INVDA (255 - *dst_a)
945
946 /* sss */
dBLEND_FUNC(blend_src_copy)947 static dBLEND_FUNC(blend_src_copy)
948 {
949 if ( src_inc )
950 memcpy( dst, src, bytes);
951 else
952 memset( dst, *src, bytes);
953 }
954
955 /* ddd */
dBLEND_FUNC(blend_dst_copy)956 static dBLEND_FUNC(blend_dst_copy)
957 {
958 }
959
960 /* 0 */
dBLEND_FUNC(blend_clear)961 static dBLEND_FUNC(blend_clear)
962 {
963 memset( dst, 0, bytes);
964 }
965
966 dBLEND_FUNCx(blend_src_over, UP(S) + UP(D) * INVSA / 255)
967 dBLEND_FUNCx(blend_xor, (UP(S) * INVDA + UP(D) * INVSA) / 255)
968 dBLEND_FUNCx(blend_dst_over, UP(D) + UP(S) * INVDA / 255)
969 dBLEND_FUNCx(blend_src_in, UP(S) * DA / 255)
970 dBLEND_FUNCx(blend_dst_in, UP(D) * SA / 255)
971 dBLEND_FUNCx(blend_src_out, UP(S) * INVDA / 255)
972 dBLEND_FUNCx(blend_dst_out, UP(D) * INVSA / 255)
973 dBLEND_FUNCx(blend_src_atop, (UP(S) * DA + UP(D) * INVSA) / 255)
974 dBLEND_FUNCx(blend_dst_atop, (UP(D) * SA + UP(S) * INVDA) / 255)
975
976 /* sss + ddd */
dBLEND_FUNC(blend_add)977 static dBLEND_FUNC(blend_add)
978 {
979 BLEND_LOOP {
980 dVAL(S + D);
981 STORE;
982 }
983 }
984
985 /* SEPARABLE(S * D) */
986 dBLEND_FUNCx(blend_multiply, (UP(D) * (S + INVSA) + UP(S) * INVDA) / 255)
987
988 /* SEPARABLE(D * SA + S * DA - S * D) */
989 dBLEND_FUNCx(blend_screen, (UP(S) * 255 + UP(D) * (255 - S)) / 255)
990
991 #define SEPARABLE(f) (UP(S) * INVDA + UP(D) * INVSA + (f))/255
992 dBLEND_FUNCx(blend_overlay, SEPARABLE(
993 (2 * D < DA) ?
994 (2 * UP(D) * S) :
995 (UP(SA) * DA - UP(2) * (DA - D) * (SA - S))
996 ))
997
dBLEND_FUNC(blend_darken)998 static dBLEND_FUNC(blend_darken)
999 {
1000 BLEND_LOOP {
1001 register int32_t ss = UP(S) * DA;
1002 register int32_t dd = UP(D) * SA;
1003 dVAL(DOWN(SEPARABLE((ss > dd) ? dd : ss)));
1004 STORE;
1005 }
1006 }
1007
dBLEND_FUNC(blend_lighten)1008 static dBLEND_FUNC(blend_lighten)
1009 {
1010 BLEND_LOOP {
1011 register int32_t ss = UP(S) * DA;
1012 register int32_t dd = UP(D) * SA;
1013 dVAL(DOWN(SEPARABLE((ss > dd) ? ss : dd)));
1014 STORE;
1015 }
1016 }
1017
dBLEND_FUNC(blend_color_dodge)1018 static dBLEND_FUNC(blend_color_dodge)
1019 {
1020 BLEND_LOOP {
1021 register int32_t s;
1022 if ( S >= SA ) {
1023 s = D ? UP(SA) * DA : 0;
1024 } else {
1025 register int32_t dodge = D * SA / (SA - S);
1026 s = UP(SA) * ((DA < dodge) ? DA : dodge);
1027 }
1028 s = DOWN(SEPARABLE(s));
1029 STORE;
1030 }
1031 }
1032
dBLEND_FUNC(blend_color_burn)1033 static dBLEND_FUNC(blend_color_burn)
1034 {
1035 BLEND_LOOP {
1036 register int32_t s;
1037 if ( S == 0 ) {
1038 s = (D < DA) ? 0 : UP(SA) * DA;
1039 } else {
1040 register int32_t burn = (DA - D) * SA / S;
1041 s = (DA < burn) ? 0 : UP(SA) * (DA - burn);
1042 }
1043 s = DOWN(SEPARABLE(s));
1044 STORE;
1045 }
1046 }
1047
1048 dBLEND_FUNCx(blend_hard_light, SEPARABLE(
1049 (2 * S < SA) ?
1050 (2 * UP(D) * S) :
1051 (UP(SA) * DA - UP(2) * (DA - D) * (SA - S))
1052 ))
1053
dBLEND_FUNC(blend_soft_light)1054 static dBLEND_FUNC(blend_soft_light)
1055 {
1056 BLEND_LOOP {
1057 register int32_t s;
1058 if ( 2 * S < SA ) {
1059 s = DA ? D * (UP(SA) - UP(DA - D) * (SA - 2 * S) / DA ) : 0;
1060 } else if (DA == 0) {
1061 s = 0;
1062 } else if (4 * D <= DA) {
1063 s = D * (UP(SA) + (2 * S - SA) * ((UP(16) * D / DA - UP(12)) * D / DA + UP(3)));
1064 } else {
1065 s = 256 * (D * SA + (sqrt(D * DA) - D) * (2 * SA - S));
1066 }
1067 s = DOWN(SEPARABLE(s));
1068 STORE;
1069 }
1070 }
1071
dBLEND_FUNC(blend_difference)1072 static dBLEND_FUNC(blend_difference)
1073 {
1074 BLEND_LOOP {
1075 dVAL(UP(D) * SA - UP(S) * DA);
1076 if ( s < 0 ) s = -s;
1077 s = DOWN(SEPARABLE(s));
1078 STORE;
1079 }
1080 }
1081
1082 dBLEND_FUNCx(blend_exclusion, SEPARABLE( UP(S) * (DA - 2 * D) + UP(D) * SA ))
1083
1084 static BlendFunc* blend_functions[] = {
1085 blend_src_over,
1086 blend_xor,
1087 blend_dst_over,
1088 blend_src_copy,
1089 blend_dst_copy,
1090 blend_clear,
1091 blend_src_in,
1092 blend_dst_in,
1093 blend_src_out,
1094 blend_dst_out,
1095 blend_src_atop,
1096 blend_dst_atop,
1097 blend_add,
1098 blend_multiply,
1099 blend_screen,
1100 blend_dst_copy,
1101 blend_overlay,
1102 blend_darken,
1103 blend_lighten,
1104 blend_color_dodge,
1105 blend_color_burn,
1106 blend_hard_light,
1107 blend_soft_light,
1108 blend_difference,
1109 blend_exclusion
1110 };
1111
1112 static void
find_blend_proc(int rop,BlendFunc ** blend1,BlendFunc ** blend2)1113 find_blend_proc( int rop, BlendFunc ** blend1, BlendFunc ** blend2 )
1114 {
1115 *blend1 = blend_functions[rop];
1116 *blend2 = (rop >= ropMultiply) ? blend_functions[ropScreen] : blend_functions[rop];
1117 }
1118
1119 typedef struct {
1120 PIcon i;
1121 PBitBltProc proc;
1122 BlendFunc *blend1, *blend2;
1123 int bpp, bytes, optimized_stride;
1124 PImgPaintContext ctx;
1125 Byte *color;
1126
1127 Bool use_dst_alpha, is_icon;
1128 Byte src_alpha,dst_alpha;
1129 } ImgHLineRec;
1130
1131 static void
setpixel(ImgHLineRec * rec,int x,int y)1132 setpixel( ImgHLineRec* rec, int x, int y)
1133 {
1134 switch ( rec->bpp ) {
1135 case 1: {
1136 Byte * dst = rec->i->data + rec->i->lineSize * y + x / 8, src = *dst;
1137 Byte shift = 7 - (x & 7);
1138 src = (src >> shift) & 1;
1139 rec->proc( rec->color, &src, 1);
1140 if ( src & 1 )
1141 *dst |= 1 << shift;
1142 else
1143 *dst &= ~(1 << shift);
1144 break;
1145 }
1146 case 4: {
1147 Byte * dst = rec->i->data + rec->i->lineSize * y + x / 2, src = *dst, tmp = *dst;
1148 if ( x & 1 ) {
1149 rec->proc( rec->color, &src, 1);
1150 *dst = (tmp & 0xf0) | (src & 0x0f);
1151 } else {
1152 src >>= 4;
1153 rec->proc( rec->color, &src, 1);
1154 *dst = (tmp & 0x0f) | (src << 4);
1155 }
1156 break;
1157 }
1158 case 8:
1159 if ( rec->proc)
1160 rec->proc( rec->color, rec->i->data + rec->i->lineSize * y + x, 1);
1161 else
1162 rec->blend1(
1163 rec-> color, 0, &rec->src_alpha, 0,
1164 rec->i->data + rec->i->lineSize * y + x,
1165 rec->use_dst_alpha ?
1166 &rec->dst_alpha : (rec->i->mask + rec->i->maskLine * y + x), 0,
1167 1
1168 );
1169 break;
1170 default:
1171 if ( rec->proc)
1172 rec->proc( rec->color, rec->i->data + rec->i->lineSize * y + x * rec->bytes, rec->bytes);
1173 else
1174 rec->blend1(
1175 rec-> color, 0, &rec->src_alpha, 0,
1176 rec->i->data + rec->i->lineSize * y + x * rec->bytes,
1177 rec->use_dst_alpha ?
1178 &rec->dst_alpha : (rec->i->mask + rec->i->maskLine * y + x), 0,
1179 rec->bytes
1180 );
1181 }
1182
1183 if ( rec->blend2 && rec->is_icon ) {
1184 Byte * a = rec->i->mask + rec->i->maskLine * y + x;
1185 rec->blend2( &rec->src_alpha, 0, &rec->src_alpha, 0, (Byte*)a, a, 0, 1);
1186 }
1187 }
1188
1189 static void
hline(ImgHLineRec * rec,int x,int n,int y)1190 hline( ImgHLineRec *rec, int x, int n, int y)
1191 {
1192 switch ( rec->bpp) {
1193 case 8:
1194 case 24: {
1195 /* optimized multipixel set */
1196 int wn;
1197 int w = rec->bytes, stride = rec->optimized_stride;
1198 Byte * dst = rec->i->data + rec->i->lineSize * y + x * w;
1199 Byte * mask = ( rec->blend1 && !rec->use_dst_alpha) ?
1200 (rec->i->mask + rec->i->maskLine * y + x) : NULL;
1201 for ( wn = w * n; wn > 0; wn -= stride, dst += stride) {
1202 int dw = ( wn >= stride ) ? stride : wn;
1203 if ( rec->proc )
1204 rec->proc( rec->color, dst, dw);
1205 else {
1206 Byte mask_buf[MAX_SIZEOF_PIXEL];
1207 if ( mask ) {
1208 int bp = rec->bpp / 8;
1209 int dm = dw / bp;
1210 fill_alpha_buf( mask_buf, mask, dm, bp);
1211 rec->blend2(
1212 &rec->src_alpha, 0,
1213 &rec->src_alpha, 0,
1214 mask, mask, 1, dm);
1215 mask += dm;
1216 }
1217 rec->blend1( rec->color, 1,
1218 &rec->src_alpha, 0,
1219 dst,
1220 mask ? mask_buf : &rec->dst_alpha,
1221 rec->use_dst_alpha ? 0 : 1,
1222 dw);
1223 }
1224 }
1225 return;
1226 }
1227 default: {
1228 int i;
1229 for ( i = 0; i < n; i++, x++) setpixel(rec, x, y);
1230 }}
1231 }
1232
1233 #define HLINE_INIT_OK 0
1234 #define HLINE_INIT_FAIL 1
1235 #define HLINE_INIT_RETRY 2
1236
1237 /* prepare to draw horizontal lines with alpha etc using single solid color */
1238 static int
hline_init(ImgHLineRec * rec,Handle dest,PImgPaintContext ctx,char * method)1239 hline_init( ImgHLineRec * rec, Handle dest, PImgPaintContext ctx, char * method)
1240 {
1241 int i;
1242
1243 /* misc */
1244 rec->ctx = ctx;
1245 rec->i = (PIcon) dest;
1246 rec->bpp = rec->i->type & imBPP;
1247 rec->bytes = rec->bpp / 8;
1248
1249 /* deal with alpha request */
1250 if ( ctx-> rop & ropConstantAlpha ) {
1251 int j, rop = ctx->rop;
1252 /* differentiate between per-pixel alpha and a global value */
1253 if ( ctx->rop & ropSrcAlpha )
1254 rec->src_alpha = (rop >> ropSrcAlphaShift) & 0xff;
1255 else
1256 rec->src_alpha = 0xff;
1257 if ( rop & ropDstAlpha ) {
1258 rec->use_dst_alpha = true;
1259 rec->dst_alpha = (rop >> ropDstAlphaShift) & 0xff;
1260 }
1261 rop &= ropPorterDuffMask;
1262 if ( rop > ropMaxPDFunc || rop < 0 ) return false;
1263 find_blend_proc( rop, &rec->blend1, &rec->blend2 );
1264 rec->is_icon = kind_of( dest, CIcon );
1265
1266 /* align types and geometry - can only operate over imByte and imRGB */
1267 int bpp = ( PImage(dest)->type & imGrayScale) ? imByte : imRGB;
1268 if (PImage(dest)-> type != bpp || ( rec->is_icon && PIcon(dest)->maskType != imbpp8 )) {
1269 int type = PImage(dest)->type;
1270 int mask = rec->is_icon ? PIcon(dest)->maskType : 0;
1271
1272 if ( type != bpp ) {
1273 resample_colors( dest, bpp, ctx );
1274 CIcon(dest)-> set_type( dest, bpp );
1275 if ( PImage(dest)->type != bpp)
1276 return HLINE_INIT_FAIL;
1277 }
1278 if ( rec->is_icon && mask != imbpp8 ) {
1279 CIcon(dest)-> set_maskType( dest, imbpp8 );
1280 if ( PIcon(dest)->maskType != imbpp8)
1281 return HLINE_INIT_FAIL;
1282 }
1283 return HLINE_INIT_RETRY;
1284 }
1285
1286 if ( rec->is_icon ) {
1287 if ( PIcon(dest)-> maskType != imbpp8)
1288 croak("panic: assert failed for %s: %s", method, "dst mask type");
1289 rec->use_dst_alpha = false;
1290 } else if ( !rec->use_dst_alpha ) {
1291 rec->use_dst_alpha = true;
1292 rec->dst_alpha = 0xff;
1293 }
1294 rec->proc = NULL;
1295
1296 /* premultiply colors */
1297 for ( j = 0; j < bpp / 8; j++) {
1298 ctx->color[j] = (float)(ctx->color[j] * rec->src_alpha) / 255.0 + .5;
1299 ctx->backColor[j] = (float)(ctx->backColor[j] * rec->src_alpha) / 255.0 + .5;
1300 }
1301 } else {
1302 rec->blend1 = rec->blend2 = NULL;
1303 rec->proc = find_blt_proc(ctx->rop);
1304 }
1305
1306 rec->color = ctx->color;
1307
1308 /* colors; optimize 8 and 24 pixels for horizontal line memcpy */
1309 switch ( rec->bpp ) {
1310 case 8:
1311 memset( ctx->color + 1, ctx->color[0], MAX_SIZEOF_PIXEL - 1);
1312 rec->optimized_stride = MAX_SIZEOF_PIXEL;
1313 break;
1314 case 24:
1315 for ( i = 1; i < MAX_SIZEOF_PIXEL / 3; i++)
1316 memcpy( ctx->color + i * 3, ctx->color, 3);
1317 rec->optimized_stride = (MAX_SIZEOF_PIXEL / 3) * 3;
1318 }
1319
1320 return HLINE_INIT_OK;
1321 }
1322
1323 typedef struct {
1324 ImgHLineRec h;
1325 Bool solid, segment_is_fg, skip_pixel;
1326 int current_segment, segment_offset, n_segments;
1327 } ImgSegmentedLineRec;
1328
1329 static void
segmented_hline(ImgSegmentedLineRec * rec,int x1,int x2,int y,int visibility)1330 segmented_hline( ImgSegmentedLineRec *rec, int x1, int x2, int y, int visibility)
1331 {
1332 int n = abs(x2 - x1) + 1;
1333 int dx = (x1 < x2) ? 1 : -1;
1334 /* printf("(%d,%d)->%d %d\n", x1, y, x2,visibility); */
1335 if ( rec->skip_pixel ) {
1336 rec->skip_pixel = false;
1337 if ( n-- == 1 ) return;
1338 x1 += dx;
1339 }
1340 if ( rec->solid) {
1341 if ( visibility == VISIBILITY_CLEAR ) {
1342 if ( x2 < x1 )
1343 hline( &rec->h, x2, x1 - x2 + 1, y);
1344 else
1345 hline( &rec->h, x1, x2 - x1 + 1, y);
1346 } else {
1347 /* VISIBILITY_NONE is not reaching here */
1348 int i;
1349 for ( i = 0; i < n; i++, x1 += dx)
1350 if ( img_point_in_region(x1, y, rec->h.ctx->region))
1351 setpixel(&rec->h, x1, y);
1352 }
1353 } else {
1354 int i;
1355 for ( i = 0; i < n; i++, x1 += dx) {
1356 /* calculate color */
1357 rec->h.color = rec->segment_is_fg ?
1358 rec->h.ctx->color :
1359 ( rec->h.ctx->transparent ? NULL : rec->h.ctx->backColor )
1360 ;
1361 if ( ++rec->segment_offset >= rec->h.ctx->linePattern[rec->current_segment]) {
1362 rec->segment_offset = 0;
1363 if ( ++rec->current_segment >= rec->n_segments ) {
1364 rec->current_segment = 0;
1365 rec->segment_is_fg = true;
1366 } else {
1367 rec->segment_is_fg = !rec->segment_is_fg;
1368 }
1369 }
1370
1371 /* put pixel */
1372 if (
1373 (visibility > VISIBILITY_NONE) &&
1374 (rec->h.color != NULL) &&
1375 (
1376 (visibility == VISIBILITY_CLEAR) ||
1377 img_point_in_region(x1, y, rec->h.ctx->region)
1378 )
1379 )
1380 setpixel(&rec->h, x1, y);
1381 }
1382 }
1383 }
1384
1385 Bool
img_polyline(Handle dest,int n_points,Point * points,PImgPaintContext ctx)1386 img_polyline( Handle dest, int n_points, Point * points, PImgPaintContext ctx)
1387 {
1388 PIcon i = (PIcon) dest;
1389 int j;
1390 int type = i->type;
1391 int maskType = kind_of(dest, CIcon) ? i->maskType : 0;
1392 ImgSegmentedLineRec rec;
1393 BoxRegionRec dummy_region;
1394 Box dummy_region_box, *pbox;
1395 Point* pp;
1396 Rect enclosure;
1397 Bool closed;
1398
1399 if ( ctx->rop == ropNoOper || n_points <= 1) return true;
1400
1401 switch ( hline_init( &rec.h, dest, ctx, "img_polyline")) {
1402 case HLINE_INIT_RETRY: {
1403 Bool ok;
1404 ok = img_polyline( dest, n_points, points, ctx);
1405 if ( i-> options. optPreserveType ) {
1406 if ( type != i->type )
1407 CImage(dest)-> set_type( dest, type );
1408 if ( maskType != 0 && maskType != i->maskType )
1409 CIcon(dest)-> set_maskType( dest, maskType );
1410 }
1411 return ok;
1412 }
1413 case HLINE_INIT_FAIL:
1414 return false;
1415 }
1416
1417 rec.solid = (strcmp((const char*)ctx->linePattern, (const char*)lpSolid) == 0);
1418 if ( *(ctx->linePattern) == 0) {
1419 if ( ctx->transparent ) return true;
1420 rec.solid = true;
1421 memcpy( ctx->color, ctx->backColor, MAX_SIZEOF_PIXEL);
1422 }
1423
1424 if ( rec.solid )
1425 rec.h.color = ctx->color;
1426
1427 /* patterns */
1428 rec.n_segments = strlen(( const char*) ctx->linePattern );
1429 rec.current_segment = 0;
1430 rec.segment_offset = 0;
1431 rec.segment_is_fg = 1;
1432 if ( ctx->region == NULL ) {
1433 dummy_region.n_boxes = 1;
1434 dummy_region.boxes = &dummy_region_box;
1435 dummy_region_box.x = 0;
1436 dummy_region_box.y = 0;
1437 dummy_region_box.width = i->w;
1438 dummy_region_box.height = i->h;
1439 ctx->region = &dummy_region;
1440 }
1441 enclosure.left = ctx->region->boxes[0].x;
1442 enclosure.bottom = ctx->region->boxes[0].y;
1443 enclosure.right = ctx->region->boxes[0].x + ctx->region->boxes[0].width - 1;
1444 enclosure.top = ctx->region->boxes[0].y + ctx->region->boxes[0].height - 1;
1445 for ( j = 1, pbox = ctx->region->boxes + 1; j < ctx->region->n_boxes; j++, pbox++) {
1446 int right = pbox->x + pbox->width - 1;
1447 int top = pbox->y + pbox->height - 1;
1448 if ( enclosure.left > pbox->x ) enclosure.left = pbox->x;
1449 if ( enclosure.bottom > pbox->y ) enclosure.bottom = pbox->y;
1450 if ( enclosure.right < right ) enclosure.right = right;
1451 if ( enclosure.top < top ) enclosure.top = top;
1452 }
1453
1454 closed = points[0].x == points[n_points-1].x && points[0].y == points[n_points-1].y && n_points > 2;
1455 for ( j = 0, pp = points; j < n_points - 1; j++, pp++) {
1456 /* calculate clipping: -1 invisible, 0 definitely clipped, 1 possibly clipped */
1457 int visibility;
1458 int curr_maj, curr_min, to_maj, delta_maj, delta_min;
1459 int delta_y, delta_x;
1460 int dir = 0, d, d_inc1, d_inc2;
1461 int inc_maj, inc_min;
1462 int x, y, acc_x = 0, acc_y = INT_MIN, ox;
1463 Point a, b;
1464
1465 /* printf("* p(%d): (%d,%d)-(%d,%d)\n", j, pp[0].x, pp[0].y, pp[1].x, pp[1].y); */
1466 a.x = pp[0].x + ctx->translate.x;
1467 a.y = pp[0].y + ctx->translate.y;
1468 b.x = pp[1].x + ctx->translate.x;
1469 b.y = pp[1].y + ctx->translate.y;
1470 if (a.x == b.x && a.y == b.y && n_points > 2) continue;
1471
1472 if (
1473 ( a.x < enclosure.left && b.x < enclosure.left) ||
1474 ( a.x > enclosure.right && b.x > enclosure.right) ||
1475 ( a.y < enclosure.bottom && b.y < enclosure.bottom) ||
1476 ( a.y > enclosure.top && b.y > enclosure.top)
1477 ) {
1478 visibility = VISIBILITY_NONE;
1479 if ( rec.solid ) continue;
1480 } else if (
1481 a.x >= enclosure.left && b.x >= enclosure.left &&
1482 a.x <= enclosure.right && b.x <= enclosure.right &&
1483 a.y >= enclosure.bottom && b.y >= enclosure.bottom &&
1484 a.y <= enclosure.top && b.y <= enclosure.top
1485 ) {
1486 if ( ctx->region->n_boxes > 1) {
1487 int i,n;
1488 Box *e;
1489 visibility = VISIBILITY_CLIPPED;
1490 for (
1491 i = 0, e = ctx->region->boxes, n = ctx->region->n_boxes;
1492 i < n; i++, e++
1493 ) {
1494 int r = e->x + e->width;
1495 int t = e->y + e->height;
1496 if (
1497 a.x >= e->x && a.y >= e->y && a.x < r && a.y < t &&
1498 b.x >= e->x && b.y >= e->y && b.x < r && b.y < t
1499 ) {
1500 visibility = VISIBILITY_CLEAR;
1501 break;
1502 }
1503 }
1504 } else {
1505 visibility = VISIBILITY_CLEAR;
1506 }
1507 } else {
1508 visibility = VISIBILITY_CLIPPED;
1509 }
1510
1511 /*
1512 Bresenham line plotting, (c) LiloHuang @ 2008, kenwu@cpan.org
1513 http://cpansearch.perl.org/src/KENWU/Algorithm-Line-Bresenham-C-0.1/Line/Bresenham/C/C.xs
1514 */
1515 rec.skip_pixel = closed || (j > 0);
1516 delta_y = b.y - a.y;
1517 delta_x = b.x - a.x;
1518 if (abs(delta_y) > abs(delta_x)) dir = 1;
1519
1520 if (dir) {
1521 curr_maj = a.y;
1522 curr_min = a.x;
1523 to_maj = b.y;
1524 delta_maj = delta_y;
1525 delta_min = delta_x;
1526 } else {
1527 curr_maj = a.x;
1528 curr_min = a.y;
1529 to_maj = b.x;
1530 delta_maj = delta_x;
1531 delta_min = delta_y;
1532 }
1533
1534 if (delta_maj != 0)
1535 inc_maj = (abs(delta_maj)==delta_maj ? 1 : -1);
1536 else
1537 inc_maj = 0;
1538
1539 if (delta_min != 0)
1540 inc_min = (abs(delta_min)==delta_min ? 1 : -1);
1541 else
1542 inc_min = 0;
1543
1544 delta_maj = abs(delta_maj);
1545 delta_min = abs(delta_min);
1546
1547 d = (delta_min << 1) - delta_maj;
1548 d_inc1 = (delta_min << 1);
1549 d_inc2 = ((delta_min - delta_maj) << 1);
1550
1551 x = INT_MIN;
1552 while(1) {
1553 ox = x;
1554 if (dir) {
1555 x = curr_min;
1556 y = curr_maj;
1557 } else {
1558 x = curr_maj;
1559 y = curr_min;
1560 }
1561 if ( acc_y != y ) {
1562 if ( acc_y > INT_MIN)
1563 segmented_hline( &rec, acc_x, ox, acc_y, visibility);
1564 acc_x = x;
1565 acc_y = y;
1566 }
1567
1568 if (curr_maj == to_maj) break;
1569 curr_maj += inc_maj;
1570 if (d < 0) {
1571 d += d_inc1;
1572 } else {
1573 d += d_inc2;
1574 curr_min += inc_min;
1575 }
1576 }
1577 if ( acc_y > INT_MIN)
1578 segmented_hline( &rec, acc_x, x, acc_y, visibility);
1579 }
1580 return true;
1581 }
1582
1583 typedef struct {
1584 int dX;
1585 int dY;
1586 int bpp;
1587 int sls;
1588 int dls;
1589 int mls;
1590 int als;
1591 Byte * src;
1592 Byte * dst;
1593 Byte * srcMask;
1594 Byte * dstMask;
1595 Bool use_src_alpha;
1596 Bool use_dst_alpha;
1597 Byte src_alpha_mul;
1598 Byte dst_alpha_mul;
1599 Byte * pmsbuf;
1600 Byte * asbuf;
1601 Byte * adbuf;
1602 BlendFunc * blend1, * blend2;
1603 } ImgPutAlphaCallbackRec;
1604
1605 static void
multiply(Byte * src,Byte * alpha,int alpha_step,Byte * dst,int bytes)1606 multiply( Byte * src, Byte * alpha, int alpha_step, Byte * dst, int bytes)
1607 {
1608 while (bytes--) {
1609 *(dst++) = *(src++) * *alpha / 255.0 + .5;
1610 alpha += alpha_step;
1611 }
1612 }
1613
1614 static Bool
img_put_alpha_single(int x,int y,int w,int h,ImgPutAlphaCallbackRec * ptr)1615 img_put_alpha_single( int x, int y, int w, int h, ImgPutAlphaCallbackRec * ptr)
1616 {
1617 int i;
1618 const int bpp = ptr->bpp;
1619 int bytes = w * bpp;
1620 const int sls = ptr->sls;
1621 const int dls = ptr->dls;
1622 const int mls = ptr->mls;
1623 const int als = ptr->als;
1624 const Byte * s = ptr->src + (ptr->dY + y) * ptr->sls + (ptr->dX + x) * bpp;
1625 const Byte * d = ptr->dst + y * ptr->dls + x * bpp;
1626 const Byte * m = ( mls > 0) ? ptr->srcMask + (ptr->dY + y) * mls + (ptr->dX + x) : NULL;
1627 const Byte * a = ( als > 0) ? ptr->dstMask + y * als + x : NULL;
1628 #ifdef HAVE_OPENMP
1629 #pragma omp parallel for
1630 #endif
1631 for ( i = 0; i < h; i++) {
1632 Byte *asbuf_ptr, *adbuf_ptr, *s_ptr, *m_ptr, *d_ptr, *a_ptr;
1633
1634 s_ptr = (Byte*)s + sls * i;
1635 d_ptr = (Byte*)d + dls * i;
1636 m_ptr = m ? (Byte*)m + mls * i : NULL;
1637 a_ptr = a ? (Byte*)a + als * i : NULL;
1638
1639 if ( !ptr->use_src_alpha ) {
1640 asbuf_ptr = ptr->asbuf + bytes * OMP_THREAD_NUM;
1641 fill_alpha_buf( asbuf_ptr, m_ptr, w, bpp);
1642 if ( ptr-> src_alpha_mul < 255 )
1643 multiply( asbuf_ptr, &ptr->src_alpha_mul, 0, asbuf_ptr, bytes);
1644 } else
1645 asbuf_ptr = ptr->asbuf;
1646
1647 if ( !ptr->use_dst_alpha ) {
1648 adbuf_ptr = ptr->adbuf + bytes * OMP_THREAD_NUM;
1649 fill_alpha_buf( adbuf_ptr, a_ptr, w, bpp);
1650 if ( ptr-> dst_alpha_mul < 255 )
1651 multiply( adbuf_ptr, &ptr->dst_alpha_mul, 0, adbuf_ptr, bytes);
1652 } else
1653 adbuf_ptr = ptr->adbuf;
1654
1655 if ( ptr-> pmsbuf ) {
1656 Byte *pmsbuf = ptr-> pmsbuf + bytes * OMP_THREAD_NUM;
1657 multiply( s_ptr, asbuf_ptr, ptr->use_src_alpha ? 0 : 1, pmsbuf, bytes);
1658 s_ptr = pmsbuf;
1659 }
1660 ptr->blend1(
1661 s_ptr, 1,
1662 asbuf_ptr, ptr->use_src_alpha ? 0 : 1,
1663 d_ptr,
1664 adbuf_ptr, ptr->use_dst_alpha ? 0 : 1,
1665 bytes);
1666 if (a == NULL)
1667 continue;
1668
1669 #define BLEND_ALPHA(src,step)\
1670 ptr->blend2(\
1671 src,step,\
1672 src,step,\
1673 (Byte*)a_ptr,\
1674 a_ptr, ptr->use_dst_alpha ? 0 : 1,\
1675 w)
1676
1677 if ( ptr->dst_alpha_mul < 255 )
1678 multiply( a_ptr, &ptr->dst_alpha_mul, 0, a_ptr, w);
1679
1680 if ( ptr-> src_alpha_mul < 255 ) {
1681 if ( bpp == 3 ) /* reuse the old values from multiply() otherwise */
1682 multiply( m_ptr, &ptr->src_alpha_mul, 0, asbuf_ptr, w);
1683 BLEND_ALPHA(asbuf_ptr,1);
1684 } else if ( ptr->use_src_alpha )
1685 BLEND_ALPHA(ptr->asbuf,0);
1686 else
1687 BLEND_ALPHA(m_ptr,1);
1688 #undef BLEND2
1689 }
1690 return true;
1691 }
1692
1693 /*
1694 This is basically a lightweight pixman_image_composite() .
1695 Converts images to either 8 or 24 bits before processing
1696 */
1697 static Bool
img_put_alpha(Handle dest,Handle src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH,int rop,PBoxRegionRec region)1698 img_put_alpha( Handle dest, Handle src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH, int rop, PBoxRegionRec region)
1699 {
1700 int bpp, bytes, mls, als, xrop;
1701 unsigned int src_alpha = 0, dst_alpha = 0;
1702 Bool use_src_alpha = false, use_dst_alpha = false, use_pms = false;
1703 Byte *asbuf, *adbuf, *pmsbuf = NULL, src_alpha_mul = 255, dst_alpha_mul = 255;
1704
1705 xrop = rop;
1706
1707 /* differentiate between per-pixel alpha and a global value */
1708 if ( rop & ropSrcAlpha ) {
1709 use_src_alpha = true;
1710 src_alpha = (rop >> ropSrcAlphaShift) & 0xff;
1711 }
1712 if ( rop & ropDstAlpha ) {
1713 use_dst_alpha = true;
1714 dst_alpha = (rop >> ropDstAlphaShift) & 0xff;
1715 }
1716 if ( rop & ropPremultiply )
1717 use_pms = true;
1718 rop &= ropPorterDuffMask;
1719 if ( rop > ropMaxPDFunc || rop < 0 ) return false;
1720
1721 /* align types and geometry - can only operate over imByte and imRGB */
1722 bpp = (( PImage(src)->type & imGrayScale) && ( PImage(dest)->type & imGrayScale)) ? imByte : imRGB;
1723
1724 /* adjust rectangles */
1725 if ( dstX < 0 || dstY < 0 || dstX + dstW >= PImage(dest)-> w || dstY + dstH >= PImage(dest)-> h) {
1726 if ( dstX < 0) {
1727 dstW += dstX;
1728 srcX -= dstX;
1729 dstX = 0;
1730 }
1731 if ( dstY < 0) {
1732 dstH += dstY;
1733 srcY -= dstY;
1734 dstY = 0;
1735 }
1736 if ( dstX + dstW > PImage(dest)-> w)
1737 dstW = PImage(dest)-> w - dstX;
1738 if ( dstY + dstH > PImage(dest)-> h)
1739 dstH = PImage(dest)-> h - dstY;
1740 }
1741 if ( srcX + srcW > PImage(src)-> w)
1742 srcW = PImage(src)-> w - srcX;
1743 if ( srcY + srcH > PImage(src)-> h)
1744 srcH = PImage(src)-> h - srcY;
1745 if ( srcH <= 0 || srcW <= 0 )
1746 return false;
1747
1748 /* adjust source type */
1749 if (PImage(src)-> type != bpp || srcW != dstW || srcH != dstH ) {
1750 Bool ok;
1751 Handle dup;
1752
1753 if ( srcW != PImage(src)-> w || srcH != PImage(src)-> h)
1754 dup = CImage(src)-> extract( src, srcX, srcY, srcW, srcH );
1755 else
1756 dup = CImage(src)-> dup(src);
1757
1758 if ( srcW != dstW || srcH != dstH )
1759 CImage(dup)->stretch( dup, dstW, dstH );
1760 if ( PImage( dup )-> type != bpp )
1761 CImage(dup)-> set_type( dup, bpp);
1762
1763 ok = img_put_alpha( dest, dup, dstX, dstY, 0, 0, dstW, dstH, dstW, dstH, xrop, region);
1764
1765 Object_destroy(dup);
1766 return ok;
1767 }
1768
1769 /* adjust destination type */
1770 if (PImage(dest)-> type != bpp || ( kind_of( dest, CIcon) && PIcon(dest)->maskType != imbpp8 )) {
1771 Bool ok;
1772 Bool icon = kind_of(dest, CIcon);
1773 int type = PImage(dest)->type;
1774 int mask = icon ? PIcon(dest)->maskType : 0;
1775
1776 if ( type != bpp )
1777 CIcon(dest)-> set_type( dest, bpp );
1778 if ( icon && mask != imbpp8 )
1779 CIcon(dest)-> set_maskType( dest, imbpp8 );
1780 ok = img_put_alpha( dest, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH, xrop, region);
1781 if ( PImage(dest)-> options. optPreserveType ) {
1782 if ( type != bpp )
1783 CImage(dest)-> set_type( dest, type );
1784 if ( icon && mask != imbpp8 )
1785 CIcon(dest)-> set_maskType( dest, mask );
1786 }
1787 return ok;
1788 }
1789
1790 /* assign pointers */
1791 if ( srcW != dstW || srcH != dstH ||
1792 PImage(src)->type != PImage(dest)->type || PImage(src)-> type != bpp)
1793 croak("panic: assert failed for img_put_alpha: %s", "types and geometry");
1794
1795 bpp = ( bpp == imByte ) ? 1 : 3;
1796 if ( kind_of(src, CIcon)) {
1797 mls = PIcon(src)-> maskLine;
1798 if ( PIcon(src)-> maskType != imbpp8)
1799 croak("panic: assert failed for img_put_alpha: %s", "src mask type");
1800 if ( use_src_alpha )
1801 src_alpha_mul = src_alpha;
1802 use_src_alpha = false;
1803 } else {
1804 mls = 0;
1805 }
1806
1807 if ( kind_of(dest, CIcon)) {
1808 als = PIcon(dest)-> maskLine;
1809 if ( PIcon(dest)-> maskType != imbpp8)
1810 croak("panic: assert failed for img_put_alpha: %s", "dst mask type");
1811 if ( use_dst_alpha )
1812 dst_alpha_mul = dst_alpha;
1813 use_dst_alpha = false;
1814 } else {
1815 als = 0;
1816 }
1817
1818 if ( !use_src_alpha && mls == 0) {
1819 use_src_alpha = true;
1820 src_alpha = 0xff;
1821 }
1822 if ( !use_dst_alpha && als == 0) {
1823 use_dst_alpha = true;
1824 dst_alpha = 0xff;
1825 }
1826 if ( use_pms && !use_src_alpha && mls == 0 )
1827 use_pms = false;
1828
1829 /* make buffers */
1830 bytes = dstW * bpp;
1831 if ( !(asbuf = malloc(use_src_alpha ? 1 : (bytes * OMP_MAX_THREADS)))) {
1832 warn("not enough memory");
1833 return false;
1834 }
1835 if ( !(adbuf = malloc(use_dst_alpha ? 1 : (bytes * OMP_MAX_THREADS)))) {
1836 free(asbuf);
1837 warn("not enough memory");
1838 return false;
1839 }
1840 if ( use_pms ) {
1841 if ( !(pmsbuf = malloc( bytes * OMP_MAX_THREADS))) {
1842 free(adbuf);
1843 free(asbuf);
1844 warn("not enough memory");
1845 return false;
1846 }
1847 }
1848
1849 if ( use_src_alpha ) asbuf[0] = src_alpha;
1850 if ( use_dst_alpha ) adbuf[0] = dst_alpha;
1851
1852 /* select function */
1853 {
1854 ImgPutAlphaCallbackRec rec = {
1855 /* dX */ srcX - dstX,
1856 /* dY */ srcY - dstY,
1857 /* bpp */ bpp,
1858 /* sls */ PImage(src )-> lineSize,
1859 /* dls */ PImage(dest)-> lineSize,
1860 /* mls */ mls,
1861 /* als */ als,
1862 /* src */ PImage(src )->data,
1863 /* dst */ PImage(dest)->data,
1864 /* srcMask */ (mls > 0) ? PIcon(src )->mask : NULL,
1865 /* dstMask */ (als > 0) ? PIcon(dest)->mask : NULL,
1866 /* use_src_alpha */ use_src_alpha,
1867 /* use_dst_alpha */ use_dst_alpha,
1868 /* src_alpha_mul */ src_alpha_mul,
1869 /* dst_alpha_mul */ dst_alpha_mul,
1870 /* pmsbuf */ pmsbuf,
1871 /* asbuf */ asbuf,
1872 /* adbuf */ adbuf,
1873 };
1874 find_blend_proc(rop, &rec.blend1, &rec.blend2);
1875 img_region_foreach( region,
1876 dstX, dstY, dstW, dstH,
1877 (RegionCallbackFunc*)img_put_alpha_single, &rec
1878 );
1879 };
1880
1881 /* cleanup */
1882 free(adbuf);
1883 free(asbuf);
1884 if (pmsbuf) free(pmsbuf);
1885
1886 return true;
1887 }
1888
1889 typedef struct {
1890 int bpp, als, dls, step, pat_x_offset;
1891 Byte * dst, *dstMask, *pattern_buf, *adbuf;
1892 Bool use_dst_alpha, solid;
1893 Byte src_alpha;
1894 PImgPaintContext ctx;
1895 BlendFunc * blend1, * blend2;
1896 } ImgBarAlphaCallbackRec;
1897
1898 static Bool
img_bar_alpha_single_opaque(int x,int y,int w,int h,ImgBarAlphaCallbackRec * ptr)1899 img_bar_alpha_single_opaque( int x, int y, int w, int h, ImgBarAlphaCallbackRec * ptr)
1900 {
1901 int i;
1902 const int bpp = ptr->bpp;
1903 const int blt_bytes = w * bpp;
1904 const int dls = ptr->dls;
1905 const int als = ptr->als;
1906 const Byte * d = ptr->dst + y * ptr->dls + x * bpp;
1907 const Byte * a = (als > 0) ? ptr->dstMask + y * als + x : NULL;
1908 int blt_step = (blt_bytes > ptr->step) ? ptr->step : blt_bytes;
1909 Byte * pat_ptr;
1910
1911 if (!ptr->solid && (( ptr-> pat_x_offset % FILL_PATTERN_SIZE ) != (x % FILL_PATTERN_SIZE))) {
1912 int dx = (x % FILL_PATTERN_SIZE) - ( ptr-> pat_x_offset % FILL_PATTERN_SIZE );
1913 if ( dx < 0 ) dx += FILL_PATTERN_SIZE;
1914 pat_ptr = ptr->pattern_buf + dx * bpp;
1915 if ( blt_step + FILL_PATTERN_SIZE * bpp > BLT_BUFSIZE )
1916 blt_step -= FILL_PATTERN_SIZE * bpp;
1917 } else
1918 pat_ptr = ptr->pattern_buf;
1919
1920 for ( i = 0; i < h; i++) {
1921 Byte *adbuf_ptr;
1922
1923 int bytes = blt_bytes;
1924 Byte *d_ptr = (Byte *)d;
1925 Byte *s_ptr = pat_ptr + ((y + i) % FILL_PATTERN_SIZE) * ptr->step;
1926
1927 if ( !ptr->use_dst_alpha ) {
1928 adbuf_ptr = ptr->adbuf;
1929 fill_alpha_buf( adbuf_ptr, (Byte*)a, w, bpp);
1930 } else
1931 adbuf_ptr = ptr->adbuf;
1932
1933 while ( bytes > 0 ) {
1934 ptr->blend1(
1935 s_ptr, 1,
1936 &ptr->src_alpha, 0,
1937 d_ptr,
1938 adbuf_ptr, ptr->use_dst_alpha ? 0 : 1,
1939 ( bytes > blt_step ) ? blt_step : bytes);
1940 bytes -= blt_step;
1941 d_ptr += blt_step;
1942 }
1943 d += dls;
1944
1945 if ( a ) {
1946 ptr->blend2(
1947 &ptr->src_alpha, 0,
1948 &ptr->src_alpha, 0,
1949 (Byte*)a,
1950 a, ptr->use_dst_alpha ? 0 : 1,
1951 w
1952 );
1953 a += als;
1954 }
1955 }
1956 return true;
1957 }
1958
1959 static Bool
img_bar_alpha_single_transparent(int x,int y,int w,int h,ImgBarAlphaCallbackRec * ptr)1960 img_bar_alpha_single_transparent( int x, int y, int w, int h, ImgBarAlphaCallbackRec * ptr)
1961 {
1962 int i, j;
1963 const int bpp = ptr->bpp;
1964 const int blt_bytes = w * bpp;
1965 const int dls = ptr->dls;
1966 const int als = ptr->als;
1967 const Byte * d = ptr->dst + y * ptr->dls + x * bpp;
1968 const Byte * a = (als > 0) ? ptr->dstMask + y * als + x : NULL;
1969
1970 for ( i = 0; i < h; i++) {
1971 unsigned int pat;
1972 Byte *d_ptr, *a_ptr, *adbuf_ptr, *adbuf_ptr2;
1973 pat = (unsigned int) ptr->ctx->pattern[(i + ptr->ctx->patternOffset. y) % FILL_PATTERN_SIZE];
1974 if ( pat == 0 ) goto NEXT_LINE;
1975 pat = (((pat << 8) | pat) >> ((ptr->ctx->patternOffset. x + 8 - (x % 8)) % FILL_PATTERN_SIZE)) & 0xff;
1976
1977 if ( !ptr->use_dst_alpha ) {
1978 adbuf_ptr = ptr->adbuf;
1979 fill_alpha_buf( adbuf_ptr, (Byte*)a, w, bpp);
1980 } else
1981 adbuf_ptr = ptr->adbuf;
1982
1983 if ( pat == 0xff && bpp == 1) {
1984 ptr->blend1(
1985 ptr->ctx->color, 0,
1986 &ptr->src_alpha, 0,
1987 (Byte*)d,
1988 adbuf_ptr, ptr->use_dst_alpha ? 0 : 1,
1989 blt_bytes);
1990 if ( a ) ptr->blend2(
1991 &ptr->src_alpha, 0,
1992 &ptr->src_alpha, 0,
1993 (Byte*)a,
1994 a, ptr->use_dst_alpha ? 0 : 1,
1995 w
1996 );
1997 goto NEXT_LINE;
1998 }
1999
2000 for (
2001 j = 0, d_ptr = (Byte*)d, a_ptr = (Byte*)a, adbuf_ptr2 = adbuf_ptr;
2002 j < w;
2003 j++
2004 ) {
2005 if ( pat & (0x80 >> (j % 8)) ) {
2006 ptr->blend1(
2007 ptr->ctx->color, 0,
2008 &ptr->src_alpha, 0,
2009 d_ptr,
2010 adbuf_ptr2, ptr->use_dst_alpha ? 0 : 1,
2011 bpp);
2012 if ( a ) ptr->blend2(
2013 &ptr->src_alpha, 0,
2014 &ptr->src_alpha, 0,
2015 a_ptr,
2016 a_ptr, ptr->use_dst_alpha ? 0 : 1,
2017 1
2018 );
2019 }
2020 d_ptr += bpp;
2021 if ( a ) a_ptr++;
2022 if ( !ptr-> use_dst_alpha ) adbuf_ptr2++;
2023 }
2024
2025 NEXT_LINE:
2026 d += dls;
2027 if ( a ) a += als;
2028 }
2029 return true;
2030 }
2031
2032 static Bool
img_bar_alpha(Handle dest,int x,int y,int w,int h,PImgPaintContext ctx)2033 img_bar_alpha( Handle dest, int x, int y, int w, int h, PImgPaintContext ctx)
2034 {
2035 int bpp, als;
2036 unsigned int src_alpha = 0xff, dst_alpha = 0;
2037 Bool use_dst_alpha = false, solid;
2038 Byte blt_buffer[BLT_BUFSIZE], *adbuf;
2039 int j, k, blt_bytes, blt_step = -1;
2040
2041 if ( ctx->transparent && (memcmp( ctx->pattern, fillPatterns[fpEmpty], sizeof(FillPattern)) == 0))
2042 return true;
2043
2044 /* align types and geometry - can only operate over imByte and imRGB */
2045 bpp = ( PImage(dest)->type & imGrayScale) ? imByte : imRGB;
2046 if (PImage(dest)-> type != bpp || ( kind_of( dest, CIcon) && PIcon(dest)->maskType != imbpp8 )) {
2047 Bool icon = kind_of(dest, CIcon), ok;
2048 int type = PImage(dest)->type;
2049 int mask = icon ? PIcon(dest)->maskType : 0;
2050
2051 if ( type != bpp ) {
2052 resample_colors( dest, bpp, ctx );
2053 CIcon(dest)-> set_type( dest, bpp );
2054 }
2055 if ( icon && mask != imbpp8 )
2056 CIcon(dest)-> set_maskType( dest, imbpp8 );
2057 ok = img_bar_alpha( dest, x, y, w, h, ctx);
2058 if ( PImage(dest)-> options. optPreserveType ) {
2059 if ( type != bpp )
2060 CImage(dest)-> set_type( dest, type );
2061 if ( icon && mask != imbpp8 )
2062 CIcon(dest)-> set_maskType( dest, mask );
2063 }
2064 return ok;
2065 }
2066
2067 /* differentiate between per-pixel alpha and a global value */
2068 if ( ctx->rop & ropSrcAlpha )
2069 src_alpha = (ctx->rop >> ropSrcAlphaShift) & 0xff;
2070 if ( ctx->rop & ropDstAlpha ) {
2071 use_dst_alpha = true;
2072 dst_alpha = (ctx->rop >> ropDstAlphaShift) & 0xff;
2073 }
2074 ctx->rop &= ropPorterDuffMask;
2075 if ( ctx->rop > ropMaxPDFunc || ctx->rop < 0 ) ctx->rop = ropSrcOver;
2076
2077 /* assign pointers */
2078 bpp = ( bpp == imByte ) ? 1 : 3;
2079 if ( kind_of(dest, CIcon)) {
2080 als = PIcon(dest)-> maskLine;
2081 if ( PIcon(dest)-> maskType != imbpp8)
2082 croak("panic: assert failed for img_bar_alpha: %s", "dst mask type");
2083 use_dst_alpha = false;
2084 } else {
2085 als = 0;
2086 }
2087
2088 if ( !use_dst_alpha && als == 0) {
2089 use_dst_alpha = true;
2090 dst_alpha = 0xff;
2091 }
2092 if ( !(adbuf = malloc(use_dst_alpha ? 1 : (bpp * w)))) {
2093 warn("not enough memory");
2094 return false;
2095 }
2096 if ( use_dst_alpha ) adbuf[0] = dst_alpha;
2097
2098 /* premultiply colors */
2099 for ( j = 0; j < bpp; j++) {
2100 ctx->color[j] = (float)(ctx->color[j] * src_alpha) / 255.0 + .5;
2101 ctx->backColor[j] = (float)(ctx->backColor[j] * src_alpha) / 255.0 + .5;
2102 }
2103
2104 solid = (memcmp( ctx->pattern, fillPatterns[fpSolid], sizeof(FillPattern)) == 0);
2105 if ( solid || !ctx->transparent ) {
2106 /* render a (minimum) 8x8xPIXEL matrix with pattern, then
2107 replicate it over blt_buffer as much as possible, to streamline
2108 byte operations */
2109 blt_bytes = w * bpp;
2110 if ( blt_bytes < FILL_PATTERN_SIZE * bpp ) blt_bytes = FILL_PATTERN_SIZE * bpp;
2111 blt_bytes *= FILL_PATTERN_SIZE;
2112 blt_step = ((blt_bytes > BLT_BUFSIZE) ? BLT_BUFSIZE : blt_bytes) / FILL_PATTERN_SIZE;
2113 if ( bpp > 1 )
2114 blt_step = (blt_step / bpp / FILL_PATTERN_SIZE) * bpp * FILL_PATTERN_SIZE;
2115 for ( j = 0; j < FILL_PATTERN_SIZE; j++) {
2116 unsigned int pat, strip_size;
2117 Byte matrix[MAX_SIZEOF_PIXEL * FILL_PATTERN_SIZE], *buffer;
2118 if ( solid ) {
2119 pat = 0xff;
2120 } else {
2121 pat = (unsigned int) ctx->pattern[(j + ctx->patternOffset. y) % FILL_PATTERN_SIZE];
2122 pat = (((pat << 8) | pat) >> ((ctx->patternOffset. x + 8 - (x % 8)) % FILL_PATTERN_SIZE)) & 0xff;
2123 }
2124 buffer = blt_buffer + j * blt_step;
2125 if ( bpp == 1 ) {
2126 strip_size = FILL_PATTERN_SIZE;
2127 for ( k = 0; k < FILL_PATTERN_SIZE; k++)
2128 matrix[k] = *((pat & (0x80 >> k)) ? ctx->color : ctx->backColor);
2129 } else {
2130 strip_size = FILL_PATTERN_SIZE * bpp;
2131 for ( k = 0; k < FILL_PATTERN_SIZE; k++) {
2132 Byte * color = (pat & (0x80 >> k)) ? ctx->color : ctx->backColor;
2133 memcpy( matrix + k * bpp, color, bpp);
2134 }
2135 }
2136 if ( strip_size > 1 ) {
2137 Byte * buf = buffer;
2138 for ( k = 0; k < blt_step / strip_size; k++, buf += strip_size)
2139 memcpy( buf, matrix, strip_size);
2140 if ( blt_step % strip_size != 0)
2141 memcpy( buf, matrix, blt_step % strip_size);
2142 }
2143 }
2144
2145 /*
2146 printf("bpp:%d step:%d\n", bpp, blt_step);
2147 for ( j = 0; j < 8; j++) {
2148 printf("%d: ", j);
2149 for ( k = 0; k < blt_step; k++) {
2150 printf("%02x", blt_buffer[ j * blt_step + k]);
2151 }
2152 printf("\n");
2153 }
2154 */
2155 }
2156
2157 /* select function */
2158 {
2159 ImgBarAlphaCallbackRec rec = {
2160 /* bpp */ bpp,
2161 /* als */ als,
2162 /* dls */ PImage(dest)-> lineSize,
2163 /* step */ blt_step,
2164 /* pat_x_offset */ x,
2165 /* dst */ PImage(dest)->data,
2166 /* dstMask */ (als > 0) ? PIcon(dest)->mask : NULL,
2167 /* pattern_buf */ blt_buffer,
2168 /* adbuf */ adbuf,
2169 /* use_dst_alpha */ use_dst_alpha,
2170 /* solid */ solid,
2171 /* src_alpha */ src_alpha,
2172 /* ctx */ ctx
2173 };
2174 find_blend_proc(ctx->rop, &rec.blend1, &rec.blend2);
2175 img_region_foreach( ctx->region, x, y, w, h,
2176 ( RegionCallbackFunc *)((solid || !ctx->transparent) ?
2177 img_bar_alpha_single_opaque : img_bar_alpha_single_transparent),
2178 &rec
2179 );
2180 };
2181
2182 free(adbuf);
2183
2184 return true;
2185 }
2186
2187 typedef struct {
2188 PIcon i;
2189 Rect clip;
2190 int y, bpp, bytes;
2191 Byte * color;
2192 Bool single_border;
2193 int first;
2194 PList * lists;
2195 PBoxRegionRec new_region;
2196 int new_region_size;
2197 } FillSession;
2198
2199 static Bool
fs_get_pixel(FillSession * fs,int x,int y)2200 fs_get_pixel( FillSession * fs, int x, int y)
2201 {
2202 Byte * data;
2203
2204
2205 if ( x < fs-> clip. left || x > fs-> clip. right || y < fs-> clip. bottom || y > fs-> clip. top)
2206 return false;
2207
2208 if ( fs-> lists[ y - fs-> first]) {
2209 PList l = fs-> lists[ y - fs-> first];
2210 int i;
2211 for ( i = 0; i < l-> count; i+=2) {
2212 if (((int) l-> items[i+1] >= x) && ((int)l->items[i] <= x))
2213 return false;
2214 }
2215 }
2216
2217 data = fs->i->data + fs->i->lineSize * y;
2218
2219 switch( fs-> bpp) {
2220 case 1: {
2221 Byte xz = *(data + (x >> 3));
2222 Byte v = ( xz & ( 0x80 >> ( x & 7)) ? 1 : 0);
2223 return fs-> single_border ?
2224 ( v == *(fs-> color)) : ( v != *(fs-> color));
2225 }
2226 case 4: {
2227 Byte xz = *(data + (x >> 1));
2228 Byte v = (x & 1) ? ( xz & 0xF) : ( xz >> 4);
2229 return fs-> single_border ?
2230 ( v == *(fs-> color)) : ( v != *(fs-> color));
2231 }
2232 case 8:
2233 return fs-> single_border ?
2234 ( *(fs-> color) == *(data + x) ):
2235 ( *(fs-> color) != *(data + x) );
2236 case 16:
2237 return fs-> single_border ?
2238 ( *((uint16_t*)(fs-> color)) == *((uint16_t*)data + x) ) :
2239 ( *((uint16_t*)(fs-> color)) != *((uint16_t*)data + x) );
2240 case 32:
2241 return fs-> single_border ?
2242 ( *((uint32_t*)(fs-> color)) == *((uint32_t*)data + x) ) :
2243 ( *((uint32_t*)(fs-> color)) != *((uint32_t*)data + x) );
2244 default: {
2245 return fs-> single_border ?
2246 ( memcmp(data + x * fs->bytes, fs->color, fs->bytes) == 0) :
2247 ( memcmp(data + x * fs->bytes, fs->color, fs->bytes) != 0);
2248 }}
2249 }
2250
2251 static void
fs_hline(FillSession * fs,int x1,int y,int x2)2252 fs_hline( FillSession * fs, int x1, int y, int x2)
2253 {
2254 y -= fs-> first;
2255 if ( fs-> lists[y] == NULL)
2256 fs-> lists[y] = plist_create( 32, 128);
2257 list_add( fs-> lists[y], ( Handle) x1);
2258 list_add( fs-> lists[y], ( Handle) x2);
2259 }
2260
2261 static int
fs_fill(FillSession * fs,int sx,int sy,int d,int pxl,int pxr)2262 fs_fill( FillSession * fs, int sx, int sy, int d, int pxl, int pxr)
2263 {
2264 int x, xr = sx;
2265 while ( sx > fs-> clip. left && fs_get_pixel( fs, sx - 1, sy)) sx--;
2266 while ( xr < fs-> clip. right && fs_get_pixel( fs, xr + 1, sy)) xr++;
2267 fs_hline( fs, sx, sy, xr);
2268
2269 if ( sy + d >= fs-> clip. bottom && sy + d <= fs-> clip. top) {
2270 x = sx;
2271 while ( x <= xr) {
2272 if ( fs_get_pixel( fs, x, sy + d))
2273 x = fs_fill( fs, x, sy + d, d, sx, xr);
2274 x++;
2275 }
2276 }
2277
2278 if ( sy - d >= fs-> clip. bottom && sy - d <= fs-> clip. top) {
2279 x = sx;
2280 while ( x < pxl) {
2281 if ( fs_get_pixel( fs, x, sy - d))
2282 x = fs_fill( fs, x, sy - d, -d, sx, xr);
2283 x++;
2284 }
2285 x = pxr;
2286 while ( x <= xr) {
2287 if ( fs_get_pixel( fs, x, sy - d))
2288 x = fs_fill( fs, x, sy - d, -d, sx, xr);
2289 x++;
2290 }
2291 }
2292 return xr;
2293 }
2294
2295 static Bool
fs_intersect(int x1,int y,int w,int h,FillSession * fs)2296 fs_intersect( int x1, int y, int w, int h, FillSession * fs)
2297 {
2298 PList l;
2299 Handle * items;
2300 int i, j, x2;
2301
2302 x2 = x1 + w - 1;
2303 for ( i = 0; i < h; i++)
2304 if (( l = fs-> lists[y + i - fs->first]) != NULL )
2305 for ( j = 0, items = l->items; j < l-> count; j+=2) {
2306 Box * box;
2307 int left = (int) (*(items++));
2308 int right = (int) (*(items++));
2309 if ( left < x1 )
2310 left = x1;
2311 if ( right > x2)
2312 right = x2;
2313 if ( left > right )
2314 continue;
2315 if ( fs-> new_region-> n_boxes >= fs-> new_region_size ) {
2316 PBoxRegionRec n;
2317 fs-> new_region_size *= 2;
2318 if ( !( n = img_region_alloc( fs-> new_region, fs-> new_region_size)))
2319 return false;
2320 fs-> new_region = n;
2321 }
2322 box = fs-> new_region-> boxes + fs-> new_region-> n_boxes;
2323 box-> x = left;
2324 box-> y = y + i;
2325 box-> width = right - left + 1;
2326 box-> height = 1;
2327 fs-> new_region-> n_boxes++;
2328 }
2329
2330 return true;
2331 }
2332
2333 Bool
img_flood_fill(Handle self,int x,int y,ColorPixel color,Bool single_border,PImgPaintContext ctx)2334 img_flood_fill( Handle self, int x, int y, ColorPixel color, Bool single_border, PImgPaintContext ctx)
2335 {
2336 Bool ok = true;
2337 Box box;
2338 FillSession fs;
2339
2340 fs.i = ( PIcon ) self;
2341 fs.color = color;
2342 fs.bpp = fs.i->type & imBPP;
2343 fs.bytes = fs.bpp / 8;
2344 fs.single_border = single_border;
2345
2346 if ( ctx-> region ) {
2347 Box box = img_region_box( ctx-> region );
2348 fs. clip. left = box. x;
2349 fs. clip. bottom = box. y;
2350 fs. clip. right = box. x + box. width - 1;
2351 fs. clip. top = box. y + box. height - 1;
2352 } else {
2353 fs. clip. left = 0;
2354 fs. clip. bottom = 0;
2355 fs. clip. right = fs.i->w - 1;
2356 fs. clip. top = fs.i->h - 1;
2357 }
2358
2359 fs. new_region_size = (fs. clip. top - fs. clip. bottom + 1) * 4;
2360 if ( !( fs. new_region = img_region_alloc(NULL, fs. new_region_size)))
2361 return false;
2362
2363 fs. first = fs. clip. bottom;
2364 if ( !( fs. lists = malloc(( fs. clip. top - fs. clip. bottom + 1) * sizeof( void*)))) {
2365 free( fs. new_region );
2366 return false;
2367 }
2368 bzero( fs. lists, ( fs. clip. top - fs. clip. bottom + 1) * sizeof( void*));
2369
2370 if ( fs_get_pixel( &fs, x, y)) {
2371 fs_fill( &fs, x, y, -1, x, x);
2372 ok = img_region_foreach( ctx->region,
2373 0, 0, fs.i->w, fs.i->h,
2374 (RegionCallbackFunc*)fs_intersect, &fs
2375 );
2376 }
2377
2378 for ( x = 0; x < fs. clip. bottom - fs. clip. top + 1; x++)
2379 if ( fs. lists[x])
2380 plist_destroy( fs.lists[x]);
2381 free( fs. lists);
2382
2383 if ( ok ) {
2384 ctx-> region = fs. new_region;
2385 box = img_region_box( ctx-> region );
2386 ok = img_bar( self, box.x, box.y, box.width, box.height, ctx);
2387 }
2388
2389 free( fs. new_region);
2390
2391 return ok;
2392 }
2393
2394 /* alpha stuff */
2395 void
img_premultiply_alpha_constant(Handle self,int alpha)2396 img_premultiply_alpha_constant( Handle self, int alpha)
2397 {
2398 Byte * data;
2399 int i, j, pixels;
2400 if ( PImage(self)-> type == imByte ) {
2401 pixels = 1;
2402 } else if ( PImage(self)-> type == imRGB ) {
2403 pixels = 3;
2404 } else {
2405 croak("Not implemented");
2406 }
2407
2408 data = PImage(self)-> data;
2409 for ( i = 0; i < PImage(self)-> h; i++) {
2410 register Byte *d = data, k;
2411 for ( j = 0; j < PImage(self)-> w; j++ ) {
2412 for ( k = 0; k < pixels; k++, d++)
2413 *d = (alpha * *d) / 255.0 + .5;
2414 }
2415 data += PImage(self)-> lineSize;
2416 }
2417 }
2418
img_premultiply_alpha_map(Handle self,Handle alpha)2419 void img_premultiply_alpha_map( Handle self, Handle alpha)
2420 {
2421 Byte * data, * mask;
2422 int i, pixels;
2423 if ( PImage(self)-> type == imByte ) {
2424 pixels = 1;
2425 } else if ( PImage(self)-> type == imRGB ) {
2426 pixels = 3;
2427 } else {
2428 croak("Not implemented");
2429 }
2430
2431 if ( PImage(alpha)-> type != imByte )
2432 croak("Not implemented");
2433
2434 data = PImage(self)-> data;
2435 mask = PImage(alpha)-> data;
2436 for ( i = 0; i < PImage(self)-> h; i++) {
2437 int j;
2438 register Byte *d = data, *m = mask, k;
2439 for ( j = 0; j < PImage(self)-> w; j++ ) {
2440 register uint16_t alpha = *m++;
2441 for ( k = 0; k < pixels; k++, d++)
2442 *d = (alpha * *d) / 255.0 + .5;
2443 }
2444 data += PImage(self)-> lineSize;
2445 mask += PImage(alpha)-> lineSize;
2446 }
2447 }
2448
2449 #ifdef __cplusplus
2450 }
2451 #endif
2452
2453