gfx/cairo/libpixman/src/pixman-combine-float.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
     2 /*
     3  * Copyright © 2010, 2012 Soren Sandmann Pedersen
     4  * Copyright © 2010, 2012 Red Hat, Inc.
     5  *
     6  * Permission is hereby granted, free of charge, to any person obtaining a
     7  * copy of this software and associated documentation files (the "Software"),
     8  * to deal in the Software without restriction, including without limitation
     9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
    10  * and/or sell copies of the Software, and to permit persons to whom the
    11  * Software is furnished to do so, subject to the following conditions:
    12  *
    13  * The above copyright notice and this permission notice (including the next
    14  * paragraph) shall be included in all copies or substantial portions of the
    15  * Software.
    16  *
    17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
    20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    23  * DEALINGS IN THE SOFTWARE.
    24  *
    25  * Author: Soren Sandmann Pedersen (sandmann@cs.au.dk)
    26  */
    28 #ifdef HAVE_CONFIG_H
    29 #include <config.h>
    30 #endif
    32 #include <math.h>
    33 #include <string.h>
    34 #include <float.h>
    36 #include "pixman-private.h"
    38 /* Workaround for http://gcc.gnu.org/PR54965 */
    39 /* GCC 4.6 has problems with force_inline, so just use normal inline instead */
    40 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 6)
    41 #undef force_inline
    42 #define force_inline __inline__
    43 #endif
    45 #define IS_ZERO(f)     (-FLT_MIN < (f) && (f) < FLT_MIN)
    47 typedef float (* combine_channel_t) (float sa, float s, float da, float d);
    49 static force_inline void
    50 combine_inner (pixman_bool_t component,
    51 	       float *dest, const float *src, const float *mask, int n_pixels,
    52 	       combine_channel_t combine_a, combine_channel_t combine_c)
    53 {
    54     int i;
    56     if (!mask)
    57     {
    58 	for (i = 0; i < 4 * n_pixels; i += 4)
    59 	{
    60 	    float sa = src[i + 0];
    61 	    float sr = src[i + 1];
    62 	    float sg = src[i + 2];
    63 	    float sb = src[i + 3];
    65 	    float da = dest[i + 0];
    66 	    float dr = dest[i + 1];
    67 	    float dg = dest[i + 2];
    68 	    float db = dest[i + 3];					
    70 	    dest[i + 0] = combine_a (sa, sa, da, da);
    71 	    dest[i + 1] = combine_c (sa, sr, da, dr);
    72 	    dest[i + 2] = combine_c (sa, sg, da, dg);
    73 	    dest[i + 3] = combine_c (sa, sb, da, db);
    74 	}
    75     }
    76     else
    77     {
    78 	for (i = 0; i < 4 * n_pixels; i += 4)
    79 	{
    80 	    float sa, sr, sg, sb;
    81 	    float ma, mr, mg, mb;
    82 	    float da, dr, dg, db;
    84 	    sa = src[i + 0];
    85 	    sr = src[i + 1];
    86 	    sg = src[i + 2];
    87 	    sb = src[i + 3];
    89 	    if (component)
    90 	    {
    91 		ma = mask[i + 0];
    92 		mr = mask[i + 1];
    93 		mg = mask[i + 2];
    94 		mb = mask[i + 3];
    96 		sr *= mr;
    97 		sg *= mg;
    98 		sb *= mb;
   100 		ma *= sa;
   101 		mr *= sa;
   102 		mg *= sa;
   103 		mb *= sa;
   105 		sa = ma;
   106 	    }
   107 	    else
   108 	    {
   109 		ma = mask[i + 0];
   111 		sa *= ma;
   112 		sr *= ma;
   113 		sg *= ma;
   114 		sb *= ma;
   116 		ma = mr = mg = mb = sa;
   117 	    }
   119 	    da = dest[i + 0];
   120 	    dr = dest[i + 1];
   121 	    dg = dest[i + 2];
   122 	    db = dest[i + 3];
   124 	    dest[i + 0] = combine_a (ma, sa, da, da);
   125 	    dest[i + 1] = combine_c (mr, sr, da, dr);
   126 	    dest[i + 2] = combine_c (mg, sg, da, dg);
   127 	    dest[i + 3] = combine_c (mb, sb, da, db);
   128 	}
   129     }
   130 }
   132 #define MAKE_COMBINER(name, component, combine_a, combine_c)		\
   133     static void								\
   134     combine_ ## name ## _float (pixman_implementation_t *imp,		\
   135 				pixman_op_t              op,		\
   136 				float                   *dest,		\
   137 				const float             *src,		\
   138 				const float             *mask,		\
   139 				int		         n_pixels)	\
   140     {									\
   141 	combine_inner (component, dest, src, mask, n_pixels,		\
   142 		       combine_a, combine_c);				\
   143     }
   145 #define MAKE_COMBINERS(name, combine_a, combine_c)			\
   146     MAKE_COMBINER(name ## _ca, TRUE, combine_a, combine_c)		\
   147     MAKE_COMBINER(name ## _u, FALSE, combine_a, combine_c)
   150 /*
   151  * Porter/Duff operators
   152  */
   153 typedef enum
   154 {
   155     ZERO,
   156     ONE,
   157     SRC_ALPHA,
   158     DEST_ALPHA,
   159     INV_SA,
   160     INV_DA,
   161     SA_OVER_DA,
   162     DA_OVER_SA,
   163     INV_SA_OVER_DA,
   164     INV_DA_OVER_SA,
   165     ONE_MINUS_SA_OVER_DA,
   166     ONE_MINUS_DA_OVER_SA,
   167     ONE_MINUS_INV_DA_OVER_SA,
   168     ONE_MINUS_INV_SA_OVER_DA
   169 } combine_factor_t;
   171 #define CLAMP(f)					\
   172     (((f) < 0)? 0 : (((f) > 1.0) ? 1.0 : (f)))
   174 static force_inline float
   175 get_factor (combine_factor_t factor, float sa, float da)
   176 {
   177     float f = -1;
   179     switch (factor)
   180     {
   181     case ZERO:
   182 	f = 0.0f;
   183 	break;
   185     case ONE:
   186 	f = 1.0f;
   187 	break;
   189     case SRC_ALPHA:
   190 	f = sa;
   191 	break;
   193     case DEST_ALPHA:
   194 	f = da;
   195 	break;
   197     case INV_SA:
   198 	f = 1 - sa;
   199 	break;
   201     case INV_DA:
   202 	f = 1 - da;
   203 	break;
   205     case SA_OVER_DA:
   206 	if (IS_ZERO (da))
   207 	    f = 1.0f;
   208 	else
   209 	    f = CLAMP (sa / da);
   210 	break;
   212     case DA_OVER_SA:
   213 	if (IS_ZERO (sa))
   214 	    f = 1.0f;
   215 	else
   216 	    f = CLAMP (da / sa);
   217 	break;
   219     case INV_SA_OVER_DA:
   220 	if (IS_ZERO (da))
   221 	    f = 1.0f;
   222 	else
   223 	    f = CLAMP ((1.0f - sa) / da);
   224 	break;
   226     case INV_DA_OVER_SA:
   227 	if (IS_ZERO (sa))
   228 	    f = 1.0f;
   229 	else
   230 	    f = CLAMP ((1.0f - da) / sa);
   231 	break;
   233     case ONE_MINUS_SA_OVER_DA:
   234 	if (IS_ZERO (da))
   235 	    f = 0.0f;
   236 	else
   237 	    f = CLAMP (1.0f - sa / da);
   238 	break;
   240     case ONE_MINUS_DA_OVER_SA:
   241 	if (IS_ZERO (sa))
   242 	    f = 0.0f;
   243 	else
   244 	    f = CLAMP (1.0f - da / sa);
   245 	break;
   247     case ONE_MINUS_INV_DA_OVER_SA:
   248 	if (IS_ZERO (sa))
   249 	    f = 0.0f;
   250 	else
   251 	    f = CLAMP (1.0f - (1.0f - da) / sa);
   252 	break;
   254     case ONE_MINUS_INV_SA_OVER_DA:
   255 	if (IS_ZERO (da))
   256 	    f = 0.0f;
   257 	else
   258 	    f = CLAMP (1.0f - (1.0f - sa) / da);
   259 	break;
   260     }
   262     return f;
   263 }
   265 #define MAKE_PD_COMBINERS(name, a, b)					\
   266     static float force_inline						\
   267     pd_combine_ ## name (float sa, float s, float da, float d)		\
   268     {									\
   269 	const float fa = get_factor (a, sa, da);			\
   270 	const float fb = get_factor (b, sa, da);			\
   271 									\
   272 	return MIN (1.0f, s * fa + d * fb);				\
   273     }									\
   274     									\
   275     MAKE_COMBINERS(name, pd_combine_ ## name, pd_combine_ ## name)
   277 MAKE_PD_COMBINERS (clear,			ZERO,				ZERO)
   278 MAKE_PD_COMBINERS (src,				ONE,				ZERO)
   279 MAKE_PD_COMBINERS (dst,				ZERO,				ONE)
   280 MAKE_PD_COMBINERS (over,			ONE,				INV_SA)
   281 MAKE_PD_COMBINERS (over_reverse,		INV_DA,				ONE)
   282 MAKE_PD_COMBINERS (in,				DEST_ALPHA,			ZERO)
   283 MAKE_PD_COMBINERS (in_reverse,			ZERO,				SRC_ALPHA)
   284 MAKE_PD_COMBINERS (out,				INV_DA,				ZERO)
   285 MAKE_PD_COMBINERS (out_reverse,			ZERO,				INV_SA)
   286 MAKE_PD_COMBINERS (atop,			DEST_ALPHA,			INV_SA)
   287 MAKE_PD_COMBINERS (atop_reverse,		INV_DA,				SRC_ALPHA)
   288 MAKE_PD_COMBINERS (xor,				INV_DA,				INV_SA)
   289 MAKE_PD_COMBINERS (add,				ONE,				ONE)
   291 MAKE_PD_COMBINERS (saturate,			INV_DA_OVER_SA,			ONE)
   293 MAKE_PD_COMBINERS (disjoint_clear,		ZERO,				ZERO)
   294 MAKE_PD_COMBINERS (disjoint_src,		ONE,				ZERO)
   295 MAKE_PD_COMBINERS (disjoint_dst,		ZERO,				ONE)
   296 MAKE_PD_COMBINERS (disjoint_over,		ONE,				INV_SA_OVER_DA)
   297 MAKE_PD_COMBINERS (disjoint_over_reverse,	INV_DA_OVER_SA,			ONE)
   298 MAKE_PD_COMBINERS (disjoint_in,			ONE_MINUS_INV_DA_OVER_SA,	ZERO)
   299 MAKE_PD_COMBINERS (disjoint_in_reverse,		ZERO,				ONE_MINUS_INV_SA_OVER_DA)
   300 MAKE_PD_COMBINERS (disjoint_out,		INV_DA_OVER_SA,			ZERO)
   301 MAKE_PD_COMBINERS (disjoint_out_reverse,	ZERO,				INV_SA_OVER_DA)
   302 MAKE_PD_COMBINERS (disjoint_atop,		ONE_MINUS_INV_DA_OVER_SA,	INV_SA_OVER_DA)
   303 MAKE_PD_COMBINERS (disjoint_atop_reverse,	INV_DA_OVER_SA,			ONE_MINUS_INV_SA_OVER_DA)
   304 MAKE_PD_COMBINERS (disjoint_xor,		INV_DA_OVER_SA,			INV_SA_OVER_DA)
   306 MAKE_PD_COMBINERS (conjoint_clear,		ZERO,				ZERO)
   307 MAKE_PD_COMBINERS (conjoint_src,		ONE,				ZERO)
   308 MAKE_PD_COMBINERS (conjoint_dst,		ZERO,				ONE)
   309 MAKE_PD_COMBINERS (conjoint_over,		ONE,				ONE_MINUS_SA_OVER_DA)
   310 MAKE_PD_COMBINERS (conjoint_over_reverse,	ONE_MINUS_DA_OVER_SA,		ONE)
   311 MAKE_PD_COMBINERS (conjoint_in,			DA_OVER_SA,			ZERO)
   312 MAKE_PD_COMBINERS (conjoint_in_reverse,		ZERO,				SA_OVER_DA)
   313 MAKE_PD_COMBINERS (conjoint_out,		ONE_MINUS_DA_OVER_SA,		ZERO)
   314 MAKE_PD_COMBINERS (conjoint_out_reverse,	ZERO,				ONE_MINUS_SA_OVER_DA)
   315 MAKE_PD_COMBINERS (conjoint_atop,		DA_OVER_SA,			ONE_MINUS_SA_OVER_DA)
   316 MAKE_PD_COMBINERS (conjoint_atop_reverse,	ONE_MINUS_DA_OVER_SA,		SA_OVER_DA)
   317 MAKE_PD_COMBINERS (conjoint_xor,		ONE_MINUS_DA_OVER_SA,		ONE_MINUS_SA_OVER_DA)
   319 /*
   320  * PDF blend modes:
   321  *
   322  * The following blend modes have been taken from the PDF ISO 32000
   323  * specification, which at this point in time is available from
   324  * http://www.adobe.com/devnet/acrobat/pdfs/PDF32000_2008.pdf
   325  * The relevant chapters are 11.3.5 and 11.3.6.
   326  * The formula for computing the final pixel color given in 11.3.6 is:
   327  * αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs)
   328  * with B() being the blend function.
   329  * Note that OVER is a special case of this operation, using B(Cb, Cs) = Cs
   330  *
   331  * These blend modes should match the SVG filter draft specification, as
   332  * it has been designed to mirror ISO 32000. Note that at the current point
   333  * no released draft exists that shows this, as the formulas have not been
   334  * updated yet after the release of ISO 32000.
   335  *
   336  * The default implementation here uses the PDF_SEPARABLE_BLEND_MODE and
   337  * PDF_NON_SEPARABLE_BLEND_MODE macros, which take the blend function as an
   338  * argument. Note that this implementation operates on premultiplied colors,
   339  * while the PDF specification does not. Therefore the code uses the formula
   340  * ar.Cra = (1 – as) . Dca + (1 – ad) . Sca + B(Dca, ad, Sca, as)
   341  */
   343 #define MAKE_SEPARABLE_PDF_COMBINERS(name)				\
   344     static force_inline float						\
   345     combine_ ## name ## _a (float sa, float s, float da, float d)	\
   346     {									\
   347 	return da + sa - da * sa;					\
   348     }									\
   349     									\
   350     static force_inline float						\
   351     combine_ ## name ## _c (float sa, float s, float da, float d)	\
   352     {									\
   353 	float f = (1 - sa) * d + (1 - da) * s;				\
   354 									\
   355 	return f + blend_ ## name (sa, s, da, d);			\
   356     }									\
   357     									\
   358     MAKE_COMBINERS (name, combine_ ## name ## _a, combine_ ## name ## _c)
   360 static force_inline float
   361 blend_multiply (float sa, float s, float da, float d)
   362 {
   363     return d * s;
   364 }
   366 static force_inline float
   367 blend_screen (float sa, float s, float da, float d)
   368 {
   369     return d * sa + s * da - s * d;
   370 }
   372 static force_inline float
   373 blend_overlay (float sa, float s, float da, float d)
   374 {
   375     if (2 * d < da)
   376 	return 2 * s * d;
   377     else
   378 	return sa * da - 2 * (da - d) * (sa - s);
   379 }
   381 static force_inline float
   382 blend_darken (float sa, float s, float da, float d)
   383 {
   384     s = s * da;
   385     d = d * sa;
   387     if (s > d)
   388 	return d;
   389     else
   390 	return s;
   391 }
   393 static force_inline float
   394 blend_lighten (float sa, float s, float da, float d)
   395 {
   396     s = s * da;
   397     d = d * sa;
   399     if (s > d)
   400 	return s;
   401     else
   402 	return d;
   403 }
   405 static force_inline float
   406 blend_color_dodge (float sa, float s, float da, float d)
   407 {
   408     if (IS_ZERO (d))
   409 	return 0.0f;
   410     else if (d * sa >= sa * da - s * da)
   411 	return sa * da;
   412     else if (IS_ZERO (sa - s))
   413 	return sa * da;
   414     else
   415 	return sa * sa * d / (sa - s);
   416 }
   418 static force_inline float
   419 blend_color_burn (float sa, float s, float da, float d)
   420 {
   421     if (d >= da)
   422 	return sa * da;
   423     else if (sa * (da - d) >= s * da)
   424 	return 0.0f;
   425     else if (IS_ZERO (s))
   426 	return 0.0f;
   427     else
   428 	return sa * (da - sa * (da - d) / s);
   429 }
   431 static force_inline float
   432 blend_hard_light (float sa, float s, float da, float d)
   433 {
   434     if (2 * s < sa)
   435 	return 2 * s * d;
   436     else
   437 	return sa * da - 2 * (da - d) * (sa - s);
   438 }
   440 static force_inline float
   441 blend_soft_light (float sa, float s, float da, float d)
   442 {
   443     if (2 * s < sa)
   444     {
   445 	if (IS_ZERO (da))
   446 	    return d * sa;
   447 	else
   448 	    return d * sa - d * (da - d) * (sa - 2 * s) / da;
   449     }
   450     else
   451     {
   452 	if (IS_ZERO (da))
   453 	{
   454 	    return 0.0f;
   455 	}
   456 	else
   457 	{
   458 	    if (4 * d <= da)
   459 		return d * sa + (2 * s - sa) * d * ((16 * d / da - 12) * d / da + 3);
   460 	    else
   461 		return d * sa + (sqrtf (d * da) - d) * (2 * s - sa);
   462 	}
   463     }
   464 }
   466 static force_inline float
   467 blend_difference (float sa, float s, float da, float d)
   468 {
   469     float dsa = d * sa;
   470     float sda = s * da;
   472     if (sda < dsa)
   473 	return dsa - sda;
   474     else
   475 	return sda - dsa;
   476 }
   478 static force_inline float
   479 blend_exclusion (float sa, float s, float da, float d)
   480 {
   481     return s * da + d * sa - 2 * d * s;
   482 }
   484 MAKE_SEPARABLE_PDF_COMBINERS (multiply)
   485 MAKE_SEPARABLE_PDF_COMBINERS (screen)
   486 MAKE_SEPARABLE_PDF_COMBINERS (overlay)
   487 MAKE_SEPARABLE_PDF_COMBINERS (darken)
   488 MAKE_SEPARABLE_PDF_COMBINERS (lighten)
   489 MAKE_SEPARABLE_PDF_COMBINERS (color_dodge)
   490 MAKE_SEPARABLE_PDF_COMBINERS (color_burn)
   491 MAKE_SEPARABLE_PDF_COMBINERS (hard_light)
   492 MAKE_SEPARABLE_PDF_COMBINERS (soft_light)
   493 MAKE_SEPARABLE_PDF_COMBINERS (difference)
   494 MAKE_SEPARABLE_PDF_COMBINERS (exclusion)
   496 /*
   497  * PDF nonseperable blend modes.
   498  *
   499  * These are implemented using the following functions to operate in Hsl
   500  * space, with Cmax, Cmid, Cmin referring to the max, mid and min value
   501  * of the red, green and blue components.
   502  *
   503  * LUM (C) = 0.3 × Cred + 0.59 × Cgreen + 0.11 × Cblue
   504  *
   505  * clip_color (C):
   506  *   l = LUM (C)
   507  *   min = Cmin
   508  *   max = Cmax
   509  *   if n < 0.0
   510  *     C = l + (((C – l) × l) ⁄     (l – min))
   511  *   if x > 1.0
   512  *     C = l + (((C – l) × (1 – l)) (max – l))
   513  *   return C
   514  *
   515  * set_lum (C, l):
   516  *   d = l – LUM (C)
   517  *   C += d
   518  *   return clip_color (C)
   519  *
   520  * SAT (C) = CH_MAX (C) - CH_MIN (C)
   521  *
   522  * set_sat (C, s):
   523  *  if Cmax > Cmin
   524  *    Cmid = ( ( ( Cmid – Cmin ) × s ) ⁄ ( Cmax – Cmin ) )
   525  *    Cmax = s
   526  *  else
   527  *    Cmid = Cmax = 0.0
   528  *  Cmin = 0.0
   529  *  return C
   530  */
   532 /* For premultiplied colors, we need to know what happens when C is
   533  * multiplied by a real number. LUM and SAT are linear:
   534  *
   535  *    LUM (r × C) = r × LUM (C)		SAT (r × C) = r × SAT (C)
   536  *
   537  * If we extend clip_color with an extra argument a and change
   538  *
   539  *        if x >= 1.0
   540  *
   541  * into
   542  *
   543  *        if x >= a
   544  *
   545  * then clip_color is also linear:
   546  *
   547  *     r * clip_color (C, a) = clip_color (r_c, ra);
   548  *
   549  * for positive r.
   550  *
   551  * Similarly, we can extend set_lum with an extra argument that is just passed
   552  * on to clip_color:
   553  *
   554  *     r × set_lum ( C, l, a)
   555  *
   556  *   = r × clip_color ( C + l - LUM (C), a)
   557  *
   558  *   = clip_color ( r * C + r × l - LUM (r × C), r * a)
   559  *
   560  *   = set_lum ( r * C, r * l, r * a)
   561  *
   562  * Finally, set_sat:
   563  *
   564  *     r * set_sat (C, s) = set_sat (x * C, r * s)
   565  *
   566  * The above holds for all non-zero x because they x'es in the fraction for
   567  * C_mid cancel out. Specifically, it holds for x = r:
   568  *
   569  *     r * set_sat (C, s) = set_sat (r_c, rs)
   570  *
   571  *
   572  *
   573  *
   574  * So, for the non-separable PDF blend modes, we have (using s, d for
   575  * non-premultiplied colors, and S, D for premultiplied:
   576  *
   577  *   Color:
   578  *
   579  *     a_s * a_d * B(s, d)
   580  *   = a_s * a_d * set_lum (S/a_s, LUM (D/a_d), 1)
   581  *   = set_lum (S * a_d, a_s * LUM (D), a_s * a_d)
   582  *
   583  *
   584  *   Luminosity:
   585  *
   586  *     a_s * a_d * B(s, d)
   587  *   = a_s * a_d * set_lum (D/a_d, LUM(S/a_s), 1)
   588  *   = set_lum (a_s * D, a_d * LUM(S), a_s * a_d)
   589  *
   590  *
   591  *   Saturation:
   592  *
   593  *     a_s * a_d * B(s, d)
   594  *   = a_s * a_d * set_lum (set_sat (D/a_d, SAT (S/a_s)), LUM (D/a_d), 1)
   595  *   = set_lum (a_s * a_d * set_sat (D/a_d, SAT (S/a_s)),
   596  *                                        a_s * LUM (D), a_s * a_d)
   597  *   = set_lum (set_sat (a_s * D, a_d * SAT (S), a_s * LUM (D), a_s * a_d))
   598  *
   599  *   Hue:
   600  *
   601  *     a_s * a_d * B(s, d)
   602  *   = a_s * a_d * set_lum (set_sat (S/a_s, SAT (D/a_d)), LUM (D/a_d), 1)
   603  *   = set_lum (set_sat (a_d * S, a_s * SAT (D)), a_s * LUM (D), a_s * a_d)
   604  *
   605  */
   607 typedef struct
   608 {
   609     float	r;
   610     float	g;
   611     float	b;
   612 } rgb_t;
   614 static force_inline float
   615 minf (float a, float b)
   616 {
   617     return a < b? a : b;
   618 }
   620 static force_inline float
   621 maxf (float a, float b)
   622 {
   623     return a > b? a : b;
   624 }
   626 static force_inline float
   627 channel_min (const rgb_t *c)
   628 {
   629     return minf (minf (c->r, c->g), c->b);
   630 }
   632 static force_inline float
   633 channel_max (const rgb_t *c)
   634 {
   635     return maxf (maxf (c->r, c->g), c->b);
   636 }
   638 static force_inline float
   639 get_lum (const rgb_t *c)
   640 {
   641     return c->r * 0.3f + c->g * 0.59f + c->b * 0.11f;
   642 }
   644 static force_inline float
   645 get_sat (const rgb_t *c)
   646 {
   647     return channel_max (c) - channel_min (c);
   648 }
   650 static void
   651 clip_color (rgb_t *color, float a)
   652 {
   653     float l = get_lum (color);
   654     float n = channel_min (color);
   655     float x = channel_max (color);
   656     float t;
   658     if (n < 0.0f)
   659     {
   660 	t = l - n;
   661 	if (IS_ZERO (t))
   662 	{
   663 	    color->r = 0.0f;
   664 	    color->g = 0.0f;
   665 	    color->b = 0.0f;
   666 	}
   667 	else
   668 	{
   669 	    color->r = l + (((color->r - l) * l) / t);
   670 	    color->g = l + (((color->g - l) * l) / t);
   671 	    color->b = l + (((color->b - l) * l) / t);
   672 	}
   673     }
   674     if (x > a)
   675     {
   676 	t = x - l;
   677 	if (IS_ZERO (t))
   678 	{
   679 	    color->r = a;
   680 	    color->g = a;
   681 	    color->b = a;
   682 	}
   683 	else
   684 	{
   685 	    color->r = l + (((color->r - l) * (a - l) / t));
   686 	    color->g = l + (((color->g - l) * (a - l) / t));
   687 	    color->b = l + (((color->b - l) * (a - l) / t));
   688 	}
   689     }
   690 }
   692 static void
   693 set_lum (rgb_t *color, float sa, float l)
   694 {
   695     float d = l - get_lum (color);
   697     color->r = color->r + d;
   698     color->g = color->g + d;
   699     color->b = color->b + d;
   701     clip_color (color, sa);
   702 }
   704 static void
   705 set_sat (rgb_t *src, float sat)
   706 {
   707     float *max, *mid, *min;
   708     float t;
   710     if (src->r > src->g)
   711     {
   712 	if (src->r > src->b)
   713 	{
   714 	    max = &(src->r);
   716 	    if (src->g > src->b)
   717 	    {
   718 		mid = &(src->g);
   719 		min = &(src->b);
   720 	    }
   721 	    else
   722 	    {
   723 		mid = &(src->b);
   724 		min = &(src->g);
   725 	    }
   726 	}
   727 	else
   728 	{
   729 	    max = &(src->b);
   730 	    mid = &(src->r);
   731 	    min = &(src->g);
   732 	}
   733     }
   734     else
   735     {
   736 	if (src->r > src->b)
   737 	{
   738 	    max = &(src->g);
   739 	    mid = &(src->r);
   740 	    min = &(src->b);
   741 	}
   742 	else
   743 	{
   744 	    min = &(src->r);
   746 	    if (src->g > src->b)
   747 	    {
   748 		max = &(src->g);
   749 		mid = &(src->b);
   750 	    }
   751 	    else
   752 	    {
   753 		max = &(src->b);
   754 		mid = &(src->g);
   755 	    }
   756 	}
   757     }
   759     t = *max - *min;
   761     if (IS_ZERO (t))
   762     {
   763 	*mid = *max = 0.0f;
   764     }
   765     else
   766     {
   767 	*mid = ((*mid - *min) * sat) / t;
   768 	*max = sat;
   769     }
   771     *min = 0.0f;
   772 }
   774 /*
   775  * Hue:
   776  * B(Cb, Cs) = set_lum (set_sat (Cs, SAT (Cb)), LUM (Cb))
   777  */
   778 static force_inline void
   779 blend_hsl_hue (rgb_t *res,
   780 	       const rgb_t *dest, float da,
   781 	       const rgb_t *src, float sa)
   782 {
   783     res->r = src->r * da;
   784     res->g = src->g * da;
   785     res->b = src->b * da;
   787     set_sat (res, get_sat (dest) * sa);
   788     set_lum (res, sa * da, get_lum (dest) * sa);
   789 }
   791 /*
   792  * Saturation:
   793  * B(Cb, Cs) = set_lum (set_sat (Cb, SAT (Cs)), LUM (Cb))
   794  */
   795 static force_inline void
   796 blend_hsl_saturation (rgb_t *res,
   797 		      const rgb_t *dest, float da,
   798 		      const rgb_t *src, float sa)
   799 {
   800     res->r = dest->r * sa;
   801     res->g = dest->g * sa;
   802     res->b = dest->b * sa;
   804     set_sat (res, get_sat (src) * da);
   805     set_lum (res, sa * da, get_lum (dest) * sa);
   806 }
   808 /*
   809  * Color:
   810  * B(Cb, Cs) = set_lum (Cs, LUM (Cb))
   811  */
   812 static force_inline void
   813 blend_hsl_color (rgb_t *res,
   814 		 const rgb_t *dest, float da,
   815 		 const rgb_t *src, float sa)
   816 {
   817     res->r = src->r * da;
   818     res->g = src->g * da;
   819     res->b = src->b * da;
   821     set_lum (res, sa * da, get_lum (dest) * sa);
   822 }
   824 /*
   825  * Luminosity:
   826  * B(Cb, Cs) = set_lum (Cb, LUM (Cs))
   827  */
   828 static force_inline void
   829 blend_hsl_luminosity (rgb_t *res,
   830 		      const rgb_t *dest, float da,
   831 		      const rgb_t *src, float sa)
   832 {
   833     res->r = dest->r * sa;
   834     res->g = dest->g * sa;
   835     res->b = dest->b * sa;
   837     set_lum (res, sa * da, get_lum (src) * da);
   838 }
   840 #define MAKE_NON_SEPARABLE_PDF_COMBINERS(name)				\
   841     static void								\
   842     combine_ ## name ## _u_float (pixman_implementation_t *imp,		\
   843 				  pixman_op_t              op,		\
   844 				  float                   *dest,	\
   845 				  const float             *src,		\
   846 				  const float             *mask,	\
   847 				  int		           n_pixels)	\
   848     {									\
   849     	int i;								\
   850 									\
   851 	for (i = 0; i < 4 * n_pixels; i += 4)				\
   852 	{								\
   853 	    float sa, da;						\
   854 	    rgb_t sc, dc, rc;						\
   855 									\
   856 	    sa = src[i + 0];						\
   857 	    sc.r = src[i + 1];						\
   858 	    sc.g = src[i + 2];						\
   859 	    sc.b = src[i + 3];						\
   860 									\
   861 	    da = dest[i + 0];						\
   862 	    dc.r = dest[i + 1];						\
   863 	    dc.g = dest[i + 2];						\
   864 	    dc.b = dest[i + 3];						\
   865 									\
   866 	    if (mask)							\
   867 	    {								\
   868 		float ma = mask[i + 0];					\
   869 									\
   870 		/* Component alpha is not supported for HSL modes */	\
   871 		sa *= ma;						\
   872 		sc.r *= ma;						\
   873 		sc.g *= ma;						\
   874 		sc.g *= ma;						\
   875 	    }								\
   876 									\
   877 	    blend_ ## name (&rc, &dc, da, &sc, sa);			\
   878 									\
   879 	    dest[i + 0] = sa + da - sa * da;				\
   880 	    dest[i + 1] = (1 - sa) * dc.r + (1 - da) * sc.r + rc.r;	\
   881 	    dest[i + 2] = (1 - sa) * dc.g + (1 - da) * sc.g + rc.g;	\
   882 	    dest[i + 3] = (1 - sa) * dc.b + (1 - da) * sc.b + rc.b;	\
   883 	}								\
   884     }
   886 MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_hue)
   887 MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_saturation)
   888 MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_color)
   889 MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_luminosity)
   891 void
   892 _pixman_setup_combiner_functions_float (pixman_implementation_t *imp)
   893 {
   894     /* Unified alpha */
   895     imp->combine_float[PIXMAN_OP_CLEAR] = combine_clear_u_float;
   896     imp->combine_float[PIXMAN_OP_SRC] = combine_src_u_float;
   897     imp->combine_float[PIXMAN_OP_DST] = combine_dst_u_float;
   898     imp->combine_float[PIXMAN_OP_OVER] = combine_over_u_float;
   899     imp->combine_float[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_u_float;
   900     imp->combine_float[PIXMAN_OP_IN] = combine_in_u_float;
   901     imp->combine_float[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_u_float;
   902     imp->combine_float[PIXMAN_OP_OUT] = combine_out_u_float;
   903     imp->combine_float[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_u_float;
   904     imp->combine_float[PIXMAN_OP_ATOP] = combine_atop_u_float;
   905     imp->combine_float[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_u_float;
   906     imp->combine_float[PIXMAN_OP_XOR] = combine_xor_u_float;
   907     imp->combine_float[PIXMAN_OP_ADD] = combine_add_u_float;
   908     imp->combine_float[PIXMAN_OP_SATURATE] = combine_saturate_u_float;
   910     /* Disjoint, unified */
   911     imp->combine_float[PIXMAN_OP_DISJOINT_CLEAR] = combine_disjoint_clear_u_float;
   912     imp->combine_float[PIXMAN_OP_DISJOINT_SRC] = combine_disjoint_src_u_float;
   913     imp->combine_float[PIXMAN_OP_DISJOINT_DST] = combine_disjoint_dst_u_float;
   914     imp->combine_float[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_u_float;
   915     imp->combine_float[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_disjoint_over_reverse_u_float;
   916     imp->combine_float[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_u_float;
   917     imp->combine_float[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_u_float;
   918     imp->combine_float[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_u_float;
   919     imp->combine_float[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_u_float;
   920     imp->combine_float[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_u_float;
   921     imp->combine_float[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_u_float;
   922     imp->combine_float[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_u_float;
   924     /* Conjoint, unified */
   925     imp->combine_float[PIXMAN_OP_CONJOINT_CLEAR] = combine_conjoint_clear_u_float;
   926     imp->combine_float[PIXMAN_OP_CONJOINT_SRC] = combine_conjoint_src_u_float;
   927     imp->combine_float[PIXMAN_OP_CONJOINT_DST] = combine_conjoint_dst_u_float;
   928     imp->combine_float[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_u_float;
   929     imp->combine_float[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_u_float;
   930     imp->combine_float[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_u_float;
   931     imp->combine_float[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_u_float;
   932     imp->combine_float[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_u_float;
   933     imp->combine_float[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_u_float;
   934     imp->combine_float[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_u_float;
   935     imp->combine_float[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_u_float;
   936     imp->combine_float[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_u_float;
   938     /* PDF operators, unified */
   939     imp->combine_float[PIXMAN_OP_MULTIPLY] = combine_multiply_u_float;
   940     imp->combine_float[PIXMAN_OP_SCREEN] = combine_screen_u_float;
   941     imp->combine_float[PIXMAN_OP_OVERLAY] = combine_overlay_u_float;
   942     imp->combine_float[PIXMAN_OP_DARKEN] = combine_darken_u_float;
   943     imp->combine_float[PIXMAN_OP_LIGHTEN] = combine_lighten_u_float;
   944     imp->combine_float[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_u_float;
   945     imp->combine_float[PIXMAN_OP_COLOR_BURN] = combine_color_burn_u_float;
   946     imp->combine_float[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_u_float;
   947     imp->combine_float[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_u_float;
   948     imp->combine_float[PIXMAN_OP_DIFFERENCE] = combine_difference_u_float;
   949     imp->combine_float[PIXMAN_OP_EXCLUSION] = combine_exclusion_u_float;
   951     imp->combine_float[PIXMAN_OP_HSL_HUE] = combine_hsl_hue_u_float;
   952     imp->combine_float[PIXMAN_OP_HSL_SATURATION] = combine_hsl_saturation_u_float;
   953     imp->combine_float[PIXMAN_OP_HSL_COLOR] = combine_hsl_color_u_float;
   954     imp->combine_float[PIXMAN_OP_HSL_LUMINOSITY] = combine_hsl_luminosity_u_float;
   956     /* Component alpha combiners */
   957     imp->combine_float_ca[PIXMAN_OP_CLEAR] = combine_clear_ca_float;
   958     imp->combine_float_ca[PIXMAN_OP_SRC] = combine_src_ca_float;
   959     imp->combine_float_ca[PIXMAN_OP_DST] = combine_dst_ca_float;
   960     imp->combine_float_ca[PIXMAN_OP_OVER] = combine_over_ca_float;
   961     imp->combine_float_ca[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_ca_float;
   962     imp->combine_float_ca[PIXMAN_OP_IN] = combine_in_ca_float;
   963     imp->combine_float_ca[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_ca_float;
   964     imp->combine_float_ca[PIXMAN_OP_OUT] = combine_out_ca_float;
   965     imp->combine_float_ca[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_ca_float;
   966     imp->combine_float_ca[PIXMAN_OP_ATOP] = combine_atop_ca_float;
   967     imp->combine_float_ca[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_ca_float;
   968     imp->combine_float_ca[PIXMAN_OP_XOR] = combine_xor_ca_float;
   969     imp->combine_float_ca[PIXMAN_OP_ADD] = combine_add_ca_float;
   970     imp->combine_float_ca[PIXMAN_OP_SATURATE] = combine_saturate_ca_float;
   972     /* Disjoint CA */
   973     imp->combine_float_ca[PIXMAN_OP_DISJOINT_CLEAR] = combine_disjoint_clear_ca_float;
   974     imp->combine_float_ca[PIXMAN_OP_DISJOINT_SRC] = combine_disjoint_src_ca_float;
   975     imp->combine_float_ca[PIXMAN_OP_DISJOINT_DST] = combine_disjoint_dst_ca_float;
   976     imp->combine_float_ca[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_ca_float;
   977     imp->combine_float_ca[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_disjoint_over_reverse_ca_float;
   978     imp->combine_float_ca[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_ca_float;
   979     imp->combine_float_ca[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_ca_float;
   980     imp->combine_float_ca[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_ca_float;
   981     imp->combine_float_ca[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_ca_float;
   982     imp->combine_float_ca[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_ca_float;
   983     imp->combine_float_ca[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_ca_float;
   984     imp->combine_float_ca[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_ca_float;
   986     /* Conjoint CA */
   987     imp->combine_float_ca[PIXMAN_OP_CONJOINT_CLEAR] = combine_conjoint_clear_ca_float;
   988     imp->combine_float_ca[PIXMAN_OP_CONJOINT_SRC] = combine_conjoint_src_ca_float;
   989     imp->combine_float_ca[PIXMAN_OP_CONJOINT_DST] = combine_conjoint_dst_ca_float;
   990     imp->combine_float_ca[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_ca_float;
   991     imp->combine_float_ca[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_ca_float;
   992     imp->combine_float_ca[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_ca_float;
   993     imp->combine_float_ca[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_ca_float;
   994     imp->combine_float_ca[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_ca_float;
   995     imp->combine_float_ca[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_ca_float;
   996     imp->combine_float_ca[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_ca_float;
   997     imp->combine_float_ca[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_ca_float;
   998     imp->combine_float_ca[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_ca_float;
  1000     /* PDF operators CA */
  1001     imp->combine_float_ca[PIXMAN_OP_MULTIPLY] = combine_multiply_ca_float;
  1002     imp->combine_float_ca[PIXMAN_OP_SCREEN] = combine_screen_ca_float;
  1003     imp->combine_float_ca[PIXMAN_OP_OVERLAY] = combine_overlay_ca_float;
  1004     imp->combine_float_ca[PIXMAN_OP_DARKEN] = combine_darken_ca_float;
  1005     imp->combine_float_ca[PIXMAN_OP_LIGHTEN] = combine_lighten_ca_float;
  1006     imp->combine_float_ca[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_ca_float;
  1007     imp->combine_float_ca[PIXMAN_OP_COLOR_BURN] = combine_color_burn_ca_float;
  1008     imp->combine_float_ca[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_ca_float;
  1009     imp->combine_float_ca[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_ca_float;
  1010     imp->combine_float_ca[PIXMAN_OP_DIFFERENCE] = combine_difference_ca_float;
  1011     imp->combine_float_ca[PIXMAN_OP_EXCLUSION] = combine_exclusion_ca_float;
  1013     /* It is not clear that these make sense, so make them noops for now */
  1014     imp->combine_float_ca[PIXMAN_OP_HSL_HUE] = combine_dst_u_float;
  1015     imp->combine_float_ca[PIXMAN_OP_HSL_SATURATION] = combine_dst_u_float;
  1016     imp->combine_float_ca[PIXMAN_OP_HSL_COLOR] = combine_dst_u_float;
  1017     imp->combine_float_ca[PIXMAN_OP_HSL_LUMINOSITY] = combine_dst_u_float;

mercurial