Blame libfreerdp/gdi/bitmap.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * GDI Bitmap Functions
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2016 Armin Novak <armin.novak@thincast.com>
Packit 1fb8d4
 * Copyright 2016 Thincast Technologies GmbH
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/api.h>
Packit 1fb8d4
#include <freerdp/freerdp.h>
Packit 1fb8d4
#include <freerdp/gdi/gdi.h>
Packit 1fb8d4
#include <freerdp/codec/color.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/gdi/region.h>
Packit 1fb8d4
#include <freerdp/gdi/bitmap.h>
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
#include <freerdp/gdi/shape.h>
Packit 1fb8d4
Packit 1fb8d4
#include "brush.h"
Packit 1fb8d4
#include "clipping.h"
Packit 1fb8d4
#include "../gdi/gdi.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG FREERDP_TAG("gdi.bitmap")
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Get pixel at the given coordinates.\n
Packit 1fb8d4
 * @msdn{dd144909}
Packit 1fb8d4
 * @param hdc device context
Packit 1fb8d4
 * @param nXPos pixel x position
Packit 1fb8d4
 * @param nYPos pixel y position
Packit 1fb8d4
 * @return pixel color
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
INLINE UINT32 gdi_GetPixel(HGDI_DC hdc, UINT32 nXPos, UINT32 nYPos)
Packit 1fb8d4
{
Packit 1fb8d4
	HGDI_BITMAP hBmp = (HGDI_BITMAP) hdc->selectedObject;
Packit 1fb8d4
	BYTE* data = &(hBmp->data[(nYPos * hBmp->scanline) + nXPos * GetBytesPerPixel(
Packit 1fb8d4
	                                                       hBmp->format)]);
Packit 1fb8d4
	return ReadColor(data, hBmp->format);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
INLINE BYTE* gdi_GetPointer(HGDI_BITMAP hBmp, UINT32 X, UINT32 Y)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 bpp = GetBytesPerPixel(hBmp->format);
Packit 1fb8d4
	return &hBmp->data[(Y * hBmp->width * bpp) + X * bpp];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Set pixel at the given coordinates.\n
Packit 1fb8d4
 * @msdn{dd145078}
Packit 1fb8d4
 * @param hdc device context
Packit 1fb8d4
 * @param X pixel x position
Packit 1fb8d4
 * @param Y pixel y position
Packit 1fb8d4
 * @param crColor new pixel color
Packit 1fb8d4
 * @return
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static INLINE UINT32 gdi_SetPixelBmp(HGDI_BITMAP hBmp, UINT32 X, UINT32 Y,
Packit 1fb8d4
                                     UINT32 crColor)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE* p = &hBmp->data[(Y * hBmp->scanline) + X * GetBytesPerPixel(
Packit 1fb8d4
	                                               hBmp->format)];
Packit 1fb8d4
	WriteColor(p, hBmp->format, crColor);
Packit 1fb8d4
	return crColor;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
INLINE UINT32 gdi_SetPixel(HGDI_DC hdc, UINT32 X, UINT32 Y, UINT32 crColor)
Packit 1fb8d4
{
Packit 1fb8d4
	HGDI_BITMAP hBmp = (HGDI_BITMAP) hdc->selectedObject;
Packit 1fb8d4
	return gdi_SetPixelBmp(hBmp, X, Y, crColor);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Create a new bitmap with the given width, height, color format and pixel buffer.\n
Packit 1fb8d4
 * @msdn{dd183485}
Packit 1fb8d4
 * @param nWidth width
Packit 1fb8d4
 * @param nHeight height
Packit 1fb8d4
 * @param cBitsPerPixel bits per pixel
Packit 1fb8d4
 * @param data pixel buffer
Packit 1fb8d4
 * @param fkt_free The function used for deallocation of the buffer, NULL for none.
Packit 1fb8d4
 * @return new bitmap
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
HGDI_BITMAP gdi_CreateBitmap(UINT32 nWidth, UINT32 nHeight, UINT32 format,
Packit 1fb8d4
                             BYTE* data)
Packit 1fb8d4
{
Packit 1fb8d4
	return gdi_CreateBitmapEx(nWidth, nHeight, format, 0, data, _aligned_free);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
HGDI_BITMAP gdi_CreateBitmapEx(UINT32 nWidth, UINT32 nHeight, UINT32 format,
Packit 1fb8d4
                               UINT32 stride, BYTE* data, void (*fkt_free)(void*))
Packit 1fb8d4
{
Packit 1fb8d4
	HGDI_BITMAP hBitmap = (HGDI_BITMAP) calloc(1, sizeof(GDI_BITMAP));
Packit 1fb8d4
Packit 1fb8d4
	if (!hBitmap)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	hBitmap->objectType = GDIOBJECT_BITMAP;
Packit 1fb8d4
	hBitmap->format = format;
Packit 1fb8d4
Packit 1fb8d4
	if (stride > 0)
Packit 1fb8d4
		hBitmap->scanline = stride;
Packit 1fb8d4
	else
Packit 1fb8d4
		hBitmap->scanline = nWidth * GetBytesPerPixel(hBitmap->format);
Packit 1fb8d4
Packit 1fb8d4
	hBitmap->width = nWidth;
Packit 1fb8d4
	hBitmap->height = nHeight;
Packit 1fb8d4
	hBitmap->data = data;
Packit 1fb8d4
	hBitmap->free = fkt_free;
Packit 1fb8d4
	return hBitmap;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Create a new bitmap of the given width and height compatible with the current device context.\n
Packit 1fb8d4
 * @msdn{dd183488}
Packit 1fb8d4
 * @param hdc device context
Packit 1fb8d4
 * @param nWidth width
Packit 1fb8d4
 * @param nHeight height
Packit 1fb8d4
 * @return new bitmap
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
HGDI_BITMAP gdi_CreateCompatibleBitmap(HGDI_DC hdc, UINT32 nWidth,
Packit 1fb8d4
                                       UINT32 nHeight)
Packit 1fb8d4
{
Packit 1fb8d4
	HGDI_BITMAP hBitmap = (HGDI_BITMAP) calloc(1, sizeof(GDI_BITMAP));
Packit 1fb8d4
Packit 1fb8d4
	if (!hBitmap)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	hBitmap->objectType = GDIOBJECT_BITMAP;
Packit 1fb8d4
	hBitmap->format = hdc->format;
Packit 1fb8d4
	hBitmap->width = nWidth;
Packit 1fb8d4
	hBitmap->height = nHeight;
Packit 1fb8d4
	hBitmap->data = _aligned_malloc(nWidth * nHeight * GetBytesPerPixel(
Packit 1fb8d4
	                                    hBitmap->format), 16);
Packit 1fb8d4
	hBitmap->free = _aligned_free;
Packit 1fb8d4
Packit 1fb8d4
	if (!hBitmap->data)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(hBitmap);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	hBitmap->scanline = nWidth * GetBytesPerPixel(hBitmap->format);
Packit 1fb8d4
	return hBitmap;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL op_not(UINT32* stack, UINT32* stackp)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!stack || !stackp)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (*stackp < 1)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	stack[(*stackp) - 1] = ~stack[(*stackp) - 1];
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL op_and(UINT32* stack, UINT32* stackp)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!stack || !stackp)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (*stackp < 2)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	(*stackp)--;
Packit 1fb8d4
	stack[(*stackp) - 1] &= stack[(*stackp)];
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL op_or(UINT32* stack, UINT32* stackp)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!stack || !stackp)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (*stackp < 2)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	(*stackp)--;
Packit 1fb8d4
	stack[(*stackp) - 1] |= stack[(*stackp)];
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL op_xor(UINT32* stack, UINT32* stackp)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!stack || !stackp)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (*stackp < 2)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	(*stackp)--;
Packit 1fb8d4
	stack[(*stackp) - 1] ^= stack[(*stackp)];
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static UINT32 process_rop(UINT32 src, UINT32 dst, UINT32 pat, const char* rop,
Packit 1fb8d4
                          UINT32 format)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD stack[10] = { 0 };
Packit 1fb8d4
	DWORD stackp = 0;
Packit 1fb8d4
Packit 1fb8d4
	while (*rop != '\0')
Packit 1fb8d4
	{
Packit 1fb8d4
		char op = *rop++;
Packit 1fb8d4
Packit 1fb8d4
		switch (op)
Packit 1fb8d4
		{
Packit 1fb8d4
			case '0':
Packit 1fb8d4
				stack[stackp++] = FreeRDPGetColor(format, 0, 0, 0, 0xFF);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case '1':
Packit 1fb8d4
				stack[stackp++] = FreeRDPGetColor(format, 0xFF, 0xFF, 0xFF, 0xFF);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case 'D':
Packit 1fb8d4
				stack[stackp++] = dst;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case 'S':
Packit 1fb8d4
				stack[stackp++] = src;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case 'P':
Packit 1fb8d4
				stack[stackp++] = pat;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case 'x':
Packit 1fb8d4
				op_xor(stack, &stackp);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case 'a':
Packit 1fb8d4
				op_and(stack, &stackp);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case 'o':
Packit 1fb8d4
				op_or(stack, &stackp);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case 'n':
Packit 1fb8d4
				op_not(stack, &stackp);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return stack[0];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE BOOL BitBlt_write(HGDI_DC hdcDest, HGDI_DC hdcSrc, INT32 nXDest,
Packit 1fb8d4
                                INT32 nYDest, INT32 nXSrc, INT32 nYSrc, INT32 x, INT32 y,
Packit 1fb8d4
                                BOOL useSrc, BOOL usePat, UINT32 style,
Packit 1fb8d4
                                const char* rop, const gdiPalette* palette)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 dstColor;
Packit 1fb8d4
	UINT32 colorA;
Packit 1fb8d4
	UINT32 colorB = 0;
Packit 1fb8d4
	UINT32 colorC = 0;
Packit 1fb8d4
	const INT32 dstX = nXDest + x;
Packit 1fb8d4
	const INT32 dstY = nYDest + y;
Packit 1fb8d4
	BYTE* dstp = gdi_get_bitmap_pointer(hdcDest, dstX, dstY);
Packit 1fb8d4
Packit 1fb8d4
	if (!dstp)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "dstp=%p", (void*) dstp);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	colorA = ReadColor(dstp, hdcDest->format);
Packit 1fb8d4
Packit 1fb8d4
	if (useSrc)
Packit 1fb8d4
	{
Packit 1fb8d4
		const BYTE* srcp = gdi_get_bitmap_pointer(hdcSrc, nXSrc + x, nYSrc + y);
Packit 1fb8d4
Packit 1fb8d4
		if (!srcp)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "srcp=%p", (void*) srcp);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		colorC = ReadColor(srcp, hdcSrc->format);
Packit 1fb8d4
		colorC = FreeRDPConvertColor(colorC, hdcSrc->format, hdcDest->format, palette);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (usePat)
Packit 1fb8d4
	{
Packit 1fb8d4
		switch (style)
Packit 1fb8d4
		{
Packit 1fb8d4
			case GDI_BS_SOLID:
Packit 1fb8d4
				colorB = hdcDest->brush->color;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case GDI_BS_HATCHED:
Packit 1fb8d4
			case GDI_BS_PATTERN:
Packit 1fb8d4
				{
Packit 1fb8d4
					const BYTE* patp = gdi_get_brush_pointer(hdcDest, nXDest + x, nYDest + y);
Packit 1fb8d4
Packit 1fb8d4
					if (!patp)
Packit 1fb8d4
					{
Packit 1fb8d4
						WLog_ERR(TAG, "patp=%p", (void*) patp);
Packit 1fb8d4
						return FALSE;
Packit 1fb8d4
					}
Packit 1fb8d4
Packit 1fb8d4
					colorB = ReadColor(patp, hdcDest->format);
Packit 1fb8d4
				}
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	dstColor = process_rop(colorC, colorA, colorB, rop, hdcDest->format);
Packit 1fb8d4
	return WriteColor(dstp, hdcDest->format, dstColor);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL adjust_src_coordinates(HGDI_DC hdcSrc, INT32 nWidth, INT32 nHeight,
Packit 1fb8d4
                                   INT32* px, INT32* py)
Packit 1fb8d4
{
Packit 1fb8d4
	HGDI_BITMAP hSrcBmp;
Packit 1fb8d4
	INT32 nXSrc, nYSrc;
Packit 1fb8d4
Packit 1fb8d4
	if (!hdcSrc || (nWidth < 0) || (nHeight < 0) || !px || !py)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	hSrcBmp = (HGDI_BITMAP) hdcSrc->selectedObject;
Packit 1fb8d4
	nXSrc = *px;
Packit 1fb8d4
	nYSrc = *py;
Packit 1fb8d4
Packit 1fb8d4
	if (!hSrcBmp)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (nYSrc < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		nYSrc = 0;
Packit 1fb8d4
		nHeight = nHeight + nYSrc;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((nXSrc) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		nXSrc = 0;
Packit 1fb8d4
		nWidth = nWidth + nXSrc;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (hSrcBmp->width < (nXSrc + nWidth))
Packit 1fb8d4
		nXSrc = hSrcBmp->width - nWidth;
Packit 1fb8d4
Packit 1fb8d4
	if (hSrcBmp->height < (nYSrc + nHeight))
Packit 1fb8d4
		nYSrc = hSrcBmp->height - nHeight;
Packit 1fb8d4
Packit 1fb8d4
	if ((nXSrc < 0) || (nYSrc < 0))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	*px = nXSrc;
Packit 1fb8d4
	*py = nYSrc;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL adjust_src_dst_coordinates(HGDI_DC hdcDest, INT32* pnXSrc, INT32* pnYSrc,
Packit 1fb8d4
                                       INT32* pnXDst, INT32* pnYDst, INT32* pnWidth, INT32* pnHeight)
Packit 1fb8d4
{
Packit 1fb8d4
	HGDI_BITMAP hDstBmp;
Packit 1fb8d4
	volatile INT32 diffX, diffY;
Packit 1fb8d4
	volatile INT32 nXSrc, nYSrc;
Packit 1fb8d4
	volatile INT32 nXDst, nYDst, nWidth, nHeight;
Packit 1fb8d4
Packit 1fb8d4
	if (!hdcDest || !pnXSrc || !pnYSrc || !pnXDst || !pnYDst || !pnWidth || !pnHeight)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	hDstBmp = (HGDI_BITMAP) hdcDest->selectedObject;
Packit 1fb8d4
	nXSrc = *pnXSrc;
Packit 1fb8d4
	nYSrc = *pnYSrc;
Packit 1fb8d4
	nXDst = *pnXDst;
Packit 1fb8d4
	nYDst = *pnYDst;
Packit 1fb8d4
	nWidth = *pnWidth;
Packit 1fb8d4
	nHeight = *pnHeight;
Packit 1fb8d4
Packit 1fb8d4
	if (!hDstBmp)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (nXDst < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		nXSrc -= nXDst;
Packit 1fb8d4
		nWidth += nXDst;
Packit 1fb8d4
		nXDst = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (nYDst < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		nYSrc -= nYDst;
Packit 1fb8d4
		nHeight += nYDst;
Packit 1fb8d4
		nYDst = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	diffX = hDstBmp->width - nXDst - nWidth;
Packit 1fb8d4
Packit 1fb8d4
	if (diffX < 0)
Packit 1fb8d4
		nWidth += diffX;
Packit 1fb8d4
Packit 1fb8d4
	diffY = hDstBmp->height - nYDst - nHeight;
Packit 1fb8d4
Packit 1fb8d4
	if (diffY < 0)
Packit 1fb8d4
		nHeight += diffY;
Packit 1fb8d4
Packit 1fb8d4
	if ((nXDst < 0) || (nYDst < 0) || (nWidth < 0) || (nHeight < 0))
Packit 1fb8d4
	{
Packit 1fb8d4
		nXDst = 0;
Packit 1fb8d4
		nYDst = 0;
Packit 1fb8d4
		nWidth = 0;
Packit 1fb8d4
		nHeight = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	*pnXSrc = nXSrc;
Packit 1fb8d4
	*pnYSrc = nYSrc;
Packit 1fb8d4
	*pnXDst = nXDst;
Packit 1fb8d4
	*pnYDst = nYDst;
Packit 1fb8d4
	*pnWidth = nWidth;
Packit 1fb8d4
	*pnHeight = nHeight;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL BitBlt_process(HGDI_DC hdcDest, INT32 nXDest, INT32 nYDest,
Packit 1fb8d4
                           INT32 nWidth, INT32 nHeight, HGDI_DC hdcSrc,
Packit 1fb8d4
                           INT32 nXSrc, INT32 nYSrc, const char* rop, const gdiPalette* palette)
Packit 1fb8d4
{
Packit 1fb8d4
	INT32 x, y;
Packit 1fb8d4
	UINT32 style = 0;
Packit 1fb8d4
	BOOL useSrc = FALSE;
Packit 1fb8d4
	BOOL usePat = FALSE;
Packit 1fb8d4
	const char* iter = rop;
Packit 1fb8d4
Packit 1fb8d4
	while (*iter != '\0')
Packit 1fb8d4
	{
Packit 1fb8d4
		switch (*iter++)
Packit 1fb8d4
		{
Packit 1fb8d4
			case 'P':
Packit 1fb8d4
				usePat = TRUE;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case 'S':
Packit 1fb8d4
				useSrc = TRUE;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!hdcDest)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!adjust_src_dst_coordinates(hdcDest, &nXSrc, &nYSrc, &nXDest, &nYDest, &nWidth, &nHeight))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (useSrc && !hdcSrc)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (useSrc)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!adjust_src_coordinates(hdcSrc, nWidth, nHeight, &nXSrc, &nYSrc))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (usePat)
Packit 1fb8d4
	{
Packit 1fb8d4
		style = gdi_GetBrushStyle(hdcDest);
Packit 1fb8d4
Packit 1fb8d4
		switch (style)
Packit 1fb8d4
		{
Packit 1fb8d4
			case GDI_BS_SOLID:
Packit 1fb8d4
			case GDI_BS_HATCHED:
Packit 1fb8d4
			case GDI_BS_PATTERN:
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				WLog_ERR(TAG, "Invalid brush!!");
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((nXDest > nXSrc) && (nYDest > nYSrc))
Packit 1fb8d4
	{
Packit 1fb8d4
		for (y = nHeight - 1; y >= 0; y--)
Packit 1fb8d4
		{
Packit 1fb8d4
			for (x = nWidth - 1; x >= 0; x--)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (!BitBlt_write(hdcDest, hdcSrc, nXDest, nYDest,
Packit 1fb8d4
				                  nXSrc, nYSrc, x, y, useSrc,
Packit 1fb8d4
				                  usePat, style, rop, palette))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (nXDest > nXSrc)
Packit 1fb8d4
	{
Packit 1fb8d4
		for (y = 0; y < nHeight; y++)
Packit 1fb8d4
		{
Packit 1fb8d4
			for (x = nWidth - 1; x >= 0; x--)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (!BitBlt_write(hdcDest, hdcSrc, nXDest, nYDest,
Packit 1fb8d4
				                  nXSrc, nYSrc, x, y, useSrc,
Packit 1fb8d4
				                  usePat, style, rop, palette))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (nYDest > nYSrc)
Packit 1fb8d4
	{
Packit 1fb8d4
		for (y = nHeight - 1; y >= 0; y--)
Packit 1fb8d4
		{
Packit 1fb8d4
			for (x = 0; x < nWidth; x++)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (!BitBlt_write(hdcDest, hdcSrc, nXDest, nYDest,
Packit 1fb8d4
				                  nXSrc, nYSrc, x, y, useSrc,
Packit 1fb8d4
				                  usePat, style, rop, palette))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		for (y = 0; y < nHeight; y++)
Packit 1fb8d4
		{
Packit 1fb8d4
			for (x = 0; x < nWidth; x++)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (!BitBlt_write(hdcDest, hdcSrc, nXDest, nYDest,
Packit 1fb8d4
				                  nXSrc, nYSrc, x, y, useSrc,
Packit 1fb8d4
				                  usePat, style, rop, palette))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Perform a bit blit operation on the given pixel buffers.\n
Packit 1fb8d4
 * @msdn{dd183370}
Packit 1fb8d4
 * @param hdcDest destination device context
Packit 1fb8d4
 * @param nXDest destination x1
Packit 1fb8d4
 * @param nYDest destination y1
Packit 1fb8d4
 * @param nWidth width
Packit 1fb8d4
 * @param nHeight height
Packit 1fb8d4
 * @param hdcSrc source device context
Packit 1fb8d4
 * @param nXSrc source x1
Packit 1fb8d4
 * @param nYSrc source y1
Packit 1fb8d4
 * @param rop raster operation code
Packit 1fb8d4
 * @return 0 on failure, non-zero otherwise
Packit 1fb8d4
 */
Packit 1fb8d4
BOOL gdi_BitBlt(HGDI_DC hdcDest, INT32 nXDest, INT32 nYDest,
Packit 1fb8d4
                INT32 nWidth, INT32 nHeight, HGDI_DC hdcSrc,
Packit 1fb8d4
                INT32 nXSrc, INT32 nYSrc, DWORD rop, const gdiPalette* palette)
Packit 1fb8d4
{
Packit 1fb8d4
	HGDI_BITMAP hSrcBmp, hDstBmp;
Packit 1fb8d4
Packit 1fb8d4
	if (!hdcDest)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!gdi_ClipCoords(hdcDest, &nXDest, &nYDest, &nWidth, &nHeight, &nXSrc,
Packit 1fb8d4
	                    &nYSrc))
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
Packit 1fb8d4
	/* Check which ROP should be performed.
Packit 1fb8d4
	 * Some specific ROP are used heavily and are resource intensive,
Packit 1fb8d4
	 * add optimized versions for these here.
Packit 1fb8d4
	 *
Packit 1fb8d4
	 * For all others fall back to the generic implementation.
Packit 1fb8d4
	 */
Packit 1fb8d4
	switch (rop)
Packit 1fb8d4
	{
Packit 1fb8d4
		case GDI_SRCCOPY:
Packit 1fb8d4
			if (!hdcSrc)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			if (!adjust_src_dst_coordinates(hdcDest, &nXSrc, &nYSrc, &nXDest, &nYDest, &nWidth, &nHeight))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			if (!adjust_src_coordinates(hdcSrc, nWidth, nHeight, &nXSrc, &nYSrc))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			hSrcBmp = (HGDI_BITMAP) hdcSrc->selectedObject;
Packit 1fb8d4
			hDstBmp = (HGDI_BITMAP) hdcDest->selectedObject;
Packit 1fb8d4
Packit 1fb8d4
			if (!hSrcBmp || !hDstBmp)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			if (!freerdp_image_copy(hDstBmp->data, hDstBmp->format, hDstBmp->scanline,
Packit 1fb8d4
			                        nXDest, nYDest, nWidth, nHeight,
Packit 1fb8d4
			                        hSrcBmp->data, hSrcBmp->format, hSrcBmp->scanline, nXSrc, nYSrc, palette, FREERDP_FLIP_NONE))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_DSTCOPY:
Packit 1fb8d4
			hSrcBmp = (HGDI_BITMAP) hdcDest->selectedObject;
Packit 1fb8d4
			hDstBmp = (HGDI_BITMAP) hdcDest->selectedObject;
Packit 1fb8d4
Packit 1fb8d4
			if (!adjust_src_dst_coordinates(hdcDest, &nXSrc, &nYSrc, &nXDest, &nYDest, &nWidth, &nHeight))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			if (!adjust_src_coordinates(hdcDest, nWidth, nHeight, &nXSrc, &nYSrc))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			if (!hSrcBmp || !hDstBmp)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			if (!freerdp_image_copy(hDstBmp->data, hDstBmp->format, hDstBmp->scanline,
Packit 1fb8d4
			                        nXDest, nYDest, nWidth, nHeight,
Packit 1fb8d4
			                        hSrcBmp->data, hSrcBmp->format, hSrcBmp->scanline, nXSrc, nYSrc, palette, FREERDP_FLIP_NONE))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			if (!BitBlt_process(hdcDest, nXDest, nYDest,
Packit 1fb8d4
			                    nWidth, nHeight, hdcSrc,
Packit 1fb8d4
			                    nXSrc, nYSrc, gdi_rop_to_string(rop), palette))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!gdi_InvalidateRegion(hdcDest, nXDest, nYDest, nWidth, nHeight))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}