gfx/cairo/libpixman/src/pixman-linear-gradient.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
     2 /*
     3  * Copyright © 2000 SuSE, Inc.
     4  * Copyright © 2007 Red Hat, Inc.
     5  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
     6  *             2005 Lars Knoll & Zack Rusin, Trolltech
     7  *
     8  * Permission to use, copy, modify, distribute, and sell this software and its
     9  * documentation for any purpose is hereby granted without fee, provided that
    10  * the above copyright notice appear in all copies and that both that
    11  * copyright notice and this permission notice appear in supporting
    12  * documentation, and that the name of Keith Packard not be used in
    13  * advertising or publicity pertaining to distribution of the software without
    14  * specific, written prior permission.  Keith Packard makes no
    15  * representations about the suitability of this software for any purpose.  It
    16  * is provided "as is" without express or implied warranty.
    17  *
    18  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
    19  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
    20  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
    21  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    22  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    23  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
    24  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
    25  * SOFTWARE.
    26  */
    28 #ifdef HAVE_CONFIG_H
    29 #include <config.h>
    30 #endif
    31 #include <stdlib.h>
    32 #include "pixman-private.h"
    34 #include "pixman-dither.h"
    36 static pixman_bool_t
    37 linear_gradient_is_horizontal (pixman_image_t *image,
    38 			       int             x,
    39 			       int             y,
    40 			       int             width,
    41 			       int             height)
    42 {
    43     linear_gradient_t *linear = (linear_gradient_t *)image;
    44     pixman_vector_t v;
    45     pixman_fixed_32_32_t l;
    46     pixman_fixed_48_16_t dx, dy;
    47     double inc;
    49     if (image->common.transform)
    50     {
    51 	/* projective transformation */
    52 	if (image->common.transform->matrix[2][0] != 0 ||
    53 	    image->common.transform->matrix[2][1] != 0 ||
    54 	    image->common.transform->matrix[2][2] == 0)
    55 	{
    56 	    return FALSE;
    57 	}
    59 	v.vector[0] = image->common.transform->matrix[0][1];
    60 	v.vector[1] = image->common.transform->matrix[1][1];
    61 	v.vector[2] = image->common.transform->matrix[2][2];
    62     }
    63     else
    64     {
    65 	v.vector[0] = 0;
    66 	v.vector[1] = pixman_fixed_1;
    67 	v.vector[2] = pixman_fixed_1;
    68     }
    70     dx = linear->p2.x - linear->p1.x;
    71     dy = linear->p2.y - linear->p1.y;
    73     l = dx * dx + dy * dy;
    75     if (l == 0)
    76 	return FALSE;
    78     /*
    79      * compute how much the input of the gradient walked changes
    80      * when moving vertically through the whole image
    81      */
    82     inc = height * (double) pixman_fixed_1 * pixman_fixed_1 *
    83 	(dx * v.vector[0] + dy * v.vector[1]) /
    84 	(v.vector[2] * (double) l);
    86     /* check that casting to integer would result in 0 */
    87     if (-1 < inc && inc < 1)
    88 	return TRUE;
    90     return FALSE;
    91 }
    93 static uint32_t *
    94 linear_get_scanline_narrow (pixman_iter_t  *iter,
    95 			    const uint32_t *mask)
    96 {
    97     pixman_image_t *image  = iter->image;
    98     int             x      = iter->x;
    99     int             y      = iter->y;
   100     int             width  = iter->width;
   101     uint32_t *      buffer = iter->buffer;
   103     pixman_vector_t v, unit;
   104     pixman_fixed_32_32_t l;
   105     pixman_fixed_48_16_t dx, dy;
   106     gradient_t *gradient = (gradient_t *)image;
   107     linear_gradient_t *linear = (linear_gradient_t *)image;
   108     uint32_t *end = buffer + width;
   109     pixman_gradient_walker_t walker;
   111     _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
   113     /* reference point is the center of the pixel */
   114     v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
   115     v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
   116     v.vector[2] = pixman_fixed_1;
   118     if (image->common.transform)
   119     {
   120 	if (!pixman_transform_point_3d (image->common.transform, &v))
   121 	    return iter->buffer;
   123 	unit.vector[0] = image->common.transform->matrix[0][0];
   124 	unit.vector[1] = image->common.transform->matrix[1][0];
   125 	unit.vector[2] = image->common.transform->matrix[2][0];
   126     }
   127     else
   128     {
   129 	unit.vector[0] = pixman_fixed_1;
   130 	unit.vector[1] = 0;
   131 	unit.vector[2] = 0;
   132     }
   134     dx = linear->p2.x - linear->p1.x;
   135     dy = linear->p2.y - linear->p1.y;
   137     l = dx * dx + dy * dy;
   139     if (l == 0 || unit.vector[2] == 0)
   140     {
   141 	/* affine transformation only */
   142         pixman_fixed_32_32_t t, next_inc;
   143 	double inc;
   145 	if (l == 0 || v.vector[2] == 0)
   146 	{
   147 	    t = 0;
   148 	    inc = 0;
   149 	}
   150 	else
   151 	{
   152 	    double invden, v2;
   154 	    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
   155 		(l * (double) v.vector[2]);
   156 	    v2 = v.vector[2] * (1. / pixman_fixed_1);
   157 	    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
   158 		 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
   159 	    inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
   160 	}
   161 	next_inc = 0;
   163 	if (((pixman_fixed_32_32_t )(inc * width)) == 0)
   164 	{
   165 	    register uint32_t color;
   167 	    color = _pixman_gradient_walker_pixel (&walker, t);
   168 	    while (buffer < end)
   169 		*buffer++ = color;
   170 	}
   171 	else
   172 	{
   173 	    int i;
   175 	    i = 0;
   176 	    while (buffer < end)
   177 	    {
   178 		if (!mask || *mask++)
   179 		{
   180 		    *buffer = _pixman_gradient_walker_pixel (&walker,
   181 							     t + next_inc);
   182 		}
   183 		i++;
   184 		next_inc = inc * i;
   185 		buffer++;
   186 	    }
   187 	}
   188     }
   189     else
   190     {
   191 	/* projective transformation */
   192         double t;
   194 	t = 0;
   196 	while (buffer < end)
   197 	{
   198 	    if (!mask || *mask++)
   199 	    {
   200 	        if (v.vector[2] != 0)
   201 		{
   202 		    double invden, v2;
   204 		    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
   205 			(l * (double) v.vector[2]);
   206 		    v2 = v.vector[2] * (1. / pixman_fixed_1);
   207 		    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
   208 			 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
   209 		}
   211 		*buffer = _pixman_gradient_walker_pixel (&walker, t);
   212 	    }
   214 	    ++buffer;
   216 	    v.vector[0] += unit.vector[0];
   217 	    v.vector[1] += unit.vector[1];
   218 	    v.vector[2] += unit.vector[2];
   219 	}
   220     }
   222     iter->y++;
   224     return iter->buffer;
   225 }
   227 static uint32_t *
   228 linear_get_scanline_16 (pixman_iter_t  *iter,
   229 			const uint32_t *mask)
   230 {
   231     pixman_image_t *image  = iter->image;
   232     int             x      = iter->x;
   233     int             y      = iter->y;
   234     int             width  = iter->width;
   235     uint16_t *      buffer = (uint16_t*)iter->buffer;
   236     pixman_bool_t   toggle = ((x ^ y) & 1);
   238     pixman_vector_t v, unit;
   239     pixman_fixed_32_32_t l;
   240     pixman_fixed_48_16_t dx, dy;
   241     gradient_t *gradient = (gradient_t *)image;
   242     linear_gradient_t *linear = (linear_gradient_t *)image;
   243     uint16_t *end = buffer + width;
   244     pixman_gradient_walker_t walker;
   246     _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
   248     /* reference point is the center of the pixel */
   249     v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
   250     v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
   251     v.vector[2] = pixman_fixed_1;
   253     if (image->common.transform)
   254     {
   255 	if (!pixman_transform_point_3d (image->common.transform, &v))
   256 	    return iter->buffer;
   258 	unit.vector[0] = image->common.transform->matrix[0][0];
   259 	unit.vector[1] = image->common.transform->matrix[1][0];
   260 	unit.vector[2] = image->common.transform->matrix[2][0];
   261     }
   262     else
   263     {
   264 	unit.vector[0] = pixman_fixed_1;
   265 	unit.vector[1] = 0;
   266 	unit.vector[2] = 0;
   267     }
   269     dx = linear->p2.x - linear->p1.x;
   270     dy = linear->p2.y - linear->p1.y;
   272     l = dx * dx + dy * dy;
   274     if (l == 0 || unit.vector[2] == 0)
   275     {
   276 	/* affine transformation only */
   277         pixman_fixed_32_32_t t, next_inc;
   278 	double inc;
   280 	if (l == 0 || v.vector[2] == 0)
   281 	{
   282 	    t = 0;
   283 	    inc = 0;
   284 	}
   285 	else
   286 	{
   287 	    double invden, v2;
   289 	    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
   290 		(l * (double) v.vector[2]);
   291 	    v2 = v.vector[2] * (1. / pixman_fixed_1);
   292 	    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
   293 		 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
   294 	    inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
   295 	}
   296 	next_inc = 0;
   298 	if (((pixman_fixed_32_32_t )(inc * width)) == 0)
   299 	{
   300 	    register uint32_t color;
   301 	    uint16_t dither_diff;
   302 	    uint16_t color16;
   303 	    uint16_t color16b;
   305 	    color = _pixman_gradient_walker_pixel (&walker, t);
   306 	    color16 = dither_8888_to_0565(color, toggle);
   307 	    color16b = dither_8888_to_0565(color, toggle^1);
   308 	    // compute the difference
   309 	    dither_diff =  color16 ^ color16b;
   310 	    while (buffer < end) {
   311 		*buffer++ = color16;
   312 		// use dither_diff to toggle between color16 and color16b
   313 		color16 ^= dither_diff;
   314 		toggle ^= 1;
   315 	    }
   316 	}
   317 	else
   318 	{
   319 	    int i;
   321 	    i = 0;
   322 	    while (buffer < end)
   323 	    {
   324 		if (!mask || *mask++)
   325 		{
   326 		    *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker,
   327 										 t + next_inc),
   328 						  toggle);
   329 		}
   330 		toggle ^= 1;
   331 		i++;
   332 		next_inc = inc * i;
   333 		buffer++;
   334 	    }
   335 	}
   336     }
   337     else
   338     {
   339 	/* projective transformation */
   340         double t;
   342 	t = 0;
   344 	while (buffer < end)
   345 	{
   346 	    if (!mask || *mask++)
   347 	    {
   348 	        if (v.vector[2] != 0)
   349 		{
   350 		    double invden, v2;
   352 		    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
   353 			(l * (double) v.vector[2]);
   354 		    v2 = v.vector[2] * (1. / pixman_fixed_1);
   355 		    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
   356 			 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
   357 		}
   359 		*buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t),
   360 					      toggle);
   361 	    }
   362 	    toggle ^= 1;
   364 	    ++buffer;
   366 	    v.vector[0] += unit.vector[0];
   367 	    v.vector[1] += unit.vector[1];
   368 	    v.vector[2] += unit.vector[2];
   369 	}
   370     }
   372     iter->y++;
   374     return iter->buffer;
   375 }
   377 static uint32_t *
   378 linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
   379 {
   380     uint32_t *buffer = linear_get_scanline_narrow (iter, NULL);
   382     pixman_expand_to_float (
   383 	(argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
   385     return buffer;
   386 }
   388 void
   389 _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t  *iter)
   390 {
   391     // XXX: we can't use this optimization when dithering
   392     if (0 && linear_gradient_is_horizontal (
   393 	    iter->image, iter->x, iter->y, iter->width, iter->height))
   394     {
   395 	if (iter->iter_flags & ITER_16)
   396 	    linear_get_scanline_16 (iter, NULL);
   397 	else if (iter->iter_flags & ITER_NARROW)
   398 	    linear_get_scanline_narrow (iter, NULL);
   399 	else
   400 	    linear_get_scanline_wide (iter, NULL);
   402 	iter->get_scanline = _pixman_iter_get_scanline_noop;
   403     }
   404     else
   405     {
   406 	if (iter->iter_flags & ITER_16)
   407 	    iter->get_scanline = linear_get_scanline_16;
   408 	else if (iter->iter_flags & ITER_NARROW)
   409 	    iter->get_scanline = linear_get_scanline_narrow;
   410 	else
   411 	    iter->get_scanline = linear_get_scanline_wide;
   412     }
   413 }
   415 PIXMAN_EXPORT pixman_image_t *
   416 pixman_image_create_linear_gradient (const pixman_point_fixed_t *  p1,
   417                                      const pixman_point_fixed_t *  p2,
   418                                      const pixman_gradient_stop_t *stops,
   419                                      int                           n_stops)
   420 {
   421     pixman_image_t *image;
   422     linear_gradient_t *linear;
   424     image = _pixman_image_allocate ();
   426     if (!image)
   427 	return NULL;
   429     linear = &image->linear;
   431     if (!_pixman_init_gradient (&linear->common, stops, n_stops))
   432     {
   433 	free (image);
   434 	return NULL;
   435     }
   437     linear->p1 = *p1;
   438     linear->p2 = *p2;
   440     image->type = LINEAR;
   442     return image;
   443 }

mercurial