FreeRDP
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 
40 static BOOL gdi_rop_color(UINT32 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 
119 BOOL gdi_LineTo(HGDI_DC hdc, UINT32 nXEnd, UINT32 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 = nXEnd;
130  const INT32 y2 = 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, x, y);
179  WINPR_ASSERT(pixel);
180  gdi_rop_color(rop2, pixel, pen, bmp->format);
181  }
182  }
183  else
184  {
185  break;
186  }
187 
188  e2 = 2 * e;
189 
190  if (e2 > -dy)
191  {
192  e -= dy;
193  x += sx;
194  }
195 
196  if (e2 < dx)
197  {
198  e += dx;
199  y += sy;
200  }
201  }
202 
203  return TRUE;
204 }
205 
213 BOOL gdi_PolylineTo(HGDI_DC hdc, GDI_POINT* lppt, DWORD cCount)
214 {
215  WINPR_ASSERT(hdc);
216  WINPR_ASSERT(lppt || (cCount == 0));
217 
218  for (DWORD i = 0; i < cCount; i++)
219  {
220  if (!gdi_LineTo(hdc, lppt[i].x, lppt[i].y))
221  return FALSE;
222 
223  if (!gdi_MoveToEx(hdc, lppt[i].x, lppt[i].y, NULL))
224  return FALSE;
225  }
226 
227  return TRUE;
228 }
229 
237 BOOL gdi_Polyline(HGDI_DC hdc, GDI_POINT* lppt, UINT32 cPoints)
238 {
239  WINPR_ASSERT(hdc);
240  WINPR_ASSERT(lppt || (cPoints == 0));
241 
242  if (cPoints > 0)
243  {
244  GDI_POINT pt = { 0 };
245 
246  if (!gdi_MoveToEx(hdc, lppt[0].x, lppt[0].y, &pt))
247  return FALSE;
248 
249  for (UINT32 i = 0; i < cPoints; i++)
250  {
251  if (!gdi_LineTo(hdc, lppt[i].x, lppt[i].y))
252  return FALSE;
253 
254  if (!gdi_MoveToEx(hdc, lppt[i].x, lppt[i].y, NULL))
255  return FALSE;
256  }
257 
258  if (!gdi_MoveToEx(hdc, pt.x, pt.y, NULL))
259  return FALSE;
260  }
261 
262  return TRUE;
263 }
264 
273 BOOL gdi_PolyPolyline(HGDI_DC hdc, GDI_POINT* lppt, const UINT32* lpdwPolyPoints, DWORD cCount)
274 {
275  DWORD j = 0;
276 
277  WINPR_ASSERT(hdc);
278  WINPR_ASSERT(lppt || (cCount == 0));
279  WINPR_ASSERT(lpdwPolyPoints || (cCount == 0));
280 
281  for (DWORD i = 0; i < cCount; i++)
282  {
283  const UINT32 cPoints = lpdwPolyPoints[i];
284 
285  if (!gdi_Polyline(hdc, &lppt[j], cPoints))
286  return FALSE;
287 
288  j += cPoints;
289  }
290 
291  return TRUE;
292 }
293 
302 BOOL gdi_MoveToEx(HGDI_DC hdc, UINT32 X, UINT32 Y, HGDI_POINT lpPoint)
303 {
304  WINPR_ASSERT(hdc);
305 
306  if (lpPoint != NULL)
307  {
308  lpPoint->x = hdc->pen->posX;
309  lpPoint->y = hdc->pen->posY;
310  }
311 
312  hdc->pen->posX = X;
313  hdc->pen->posY = Y;
314  return TRUE;
315 }