aboutsummaryrefslogtreecommitdiff
path: root/pixman/pixman
diff options
context:
space:
mode:
Diffstat (limited to 'pixman/pixman')
-rw-r--r--pixman/pixman/pixman-combine-float.c34
-rw-r--r--pixman/pixman/pixman-gradient-walker.c106
-rw-r--r--pixman/pixman/pixman-private.h13
3 files changed, 92 insertions, 61 deletions
diff --git a/pixman/pixman/pixman-combine-float.c b/pixman/pixman/pixman-combine-float.c
index 06ce2037e..5ea739f76 100644
--- a/pixman/pixman/pixman-combine-float.c
+++ b/pixman/pixman/pixman-combine-float.c
@@ -42,8 +42,6 @@
#define force_inline __inline__
#endif
-#define IS_ZERO(f) (-FLT_MIN < (f) && (f) < FLT_MIN)
-
typedef float (* combine_channel_t) (float sa, float s, float da, float d);
static force_inline void
@@ -203,56 +201,56 @@ get_factor (combine_factor_t factor, float sa, float da)
break;
case SA_OVER_DA:
- if (IS_ZERO (da))
+ if (FLOAT_IS_ZERO (da))
f = 1.0f;
else
f = CLAMP (sa / da);
break;
case DA_OVER_SA:
- if (IS_ZERO (sa))
+ if (FLOAT_IS_ZERO (sa))
f = 1.0f;
else
f = CLAMP (da / sa);
break;
case INV_SA_OVER_DA:
- if (IS_ZERO (da))
+ if (FLOAT_IS_ZERO (da))
f = 1.0f;
else
f = CLAMP ((1.0f - sa) / da);
break;
case INV_DA_OVER_SA:
- if (IS_ZERO (sa))
+ if (FLOAT_IS_ZERO (sa))
f = 1.0f;
else
f = CLAMP ((1.0f - da) / sa);
break;
case ONE_MINUS_SA_OVER_DA:
- if (IS_ZERO (da))
+ if (FLOAT_IS_ZERO (da))
f = 0.0f;
else
f = CLAMP (1.0f - sa / da);
break;
case ONE_MINUS_DA_OVER_SA:
- if (IS_ZERO (sa))
+ if (FLOAT_IS_ZERO (sa))
f = 0.0f;
else
f = CLAMP (1.0f - da / sa);
break;
case ONE_MINUS_INV_DA_OVER_SA:
- if (IS_ZERO (sa))
+ if (FLOAT_IS_ZERO (sa))
f = 0.0f;
else
f = CLAMP (1.0f - (1.0f - da) / sa);
break;
case ONE_MINUS_INV_SA_OVER_DA:
- if (IS_ZERO (da))
+ if (FLOAT_IS_ZERO (da))
f = 0.0f;
else
f = CLAMP (1.0f - (1.0f - sa) / da);
@@ -405,11 +403,11 @@ blend_lighten (float sa, float s, float da, float d)
static force_inline float
blend_color_dodge (float sa, float s, float da, float d)
{
- if (IS_ZERO (d))
+ if (FLOAT_IS_ZERO (d))
return 0.0f;
else if (d * sa >= sa * da - s * da)
return sa * da;
- else if (IS_ZERO (sa - s))
+ else if (FLOAT_IS_ZERO (sa - s))
return sa * da;
else
return sa * sa * d / (sa - s);
@@ -422,7 +420,7 @@ blend_color_burn (float sa, float s, float da, float d)
return sa * da;
else if (sa * (da - d) >= s * da)
return 0.0f;
- else if (IS_ZERO (s))
+ else if (FLOAT_IS_ZERO (s))
return 0.0f;
else
return sa * (da - sa * (da - d) / s);
@@ -442,14 +440,14 @@ blend_soft_light (float sa, float s, float da, float d)
{
if (2 * s < sa)
{
- if (IS_ZERO (da))
+ if (FLOAT_IS_ZERO (da))
return d * sa;
else
return d * sa - d * (da - d) * (sa - 2 * s) / da;
}
else
{
- if (IS_ZERO (da))
+ if (FLOAT_IS_ZERO (da))
{
return 0.0f;
}
@@ -658,7 +656,7 @@ clip_color (rgb_t *color, float a)
if (n < 0.0f)
{
t = l - n;
- if (IS_ZERO (t))
+ if (FLOAT_IS_ZERO (t))
{
color->r = 0.0f;
color->g = 0.0f;
@@ -674,7 +672,7 @@ clip_color (rgb_t *color, float a)
if (x > a)
{
t = x - l;
- if (IS_ZERO (t))
+ if (FLOAT_IS_ZERO (t))
{
color->r = a;
color->g = a;
@@ -758,7 +756,7 @@ set_sat (rgb_t *src, float sat)
t = *max - *min;
- if (IS_ZERO (t))
+ if (FLOAT_IS_ZERO (t))
{
*mid = *max = 0.0f;
}
diff --git a/pixman/pixman/pixman-gradient-walker.c b/pixman/pixman/pixman-gradient-walker.c
index e7e724fa6..5944a559a 100644
--- a/pixman/pixman/pixman-gradient-walker.c
+++ b/pixman/pixman/pixman-gradient-walker.c
@@ -37,11 +37,14 @@ _pixman_gradient_walker_init (pixman_gradient_walker_t *walker,
walker->stops = gradient->stops;
walker->left_x = 0;
walker->right_x = 0x10000;
- walker->stepper = 0;
- walker->left_ag = 0;
- walker->left_rb = 0;
- walker->right_ag = 0;
- walker->right_rb = 0;
+ walker->a_s = 0.0f;
+ walker->a_b = 0.0f;
+ walker->r_s = 0.0f;
+ walker->r_b = 0.0f;
+ walker->g_s = 0.0f;
+ walker->g_b = 0.0f;
+ walker->b_s = 0.0f;
+ walker->b_b = 0.0f;
walker->repeat = repeat;
walker->need_reset = TRUE;
@@ -55,6 +58,9 @@ gradient_walker_reset (pixman_gradient_walker_t *walker,
pixman_color_t *left_c, *right_c;
int n, count = walker->num_stops;
pixman_gradient_stop_t *stops = walker->stops;
+ float la, lr, lg, lb;
+ float ra, rr, rg, rb;
+ float lx, rx;
if (walker->repeat == PIXMAN_REPEAT_NORMAL)
{
@@ -116,24 +122,49 @@ gradient_walker_reset (pixman_gradient_walker_t *walker,
left_c = right_c;
}
- walker->left_x = left_x;
- walker->right_x = right_x;
- walker->left_ag = ((left_c->alpha >> 8) << 16) | (left_c->green >> 8);
- walker->left_rb = ((left_c->red & 0xff00) << 8) | (left_c->blue >> 8);
- walker->right_ag = ((right_c->alpha >> 8) << 16) | (right_c->green >> 8);
- walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8);
-
- if (walker->left_x == walker->right_x ||
- (walker->left_ag == walker->right_ag &&
- walker->left_rb == walker->right_rb))
+ /* The alpha channel is scaled to be in the [0, 255] interval,
+ * and the red/green/blue channels are scaled to be in [0, 1].
+ * This ensures that after premultiplication all channels will
+ * be in the [0, 255] interval.
+ */
+ la = (left_c->alpha * (1.0f/257.0f));
+ lr = (left_c->red * (1.0f/257.0f));
+ lg = (left_c->green * (1.0f/257.0f));
+ lb = (left_c->blue * (1.0f/257.0f));
+
+ ra = (right_c->alpha * (1.0f/257.0f));
+ rr = (right_c->red * (1.0f/257.0f));
+ rg = (right_c->green * (1.0f/257.0f));
+ rb = (right_c->blue * (1.0f/257.0f));
+
+ lx = left_x * (1.0f/65536.0f);
+ rx = right_x * (1.0f/65536.0f);
+
+ if (FLOAT_IS_ZERO (rx - lx) || left_x == INT32_MIN || right_x == INT32_MAX)
{
- walker->stepper = 0;
+ walker->a_s = walker->r_s = walker->g_s = walker->b_s = 0.0f;
+ walker->a_b = (la + ra) / 2.0f;
+ walker->r_b = (lr + rr) / 510.0f;
+ walker->g_b = (lg + rg) / 510.0f;
+ walker->b_b = (lb + rb) / 510.0f;
}
else
{
- int32_t width = right_x - left_x;
- walker->stepper = ((1 << 24) + width / 2) / width;
+ float w_rec = 1.0f / (rx - lx);
+
+ walker->a_b = (la * rx - ra * lx) * w_rec;
+ walker->r_b = (lr * rx - rr * lx) * w_rec * (1.0f/255.0f);
+ walker->g_b = (lg * rx - rg * lx) * w_rec * (1.0f/255.0f);
+ walker->b_b = (lb * rx - rb * lx) * w_rec * (1.0f/255.0f);
+
+ walker->a_s = (ra - la) * w_rec;
+ walker->r_s = (rr - lr) * w_rec * (1.0f/255.0f);
+ walker->g_s = (rg - lg) * w_rec * (1.0f/255.0f);
+ walker->b_s = (rb - lb) * w_rec * (1.0f/255.0f);
}
+
+ walker->left_x = left_x;
+ walker->right_x = right_x;
walker->need_reset = FALSE;
}
@@ -142,31 +173,30 @@ uint32_t
_pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
pixman_fixed_48_16_t x)
{
- int dist, idist;
- uint32_t t1, t2, a, color;
+ float a, r, g, b;
+ uint8_t a8, r8, g8, b8;
+ uint32_t v;
+ float y;
if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
- gradient_walker_reset (walker, x);
-
- dist = ((int)(x - walker->left_x) * walker->stepper) >> 16;
- idist = 256 - dist;
+ gradient_walker_reset (walker, x);
- /* combined INTERPOLATE and premultiply */
- t1 = walker->left_rb * idist + walker->right_rb * dist;
- t1 = (t1 >> 8) & 0xff00ff;
+ y = x * (1.0f / 65536.0f);
- t2 = walker->left_ag * idist + walker->right_ag * dist;
- t2 &= 0xff00ff00;
+ a = walker->a_s * y + walker->a_b;
+ r = a * (walker->r_s * y + walker->r_b);
+ g = a * (walker->g_s * y + walker->g_b);
+ b = a * (walker->b_s * y + walker->b_b);
- color = t2 & 0xff000000;
- a = t2 >> 24;
+ a8 = a + 0.5f;
+ r8 = r + 0.5f;
+ g8 = g + 0.5f;
+ b8 = b + 0.5f;
- t1 = t1 * a + 0x800080;
- t1 = (t1 + ((t1 >> 8) & 0xff00ff)) >> 8;
+ v = ((a8 << 24) & 0xff000000) |
+ ((r8 << 16) & 0x00ff0000) |
+ ((g8 << 8) & 0x0000ff00) |
+ ((b8 >> 0) & 0x000000ff);
- t2 = (t2 >> 8) * a + 0x800080;
- t2 = (t2 + ((t2 >> 8) & 0xff00ff));
-
- return (color | (t1 & 0xff00ff) | (t2 & 0xff00));
+ return v;
}
-
diff --git a/pixman/pixman/pixman-private.h b/pixman/pixman/pixman-private.h
index 181ab5c35..6d9c05321 100644
--- a/pixman/pixman/pixman-private.h
+++ b/pixman/pixman/pixman-private.h
@@ -1,3 +1,5 @@
+#include <float.h>
+
#ifndef PIXMAN_PRIVATE_H
#define PIXMAN_PRIVATE_H
@@ -317,13 +319,12 @@ _pixman_image_validate (pixman_image_t *image);
*/
typedef struct
{
- uint32_t left_ag;
- uint32_t left_rb;
- uint32_t right_ag;
- uint32_t right_rb;
+ float a_s, a_b;
+ float r_s, r_b;
+ float g_s, g_b;
+ float b_s, b_b;
pixman_fixed_t left_x;
pixman_fixed_t right_x;
- pixman_fixed_t stepper;
pixman_gradient_stop_t *stops;
int num_stops;
@@ -879,6 +880,8 @@ pixman_list_move_to_front (pixman_list_t *list, pixman_link_t *link)
#define CLIP(v, low, high) ((v) < (low) ? (low) : ((v) > (high) ? (high) : (v)))
+#define FLOAT_IS_ZERO(f) (-FLT_MIN < (f) && (f) < FLT_MIN)
+
/* Conversion between 8888 and 0565 */
static force_inline uint16_t