michael@0: /* michael@0: * michael@0: * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. michael@0: * 2005 Lars Knoll & Zack Rusin, Trolltech michael@0: * michael@0: * Permission to use, copy, modify, distribute, and sell this software and its michael@0: * documentation for any purpose is hereby granted without fee, provided that michael@0: * the above copyright notice appear in all copies and that both that michael@0: * copyright notice and this permission notice appear in supporting michael@0: * documentation, and that the name of Keith Packard not be used in michael@0: * advertising or publicity pertaining to distribution of the software without michael@0: * specific, written prior permission. Keith Packard makes no michael@0: * representations about the suitability of this software for any purpose. It michael@0: * is provided "as is" without express or implied warranty. michael@0: * michael@0: * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS michael@0: * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND michael@0: * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY michael@0: * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES michael@0: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN michael@0: * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING michael@0: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS michael@0: * SOFTWARE. michael@0: */ michael@0: michael@0: #ifdef HAVE_CONFIG_H michael@0: #include michael@0: #endif michael@0: #include "pixman-private.h" michael@0: michael@0: void michael@0: _pixman_gradient_walker_init (pixman_gradient_walker_t *walker, michael@0: gradient_t * gradient, michael@0: pixman_repeat_t repeat) michael@0: { michael@0: walker->num_stops = gradient->n_stops; michael@0: walker->stops = gradient->stops; michael@0: walker->left_x = 0; michael@0: walker->right_x = 0x10000; michael@0: walker->stepper = 0; michael@0: walker->left_ag = 0; michael@0: walker->left_rb = 0; michael@0: walker->right_ag = 0; michael@0: walker->right_rb = 0; michael@0: walker->repeat = repeat; michael@0: michael@0: walker->need_reset = TRUE; michael@0: } michael@0: michael@0: static void michael@0: gradient_walker_reset (pixman_gradient_walker_t *walker, michael@0: pixman_fixed_48_16_t pos) michael@0: { michael@0: int32_t x, left_x, right_x; michael@0: pixman_color_t *left_c, *right_c; michael@0: int n, count = walker->num_stops; michael@0: pixman_gradient_stop_t *stops = walker->stops; michael@0: michael@0: if (walker->repeat == PIXMAN_REPEAT_NORMAL) michael@0: { michael@0: x = (int32_t)pos & 0xffff; michael@0: } michael@0: else if (walker->repeat == PIXMAN_REPEAT_REFLECT) michael@0: { michael@0: x = (int32_t)pos & 0xffff; michael@0: if ((int32_t)pos & 0x10000) michael@0: x = 0x10000 - x; michael@0: } michael@0: else michael@0: { michael@0: x = pos; michael@0: } michael@0: michael@0: for (n = 0; n < count; n++) michael@0: { michael@0: if (x < stops[n].x) michael@0: break; michael@0: } michael@0: michael@0: left_x = stops[n - 1].x; michael@0: left_c = &stops[n - 1].color; michael@0: michael@0: right_x = stops[n].x; michael@0: right_c = &stops[n].color; michael@0: michael@0: if (walker->repeat == PIXMAN_REPEAT_NORMAL) michael@0: { michael@0: left_x += (pos - x); michael@0: right_x += (pos - x); michael@0: } michael@0: else if (walker->repeat == PIXMAN_REPEAT_REFLECT) michael@0: { michael@0: if ((int32_t)pos & 0x10000) michael@0: { michael@0: pixman_color_t *tmp_c; michael@0: int32_t tmp_x; michael@0: michael@0: tmp_x = 0x10000 - right_x; michael@0: right_x = 0x10000 - left_x; michael@0: left_x = tmp_x; michael@0: michael@0: tmp_c = right_c; michael@0: right_c = left_c; michael@0: left_c = tmp_c; michael@0: michael@0: x = 0x10000 - x; michael@0: } michael@0: left_x += (pos - x); michael@0: right_x += (pos - x); michael@0: } michael@0: else if (walker->repeat == PIXMAN_REPEAT_NONE) michael@0: { michael@0: if (n == 0) michael@0: right_c = left_c; michael@0: else if (n == count) michael@0: left_c = right_c; michael@0: } michael@0: michael@0: walker->left_x = left_x; michael@0: walker->right_x = right_x; michael@0: walker->left_ag = ((left_c->alpha >> 8) << 16) | (left_c->green >> 8); michael@0: walker->left_rb = ((left_c->red & 0xff00) << 8) | (left_c->blue >> 8); michael@0: walker->right_ag = ((right_c->alpha >> 8) << 16) | (right_c->green >> 8); michael@0: walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8); michael@0: michael@0: if (walker->left_x == walker->right_x || michael@0: (walker->left_ag == walker->right_ag && michael@0: walker->left_rb == walker->right_rb)) michael@0: { michael@0: walker->stepper = 0; michael@0: } michael@0: else michael@0: { michael@0: int32_t width = right_x - left_x; michael@0: walker->stepper = ((1 << 24) + width / 2) / width; michael@0: } michael@0: michael@0: walker->need_reset = FALSE; michael@0: } michael@0: michael@0: uint32_t michael@0: _pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker, michael@0: pixman_fixed_48_16_t x) michael@0: { michael@0: int dist, idist; michael@0: uint32_t t1, t2, a, color; michael@0: michael@0: if (walker->need_reset || x < walker->left_x || x >= walker->right_x) michael@0: gradient_walker_reset (walker, x); michael@0: michael@0: dist = ((int)(x - walker->left_x) * walker->stepper) >> 16; michael@0: idist = 256 - dist; michael@0: michael@0: /* combined INTERPOLATE and premultiply */ michael@0: t1 = walker->left_rb * idist + walker->right_rb * dist; michael@0: t1 = (t1 >> 8) & 0xff00ff; michael@0: michael@0: t2 = walker->left_ag * idist + walker->right_ag * dist; michael@0: t2 &= 0xff00ff00; michael@0: michael@0: color = t2 & 0xff000000; michael@0: a = t2 >> 24; michael@0: michael@0: t1 = t1 * a + 0x800080; michael@0: t1 = (t1 + ((t1 >> 8) & 0xff00ff)) >> 8; michael@0: michael@0: t2 = (t2 >> 8) * a + 0x800080; michael@0: t2 = (t2 + ((t2 >> 8) & 0xff00ff)); michael@0: michael@0: return (color | (t1 & 0xff00ff) | (t2 & 0xff00)); michael@0: } michael@0: