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