michael@0: summary: Bug 689707. Use lower precision bilinear interpolation. r=joe michael@0: michael@0: diff --git a/gfx/cairo/libpixman/src/pixman-bits-image.c b/gfx/cairo/libpixman/src/pixman-bits-image.c michael@0: --- a/gfx/cairo/libpixman/src/pixman-bits-image.c michael@0: +++ b/gfx/cairo/libpixman/src/pixman-bits-image.c michael@0: @@ -124,18 +124,18 @@ bits_image_fetch_pixel_bilinear (bits_im michael@0: int height = image->height; michael@0: int x1, y1, x2, y2; michael@0: uint32_t tl, tr, bl, br; michael@0: int32_t distx, disty; michael@0: michael@0: x1 = x - pixman_fixed_1 / 2; michael@0: y1 = y - pixman_fixed_1 / 2; michael@0: michael@0: - distx = (x1 >> 8) & 0xff; michael@0: - disty = (y1 >> 8) & 0xff; michael@0: + distx = interpolation_coord(x1); michael@0: + disty = interpolation_coord(y1); michael@0: michael@0: x1 = pixman_fixed_to_int (x1); michael@0: y1 = pixman_fixed_to_int (y1); michael@0: x2 = x1 + 1; michael@0: y2 = y1 + 1; michael@0: michael@0: if (repeat_mode != PIXMAN_REPEAT_NONE) michael@0: { michael@0: @@ -190,17 +190,17 @@ bits_image_fetch_bilinear_no_repeat_8888 michael@0: michael@0: if (!pixman_transform_point_3d (bits->common.transform, &v)) michael@0: return; michael@0: michael@0: ux = ux_top = ux_bottom = bits->common.transform->matrix[0][0]; michael@0: x = x_top = x_bottom = v.vector[0] - pixman_fixed_1/2; michael@0: michael@0: y = v.vector[1] - pixman_fixed_1/2; michael@0: - disty = (y >> 8) & 0xff; michael@0: + disty = interpolation_coord(y); michael@0: michael@0: /* Load the pointers to the first and second lines from the source michael@0: * image that bilinear code must read. michael@0: * michael@0: * The main trick in this code is about the check if any line are michael@0: * outside of the image; michael@0: * michael@0: * When I realize that a line (any one) is outside, I change michael@0: @@ -299,17 +299,17 @@ bits_image_fetch_bilinear_no_repeat_8888 michael@0: while (buffer < end && x < 0) michael@0: { michael@0: uint32_t tr, br; michael@0: int32_t distx; michael@0: michael@0: tr = top_row[pixman_fixed_to_int (x_top) + 1] | top_mask; michael@0: br = bottom_row[pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; michael@0: michael@0: - distx = (x >> 8) & 0xff; michael@0: + distx = interpolation_coord(x); michael@0: michael@0: *buffer++ = bilinear_interpolation (0, tr, 0, br, distx, disty); michael@0: michael@0: x += ux; michael@0: x_top += ux_top; michael@0: x_bottom += ux_bottom; michael@0: mask += mask_inc; michael@0: } michael@0: @@ -324,17 +324,17 @@ bits_image_fetch_bilinear_no_repeat_8888 michael@0: uint32_t tl, tr, bl, br; michael@0: int32_t distx; michael@0: michael@0: tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; michael@0: tr = top_row [pixman_fixed_to_int (x_top) + 1] | top_mask; michael@0: bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; michael@0: br = bottom_row [pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; michael@0: michael@0: - distx = (x >> 8) & 0xff; michael@0: + distx = interpolation_coord(x); michael@0: michael@0: *buffer = bilinear_interpolation (tl, tr, bl, br, distx, disty); michael@0: } michael@0: michael@0: buffer++; michael@0: x += ux; michael@0: x_top += ux_top; michael@0: x_bottom += ux_bottom; michael@0: @@ -348,17 +348,17 @@ bits_image_fetch_bilinear_no_repeat_8888 michael@0: if (*mask) michael@0: { michael@0: uint32_t tl, bl; michael@0: int32_t distx; michael@0: michael@0: tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; michael@0: bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; michael@0: michael@0: - distx = (x >> 8) & 0xff; michael@0: + distx = interpolation_coord(x); michael@0: michael@0: *buffer = bilinear_interpolation (tl, 0, bl, 0, distx, disty); michael@0: } michael@0: michael@0: buffer++; michael@0: x += ux; michael@0: x_top += ux_top; michael@0: x_bottom += ux_bottom; michael@0: @@ -675,18 +675,18 @@ bits_image_fetch_bilinear_affine (pixman michael@0: const uint8_t *row2; michael@0: michael@0: if (mask && !mask[i]) michael@0: goto next; michael@0: michael@0: x1 = x - pixman_fixed_1 / 2; michael@0: y1 = y - pixman_fixed_1 / 2; michael@0: michael@0: - distx = (x1 >> 8) & 0xff; michael@0: - disty = (y1 >> 8) & 0xff; michael@0: + distx = interpolation_coord(x1); michael@0: + disty = interpolation_coord(y1); michael@0: michael@0: y1 = pixman_fixed_to_int (y1); michael@0: y2 = y1 + 1; michael@0: x1 = pixman_fixed_to_int (x1); michael@0: x2 = x1 + 1; michael@0: michael@0: if (repeat_mode != PIXMAN_REPEAT_NONE) michael@0: { michael@0: diff --git a/gfx/cairo/libpixman/src/pixman-inlines.h b/gfx/cairo/libpixman/src/pixman-inlines.h michael@0: --- a/gfx/cairo/libpixman/src/pixman-inlines.h michael@0: +++ b/gfx/cairo/libpixman/src/pixman-inlines.h michael@0: @@ -76,16 +76,31 @@ repeat (pixman_repeat_t repeat, int *c, michael@0: { michael@0: *c = MOD (*c, size * 2); michael@0: if (*c >= size) michael@0: *c = size * 2 - *c - 1; michael@0: } michael@0: return TRUE; michael@0: } michael@0: michael@0: +#ifdef MOZ_GFX_OPTIMIZE_MOBILE michael@0: +#define LOW_QUALITY_INTERPOLATION michael@0: +#endif michael@0: + michael@0: +static force_inline int32_t michael@0: +interpolation_coord(pixman_fixed_t t) michael@0: +{ michael@0: +#ifdef LOW_QUALITY_INTERPOLATION michael@0: + return (t >> 12) & 0xf; michael@0: +#else michael@0: + return (t >> 8) & 0xff; michael@0: +#endif michael@0: +} michael@0: + michael@0: + michael@0: #if SIZEOF_LONG > 4 michael@0: michael@0: static force_inline uint32_t michael@0: bilinear_interpolation (uint32_t tl, uint32_t tr, michael@0: uint32_t bl, uint32_t br, michael@0: int distx, int disty) michael@0: { michael@0: uint64_t distxy, distxiy, distixy, distixiy; michael@0: @@ -122,16 +137,44 @@ bilinear_interpolation (uint32_t tl, uin michael@0: f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy; michael@0: r |= ((f >> 16) & 0x000000ff00000000ull) | (f & 0xff000000ull); michael@0: michael@0: return (uint32_t)(r >> 16); michael@0: } michael@0: michael@0: #else michael@0: michael@0: +#ifdef LOW_QUALITY_INTERPOLATION michael@0: +/* Based on Filter_32_opaque_portable from Skia */ michael@0: +static force_inline uint32_t michael@0: +bilinear_interpolation(uint32_t a00, uint32_t a01, michael@0: + uint32_t a10, uint32_t a11, michael@0: + int x, int y) michael@0: +{ michael@0: + int xy = x * y; michael@0: + static const uint32_t mask = 0xff00ff; michael@0: + michael@0: + int scale = 256 - 16*y - 16*x + xy; michael@0: + uint32_t lo = (a00 & mask) * scale; michael@0: + uint32_t hi = ((a00 >> 8) & mask) * scale; michael@0: + michael@0: + scale = 16*x - xy; michael@0: + lo += (a01 & mask) * scale; michael@0: + hi += ((a01 >> 8) & mask) * scale; michael@0: + michael@0: + scale = 16*y - xy; michael@0: + lo += (a10 & mask) * scale; michael@0: + hi += ((a10 >> 8) & mask) * scale; michael@0: + michael@0: + lo += (a11 & mask) * xy; michael@0: + hi += ((a11 >> 8) & mask) * xy; michael@0: + michael@0: + return ((lo >> 8) & mask) | (hi & ~mask); michael@0: +} michael@0: +#else michael@0: static force_inline uint32_t michael@0: bilinear_interpolation (uint32_t tl, uint32_t tr, michael@0: uint32_t bl, uint32_t br, michael@0: int distx, int disty) michael@0: { michael@0: int distxy, distxiy, distixy, distixiy; michael@0: uint32_t f, r; michael@0: michael@0: @@ -164,17 +207,17 @@ bilinear_interpolation (uint32_t tl, uin michael@0: michael@0: /* Alpha */ michael@0: f = (tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy michael@0: + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy; michael@0: r |= f & 0xff000000; michael@0: michael@0: return r; michael@0: } michael@0: - michael@0: +#endif michael@0: #endif michael@0: michael@0: /* michael@0: * For each scanline fetched from source image with PAD repeat: michael@0: * - calculate how many pixels need to be padded on the left side michael@0: * - calculate how many pixels need to be padded on the right side michael@0: * - update width to only count pixels which are fetched from the image michael@0: * All this information is returned via 'width', 'left_pad', 'right_pad'