@@ -302,6 +302,210 @@ static const twin_src_msk_op comp3[2][4][4][3] = {
302
302
#define operand_index (o ) \
303
303
((o)->source_kind == TWIN_SOLID ? 3 : o->u.pixmap->format)
304
304
305
+ #define _twin_add_ARGB (s , d , i , t ) (((t) = (s) + twin_get_8(d, i)))
306
+ #define _twin_add (s , d , t ) (((t) = (s) + (d)))
307
+ #define _twin_div (d , den , i , t ) \
308
+ (((t) = (d) / (den)), (t) = twin_get_8((t), 0), \
309
+ (twin_argb32_t) twin_sat(t) << (i))
310
+ #define _twin_sub_ARGB (s , d , i , t ) (((t) = (s) - twin_get_8(d, i)))
311
+ #define _twin_sub (s , d , t ) (((t) = (s) - (d)))
312
+ #define twin_put_8 (d , i , t ) (((t) = (d) << (i)))
313
+
314
+ #define min (x , y ) \
315
+ ({ \
316
+ typeof(x) _x = (x); \
317
+ typeof(y) _y = (y); \
318
+ (void) (&_x == &_y); \
319
+ _x < _y ? _x : _y; \
320
+ })
321
+ #define max (x , y ) \
322
+ ({ \
323
+ typeof(x) _x = (x); \
324
+ typeof(y) _y = (y); \
325
+ (void) (&_x == &_y); \
326
+ _x > _y ? _x : _y; \
327
+ })
328
+
329
+ void twin_stack (twin_pixmap_t * trg_px ,
330
+ twin_pixmap_t * src_px ,
331
+ int radius ,
332
+ int first_str ,
333
+ int first_end ,
334
+ int second_str ,
335
+ int second_end ,
336
+ bool horiz_scan )
337
+ {
338
+ int den = (radius + 1 ) * (radius + 1 );
339
+ twin_pointer_t src_ptr , trg_ptr , old_ptr , new_ptr ;
340
+ twin_argb32_t sumInR , sumOutR , sumR , sumInG , sumOutG , sumG , sumInB , sumOutB ,
341
+ sumB , _cur , _old , _new , _src ;
342
+ uint16_t t1 , t2 , t3 ;
343
+ for (int first = first_str ; first < first_end ; first ++ ) {
344
+ sumInR = sumOutR = sumR = sumInG = sumOutG = sumG = sumInB = sumOutB =
345
+ sumB = 0x00000000 ;
346
+
347
+ /* Initialize SumOut by padding */
348
+ if (horiz_scan )
349
+ src_ptr = twin_pixmap_pointer (src_px , second_str , first );
350
+ else
351
+ src_ptr = twin_pixmap_pointer (src_px , first , second_str );
352
+ _src = * src_ptr .argb32 ;
353
+
354
+ for (int i = second_str ; i < second_str + radius ; i ++ ) {
355
+ sumOutR = _twin_add_ARGB (sumOutR , _src , 0 , t1 );
356
+ sumOutG = _twin_add_ARGB (sumOutG , _src , 8 , t2 );
357
+ sumOutB = _twin_add_ARGB (sumOutB , _src , 16 , t3 );
358
+ for (int j = 0 ; j < (i - second_str ) + 1 ; j ++ ) {
359
+ sumR = _twin_add_ARGB (sumR , _src , 0 , t1 );
360
+ sumG = _twin_add_ARGB (sumG , _src , 8 , t2 );
361
+ sumB = _twin_add_ARGB (sumB , _src , 16 , t3 );
362
+ }
363
+ }
364
+
365
+ /* Initialize SumIn */
366
+ for (int i = second_str ; i < second_str + radius ; i ++ ) {
367
+ if (horiz_scan )
368
+ src_ptr = twin_pixmap_pointer (src_px , i , first );
369
+ else
370
+ src_ptr = twin_pixmap_pointer (src_px , first , i );
371
+ _src = * src_ptr .argb32 ;
372
+ sumInR = _twin_add_ARGB (sumInR , _src , 0 , t1 );
373
+ sumInG = _twin_add_ARGB (sumInG , _src , 8 , t2 );
374
+ sumInB = _twin_add_ARGB (sumInB , _src , 16 , t3 );
375
+ for (int j = 0 ; j < radius - (i - second_str ); j ++ ) {
376
+ sumR = _twin_add_ARGB (sumR , _src , 0 , t1 );
377
+ sumG = _twin_add_ARGB (sumG , _src , 8 , t2 );
378
+ sumB = _twin_add_ARGB (sumB , _src , 16 , t3 );
379
+ }
380
+ }
381
+
382
+ for (int cur = second_str ; cur < second_end ; cur ++ ) {
383
+ if (horiz_scan ) {
384
+ src_ptr = twin_pixmap_pointer (src_px , cur , first );
385
+ trg_ptr = twin_pixmap_pointer (trg_px , cur , first );
386
+ old_ptr = twin_pixmap_pointer (
387
+ src_px , max (cur - radius , second_str ), first );
388
+ new_ptr = twin_pixmap_pointer (
389
+ src_px , min (cur + radius , second_end - 1 ), first );
390
+ } else {
391
+ src_ptr = twin_pixmap_pointer (src_px , first , cur );
392
+ trg_ptr = twin_pixmap_pointer (trg_px , first , cur );
393
+ old_ptr = twin_pixmap_pointer (src_px , first ,
394
+ max (cur - radius , second_str ));
395
+ new_ptr = twin_pixmap_pointer (
396
+ src_px , first , min (cur + radius , second_end - 1 ));
397
+ }
398
+ _cur = * src_ptr .argb32 ;
399
+ _old = * old_ptr .argb32 ;
400
+ _new = * new_ptr .argb32 ;
401
+ /* STEP 1 : sum_out + current */
402
+ sumOutR = _twin_add_ARGB (sumOutR , _cur , 0 , t1 );
403
+ sumOutG = _twin_add_ARGB (sumOutG , _cur , 8 , t2 );
404
+ sumOutB = _twin_add_ARGB (sumOutB , _cur , 16 , t3 );
405
+ /* STEP 2 : sum_in + new */
406
+ sumInR = _twin_add_ARGB (sumInR , _new , 0 , t1 );
407
+ sumInG = _twin_add_ARGB (sumInG , _new , 8 , t2 );
408
+ sumInB = _twin_add_ARGB (sumInB , _new , 16 , t3 );
409
+ /* STEP 3 : sum + sum_in */
410
+ sumR = _twin_add (sumR , sumInR , t1 );
411
+ sumG = _twin_add (sumG , sumInG , t2 );
412
+ sumB = _twin_add (sumB , sumInB , t3 );
413
+ /* STEP 4 : sum / denominator */
414
+ * trg_ptr .argb32 =
415
+ (_twin_div (sumR , den , 0 , t1 ) | _twin_div (sumG , den , 8 , t2 ) |
416
+ _twin_div (sumB , den , 16 , t3 ) | (* src_ptr .argb32 & 0xff000000 ));
417
+ /* STEP 5 : sum - sum_out */
418
+ sumR = _twin_sub (sumR , sumOutR , t1 );
419
+ sumG = _twin_sub (sumG , sumOutG , t2 );
420
+ sumB = _twin_sub (sumB , sumOutB , t3 );
421
+ /* STEP 6 : sum_out - old */
422
+ sumOutR = _twin_sub_ARGB (sumOutR , _old , 0 , t1 );
423
+ sumOutG = _twin_sub_ARGB (sumOutG , _old , 8 , t2 );
424
+ sumOutB = _twin_sub_ARGB (sumOutB , _old , 16 , t3 );
425
+ /* STEP 7 : sum_in - current */
426
+ sumInR = _twin_sub_ARGB (sumInR , _cur , 0 , t1 );
427
+ sumInG = _twin_sub_ARGB (sumInG , _cur , 8 , t2 );
428
+ sumInB = _twin_sub_ARGB (sumInB , _cur , 16 , t3 );
429
+ }
430
+ }
431
+ }
432
+
433
+ void twin_stack_blur (twin_pixmap_t * px ,
434
+ int radius ,
435
+ twin_coord_t left ,
436
+ twin_coord_t right ,
437
+ twin_coord_t top ,
438
+ twin_coord_t bottom )
439
+ {
440
+ if (px -> format != TWIN_ARGB32 )
441
+ return ;
442
+ twin_pixmap_t * tmp_px =
443
+ twin_pixmap_create (px -> format , px -> width , px -> height );
444
+ memcpy (tmp_px -> p .v , px -> p .v ,
445
+ px -> width * px -> height * twin_bytes_per_pixel (px -> format ));
446
+ /*
447
+ * Originally, performing a 2D convolution on each pixel takes O(width *
448
+ * height * k²). However, by first scanning horizontally and then vertically
449
+ * across the pixel map, and applying a 1D convolution to each pixel, the
450
+ * complexity is reduced to O(2 * width * height * k).
451
+ */
452
+ twin_stack (tmp_px , px , radius , top , bottom , left , right , true);
453
+ twin_stack (px , tmp_px , radius , left , right , top , bottom , false);
454
+ twin_pixmap_destroy (tmp_px );
455
+ return ;
456
+ }
457
+
458
+ void twin_shadow_border (twin_pixmap_t * shadow )
459
+ {
460
+ twin_pixmap_t * target = shadow -> window -> pixmap ;
461
+ twin_coord_t target_right = target -> x + target -> width ,
462
+ target_bottom = target -> y + target -> height , border = 5 ,
463
+ right_edge = (* shadow ).width - ((* shadow ).x - (* target ).x ),
464
+ bottom_edge = (* shadow ).height - ((* shadow ).y - (* target ).y ),
465
+ right_span = right_edge ;
466
+ twin_pointer_t dst ;
467
+ twin_source_u src ;
468
+ twin_argb32_t color_x , color_y = 0xff000000 ;
469
+ for (twin_coord_t y = 0 ; y < (* shadow ).height ; y ++ ) {
470
+ color_x = 0xff000000 ;
471
+ /* Render the right edge of the shadow border. */
472
+ if (shadow -> y + y < target_bottom ) {
473
+ for (twin_coord_t x = right_edge - border ; x < (* shadow ).width ; x ++ )
474
+ if (shadow -> x + x > target_right - border ) {
475
+ dst = twin_pixmap_pointer (shadow , x , y );
476
+ src .c = color_x ;
477
+ _twin_c_over_argb32 (dst , src , 1 );
478
+ if ((shadow -> x + x - target_right ) % border == 0 ) {
479
+ color_x >>= 1 ;
480
+ color_x &= 0xff000000 ;
481
+ }
482
+ }
483
+ } else
484
+ /* Calculate the range of the corner. */
485
+ right_span ++ ;
486
+
487
+ /* Render the bottom edge of the shadow border. */
488
+ if (shadow -> y + y > target_bottom - border ) {
489
+ dst = twin_pixmap_pointer (shadow , 0 , y );
490
+ src .c = color_y ;
491
+ _twin_c_over_argb32 (dst , src , right_edge );
492
+ /* Render the bottom-right corner of the shadow border. */
493
+ for (twin_coord_t i = 0 ; i < right_span - right_edge ; i ++ ) {
494
+ /* The corner's pixels are symmetrical to the diagonal. */
495
+ dst = twin_pixmap_pointer (shadow , right_edge + i , y );
496
+ _twin_c_over_argb32 (dst , src , 1 );
497
+ dst = twin_pixmap_pointer (
498
+ shadow , right_edge + (y - bottom_edge ), bottom_edge + i );
499
+ _twin_c_over_argb32 (dst , src , 1 );
500
+ }
501
+ if ((shadow -> y + y - target_bottom ) % border == 0 ) {
502
+ color_y >>= 1 ;
503
+ color_y &= 0xff000000 ;
504
+ }
505
+ }
506
+ }
507
+ }
508
+
305
509
/* FIXME: source clipping is busted */
306
510
static void _twin_composite_simple (twin_pixmap_t * dst ,
307
511
twin_coord_t dst_x ,
0 commit comments