فهرست منبع

Cleanup WIN_CreateCursor() code a bit

Closes #6476
Dimitriy Ryazantcev 2 سال پیش
والد
کامیت
876c97454a
4فایلهای تغییر یافته به همراه52 افزوده شده و 56 حذف شده
  1. 7 3
      src/video/SDL_shape.c
  2. 1 1
      src/video/SDL_shape_internals.h
  3. 43 51
      src/video/windows/SDL_windowsmouse.c
  4. 1 1
      src/video/x11/SDL_x11shape.c

+ 7 - 3
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++) {

+ 1 - 1
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);

+ 43 - 51
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;
-
-    maskbitslen = ((surface->w + (pad - (surface->w % pad))) / 8) * surface->h;
-    maskbits = SDL_small_alloc(Uint8, maskbitslen, &isstack);
-    if (!maskbits) {
-        SDL_OutOfMemory();
+    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;
+
+    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 (!hicon) {
-        WIN_SetError("CreateIconIndirect()");
-        return NULL;
+    if (colorBitmap) {
+        DeleteObject(colorBitmap);
     }
 
-    /* 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 (maskBitmap) {
+        DeleteObject(maskBitmap);
+    }
 
-    if (!hcursor) {
-        WIN_SetError("CopyImage()");
+    if (!hicon) {
+        WIN_SetError("CreateIconIndirect()");
         return NULL;
     }
 
     cursor = SDL_calloc(1, sizeof(*cursor));
     if (cursor) {
-        cursor->driverdata = hcursor;
+        cursor->driverdata = hicon;
     } else {
-        DestroyIcon(hcursor);
+        DestroyIcon(hicon);
         SDL_OutOfMemory();
     }
 

+ 1 - 1
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);