11176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/*
21176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright © 2000 SuSE, Inc.
31176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright © 2007 Red Hat, Inc.
41176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
51176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *             2005 Lars Knoll & Zack Rusin, Trolltech
61176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
71176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Permission to use, copy, modify, distribute, and sell this software and its
81176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * documentation for any purpose is hereby granted without fee, provided that
91176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * the above copyright notice appear in all copies and that both that
101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * copyright notice and this permission notice appear in supporting
111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * documentation, and that the name of Keith Packard not be used in
121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * advertising or publicity pertaining to distribution of the software without
131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * specific, written prior permission.  Keith Packard makes no
141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * representations about the suitability of this software for any purpose.  It
151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * is provided "as is" without express or implied warranty.
161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * SOFTWARE.
251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */
261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#ifdef HAVE_CONFIG_H
281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <config.h>
291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif
301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <stdlib.h>
321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <math.h>
331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include "pixman-private.h"
341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
351176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic force_inline double
361176bdada62cabc6ec4b0308a930e83b679d5d36John Reckcoordinates_to_parameter (double x, double y, double angle)
371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    double t;
391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    t = atan2 (y, x) + angle;
411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    while (t < 0)
431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	t += 2 * M_PI;
441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    while (t >= 2 * M_PI)
461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	t -= 2 * M_PI;
471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return 1 - t * (1 / (2 * M_PI)); /* Scale t to [0, 1] and
491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck				      * make rotation CCW
501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck				      */
511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
531176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic uint32_t *
541176bdada62cabc6ec4b0308a930e83b679d5d36John Reckconical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_image_t *image = iter->image;
571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int x = iter->x;
581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int y = iter->y;
591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int width = iter->width;
601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint32_t *buffer = iter->buffer;
611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    gradient_t *gradient = (gradient_t *)image;
631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    conical_gradient_t *conical = (conical_gradient_t *)image;
641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint32_t       *end = buffer + width;
651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_gradient_walker_t walker;
661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_bool_t affine = TRUE;
671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    double cx = 1.;
681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    double cy = 0.;
691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    double cz = 0.;
701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    double rx = x + 0.5;
711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    double ry = y + 0.5;
721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    double rz = 1.;
731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (image->common.transform)
771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_vector_t v;
791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	/* reference point is the center of the pixel */
811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	v.vector[2] = pixman_fixed_1;
841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (!pixman_transform_point_3d (image->common.transform, &v))
861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    return iter->buffer;
871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	cx = image->common.transform->matrix[0][0] / 65536.;
891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	cy = image->common.transform->matrix[1][0] / 65536.;
901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	cz = image->common.transform->matrix[2][0] / 65536.;
911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	rx = v.vector[0] / 65536.;
931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	ry = v.vector[1] / 65536.;
941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	rz = v.vector[2] / 65536.;
951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	affine =
971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    image->common.transform->matrix[2][0] == 0 &&
981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    v.vector[2] == pixman_fixed_1;
991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
1001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (affine)
1021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
1031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	rx -= conical->center.x / 65536.;
1041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	ry -= conical->center.y / 65536.;
1051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	while (buffer < end)
1071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
1081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    if (!mask || *mask++)
1091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    {
1101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		double t = coordinates_to_parameter (rx, ry, conical->angle);
1111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		*buffer = _pixman_gradient_walker_pixel (
1131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
1141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    }
1151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    ++buffer;
1171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    rx += cx;
1191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    ry += cy;
1201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
1211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
1221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    else
1231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
1241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	while (buffer < end)
1251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
1261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    double x, y;
1271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    if (!mask || *mask++)
1291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    {
1301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		double t;
1311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		if (rz != 0)
1331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		{
1341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    x = rx / rz;
1351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    y = ry / rz;
1361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		}
1371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		else
1381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		{
1391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    x = y = 0.;
1401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		}
1411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		x -= conical->center.x / 65536.;
1431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		y -= conical->center.y / 65536.;
1441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		t = coordinates_to_parameter (x, y, conical->angle);
1461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		*buffer = _pixman_gradient_walker_pixel (
1481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
1491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    }
1501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    ++buffer;
1521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    rx += cx;
1541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    ry += cy;
1551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    rz += cz;
1561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
1571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
1581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    iter->y++;
1601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return iter->buffer;
1611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
1621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1631176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic uint32_t *
1641176bdada62cabc6ec4b0308a930e83b679d5d36John Reckconical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
1651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
1661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint32_t *buffer = conical_get_scanline_narrow (iter, NULL);
1671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_expand_to_float (
1691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	(argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
1701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return buffer;
1721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
1731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1741176bdada62cabc6ec4b0308a930e83b679d5d36John Reckvoid
1751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck_pixman_conical_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
1761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
1771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (iter->iter_flags & ITER_NARROW)
1781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	iter->get_scanline = conical_get_scanline_narrow;
1791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    else
1801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	iter->get_scanline = conical_get_scanline_wide;
1811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
1821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1831176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT pixman_image_t *
1841176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_image_create_conical_gradient (const pixman_point_fixed_t *  center,
1851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck                                      pixman_fixed_t                angle,
1861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck                                      const pixman_gradient_stop_t *stops,
1871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck                                      int                           n_stops)
1881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
1891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_image_t *image = _pixman_image_allocate ();
1901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    conical_gradient_t *conical;
1911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (!image)
1931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	return NULL;
1941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    conical = &image->conical;
1961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (!_pixman_init_gradient (&conical->common, stops, n_stops))
1981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
1991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	free (image);
2001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	return NULL;
2011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
2021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    angle = MOD (angle, pixman_int_to_fixed (360));
2041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    image->type = CONICAL;
2061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    conical->center = *center;
2081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    conical->angle = (pixman_fixed_to_double (angle) / 180.0) * M_PI;
2091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return image;
2111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
2121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
213