From 305a83721f5c6423fc1e7fbb0cf1d67c0f92ecb7 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Wed, 4 Jan 2006 16:26:10 +0000 Subject: [PATCH] Originally: 2005-10-10 David Reveman Add entries for gradient support. Add PictureGradientColor. Add necessary functionality for gradient support. Enable gradient support. --- pixman/ChangeLog | 13 ++ pixman/src/fbcompose.c | 87 +++++++---- pixman/src/icimage.c | 334 +++++++++++++++++++++++++++++++++++++++-- pixman/src/icimage.h | 72 +++++++++ pixman/src/icint.h | 7 + pixman/src/pixman.h | 48 ++++-- 6 files changed, 508 insertions(+), 53 deletions(-) diff --git a/pixman/ChangeLog b/pixman/ChangeLog index 50b57a898..37395ecae 100644 --- a/pixman/ChangeLog +++ b/pixman/ChangeLog @@ -1,3 +1,16 @@ +2006-01-04 Carl Worth + + Originally: 2005-10-10 David Reveman + + * 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 * src/pixman-remap.h: Remove duplicate definitions of diff --git a/pixman/src/fbcompose.c b/pixman/src/fbcompose.c index fe0766242..fa151cb9d 100644 --- a/pixman/src/fbcompose.c +++ b/pixman/src/fbcompose.c @@ -33,8 +33,9 @@ #include "pixregionint.h" +#include + // #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 diff --git a/pixman/src/icimage.c b/pixman/src/icimage.c index 52cdd9634..b50bcff75 100644 --- a/pixman/src/icimage.c +++ b/pixman/src/icimage.c @@ -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 && diff --git a/pixman/src/icimage.h b/pixman/src/icimage.h index f80dd0f48..8ca73bff4 100644 --- a/pixman/src/icimage.h +++ b/pixman/src/icimage.h @@ -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_ */ diff --git a/pixman/src/icint.h b/pixman/src/icint.h index 5e6367e8f..81b2756f0 100644 --- a/pixman/src/icint.h +++ b/pixman/src/icint.h @@ -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 * diff --git a/pixman/src/pixman.h b/pixman/src/pixman.h index a03453ee5..bd5194eb1 100644 --- a/pixman/src/pixman.h +++ b/pixman/src/pixman.h @@ -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,