FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
line.c
1
22#include <freerdp/config.h>
23
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27
28#include <winpr/assert.h>
29
30#include <freerdp/freerdp.h>
31#include <freerdp/gdi/gdi.h>
32#include <freerdp/gdi/pen.h>
33#include <freerdp/gdi/bitmap.h>
34#include <freerdp/gdi/region.h>
35
36#include "drawing.h"
37#include "clipping.h"
38#include "line.h"
39
40static BOOL gdi_rop_color(INT32 rop, BYTE* pixelPtr, UINT32 pen, UINT32 format)
41{
42 WINPR_ASSERT(pixelPtr);
43 const UINT32 srcPixel = FreeRDPReadColor(pixelPtr, format);
44 UINT32 dstPixel = 0;
45
46 switch (rop)
47 {
48 case GDI_R2_BLACK: /* LineTo_BLACK */
49 dstPixel = FreeRDPGetColor(format, 0, 0, 0, 0xFF);
50 break;
51
52 case GDI_R2_NOTMERGEPEN: /* LineTo_NOTMERGEPEN */
53 dstPixel = ~(srcPixel | pen);
54 break;
55
56 case GDI_R2_MASKNOTPEN: /* LineTo_MASKNOTPEN */
57 dstPixel = srcPixel & ~pen;
58 break;
59
60 case GDI_R2_NOTCOPYPEN: /* LineTo_NOTCOPYPEN */
61 dstPixel = ~pen;
62 break;
63
64 case GDI_R2_MASKPENNOT: /* LineTo_MASKPENNOT */
65 dstPixel = pen & ~srcPixel;
66 break;
67
68 case GDI_R2_NOT: /* LineTo_NOT */
69 dstPixel = ~srcPixel;
70 break;
71
72 case GDI_R2_XORPEN: /* LineTo_XORPEN */
73 dstPixel = srcPixel ^ pen;
74 break;
75
76 case GDI_R2_NOTMASKPEN: /* LineTo_NOTMASKPEN */
77 dstPixel = ~(srcPixel & pen);
78 break;
79
80 case GDI_R2_MASKPEN: /* LineTo_MASKPEN */
81 dstPixel = srcPixel & pen;
82 break;
83
84 case GDI_R2_NOTXORPEN: /* LineTo_NOTXORPEN */
85 dstPixel = ~(srcPixel ^ pen);
86 break;
87
88 case GDI_R2_NOP: /* LineTo_NOP */
89 dstPixel = srcPixel;
90 break;
91
92 case GDI_R2_MERGENOTPEN: /* LineTo_MERGENOTPEN */
93 dstPixel = srcPixel | ~pen;
94 break;
95
96 case GDI_R2_COPYPEN: /* LineTo_COPYPEN */
97 dstPixel = pen;
98 break;
99
100 case GDI_R2_MERGEPENNOT: /* LineTo_MERGEPENNOT */
101 dstPixel = srcPixel | ~pen;
102 break;
103
104 case GDI_R2_MERGEPEN: /* LineTo_MERGEPEN */
105 dstPixel = srcPixel | pen;
106 break;
107
108 case GDI_R2_WHITE: /* LineTo_WHITE */
109 dstPixel = FreeRDPGetColor(format, 0xFF, 0xFF, 0xFF, 0xFF);
110 break;
111
112 default:
113 return FALSE;
114 }
115
116 return FreeRDPWriteColor(pixelPtr, format, dstPixel);
117}
118
119BOOL gdi_LineTo(HGDI_DC hdc, INT32 nXEnd, INT32 nYEnd)
120{
121 INT32 e2 = 0;
122 UINT32 pen = 0;
123
124 WINPR_ASSERT(hdc);
125 const INT32 rop2 = gdi_GetROP2(hdc);
126
127 const INT32 x1 = hdc->pen->posX;
128 const INT32 y1 = hdc->pen->posY;
129 const INT32 x2 = WINPR_ASSERTING_INT_CAST(int32_t, nXEnd);
130 const INT32 y2 = WINPR_ASSERTING_INT_CAST(int32_t, nYEnd);
131 const INT32 dx = (x1 > x2) ? x1 - x2 : x2 - x1;
132 const INT32 dy = (y1 > y2) ? y1 - y2 : y2 - y1;
133 const INT32 sx = (x1 < x2) ? 1 : -1;
134 const INT32 sy = (y1 < y2) ? 1 : -1;
135 INT32 e = dx - dy;
136 INT32 x = x1;
137 INT32 y = y1;
138
139 WINPR_ASSERT(hdc->clip);
140 INT32 bx1 = 0;
141 INT32 by1 = 0;
142 INT32 bx2 = 0;
143 INT32 by2 = 0;
144 if (hdc->clip->null)
145 {
146 bx1 = (x1 < x2) ? x1 : x2;
147 by1 = (y1 < y2) ? y1 : y2;
148 bx2 = (x1 > x2) ? x1 : x2;
149 by2 = (y1 > y2) ? y1 : y2;
150 }
151 else
152 {
153 bx1 = hdc->clip->x;
154 by1 = hdc->clip->y;
155 bx2 = bx1 + hdc->clip->w - 1;
156 by2 = by1 + hdc->clip->h - 1;
157 }
158
159 HGDI_BITMAP bmp = (HGDI_BITMAP)hdc->selectedObject;
160 WINPR_ASSERT(bmp);
161
162 bx1 = MAX(bx1, 0);
163 by1 = MAX(by1, 0);
164 bx2 = MIN(bx2, bmp->width - 1);
165 by2 = MIN(by2, bmp->height - 1);
166
167 if (!gdi_InvalidateRegion(hdc, bx1, by1, bx2 - bx1 + 1, by2 - by1 + 1))
168 return FALSE;
169
170 pen = gdi_GetPenColor(hdc->pen, bmp->format);
171
172 while (1)
173 {
174 if (!(x == x2 && y == y2))
175 {
176 if ((x >= bx1 && x <= bx2) && (y >= by1 && y <= by2))
177 {
178 BYTE* pixel = gdi_GetPointer(bmp, WINPR_ASSERTING_INT_CAST(uint32_t, x),
179 WINPR_ASSERTING_INT_CAST(uint32_t, y));
180 WINPR_ASSERT(pixel);
181 gdi_rop_color(rop2, pixel, pen, bmp->format);
182 }
183 }
184 else
185 {
186 break;
187 }
188
189 e2 = 2 * e;
190
191 if (e2 > -dy)
192 {
193 e -= dy;
194 x += sx;
195 }
196
197 if (e2 < dx)
198 {
199 e += dx;
200 y += sy;
201 }
202 }
203
204 return TRUE;
205}
206
214BOOL gdi_PolylineTo(HGDI_DC hdc, GDI_POINT* lppt, DWORD cCount)
215{
216 WINPR_ASSERT(hdc);
217 WINPR_ASSERT(lppt || (cCount == 0));
218
219 for (DWORD i = 0; i < cCount; i++)
220 {
221 if (!gdi_LineTo(hdc, lppt[i].x, lppt[i].y))
222 return FALSE;
223
224 if (!gdi_MoveToEx(hdc, lppt[i].x, lppt[i].y, NULL))
225 return FALSE;
226 }
227
228 return TRUE;
229}
230
238BOOL gdi_Polyline(HGDI_DC hdc, GDI_POINT* lppt, UINT32 cPoints)
239{
240 WINPR_ASSERT(hdc);
241 WINPR_ASSERT(lppt || (cPoints == 0));
242
243 if (cPoints > 0)
244 {
245 GDI_POINT pt = { 0 };
246
247 if (!gdi_MoveToEx(hdc, lppt[0].x, lppt[0].y, &pt))
248 return FALSE;
249
250 for (UINT32 i = 0; i < cPoints; i++)
251 {
252 if (!gdi_LineTo(hdc, lppt[i].x, lppt[i].y))
253 return FALSE;
254
255 if (!gdi_MoveToEx(hdc, lppt[i].x, lppt[i].y, NULL))
256 return FALSE;
257 }
258
259 if (!gdi_MoveToEx(hdc, pt.x, pt.y, NULL))
260 return FALSE;
261 }
262
263 return TRUE;
264}
265
274BOOL gdi_PolyPolyline(HGDI_DC hdc, GDI_POINT* lppt, const UINT32* lpdwPolyPoints, DWORD cCount)
275{
276 DWORD j = 0;
277
278 WINPR_ASSERT(hdc);
279 WINPR_ASSERT(lppt || (cCount == 0));
280 WINPR_ASSERT(lpdwPolyPoints || (cCount == 0));
281
282 for (DWORD i = 0; i < cCount; i++)
283 {
284 const UINT32 cPoints = lpdwPolyPoints[i];
285
286 if (!gdi_Polyline(hdc, &lppt[j], cPoints))
287 return FALSE;
288
289 j += cPoints;
290 }
291
292 return TRUE;
293}
294
303BOOL gdi_MoveToEx(HGDI_DC hdc, INT32 X, INT32 Y, HGDI_POINT lpPoint)
304{
305 WINPR_ASSERT(hdc);
306
307 if (lpPoint != NULL)
308 {
309 lpPoint->x = hdc->pen->posX;
310 lpPoint->y = hdc->pen->posY;
311 }
312
313 hdc->pen->posX = X;
314 hdc->pen->posY = Y;
315 return TRUE;
316}