pixman-gradient-walker.c revision 1176bdada62cabc6ec4b0308a930e83b679d5d36
11176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/*
21176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
31176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
41176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *             2005 Lars Knoll & Zack Rusin, Trolltech
51176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
61176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Permission to use, copy, modify, distribute, and sell this software and its
71176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * documentation for any purpose is hereby granted without fee, provided that
81176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * the above copyright notice appear in all copies and that both that
91176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * copyright notice and this permission notice appear in supporting
101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * documentation, and that the name of Keith Packard not be used in
111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * advertising or publicity pertaining to distribution of the software without
121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * specific, written prior permission.  Keith Packard makes no
131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * representations about the suitability of this software for any purpose.  It
141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * is provided "as is" without express or implied warranty.
151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * SOFTWARE.
241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */
251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#ifdef HAVE_CONFIG_H
271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <config.h>
281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif
291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include "pixman-private.h"
301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
311176bdada62cabc6ec4b0308a930e83b679d5d36John Reckvoid
321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck_pixman_gradient_walker_init (pixman_gradient_walker_t *walker,
331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck                              gradient_t *              gradient,
341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck                              pixman_repeat_t		repeat)
351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->num_stops = gradient->n_stops;
371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->stops     = gradient->stops;
381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->left_x    = 0;
391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->right_x   = 0x10000;
401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->a_s       = 0.0f;
411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->a_b       = 0.0f;
421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->r_s       = 0.0f;
431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->r_b       = 0.0f;
441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->g_s       = 0.0f;
451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->g_b       = 0.0f;
461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->b_s       = 0.0f;
471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->b_b       = 0.0f;
481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->repeat    = repeat;
491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->need_reset = TRUE;
511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
531176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic void
541176bdada62cabc6ec4b0308a930e83b679d5d36John Reckgradient_walker_reset (pixman_gradient_walker_t *walker,
551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		       pixman_fixed_48_16_t      pos)
561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int32_t x, left_x, right_x;
581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_color_t *left_c, *right_c;
591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int n, count = walker->num_stops;
601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_gradient_stop_t *stops = walker->stops;
611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    float la, lr, lg, lb;
621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    float ra, rr, rg, rb;
631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    float lx, rx;
641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (walker->repeat == PIXMAN_REPEAT_NORMAL)
661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	x = (int32_t)pos & 0xffff;
681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	x = (int32_t)pos & 0xffff;
721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if ((int32_t)pos & 0x10000)
731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    x = 0x10000 - x;
741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    else
761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	x = pos;
781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    for (n = 0; n < count; n++)
811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (x < stops[n].x)
831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    break;
841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    left_x =  stops[n - 1].x;
871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    left_c = &stops[n - 1].color;
881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    right_x =  stops[n].x;
901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    right_c = &stops[n].color;
911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (walker->repeat == PIXMAN_REPEAT_NORMAL)
931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	left_x  += (pos - x);
951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	right_x += (pos - x);
961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if ((int32_t)pos & 0x10000)
1001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
1011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    pixman_color_t  *tmp_c;
1021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    int32_t tmp_x;
1031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    tmp_x   = 0x10000 - right_x;
1051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    right_x = 0x10000 - left_x;
1061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    left_x  = tmp_x;
1071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    tmp_c   = right_c;
1091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    right_c = left_c;
1101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    left_c  = tmp_c;
1111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    x = 0x10000 - x;
1131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
1141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	left_x  += (pos - x);
1151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	right_x += (pos - x);
1161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
1171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    else if (walker->repeat == PIXMAN_REPEAT_NONE)
1181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
1191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (n == 0)
1201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    right_c = left_c;
1211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	else if (n == count)
1221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    left_c = right_c;
1231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
1241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /* The alpha channel is scaled to be in the [0, 255] interval,
1261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * and the red/green/blue channels are scaled to be in [0, 1].
1271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * This ensures that after premultiplication all channels will
1281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * be in the [0, 255] interval.
1291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     */
1301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    la = (left_c->alpha * (1.0f/257.0f));
1311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    lr = (left_c->red * (1.0f/257.0f));
1321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    lg = (left_c->green * (1.0f/257.0f));
1331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    lb = (left_c->blue * (1.0f/257.0f));
1341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    ra = (right_c->alpha * (1.0f/257.0f));
1361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    rr = (right_c->red * (1.0f/257.0f));
1371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    rg = (right_c->green * (1.0f/257.0f));
1381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    rb = (right_c->blue * (1.0f/257.0f));
1391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    lx = left_x * (1.0f/65536.0f);
1411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    rx = right_x * (1.0f/65536.0f);
1421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (FLOAT_IS_ZERO (rx - lx) || left_x == INT32_MIN || right_x == INT32_MAX)
1441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
1451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	walker->a_s = walker->r_s = walker->g_s = walker->b_s = 0.0f;
1461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	walker->a_b = (la + ra) / 2.0f;
1471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	walker->r_b = (lr + rr) / 510.0f;
1481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	walker->g_b = (lg + rg) / 510.0f;
1491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	walker->b_b = (lb + rb) / 510.0f;
1501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
1511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    else
1521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
1531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	float w_rec = 1.0f / (rx - lx);
1541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	walker->a_b = (la * rx - ra * lx) * w_rec;
1561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	walker->r_b = (lr * rx - rr * lx) * w_rec * (1.0f/255.0f);
1571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	walker->g_b = (lg * rx - rg * lx) * w_rec * (1.0f/255.0f);
1581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	walker->b_b = (lb * rx - rb * lx) * w_rec * (1.0f/255.0f);
1591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	walker->a_s = (ra - la) * w_rec;
1611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	walker->r_s = (rr - lr) * w_rec * (1.0f/255.0f);
1621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	walker->g_s = (rg - lg) * w_rec * (1.0f/255.0f);
1631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	walker->b_s = (rb - lb) * w_rec * (1.0f/255.0f);
1641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
1651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->left_x = left_x;
1671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->right_x = right_x;
1681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    walker->need_reset = FALSE;
1701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
1711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1721176bdada62cabc6ec4b0308a930e83b679d5d36John Reckuint32_t
1731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck_pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
1741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck                               pixman_fixed_48_16_t      x)
1751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
1761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    float a, r, g, b;
1771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint8_t a8, r8, g8, b8;
1781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint32_t v;
1791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    float y;
1801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
1821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        gradient_walker_reset (walker, x);
1831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    y = x * (1.0f / 65536.0f);
1851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    a = walker->a_s * y + walker->a_b;
1871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    r = a * (walker->r_s * y + walker->r_b);
1881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    g = a * (walker->g_s * y + walker->g_b);
1891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    b = a * (walker->b_s * y + walker->b_b);
1901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    a8 = a + 0.5f;
1921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    r8 = r + 0.5f;
1931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    g8 = g + 0.5f;
1941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    b8 = b + 0.5f;
1951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    v = ((a8 << 24) & 0xff000000) |
1971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        ((r8 << 16) & 0x00ff0000) |
1981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        ((g8 <<  8) & 0x0000ff00) |
1991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        ((b8 >>  0) & 0x000000ff);
2001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return v;
2021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
203