Blame libfreerdp/codec/include/bitmap.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * RLE Compressed Bitmap Stream
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2011 Jay Sorg <jay.sorg@gmail.com>
Packit Service fa4841
 * Copyright 2016 Armin Novak <armin.novak@thincast.com>
Packit Service fa4841
 * Copyright 2016 Thincast Technologies GmbH
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
/* do not compile the file directly */
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Write a foreground/background image to a destination buffer.
Packit Service fa4841
 */
Packit Service fa4841
static INLINE BYTE* WRITEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, UINT32 rowDelta,
Packit Service fa4841
                                   BYTE bitmask, PIXEL fgPel, INT32 cBits)
Packit Service fa4841
{
Packit Service fa4841
	PIXEL xorPixel;
Packit Service fa4841
	BYTE mask = 0x01;
Packit Service fa4841
Packit Service fa4841
	if (cBits > 8)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service b1ea74
	UNROLL(cBits, {
Packit Service fa4841
		UINT32 data;
Packit Service fa4841
		DESTREADPIXEL(xorPixel, pbDest - rowDelta);
Packit Service fa4841
Packit Service fa4841
		if (bitmask & mask)
Packit Service fa4841
			data = xorPixel ^ fgPel;
Packit Service fa4841
		else
Packit Service fa4841
			data = xorPixel;
Packit Service fa4841
Packit Service fa4841
		DESTWRITEPIXEL(pbDest, data);
Packit Service fa4841
		DESTNEXTPIXEL(pbDest);
Packit Service fa4841
		mask = mask << 1;
Packit Service fa4841
	});
Packit Service fa4841
	return pbDest;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Write a foreground/background image to a destination buffer
Packit Service fa4841
 * for the first line of compressed data.
Packit Service fa4841
 */
Packit Service fa4841
static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, BYTE bitmask,
Packit Service b1ea74
                                            PIXEL fgPel, UINT32 cBits)
Packit Service fa4841
{
Packit Service fa4841
	BYTE mask = 0x01;
Packit Service fa4841
Packit Service fa4841
	if (cBits > 8)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service b1ea74
	UNROLL(cBits, {
Packit Service fa4841
		UINT32 data;
Packit Service fa4841
Packit Service fa4841
		if (bitmask & mask)
Packit Service fa4841
			data = fgPel;
Packit Service fa4841
		else
Packit Service b1ea74
			data = BLACK_PIXEL;
Packit Service fa4841
Packit Service fa4841
		DESTWRITEPIXEL(pbDest, data);
Packit Service fa4841
		DESTNEXTPIXEL(pbDest);
Packit Service fa4841
		mask = mask << 1;
Packit Service fa4841
	});
Packit Service fa4841
	return pbDest;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Decompress an RLE compressed bitmap.
Packit Service fa4841
 */
Packit Service b1ea74
static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BYTE* pbDestBuffer,
Packit Service fa4841
                                 UINT32 rowDelta, UINT32 width, UINT32 height)
Packit Service fa4841
{
Packit Service fa4841
	const BYTE* pbSrc = pbSrcBuffer;
Packit Service b1ea74
	const BYTE* pbEnd;
Packit Service b1ea74
	const BYTE* pbDestEnd;
Packit Service fa4841
	BYTE* pbDest = pbDestBuffer;
Packit Service fa4841
	PIXEL temp;
Packit Service fa4841
	PIXEL fgPel = WHITE_PIXEL;
Packit Service fa4841
	BOOL fInsertFgPel = FALSE;
Packit Service fa4841
	BOOL fFirstLine = TRUE;
Packit Service fa4841
	BYTE bitmask;
Packit Service fa4841
	PIXEL pixelA, pixelB;
Packit Service fa4841
	UINT32 runLength;
Packit Service fa4841
	UINT32 code;
Packit Service fa4841
	UINT32 advance;
Packit Service fa4841
	RLEEXTRA
Packit Service fa4841
Packit Service fa4841
	if ((rowDelta == 0) || (rowDelta < width))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!pbSrcBuffer || !pbDestBuffer)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service b1ea74
	pbEnd = pbSrcBuffer + cbSrcBuffer;
Packit Service b1ea74
	pbDestEnd = pbDestBuffer + rowDelta * height;
Packit Service b1ea74
Packit Service fa4841
	while (pbSrc < pbEnd)
