FreeRDP/libfreerdp/gdi/line.c

300 lines
5.9 KiB
C
Raw Normal View History

2011-07-01 00:17:55 +04:00
/**
2012-10-09 07:02:04 +04:00
* FreeRDP: A Remote Desktop Protocol Implementation
2011-07-01 00:17:55 +04:00
* GDI Line Functions
*
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
* Copyright 2016 Thincast Technologies GmbH
2011-07-01 00:17:55 +04:00
*
* 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
2011-07-01 00:17:55 +04:00
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <freerdp/freerdp.h>
#include <freerdp/gdi/gdi.h>
#include <freerdp/gdi/pen.h>
#include <freerdp/gdi/bitmap.h>
#include <freerdp/gdi/region.h>
2011-07-01 00:17:55 +04:00
#include "drawing.h"
#include "clipping.h"
#include "line.h"
2011-07-01 00:17:55 +04:00
/**
* Draw a line from the current position to the given position.\n
* @msdn{dd145029}
* @param hdc device context
* @param nXEnd ending x position
* @param nYEnd ending y position
* @return nonzero if successful, 0 otherwise
2011-07-01 00:17:55 +04:00
*/
static BOOL gdi_rop_color(UINT32 rop, BYTE* pixelPtr, UINT32 pen, UINT32 format)
{
UINT32 pixel = ReadColor(pixelPtr, format);
switch(rop)
{
case 1: /* LineTo_BLACK */
pixel = GetColor(format, 0, 0, 0, 0xFF);
break;
case 2: /* LineTo_NOTMERGEPEN */
pixel = ~(pixel | pen);
break;
case 3: /* LineTo_MASKNOTPEN */
pixel &= ~pen;
break;
case 4: /* LineTo_NOTCOPYPEN */
pixel = ~pen;
break;
case 5: /* LineTo_MASKPENNOT */
pixel = pen & ~pixel;
break;
case 6: /* LineTo_NOT */
pixel = ~pixel;
break;
case 7: /* LineTo_XORPEN */
pixel = pixel ^ pen;
break;
case 8: /* LineTo_NOTMASKPEN */
pixel = ~(pixel & pen);
break;
case 9: /* LineTo_MASKPEN */
pixel &= pen;
break;
case 10: /* LineTo_NOTXORPEN */
pixel = ~(pixel ^ pen);
break;
case 11: /* LineTo_NOP */
break;
case 12: /* LineTo_MERGENOTPEN */
pixel |= ~pen;
break;
case 13: /* LineTo_COPYPEN */
pixel = pen;
break;
case 14: /* LineTo_MERGEPENNOT */
pixel = pixel | ~pen;
break;
case 15: /* LineTo_MERGEPEN */
pixel = pixel | pen;
break;
case 16: /* LineTo_WHITE */
pixel = GetColor(format, 0, 0, 0, 0);
break;
2011-07-01 00:17:55 +04:00
default:
return FALSE;
}
WriteColor(pixelPtr, format, pixel);
return TRUE;
}
BOOL gdi_LineTo(HGDI_DC hdc, UINT32 nXEnd, UINT32 nYEnd)
2011-07-01 00:17:55 +04:00
{
UINT32 x, y;
UINT32 x1, y1;
UINT32 x2, y2;
UINT32 e, e2;
INT32 dx, dy;
INT32 sx, sy;
INT32 bx1, by1;
INT32 bx2, by2;
HGDI_BITMAP bmp;
UINT32 pen;
UINT32 rop2 = gdi_GetROP2(hdc);
x1 = hdc->pen->posX;
y1 = hdc->pen->posY;
x2 = nXEnd;
y2 = nYEnd;
dx = (x1 > x2) ? x1 - x2 : x2 - x1;
dy = (y1 > y2) ? y1 - y2 : y2 - y1;
sx = (x1 < x2) ? 1 : -1;
sy = (y1 < y2) ? 1 : -1;
2011-07-01 00:17:55 +04:00
e = dx - dy;
x = x1;
y = y1;
bmp = (HGDI_BITMAP) hdc->selectedObject;
if (hdc->clip->null)
{
bx1 = (x1 < x2) ? x1 : x2;
by1 = (y1 < y2) ? y1 : y2;
bx2 = (x1 > x2) ? x1 : x2;
by2 = (y1 > y2) ? y1 : y2;
}
else
{
bx1 = hdc->clip->x;
by1 = hdc->clip->y;
bx2 = bx1 + hdc->clip->w - 1;
by2 = by1 + hdc->clip->h - 1;
}
bx1 = MAX(bx1, 0);
by1 = MAX(by1, 0);
bx2 = MIN(bx2, bmp->width - 1);
by2 = MIN(by2, bmp->height - 1);
if (!gdi_InvalidateRegion(hdc, bx1, by1, bx2 - bx1 + 1, by2 - by1 + 1))
return FALSE;
pen = gdi_GetPenColor(hdc->pen, bmp->format);
while (1)
{
if (!(x == x2 && y == y2))
{
if ((x >= bx1 && x <= bx2) && (y >= by1 && y <= by2))
{
BYTE* pixel = gdi_GetPointer(bmp, x, y);
gdi_rop_color(rop2, pixel, pen, bmp->format);
}
}
else
{
break;
}
e2 = 2 * e;
if (e2 > -dy)
{
e -= dy;
x += sx;
}
if (e2 < dx)
{
e += dx;
y += sy;
}
}
return TRUE;
2011-07-01 00:17:55 +04:00
}
/**
* Draw one or more straight lines
* @param hdc device context
* @param lppt array of points
* @param cCount number of points
* @return nonzero on success, 0 otherwise
2011-07-01 00:17:55 +04:00
*/
BOOL gdi_PolylineTo(HGDI_DC hdc, GDI_POINT *lppt, DWORD cCount)
2011-07-01 00:17:55 +04:00
{
DWORD i;
2011-07-01 00:17:55 +04:00
for (i = 0; i < cCount; i++)
{
if (!gdi_LineTo(hdc, lppt[i].x, lppt[i].y))
return FALSE;
if (!gdi_MoveToEx(hdc, lppt[i].x, lppt[i].y, NULL))
return FALSE;
2011-07-01 00:17:55 +04:00
}
return TRUE;
2011-07-01 00:17:55 +04:00
}
/**
* Draw one or more straight lines
* @param hdc device context
* @param lppt array of points
* @param cPoints number of points
* @return nonzero on success, 0 otherwise
2011-07-01 00:17:55 +04:00
*/
BOOL gdi_Polyline(HGDI_DC hdc, GDI_POINT *lppt, UINT32 cPoints)
2011-07-01 00:17:55 +04:00
{
if (cPoints > 0)
{
UINT32 i;
2011-07-01 00:17:55 +04:00
GDI_POINT pt;
if (!gdi_MoveToEx(hdc, lppt[0].x, lppt[0].y, &pt))
return FALSE;
2011-07-01 00:17:55 +04:00
for (i = 0; i < cPoints; i++)
{
if (!gdi_LineTo(hdc, lppt[i].x, lppt[i].y))
return FALSE;
if (!gdi_MoveToEx(hdc, lppt[i].x, lppt[i].y, NULL))
return FALSE;
2011-07-01 00:17:55 +04:00
}
if (!gdi_MoveToEx(hdc, pt.x, pt.y, NULL))
return FALSE;
2011-07-01 00:17:55 +04:00
}
return TRUE;
2011-07-01 00:17:55 +04:00
}
/**
* Draw multiple series of connected line segments
* @param hdc device context
* @param lppt array of points
* @param lpdwPolyPoints array of numbers of points per series
* @param cCount count of entries in lpdwPolyPoints
* @return nonzero on success, 0 otherwise
2011-07-01 00:17:55 +04:00
*/
BOOL gdi_PolyPolyline(HGDI_DC hdc, GDI_POINT *lppt, UINT32 *lpdwPolyPoints, DWORD cCount)
2011-07-01 00:17:55 +04:00
{
UINT32 cPoints;
DWORD i, j = 0;
2011-07-01 00:17:55 +04:00
for (i = 0; i < cCount; i++)
{
cPoints = lpdwPolyPoints[i];
if (!gdi_Polyline(hdc, &lppt[j], cPoints))
return FALSE;
2011-07-01 00:17:55 +04:00
j += cPoints;
}
return TRUE;
2011-07-01 00:17:55 +04:00
}
/**
* Move pen from the current device context to a new position.
* @param hdc device context
* @param X x position
* @param Y y position
* @return nonzero on success, 0 otherwise
2011-07-01 00:17:55 +04:00
*/
BOOL gdi_MoveToEx(HGDI_DC hdc, UINT32 X, UINT32 Y, HGDI_POINT lpPoint)
2011-07-01 00:17:55 +04:00
{
if (lpPoint != NULL)
{
lpPoint->x = hdc->pen->posX;
lpPoint->y = hdc->pen->posY;
}
hdc->pen->posX = X;
hdc->pen->posY = Y;
return TRUE;
2011-07-01 00:17:55 +04:00
}