11176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
21176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/*
31176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
41176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
51176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright © 2000 SuSE, Inc.
61176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *             2005 Lars Knoll & Zack Rusin, Trolltech
71176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright © 2007 Red Hat, Inc.
81176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
91176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Permission to use, copy, modify, distribute, and sell this software and its
111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * documentation for any purpose is hereby granted without fee, provided that
121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * the above copyright notice appear in all copies and that both that
131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * copyright notice and this permission notice appear in supporting
141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * documentation, and that the name of Keith Packard not be used in
151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * advertising or publicity pertaining to distribution of the software without
161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * specific, written prior permission.  Keith Packard makes no
171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * representations about the suitability of this software for any purpose.  It
181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * is provided "as is" without express or implied warranty.
191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * SOFTWARE.
281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */
291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#ifdef HAVE_CONFIG_H
311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <config.h>
321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif
331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <stdlib.h>
341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <math.h>
351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include "pixman-private.h"
361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
371176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic inline pixman_fixed_32_32_t
381176bdada62cabc6ec4b0308a930e83b679d5d36John Reckdot (pixman_fixed_48_16_t x1,
391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     pixman_fixed_48_16_t y1,
401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     pixman_fixed_48_16_t z1,
411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     pixman_fixed_48_16_t x2,
421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     pixman_fixed_48_16_t y2,
431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     pixman_fixed_48_16_t z2)
441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /*
461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * Exact computation, assuming that the input values can
471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * be represented as pixman_fixed_16_16_t
481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     */
491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return x1 * x2 + y1 * y2 + z1 * z2;
501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
521176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic inline double
531176bdada62cabc6ec4b0308a930e83b679d5d36John Reckfdot (double x1,
541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck      double y1,
551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck      double z1,
561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck      double x2,
571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck      double y2,
581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck      double z2)
591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /*
611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * Error can be unbound in some special cases.
621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * Using clever dot product algorithms (for example compensated
631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * dot product) would improve this but make the code much less
641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * obvious
651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     */
661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return x1 * x2 + y1 * y2 + z1 * z2;
671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
691176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic uint32_t
701176bdada62cabc6ec4b0308a930e83b679d5d36John Reckradial_compute_color (double                    a,
711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		      double                    b,
721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		      double                    c,
731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		      double                    inva,
741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		      double                    dr,
751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		      double                    mindr,
761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		      pixman_gradient_walker_t *walker,
771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		      pixman_repeat_t           repeat)
781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /*
801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * In this function error propagation can lead to bad results:
811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *  - discr can have an unbound error (if b*b-a*c is very small),
821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *    potentially making it the opposite sign of what it should have been
831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *    (thus clearing a pixel that would have been colored or vice-versa)
841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *    or propagating the error to sqrtdiscr;
851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *    if discr has the wrong sign or b is very small, this can lead to bad
861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *    results
871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *  - the algorithm used to compute the solutions of the quadratic
891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *    equation is not numerically stable (but saves one division compared
901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *    to the numerically stable one);
911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *    this can be a problem if a*c is much smaller than b*b
921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *  - the above problems are worse if a is small (as inva becomes bigger)
941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     */
951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    double discr;
961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (a == 0)
981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	double t;
1001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (b == 0)
1021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    return 0;
1031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	t = pixman_fixed_1 / 2 * c / b;
1051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (repeat == PIXMAN_REPEAT_NONE)
1061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
1071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    if (0 <= t && t <= pixman_fixed_1)
1081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		return _pixman_gradient_walker_pixel (walker, t);
1091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
1101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	else
1111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
1121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    if (t * dr >= mindr)
1131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		return _pixman_gradient_walker_pixel (walker, t);
1141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
1151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	return 0;
1171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
1181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    discr = fdot (b, a, 0, b, -c, 0);
1201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (discr >= 0)
1211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
1221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	double sqrtdiscr, t0, t1;
1231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	sqrtdiscr = sqrt (discr);
1251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	t0 = (b + sqrtdiscr) * inva;
1261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	t1 = (b - sqrtdiscr) * inva;
1271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	/*
1291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * The root that must be used is the biggest one that belongs
1301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * to the valid range ([0,1] for PIXMAN_REPEAT_NONE, any
1311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * solution that results in a positive radius otherwise).
1321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 *
1331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * If a > 0, t0 is the biggest solution, so if it is valid, it
1341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * is the correct result.
1351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 *
1361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * If a < 0, only one of the solutions can be valid, so the
1371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * order in which they are tested is not important.
1381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 */
1391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (repeat == PIXMAN_REPEAT_NONE)
1401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
1411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    if (0 <= t0 && t0 <= pixman_fixed_1)
1421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		return _pixman_gradient_walker_pixel (walker, t0);
1431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    else if (0 <= t1 && t1 <= pixman_fixed_1)
1441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		return _pixman_gradient_walker_pixel (walker, t1);
1451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
1461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	else
1471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
1481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    if (t0 * dr >= mindr)
1491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		return _pixman_gradient_walker_pixel (walker, t0);
1501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    else if (t1 * dr >= mindr)
1511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		return _pixman_gradient_walker_pixel (walker, t1);
1521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
1531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
1541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return 0;
1561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
1571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1581176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic uint32_t *
1591176bdada62cabc6ec4b0308a930e83b679d5d36John Reckradial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
1601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
1611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /*
1621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * Implementation of radial gradients following the PDF specification.
1631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
1641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * Manual (PDF 32000-1:2008 at the time of this writing).
1651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
1661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * In the radial gradient problem we are given two circles (c₁,r₁) and
1671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * (c₂,r₂) that define the gradient itself.
1681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
1691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * Mathematically the gradient can be defined as the family of circles
1701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
1711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
1721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
1731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * excluding those circles whose radius would be < 0. When a point
1741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * belongs to more than one circle, the one with a bigger t is the only
1751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * one that contributes to its color. When a point does not belong
1761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
1771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * Further limitations on the range of values for t are imposed when
1781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * the gradient is not repeated, namely t must belong to [0,1].
1791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
1801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * The graphical result is the same as drawing the valid (radius > 0)
1811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient
1821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * is not repeated) using SOURCE operator composition.
1831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
1841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * It looks like a cone pointing towards the viewer if the ending circle
1851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * is smaller than the starting one, a cone pointing inside the page if
1861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * the starting circle is the smaller one and like a cylinder if they
1871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * have the same radius.
1881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
1891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * What we actually do is, given the point whose color we are interested
1901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * in, compute the t values for that point, solving for t in:
1911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
1921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
1931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
1941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * Let's rewrite it in a simpler way, by defining some auxiliary
1951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * variables:
1961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
1971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     cd = c₂ - c₁
1981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     pd = p - c₁
1991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     dr = r₂ - r₁
2001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     length(t·cd - pd) = r₁ + t·dr
2011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * which actually means
2031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr
2051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * or
2071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
2091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes:
2111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
2131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * where we can actually expand the squares and solve for t:
2151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
2171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *       = r₁² + 2·r₁·t·dr + t²·dr²
2181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
2201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *         (pdx² + pdy² - r₁²) = 0
2211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     A = cdx² + cdy² - dr²
2231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     B = pdx·cdx + pdy·cdy + r₁·dr
2241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     C = pdx² + pdy² - r₁²
2251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     At² - 2Bt + C = 0
2261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * The solutions (unless the equation degenerates because of A = 0) are:
2281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *     t = (B ± ⎷(B² - A·C)) / A
2301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * The solution we are going to prefer is the bigger one, unless the
2321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * radius associated to it is negative (or it falls outside the valid t
2331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * range).
2341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * Additional observations (useful for optimizations):
2361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * A does not depend on p
2371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *
2381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * A < 0 <=> one of the two circles completely contains the other one
2391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *   <=> for every p, the radiuses associated with the two t solutions
2401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     *       have opposite sign
2411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     */
2421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_image_t *image = iter->image;
2431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int x = iter->x;
2441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int y = iter->y;
2451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int width = iter->width;
2461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint32_t *buffer = iter->buffer;
2471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    gradient_t *gradient = (gradient_t *)image;
2491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial_gradient_t *radial = (radial_gradient_t *)image;
2501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint32_t *end = buffer + width;
2511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_gradient_walker_t walker;
2521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_vector_t v, unit;
2531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /* reference point is the center of the pixel */
2551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
2561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
2571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    v.vector[2] = pixman_fixed_1;
2581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
2601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (image->common.transform)
2621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
2631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (!pixman_transform_point_3d (image->common.transform, &v))
2641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    return iter->buffer;
2651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	unit.vector[0] = image->common.transform->matrix[0][0];
2671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	unit.vector[1] = image->common.transform->matrix[1][0];
2681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	unit.vector[2] = image->common.transform->matrix[2][0];
2691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
2701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    else
2711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
2721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	unit.vector[0] = pixman_fixed_1;
2731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	unit.vector[1] = 0;
2741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	unit.vector[2] = 0;
2751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
2761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1)
2781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
2791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	/*
2801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * Given:
2811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 *
2821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * t = (B ± ⎷(B² - A·C)) / A
2831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 *
2841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * where
2851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 *
2861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * A = cdx² + cdy² - dr²
2871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * B = pdx·cdx + pdy·cdy + r₁·dr
2881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * C = pdx² + pdy² - r₁²
2891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * det = B² - A·C
2901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 *
2911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * Since we have an affine transformation, we know that (pdx, pdy)
2921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * increase linearly with each pixel,
2931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 *
2941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * pdx = pdx₀ + n·ux,
2951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * pdy = pdy₀ + n·uy,
2961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 *
2971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * we can then express B, C and det through multiple differentiation.
2981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 */
2991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_fixed_32_32_t b, db, c, dc, ddc;
3001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	/* warning: this computation may overflow */
3021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	v.vector[0] -= radial->c1.x;
3031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	v.vector[1] -= radial->c1.y;
3041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	/*
3061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * B and C are computed and updated exactly.
3071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * If fdot was used instead of dot, in the worst case it would
3081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * lose 11 bits of precision in each of the multiplication and
3091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * summing up would zero out all the bit that were preserved,
3101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * thus making the result 0 instead of the correct one.
3111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * This would mean a worst case of unbound relative error or
3121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * about 2^10 absolute error
3131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 */
3141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	b = dot (v.vector[0], v.vector[1], radial->c1.radius,
3151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		 radial->delta.x, radial->delta.y, radial->delta.radius);
3161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	db = dot (unit.vector[0], unit.vector[1], 0,
3171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		  radial->delta.x, radial->delta.y, 0);
3181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	c = dot (v.vector[0], v.vector[1],
3201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		 -((pixman_fixed_48_16_t) radial->c1.radius),
3211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		 v.vector[0], v.vector[1], radial->c1.radius);
3221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0],
3231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		  2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1],
3241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		  0,
3251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		  unit.vector[0], unit.vector[1], 0);
3261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	ddc = 2 * dot (unit.vector[0], unit.vector[1], 0,
3271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		       unit.vector[0], unit.vector[1], 0);
3281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	while (buffer < end)
3301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
3311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    if (!mask || *mask++)
3321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    {
3331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		*buffer = radial_compute_color (radial->a, b, c,
3341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck						radial->inva,
3351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck						radial->delta.radius,
3361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck						radial->mindr,
3371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck						&walker,
3381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck						image->common.repeat);
3391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    }
3401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    b += db;
3421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    c += dc;
3431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    dc += ddc;
3441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    ++buffer;
3451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
3461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
3471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    else
3481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
3491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	/* projective */
3501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	/* Warning:
3511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 * error propagation guarantees are much looser than in the affine case
3521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	 */
3531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	while (buffer < end)
3541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
3551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    if (!mask || *mask++)
3561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    {
3571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		if (v.vector[2] != 0)
3581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		{
3591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    double pdx, pdy, invv2, b, c;
3601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    invv2 = 1. * pixman_fixed_1 / v.vector[2];
3621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    pdx = v.vector[0] * invv2 - radial->c1.x;
3641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    /*    / pixman_fixed_1 */
3651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    pdy = v.vector[1] * invv2 - radial->c1.y;
3671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    /*    / pixman_fixed_1 */
3681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    b = fdot (pdx, pdy, radial->c1.radius,
3701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			      radial->delta.x, radial->delta.y,
3711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			      radial->delta.radius);
3721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    /*  / pixman_fixed_1 / pixman_fixed_1 */
3731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    c = fdot (pdx, pdy, -radial->c1.radius,
3751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck			      pdx, pdy, radial->c1.radius);
3761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    /*  / pixman_fixed_1 / pixman_fixed_1 */
3771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    *buffer = radial_compute_color (radial->a, b, c,
3791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck						    radial->inva,
3801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck						    radial->delta.radius,
3811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck						    radial->mindr,
3821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck						    &walker,
3831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck						    image->common.repeat);
3841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		}
3851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		else
3861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		{
3871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    *buffer = 0;
3881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		}
3891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    }
3901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    ++buffer;
3921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    v.vector[0] += unit.vector[0];
3941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    v.vector[1] += unit.vector[1];
3951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    v.vector[2] += unit.vector[2];
3961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
3971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
3981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
3991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    iter->y++;
4001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return iter->buffer;
4011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
4021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4031176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic uint32_t *
4041176bdada62cabc6ec4b0308a930e83b679d5d36John Reckradial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
4051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
4061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint32_t *buffer = radial_get_scanline_narrow (iter, NULL);
4071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_expand_to_float (
4091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	(argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
4101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return buffer;
4121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
4131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4141176bdada62cabc6ec4b0308a930e83b679d5d36John Reckvoid
4151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck_pixman_radial_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
4161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
4171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (iter->iter_flags & ITER_NARROW)
4181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	iter->get_scanline = radial_get_scanline_narrow;
4191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    else
4201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	iter->get_scanline = radial_get_scanline_wide;
4211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
4221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4231176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT pixman_image_t *
4241176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_image_create_radial_gradient (const pixman_point_fixed_t *  inner,
4251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck                                     const pixman_point_fixed_t *  outer,
4261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck                                     pixman_fixed_t                inner_radius,
4271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck                                     pixman_fixed_t                outer_radius,
4281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck                                     const pixman_gradient_stop_t *stops,
4291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck                                     int                           n_stops)
4301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
4311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_image_t *image;
4321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial_gradient_t *radial;
4331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    image = _pixman_image_allocate ();
4351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (!image)
4371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	return NULL;
4381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial = &image->radial;
4401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (!_pixman_init_gradient (&radial->common, stops, n_stops))
4421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
4431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	free (image);
4441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	return NULL;
4451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
4461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    image->type = RADIAL;
4481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial->c1.x = inner->x;
4501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial->c1.y = inner->y;
4511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial->c1.radius = inner_radius;
4521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial->c2.x = outer->x;
4531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial->c2.y = outer->y;
4541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial->c2.radius = outer_radius;
4551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /* warning: this computations may overflow */
4571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial->delta.x = radial->c2.x - radial->c1.x;
4581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial->delta.y = radial->c2.y - radial->c1.y;
4591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial->delta.radius = radial->c2.radius - radial->c1.radius;
4601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /* computed exactly, then cast to double -> every bit of the double
4621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck       representation is correct (53 bits) */
4631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial->a = dot (radial->delta.x, radial->delta.y, -radial->delta.radius,
4641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		     radial->delta.x, radial->delta.y, radial->delta.radius);
4651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (radial->a != 0)
4661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	radial->inva = 1. * pixman_fixed_1 / radial->a;
4671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    radial->mindr = -1. * pixman_fixed_1 * radial->c1.radius;
4691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
4701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return image;
4711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
472