From: sonyps5201314 sonyps5201314@gmail.com
--- dlls/winemac.drv/cocoa_window.m | 217 ++++++++++++++++++++++++++++++++ dlls/winemac.drv/gdi.c | 163 ++++++++++++++++++++++++ dlls/winemac.drv/macdrv_cocoa.h | 8 ++ 3 files changed, 388 insertions(+)
diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 2525c894d09..e5e0bc57027 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -3962,3 +3962,220 @@ void macdrv_clear_ime_text(void) [[window contentView] clearMarkedText]; }); } + +#define wxOSX_USE_PREMULTIPLIED_ALPHA 1 +static const int kBestByteAlignement = 16; +static const int kMaskBytesPerPixel = 1; + +static size_t GetBestBytesPerRow( size_t rawBytes ) +{ + return (((rawBytes)+kBestByteAlignement-1) & ~(kBestByteAlignement-1) ); +} + +static CGColorSpaceRef genericRGBColorSpace; +CGColorSpaceRef wxMacGetGenericRGBColorSpace() +{ + if (genericRGBColorSpace == NULL) + { +#if wxOSX_USE_IPHONE + genericRGBColorSpace = CGColorSpaceCreateDeviceRGB(); +#else + genericRGBColorSpace = CGColorSpaceCreateWithName( kCGColorSpaceSRGB ); +#endif + } + + return genericRGBColorSpace; +} + +OSStatus wxMacDrawCGImage( + CGContextRef inContext, + const CGRect * inBounds, + CGImageRef inImage) +{ + CGContextSaveGState(inContext); + CGContextTranslateCTM(inContext, inBounds->origin.x, inBounds->origin.y + inBounds->size.height); + CGRect r = *inBounds; + r.origin.x = r.origin.y = 0; + CGContextScaleCTM(inContext, 1, -1); + CGContextDrawImage(inContext, r, inImage ); + CGContextRestoreGState(inContext); + return noErr; +} + +CGContextRef Bitmap_Create(int w, int h, double contentScaleFactor, size_t* bitmap_width, size_t* bitmap_height) +{ + *bitmap_width = MAX(1, w*contentScaleFactor); + *bitmap_height = MAX(1, h*contentScaleFactor); + + size_t bytesPerRow = GetBestBytesPerRow(*bitmap_width * 4); + CGContextRef hBitmap = CGBitmapContextCreate(NULL, *bitmap_width, *bitmap_height, 8, bytesPerRow, wxMacGetGenericRGBColorSpace(), kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little); + //wxCHECK_MSG(hBitmap, false, wxT("Unable to create CGBitmapContext context")); + if(hBitmap == NULL) + { + NSLog(@"Unable to create CGBitmapContext context"); + return NULL; + } + CGContextTranslateCTM(hBitmap, 0, *bitmap_height); + CGContextScaleCTM(hBitmap, 1 * contentScaleFactor, -1 * contentScaleFactor); + return hBitmap; +} + +void macdrv_get_image_from_screen(const struct wxRect *subrect, double contentScaleFactor, void* *pbits, int* pbytes_per_line) +{ + // Get the source rectangle + CGRect cgbounds; + cgbounds = CGDisplayBounds(CGMainDisplayID()); + int screen_width = cgbounds.size.width; + int screen_height = cgbounds.size.height; + struct wxRect fullRect = {0, 0, screen_width, screen_height}; + + struct wxRect rect; + BOOL needSubImage = FALSE; + if (subrect && memcmp(subrect, &fullRect, sizeof(struct wxRect)) != 0 ) + { + rect = *subrect; + needSubImage = TRUE; + } + else + { + rect = fullRect; + } + + // Create a bitmap in our format + //wxBitmap bmp(rect.GetSize(), 32); + size_t bitmap_width, bitmap_height; + CGContextRef hBitmap = Bitmap_Create(rect.width, rect.height, contentScaleFactor, &bitmap_width, &bitmap_height); + + // Capture full screen image + CGImageRef image = NULL; + + image = CGDisplayCreateImage(kCGDirectMainDisplay); + + if(image == NULL) + { + NSLog(@"wxScreenDC::GetAsBitmap - unable to get screenshot."); + return; + } + + if (needSubImage) + { + // Crop a sub image from a fullscreen image + CGImageRef fullImage = image; + image = CGImageCreateWithImageInRect(fullImage, CGRectMake(subrect->x, subrect->y, rect.width, rect.height)); + CGImageRelease(fullImage); + if(image == NULL) + { + NSLog(@"wxScreenDC::GetAsBitmap - unable to get screenshot."); + return; + } + } + + // Draw to a bitmap in our format + CGContextRef context = hBitmap; + + CGContextSaveGState(context); + + // Adjust the coordinate system of the bitmap in our format to be the same as that of Windows + CGContextTranslateCTM( context, 0, rect.height ); + CGContextScaleCTM( context, 1, -1 ); + + + // Set the quality level to use when rescaling +// CGContextSetAllowsAntialiasing(context, YES); +// CGContextSetShouldAntialias(context, YES); +// CGContextSetInterpolationQuality(context, kCGInterpolationHigh); + CGContextDrawImage(context, CGRectMake(0, 0, rect.width, rect.height), image); + + CGImageRelease(image); + + CGContextRestoreGState(context); + + // Export image for debugging + //CGImageRef ref = CGBitmapContextCreateImage(context); + + const unsigned char* sourcedata = (const unsigned char*)(CGBitmapContextGetData(hBitmap)); + int sourcelinesize = (int) CGBitmapContextGetBytesPerRow(hBitmap); + *pbytes_per_line = sourcelinesize; + void* pbuf = malloc(sourcelinesize*bitmap_height); + memcpy(pbuf, sourcedata, sourcelinesize*bitmap_height); + *pbits = pbuf; + + CGContextRelease(hBitmap); + hBitmap = NULL; +} + +void macdrv_get_image(macdrv_view v, const struct wxRect *subrect, double contentScaleFactor, void* *pbits, int* pbytes_per_line) +{ + WineContentView* view = (WineContentView*)v; + + //const wxSize bitmapSize(subrect ? subrect->GetSize() : m_window->GetSize()); + struct wxSize bitmapSize; + if (subrect) { + struct wxSize subSize = {subrect->width, subrect->height}; + bitmapSize = subSize; + } + else + { + struct wxSize fullSize = {view.bounds.size.width, view.bounds.size.height}; + bitmapSize = fullSize; + } + + // create bitmap + //wxBitmap bitmap; + //bitmap.CreateWithDIPSize(bitmapSize, contentScaleFactor); + size_t bitmap_width, bitmap_height; + CGContextRef hBitmap = Bitmap_Create(bitmapSize.x, bitmapSize.y, contentScaleFactor, &bitmap_width, &bitmap_height); + + // drawing + if ( [view isHiddenOrHasHiddenAncestor] == NO ) + { + // the old implementaiton is not working under 10.15, the new one should work for older systems as well + // however the new implementation does not take into account the backgroundViews, and I'm not sure about + // until we're + // sure the replacement is always better + + bool useOldImplementation = false; + NSBitmapImageRep *rep = nil; + + if ( useOldImplementation ) + { + [view lockFocus]; + // we use this method as other methods force a repaint, and this method can be + // called from OnPaint, even with the window's paint dc as source (see wxHTMLWindow) + rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: [view bounds]]; + [view unlockFocus]; + + } + else + { + rep = [view bitmapImageRepForCachingDisplayInRect:[view bounds]]; + [view cacheDisplayInRect:[view bounds] toBitmapImageRep:rep]; + } + + CGImageRef cgImageRef = (CGImageRef)[rep CGImage]; + + CGRect r = CGRectMake( 0 , 0 , CGImageGetWidth(cgImageRef) , CGImageGetHeight(cgImageRef) ); + + // The bitmap created by wxBitmap::CreateWithDIPSize() above is scaled, + // so we need to adjust the coordinates for it. + r.size.width /= contentScaleFactor; + r.size.height /= contentScaleFactor; + + // since our context is upside down we dont use CGContextDrawImage + wxMacDrawCGImage( hBitmap , &r, cgImageRef ) ; + + if ( useOldImplementation ) + [rep release]; + } + + const unsigned char* sourcedata = (const unsigned char*)(CGBitmapContextGetData(hBitmap)); + int sourcelinesize = (int) CGBitmapContextGetBytesPerRow(hBitmap); + *pbytes_per_line = sourcelinesize; + void* pbuf = malloc(sourcelinesize*bitmap_height); + memcpy(pbuf, sourcedata, sourcelinesize*bitmap_height); + *pbits = pbuf; + + CGContextRelease(hBitmap); + hBitmap = NULL; +} + diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c index fd1da722061..5b7a6d32452 100644 --- a/dlls/winemac.drv/gdi.c +++ b/dlls/winemac.drv/gdi.c @@ -215,6 +215,168 @@ static BOOL CDECL macdrv_DeleteDC(PHYSDEV dev) return TRUE; }
+static void CDECL free_heap_bits( struct gdi_image_bits *bits ) +{ + free( bits->ptr ); +} + +typedef unsigned long VisualID; +typedef struct { + void *visual; + VisualID visualid; + int screen; + int depth; +#if defined(__cplusplus) || defined(c_plusplus) + int c_class; /* C++ */ +#else + int class; +#endif + unsigned long red_mask; + unsigned long green_mask; + unsigned long blue_mask; + int colormap_size; + int bits_per_rgb; +} XVisualInfo; + +/* Maps pixel to the entry in the system palette */ +int *X11DRV_PALETTE_XPixelToPalette = NULL; + +/* store the palette or color mask data in the bitmap info structure */ +static void set_color_info( const XVisualInfo *vis, BITMAPINFO *info, BOOL has_alpha ) +{ + DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize); + + info->bmiHeader.biCompression = BI_RGB; + info->bmiHeader.biClrUsed = 0; + + switch (info->bmiHeader.biBitCount) + { + case 4: + case 8: + { + RGBQUAD *rgb = (RGBQUAD *)colors; + PALETTEENTRY palette[256]; + UINT i, count; + + info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount; + //count = X11DRV_GetSystemPaletteEntries( NULL, 0, info->bmiHeader.biClrUsed, palette ); + count = 0; + for (i = 0; i < count; i++) + { + rgb[i].rgbRed = palette[i].peRed; + rgb[i].rgbGreen = palette[i].peGreen; + rgb[i].rgbBlue = palette[i].peBlue; + rgb[i].rgbReserved = 0; + } + memset( &rgb[count], 0, (info->bmiHeader.biClrUsed - count) * sizeof(*rgb) ); + break; + } + case 16: + colors[0] = vis->red_mask; + colors[1] = vis->green_mask; + colors[2] = vis->blue_mask; + info->bmiHeader.biCompression = BI_BITFIELDS; + break; + case 32: + colors[0] = vis->red_mask; + colors[1] = vis->green_mask; + colors[2] = vis->blue_mask; + if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff || !has_alpha) + info->bmiHeader.biCompression = BI_BITFIELDS; + break; + } +} + +extern macdrv_view macdrv_get_cocoa_view(HWND hwnd); + +void macdrv_get_image_from_screen(const struct wxRect *subrect, double contentScaleFactor, void* *pbits, int* pbytes_per_line); +void macdrv_get_image(macdrv_view v, const struct wxRect *subrect, double contentScaleFactor, void* *pbits, int* pbytes_per_line); + +/*********************************************************************** + * macdrv_GetImage + */ +DWORD CDECL macdrv_GetImage( PHYSDEV dev, BITMAPINFO *info, + struct gdi_image_bits *bits, struct bitblt_coords *src ) +{ + MACDRV_PDEVICE *physdev = get_macdrv_dev(dev); + DWORD ret = ERROR_SUCCESS; + XVisualInfo vis = {0}; + UINT align, x, y, width, height; + const int *mapping = NULL; + + vis.depth = bits_per_pixel; + + vis.red_mask = 0xff0000; + vis.green_mask = 0x00ff00; + vis.blue_mask = 0x0000ff; + + /* align start and width to 32-bit boundary */ + switch (bits_per_pixel) + { + case 1: align = 32; break; + case 4: align = 8; mapping = X11DRV_PALETTE_XPixelToPalette; break; + case 8: align = 4; mapping = X11DRV_PALETTE_XPixelToPalette; break; + case 16: align = 2; break; + case 24: align = 4; break; + case 32: align = 1; break; + default: + FIXME( "depth %u bpp %u not supported yet\n", vis.depth, bits_per_pixel ); + return ERROR_BAD_FORMAT; + } + + info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = bits_per_pixel; + info->bmiHeader.biXPelsPerMeter = 0; + info->bmiHeader.biYPelsPerMeter = 0; + info->bmiHeader.biClrImportant = 0; + set_color_info( &vis, info, FALSE ); + + if (!bits) return ERROR_SUCCESS; /* just querying the color information */ + + x = src->visrect.left & ~(align - 1); + y = src->visrect.top; + width = src->visrect.right - x; + height = src->visrect.bottom - src->visrect.top; + //if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1); + /* make the source rectangle relative to the returned bits */ + src->x -= x; + src->y -= y; + OffsetRect( &src->visrect, -x, -y ); + + //Get image from the platform device + int bytes_per_line = 0; + HWND hwnd = NtUserWindowFromDC(dev->hdc); + // We will only create 32 bit bitmaps + if (hwnd == NULL || hwnd == NtUserGetDesktopWindow()) + { + struct wxRect subrect = {src->log_x, src->log_y, src->log_width, src->log_height}; + macdrv_get_image_from_screen(&subrect, 1.0, &bits->ptr, &bytes_per_line); + } + else + { + macdrv_view view = macdrv_get_cocoa_view(hwnd); + if (view != NULL) + { + struct wxRect subrect = {src->log_x, src->log_y, src->log_width, src->log_height}; + macdrv_get_image(view, &subrect, 1.0, &bits->ptr, &bytes_per_line); + } + else + { + // Window in other process are not currently supported + FIXME( "Window in other process is not supported yet\n"); + } + } + if (bits->ptr) { + bits->is_copy = TRUE; + bits->free = free_heap_bits; + } + + info->bmiHeader.biWidth = width; + info->bmiHeader.biHeight = -height; + info->bmiHeader.biSizeImage = height * bytes_per_line; + return ret; +}
/*********************************************************************** * GetDeviceCaps (MACDRV.@) @@ -263,6 +425,7 @@ static const struct user_driver_funcs macdrv_funcs = .dc_funcs.pDeleteDC = macdrv_DeleteDC, .dc_funcs.pGetDeviceCaps = macdrv_GetDeviceCaps, .dc_funcs.pGetDeviceGammaRamp = macdrv_GetDeviceGammaRamp, + .dc_funcs.pGetImage = macdrv_GetImage, .dc_funcs.pSetDeviceGammaRamp = macdrv_SetDeviceGammaRamp, .dc_funcs.priority = GDI_PRIORITY_GRAPHICS_DRV,
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 6196032c08d..618ebcdda0c 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -150,6 +150,14 @@ struct macdrv_display { CGRect work_frame; };
+//wxWidgets +struct wxSize { + int x, y; +}; +struct wxRect { + int x, y, width, height; +}; +
/* main */ extern int macdrv_err_on;