1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * GDI Shape Functions
4  *
5  * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  * Copyright 2016 Armin Novak <armin.novak@thincast.com>
7  * Copyright 2016 Thincast Technologies GmbH
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *     http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 
30 #include <freerdp/freerdp.h>
31 #include <freerdp/gdi/gdi.h>
32 
33 #include <freerdp/gdi/bitmap.h>
34 #include <freerdp/gdi/region.h>
35 #include <freerdp/gdi/shape.h>
36 
37 #include <freerdp/log.h>
38 
39 #include "clipping.h"
40 #include "../gdi/gdi.h"
41 
42 #define TAG FREERDP_TAG("gdi.shape")
43 
Ellipse_Bresenham(HGDI_DC hdc,int x1,int y1,int x2,int y2)44 static void Ellipse_Bresenham(HGDI_DC hdc, int x1, int y1, int x2, int y2)
45 {
46 	INT32 e, e2;
47 	INT32 dx, dy;
48 	INT32 a, b, c;
49 	a = (x1 < x2) ? x2 - x1 : x1 - x2;
50 	b = (y1 < y2) ? y2 - y1 : y1 - y2;
51 	c = b & 1;
52 	dx = 4 * (1 - a) * b * b;
53 	dy = 4 * (c + 1) * a * a;
54 	e = dx + dy + c * a * a;
55 
56 	if (x1 > x2)
57 	{
58 		x1 = x2;
59 		x2 += a;
60 	}
61 
62 	if (y1 > y2)
63 		y1 = y2;
64 
65 	y1 += (b + 1) / 2;
66 	y2 = y1 - c;
67 	a *= 8 * a;
68 	c = 8 * b * b;
69 
70 	do
71 	{
72 		gdi_SetPixel(hdc, x2, y1, 0);
73 		gdi_SetPixel(hdc, x1, y1, 0);
74 		gdi_SetPixel(hdc, x1, y2, 0);
75 		gdi_SetPixel(hdc, x2, y2, 0);
76 		e2 = 2 * e;
77 
78 		if (e2 >= dx)
79 		{
80 			x1++;
81 			x2--;
82 			e += dx += c;
83 		}
84 
85 		if (e2 <= dy)
86 		{
87 			y1++;
88 			y2--;
89 			e += dy += a;
90 		}
91 	} while (x1 <= x2);
92 
93 	while (y1 - y2 < b)
94 	{
95 		gdi_SetPixel(hdc, x1 - 1, ++y1, 0);
96 		gdi_SetPixel(hdc, x1 - 1, --y2, 0);
97 	}
98 }
99 
100 /**
101  * Draw an ellipse
102  * @msdn{dd162510}
103  * @param hdc device context
104  * @param nLeftRect x1
105  * @param nTopRect y1
106  * @param nRightRect x2
107  * @param nBottomRect y2
108  * @return nonzero if successful, 0 otherwise
109  */
gdi_Ellipse(HGDI_DC hdc,int nLeftRect,int nTopRect,int nRightRect,int nBottomRect)110 BOOL gdi_Ellipse(HGDI_DC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect)
111 {
112 	Ellipse_Bresenham(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
113 	return TRUE;
114 }
115 
116 /**
117  * Fill a rectangle with the given brush.\n
118  * @msdn{dd162719}
119  * @param hdc device context
120  * @param rect rectangle
121  * @param hbr brush
122  * @return nonzero if successful, 0 otherwise
123  */
124 
gdi_FillRect(HGDI_DC hdc,const HGDI_RECT rect,HGDI_BRUSH hbr)125 BOOL gdi_FillRect(HGDI_DC hdc, const HGDI_RECT rect, HGDI_BRUSH hbr)
126 {
127 	INT32 x, y;
128 	UINT32 color, dstColor;
129 	BOOL monochrome = FALSE;
130 	INT32 nXDest, nYDest;
131 	INT32 nWidth, nHeight;
132 	const BYTE* srcp;
133 	DWORD formatSize;
134 	gdi_RectToCRgn(rect, &nXDest, &nYDest, &nWidth, &nHeight);
135 
136 	if (!hdc || !hbr)
137 		return FALSE;
138 
139 	if (!gdi_ClipCoords(hdc, &nXDest, &nYDest, &nWidth, &nHeight, NULL, NULL))
140 		return TRUE;
141 
142 	switch (hbr->style)
143 	{
144 		case GDI_BS_SOLID:
145 			color = hbr->color;
146 
147 			for (x = 0; x < nWidth; x++)
148 			{
149 				BYTE* dstp = gdi_get_bitmap_pointer(hdc, nXDest + x, nYDest);
150 
151 				if (dstp)
152 					WriteColor(dstp, hdc->format, color);
153 			}
154 
155 			srcp = gdi_get_bitmap_pointer(hdc, nXDest, nYDest);
156 			formatSize = GetBytesPerPixel(hdc->format);
157 
158 			for (y = 1; y < nHeight; y++)
159 			{
160 				BYTE* dstp = gdi_get_bitmap_pointer(hdc, nXDest, nYDest + y);
161 				memcpy(dstp, srcp, nWidth * formatSize * 1ULL);
162 			}
163 
164 			break;
165 
166 		case GDI_BS_HATCHED:
167 		case GDI_BS_PATTERN:
168 			monochrome = (hbr->pattern->format == PIXEL_FORMAT_MONO);
169 			formatSize = GetBytesPerPixel(hbr->pattern->format);
170 
171 			for (y = 0; y < nHeight; y++)
172 			{
173 				for (x = 0; x < nWidth; x++)
174 				{
175 					const UINT32 yOffset =
176 					    ((nYDest + y) * hbr->pattern->width % hbr->pattern->height) * formatSize;
177 					const UINT32 xOffset = ((nXDest + x) % hbr->pattern->width) * formatSize;
178 					const BYTE* patp = &hbr->pattern->data[yOffset + xOffset];
179 					BYTE* dstp = gdi_get_bitmap_pointer(hdc, nXDest + x, nYDest + y);
180 
181 					if (!patp)
182 						return FALSE;
183 
184 					if (monochrome)
185 					{
186 						if (*patp == 0)
187 							dstColor = hdc->bkColor;
188 						else
189 							dstColor = hdc->textColor;
190 					}
191 					else
192 					{
193 						dstColor = ReadColor(patp, hbr->pattern->format);
194 						dstColor =
195 						    FreeRDPConvertColor(dstColor, hbr->pattern->format, hdc->format, NULL);
196 					}
197 
198 					if (dstp)
199 						WriteColor(dstp, hdc->format, dstColor);
200 				}
201 			}
202 
203 			break;
204 
205 		default:
206 			break;
207 	}
208 
209 	if (!gdi_InvalidateRegion(hdc, nXDest, nYDest, nWidth, nHeight))
210 		return FALSE;
211 
212 	return TRUE;
213 }
214 
215 /**
216  * Draw a polygon
217  * @msdn{dd162814}
218  * @param hdc device context
219  * @param lpPoints array of points
220  * @param nCount number of points
221  * @return nonzero if successful, 0 otherwise
222  */
gdi_Polygon(HGDI_DC hdc,GDI_POINT * lpPoints,int nCount)223 BOOL gdi_Polygon(HGDI_DC hdc, GDI_POINT* lpPoints, int nCount)
224 {
225 	WLog_ERR(TAG, "Not implemented!");
226 	return FALSE;
227 }
228 
229 /**
230  * Draw a series of closed polygons
231  * @msdn{dd162818}
232  * @param hdc device context
233  * @param lpPoints array of series of points
234  * @param lpPolyCounts array of number of points in each series
235  * @param nCount count of number of points in lpPolyCounts
236  * @return nonzero if successful, 0 otherwise
237  */
gdi_PolyPolygon(HGDI_DC hdc,GDI_POINT * lpPoints,int * lpPolyCounts,int nCount)238 BOOL gdi_PolyPolygon(HGDI_DC hdc, GDI_POINT* lpPoints, int* lpPolyCounts, int nCount)
239 {
240 	WLog_ERR(TAG, "Not implemented!");
241 	return FALSE;
242 }
243 
gdi_Rectangle(HGDI_DC hdc,INT32 nXDst,INT32 nYDst,INT32 nWidth,INT32 nHeight)244 BOOL gdi_Rectangle(HGDI_DC hdc, INT32 nXDst, INT32 nYDst, INT32 nWidth, INT32 nHeight)
245 {
246 	INT32 x, y;
247 	UINT32 color;
248 
249 	if (!gdi_ClipCoords(hdc, &nXDst, &nYDst, &nWidth, &nHeight, NULL, NULL))
250 		return TRUE;
251 
252 	color = hdc->textColor;
253 
254 	for (y = 0; y < nHeight; y++)
255 	{
256 		BYTE* dstLeft = gdi_get_bitmap_pointer(hdc, nXDst, nYDst + y);
257 		BYTE* dstRight = gdi_get_bitmap_pointer(hdc, nXDst + nWidth - 1, nYDst + y);
258 
259 		if (dstLeft)
260 			WriteColor(dstLeft, hdc->format, color);
261 
262 		if (dstRight)
263 			WriteColor(dstRight, hdc->format, color);
264 	}
265 
266 	for (x = 0; x < nWidth; x++)
267 	{
268 		BYTE* dstTop = gdi_get_bitmap_pointer(hdc, nXDst + x, nYDst);
269 		BYTE* dstBottom = gdi_get_bitmap_pointer(hdc, nXDst + x, nYDst + nHeight - 1);
270 
271 		if (dstTop)
272 			WriteColor(dstTop, hdc->format, color);
273 
274 		if (dstBottom)
275 			WriteColor(dstBottom, hdc->format, color);
276 	}
277 
278 	return FALSE;
279 }
280