Home | History | Annotate | Download | only in demos
      1 #include "../test/utils.h"
      2 #include "gtk-utils.h"
      3 
      4 #define NUM_GRADIENTS 9
      5 #define NUM_STOPS 3
      6 #define NUM_REPEAT 4
      7 #define SIZE 128
      8 #define WIDTH (SIZE * NUM_GRADIENTS)
      9 #define HEIGHT (SIZE * NUM_REPEAT)
     10 
     11 /*
     12  * We want to test all the possible relative positions of the start
     13  * and end circle:
     14  *
     15  *  - The start circle can be smaller/equal/bigger than the end
     16  *    circle. A radial gradient can be classified in one of these
     17  *    three cases depending on the sign of dr.
     18  *
     19  *  - The smaller circle can be completely inside/internally
     20  *    tangent/outside (at least in part) of the bigger circle. This
     21  *    classification is the same as the one which can be computed by
     22  *    examining the sign of a = (dx^2 + dy^2 - dr^2).
     23  *
     24  *  - If the two circles have the same size, neither can be inside or
     25  *    internally tangent
     26  *
     27  * This test draws radial gradients whose circles always have the same
     28  * centers (0, 0) and (1, 0), but with different radiuses. From left
     29  * to right:
     30  *
     31  * - Degenerate start circle completely inside the end circle
     32  *     0.00 -> 1.75; dr = 1.75 > 0; a = 1 - 1.75^2 < 0
     33  *
     34  * - Small start circle completely inside the end circle
     35  *     0.25 -> 1.75; dr =  1.5 > 0; a = 1 - 1.50^2 < 0
     36  *
     37  * - Small start circle internally tangent to the end circle
     38  *     0.50 -> 1.50; dr =  1.0 > 0; a = 1 - 1.00^2 = 0
     39  *
     40  * - Small start circle outside of the end circle
     41  *     0.50 -> 1.00; dr =  0.5 > 0; a = 1 - 0.50^2 > 0
     42  *
     43  * - Start circle with the same size as the end circle
     44  *     1.00 -> 1.00; dr =  0.0 = 0; a = 1 - 0.00^2 > 0
     45  *
     46  * - Small end circle outside of the start circle
     47  *     1.00 -> 0.50; dr = -0.5 > 0; a = 1 - 0.50^2 > 0
     48  *
     49  * - Small end circle internally tangent to the start circle
     50  *     1.50 -> 0.50; dr = -1.0 > 0; a = 1 - 1.00^2 = 0
     51  *
     52  * - Small end circle completely inside the start circle
     53  *     1.75 -> 0.25; dr = -1.5 > 0; a = 1 - 1.50^2 < 0
     54  *
     55  * - Degenerate end circle completely inside the start circle
     56  *     0.00 -> 1.75; dr = 1.75 > 0; a = 1 - 1.75^2 < 0
     57  *
     58  */
     59 
     60 const static double radiuses[NUM_GRADIENTS] = {
     61     0.00,
     62     0.25,
     63     0.50,
     64     0.50,
     65     1.00,
     66     1.00,
     67     1.50,
     68     1.75,
     69     1.75
     70 };
     71 
     72 #define double_to_color(x)					\
     73     (((uint32_t) ((x)*65536)) - (((uint32_t) ((x)*65536)) >> 16))
     74 
     75 #define PIXMAN_STOP(offset,r,g,b,a)		\
     76     { pixman_double_to_fixed (offset),		\
     77 	{					\
     78 	double_to_color (r),			\
     79 	double_to_color (g),			\
     80 	double_to_color (b),			\
     81 	double_to_color (a)			\
     82 	}					\
     83     }
     84 
     85 static const pixman_gradient_stop_t stops[NUM_STOPS] = {
     86     PIXMAN_STOP (0.0,        1, 0, 0, 0.75),
     87     PIXMAN_STOP (0.70710678, 0, 1, 0, 0),
     88     PIXMAN_STOP (1.0,        0, 0, 1, 1)
     89 };
     90 
     91 static pixman_image_t *
     92 create_radial (int index)
     93 {
     94     pixman_point_fixed_t p0, p1;
     95     pixman_fixed_t r0, r1;
     96     double x0, x1, radius0, radius1, left, right, center;
     97 
     98     x0 = 0;
     99     x1 = 1;
    100     radius0 = radiuses[index];
    101     radius1 = radiuses[NUM_GRADIENTS - index - 1];
    102 
    103     /* center the gradient */
    104     left = MIN (x0 - radius0, x1 - radius1);
    105     right = MAX (x0 + radius0, x1 + radius1);
    106     center = (left + right) * 0.5;
    107     x0 -= center;
    108     x1 -= center;
    109 
    110     /* scale to make it fit within a 1x1 rect centered in (0,0) */
    111     x0 *= 0.25;
    112     x1 *= 0.25;
    113     radius0 *= 0.25;
    114     radius1 *= 0.25;
    115 
    116     p0.x = pixman_double_to_fixed (x0);
    117     p0.y = pixman_double_to_fixed (0);
    118 
    119     p1.x = pixman_double_to_fixed (x1);
    120     p1.y = pixman_double_to_fixed (0);
    121 
    122     r0 = pixman_double_to_fixed (radius0);
    123     r1 = pixman_double_to_fixed (radius1);
    124 
    125     return pixman_image_create_radial_gradient (&p0, &p1,
    126 						r0, r1,
    127 						stops, NUM_STOPS);
    128 }
    129 
    130 static const pixman_repeat_t repeat[NUM_REPEAT] = {
    131     PIXMAN_REPEAT_NONE,
    132     PIXMAN_REPEAT_NORMAL,
    133     PIXMAN_REPEAT_REFLECT,
    134     PIXMAN_REPEAT_PAD
    135 };
    136 
    137 int
    138 main (int argc, char **argv)
    139 {
    140     pixman_transform_t transform;
    141     pixman_image_t *src_img, *dest_img;
    142     int i, j;
    143 
    144     enable_divbyzero_exceptions ();
    145 
    146     dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8,
    147 					 WIDTH, HEIGHT,
    148 					 NULL, 0);
    149 
    150     draw_checkerboard (dest_img, 25, 0xffaaaaaa, 0xffbbbbbb);
    151 
    152     pixman_transform_init_identity (&transform);
    153 
    154     /*
    155      * The create_radial() function returns gradients centered in the
    156      * origin and whose interesting part fits a 1x1 square. We want to
    157      * paint these gradients on a SIZExSIZE square and to make things
    158      * easier we want the origin in the top-left corner of the square
    159      * we want to see.
    160      */
    161     pixman_transform_translate (NULL, &transform,
    162 				pixman_double_to_fixed (0.5),
    163 				pixman_double_to_fixed (0.5));
    164 
    165     pixman_transform_scale (NULL, &transform,
    166 			    pixman_double_to_fixed (SIZE),
    167 			    pixman_double_to_fixed (SIZE));
    168 
    169     /*
    170      * Gradients are evaluated at the center of each pixel, so we need
    171      * to translate by half a pixel to trigger some interesting
    172      * cornercases. In particular, the original implementation of PDF
    173      * radial gradients tried to divide by 0 when using this transform
    174      * on the "tangent circles" cases.
    175      */
    176     pixman_transform_translate (NULL, &transform,
    177 				pixman_double_to_fixed (0.5),
    178 				pixman_double_to_fixed (0.5));
    179 
    180     for (i = 0; i < NUM_GRADIENTS; i++)
    181     {
    182 	src_img = create_radial (i);
    183 	pixman_image_set_transform (src_img, &transform);
    184 
    185 	for (j = 0; j < NUM_REPEAT; j++)
    186 	{
    187 	    pixman_image_set_repeat (src_img, repeat[j]);
    188 
    189 	    pixman_image_composite32 (PIXMAN_OP_OVER,
    190 				      src_img,
    191 				      NULL,
    192 				      dest_img,
    193 				      0, 0,
    194 				      0, 0,
    195 				      i * SIZE, j * SIZE,
    196 				      SIZE, SIZE);
    197 
    198 	}
    199 
    200 	pixman_image_unref (src_img);
    201     }
    202 
    203     show_image (dest_img);
    204 
    205     pixman_image_unref (dest_img);
    206 
    207     return 0;
    208 }
    209