diff --git a/src/video/SDL_shape.c b/src/video/SDL_shape.c index 2362ed7f7f..cb8d7c2f49 100644 --- a/src/video/SDL_shape.c +++ b/src/video/SDL_shape.c @@ -55,14 +55,15 @@ SDL_bool SDL_IsShapedWindow(const SDL_Window *window) return (window->shaper != NULL); } -/* REQUIRES that bitmap point to a w-by-h bitmap with ppb pixels-per-byte. */ -void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode, SDL_Surface *shape, Uint8 *bitmap, Uint8 ppb) +/* REQUIRES that bitmap point to a w-by-h bitmap with ppb pixels-per-byte and alignBytes scan line alignment. */ +void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode, SDL_Surface *shape, Uint8* bitmap, Uint8 ppb, Uint8 alignBytes) { int x = 0; int y = 0; Uint8 r = 0, g = 0, b = 0, alpha = 0; Uint32 mask_value = 0; - size_t bytes_per_scanline = (size_t)(shape->w + (ppb - 1)) / ppb; + int bytes_per_scanline; + Uint8 *bitmap_scanline; SDL_Color key; @@ -70,6 +71,9 @@ void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode, SDL_Surface *shape, Uint SDL_LockSurface(shape); } + bytes_per_scanline = (shape->w + (ppb - 1)) / ppb; + bytes_per_scanline = (bytes_per_scanline + (alignBytes - 1)) & ~(alignBytes - 1); + SDL_memset(bitmap, 0, shape->h * bytes_per_scanline); for (y = 0; y < shape->h; y++) { diff --git a/src/video/SDL_shape_internals.h b/src/video/SDL_shape_internals.h index fa8e90adbf..85e164c5b6 100644 --- a/src/video/SDL_shape_internals.h +++ b/src/video/SDL_shape_internals.h @@ -51,7 +51,7 @@ typedef struct SDL_ShapeTree typedef void (*SDL_TraversalFunction)(SDL_ShapeTree *, void *); -extern void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode, SDL_Surface *shape, Uint8 *bitmap, Uint8 ppb); +extern void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode, SDL_Surface *shape, Uint8 *bitmap, Uint8 ppb, Uint8 alignBytes); extern SDL_ShapeTree *SDL_CalculateShapeTree(SDL_WindowShapeMode mode, SDL_Surface *shape); extern void SDL_TraverseShapeTree(SDL_ShapeTree *tree, SDL_TraversalFunction function, void *closure); extern void SDL_FreeShapeTree(SDL_ShapeTree **shape_tree); diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c index 44491d37ab..b9d77af31f 100644 --- a/src/video/windows/SDL_windowsmouse.c +++ b/src/video/windows/SDL_windowsmouse.c @@ -26,6 +26,8 @@ #include "../../events/SDL_mouse_c.h" +#include "../SDL_shape_internals.h" + DWORD SDL_last_warp_time = 0; HCURSOR SDL_cursor = NULL; static SDL_Cursor *SDL_blank_cursor = NULL; @@ -86,81 +88,71 @@ static SDL_Cursor *WIN_CreateDefaultCursor() static SDL_Cursor *WIN_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y) { - /* msdn says cursor mask has to be padded out to word alignment. Not sure - if that means machine word or WORD, but this handles either case. */ - const size_t pad = (sizeof(size_t) * 8); /* 32 or 64, or whatever. */ - SDL_Cursor *cursor; HICON hicon; - HICON hcursor; - HDC hdc; - BITMAPV4HEADER bmh; - LPVOID pixels; - LPVOID maskbits; - size_t maskbitslen; - SDL_bool isstack; + SDL_Cursor *cursor; + BITMAPV5HEADER bmh; ICONINFO ii; + HBITMAP colorBitmap = NULL, maskBitmap = NULL; + LPVOID colorBits, maskBits; + int maskPitch; SDL_zero(bmh); - bmh.bV4Size = sizeof(bmh); - bmh.bV4Width = surface->w; - bmh.bV4Height = -surface->h; /* Invert the image */ - bmh.bV4Planes = 1; - bmh.bV4BitCount = 32; - bmh.bV4V4Compression = BI_BITFIELDS; - bmh.bV4AlphaMask = 0xFF000000; - bmh.bV4RedMask = 0x00FF0000; - bmh.bV4GreenMask = 0x0000FF00; - bmh.bV4BlueMask = 0x000000FF; + bmh.bV5Size = sizeof(bmh); + bmh.bV5Width = surface->w; + bmh.bV5Height = -surface->h; /* Invert the image to make it top-down. */ + bmh.bV5Planes = 1; + bmh.bV5BitCount = surface->format->BitsPerPixel; + bmh.bV5Compression = BI_BITFIELDS; + bmh.bV5RedMask = surface->format->Rmask; + bmh.bV5GreenMask = surface->format->Gmask; + bmh.bV5BlueMask = surface->format->Bmask; + bmh.bV5AlphaMask = surface->format->Amask; - maskbitslen = ((surface->w + (pad - (surface->w % pad))) / 8) * surface->h; - maskbits = SDL_small_alloc(Uint8, maskbitslen, &isstack); - if (!maskbits) { - SDL_OutOfMemory(); + colorBitmap = CreateDIBSection(NULL, (BITMAPINFO *) &bmh, DIB_RGB_COLORS, &colorBits, NULL, 0); + + if (!colorBitmap || !colorBits) { + WIN_SetError("CreateDIBSection()"); return NULL; } - /* AND the cursor against full bits: no change. We already have alpha. */ - SDL_memset(maskbits, 0xFF, maskbitslen); + SDL_memcpy(colorBits, surface->pixels, surface->pitch * surface->h); + + /* Scan lines in 1 bpp mask should be aligned to WORD boundary. */ + maskPitch = (((surface->w + 15) & ~15) / 8); + if ((maskBits = SDL_stack_alloc(Uint8, maskPitch * surface->h))) { + SDL_WindowShapeMode mode = { ShapeModeDefault }; + SDL_CalculateShapeBitmap(mode, surface, maskBits, 8, sizeof(WORD)); + maskBitmap = CreateBitmap(surface->w, surface->h, 1, 1, maskBits); + SDL_stack_free(maskBits); + } - hdc = GetDC(NULL); SDL_zero(ii); ii.fIcon = FALSE; ii.xHotspot = (DWORD)hot_x; ii.yHotspot = (DWORD)hot_y; - ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO *)&bmh, DIB_RGB_COLORS, &pixels, NULL, 0); - ii.hbmMask = CreateBitmap(surface->w, surface->h, 1, 1, maskbits); - ReleaseDC(NULL, hdc); - SDL_small_free(maskbits, isstack); - - SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888); - SDL_assert(surface->pitch == surface->w * 4); - SDL_memcpy(pixels, surface->pixels, (size_t)surface->h * surface->pitch); + ii.hbmColor = colorBitmap; + ii.hbmMask = maskBitmap; hicon = CreateIconIndirect(&ii); - DeleteObject(ii.hbmColor); - DeleteObject(ii.hbmMask); + if (colorBitmap) { + DeleteObject(colorBitmap); + } + + if (maskBitmap) { + DeleteObject(maskBitmap); + } if (!hicon) { WIN_SetError("CreateIconIndirect()"); return NULL; } - /* The cursor returned by CreateIconIndirect does not respect system cursor size - preference, use CopyImage to duplicate the cursor with desired sizes */ - hcursor = CopyImage(hicon, IMAGE_CURSOR, surface->w, surface->h, 0); - DestroyIcon(hicon); - - if (!hcursor) { - WIN_SetError("CopyImage()"); - return NULL; - } - cursor = SDL_calloc(1, sizeof(*cursor)); if (cursor) { - cursor->driverdata = hcursor; + cursor->driverdata = hicon; } else { - DestroyIcon(hcursor); + DestroyIcon(hicon); SDL_OutOfMemory(); } diff --git a/src/video/x11/SDL_x11shape.c b/src/video/x11/SDL_x11shape.c index 373d6eba1a..f1fd20e145 100644 --- a/src/video/x11/SDL_x11shape.c +++ b/src/video/x11/SDL_x11shape.c @@ -81,7 +81,7 @@ int X11_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape, SDL_WindowS data = shaper->driverdata; /* Assume that shaper->alphacutoff already has a value, because SDL_SetWindowShape() should have given it one. */ - SDL_CalculateShapeBitmap(shaper->mode, shape, data->bitmap, 8); + SDL_CalculateShapeBitmap(shaper->mode, shape, data->bitmap, 8, 1); windowdata = shaper->window->driverdata; shapemask = X11_XCreateBitmapFromData(windowdata->videodata->display, windowdata->xwindow, data->bitmap, shaper->window->w, shaper->window->h);