Add qemu 2.4.0
[kvmfornfv.git] / qemu / pixman / pixman / pixman-linear-gradient.c
diff --git a/qemu/pixman/pixman/pixman-linear-gradient.c b/qemu/pixman/pixman/pixman-linear-gradient.c
new file mode 100644 (file)
index 0000000..40c8c9f
--- /dev/null
@@ -0,0 +1,287 @@
+/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
+/*
+ * Copyright © 2000 SuSE, Inc.
+ * Copyright © 2007 Red Hat, Inc.
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *             2005 Lars Knoll & Zack Rusin, Trolltech
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include "pixman-private.h"
+
+static pixman_bool_t
+linear_gradient_is_horizontal (pixman_image_t *image,
+                              int             x,
+                              int             y,
+                              int             width,
+                              int             height)
+{
+    linear_gradient_t *linear = (linear_gradient_t *)image;
+    pixman_vector_t v;
+    pixman_fixed_32_32_t l;
+    pixman_fixed_48_16_t dx, dy;
+    double inc;
+
+    if (image->common.transform)
+    {
+       /* projective transformation */
+       if (image->common.transform->matrix[2][0] != 0 ||
+           image->common.transform->matrix[2][1] != 0 ||
+           image->common.transform->matrix[2][2] == 0)
+       {
+           return FALSE;
+       }
+
+       v.vector[0] = image->common.transform->matrix[0][1];
+       v.vector[1] = image->common.transform->matrix[1][1];
+       v.vector[2] = image->common.transform->matrix[2][2];
+    }
+    else
+    {
+       v.vector[0] = 0;
+       v.vector[1] = pixman_fixed_1;
+       v.vector[2] = pixman_fixed_1;
+    }
+
+    dx = linear->p2.x - linear->p1.x;
+    dy = linear->p2.y - linear->p1.y;
+
+    l = dx * dx + dy * dy;
+
+    if (l == 0)
+       return FALSE;
+
+    /*
+     * compute how much the input of the gradient walked changes
+     * when moving vertically through the whole image
+     */
+    inc = height * (double) pixman_fixed_1 * pixman_fixed_1 *
+       (dx * v.vector[0] + dy * v.vector[1]) /
+       (v.vector[2] * (double) l);
+
+    /* check that casting to integer would result in 0 */
+    if (-1 < inc && inc < 1)
+       return TRUE;
+
+    return FALSE;
+}
+
+static uint32_t *
+linear_get_scanline_narrow (pixman_iter_t  *iter,
+                           const uint32_t *mask)
+{
+    pixman_image_t *image  = iter->image;
+    int             x      = iter->x;
+    int             y      = iter->y;
+    int             width  = iter->width;
+    uint32_t *      buffer = iter->buffer;
+
+    pixman_vector_t v, unit;
+    pixman_fixed_32_32_t l;
+    pixman_fixed_48_16_t dx, dy;
+    gradient_t *gradient = (gradient_t *)image;
+    linear_gradient_t *linear = (linear_gradient_t *)image;
+    uint32_t *end = buffer + width;
+    pixman_gradient_walker_t walker;
+
+    _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
+
+    /* reference point is the center of the pixel */
+    v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
+    v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
+    v.vector[2] = pixman_fixed_1;
+
+    if (image->common.transform)
+    {
+       if (!pixman_transform_point_3d (image->common.transform, &v))
+           return iter->buffer;
+
+       unit.vector[0] = image->common.transform->matrix[0][0];
+       unit.vector[1] = image->common.transform->matrix[1][0];
+       unit.vector[2] = image->common.transform->matrix[2][0];
+    }
+    else
+    {
+       unit.vector[0] = pixman_fixed_1;
+       unit.vector[1] = 0;
+       unit.vector[2] = 0;
+    }
+
+    dx = linear->p2.x - linear->p1.x;
+    dy = linear->p2.y - linear->p1.y;
+
+    l = dx * dx + dy * dy;
+
+    if (l == 0 || unit.vector[2] == 0)
+    {
+       /* affine transformation only */
+        pixman_fixed_32_32_t t, next_inc;
+       double inc;
+
+       if (l == 0 || v.vector[2] == 0)
+       {
+           t = 0;
+           inc = 0;
+       }
+       else
+       {
+           double invden, v2;
+
+           invden = pixman_fixed_1 * (double) pixman_fixed_1 /
+               (l * (double) v.vector[2]);
+           v2 = v.vector[2] * (1. / pixman_fixed_1);
+           t = ((dx * v.vector[0] + dy * v.vector[1]) - 
+                (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
+           inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
+       }
+       next_inc = 0;
+
+       if (((pixman_fixed_32_32_t )(inc * width)) == 0)
+       {
+           register uint32_t color;
+
+           color = _pixman_gradient_walker_pixel (&walker, t);
+           while (buffer < end)
+               *buffer++ = color;
+       }
+       else
+       {
+           int i;
+
+           i = 0;
+           while (buffer < end)
+           {
+               if (!mask || *mask++)
+               {
+                   *buffer = _pixman_gradient_walker_pixel (&walker,
+                                                            t + next_inc);
+               }
+               i++;
+               next_inc = inc * i;
+               buffer++;
+           }
+       }
+    }
+    else
+    {
+       /* projective transformation */
+        double t;
+
+       t = 0;
+
+       while (buffer < end)
+       {
+           if (!mask || *mask++)
+           {
+               if (v.vector[2] != 0)
+               {
+                   double invden, v2;
+
+                   invden = pixman_fixed_1 * (double) pixman_fixed_1 /
+                       (l * (double) v.vector[2]);
+                   v2 = v.vector[2] * (1. / pixman_fixed_1);
+                   t = ((dx * v.vector[0] + dy * v.vector[1]) - 
+                        (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
+               }
+
+               *buffer = _pixman_gradient_walker_pixel (&walker, t);
+           }
+
+           ++buffer;
+
+           v.vector[0] += unit.vector[0];
+           v.vector[1] += unit.vector[1];
+           v.vector[2] += unit.vector[2];
+       }
+    }
+
+    iter->y++;
+
+    return iter->buffer;
+}
+
+static uint32_t *
+linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
+{
+    uint32_t *buffer = linear_get_scanline_narrow (iter, NULL);
+
+    pixman_expand_to_float (
+       (argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
+
+    return buffer;
+}
+
+void
+_pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t  *iter)
+{
+    if (linear_gradient_is_horizontal (
+           iter->image, iter->x, iter->y, iter->width, iter->height))
+    {
+       if (iter->iter_flags & ITER_NARROW)
+           linear_get_scanline_narrow (iter, NULL);
+       else
+           linear_get_scanline_wide (iter, NULL);
+
+       iter->get_scanline = _pixman_iter_get_scanline_noop;
+    }
+    else
+    {
+       if (iter->iter_flags & ITER_NARROW)
+           iter->get_scanline = linear_get_scanline_narrow;
+       else
+           iter->get_scanline = linear_get_scanline_wide;
+    }
+}
+
+PIXMAN_EXPORT pixman_image_t *
+pixman_image_create_linear_gradient (const pixman_point_fixed_t *  p1,
+                                     const pixman_point_fixed_t *  p2,
+                                     const pixman_gradient_stop_t *stops,
+                                     int                           n_stops)
+{
+    pixman_image_t *image;
+    linear_gradient_t *linear;
+
+    image = _pixman_image_allocate ();
+
+    if (!image)
+       return NULL;
+
+    linear = &image->linear;
+
+    if (!_pixman_init_gradient (&linear->common, stops, n_stops))
+    {
+       free (image);
+       return NULL;
+    }
+
+    linear->p1 = *p1;
+    linear->p2 = *p2;
+
+    image->type = LINEAR;
+
+    return image;
+}
+