xfree86: Fix rotation of 2-color non-interleaved cursor images

When RandR 1.2's transformation code is enabled, it rotates the cursor
image so that it appears upright on a rotated screen.  This code
completely mangles 2-color cursors on hardware where the the mask and
source images are not interleaved due to two problems:

1. stride is calculated as (width / 4) rather than (width / 8), so the
   expression (y * stride) skips two lines instead of one for every
   time y is incremented.
2. cursor_bitpos ignores the 'mask' parameter if the hardware doesn't
   specify any of the HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_* flags.

To fix this, refactor the code to pass the whole xf86CursorInfoPtr
through to cursor_bitpos and compute the correct stride there based on
the flags.  If none of the SOURCE_MASK_INTERLEAVE flags are set, use
the total cursor size to move the 'image' variable into the mask part
of the image before computing the desired byte pointer.

Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
Reviewed-by: Robert Morell <rmorell@nvidia.com>
Reviewed-by: Alex Deucher <alexdeucher@gmail.com>
Tested-by: Cyril Brulebois <kibi@debian.org>
This commit is contained in:
Aaron Plattner 2010-11-15 20:43:18 -08:00
parent 23e3d1f233
commit ffcbfa0063

View File

@ -1,5 +1,6 @@
/* /*
* Copyright © 2007 Keith Packard * Copyright © 2007 Keith Packard
* Copyright © 2010 Aaron Plattner
* *
* Permission to use, copy, modify, distribute, and sell this software and its * Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that * documentation for any purpose is hereby granted without fee, provided that
@ -126,12 +127,33 @@ xf86_crtc_rotate_coord_back (Rotation rotation,
*y_src = y_dst; *y_src = y_dst;
} }
struct cursor_bit {
CARD8 *byte;
char bitpos;
};
/* /*
* Convert an x coordinate to a position within the cursor bitmap * Convert an x coordinate to a position within the cursor bitmap
*/ */
static int static struct cursor_bit
cursor_bitpos (int flags, int x, Bool mask) cursor_bitpos (CARD8 *image, xf86CursorInfoPtr cursor_info, int x, int y,
Bool mask)
{ {
const int flags = cursor_info->Flags;
const Bool interleaved =
!!(flags & (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8 |
HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16 |
HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 |
HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64));
const int width = cursor_info->MaxWidth;
const int height = cursor_info->MaxHeight;
const int stride = interleaved ? width / 4 : width / 8;
struct cursor_bit ret;
image += y * stride;
if (flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK) if (flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK)
mask = !mask; mask = !mask;
if (flags & HARDWARE_CURSOR_NIBBLE_SWAPPED) if (flags & HARDWARE_CURSOR_NIBBLE_SWAPPED)
@ -149,29 +171,33 @@ cursor_bitpos (int flags, int x, Bool mask)
x = ((x & ~31) << 1) | (mask << 5) | (x & 31); x = ((x & ~31) << 1) | (mask << 5) | (x & 31);
else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64) else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64)
x = ((x & ~63) << 1) | (mask << 6) | (x & 63); x = ((x & ~63) << 1) | (mask << 6) | (x & 63);
return x; else if (mask)
image += stride * height;
ret.byte = image + (x / 8);
ret.bitpos = x & 7;
return ret;
} }
/* /*
* Fetch one bit from a cursor bitmap * Fetch one bit from a cursor bitmap
*/ */
static CARD8 static CARD8
get_bit (CARD8 *image, int stride, int flags, int x, int y, Bool mask) get_bit (CARD8 *image, xf86CursorInfoPtr cursor_info, int x, int y, Bool mask)
{ {
x = cursor_bitpos (flags, x, mask); struct cursor_bit bit = cursor_bitpos(image, cursor_info, x, y, mask);
image += y * stride; return (*bit.byte >> bit.bitpos) & 1;
return (image[(x >> 3)] >> (x & 7)) & 1;
} }
/* /*
* Set one bit in a cursor bitmap * Set one bit in a cursor bitmap
*/ */
static void static void
set_bit (CARD8 *image, int stride, int flags, int x, int y, Bool mask) set_bit (CARD8 *image, xf86CursorInfoPtr cursor_info, int x, int y, Bool mask)
{ {
x = cursor_bitpos (flags, x, mask); struct cursor_bit bit = cursor_bitpos(image, cursor_info, x, y, mask);
image += y * stride; *bit.byte |= 1 << bit.bitpos;
image[(x >> 3)] |= 1 << (x & 7);
} }
/* /*
@ -186,7 +212,6 @@ xf86_crtc_convert_cursor_to_argb (xf86CrtcPtr crtc, unsigned char *src)
CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image; CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image;
int x, y; int x, y;
int xin, yin; int xin, yin;
int stride = cursor_info->MaxWidth >> 2;
int flags = cursor_info->Flags; int flags = cursor_info->Flags;
CARD32 bits; CARD32 bits;
@ -201,10 +226,10 @@ xf86_crtc_convert_cursor_to_argb (xf86CrtcPtr crtc, unsigned char *src)
cursor_info->MaxWidth, cursor_info->MaxWidth,
cursor_info->MaxHeight, cursor_info->MaxHeight,
x, y, &xin, &yin); x, y, &xin, &yin);
if (get_bit (src, stride, flags, xin, yin, TRUE) == if (get_bit (src, cursor_info, xin, yin, TRUE) ==
((flags & HARDWARE_CURSOR_INVERT_MASK) == 0)) ((flags & HARDWARE_CURSOR_INVERT_MASK) == 0))
{ {
if (get_bit (src, stride, flags, xin, yin, FALSE)) if (get_bit (src, cursor_info, xin, yin, FALSE))
bits = xf86_config->cursor_fg; bits = xf86_config->cursor_fg;
else else
bits = xf86_config->cursor_bg; bits = xf86_config->cursor_bg;
@ -407,7 +432,6 @@ xf86_crtc_load_cursor_image (xf86CrtcPtr crtc, CARD8 *src)
int x, y; int x, y;
int xin, yin; int xin, yin;
int stride = cursor_info->MaxWidth >> 2; int stride = cursor_info->MaxWidth >> 2;
int flags = cursor_info->Flags;
cursor_image = xf86_config->cursor_image; cursor_image = xf86_config->cursor_image;
memset(cursor_image, 0, cursor_info->MaxHeight * stride); memset(cursor_image, 0, cursor_info->MaxHeight * stride);
@ -419,10 +443,10 @@ xf86_crtc_load_cursor_image (xf86CrtcPtr crtc, CARD8 *src)
cursor_info->MaxWidth, cursor_info->MaxWidth,
cursor_info->MaxHeight, cursor_info->MaxHeight,
x, y, &xin, &yin); x, y, &xin, &yin);
if (get_bit(src, stride, flags, xin, yin, FALSE)) if (get_bit(src, cursor_info, xin, yin, FALSE))
set_bit(cursor_image, stride, flags, x, y, FALSE); set_bit(cursor_image, cursor_info, x, y, FALSE);
if (get_bit(src, stride, flags, xin, yin, TRUE)) if (get_bit(src, cursor_info, xin, yin, TRUE))
set_bit(cursor_image, stride, flags, x, y, TRUE); set_bit(cursor_image, cursor_info, x, y, TRUE);
} }
} }
crtc->funcs->load_cursor_image (crtc, cursor_image); crtc->funcs->load_cursor_image (crtc, cursor_image);