Coverage Report

Created: 2026-02-26 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/gdi/shape.c
Line
Count
Source
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
#include <freerdp/config.h>
23
24
#include <stdio.h>
25
#include <string.h>
26
#include <stdlib.h>
27
28
#include <freerdp/freerdp.h>
29
#include <freerdp/gdi/gdi.h>
30
31
#include <freerdp/gdi/bitmap.h>
32
#include <freerdp/gdi/region.h>
33
#include <freerdp/gdi/shape.h>
34
35
#include <freerdp/log.h>
36
37
#include "clipping.h"
38
#include "../gdi/gdi.h"
39
40
#define TAG FREERDP_TAG("gdi.shape")
41
42
WINPR_ATTR_NODISCARD
43
static BOOL Ellipse_Bresenham(HGDI_DC hdc, int x1, int y1, int x2, int y2)
44
0
{
45
0
  INT32 a = (x1 < x2) ? x2 - x1 : x1 - x2;
46
0
  const INT32 b = (y1 < y2) ? y2 - y1 : y1 - y2;
47
0
  INT32 c = b & 1;
48
0
  INT32 dx = 4 * (1 - a) * b * b;
49
0
  INT32 dy = 4 * (c + 1) * a * a;
50
0
  INT32 e = dx + dy + c * a * a;
51
52
0
  if (x1 > x2)
53
0
  {
54
0
    x1 = x2;
55
0
    x2 += a;
56
0
  }
57
58
0
  if (y1 > y2)
59
0
    y1 = y2;
60
61
0
  y1 += (b + 1) / 2;
62
0
  y2 = y1 - c;
63
0
  a *= 8 * a;
64
0
  c = 8 * b * b;
65
66
0
  do
67
0
  {
68
0
    gdi_SetPixel(hdc, WINPR_ASSERTING_INT_CAST(UINT32, x2),
69
0
                 WINPR_ASSERTING_INT_CAST(UINT32, y1), 0);
70
0
    gdi_SetPixel(hdc, WINPR_ASSERTING_INT_CAST(UINT32, x1),
71
0
                 WINPR_ASSERTING_INT_CAST(UINT32, y1), 0);
72
0
    gdi_SetPixel(hdc, WINPR_ASSERTING_INT_CAST(UINT32, x1),
73
0
                 WINPR_ASSERTING_INT_CAST(UINT32, y2), 0);
74
0
    gdi_SetPixel(hdc, WINPR_ASSERTING_INT_CAST(UINT32, x2),
75
0
                 WINPR_ASSERTING_INT_CAST(UINT32, y2), 0);
76
77
0
    const INT32 e2 = 2 * e;
78
79
0
    if (e2 >= dx)
80
0
    {
81
0
      x1++;
82
0
      x2--;
83
0
      e += dx += c;
84
0
    }
85
86
0
    if (e2 <= dy)
87
0
    {
88
0
      y1++;
89
0
      y2--;
90
0
      e += dy += a;
91
0
    }
92
0
  } while (x1 <= x2);
93
94
0
  while (y1 - y2 < b)
95
0
  {
96
0
    y1++;
97
0
    y2--;
98
99
0
    gdi_SetPixel(hdc, WINPR_ASSERTING_INT_CAST(uint32_t, x1 - 1),
100
0
                 WINPR_ASSERTING_INT_CAST(uint32_t, y1), 0);
101
0
    gdi_SetPixel(hdc, WINPR_ASSERTING_INT_CAST(uint32_t, x1 - 1),
102
0
                 WINPR_ASSERTING_INT_CAST(uint32_t, y2), 0);
103
0
  }
104
0
  return TRUE;
105
0
}
106
107
/**
108
 * Draw an ellipse
109
 * msdn{dd162510}
110
 *
111
 * @param hdc device context
112
 * @param nLeftRect x1
113
 * @param nTopRect y1
114
 * @param nRightRect x2
115
 * @param nBottomRect y2
116
 *
117
 * @return nonzero if successful, 0 otherwise
118
 */