Packit Service fa4841
	{
Packit Service fa4841
		/* Watch out for the end of the first scanline. */
Packit Service fa4841
		if (fFirstLine)
Packit Service fa4841
		{
Packit Service fa4841
			if ((UINT32)(pbDest - pbDestBuffer) >= rowDelta)
Packit Service fa4841
			{
Packit Service fa4841
				fFirstLine = FALSE;
Packit Service fa4841
				fInsertFgPel = FALSE;
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		/*
Packit Service fa4841
		   Extract the compression order code ID from the compression
Packit Service fa4841
		   order header.
Packit Service fa4841
		*/
Packit Service fa4841
		code = ExtractCodeId(*pbSrc);
Packit Service fa4841
Packit Service fa4841
		/* Handle Background Run Orders. */
Packit Service fa4841
		if (code == REGULAR_BG_RUN || code == MEGA_MEGA_BG_RUN)
Packit Service fa4841
		{
Packit Service fa4841
			runLength = ExtractRunLength(code, pbSrc, &advance);
Packit Service fa4841
			pbSrc = pbSrc + advance;
Packit Service fa4841
Packit Service fa4841
			if (fFirstLine)
Packit Service fa4841
			{
Packit Service fa4841
				if (fInsertFgPel)
Packit Service fa4841
				{
Packit Service fa4841
					if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
Packit Service fa4841
						return FALSE;
Packit Service fa4841
Packit Service fa4841
					DESTWRITEPIXEL(pbDest, fgPel);
Packit Service fa4841
					DESTNEXTPIXEL(pbDest);
Packit Service fa4841
					runLength = runLength - 1;
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service b1ea74
				UNROLL(runLength, {
Packit Service fa4841
					DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
Packit Service fa4841
					DESTNEXTPIXEL(pbDest);
Packit Service fa4841
				});
Packit Service fa4841
			}
Packit Service fa4841
			else
Packit Service fa4841
			{
Packit Service fa4841
				if (fInsertFgPel)
Packit Service fa4841
				{
Packit Service fa4841
					DESTREADPIXEL(temp, pbDest - rowDelta);
Packit Service fa4841
Packit Service fa4841
					if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
Packit Service fa4841
						return FALSE;
Packit Service fa4841
Packit Service fa4841
					DESTWRITEPIXEL(pbDest, temp ^ fgPel);
Packit Service fa4841
					DESTNEXTPIXEL(pbDest);
Packit Service fa4841
					runLength--;
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service b1ea74
				UNROLL(runLength, {
Packit Service fa4841
					DESTREADPIXEL(temp, pbDest - rowDelta);
Packit Service fa4841
					DESTWRITEPIXEL(pbDest, temp);
Packit Service fa4841
					DESTNEXTPIXEL(pbDest);
Packit Service fa4841
				});
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			/* A follow-on background run order will need a foreground pel inserted. */
Packit Service fa4841
			fInsertFgPel = TRUE;
Packit Service fa4841
			continue;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		/* For any of the other run-types a follow-on background run
Packit Service b1ea74
		    order does not need a foreground pel inserted. */
Packit Service fa4841
		fInsertFgPel = FALSE;
Packit Service fa4841
Packit Service fa4841
		switch (code)
Packit Service fa4841
		{
Packit Service fa4841
			/* Handle Foreground Run Orders. */
Packit Service fa4841
			case REGULAR_FG_RUN:
Packit Service fa4841
			case MEGA_MEGA_FG_RUN:
Packit Service fa4841
			case LITE_SET_FG_FG_RUN:
Packit Service fa4841
			case MEGA_MEGA_SET_FG_RUN:
Packit Service fa4841
				runLength = ExtractRunLength(code, pbSrc, &advance);
Packit Service fa4841
				pbSrc = pbSrc + advance;
Packit Service fa4841
Packit Service fa4841
				if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN)
Packit Service fa4841
				{
Packit Service b1ea74
					if (pbSrc >= pbEnd)
Packit Service b1ea74
						return FALSE;
Packit Service fa4841
					SRCREADPIXEL(fgPel, pbSrc);
Packit Service fa4841
					SRCNEXTPIXEL(pbSrc);
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				if (fFirstLine)
Packit Service fa4841
				{
Packit Service b1ea74
					UNROLL(runLength, {
Packit Service fa4841
						DESTWRITEPIXEL(pbDest, fgPel);
Packit Service fa4841
						DESTNEXTPIXEL(pbDest);
Packit Service fa4841
					});
Packit Service fa4841
				}
Packit Service fa4841
				else
Packit Service fa4841
				{
Packit Service b1ea74
					UNROLL(runLength, {
Packit Service fa4841
						DESTREADPIXEL(temp, pbDest - rowDelta);
Packit Service fa4841
						DESTWRITEPIXEL(pbDest, temp ^ fgPel);
Packit Service fa4841
						DESTNEXTPIXEL(pbDest);
Packit Service fa4841
					});
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			/* Handle Dithered Run Orders. */
Packit Service fa4841
			case LITE_DITHERED_RUN:
Packit Service fa4841
			case MEGA_MEGA_DITHERED_RUN:
Packit Service fa4841
				runLength = ExtractRunLength(code, pbSrc, &advance);
Packit Service fa4841
				pbSrc = pbSrc + advance;
Packit Service b1ea74
				if (pbSrc >= pbEnd)
Packit Service b1ea74
					return FALSE;
Packit Service fa4841
				SRCREADPIXEL(pixelA, pbSrc);
Packit Service fa4841
				SRCNEXTPIXEL(pbSrc);
Packit Service b1ea74
				if (pbSrc >= pbEnd)
Packit Service b1ea74
					return FALSE;
Packit Service fa4841
				SRCREADPIXEL(pixelB, pbSrc);
Packit Service fa4841
				SRCNEXTPIXEL(pbSrc);
Packit Service fa4841
Packit Service fa4841
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength * 2))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service b1ea74
				UNROLL(runLength, {
Packit Service fa4841
					DESTWRITEPIXEL(pbDest, pixelA);
Packit Service fa4841
					DESTNEXTPIXEL(pbDest);
Packit Service fa4841
					DESTWRITEPIXEL(pbDest, pixelB);
Packit Service fa4841
					DESTNEXTPIXEL(pbDest);
Packit Service fa4841
				});
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			/* Handle Color Run Orders. */
Packit Service fa4841
			case REGULAR_COLOR_RUN:
Packit Service fa4841
			case MEGA_MEGA_COLOR_RUN:
Packit Service fa4841
				runLength = ExtractRunLength(code, pbSrc, &advance);
Packit Service fa4841
				pbSrc = pbSrc + advance;
Packit Service b1ea74
				if (pbSrc >= pbEnd)
Packit Service b1ea74
					return FALSE;
Packit Service fa4841
				SRCREADPIXEL(pixelA, pbSrc);
Packit Service fa4841
				SRCNEXTPIXEL(pbSrc);
Packit Service fa4841
Packit Service fa4841
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service b1ea74
				UNROLL(runLength, {
Packit Service fa4841
					DESTWRITEPIXEL(pbDest, pixelA);
Packit Service fa4841
					DESTNEXTPIXEL(pbDest);
Packit Service fa4841
				});
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			/* Handle Foreground/Background Image Orders. */
Packit Service fa4841
			case REGULAR_FGBG_IMAGE:
Packit Service fa4841
			case MEGA_MEGA_FGBG_IMAGE:
Packit Service fa4841
			case LITE_SET_FG_FGBG_IMAGE:
Packit Service fa4841
			case MEGA_MEGA_SET_FGBG_IMAGE:
Packit Service fa4841
				runLength = ExtractRunLength(code, pbSrc, &advance);
Packit Service fa4841
				pbSrc = pbSrc + advance;
Packit Service fa4841
Packit Service b1ea74
				if (pbSrc >= pbEnd)
Packit Service b1ea74
					return FALSE;
Packit Service fa4841
				if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE)
Packit Service fa4841
				{
Packit Service fa4841
					SRCREADPIXEL(fgPel, pbSrc);
Packit Service fa4841
					SRCNEXTPIXEL(pbSrc);
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				if (fFirstLine)
Packit Service fa4841
				{
Packit Service fa4841
					while (runLength > 8)
Packit Service fa4841
					{
Packit Service fa4841
						bitmask = *pbSrc;
Packit Service fa4841
						pbSrc = pbSrc + 1;
Packit Service fa4841
						pbDest = WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, 8);
Packit Service fa4841
Packit Service fa4841
						if (!pbDest)
Packit Service fa4841
							return FALSE;
Packit Service fa4841
Packit Service fa4841
						runLength = runLength - 8;
Packit Service fa4841
					}
Packit Service fa4841
				}
Packit Service fa4841
				else
Packit Service fa4841
				{
Packit Service fa4841
					while (runLength > 8)
Packit Service fa4841
					{
Packit Service fa4841
						bitmask = *pbSrc;
Packit Service fa4841
						pbSrc = pbSrc + 1;
Packit Service fa4841
						pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, 8);
Packit Service fa4841
Packit Service fa4841
						if (!pbDest)
Packit Service fa4841
							return FALSE;
Packit Service fa4841
Packit Service fa4841
						runLength = runLength - 8;
Packit Service fa4841
					}
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				if (runLength > 0)
Packit Service fa4841
				{
Packit Service fa4841
					bitmask = *pbSrc;
Packit Service fa4841
					pbSrc = pbSrc + 1;
Packit Service fa4841
Packit Service fa4841
					if (fFirstLine)
Packit Service fa4841
					{
Packit Service b1ea74
						pbDest =
Packit Service b1ea74
						    WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, runLength);
Packit Service fa4841
					}
Packit Service fa4841
					else
Packit Service fa4841
					{
Packit Service b1ea74
						pbDest =
Packit Service b1ea74
						    WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, runLength);
Packit Service fa4841
					}
Packit Service fa4841
Packit Service fa4841
					if (!pbDest)
Packit Service fa4841
						return FALSE;
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			/* Handle Color Image Orders. */
Packit Service fa4841
			case REGULAR_COLOR_IMAGE:
Packit Service fa4841
			case MEGA_MEGA_COLOR_IMAGE:
Packit Service fa4841
				runLength = ExtractRunLength(code, pbSrc, &advance);
Packit Service fa4841
				pbSrc = pbSrc + advance;
Packit Service b1ea74
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
Packit Service b1ea74
					return FALSE;
Packit Service b1ea74
Packit Service b1ea74
				UNROLL(runLength, {
Packit Service b1ea74
					if (pbSrc >= pbEnd)
Packit Service b1ea74
						return FALSE;
Packit Service fa4841
					SRCREADPIXEL(temp, pbSrc);
Packit Service fa4841
					SRCNEXTPIXEL(pbSrc);
Packit Service fa4841
					DESTWRITEPIXEL(pbDest, temp);
Packit Service fa4841
					DESTNEXTPIXEL(pbDest);
Packit Service fa4841
				});
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			/* Handle Special Order 1. */
Packit Service fa4841
			case SPECIAL_FGBG_1:
Packit Service fa4841
				pbSrc = pbSrc + 1;
Packit Service fa4841
Packit Service fa4841
				if (fFirstLine)
Packit Service fa4841
				{
Packit Service b1ea74
					pbDest =
Packit Service b1ea74
					    WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg1, fgPel, 8);
Packit Service fa4841
				}
Packit Service fa4841
				else
Packit Service fa4841
				{
Packit Service b1ea74
					pbDest =
Packit Service b1ea74
					    WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg1, fgPel, 8);
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				if (!pbDest)
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			/* Handle Special Order 2. */
Packit Service fa4841
			case SPECIAL_FGBG_2:
Packit Service fa4841
				pbSrc = pbSrc + 1;
Packit Service fa4841
Packit Service fa4841
				if (fFirstLine)
Packit Service fa4841
				{
Packit Service b1ea74
					pbDest =
Packit Service b1ea74
					    WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg2, fgPel, 8);
Packit Service fa4841
				}
Packit Service fa4841
				else
Packit Service fa4841
				{
Packit Service b1ea74
					pbDest =
Packit Service b1ea74
					    WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg2, fgPel, 8);
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				if (!pbDest)
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			/* Handle White Order. */
Packit Service fa4841
			case SPECIAL_WHITE:
Packit Service fa4841
				pbSrc = pbSrc + 1;
Packit Service fa4841
Packit Service fa4841
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				DESTWRITEPIXEL(pbDest, WHITE_PIXEL);
Packit Service fa4841
				DESTNEXTPIXEL(pbDest);
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			/* Handle Black Order. */
Packit Service fa4841
			case SPECIAL_BLACK:
Packit Service fa4841
				pbSrc = pbSrc + 1;
Packit Service fa4841
Packit Service fa4841
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
Packit Service fa4841
				DESTNEXTPIXEL(pbDest);
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			default:
Packit Service fa4841
				return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}