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