119
BOOL gdi_Ellipse(HGDI_DC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect)
120
0
{
121
0
  return Ellipse_Bresenham(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
122
0
}
123
124
/**
125
 * Fill a rectangle with the given brush.
126
 * msdn{dd162719}
127
 *
128
 * @param hdc device context
129
 * @param rect rectangle
130
 * @param hbr brush
131
 *
132
 * @return nonzero if successful, 0 otherwise
133
 */
134
135
BOOL gdi_FillRect(HGDI_DC hdc, const GDI_RECT* rect, HGDI_BRUSH hbr)
136
0
{
137
0
  INT32 nXDest = 0;
138
0
  INT32 nYDest = 0;
139
0
  INT32 nWidth = 0;
140
0
  INT32 nHeight = 0;
141
142
0
  if (!gdi_RectToCRgn(rect, &nXDest, &nYDest, &nWidth, &nHeight))
143
0
    return FALSE;
144
145
0
  if (!hdc || !hbr)
146
0
    return FALSE;
147
148
0
  if (!gdi_ClipCoords(hdc, &nXDest, &nYDest, &nWidth, &nHeight, NULL, NULL))
149
0
    return TRUE;
150
151
0
  switch (hbr->style)
152
0
  {
153
0
    case GDI_BS_SOLID:
154
0
    {
155
0
      const UINT32 color = hbr->color;
156
157
0
      for (INT32 x = 0; x < nWidth; x++)
158
0
      {
159
0
        BYTE* dstp = gdi_get_bitmap_pointer(hdc, nXDest + x, nYDest);
160
161
0
        if (dstp)
162
0
          FreeRDPWriteColor(dstp, hdc->format, color);
163
0
      }
164
165
0
      const BYTE* srcp = gdi_get_bitmap_pointer(hdc, nXDest, nYDest);
166
0
      const UINT32 formatSize = FreeRDPGetBytesPerPixel(hdc->format);
167
0
      if (formatSize == 0)
168
0
        return FALSE;
169
170
0
      for (INT32 y = 1; y < nHeight; y++)
171
0
      {
172
0
        BYTE* dstp = gdi_get_bitmap_pointer(hdc, nXDest, nYDest + y);
173
0
        if (!dstp)
174
0
          return FALSE;
175
0
        memcpy(dstp, srcp, 1ull * WINPR_ASSERTING_INT_CAST(size_t, nWidth) * formatSize);
176
0
      }
177
0
    }
178
0
    break;
179
180
0
    case GDI_BS_HATCHED:
181
0
    case GDI_BS_PATTERN:
182
0
    {
183
0
      const BOOL monochrome = (hbr->pattern->format == PIXEL_FORMAT_MONO);
184
0
      const UINT32 formatSize = FreeRDPGetBytesPerPixel(hbr->pattern->format);
185
0
      if (formatSize == 0)
186
0
        return FALSE;
187
188
0
      for (INT32 y = 0; y < nHeight; y++)
189
0
      {
190
0
        for (INT32 x = 0; x < nWidth; x++)
191
0
        {
192
0
          const size_t yOffset =
193
0
              ((1ULL * WINPR_ASSERTING_INT_CAST(size_t, nYDest) +
194
0
                WINPR_ASSERTING_INT_CAST(size_t, y)) *
195
0
               WINPR_ASSERTING_INT_CAST(size_t, hbr->pattern->width) %
196
0
               WINPR_ASSERTING_INT_CAST(size_t, hbr->pattern->height)) *
197
0
              formatSize;
198
0
          const size_t xOffset = ((1ULL * WINPR_ASSERTING_INT_CAST(size_t, nXDest) +
199
0
                                   WINPR_ASSERTING_INT_CAST(size_t, x)) %
200
0
                                  WINPR_ASSERTING_INT_CAST(size_t, hbr->pattern->width)) *
201
0
                                 formatSize;
202
0
          const BYTE* patp = &hbr->pattern->data[yOffset + xOffset];
203
204
0
          UINT32 dstColor = 0;
205
0
          if (monochrome)
206
0
          {
207
0
            if (*patp == 0)
208
0
              dstColor = hdc->bkColor;
209
0
            else
210
0
              dstColor = hdc->textColor;
211
0
          }
212
0
          else
213
0
          {
214
0
            const UINT32 tmp = FreeRDPReadColor(patp, hbr->pattern->format);
215
0
            dstColor =
216
0
                FreeRDPConvertColor(tmp, hbr->pattern->format, hdc->format, NULL);
217
0
          }
218
219
0
          BYTE* dstp = gdi_get_bitmap_pointer(hdc, nXDest + x, nYDest + y);
220
0
          if (dstp)
221
0
            FreeRDPWriteColor(dstp, hdc->format, dstColor);
222
0
        }
223
0
      }
224
0
    }
225
0
    break;
226
227
0
    default:
228
0
      break;
229
0
  }
230
231
0
  if (!gdi_InvalidateRegion(hdc, nXDest, nYDest, nWidth, nHeight))
232
0
    return FALSE;
233
234
0
  return TRUE;
235
0
}
236
237
/**
238
 * Draw a polygon
239
 * msdn{dd162814}
240
 * @param hdc device context
241
 * @param lpPoints array of points
242
 * @param nCount number of points
243
 * @return nonzero if successful, 0 otherwise
244
 */
245
BOOL gdi_Polygon(WINPR_ATTR_UNUSED HGDI_DC hdc, WINPR_ATTR_UNUSED GDI_POINT* lpPoints,
246
                 WINPR_ATTR_UNUSED int nCount)
247
0
{
248
0
  WLog_ERR(TAG, "Not implemented!");
249
0
  return FALSE;
250
0
}
251
252
/**
253
 * Draw a series of closed polygons
254
 * msdn{dd162818}
255
 * @param hdc device context
256
 * @param lpPoints array of series of points
257
 * @param lpPolyCounts array of number of points in each series
258
 * @param nCount count of number of points in lpPolyCounts
259
 * @return nonzero if successful, 0 otherwise
260
 */
261
BOOL gdi_PolyPolygon(WINPR_ATTR_UNUSED HGDI_DC hdc, WINPR_ATTR_UNUSED GDI_POINT* lpPoints,
262
                     WINPR_ATTR_UNUSED int* lpPolyCounts, WINPR_ATTR_UNUSED int nCount)
263
0
{
264
0
  WLog_ERR(TAG, "Not implemented!");
265
0
  return FALSE;
266
0
}
267
268
BOOL gdi_Rectangle(HGDI_DC hdc, INT32 nXDst, INT32 nYDst, INT32 nWidth, INT32 nHeight)
269
0
{
270
0
  UINT32 color = 0;
271
272
0
  if (!gdi_ClipCoords(hdc, &nXDst, &nYDst, &nWidth, &nHeight, NULL, NULL))
273
0
    return TRUE;
274
275
0
  color = hdc->textColor;
276
277
0
  for (INT32 y = 0; y < nHeight; y++)
278
0
  {
279
0
    BYTE* dstLeft = gdi_get_bitmap_pointer(hdc, nXDst, nYDst + y);
280
0
    BYTE* dstRight = gdi_get_bitmap_pointer(hdc, nXDst + nWidth - 1, nYDst + y);
281
282
0
    if (dstLeft)
283
0
      FreeRDPWriteColor(dstLeft, hdc->format, color);
284
285
0
    if (dstRight)
286
0
      FreeRDPWriteColor(dstRight, hdc->format, color);
287
0
  }
288
289
0
  for (INT32 x = 0; x < nWidth; x++)
290
0
  {
291
0
    BYTE* dstTop = gdi_get_bitmap_pointer(hdc, nXDst + x, nYDst);
292
0
    BYTE* dstBottom = gdi_get_bitmap_pointer(hdc, nXDst + x, nYDst + nHeight - 1);
293
294
0
    if (dstTop)
295
0
      FreeRDPWriteColor(dstTop, hdc->format, color);
296
297
0
    if (dstBottom)
298
0
      FreeRDPWriteColor(dstBottom, hdc->format, color);
299
0
  }
300
301
0
  return FALSE;
302
0
}