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 Shape Functions
|
|
|
|
*
|
|
|
|
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
2016-04-05 18:07:45 +03:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2022-02-16 13:20:38 +03:00
|
|
|
#include <freerdp/config.h>
|
2012-08-15 01:09:01 +04:00
|
|
|
|
2011-07-01 00:17:55 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2012-08-15 01:09:01 +04:00
|
|
|
|
2011-07-01 00:17:55 +04:00
|
|
|
#include <freerdp/freerdp.h>
|
2011-08-15 22:33:04 +04:00
|
|
|
#include <freerdp/gdi/gdi.h>
|
2011-07-01 00:17:55 +04:00
|
|
|
|
2011-08-22 21:08:01 +04:00
|
|
|
#include <freerdp/gdi/bitmap.h>
|
2016-04-05 18:07:45 +03:00
|
|
|
#include <freerdp/gdi/region.h>
|
2011-08-22 21:08:01 +04:00
|
|
|
#include <freerdp/gdi/shape.h>
|
2011-07-01 00:17:55 +04:00
|
|
|
|
2016-04-05 18:07:45 +03:00
|
|
|
#include <freerdp/log.h>
|
|
|
|
|
|
|
|
#include "clipping.h"
|
2016-10-10 12:09:06 +03:00
|
|
|
#include "../gdi/gdi.h"
|
2016-04-05 18:07:45 +03:00
|
|
|
|
|
|
|
#define TAG FREERDP_TAG("gdi.shape")
|
2011-07-01 00:17:55 +04:00
|
|
|
|
|
|
|
static void Ellipse_Bresenham(HGDI_DC hdc, int x1, int y1, int x2, int y2)
|
|
|
|
{
|
2016-04-05 18:07:45 +03:00
|
|
|
INT32 e, e2;
|
|
|
|
INT32 dx, dy;
|
|
|
|
INT32 a, b, c;
|
2011-07-01 00:17:55 +04:00
|
|
|
a = (x1 < x2) ? x2 - x1 : x1 - x2;
|
|
|
|
b = (y1 < y2) ? y2 - y1 : y1 - y2;
|
|
|
|
c = b & 1;
|
|
|
|
dx = 4 * (1 - a) * b * b;
|
|
|
|
dy = 4 * (c + 1) * a * a;
|
|
|
|
e = dx + dy + c * a * a;
|
|
|
|
|
|
|
|
if (x1 > x2)
|
|
|
|
{
|
|
|
|
x1 = x2;
|
|
|
|
x2 += a;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (y1 > y2)
|
|
|
|
y1 = y2;
|
|
|
|
|
|
|
|
y1 += (b + 1) / 2;
|
|
|
|
y2 = y1 - c;
|
|
|
|
a *= 8 * a;
|
|
|
|
c = 8 * b * b;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2016-04-05 18:07:45 +03:00
|
|
|
gdi_SetPixel(hdc, x2, y1, 0);
|
|
|
|
gdi_SetPixel(hdc, x1, y1, 0);
|
|
|
|
gdi_SetPixel(hdc, x1, y2, 0);
|
|
|
|
gdi_SetPixel(hdc, x2, y2, 0);
|
2011-07-01 00:17:55 +04:00
|
|
|
e2 = 2 * e;
|
|
|
|
|
|
|
|
if (e2 >= dx)
|
|
|
|
{
|
|
|
|
x1++;
|
|
|
|
x2--;
|
|
|
|
e += dx += c;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e2 <= dy)
|
|
|
|
{
|
|
|
|
y1++;
|
|
|
|
y2--;
|
|
|
|
e += dy += a;
|
|
|
|
}
|
2019-11-06 17:24:51 +03:00
|
|
|
} while (x1 <= x2);
|
2011-07-01 00:17:55 +04:00
|
|
|
|
|
|
|
while (y1 - y2 < b)
|
|
|
|
{
|
2016-04-05 18:07:45 +03:00
|
|
|
gdi_SetPixel(hdc, x1 - 1, ++y1, 0);
|
|
|
|
gdi_SetPixel(hdc, x1 - 1, --y2, 0);
|
2011-07-01 00:17:55 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draw an ellipse
|
2022-12-09 16:35:03 +03:00
|
|
|
* msdn{dd162510}
|
|
|
|
*
|
2011-07-01 00:17:55 +04:00
|
|
|
* @param hdc device context
|
|
|
|
* @param nLeftRect x1
|
|
|
|
* @param nTopRect y1
|
|
|
|
* @param nRightRect x2
|
|
|
|
* @param nBottomRect y2
|
2022-12-09 16:35:03 +03:00
|
|
|
*
|
2015-06-26 15:32:38 +03:00
|
|
|
* @return nonzero if successful, 0 otherwise
|
2011-07-01 00:17:55 +04:00
|
|
|
*/
|
2019-11-06 17:24:51 +03:00
|
|
|
BOOL gdi_Ellipse(HGDI_DC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect)
|
2011-07-01 00:17:55 +04:00
|
|
|
{
|
|
|
|
Ellipse_Bresenham(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
|
2015-06-26 15:32:38 +03:00
|
|
|
return TRUE;
|
2011-07-01 00:17:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-12-09 16:35:03 +03:00
|
|
|
* Fill a rectangle with the given brush.
|
|
|
|
* msdn{dd162719}
|
|
|
|
*
|
2011-07-01 00:17:55 +04:00
|
|
|
* @param hdc device context
|
|
|
|
* @param rect rectangle
|
|
|
|
* @param hbr brush
|
2022-12-09 16:35:03 +03:00
|
|
|
*
|
2015-06-26 15:32:38 +03:00
|
|
|
* @return nonzero if successful, 0 otherwise
|
2011-07-01 00:17:55 +04:00
|
|
|
*/
|
|
|
|
|
2016-04-05 18:07:45 +03:00
|
|
|
BOOL gdi_FillRect(HGDI_DC hdc, const HGDI_RECT rect, HGDI_BRUSH hbr)
|
2011-07-01 00:17:55 +04:00
|
|
|
{
|
2018-10-19 18:02:33 +03:00
|
|
|
INT32 x, y;
|
2016-08-11 10:36:06 +03:00
|
|
|
UINT32 color, dstColor;
|
|
|
|
BOOL monochrome = FALSE;
|
2018-10-19 18:02:33 +03:00
|
|
|
INT32 nXDest, nYDest;
|
|
|
|
INT32 nWidth, nHeight;
|
2016-10-11 13:14:52 +03:00
|
|
|
const BYTE* srcp;
|
2016-11-24 12:01:45 +03:00
|
|
|
DWORD formatSize;
|
2016-04-05 18:07:45 +03:00
|
|
|
gdi_RectToCRgn(rect, &nXDest, &nYDest, &nWidth, &nHeight);
|
|
|
|
|
2016-08-11 10:36:06 +03:00
|
|
|
if (!hdc || !hbr)
|
|
|
|
return FALSE;
|
|
|
|
|
2016-04-05 18:07:45 +03:00
|
|
|
if (!gdi_ClipCoords(hdc, &nXDest, &nYDest, &nWidth, &nHeight, NULL, NULL))
|
|
|
|
return TRUE;
|
2011-07-01 00:17:55 +04:00
|
|
|
|
2016-10-10 12:09:06 +03:00
|
|
|
switch (hbr->style)
|
2016-08-11 10:36:06 +03:00
|
|
|
{
|
2016-10-10 12:09:06 +03:00
|
|
|
case GDI_BS_SOLID:
|
|
|
|
color = hbr->color;
|
2016-04-05 18:07:45 +03:00
|
|
|
|
2016-10-11 13:14:52 +03:00
|
|
|
for (x = 0; x < nWidth; x++)
|
2016-10-10 12:09:06 +03:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
BYTE* dstp = gdi_get_bitmap_pointer(hdc, nXDest + x, nYDest);
|
2016-10-11 13:14:52 +03:00
|
|
|
|
|
|
|
if (dstp)
|
2022-04-28 06:43:31 +03:00
|
|
|
FreeRDPWriteColor(dstp, hdc->format, color);
|
2016-10-11 13:14:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
srcp = gdi_get_bitmap_pointer(hdc, nXDest, nYDest);
|
2022-04-28 06:43:31 +03:00
|
|
|
formatSize = FreeRDPGetBytesPerPixel(hdc->format);
|
2016-10-11 13:14:52 +03:00
|
|
|
|
|
|
|
for (y = 1; y < nHeight; y++)
|
|
|
|
{
|
|
|
|
BYTE* dstp = gdi_get_bitmap_pointer(hdc, nXDest, nYDest + y);
|
2023-08-22 10:41:28 +03:00
|
|
|
memcpy(dstp, srcp, 1ull * nWidth * formatSize);
|
2016-10-10 12:09:06 +03:00
|
|
|
}
|
2016-04-05 18:07:45 +03:00
|
|
|
|
2016-10-10 12:09:06 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GDI_BS_HATCHED:
|
|
|
|
case GDI_BS_PATTERN:
|
|
|
|
monochrome = (hbr->pattern->format == PIXEL_FORMAT_MONO);
|
2022-04-28 06:43:31 +03:00
|
|
|
formatSize = FreeRDPGetBytesPerPixel(hbr->pattern->format);
|
2016-10-10 12:09:06 +03:00
|
|
|
|
|
|
|
for (y = 0; y < nHeight; y++)
|
2016-08-11 10:36:06 +03:00
|
|
|
{
|
2016-10-10 12:09:06 +03:00
|
|
|
for (x = 0; x < nWidth; x++)
|
2016-08-11 10:36:06 +03:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
const UINT32 yOffset =
|
|
|
|
((nYDest + y) * hbr->pattern->width % hbr->pattern->height) * formatSize;
|
2016-11-24 12:01:45 +03:00
|
|
|
const UINT32 xOffset = ((nXDest + x) % hbr->pattern->width) * formatSize;
|
2016-10-10 12:09:06 +03:00
|
|
|
const BYTE* patp = &hbr->pattern->data[yOffset + xOffset];
|
2019-11-06 17:24:51 +03:00
|
|
|
BYTE* dstp = gdi_get_bitmap_pointer(hdc, nXDest + x, nYDest + y);
|
2016-10-10 12:09:06 +03:00
|
|
|
|
|
|
|
if (!patp)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (monochrome)
|
|
|
|
{
|
|
|
|
if (*patp == 0)
|
|
|
|
dstColor = hdc->bkColor;
|
|
|
|
else
|
|
|
|
dstColor = hdc->textColor;
|
|
|
|
}
|
2016-08-11 10:36:06 +03:00
|
|
|
else
|
2016-10-10 12:09:06 +03:00
|
|
|
{
|
2022-04-28 06:43:31 +03:00
|
|
|
dstColor = FreeRDPReadColor(patp, hbr->pattern->format);
|
2019-11-06 17:24:51 +03:00
|
|
|
dstColor =
|
|
|
|
FreeRDPConvertColor(dstColor, hbr->pattern->format, hdc->format, NULL);
|
2016-10-10 12:09:06 +03:00
|
|
|
}
|
2016-08-11 10:36:06 +03:00
|
|
|
|
2016-10-10 12:09:06 +03:00
|
|
|
if (dstp)
|
2022-04-28 06:43:31 +03:00
|
|
|
FreeRDPWriteColor(dstp, hdc->format, dstColor);
|
2016-10-10 12:09:06 +03:00
|
|
|
}
|
2016-08-11 10:36:06 +03:00
|
|
|
}
|
2016-10-10 12:09:06 +03:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2016-08-11 10:36:06 +03:00
|
|
|
}
|
2016-10-10 12:09:06 +03:00
|
|
|
|
2016-04-05 18:07:45 +03:00
|
|
|
if (!gdi_InvalidateRegion(hdc, nXDest, nYDest, nWidth, nHeight))
|
2015-06-26 15:32:38 +03:00
|
|
|
return FALSE;
|
|
|
|
|
2016-04-05 18:07:45 +03:00
|
|
|
return TRUE;
|
2011-07-01 00:17:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-06-26 15:32:38 +03:00
|
|
|
* Draw a polygon
|
2022-12-09 16:35:03 +03:00
|
|
|
* msdn{dd162814}
|
2011-07-01 00:17:55 +04:00
|
|
|
* @param hdc device context
|
|
|
|
* @param lpPoints array of points
|
|
|
|
* @param nCount number of points
|
2015-06-26 15:32:38 +03:00
|
|
|
* @return nonzero if successful, 0 otherwise
|
2011-07-01 00:17:55 +04:00
|
|
|
*/
|
2016-07-19 17:15:38 +03:00
|
|
|
BOOL gdi_Polygon(HGDI_DC hdc, GDI_POINT* lpPoints, int nCount)
|
2011-07-01 00:17:55 +04:00
|
|
|
{
|
2016-04-05 18:07:45 +03:00
|
|
|
WLog_ERR(TAG, "Not implemented!");
|
|
|
|
return FALSE;
|
2011-07-01 00:17:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draw a series of closed polygons
|
2022-12-09 16:35:03 +03:00
|
|
|
* msdn{dd162818}
|
2011-07-01 00:17:55 +04:00
|
|
|
* @param hdc device context
|
|
|
|
* @param lpPoints array of series of points
|
|
|
|
* @param lpPolyCounts array of number of points in each series
|
|
|
|
* @param nCount count of number of points in lpPolyCounts
|
2015-06-26 15:32:38 +03:00
|
|
|
* @return nonzero if successful, 0 otherwise
|
2011-07-01 00:17:55 +04:00
|
|
|
*/
|
2019-11-06 17:24:51 +03:00
|
|
|
BOOL gdi_PolyPolygon(HGDI_DC hdc, GDI_POINT* lpPoints, int* lpPolyCounts, int nCount)
|
2011-07-01 00:17:55 +04:00
|
|
|
{
|
2016-04-05 18:07:45 +03:00
|
|
|
WLog_ERR(TAG, "Not implemented!");
|
|
|
|
return FALSE;
|
2011-07-01 00:17:55 +04:00
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
BOOL gdi_Rectangle(HGDI_DC hdc, INT32 nXDst, INT32 nYDst, INT32 nWidth, INT32 nHeight)
|
2011-07-01 00:17:55 +04:00
|
|
|
{
|
2018-10-19 18:02:33 +03:00
|
|
|
INT32 x, y;
|
2016-07-19 17:15:38 +03:00
|
|
|
UINT32 color;
|
|
|
|
|
|
|
|
if (!gdi_ClipCoords(hdc, &nXDst, &nYDst, &nWidth, &nHeight, NULL, NULL))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
color = hdc->textColor;
|
|
|
|
|
|
|
|
for (y = 0; y < nHeight; y++)
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
BYTE* dstLeft = gdi_get_bitmap_pointer(hdc, nXDst, nYDst + y);
|
|
|
|
BYTE* dstRight = gdi_get_bitmap_pointer(hdc, nXDst + nWidth - 1, nYDst + y);
|
2016-07-19 17:15:38 +03:00
|
|
|
|
|
|
|
if (dstLeft)
|
2022-04-28 06:43:31 +03:00
|
|
|
FreeRDPWriteColor(dstLeft, hdc->format, color);
|
2016-07-19 17:15:38 +03:00
|
|
|
|
|
|
|
if (dstRight)
|
2022-04-28 06:43:31 +03:00
|
|
|
FreeRDPWriteColor(dstRight, hdc->format, color);
|
2016-07-19 17:15:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for (x = 0; x < nWidth; x++)
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
BYTE* dstTop = gdi_get_bitmap_pointer(hdc, nXDst + x, nYDst);
|
|
|
|
BYTE* dstBottom = gdi_get_bitmap_pointer(hdc, nXDst + x, nYDst + nHeight - 1);
|
2016-07-19 17:15:38 +03:00
|
|
|
|
|
|
|
if (dstTop)
|
2022-04-28 06:43:31 +03:00
|
|
|
FreeRDPWriteColor(dstTop, hdc->format, color);
|
2016-07-19 17:15:38 +03:00
|
|
|
|
|
|
|
if (dstBottom)
|
2022-04-28 06:43:31 +03:00
|
|
|
FreeRDPWriteColor(dstBottom, hdc->format, color);
|
2016-07-19 17:15:38 +03:00
|
|
|
}
|
|
|
|
|
2016-04-05 18:07:45 +03:00
|
|
|
return FALSE;
|
2011-07-01 00:17:55 +04:00
|
|
|
}
|