Blame libfreerdp/gdi/line.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * GDI Line 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/freerdp.h>
Packit 1fb8d4
#include <freerdp/gdi/gdi.h>
Packit 1fb8d4
#include <freerdp/gdi/pen.h>
Packit 1fb8d4
#include <freerdp/gdi/bitmap.h>
Packit 1fb8d4
#include <freerdp/gdi/region.h>
Packit 1fb8d4
Packit 1fb8d4
#include "drawing.h"
Packit 1fb8d4
#include "clipping.h"
Packit 1fb8d4
#include "line.h"
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Draw a line from the current position to the given position.\n
Packit 1fb8d4
 * @msdn{dd145029}
Packit 1fb8d4
 * @param hdc device context
Packit 1fb8d4
 * @param nXEnd ending x position
Packit 1fb8d4
 * @param nYEnd ending y position
Packit 1fb8d4
 * @return nonzero if successful, 0 otherwise
Packit 1fb8d4
 */
Packit 1fb8d4
static BOOL gdi_rop_color(UINT32 rop, BYTE* pixelPtr, UINT32 pen, UINT32 format)
Packit 1fb8d4
{
Packit 1fb8d4
	const UINT32 srcPixel = ReadColor(pixelPtr, format);
Packit 1fb8d4
	UINT32 dstPixel;
Packit 1fb8d4
Packit 1fb8d4
	switch (rop)
Packit 1fb8d4
	{
Packit 1fb8d4
		case GDI_R2_BLACK: /* LineTo_BLACK */
Packit 1fb8d4
			dstPixel = FreeRDPGetColor(format, 0, 0, 0, 0xFF);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_NOTMERGEPEN: /* LineTo_NOTMERGEPEN */
Packit 1fb8d4
			dstPixel = ~(srcPixel | pen);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_MASKNOTPEN: /* LineTo_MASKNOTPEN */
Packit 1fb8d4
			dstPixel = srcPixel & ~pen;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_NOTCOPYPEN: /* LineTo_NOTCOPYPEN */
Packit 1fb8d4
			dstPixel = ~pen;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_MASKPENNOT: /* LineTo_MASKPENNOT */
Packit 1fb8d4
			dstPixel = pen & ~srcPixel;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_NOT: /* LineTo_NOT */
Packit 1fb8d4
			dstPixel = ~srcPixel;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_XORPEN: /* LineTo_XORPEN */
Packit 1fb8d4
			dstPixel = srcPixel ^ pen;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_NOTMASKPEN: /* LineTo_NOTMASKPEN */
Packit 1fb8d4
			dstPixel = ~(srcPixel & pen);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_MASKPEN: /* LineTo_MASKPEN */
Packit 1fb8d4
			dstPixel = srcPixel & pen;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_NOTXORPEN: /* LineTo_NOTXORPEN */
Packit 1fb8d4
			dstPixel = ~(srcPixel ^ pen);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_NOP: /* LineTo_NOP */
Packit 1fb8d4
			dstPixel = srcPixel;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_MERGENOTPEN: /* LineTo_MERGENOTPEN */
Packit 1fb8d4
			dstPixel = srcPixel | ~pen;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_COPYPEN: /* LineTo_COPYPEN */
Packit 1fb8d4
			dstPixel = pen;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_MERGEPENNOT: /* LineTo_MERGEPENNOT */
Packit 1fb8d4
			dstPixel = srcPixel | ~pen;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_MERGEPEN: /* LineTo_MERGEPEN */
Packit 1fb8d4
			dstPixel = srcPixel | pen;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case GDI_R2_WHITE: /* LineTo_WHITE */
Packit 1fb8d4
			dstPixel = FreeRDPGetColor(format, 0xFF, 0xFF, 0xFF, 0xFF);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return WriteColor(pixelPtr, format, dstPixel);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL gdi_LineTo(HGDI_DC hdc, UINT32 nXEnd, UINT32 nYEnd)
Packit 1fb8d4
{
Packit 1fb8d4
	INT32 x, y;
Packit 1fb8d4
	INT32 x1, y1;
Packit 1fb8d4
	INT32 x2, y2;
Packit 1fb8d4
	INT32 e, e2;
Packit 1fb8d4
	INT32 dx, dy;
Packit 1fb8d4
	INT32 sx, sy;
Packit 1fb8d4
	INT32 bx1, by1;
Packit 1fb8d4
	INT32 bx2, by2;
Packit 1fb8d4
	HGDI_BITMAP bmp;
Packit 1fb8d4
	UINT32 pen;
Packit 1fb8d4
	INT32 rop2 = gdi_GetROP2(hdc);
Packit 1fb8d4
	x1 = hdc->pen->posX;
Packit 1fb8d4
	y1 = hdc->pen->posY;
Packit 1fb8d4
	x2 = nXEnd;
Packit 1fb8d4
	y2 = nYEnd;
Packit 1fb8d4
	dx = (x1 > x2) ? x1 - x2 : x2 - x1;
Packit 1fb8d4
	dy = (y1 > y2) ? y1 - y2 : y2 - y1;
Packit 1fb8d4
	sx = (x1 < x2) ? 1 : -1;
Packit 1fb8d4
	sy = (y1 < y2) ? 1 : -1;
Packit 1fb8d4
	e = dx - dy;
Packit 1fb8d4
	x = x1;
Packit 1fb8d4
	y = y1;
Packit 1fb8d4
	bmp = (HGDI_BITMAP) hdc->selectedObject;
Packit 1fb8d4
Packit 1fb8d4
	if (hdc->clip->null)
Packit 1fb8d4
	{
Packit 1fb8d4
		bx1 = (x1 < x2) ? x1 : x2;
Packit 1fb8d4
		by1 = (y1 < y2) ? y1 : y2;
Packit 1fb8d4
		bx2 = (x1 > x2) ? x1 : x2;
Packit 1fb8d4
		by2 = (y1 > y2) ? y1 : y2;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		bx1 = hdc->clip->x;
Packit 1fb8d4
		by1 = hdc->clip->y;
Packit 1fb8d4
		bx2 = bx1 + hdc->clip->w - 1;
Packit 1fb8d4
		by2 = by1 + hdc->clip->h - 1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	bx1 = MAX(bx1, 0);
Packit 1fb8d4
	by1 = MAX(by1, 0);
Packit 1fb8d4
	bx2 = MIN(bx2, bmp->width - 1);
Packit 1fb8d4
	by2 = MIN(by2, bmp->height - 1);
Packit 1fb8d4
Packit 1fb8d4
	if (!gdi_InvalidateRegion(hdc, bx1, by1, bx2 - bx1 + 1, by2 - by1 + 1))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	pen = gdi_GetPenColor(hdc->pen, bmp->format);
Packit 1fb8d4
Packit 1fb8d4
	while (1)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!(x == x2 && y == y2))
Packit 1fb8d4
		{
Packit 1fb8d4
			if ((x >= bx1 && x <= bx2) && (y >= by1 && y <= by2))
Packit 1fb8d4
			{
Packit 1fb8d4
				BYTE* pixel = gdi_GetPointer(bmp, x, y);
Packit 1fb8d4
				gdi_rop_color(rop2, pixel, pen, bmp->format);
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		e2 = 2 * e;
Packit 1fb8d4
Packit 1fb8d4
		if (e2 > -dy)
Packit 1fb8d4
		{
Packit 1fb8d4
			e -= dy;
Packit 1fb8d4
			x += sx;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (e2 < dx)
Packit 1fb8d4
		{
Packit 1fb8d4
			e += dx;
Packit 1fb8d4
			y += sy;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Draw one or more straight lines
Packit 1fb8d4
 * @param hdc device context
Packit 1fb8d4
 * @param lppt array of points
Packit 1fb8d4
 * @param cCount number of points
Packit 1fb8d4
 * @return nonzero on success, 0 otherwise
Packit 1fb8d4
 */
Packit 1fb8d4
BOOL gdi_PolylineTo(HGDI_DC hdc, GDI_POINT* lppt, DWORD cCount)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD i;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < cCount; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!gdi_LineTo(hdc, lppt[i].x, lppt[i].y))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		if (!gdi_MoveToEx(hdc, lppt[i].x, lppt[i].y, NULL))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Draw one or more straight lines
Packit 1fb8d4
 * @param hdc device context
Packit 1fb8d4
 * @param lppt array of points
Packit 1fb8d4
 * @param cPoints number of points
Packit 1fb8d4
 * @return nonzero on success, 0 otherwise
Packit 1fb8d4
 */
Packit 1fb8d4
BOOL gdi_Polyline(HGDI_DC hdc, GDI_POINT* lppt, UINT32 cPoints)
Packit 1fb8d4
{
Packit 1fb8d4
	if (cPoints > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		UINT32 i;
Packit 1fb8d4
		GDI_POINT pt;
Packit 1fb8d4
Packit 1fb8d4
		if (!gdi_MoveToEx(hdc, lppt[0].x, lppt[0].y, &pt))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		for (i = 0; i < cPoints; i++)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!gdi_LineTo(hdc, lppt[i].x, lppt[i].y))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			if (!gdi_MoveToEx(hdc, lppt[i].x, lppt[i].y, NULL))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (!gdi_MoveToEx(hdc, pt.x, pt.y, NULL))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Draw multiple series of connected line segments
Packit 1fb8d4
 * @param hdc device context
Packit 1fb8d4
 * @param lppt array of points
Packit 1fb8d4
 * @param lpdwPolyPoints array of numbers of points per series
Packit 1fb8d4
 * @param cCount count of entries in lpdwPolyPoints
Packit 1fb8d4
 * @return nonzero on success, 0 otherwise
Packit 1fb8d4
 */
Packit 1fb8d4
BOOL gdi_PolyPolyline(HGDI_DC hdc, GDI_POINT* lppt, UINT32* lpdwPolyPoints,
Packit 1fb8d4
                      DWORD cCount)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 cPoints;
Packit 1fb8d4
	DWORD i, j = 0;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < cCount; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		cPoints = lpdwPolyPoints[i];
Packit 1fb8d4
Packit 1fb8d4
		if (!gdi_Polyline(hdc, &lppt[j], cPoints))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		j += cPoints;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Move pen from the current device context to a new position.
Packit 1fb8d4
 * @param hdc device context
Packit 1fb8d4
 * @param X x position
Packit 1fb8d4
 * @param Y y position
Packit 1fb8d4
 * @return nonzero on success, 0 otherwise
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL gdi_MoveToEx(HGDI_DC hdc, UINT32 X, UINT32 Y, HGDI_POINT lpPoint)
Packit 1fb8d4
{
Packit 1fb8d4
	if (lpPoint != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		lpPoint->x = hdc->pen->posX;
Packit 1fb8d4
		lpPoint->y = hdc->pen->posY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	hdc->pen->posX = X;
Packit 1fb8d4
	hdc->pen->posY = Y;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}