ChangeLog: Implementation of TransparentBlt. Description: It performs a bit-block transfer of the color data corresponding to a rectangle of pixels from the specified source device context into a destination device context. Warren Baird : Warren_Baird@cimmetry.com Xavier Servettaz diff -ur clean/wine/dlls/msimg32/msimg32_main.c wine/dlls/msimg32/msimg32_main.c --- clean/wine/dlls/msimg32/msimg32_main.c 16 Dec 2002 19:39:01 -0000 1.1.1.2 +++ wine/dlls/msimg32/msimg32_main.c 29 Jan 2003 16:41:58 -0000 @@ -20,6 +20,9 @@ #include "wingdi.h" #include "winerror.h" #include "wine/debug.h" +#include "winuser.h" +#include <stdlib.h> + WINE_DEFAULT_DEBUG_CHANNEL(msimg32); @@ -56,9 +59,191 @@ HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc, UINT crTransparent ) { - FIXME("stub: TransparentBlt from %p to %p\n", hdcSrc, hdcDest ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + BOOL result = FALSE; + RECT dstDevRect, srcDevRect; + int dstDCID = 0, srcDCID = 0; + HDC hdcBack = 0, hdcObject = 0, hdcMem = 0, hdcSave = 0; + HBITMAP bmAndBack = 0, bmAndObject = 0, bmAndMem = 0, bmSave = 0; + HBITMAP bmBackOld = 0, bmObjectOld = 0, bmMemOld = 0, bmSaveOld = 0; + COLORREF color; + LONG dstWidth = 0; + LONG dstHeight = 0; + LONG srcWidth = 0; + LONG srcHeight = 0; + LONG maxWidth = 0; + LONG maxHeight = 0; + /* Create some DCs to hold temporary data. */ + hdcBack = CreateCompatibleDC(hdcDest); + hdcObject = CreateCompatibleDC(hdcDest); + hdcMem = CreateCompatibleDC(hdcDest); + hdcSave = CreateCompatibleDC(hdcDest); + + if (hdcBack == 0 || hdcObject == 0 || hdcMem == 0 || hdcSave == 0) { + goto exit; + } + + /* Convert destination logical coordinates to device coordinates. */ + SetRect(&dstDevRect, xDest, yDest, xDest + widthDest, yDest + heightDst); + LPtoDP(hdcDest, (LPPOINT) &dstDevRect, 2); + dstWidth = dstDevRect.right - dstDevRect.left; + dstHeight = dstDevRect.bottom - dstDevRect.top; + + /* Convert source logical coordinates to device coordinates. */ + SetRect(&srcDevRect, xSrc, ySrc, xSrc + widthSrc, ySrc + heightSrc); + LPtoDP(hdcSrc, (LPPOINT) &srcDevRect, 2); + srcWidth = srcDevRect.right - srcDevRect.left; + srcHeight = srcDevRect.bottom - srcDevRect.top; + + /********************************************* + * Perform transparency operation on the + * largest DC to avoid rouding issues resulting + * in images too dark + ********************************************/ + + /* calculate max extends */ + maxWidth = max(abs(srcWidth), abs(dstWidth)); + maxHeight = max(abs(srcHeight), abs(dstHeight)); + + /* Save and reset destination and source DC settings. */ + dstDCID = SaveDC(hdcDest); + SetBkMode(hdcDest, OPAQUE); + SetBkColor(hdcDest, RGB(255, 255, 255)); + SetMapMode(hdcDest, MM_TEXT); + SetViewportOrgEx(hdcDest, 0, 0, NULL); + SetWindowOrgEx(hdcDest, 0, 0, NULL); + + srcDCID = SaveDC(hdcSrc); + SetBkMode(hdcSrc, OPAQUE); + SetBkColor(hdcSrc, RGB(255, 255, 255)); + SetMapMode(hdcSrc, MM_TEXT); + SetViewportOrgEx(hdcSrc, 0, 0, NULL); + SetWindowOrgEx(hdcSrc, 0, 0, NULL); + + /* Create a bitmap for each DC. */ + bmAndBack = CreateBitmap(maxWidth , maxHeight, 1, 1, 0); + bmAndObject = CreateBitmap(maxWidth , maxHeight, 1, 1, 0); + bmAndMem = CreateCompatibleBitmap(hdcDest, maxWidth, maxHeight); + bmSave = CreateCompatibleBitmap(hdcDest, srcWidth, srcHeight); + + if (bmAndBack == 0 || bmAndObject == 0 || bmAndMem == 0 || bmSave == 0) { + goto exit; + } + + /* Each DC must select a bitmap object to store pixel data. */ + bmBackOld = (HBITMAP)SelectObject(hdcBack, bmAndBack); + bmObjectOld = (HBITMAP)SelectObject(hdcObject, bmAndObject); + bmMemOld = (HBITMAP)SelectObject(hdcMem, bmAndMem); + bmSaveOld = (HBITMAP)SelectObject(hdcSave, bmSave); + + if (bmBackOld == 0 || bmObjectOld == 0 || bmMemOld == 0 || bmSaveOld == 0) { + goto exit; + } + + /* Save the given bitmap because it will be overwritten. */ + if (!BitBlt(hdcSave, 0, 0, srcWidth, srcHeight, hdcSrc, srcDevRect.left, srcDevRect.top, SRCCOPY)) { + goto exit; + } + + /* Set the background color of the source DC + to the color contained in the parts of the bitmap that should be transparent. */ + color = SetBkColor(hdcSrc, crTransparent); + + /* Create the object mask for the bitmap + by performing a BitBlt() from the source bitmap to a monochrome bitmap. */ + if (!StretchBlt(hdcObject, 0, 0, maxWidth, maxHeight, hdcSrc, srcDevRect.left, srcDevRect.top, srcWidth , srcHeight , SRCCOPY)) { + goto exit; + } + + /* Set the background color of the source DC back to the original color. */ + SetBkColor(hdcSrc, color); + + /* Create the inverse of the object mask. */ + if (!BitBlt(hdcBack, 0, 0, maxWidth, maxHeight, hdcObject, 0, 0, NOTSRCCOPY)) { + goto exit; + } + + /* Copy the background of the main DC to the destination. */ + if (!StretchBlt(hdcMem, 0, 0, maxWidth , maxHeight, hdcDest, dstDevRect.left, dstDevRect.top, dstWidth , dstHeight , SRCCOPY)) {{ + goto exit; + } + + /* Mask out the places where the bitmap will be placed. */ + if (!BitBlt(hdcMem, 0, 0, maxWidth, maxHeight, hdcObject, 0, 0, SRCAND)) { + goto exit; + } + + /* Mask out the transparent colored pixels on the bitmap. */ + if (!StretchBlt(hdcSrc, srcDevRect.left, srcDevRect.top, srcWidth, srcHeight , hdcBack, 0, 0, maxWidth, maxHeight, SRCAND)) { + goto exit; + } + + /* XOR the bitmap with the background on the destination DC. */ + if (!StretchBlt(hdcMem, 0, 0, maxWidth , maxHeight, hdcSrc, srcDevRect.left, srcDevRect.top, srcWidth , srcHeight , SRCPAINT)) {{ + goto exit; + } + + /* Copy the destination to the screen. */ + if (!StretchBlt(hdcDest, dstDevRect.left, dstDevRect.top, dstWidth, dstHeight , hdcMem, 0, 0, maxWidth , maxHeight, SRCCOPY)) {{{ + goto exit; + } + + /* Place the original bitmap back into the given bitmap. */ + if (!BitBlt(hdcSrc, srcDevRect.left, srcDevRect.top, srcWidth, srcHeight, hdcSave, 0, 0, SRCCOPY)) { + goto exit; + } + + result = TRUE; + + exit: + /* Restore destination and source DC settings. */ + if (dstDCID) + RestoreDC(hdcDest, dstDCID); + if (srcDCID) + RestoreDC(hdcSrc, srcDCID); + + /* Select old bitmaps. */ + if (bmSaveOld != 0) { + SelectObject(hdcSave, bmSaveOld); + } + if (bmMemOld != 0) { + SelectObject(hdcMem, bmMemOld); + } + if (bmObjectOld != 0) { + SelectObject(hdcObject, bmObjectOld); + } + if (bmBackOld != 0) { + SelectObject(hdcBack, bmBackOld); + } + + /* Delete bitmaps. */ + if (bmSave != 0) { + DeleteObject(bmSave); + } + if (bmAndMem != 0) { + DeleteObject(bmAndMem); + } + if (bmAndObject != 0) { + DeleteObject(bmAndObject); + } + if (bmAndBack != 0) { + DeleteObject(bmAndBack); + } + + /* Delete DCs. */ + if (hdcSave != 0) { + DeleteDC(hdcSave); + } + if (hdcMem != 0) { + DeleteDC(hdcMem); + } + if (hdcObject != 0) { + DeleteDC(hdcObject); + } + if (hdcBack != 0) { + DeleteDC(hdcBack); + } + + return result; }