summaryrefslogtreecommitdiff
path: root/fb/fbcompose.c
diff options
context:
space:
mode:
authorLars Knoll <lars@trolltech.com>2005-07-01 10:05:43 +0000
committerLars Knoll <lars@trolltech.com>2005-07-01 10:05:43 +0000
commitb5b2a0522efd61bd99b5d5d75cdd27960cd1c7e1 (patch)
tree455e2c8151f463288783b6e4e8fa29939cde4d3c /fb/fbcompose.c
parent30c019e847adef6f7f3963df8ef1f3f994669a54 (diff)
Add support for gradients and solid fills to Render.
Changed the semantics of the Convolution filter a bit. It now doesn't try to normalize the filter values but leaves this to the client. This gives more reasonable behaviour in the limit where the filter parameters sum up to 0.
Diffstat (limited to 'fb/fbcompose.c')
-rw-r--r--fb/fbcompose.c267
1 files changed, 242 insertions, 25 deletions
diff --git a/fb/fbcompose.c b/fb/fbcompose.c
index 2bfe5ca3a..394c349e8 100644
--- a/fb/fbcompose.c
+++ b/fb/fbcompose.c
@@ -34,6 +34,7 @@
#include "picturestr.h"
#include "mipict.h"
#include "fbpict.h"
+#include <math.h>
#define mod(a,b) ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
@@ -2636,6 +2637,219 @@ static void fbFetch(PicturePtr pict, int x, int y, int width, CARD32 *buffer)
#define MOD(a,b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b))
+
+static CARD32 gradientPixel(const SourcePictPtr pGradient, xFixed_48_16 pos, unsigned int spread)
+{
+ int ipos = (pos * PICT_GRADIENT_STOPTABLE_SIZE - 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;
+
+ } 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 == RepeatPad) {
+ if (ipos < 0)
+ ipos = 0;
+ else if (ipos >= PICT_GRADIENT_STOPTABLE_SIZE)
+ ipos = PICT_GRADIENT_STOPTABLE_SIZE-1;
+ } else { /* RepeatNone */
+ return 0;
+ }
+ }
+
+ assert(ipos >= 0);
+ assert(ipos < PICT_GRADIENT_STOPTABLE_SIZE);
+
+ return pGradient->linear.colorTable[ipos];
+}
+
+static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *buffer)
+{
+ SourcePictPtr pGradient = pict->pSourcePict;
+ CARD32 *end = buffer + width;
+
+ if (pGradient->type == SourcePictTypeSolidFill) {
+ register CARD32 color = pGradient->solidFill.color;
+ while (buffer < end) {
+ *buffer++ = color;
+ }
+ } else if (pGradient->type == SourcePictTypeLinear) {
+ PictVector v, unit;
+ xFixed_32_32 l;
+ xFixed_48_16 dx, dy, a, b, off;
+
+ v.vector[0] = IntToxFixed(x);
+ v.vector[1] = IntToxFixed(y);
+ v.vector[2] = xFixed1;
+ if (pict->transform) {
+ if (!PictureTransformPoint3d (pict->transform, &v))
+ return;
+ unit.vector[0] = pict->transform->matrix[0][0];
+ unit.vector[1] = pict->transform->matrix[1][0];
+ unit.vector[2] = pict->transform->matrix[2][0];
+ } else {
+ unit.vector[0] = xFixed1;
+ unit.vector[1] = 0;
+ unit.vector[2] = 0;
+ }
+
+ dx = pGradient->linear.p2.x - pGradient->linear.p1.x;
+ dy = pGradient->linear.p2.y - pGradient->linear.p1.y;
+ l = dx*dx + dy*dy;
+ if (l != 0) {
+ a = (dx << 32) / l;
+ b = (dy << 32) / l;
+ off = (-a*pGradient->linear.p1.x - b*pGradient->linear.p1.y)>>16;
+ }
+ if (l == 0 || (unit.vector[2] == 0 && v.vector[2] == xFixed1)) {
+ xFixed_48_16 inc, t;
+ /* affine transformation only */
+ if (l == 0) {
+ t = 0;
+ inc = 0;
+ } else {
+ t = ((a*v.vector[0] + b*v.vector[1]) >> 16) + off;
+ inc = (a * unit.vector[0] + b * unit.vector[1]) >> 16;
+ }
+ while (buffer < end) {
+ *buffer++ = gradientPixel(pGradient, t, pict->repeat);
+ t += inc;
+ }
+ } else {
+ /* projective transformation */
+ while (buffer < end) {
+ xFixed_48_16 t;
+ if (v.vector[2] == 0) {
+ t = 0;
+ } else {
+ xFixed_48_16 x, y;
+ x = ((xFixed_48_16)v.vector[0] << 16) / v.vector[2];
+ y = ((xFixed_48_16)v.vector[1] << 16) / v.vector[2];
+ t = ((a*x + b*y) >> 16) + off;
+ }
+ *buffer++ = gradientPixel(pGradient, t, pict->repeat);
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
+ }
+ }
+ } else {
+ /* radial or conical */
+ Bool projective = FALSE;
+ double cx = 1.;
+ double cy = 0.;
+ double cz = 0.;
+ double rx = x;
+ double ry = y;
+ double rz = 1.;
+
+ if (pict->transform) {
+ PictVector v;
+ v.vector[0] = IntToxFixed(x);
+ v.vector[1] = IntToxFixed(y);
+ v.vector[2] = xFixed1;
+ if (!PictureTransformPoint3d (pict->transform, &v))
+ return;
+
+ cx = pict->transform->matrix[0][0]/65536.;
+ cy = pict->transform->matrix[1][0]/65536.;
+ cz = pict->transform->matrix[2][0]/65536.;
+ rx = v.vector[0]/65536.;
+ ry = v.vector[1]/65536.;
+ rz = v.vector[2]/65536.;
+ projective = pict->transform->matrix[2][0] != 0 || v.vector[2] != xFixed1;
+ }
+
+ if (pGradient->type == SourcePictTypeRadial) {
+ if (!projective) {
+ rx -= pGradient->radial.fx;
+ ry -= pGradient->radial.fy;
+
+ while (buffer < end) {
+ double b = 2*(rx*pGradient->radial.dx + ry*pGradient->radial.dy);
+ double c = -(rx*rx + ry*ry);
+ double det = (b * b) - (4 * pGradient->radial.a * c);
+ double s = (-b + sqrt(det))/(2. * pGradient->radial.a);
+ *buffer = gradientPixel(pGradient,
+ (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536),
+ pict->repeat);
+ ++buffer;
+ rx += cx;
+ ry += cy;
+ }
+ } else {
+ while (buffer < end) {
+ double x, y;
+ double b, c, det, s;
+ if (rz != 0) {
+ x = rx/rz;
+ y = ry/rz;
+ } else {
+ x = y = 0.;
+ }
+ x -= pGradient->radial.fx;
+ y -= pGradient->radial.fy;
+ b = 2*(x*pGradient->radial.dx + y*pGradient->radial.dy);
+ c = -(x*x + y*y);
+ det = (b * b) - (4 * pGradient->radial.a * c);
+ s = (-b + sqrt(det))/(2. * pGradient->radial.a);
+ *buffer = gradientPixel(pGradient,
+ (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536),
+ pict->repeat);
+ ++buffer;
+ rx += cx;
+ ry += cy;
+ rz += cz;
+ }
+ }
+ } else /* SourcePictTypeConical */ {
+ double a = pGradient->conical.angle/(180.*65536);
+ if (!projective) {
+ rx -= pGradient->conical.center.x/65536.;
+ ry -= pGradient->conical.center.y/65536.;
+
+ while (buffer < end) {
+ double angle = atan2(ry, rx) + a;
+ *buffer = gradientPixel(pGradient, (xFixed_48_16) (angle * (65536. / (2*M_PI))),
+ pict->repeat);
+ ++buffer;
+ rx += cx;
+ ry += cy;
+ }
+ } else {
+
+ while (buffer < end) {
+ double x, y, angle;
+ if (rz != 0) {
+ x = rx/rz;
+ y = ry/rz;
+ } else {
+ x = y = 0.;
+ }
+ x -= pGradient->conical.center.x/65536.;
+ y -= pGradient->conical.center.y/65536.;
+ angle = atan2(y, x) + a;
+ *buffer = gradientPixel(pGradient, (xFixed_48_16) (angle * (65536. / (2*M_PI))),
+ pict->repeat);
+ ++buffer;
+ rx += cx;
+ ry += cy;
+ rz += cz;
+ }
+ }
+ }
+ }
+}
+
+
+
static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32 *buffer)
{
FbBits *bits;
@@ -2674,7 +2888,7 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32
if (pict->filter == PictFilterNearest)
{
- if (pict->repeat) {
+ if (pict->repeat == RepeatNormal) {
if (REGION_NUM_RECTS(pict->pCompositeClip) == 1) {
box = pict->pCompositeClip->extents;
for (i = 0; i < width; ++i) {
@@ -2741,7 +2955,7 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32
}
}
} else if (pict->filter == PictFilterBilinear) {
- if (pict->repeat) {
+ if (pict->repeat == RepeatNormal) {
if (REGION_NUM_RECTS(pict->pCompositeClip) == 1) {
box = pict->pCompositeClip->extents;
for (i = 0; i < width; ++i) {
@@ -2943,7 +3157,7 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32
params += 2;
for (i = 0; i < width; ++i) {
int x1, x2, y1, y2, x, y;
- INT32 srtot, sgtot, sbtot, satot, sum;
+ INT32 srtot, sgtot, sbtot, satot;
xFixed *p = params;
xFixed_48_16 tmp;
@@ -2962,13 +3176,13 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32
y1 = xFixedToInt(tmp);
y2 = y1 + cheight;
- srtot = sgtot = sbtot = satot = sum = 0;
+ srtot = sgtot = sbtot = satot = 0;
for (y = y1; y < y2; y++) {
- int ty = (pict->repeat) ? MOD (y, pict->pDrawable->height) : y;
+ int ty = (pict->repeat == RepeatNormal) ? MOD (y, pict->pDrawable->height) : y;
for (x = x1; x < x2; x++) {
if (*p) {
- int tx = (pict->repeat) ? MOD (x, pict->pDrawable->width) : x;
+ int tx = (pict->repeat == RepeatNormal) ? MOD (x, pict->pDrawable->width) : x;
if (POINT_IN_REGION (0, pict->pCompositeClip, tx, ty, &box)) {
FbBits *b = bits + (ty + pict->pDrawable->y)*stride;
CARD32 c = fetch(b, tx + pict->pDrawable->x, indexed);
@@ -2978,22 +3192,15 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32
sbtot += Blue(c) * *p;
satot += Alpha(c) * *p;
}
- sum += *p;
}
p++;
}
}
- if (sum) {
- satot /= sum;
- srtot /= sum;
- sgtot /= sum;
- sbtot /= sum;
- }
if (satot < 0) satot = 0; else if (satot > 0xff) satot = 0xff;
- if (srtot < 0) srtot = 0; else if (srtot > 0xff) srtot = 0xff;
- if (sgtot < 0) sgtot = 0; else if (sgtot > 0xff) sgtot = 0xff;
- if (sbtot < 0) sbtot = 0; else if (sbtot > 0xff) sbtot = 0xff;
+ if (srtot < 0) srtot = 0; else if (srtot > satot) srtot = satot;
+ if (sgtot < 0) sgtot = 0; else if (sgtot > satot) sgtot = satot;
+ if (sbtot < 0) sbtot = 0; else if (sbtot > satot) sbtot = satot;
buffer[i] = ((satot << 24) |
(srtot << 16) |
@@ -3094,13 +3301,17 @@ fbCompositeRect (const FbComposeData *data, CARD32 *scanline_buffer)
CARD32 *dest_buffer = src_buffer + data->width;
int i;
scanStoreProc store;
- scanFetchProc fetchSrc, fetchMask, fetchDest;
+ scanFetchProc fetchSrc = 0, fetchMask = 0, fetchDest = 0;
if (data->op == PictOpClear)
fetchSrc = 0;
- else if (data->src->alphaMap)
+ else if (!data->src->pDrawable) {
+ if (data->src->pSourcePict)
+ fetchSrc = fbFetchSourcePict;
+ } else if (data->src->alphaMap)
fetchSrc = fbFetchExternalAlpha;
- else if (data->src->repeat && data->src->pDrawable->width == 1 && data->src->pDrawable->height == 1)
+ else if (data->src->repeat == RepeatNormal &&
+ data->src->pDrawable->width == 1 && data->src->pDrawable->height == 1)
fetchSrc = fbFetchSolid;
else if (!data->src->transform && data->src->filter != PictFilterConvolution)
fetchSrc = fbFetch;
@@ -3108,9 +3319,13 @@ fbCompositeRect (const FbComposeData *data, CARD32 *scanline_buffer)
fetchSrc = fbFetchTransformed;
if (data->mask && data->op != PictOpClear) {
- if (data->mask->alphaMap)
+ if (!data->mask->pDrawable) {
+ if (data->mask->pSourcePict)
+ fetchMask = fbFetchSourcePict;
+ } else if (data->mask->alphaMap)
fetchMask = fbFetchExternalAlpha;
- else if (data->mask->repeat && data->mask->pDrawable->width == 1 && data->mask->pDrawable->height == 1)
+ else if (data->mask->repeat == RepeatNormal
+ && data->mask->pDrawable->width == 1 && data->mask->pDrawable->height == 1)
fetchMask = fbFetchSolid;
else if (!data->mask->transform && data->mask->filter != PictFilterConvolution)
fetchMask = fbFetch;
@@ -3211,17 +3426,19 @@ fbCompositeGeneral (CARD8 op,
RegionRec region;
int n;
BoxPtr pbox;
- Bool srcRepeat = pSrc->repeat && !pSrc->transform
- && (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1);
+ Bool srcRepeat = FALSE;
Bool maskRepeat = FALSE;
int w, h;
CARD32 _scanline_buffer[SCANLINE_BUFFER_LENGTH*3];
CARD32 *scanline_buffer = _scanline_buffer;
FbComposeData compose_data;
+ if (pSrc->pDrawable)
+ srcRepeat = pSrc->repeat == RepeatNormal && !pSrc->transform
+ && (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1);
- if (pMask)
- maskRepeat = pMask->repeat && !pMask->transform
+ if (pMask && pMask->pDrawable)
+ maskRepeat = pMask->repeat == RepeatNormal && !pMask->transform
&& (pMask->pDrawable->width != 1 || pMask->pDrawable->height != 1);
if (op == PictOpOver && !pMask && !pSrc->transform && !PICT_FORMAT_A(pSrc->format))