Ken Thomases : winemac: Improve handling of "invert" pixels in monochrome cursors.

Alexandre Julliard julliard at winehq.org
Fri Mar 8 14:00:36 CST 2013


Module: wine
Branch: master
Commit: 37b33a9de83d0942616f08c9eb66203296ae6ff0
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=37b33a9de83d0942616f08c9eb66203296ae6ff0

Author: Ken Thomases <ken at codeweavers.com>
Date:   Thu Mar  7 20:37:02 2013 -0600

winemac: Improve handling of "invert" pixels in monochrome cursors.

---

 dlls/winemac.drv/mouse.c |  109 +++++++++++++++++++++++++++++++++-------------
 1 files changed, 79 insertions(+), 30 deletions(-)

diff --git a/dlls/winemac.drv/mouse.c b/dlls/winemac.drv/mouse.c
index cfbb274..66214fe 100644
--- a/dlls/winemac.drv/mouse.c
+++ b/dlls/winemac.drv/mouse.c
@@ -258,21 +258,6 @@ done:
 }
 
 /***********************************************************************
- *              release_provider_cfdata
- *
- * Helper for create_monochrome_cursor.  A CFData is used by two
- * different CGDataProviders, using different offsets.  One of them is
- * constructed with a pointer to the bytes, not a reference to the
- * CFData object (because of the offset).  So, the CFData is CFRetain'ed
- * on its behalf at creation and released here.
- */
-void release_provider_cfdata(void *info, const void *data, size_t size)
-{
-    CFRelease(info);
-}
-
-
-/***********************************************************************
  *              create_monochrome_cursor
  */
 CFArrayRef create_monochrome_cursor(HDC hdc, const ICONINFOEXW *icon, int width, int height)
@@ -280,6 +265,9 @@ CFArrayRef create_monochrome_cursor(HDC hdc, const ICONINFOEXW *icon, int width,
     char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
     BITMAPINFO *info = (BITMAPINFO *)buffer;
     unsigned int width_bytes = (width + 31) / 32 * 4;
+    unsigned long *and_bits = NULL, *xor_bits;
+    unsigned long *data_bits;
+    int count, i;
     CGColorSpaceRef colorspace;
     CFMutableDataRef data;
     CGDataProviderRef provider;
@@ -306,43 +294,86 @@ CFArrayRef create_monochrome_cursor(HDC hdc, const ICONINFOEXW *icon, int width,
     info->bmiHeader.biClrUsed = 0;
     info->bmiHeader.biClrImportant = 0;
 
-    /* This will be owned by the data provider for the mask image and released
-       when it is destroyed. */
-    data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage);
-    if (!data)
+    and_bits = HeapAlloc(GetProcessHeap(), 0, info->bmiHeader.biSizeImage);
+    if (!and_bits)
     {
-        WARN("failed to create data\n");
+        WARN("failed to allocate and_bits\n");
         return NULL;
     }
-    CFDataSetLength(data, info->bmiHeader.biSizeImage);
+    xor_bits = (unsigned long*)((char*)and_bits + info->bmiHeader.biSizeImage / 2);
 
-    if (!GetDIBits(hdc, icon->hbmMask, 0, height * 2, CFDataGetMutableBytePtr(data), info, DIB_RGB_COLORS))
+    if (!GetDIBits(hdc, icon->hbmMask, 0, height * 2, and_bits, info, DIB_RGB_COLORS))
     {
         WARN("GetDIBits failed\n");
-        CFRelease(data);
+        HeapFree(GetProcessHeap(), 0, and_bits);
         return NULL;
     }
 
+    /* On Windows, the pixels of a monochrome cursor can have four effects:
+       draw black, draw white, leave unchanged (transparent), or invert.  The Mac
+       only supports the first three.  It can't do pixels which invert the
+       background.  Since the background is usually white, I am arbitrarily
+       mapping "invert" to "draw black".  This entails bitwise math between the
+       cursor's AND mask and XOR mask:
+
+            AND | XOR | Windows cursor pixel
+            --------------------------------
+             0  |  0  | black
+             0  |  1  | white
+             1  |  0  | transparent
+             1  |  1  | invert
+
+            AND | XOR | Mac image
+            ---------------------
+             0  |  0  | black (0)
+             0  |  1  | white (1)
+             1  |  0  | don't care
+             1  |  1  | black (0)
+
+            AND | XOR | Mac mask
+            ---------------------------
+             0  |  0  | paint (0)
+             0  |  1  | paint (0)
+             1  |  0  | don't paint (1)
+             1  |  1  | paint (0)
+
+       So, Mac image = AND ^ XOR and Mac mask = AND & ~XOR.
+      */
+    /* Create data for Mac image. */
+    data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage / 2);
+    if (!data)
+    {
+        WARN("failed to create data\n");
+        HeapFree(GetProcessHeap(), 0, and_bits);
+        return NULL;
+    }
+
+    /* image data = AND mask */
+    CFDataAppendBytes(data, (UInt8*)and_bits, info->bmiHeader.biSizeImage / 2);
+    /* image data ^= XOR mask */
+    data_bits = (unsigned long*)CFDataGetMutableBytePtr(data);
+    count = (info->bmiHeader.biSizeImage / 2) / sizeof(*data_bits);
+    for (i = 0; i < count; i++)
+        data_bits[i] ^= xor_bits[i];
+
     colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
     if (!colorspace)
     {
         WARN("failed to create colorspace\n");
         CFRelease(data);
+        HeapFree(GetProcessHeap(), 0, and_bits);
         return NULL;
     }
 
-    /* The data object needs to live as long as this provider, so retain it an
-       extra time and have the provider's data-release callback release it. */
-    provider = CGDataProviderCreateWithData(data, CFDataGetBytePtr(data) + width_bytes * height,
-                                            width_bytes * height, release_provider_cfdata);
+    provider = CGDataProviderCreateWithCFData(data);
+    CFRelease(data);
     if (!provider)
     {
         WARN("failed to create data provider\n");
         CGColorSpaceRelease(colorspace);
-        CFRelease(data);
+        HeapFree(GetProcessHeap(), 0, and_bits);
         return NULL;
     }
-    CFRetain(data);
 
     cgimage = CGImageCreate(width, height, 1, 1, width_bytes, colorspace,
                             kCGImageAlphaNone | kCGBitmapByteOrderDefault,
@@ -352,10 +383,28 @@ CFArrayRef create_monochrome_cursor(HDC hdc, const ICONINFOEXW *icon, int width,
     if (!cgimage)
     {
         WARN("failed to create image\n");
-        CFRelease(data);
+        HeapFree(GetProcessHeap(), 0, and_bits);
+        return NULL;
+    }
+
+    /* Create data for mask. */
+    data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage / 2);
+    if (!data)
+    {
+        WARN("failed to create data\n");
+        CGImageRelease(cgimage);
+        HeapFree(GetProcessHeap(), 0, and_bits);
         return NULL;
     }
 
+    /* mask data = AND mask */
+    CFDataAppendBytes(data, (UInt8*)and_bits, info->bmiHeader.biSizeImage / 2);
+    /* mask data &= ~XOR mask */
+    data_bits = (unsigned long*)CFDataGetMutableBytePtr(data);
+    for (i = 0; i < count; i++)
+        data_bits[i] &= ~xor_bits[i];
+    HeapFree(GetProcessHeap(), 0, and_bits);
+
     provider = CGDataProviderCreateWithCFData(data);
     CFRelease(data);
     if (!provider)




More information about the wine-cvs mailing list