Originally: 2005-10-10 David Reveman <davidr@novell.com>

Add entries for gradient support.
Add PictureGradientColor.
Add necessary functionality for gradient support.
Enable gradient support.
This commit is contained in:
Carl Worth 2006-01-04 16:26:10 +00:00
parent c6cdfc5770
commit 305a83721f
6 changed files with 508 additions and 53 deletions

View file

@ -1,3 +1,16 @@
2006-01-04 Carl Worth <cworth@cworth.org>
Originally: 2005-10-10 David Reveman <davidr@novell.com>
* src/pixman.h: Add entries for gradient support.
* src/icint.h: Add PictureGradientColor.
* src/icimage.h:
* src/icimage.c: Add necessary functionality for gradient support.
* src/fbcompose.c: Enable gradient support.
2005-11-21 Carl Worth <cworth@cworth.org>
* src/pixman-remap.h: Remove duplicate definitions of

View file

@ -33,8 +33,9 @@
#include "pixregionint.h"
#include <math.h>
// #define PIXMAN_CONVOLUTION
// #define PIXMAN_GRADIENTS
// #define PIXMAN_INDEXED_FORMATS
static Bool
@ -2676,37 +2677,72 @@ static void fbFetch(PicturePtr pict, int x, int y, int width, CARD32 *buffer)
#define DIV(a,b) ((((a) < 0) == ((b) < 0)) ? (a) / (b) :\
((a) - (b) + 1 - (((b) < 0) << 1)) / (b))
#ifdef PIXMAN_GRADIENTS
static CARD32
xRenderColorMultToCard32 (pixman_color_t *c)
{
return
((((uint32_t) c->red * c->alpha) >> 24) << 16) |
((((uint32_t) c->green * c->alpha) >> 24) << 8) |
((((uint32_t) c->blue * c->alpha) >> 24) << 0) |
((((uint32_t) c->alpha ) >> 8) << 24);
}
static CARD32 gradientPixel(const SourcePictPtr pGradient, xFixed_48_16 pos, unsigned int spread)
{
int ipos = (pos * PICT_GRADIENT_STOPTABLE_SIZE - 1) >> 16;
int ipos = (pos * pGradient->gradient.stopRange - 1) >> 16;
/* calculate the actual offset. */
if (ipos < 0 || ipos >= PICT_GRADIENT_STOPTABLE_SIZE) {
if (pGradient->type == SourcePictTypeConical || spread == RepeatNormal) {
ipos = ipos % PICT_GRADIENT_STOPTABLE_SIZE;
ipos = ipos < 0 ? PICT_GRADIENT_STOPTABLE_SIZE + ipos : ipos;
if (ipos < 0 || ipos >= pGradient->gradient.stopRange)
{
if (pGradient->type == SourcePictTypeConical || spread == RepeatNormal)
{
ipos = ipos % pGradient->gradient.stopRange;
ipos = ipos < 0 ? pGradient->gradient.stopRange + ipos : ipos;
} else if (spread == RepeatReflect) {
const int limit = PICT_GRADIENT_STOPTABLE_SIZE * 2 - 1;
ipos = ipos % limit;
ipos = ipos < 0 ? limit + ipos : ipos;
ipos = ipos >= PICT_GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos;
}
else if (spread == RepeatReflect)
{
const int limit = pGradient->gradient.stopRange * 2 - 1;
} else if (spread == RepeatPad) {
if (ipos < 0)
ipos = 0;
else if (ipos >= PICT_GRADIENT_STOPTABLE_SIZE)
ipos = PICT_GRADIENT_STOPTABLE_SIZE-1;
} else { /* RepeatNone */
return 0;
}
ipos = ipos % limit;
ipos = ipos < 0 ? limit + ipos : ipos;
ipos = ipos >= pGradient->gradient.stopRange ? limit - ipos : ipos;
}
else if (spread == RepeatPad)
{
if (ipos < 0)
ipos = 0;
else
ipos = pGradient->gradient.stopRange - 1;
}
else /* RepeatNone */
{
return 0;
}
}
assert(ipos >= 0);
assert(ipos < PICT_GRADIENT_STOPTABLE_SIZE);
if (pGradient->gradient.colorTableSize)
{
return pGradient->gradient.colorTable[ipos];
}
else
{
int i;
return pGradient->linear.colorTable[ipos];
if (ipos <= pGradient->gradient.stops->x)
return xRenderColorMultToCard32 (&pGradient->gradient.stops->color);
for (i = 1; i < pGradient->gradient.nstops; i++)
{
if (pGradient->gradient.stops[i].x >= ipos)
return PictureGradientColor (&pGradient->gradient.stops[i - 1],
&pGradient->gradient.stops[i],
ipos);
}
return xRenderColorMultToCard32 (&pGradient->gradient.stops[--i].color);
}
}
static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *buffer)
@ -2886,7 +2922,6 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *
}
}
}
#endif /* PIXMAN_GRADIENTS */
static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32 *buffer)
@ -3457,10 +3492,8 @@ fbCompositeRect (const FbComposeData *data, CARD32 *scanline_buffer)
if (data->op == PIXMAN_OPERATOR_CLEAR)
fetchSrc = NULL;
else if (!data->src->pDrawable) {
#ifdef PIXMAN_GRADIENTS
if (data->src->pSourcePict)
fetchSrc = fbFetchSourcePict;
#endif
} else if (data->src->alphaMap)
fetchSrc = fbFetchExternalAlpha;
else if (data->src->repeat == RepeatNormal &&
@ -3478,10 +3511,8 @@ fbCompositeRect (const FbComposeData *data, CARD32 *scanline_buffer)
if (data->mask && data->op != PIXMAN_OPERATOR_CLEAR) {
if (!data->mask->pDrawable) {
#ifdef PIXMAN_GRADIENTS
if (data->mask->pSourcePict)
fetchMask = fbFetchSourcePict;
#endif
} else if (data->mask->alphaMap)
fetchMask = fbFetchExternalAlpha;
else if (data->mask->repeat == RepeatNormal

View file

@ -101,6 +101,273 @@ pixman_image_createForPixels (FbPixels *pixels,
return image;
}
static CARD32 xRenderColorToCard32(pixman_color_t c)
{
return
(c.alpha >> 8 << 24) |
(c.red >> 8 << 16) |
(c.green & 0xff00) |
(c.blue >> 8);
}
static uint premultiply(uint x)
{
uint a = x >> 24;
uint t = (x & 0xff00ff) * a + 0x800080;
t = (t + ((t >> 8) & 0xff00ff)) >> 8;
t &= 0xff00ff;
x = ((x >> 8) & 0xff) * a + 0x80;
x = (x + ((x >> 8) & 0xff));
x &= 0xff00;
x |= t | (a << 24);
return x;
}
static uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b)
{
CARD32 t = (x & 0xff00ff) * a + (y & 0xff00ff) * b;
t >>= 8;
t &= 0xff00ff;
x = ((x >> 8) & 0xff00ff) * a + ((y >> 8) & 0xff00ff) * b;
x &= 0xff00ff00;
x |= t;
return x;
}
uint32_t
pixman_gradient_color (pixman_gradient_stop_t *stop1,
pixman_gradient_stop_t *stop2,
uint32_t x)
{
uint32_t current_color, next_color;
int dist, idist;
current_color = xRenderColorToCard32 (stop1->color);
next_color = xRenderColorToCard32 (stop2->color);
dist = (int) (256 * (x - stop1->x) / (stop2->x - stop1->x));
idist = 256 - dist;
return premultiply (INTERPOLATE_PIXEL_256 (current_color, idist,
next_color, dist));
}
static int
pixman_init_gradient_color_table (pixman_gradient_image_t *gradient,
int tableSize)
{
int begin_pos, end_pos;
xFixed incr, dpos;
int pos, current_stop;
pixman_gradient_stop_t *stops = gradient->stops;
int nstops = gradient->nstops;
if (gradient->colorTableSize < tableSize)
{
uint32_t *newColorTable;
newColorTable = realloc (gradient->colorTable,
tableSize * sizeof (uint32_t));
if (!newColorTable)
return 1;
gradient->colorTable = newColorTable;
gradient->colorTableSize = tableSize;
}
gradient->stopRange = tableSize;
/* The position where the gradient begins and ends */
begin_pos = (stops[0].x * gradient->colorTableSize) >> 16;
end_pos = (stops[nstops - 1].x * gradient->colorTableSize) >> 16;
pos = 0; /* The position in the color table. */
/* Up to first point */
while (pos <= begin_pos) {
gradient->colorTable[pos] = xRenderColorToCard32(stops[0].color);
++pos;
}
incr = (1<<16)/ gradient->colorTableSize; /* the double increment. */
dpos = incr * pos; /* The position in terms of 0-1. */
current_stop = 0; /* We always interpolate between current and current + 1. */
/* Gradient area */
while (pos < end_pos) {
gradient->colorTable[pos] =
pixman_gradient_color (&stops[current_stop],
&stops[current_stop + 1],
dpos);
++pos;
dpos += incr;
if (dpos > stops[current_stop + 1].x)
++current_stop;
}
/* After last point */
while (pos < gradient->colorTableSize) {
gradient->colorTable[pos] =
xRenderColorToCard32 (stops[nstops - 1].color);
++pos;
}
return 0;
}
static int
_pixman_init_gradient (pixman_gradient_image_t *gradient,
const pixman_gradient_stop_t *stops,
int n_stops)
{
pixman_fixed16_16_t dpos;
int i;
if (n_stops <= 0)
return 1;
dpos = -1;
for (i = 0; i < n_stops; i++)
{
if (stops[i].x < dpos || stops[i].x > (1 << 16))
return 1;
dpos = stops[i].x;
}
gradient->stopRange = 0xffff;
gradient->colorTable = NULL;
gradient->colorTableSize = 0;
return 0;
}
static pixman_image_t *
_pixman_create_source_image (void)
{
pixman_image_t *image;
image = (pixman_image_t *) malloc (sizeof (pixman_image_t));
image->pDrawable = 0;
image->pixels = 0;
pixman_image_init (image);
return image;
}
pixman_image_t *
pixman_image_create_linear_gradient (const pixman_linear_gradient_t *gradient,
const pixman_gradient_stop_t *stops,
int n_stops)
{
pixman_linear_gradient_image_t *linear;
pixman_image_t *image;
if (n_stops < 2)
return 0;
image = _pixman_create_source_image ();
if (!image)
return 0;
if (gradient->p1.x == gradient->p2.x && gradient->p1.y == gradient->p2.y)
return 0;
linear = malloc (sizeof (pixman_linear_gradient_image_t) +
sizeof (pixman_gradient_stop_t) * n_stops);
if (!linear)
{
free (image);
return 0;
}
linear->stops = (pixman_gradient_stop_t *) (linear + 1);
linear->nstops = n_stops;
memcpy (linear->stops, stops, sizeof (pixman_gradient_stop_t) * n_stops);
linear->type = SourcePictTypeLinear;
linear->p1 = gradient->p1;
linear->p2 = gradient->p2;
image->pSourcePict = (pixman_source_image_t *) linear;
if (_pixman_init_gradient (&image->pSourcePict->gradient, stops, n_stops))
{
free (image);
return 0;
}
return image;
}
pixman_image_t *
pixman_image_create_radial_gradient (const pixman_radial_gradient_t *gradient,
const pixman_gradient_stop_t *stops,
int n_stops)
{
pixman_radial_gradient_image_t *radial;
pixman_image_t *image;
double dx, dy, x;
if (n_stops < 2)
return 0;
image = _pixman_create_source_image ();
if (!image)
return 0;
dx = (double) (gradient->inner.x - gradient->outer.x);
dy = (double) (gradient->inner.y - gradient->outer.y);
if (sqrt (dx * dx + dy * dy) + (double) (gradient->inner.radius) >
(double) (gradient->outer.radius))
return 0;
radial = malloc (sizeof (pixman_radial_gradient_image_t) +
sizeof (pixman_gradient_stop_t) * n_stops);
if (!radial)
{
free (image);
return 0;
}
radial->stops = (pixman_gradient_stop_t *) (radial + 1);
radial->nstops = n_stops;
memcpy (radial->stops, stops, sizeof (pixman_gradient_stop_t) * n_stops);
radial->type = SourcePictTypeRadial;
x = (double) gradient->inner.radius / (double) gradient->outer.radius;
radial->dx = (gradient->outer.x - gradient->inner.x);
radial->dy = (gradient->outer.y - gradient->inner.y);
radial->fx = (gradient->inner.x) - x * radial->dx;
radial->fy = (gradient->inner.y) - x * radial->dy;
radial->m = 1. / (1 + x);
radial->b = -x * radial->m;
radial->dx /= 65536.;
radial->dy /= 65536.;
radial->fx /= 65536.;
radial->fy /= 65536.;
x = gradient->outer.radius / 65536.;
radial->a = x * x - radial->dx * radial->dx - radial->dy * radial->dy;
image->pSourcePict = (pixman_source_image_t *) radial;
if (_pixman_init_gradient (&image->pSourcePict->gradient, stops, n_stops))
{
free (image);
return 0;
}
return image;
}
void
pixman_image_init (pixman_image_t *image)
{
@ -135,16 +402,26 @@ pixman_image_init (pixman_image_t *image)
image->serialNumber = GC_CHANGE_SERIAL_BIT;
*/
image->pCompositeClip = pixman_region_create();
pixman_region_union_rect (image->pCompositeClip, image->pCompositeClip,
0, 0, image->pixels->width, image->pixels->height);
image->freeCompClip = 1;
if (image->pixels)
{
image->pCompositeClip = pixman_region_create();
pixman_region_union_rect (image->pCompositeClip, image->pCompositeClip,
0, 0, image->pixels->width,
image->pixels->height);
image->freeCompClip = 1;
image->pSourceClip = pixman_region_create ();
pixman_region_union_rect (image->pSourceClip, image->pSourceClip,
0, 0, image->pixels->width,
image->pixels->height);
image->freeSourceClip = 1;
}
else
{
image->pCompositeClip = NULL;
image->pSourceClip = NULL;
}
image->pSourceClip = pixman_region_create ();
pixman_region_union_rect (image->pSourceClip, image->pSourceClip,
0, 0, image->pixels->width, image->pixels->height);
image->freeSourceClip = 1;
image->transform = NULL;
image->filter = PIXMAN_FILTER_NEAREST;
@ -153,6 +430,8 @@ pixman_image_init (pixman_image_t *image)
image->owns_pixels = 0;
image->pSourcePict = NULL;
}
void
@ -218,25 +497,37 @@ pixman_image_set_filter (pixman_image_t *image,
int
pixman_image_get_width (pixman_image_t *image)
{
return image->pixels->width;
if (image->pixels)
return image->pixels->width;
return 0;
}
int
pixman_image_get_height (pixman_image_t *image)
{
return image->pixels->height;
if (image->pixels)
return image->pixels->height;
return 0;
}
int
pixman_image_get_depth (pixman_image_t *image)
{
return image->pixels->depth;
if (image->pixels)
return image->pixels->depth;
return 0;
}
int
pixman_image_get_stride (pixman_image_t *image)
{
return image->pixels->stride;
if (image->pixels)
return image->pixels->stride;
return 0;
}
pixman_format_t *
@ -248,7 +539,10 @@ pixman_image_get_format (pixman_image_t *image)
FbBits *
pixman_image_get_data (pixman_image_t *image)
{
return image->pixels->data;
if (image->pixels)
return image->pixels->data;
return 0;
}
void
@ -276,6 +570,11 @@ pixman_image_destroy (pixman_image_t *image)
image->transform = NULL;
}
if (image->pSourcePict) {
free (image->pSourcePict);
image->pSourcePict = NULL;
}
free (image);
}
slim_hidden_def(pixman_image_destroy);
@ -307,6 +606,10 @@ pixman_image_set_clip_region (pixman_image_t *image,
pixman_region_copy (image->clientClip, region);
image->clientClipType = CT_REGION;
}
image->stateChanges |= CPClipMask;
if (image->pSourcePict)
return 0;
if (image->freeCompClip)
pixman_region_destroy (image->pCompositeClip);
@ -326,7 +629,6 @@ pixman_image_set_clip_region (pixman_image_t *image,
image->clipOrigin.y);
}
image->stateChanges |= CPClipMask;
return 0;
}
@ -378,7 +680,7 @@ FbClipImageSrc (pixman_region16_t *region,
if (image->transform)
return 1;
/* XXX davidr hates this, wants to never use source-based clipping */
if (image->repeat != PIXMAN_REPEAT_NONE)
if (image->repeat != PIXMAN_REPEAT_NONE || image->pSourcePict)
{
/* XXX no source clipping */
if (image->compositeClipSource &&

View file

@ -54,6 +54,76 @@ typedef struct pixman_format {
} pixman_format_t;
*/
#define PICT_GRADIENT_STOPTABLE_SIZE 1024
#define SourcePictTypeSolidFill 0
#define SourcePictTypeLinear 1
#define SourcePictTypeRadial 2
#define SourcePictTypeConical 3
typedef struct _pixman_solid_fill_image {
unsigned int type;
uint32_t color;
} pixman_solid_fill_image_t;
typedef struct _pixman_gradient_image {
unsigned int type;
pixman_gradient_stop_t *stops;
int nstops;
int stopRange;
uint32_t *colorTable;
int colorTableSize;
} pixman_gradient_image_t;
typedef struct _pixman_linear_gradient_image {
unsigned int type;
pixman_gradient_stop_t *stops;
int nstops;
int stopRange;
uint32_t *colorTable;
int colorTableSize;
pixman_point_fixed_t p1;
pixman_point_fixed_t p2;
} pixman_linear_gradient_image_t;
typedef struct _pixman_radial_gradient_image {
unsigned int type;
pixman_gradient_stop_t *stops;
int nstops;
int stopRange;
uint32_t *colorTable;
int colorTableSize;
double fx;
double fy;
double dx;
double dy;
double a;
double m;
double b;
} pixman_radial_gradient_image_t;
typedef struct _pixman_conical_gradient_image {
unsigned int type;
pixman_gradient_stop_t *stops;
int nstops;
int stopRange;
uint32_t *colorTable;
int colorTableSize;
pixman_point_fixed_t center;
pixman_fixed16_16_t angle;
} pixman_conical_gradient_image_t;
typedef union _pixman_source_image {
unsigned int type;
pixman_solid_fill_image_t solidFill;
pixman_gradient_image_t gradient;
pixman_linear_gradient_image_t linear;
pixman_radial_gradient_image_t radial;
pixman_conical_gradient_image_t conical;
} pixman_source_image_t;
typedef pixman_source_image_t *SourcePictPtr;
struct pixman_image {
FbPixels *pixels;
pixman_format_t image_format;
@ -93,6 +163,8 @@ struct pixman_image {
int filter_nparams;
int owns_pixels;
pixman_source_image_t *pSourcePict;
};
#endif /* _ICIMAGE_H_ */

View file

@ -835,6 +835,13 @@ pixman_private pixman_image_t *
pixman_image_createForPixels (FbPixels *pixels,
pixman_format_t *format);
pixman_private uint32_t
pixman_gradient_color (pixman_gradient_stop_t *stop1,
pixman_gradient_stop_t *stop2,
uint32_t x);
#define PictureGradientColor pixman_gradient_color
/* icpixels.c */
pixman_private FbPixels *

View file

@ -54,7 +54,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
/* $Id: pixman.h,v 1.24 2005-10-09 16:09:53 vektor Exp $ */
/* $Id: pixman.h,v 1.25 2006-01-05 00:26:10 cworth Exp $ */
/* libic.h */
@ -332,6 +332,34 @@ typedef struct pixman_transform {
pixman_fixed16_16_t matrix[3][3];
} pixman_transform_t;
typedef struct pixman_color {
unsigned short red;
unsigned short green;
unsigned short blue;
unsigned short alpha;
} pixman_color_t;
typedef struct _pixman_gradient_stop {
pixman_fixed16_16_t x;
pixman_color_t color;
} pixman_gradient_stop_t;
typedef struct _pixman_circle {
pixman_fixed16_16_t x;
pixman_fixed16_16_t y;
pixman_fixed16_16_t radius;
} pixman_circle_t;
typedef struct pixman_linear_gradient {
pixman_point_fixed_t p1;
pixman_point_fixed_t p2;
} pixman_linear_gradient_t;
typedef struct pixman_radial_gradient {
pixman_circle_t inner;
pixman_circle_t outer;
} pixman_radial_gradient_t;
typedef enum {
PIXMAN_FILTER_FAST,
PIXMAN_FILTER_GOOD,
@ -382,15 +410,17 @@ pixman_image_get_format (pixman_image_t *image);
pixman_bits_t *
pixman_image_get_data (pixman_image_t *image);
/* iccolor.c */
pixman_image_t *
pixman_image_create_linear_gradient (const pixman_linear_gradient_t *gradient,
const pixman_gradient_stop_t *stops,
int n_stops);
/* XXX: Do we really need a struct here? Only pixman_rectangle_t uses this. */
typedef struct pixman_color {
unsigned short red;
unsigned short green;
unsigned short blue;
unsigned short alpha;
} pixman_color_t;
pixman_image_t *
pixman_image_create_radial_gradient (const pixman_radial_gradient_t *gradient,
const pixman_gradient_stop_t *stops,
int n_stops);
/* iccolor.c */
void
pixman_color_to_pixel (const pixman_format_t *format,