xserver/fb fbcompose.c,1.26,1.27 fbpict.c,1.37,1.38

Lars Knoll <xserver-commit-u7BhqnqprCWvj1b/[email protected]> Wed, 29 Jun 2005 04:57:18 -0700 (PDT)
Newsgroups gmane.comp.freedesktop.xserver.cvs
Message-ID <[email protected]>
Committed by: lars

Update of /cvs/xserver/xserver/fb
In directory gabe:/tmp/cvs-serv16798/fb

Modified Files:
	fbcompose.c fbpict.c 
Log Message:
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.



Index: fbcompose.c
===================================================================
RCS file: /cvs/xserver/xserver/fb/fbcompose.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- fbcompose.c	15 Jun 2005 12:13:57 -0000	1.26
+++ fbcompose.c	29 Jun 2005 11:57:16 -0000	1.27
@@ -2635,6 +2635,218 @@
 
 #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;
+                    if (rz != 0) {
+                        x = rx/rz;
+                        y = ry/rz;
+                    } else {
+                        x = y = 0.;
+                    }
+                    x -= pGradient->radial.fx;
+                    y -= pGradient->radial.fy;
+                    double b = 2*(x*pGradient->radial.dx + y*pGradient->radial.dy);
+                    double c = -(x*x + y*y);
+                    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;
+                    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;
+                    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.;
+                    double 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;
@@ -2673,7 +2885,7 @@
 
     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) {
@@ -2740,7 +2952,7 @@
             }
         }
     } 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) {
@@ -2942,7 +3154,7 @@
         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;
 
@@ -2961,13 +3173,13 @@
             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);
@@ -2977,22 +3189,15 @@
                             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) |
@@ -3089,13 +3294,17 @@
     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;
@@ -3103,9 +3312,13 @@
         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;
@@ -3206,17 +3419,19 @@
     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))

Index: fbpict.c
===================================================================
RCS file: /cvs/xserver/xserver/fb/fbpict.c,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -d -r1.37 -r1.38
--- fbpict.c	13 Jun 2005 08:00:58 -0000	1.37
+++ fbpict.c	29 Jun 2005 11:57:16 -0000	1.38
@@ -1362,7 +1362,7 @@
     int		    n;
     BoxPtr	    pbox;
     CompositeFunc   func = 0;
-    Bool	    srcRepeat = pSrc->repeat;
+    Bool	    srcRepeat = pSrc->pDrawable && pSrc->repeat == RepeatNormal;
     Bool	    maskRepeat = FALSE;
     Bool	    srcTransform = pSrc->transform != 0;
     Bool	    maskTransform = FALSE;
@@ -1374,19 +1374,21 @@
 
     xDst += pDst->pDrawable->x;
     yDst += pDst->pDrawable->y;
-    xSrc += pSrc->pDrawable->x;
-    ySrc += pSrc->pDrawable->y;
+    if (pSrc->pDrawable) {
+        xSrc += pSrc->pDrawable->x;
+        ySrc += pSrc->pDrawable->y;
+    }
 
     if (srcRepeat && srcTransform &&
 	pSrc->pDrawable->width == 1 &&
 	pSrc->pDrawable->height == 1)
 	srcTransform = FALSE;
 
-    if (pMask)
+    if (pMask && pMask->pDrawable)
     {
 	xMask += pMask->pDrawable->x;
 	yMask += pMask->pDrawable->y;
-	maskRepeat = pMask->repeat;
+	maskRepeat = pMask->repeat == RepeatNormal;
 	maskTransform = pMask->transform != 0;
 	if (pMask->filter == PictFilterConvolution)
 	    maskTransform = TRUE;
@@ -1399,7 +1401,8 @@
 	    maskTransform = FALSE;
     }
 
-    if (!srcTransform && !maskTransform
+    if (pSrc->pDrawable && (!pMask || pMask->pDrawable)
+        && !srcTransform && !maskTransform
         && !maskAlphaMap && !srcAlphaMap && !dstAlphaMap
         && (pSrc->filter != PictFilterConvolution)
         && (!pMask || pMask->filter != PictFilterConvolution))