зеркало из https://github.com/mozilla/gecko-dev.git
311 строки
8.7 KiB
Diff
311 строки
8.7 KiB
Diff
|
diff --git a/gfx/cairo/libpixman/src/pixman-dither.h b/gfx/cairo/libpixman/src/pixman-dither.h
|
||
|
new file mode 100644
|
||
|
--- /dev/null
|
||
|
+++ b/gfx/cairo/libpixman/src/pixman-dither.h
|
||
|
@@ -0,0 +1,51 @@
|
||
|
+#define R16_BITS 5
|
||
|
+#define G16_BITS 6
|
||
|
+#define B16_BITS 5
|
||
|
+
|
||
|
+#define R16_SHIFT (B16_BITS + G16_BITS)
|
||
|
+#define G16_SHIFT (B16_BITS)
|
||
|
+#define B16_SHIFT 0
|
||
|
+
|
||
|
+#define MASK 0xff
|
||
|
+#define ONE_HALF 0x80
|
||
|
+
|
||
|
+#define A_SHIFT 8 * 3
|
||
|
+#define R_SHIFT 8 * 2
|
||
|
+#define G_SHIFT 8
|
||
|
+#define A_MASK 0xff000000
|
||
|
+#define R_MASK 0xff0000
|
||
|
+#define G_MASK 0xff00
|
||
|
+
|
||
|
+#define RB_MASK 0xff00ff
|
||
|
+#define AG_MASK 0xff00ff00
|
||
|
+#define RB_ONE_HALF 0x800080
|
||
|
+#define RB_MASK_PLUS_ONE 0x10000100
|
||
|
+
|
||
|
+#define ALPHA_8(x) ((x) >> A_SHIFT)
|
||
|
+#define RED_8(x) (((x) >> R_SHIFT) & MASK)
|
||
|
+#define GREEN_8(x) (((x) >> G_SHIFT) & MASK)
|
||
|
+#define BLUE_8(x) ((x) & MASK)
|
||
|
+
|
||
|
+// This uses the same dithering technique that Skia does.
|
||
|
+// It is essentially preturbing the lower bit based on the
|
||
|
+// high bit
|
||
|
+static inline uint16_t dither_32_to_16(uint32_t c)
|
||
|
+{
|
||
|
+ uint8_t b = BLUE_8(c);
|
||
|
+ uint8_t g = GREEN_8(c);
|
||
|
+ uint8_t r = RED_8(c);
|
||
|
+ r = ((r << 1) - ((r >> (8 - R16_BITS) << (8 - R16_BITS)) | (r >> R16_BITS))) >> (8 - R16_BITS);
|
||
|
+ g = ((g << 1) - ((g >> (8 - G16_BITS) << (8 - G16_BITS)) | (g >> G16_BITS))) >> (8 - G16_BITS);
|
||
|
+ b = ((b << 1) - ((b >> (8 - B16_BITS) << (8 - B16_BITS)) | (b >> B16_BITS))) >> (8 - B16_BITS);
|
||
|
+ return ((r << R16_SHIFT) | (g << G16_SHIFT) | (b << B16_SHIFT));
|
||
|
+}
|
||
|
+
|
||
|
+static inline uint16_t dither_8888_to_0565(uint32_t color, pixman_bool_t toggle)
|
||
|
+{
|
||
|
+ // alternate between a preturbed truncation and a regular truncation
|
||
|
+ if (toggle) {
|
||
|
+ return dither_32_to_16(color);
|
||
|
+ } else {
|
||
|
+ return CONVERT_8888_TO_0565(color);
|
||
|
+ }
|
||
|
+}
|
||
|
diff --git a/gfx/cairo/libpixman/src/pixman-linear-gradient.c b/gfx/cairo/libpixman/src/pixman-linear-gradient.c
|
||
|
--- a/gfx/cairo/libpixman/src/pixman-linear-gradient.c
|
||
|
+++ b/gfx/cairo/libpixman/src/pixman-linear-gradient.c
|
||
|
@@ -26,16 +26,18 @@
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include <config.h>
|
||
|
#endif
|
||
|
#include <stdlib.h>
|
||
|
#include "pixman-private.h"
|
||
|
|
||
|
+#include "pixman-dither.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;
|
||
|
@@ -222,25 +224,28 @@ linear_get_scanline_narrow (pixman_iter_
|
||
|
return iter->buffer;
|
||
|
}
|
||
|
|
||
|
static uint16_t convert_8888_to_0565(uint32_t color)
|
||
|
{
|
||
|
return CONVERT_8888_TO_0565(color);
|
||
|
}
|
||
|
|
||
|
+
|
||
|
+
|
||
|
static uint32_t *
|
||
|
linear_get_scanline_16 (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;
|
||
|
uint16_t * buffer = (uint16_t*)iter->buffer;
|
||
|
+ pixman_bool_t toggle = ((x ^ y) & 1);
|
||
|
|
||
|
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;
|
||
|
uint16_t *end = buffer + width;
|
||
|
pixman_gradient_walker_t walker;
|
||
|
@@ -294,34 +299,47 @@ linear_get_scanline_16 (pixman_iter_t *
|
||
|
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 uint16_t color;
|
||
|
+ register uint32_t color;
|
||
|
+ uint16_t dither_diff;
|
||
|
+ uint16_t color16;
|
||
|
+ uint16_t color16b;
|
||
|
|
||
|
- color = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t));
|
||
|
- while (buffer < end)
|
||
|
- *buffer++ = color;
|
||
|
+ color = _pixman_gradient_walker_pixel (&walker, t);
|
||
|
+ color16 = dither_8888_to_0565(color, toggle);
|
||
|
+ color16b = dither_8888_to_0565(color, toggle^1);
|
||
|
+ // compute the difference
|
||
|
+ dither_diff = color16 ^ color16b;
|
||
|
+ while (buffer < end) {
|
||
|
+ *buffer++ = color16;
|
||
|
+ // use dither_diff to toggle between color16 and color16b
|
||
|
+ color16 ^= dither_diff;
|
||
|
+ toggle ^= 1;
|
||
|
+ }
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
i = 0;
|
||
|
while (buffer < end)
|
||
|
{
|
||
|
if (!mask || *mask++)
|
||
|
{
|
||
|
- *buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker,
|
||
|
- t + next_inc));
|
||
|
+ *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker,
|
||
|
+ t + next_inc),
|
||
|
+ toggle);
|
||
|
}
|
||
|
+ toggle ^= 1;
|
||
|
i++;
|
||
|
next_inc = inc * i;
|
||
|
buffer++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
@@ -340,18 +358,20 @@ linear_get_scanline_16 (pixman_iter_t *
|
||
|
|
||
|
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 = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t));
|
||
|
+ *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t),
|
||
|
+ toggle);
|
||
|
}
|
||
|
+ toggle ^= 1;
|
||
|
|
||
|
++buffer;
|
||
|
|
||
|
v.vector[0] += unit.vector[0];
|
||
|
v.vector[1] += unit.vector[1];
|
||
|
v.vector[2] += unit.vector[2];
|
||
|
}
|
||
|
}
|
||
|
@@ -369,17 +389,18 @@ linear_get_scanline_wide (pixman_iter_t
|
||
|
pixman_expand ((uint64_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 (
|
||
|
+ // XXX: we can't use this optimization when dithering
|
||
|
+ if (0 && linear_gradient_is_horizontal (
|
||
|
iter->image, iter->x, iter->y, iter->width, iter->height))
|
||
|
{
|
||
|
if (iter->flags & ITER_16)
|
||
|
linear_get_scanline_16 (iter, NULL);
|
||
|
else if (iter->flags & ITER_NARROW)
|
||
|
linear_get_scanline_narrow (iter, NULL);
|
||
|
else
|
||
|
linear_get_scanline_wide (iter, NULL);
|
||
|
diff --git a/gfx/cairo/libpixman/src/pixman-radial-gradient.c b/gfx/cairo/libpixman/src/pixman-radial-gradient.c
|
||
|
--- a/gfx/cairo/libpixman/src/pixman-radial-gradient.c
|
||
|
+++ b/gfx/cairo/libpixman/src/pixman-radial-gradient.c
|
||
|
@@ -29,16 +29,18 @@
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include <config.h>
|
||
|
#endif
|
||
|
#include <stdlib.h>
|
||
|
#include <math.h>
|
||
|
#include "pixman-private.h"
|
||
|
|
||
|
+#include "pixman-dither.h"
|
||
|
+
|
||
|
static inline pixman_fixed_32_32_t
|
||
|
dot (pixman_fixed_48_16_t x1,
|
||
|
pixman_fixed_48_16_t y1,
|
||
|
pixman_fixed_48_16_t z1,
|
||
|
pixman_fixed_48_16_t x2,
|
||
|
pixman_fixed_48_16_t y2,
|
||
|
pixman_fixed_48_16_t z2)
|
||
|
{
|
||
|
@@ -489,16 +491,17 @@ radial_get_scanline_16 (pixman_iter_t *i
|
||
|
* <=> for every p, the radiuses associated with the two t solutions
|
||
|
* have opposite sign
|
||
|
*/
|
||
|
pixman_image_t *image = iter->image;
|
||
|
int x = iter->x;
|
||
|
int y = iter->y;
|
||
|
int width = iter->width;
|
||
|
uint16_t *buffer = iter->buffer;
|
||
|
+ pixman_bool_t toggle = ((x ^ y) & 1);
|
||
|
|
||
|
gradient_t *gradient = (gradient_t *)image;
|
||
|
radial_gradient_t *radial = (radial_gradient_t *)image;
|
||
|
uint16_t *end = buffer + width;
|
||
|
pixman_gradient_walker_t walker;
|
||
|
pixman_vector_t v, unit;
|
||
|
|
||
|
/* reference point is the center of the pixel */
|
||
|
@@ -575,25 +578,27 @@ radial_get_scanline_16 (pixman_iter_t *i
|
||
|
unit.vector[0], unit.vector[1], 0);
|
||
|
ddc = 2 * dot (unit.vector[0], unit.vector[1], 0,
|
||
|
unit.vector[0], unit.vector[1], 0);
|
||
|
|
||
|
while (buffer < end)
|
||
|
{
|
||
|
if (!mask || *mask++)
|
||
|
{
|
||
|
- *buffer = convert_8888_to_0565(
|
||
|
+ *buffer = dither_8888_to_0565(
|
||
|
radial_compute_color (radial->a, b, c,
|
||
|
radial->inva,
|
||
|
radial->delta.radius,
|
||
|
radial->mindr,
|
||
|
&walker,
|
||
|
- image->common.repeat));
|
||
|
+ image->common.repeat),
|
||
|
+ toggle);
|
||
|
}
|
||
|
|
||
|
+ toggle ^= 1;
|
||
|
b += db;
|
||
|
c += dc;
|
||
|
dc += ddc;
|
||
|
++buffer;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
@@ -621,31 +626,33 @@ radial_get_scanline_16 (pixman_iter_t *i
|
||
|
radial->delta.x, radial->delta.y,
|
||
|
radial->delta.radius);
|
||
|
/* / pixman_fixed_1 / pixman_fixed_1 */
|
||
|
|
||
|
c = fdot (pdx, pdy, -radial->c1.radius,
|
||
|
pdx, pdy, radial->c1.radius);
|
||
|
/* / pixman_fixed_1 / pixman_fixed_1 */
|
||
|
|
||
|
- *buffer = convert_8888_to_0565 (
|
||
|
+ *buffer = dither_8888_to_0565 (
|
||
|
radial_compute_color (radial->a, b, c,
|
||
|
radial->inva,
|
||
|
radial->delta.radius,
|
||
|
radial->mindr,
|
||
|
&walker,
|
||
|
- image->common.repeat));
|
||
|
+ image->common.repeat),
|
||
|
+ toggle);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*buffer = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
++buffer;
|
||
|
+ toggle ^= 1;
|
||
|
|
||
|
v.vector[0] += unit.vector[0];
|
||
|
v.vector[1] += unit.vector[1];
|
||
|
v.vector[2] += unit.vector[2];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
iter->y++;
|
||
|
|