/** * FreeRDP: A Remote Desktop Protocol Implementation * GDI Bitmap Functions * * Copyright 2010-2011 Marc-Andre Moreau * Copyright 2016 Armin Novak * Copyright 2016 Thincast Technologies GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include "brush.h" #include "clipping.h" #define TAG FREERDP_TAG("gdi.bitmap") /** * Get pixel at the given coordinates.\n * @msdn{dd144909} * @param hdc device context * @param nXPos pixel x position * @param nYPos pixel y position * @return pixel color */ INLINE UINT32 gdi_GetPixel(HGDI_DC hdc, UINT32 nXPos, UINT32 nYPos) { HGDI_BITMAP hBmp = (HGDI_BITMAP) hdc->selectedObject; BYTE* data = &(hBmp->data[(nYPos * hBmp->scanline) + nXPos * GetBytesPerPixel( hBmp->format)]); return ReadColor(data, hBmp->format); } INLINE BYTE* gdi_GetPointer(HGDI_BITMAP hBmp, UINT32 X, UINT32 Y) { UINT32 bpp = GetBytesPerPixel(hBmp->format); return &hBmp->data[(Y * hBmp->width * bpp) + X * bpp]; } /** * Set pixel at the given coordinates.\n * @msdn{dd145078} * @param hdc device context * @param X pixel x position * @param Y pixel y position * @param crColor new pixel color * @return */ static INLINE UINT32 gdi_SetPixelBmp(HGDI_BITMAP hBmp, UINT32 X, UINT32 Y, UINT32 crColor) { BYTE* p = &hBmp->data[(Y * hBmp->scanline) + X * GetBytesPerPixel( hBmp->format)]; WriteColor(p, hBmp->format, crColor); return crColor; } INLINE UINT32 gdi_SetPixel(HGDI_DC hdc, UINT32 X, UINT32 Y, UINT32 crColor) { HGDI_BITMAP hBmp = (HGDI_BITMAP) hdc->selectedObject; return gdi_SetPixelBmp(hBmp, X, Y, crColor); } /** * Create a new bitmap with the given width, height, color format and pixel buffer.\n * @msdn{dd183485} * @param nWidth width * @param nHeight height * @param cBitsPerPixel bits per pixel * @param data pixel buffer * @param fkt_free The function used for deallocation of the buffer, NULL for none. * @return new bitmap */ HGDI_BITMAP gdi_CreateBitmap(UINT32 nWidth, UINT32 nHeight, UINT32 format, BYTE* data) { return gdi_CreateBitmapEx(nWidth, nHeight, format, 0, data, _aligned_free); } HGDI_BITMAP gdi_CreateBitmapEx(UINT32 nWidth, UINT32 nHeight, UINT32 format, UINT32 stride, BYTE* data, void (*fkt_free)(void*)) { HGDI_BITMAP hBitmap = (HGDI_BITMAP) calloc(1, sizeof(GDI_BITMAP)); if (!hBitmap) return NULL; hBitmap->objectType = GDIOBJECT_BITMAP; hBitmap->format = format; if (stride > 0) hBitmap->scanline = stride; else hBitmap->scanline = nWidth * GetBytesPerPixel(hBitmap->format); hBitmap->width = nWidth; hBitmap->height = nHeight; hBitmap->data = data; hBitmap->free = fkt_free; return hBitmap; } /** * Create a new bitmap of the given width and height compatible with the current device context.\n * @msdn{dd183488} * @param hdc device context * @param nWidth width * @param nHeight height * @return new bitmap */ HGDI_BITMAP gdi_CreateCompatibleBitmap(HGDI_DC hdc, UINT32 nWidth, UINT32 nHeight) { HGDI_BITMAP hBitmap = (HGDI_BITMAP) calloc(1, sizeof(GDI_BITMAP)); if (!hBitmap) return NULL; hBitmap->objectType = GDIOBJECT_BITMAP; hBitmap->format = hdc->format; hBitmap->width = nWidth; hBitmap->height = nHeight; hBitmap->data = _aligned_malloc(nWidth * nHeight * GetBytesPerPixel( hBitmap->format), 16); hBitmap->free = _aligned_free; if (!hBitmap->data) { free(hBitmap); return NULL; } hBitmap->scanline = nWidth * GetBytesPerPixel(hBitmap->format); return hBitmap; } static BOOL BitBlt_SRCCOPY(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { HGDI_BITMAP hSrcBmp; HGDI_BITMAP hDstBmp; if (!hdcDest || !hdcSrc) return FALSE; if ((nHeight == 0) || (nWidth == 0)) return TRUE; hSrcBmp = (HGDI_BITMAP) hdcSrc->selectedObject; hDstBmp = (HGDI_BITMAP) hdcDest->selectedObject; if (!freerdp_image_copy(hDstBmp->data, hDstBmp->format, hDstBmp->scanline, nXDest, nYDest, nWidth, nHeight, hSrcBmp->data, hSrcBmp->format, hSrcBmp->scanline, nXSrc, nYSrc, palette)) return FALSE; return TRUE; } static BOOL BitBlt_NOTSRCCOPY(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { UINT32 x, y; if (!hdcDest || !hdcSrc) return FALSE; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer( hdcSrc, nXSrc + x, nYSrc + y); BYTE* dstp = gdi_get_bitmap_pointer( hdcDest, nXDest + x, nYDest + y); if (srcp && dstp) { UINT32 color = ReadColor(srcp, hdcSrc->format); color = ConvertColor(color, hdcSrc->format, hdcDest->format, palette); color = ~color; WriteColor(dstp, hdcDest->format, color); } } } return TRUE; } static BOOL BitBlt_SRCERASE(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { UINT32 x, y; if (!hdcDest || !hdcSrc) return FALSE; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer( hdcSrc, nXSrc + x, nYSrc + y); BYTE* dstp = gdi_get_bitmap_pointer( hdcDest, nXDest + x, nYDest + y); if (srcp && dstp) { UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(dstp, hdcDest->format); UINT32 color; colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); color = colorA & ~colorB; WriteColor(dstp, hdcDest->format, color); } } } return TRUE; } static BOOL BitBlt_NOTSRCERASE(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { UINT32 x, y; if (!hdcDest || !hdcSrc) return FALSE; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer( hdcSrc, nXSrc + x, nYSrc + y); BYTE* dstp = gdi_get_bitmap_pointer( hdcDest, nXDest + x, nYDest + y); if (srcp && dstp) { UINT32 color; UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(dstp, hdcDest->format); colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); color = ~colorA & ~colorB; WriteColor(dstp, hdcDest->format, color); } } } return TRUE; } static BOOL BitBlt_SRCINVERT(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { UINT32 x, y; if (!hdcDest || !hdcSrc) return FALSE; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer( hdcSrc, nXSrc + x, nYSrc + y); BYTE* dstp = gdi_get_bitmap_pointer( hdcDest, nXDest + x, nYDest + y); if (srcp && dstp) { UINT32 color; UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(dstp, hdcDest->format); colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); color = colorA ^ colorB; WriteColor(dstp, hdcDest->format, color); } } } return TRUE; } static BOOL BitBlt_SRCAND(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { UINT32 x, y; if (!hdcDest || !hdcSrc) return FALSE; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer( hdcSrc, nXSrc + x, nYSrc + y); BYTE* dstp = gdi_get_bitmap_pointer( hdcDest, nXDest + x, nYDest + y); if (srcp && dstp) { UINT32 color; UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(dstp, hdcDest->format); colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); color = colorA & colorB; WriteColor(dstp, hdcDest->format, color); } } } return TRUE; } static BOOL BitBlt_SRCPAINT(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { UINT32 x, y; if (!hdcDest || !hdcSrc) return FALSE; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer( hdcSrc, nXSrc + x, nYSrc + y); BYTE* dstp = gdi_get_bitmap_pointer( hdcDest, nXDest + x, nYDest + y); if (srcp && dstp) { UINT32 color; UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(dstp, hdcDest->format); colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); color = colorA | colorB; WriteColor(dstp, hdcDest->format, color); } } } return TRUE; } static BOOL BitBlt_DSPDxax(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { UINT32 x, y; UINT32 color; if (!hdcDest || !hdcSrc) return FALSE; /* D = (S & P) | (~S & D) */ color = hdcDest->textColor; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer( hdcSrc, nXSrc + x, nYSrc + y); BYTE* dstp = gdi_get_bitmap_pointer( hdcDest, nXDest + x, nYDest + y); if (srcp && dstp) { UINT32 dstColor; UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(dstp, hdcDest->format); colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); dstColor = (colorA & color) | (~colorA & colorB); WriteColor(dstp, hdcDest->format, dstColor); } } } return TRUE; } static BOOL BitBlt_PSDPxax(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { UINT32 x, y; if (!hdcDest || !hdcSrc) return FALSE; /* D = (S & D) | (~S & P) */ if (hdcDest->brush->style == GDI_BS_SOLID) { UINT32 colorC = hdcDest->brush->color; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer( hdcSrc, nXSrc + x, nYSrc + y); BYTE* dstp = gdi_get_bitmap_pointer( hdcDest, nXDest + x, nYDest + y); if (srcp && dstp) { UINT32 color; UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(dstp, hdcDest->format); colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); color = (colorA & colorB) | (~colorA & colorC); WriteColor(dstp, hdcDest->format, color); } } } } else { for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer( hdcSrc, nXSrc + x, nYSrc + y); const BYTE* patp = gdi_get_brush_pointer( hdcDest, nXDest + x, nYDest + y); BYTE* dstp = gdi_get_bitmap_pointer( hdcDest, nXDest + x, nYDest + y); if (srcp && dstp) { UINT32 color; UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(dstp, hdcDest->format); UINT32 colorC = ReadColor(patp, hdcDest->format); colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); color = (colorA & colorB) | (~colorA & colorC); WriteColor(dstp, hdcDest->format, color); } } } } return TRUE; } static BOOL BitBlt_SPDSxax(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { UINT32 x, y; if (!hdcDest || !hdcSrc) return FALSE; /* D = S ^ (P & (D ^ S)) */ if (hdcDest->brush->style == GDI_BS_SOLID) { UINT32 color = hdcDest->brush->color; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer( hdcSrc, nXSrc + x, nYSrc + y); BYTE* dstp = gdi_get_bitmap_pointer( hdcDest, nXDest + x, nYDest + y); if (srcp && dstp) { UINT32 colorD; UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(dstp, hdcDest->format); colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); colorD = colorA ^ (color & (colorB ^ colorA)); WriteColor(dstp, hdcDest->format, color); } } } } else { for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer( hdcSrc, nXSrc + x, nYSrc + y); const BYTE* patp = gdi_get_brush_pointer( hdcDest, nXDest + x, nYDest + y); BYTE* dstp = gdi_get_bitmap_pointer( hdcDest, nXDest + x, nYDest + y); if (srcp && dstp) { UINT32 colorD; UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(dstp, hdcDest->format); UINT32 color = ReadColor(patp, hdcDest->format); colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); colorD = colorA ^ (color & (colorB ^ colorA)); WriteColor(dstp, hdcDest->format, color); } } } } return TRUE; } static BOOL BitBlt_SPna(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { UINT32 x, y; if (!hdcDest || !hdcSrc) return FALSE; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer(hdcSrc, nXSrc + x, nYSrc + y); const BYTE* patp = gdi_get_brush_pointer(hdcDest, nXDest + x, nYDest + y); BYTE* dstp = gdi_get_bitmap_pointer(hdcDest, nXDest + x, nYDest + y); if (srcp && patp && dstp) { UINT32 color; UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(patp, hdcDest->format); colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); color = colorA & ~colorB; WriteColor(dstp, hdcDest->format, color); } } } return TRUE; } static BOOL BitBlt_DSna(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { UINT32 x, y; if (!hdcDest || !hdcSrc) return FALSE; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer( hdcSrc, nXSrc + x, nYSrc + y); BYTE* dstp = gdi_get_bitmap_pointer( hdcDest, nXDest + x, nYDest + y); if (srcp && dstp) { UINT32 color; UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(dstp, hdcDest->format); colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); color = ~colorA & colorB; WriteColor(dstp, hdcDest->format, color); } } } return TRUE; } static BOOL BitBlt_MERGECOPY(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { UINT32 x, y; if (!hdcDest || !hdcSrc) return FALSE; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer( hdcSrc, nXSrc + x, nYSrc + y); const BYTE* patp = gdi_get_brush_pointer( hdcDest, nXDest + x, nYDest + y); BYTE* dstp = gdi_get_bitmap_pointer( hdcDest, nXDest + x, nYDest + y); if (srcp && patp && dstp) { UINT32 color; UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(patp, hdcDest->format); colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); color = colorA & colorB; WriteColor(dstp, hdcDest->format, color); } } } return TRUE; } static BOOL BitBlt_MERGEPAINT(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette) { UINT32 x, y; if (!hdcDest || !hdcSrc) return FALSE; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { const BYTE* srcp = gdi_get_bitmap_pointer(hdcSrc, nXSrc + x, nYSrc + y); BYTE* dstp = gdi_get_bitmap_pointer(hdcDest, nXDest + x, nYDest + y); if (srcp && dstp) { UINT32 colorA = ReadColor(srcp, hdcSrc->format); UINT32 colorB = ReadColor(dstp, hdcDest->format); UINT32 color; colorA = ConvertColor(colorA, hdcSrc->format, hdcDest->format, palette); color = ~colorA | colorB; WriteColor(dstp, hdcDest->format, color); } } } return TRUE; } /** * Perform a bit blit operation on the given pixel buffers.\n * @msdn{dd183370} * @param hdcDest destination device context * @param nXDest destination x1 * @param nYDest destination y1 * @param nWidth width * @param nHeight height * @param hdcSrc source device context * @param nXSrc source x1 * @param nYSrc source y1 * @param rop raster operation code * @return 0 on failure, non-zero otherwise */ BOOL gdi_BitBlt(HGDI_DC hdcDest, UINT32 nXDest, UINT32 nYDest, UINT32 nWidth, UINT32 nHeight, HGDI_DC hdcSrc, UINT32 nXSrc, UINT32 nYSrc, DWORD rop, const gdiPalette* palette) { if (!hdcDest) return FALSE; if (gdi_PatBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, rop, hdcSrc, nXSrc, nYSrc)) return TRUE; if (hdcSrc != NULL) { if (!gdi_ClipCoords(hdcDest, &nXDest, &nYDest, &nWidth, &nHeight, &nXSrc, &nYSrc)) return TRUE; } else { if (!gdi_ClipCoords(hdcDest, &nXDest, &nYDest, &nWidth, &nHeight, NULL, NULL)) return TRUE; } if (!gdi_InvalidateRegion(hdcDest, nXDest, nYDest, nWidth, nHeight)) return FALSE; switch (rop) { case GDI_SRCCOPY: return BitBlt_SRCCOPY(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); case GDI_SPna: return BitBlt_SPna(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); case GDI_DSna: return BitBlt_DSna(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); case GDI_DSPDxax: return BitBlt_DSPDxax(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); case GDI_PSDPxax: return BitBlt_PSDPxax(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); case GDI_SPDSxax: return BitBlt_SPDSxax(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); case GDI_NOTSRCCOPY: return BitBlt_NOTSRCCOPY(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); case GDI_SRCERASE: return BitBlt_SRCERASE(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); case GDI_NOTSRCERASE: return BitBlt_NOTSRCERASE(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); case GDI_SRCINVERT: return BitBlt_SRCINVERT(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); case GDI_SRCAND: return BitBlt_SRCAND(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); case GDI_SRCPAINT: return BitBlt_SRCPAINT(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); case GDI_MERGECOPY: return BitBlt_MERGECOPY(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); case GDI_MERGEPAINT: return BitBlt_MERGEPAINT(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, palette); default: WLog_ERR(TAG, "BitBlt: unknown rop: 0x%08X", rop); return FALSE; } }