FreeRDP
gdi/graphics.c
1 
22 #include <freerdp/config.h>
23 
24 #include <winpr/crt.h>
25 
26 #include <freerdp/log.h>
27 #include <freerdp/freerdp.h>
28 #include <freerdp/gdi/dc.h>
29 #include <freerdp/gdi/shape.h>
30 #include <freerdp/gdi/region.h>
31 #include <freerdp/gdi/bitmap.h>
32 
33 #include "clipping.h"
34 #include "drawing.h"
35 #include "brush.h"
36 #include "graphics.h"
37 
38 #define TAG FREERDP_TAG("gdi")
39 /* Bitmap Class */
40 
41 HGDI_BITMAP gdi_create_bitmap(rdpGdi* gdi, UINT32 nWidth, UINT32 nHeight, UINT32 SrcFormat,
42  BYTE* data)
43 {
44  UINT32 nSrcStep = 0;
45  UINT32 nDstStep = 0;
46  BYTE* pSrcData = NULL;
47  BYTE* pDstData = NULL;
48  HGDI_BITMAP bitmap = NULL;
49 
50  if (!gdi)
51  return NULL;
52 
53  nDstStep = nWidth * FreeRDPGetBytesPerPixel(gdi->dstFormat);
54  pDstData = winpr_aligned_malloc(1ull * nHeight * nDstStep, 16);
55 
56  if (!pDstData)
57  return NULL;
58 
59  pSrcData = data;
60  nSrcStep = nWidth * FreeRDPGetBytesPerPixel(SrcFormat);
61 
62  if (!freerdp_image_copy_no_overlap(pDstData, gdi->dstFormat, nDstStep, 0, 0, nWidth, nHeight,
63  pSrcData, SrcFormat, nSrcStep, 0, 0, &gdi->palette,
64  FREERDP_FLIP_NONE))
65  {
66  winpr_aligned_free(pDstData);
67  return NULL;
68  }
69 
70  bitmap = gdi_CreateBitmap(nWidth, nHeight, gdi->dstFormat, pDstData);
71  return bitmap;
72 }
73 
74 static BOOL gdi_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
75 {
76  gdiBitmap* gdi_bitmap = NULL;
77  rdpGdi* gdi = context->gdi;
78  gdi_bitmap = (gdiBitmap*)bitmap;
79  gdi_bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc);
80 
81  if (!gdi_bitmap->hdc)
82  return FALSE;
83 
84  if (!bitmap->data)
85  gdi_bitmap->bitmap = gdi_CreateCompatibleBitmap(gdi->hdc, bitmap->width, bitmap->height);
86  else
87  {
88  UINT32 format = bitmap->format;
89  gdi_bitmap->bitmap =
90  gdi_create_bitmap(gdi, bitmap->width, bitmap->height, format, bitmap->data);
91  }
92 
93  if (!gdi_bitmap->bitmap)
94  {
95  gdi_DeleteDC(gdi_bitmap->hdc);
96  gdi_bitmap->hdc = NULL;
97  return FALSE;
98  }
99 
100  gdi_bitmap->hdc->format = gdi_bitmap->bitmap->format;
101  gdi_SelectObject(gdi_bitmap->hdc, (HGDIOBJECT)gdi_bitmap->bitmap);
102  gdi_bitmap->org_bitmap = NULL;
103  return TRUE;
104 }
105 
106 static void gdi_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap)
107 {
108  gdiBitmap* gdi_bitmap = (gdiBitmap*)bitmap;
109 
110  if (gdi_bitmap)
111  {
112  if (gdi_bitmap->hdc)
113  gdi_SelectObject(gdi_bitmap->hdc, (HGDIOBJECT)gdi_bitmap->org_bitmap);
114 
115  gdi_DeleteObject((HGDIOBJECT)gdi_bitmap->bitmap);
116  gdi_DeleteDC(gdi_bitmap->hdc);
117  winpr_aligned_free(bitmap->data);
118  }
119 
120  free(bitmap);
121 }
122 
123 static BOOL gdi_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
124 {
125  gdiBitmap* gdi_bitmap = (gdiBitmap*)bitmap;
126  UINT32 width = bitmap->right - bitmap->left + 1;
127  UINT32 height = bitmap->bottom - bitmap->top + 1;
128  return gdi_BitBlt(context->gdi->primary->hdc, WINPR_ASSERTING_INT_CAST(int, bitmap->left),
129  WINPR_ASSERTING_INT_CAST(int, bitmap->top),
130  WINPR_ASSERTING_INT_CAST(int, width), WINPR_ASSERTING_INT_CAST(int, height),
131  gdi_bitmap->hdc, 0, 0, GDI_SRCCOPY, &context->gdi->palette);
132 }
133 
134 static BOOL gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, const BYTE* pSrcData,
135  UINT32 DstWidth, UINT32 DstHeight, UINT32 bpp, UINT32 length,
136  BOOL compressed, UINT32 codecId)
137 {
138  UINT32 SrcSize = length;
139  rdpGdi* gdi = context->gdi;
140  UINT32 size = DstWidth * DstHeight;
141  bitmap->compressed = FALSE;
142  bitmap->format = gdi->dstFormat;
143 
144  if ((FreeRDPGetBytesPerPixel(bitmap->format) == 0) || (DstWidth == 0) || (DstHeight == 0) ||
145  (DstWidth > UINT32_MAX / DstHeight) ||
146  (size > (UINT32_MAX / FreeRDPGetBytesPerPixel(bitmap->format))))
147  {
148  WLog_ERR(TAG, "invalid input data");
149  return FALSE;
150  }
151 
152  size *= FreeRDPGetBytesPerPixel(bitmap->format);
153  bitmap->length = size;
154  bitmap->data = (BYTE*)winpr_aligned_malloc(bitmap->length, 16);
155 
156  if (!bitmap->data)
157  return FALSE;
158 
159  if (compressed)
160  {
161  if ((codecId == RDP_CODEC_ID_REMOTEFX) || (codecId == RDP_CODEC_ID_IMAGE_REMOTEFX))
162  {
163  REGION16 invalidRegion;
164  region16_init(&invalidRegion);
165 
166  if (!rfx_process_message(context->codecs->rfx, pSrcData, SrcSize, bitmap->left,
167  bitmap->top, bitmap->data, bitmap->format, gdi->stride,
168  WINPR_ASSERTING_INT_CAST(UINT32, gdi->height), &invalidRegion))
169  {
170  WLog_ERR(TAG, "rfx_process_message failed");
171  return FALSE;
172  }
173  }
174  else if (codecId == RDP_CODEC_ID_NSCODEC)
175  {
176  const int status = nsc_process_message(
177  context->codecs->nsc, 32, DstWidth, DstHeight, pSrcData, SrcSize, bitmap->data,
178  bitmap->format, 0, 0, 0, DstWidth, DstHeight, FREERDP_FLIP_VERTICAL);
179 
180  if (status < 1)
181  {
182  WLog_ERR(TAG, "nsc_process_message failed");
183  return FALSE;
184  }
185 
186  return freerdp_image_copy_no_overlap(bitmap->data, bitmap->format, 0, 0, 0, DstWidth,
187  DstHeight, pSrcData, PIXEL_FORMAT_XRGB32, 0, 0, 0,
188  &gdi->palette, FREERDP_FLIP_VERTICAL);
189  }
190  else if (bpp < 32)
191  {
192  if (!interleaved_decompress(context->codecs->interleaved, pSrcData, SrcSize, DstWidth,
193  DstHeight, bpp, bitmap->data, bitmap->format, 0, 0, 0,
194  DstWidth, DstHeight, &gdi->palette))
195  {
196  WLog_ERR(TAG, "interleaved_decompress failed");
197  return FALSE;
198  }
199  }
200  else
201  {
202  const BOOL fidelity =
203  freerdp_settings_get_bool(context->settings, FreeRDP_DrawAllowDynamicColorFidelity);
204  freerdp_planar_switch_bgr(context->codecs->planar, fidelity);
205  if (!planar_decompress(context->codecs->planar, pSrcData, SrcSize, DstWidth, DstHeight,
206  bitmap->data, bitmap->format, 0, 0, 0, DstWidth, DstHeight,
207  TRUE))
208  {
209  WLog_ERR(TAG, "planar_decompress failed");
210  return FALSE;
211  }
212  }
213  }
214  else
215  {
216  const UINT32 SrcFormat = gdi_get_pixel_format(bpp);
217  const size_t sbpp = FreeRDPGetBytesPerPixel(SrcFormat);
218  const size_t dbpp = FreeRDPGetBytesPerPixel(bitmap->format);
219 
220  if ((sbpp == 0) || (dbpp == 0))
221  return FALSE;
222  else
223  {
224  const size_t dstSize = SrcSize * dbpp / sbpp;
225 
226  if (dstSize < bitmap->length)
227  {
228  WLog_ERR(TAG, "dstSize %" PRIuz " < bitmap->length %" PRIu32, dstSize,
229  bitmap->length);
230  return FALSE;
231  }
232  }
233 
234  if (!freerdp_image_copy_no_overlap(bitmap->data, bitmap->format, 0, 0, 0, DstWidth,
235  DstHeight, pSrcData, SrcFormat, 0, 0, 0, &gdi->palette,
236  FREERDP_FLIP_VERTICAL))
237  {
238  WLog_ERR(TAG, "freerdp_image_copy failed");
239  return FALSE;
240  }
241  }
242 
243  return TRUE;
244 }
245 
246 static BOOL gdi_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary)
247 {
248  rdpGdi* gdi = NULL;
249 
250  if (!context)
251  return FALSE;
252 
253  gdi = context->gdi;
254 
255  if (!gdi)
256  return FALSE;
257 
258  if (primary)
259  gdi->drawing = gdi->primary;
260  else
261  gdi->drawing = (gdiBitmap*)bitmap;
262 
263  return TRUE;
264 }
265 
266 /* Glyph Class */
267 static BOOL gdi_Glyph_New(rdpContext* context, rdpGlyph* glyph)
268 {
269  BYTE* data = NULL;
270  gdiGlyph* gdi_glyph = NULL;
271 
272  if (!context || !glyph)
273  return FALSE;
274 
275  gdi_glyph = (gdiGlyph*)glyph;
276  gdi_glyph->hdc = gdi_GetDC();
277 
278  if (!gdi_glyph->hdc)
279  return FALSE;
280 
281  gdi_glyph->hdc->format = PIXEL_FORMAT_MONO;
282  data = freerdp_glyph_convert(glyph->cx, glyph->cy, glyph->aj);
283 
284  if (!data)
285  {
286  gdi_DeleteDC(gdi_glyph->hdc);
287  return FALSE;
288  }
289 
290  gdi_glyph->bitmap = gdi_CreateBitmap(glyph->cx, glyph->cy, PIXEL_FORMAT_MONO, data);
291 
292  if (!gdi_glyph->bitmap)
293  {
294  gdi_DeleteDC(gdi_glyph->hdc);
295  winpr_aligned_free(data);
296  return FALSE;
297  }
298 
299  gdi_SelectObject(gdi_glyph->hdc, (HGDIOBJECT)gdi_glyph->bitmap);
300  gdi_glyph->org_bitmap = NULL;
301  return TRUE;
302 }
303 
304 static void gdi_Glyph_Free(rdpContext* context, rdpGlyph* glyph)
305 {
306  gdiGlyph* gdi_glyph = NULL;
307  gdi_glyph = (gdiGlyph*)glyph;
308 
309  if (gdi_glyph)
310  {
311  gdi_SelectObject(gdi_glyph->hdc, (HGDIOBJECT)gdi_glyph->org_bitmap);
312  gdi_DeleteObject((HGDIOBJECT)gdi_glyph->bitmap);
313  gdi_DeleteDC(gdi_glyph->hdc);
314  free(glyph->aj);
315  free(glyph);
316  }
317 }
318 
319 static BOOL gdi_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x, INT32 y, INT32 w,
320  INT32 h, INT32 sx, INT32 sy, BOOL fOpRedundant)
321 {
322  const gdiGlyph* gdi_glyph = NULL;
323  rdpGdi* gdi = NULL;
324  HGDI_BRUSH brush = NULL;
325  BOOL rc = FALSE;
326 
327  if (!context || !glyph)
328  return FALSE;
329 
330  gdi = context->gdi;
331  gdi_glyph = (const gdiGlyph*)glyph;
332 
333  if (!fOpRedundant)
334  {
335  GDI_RECT rect = { 0 };
336 
337  if (x > 0)
338  rect.left = x;
339 
340  if (y > 0)
341  rect.top = y;
342 
343  if (x + w > 0)
344  rect.right = x + w - 1;
345 
346  if (y + h > 0)
347  rect.bottom = y + h - 1;
348 
349  if ((rect.left < rect.right) && (rect.top < rect.bottom))
350  {
351  brush = gdi_CreateSolidBrush(gdi->drawing->hdc->bkColor);
352 
353  if (!brush)
354  return FALSE;
355 
356  gdi_FillRect(gdi->drawing->hdc, &rect, brush);
357  gdi_DeleteObject((HGDIOBJECT)brush);
358  }
359  }
360 
361  brush = gdi_CreateSolidBrush(gdi->drawing->hdc->textColor);
362 
363  if (!brush)
364  return FALSE;
365 
366  gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT)brush);
367  rc = gdi_BitBlt(gdi->drawing->hdc, x, y, w, h, gdi_glyph->hdc, sx, sy, GDI_GLYPH_ORDER,
368  &context->gdi->palette);
369  gdi_DeleteObject((HGDIOBJECT)brush);
370  return rc;
371 }
372 
373 static BOOL gdi_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height,
374  UINT32 bgcolor, UINT32 fgcolor, BOOL fOpRedundant)
375 {
376  rdpGdi* gdi = NULL;
377 
378  if (!context || !context->gdi)
379  return FALSE;
380 
381  gdi = context->gdi;
382 
383  if (!gdi->drawing || !gdi->drawing->hdc)
384  return FALSE;
385 
386  if (!fOpRedundant)
387  {
388  if (!gdi_decode_color(gdi, bgcolor, &bgcolor, NULL))
389  return FALSE;
390 
391  if (!gdi_decode_color(gdi, fgcolor, &fgcolor, NULL))
392  return FALSE;
393 
394  gdi_SetClipRgn(gdi->drawing->hdc, x, y, width, height);
395  gdi_SetTextColor(gdi->drawing->hdc, bgcolor);
396  gdi_SetBkColor(gdi->drawing->hdc, fgcolor);
397 
398  if (1)
399  {
400  GDI_RECT rect = { 0 };
401  HGDI_BRUSH brush = gdi_CreateSolidBrush(fgcolor);
402 
403  if (!brush)
404  return FALSE;
405 
406  if (x > 0)
407  rect.left = x;
408 
409  if (y > 0)
410  rect.top = y;
411 
412  rect.right = x + width - 1;
413  rect.bottom = y + height - 1;
414 
415  if ((x + width > rect.left) && (y + height > rect.top))
416  gdi_FillRect(gdi->drawing->hdc, &rect, brush);
417 
418  gdi_DeleteObject((HGDIOBJECT)brush);
419  }
420 
421  return gdi_SetNullClipRgn(gdi->drawing->hdc);
422  }
423 
424  return TRUE;
425 }
426 
427 static BOOL gdi_Glyph_EndDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height,
428  UINT32 bgcolor, UINT32 fgcolor)
429 {
430  rdpGdi* gdi = NULL;
431 
432  if (!context || !context->gdi)
433  return FALSE;
434 
435  gdi = context->gdi;
436 
437  if (!gdi->drawing || !gdi->drawing->hdc)
438  return FALSE;
439 
440  gdi_SetNullClipRgn(gdi->drawing->hdc);
441  return TRUE;
442 }
443 
444 /* Graphics Module */
445 BOOL gdi_register_graphics(rdpGraphics* graphics)
446 {
447  rdpBitmap bitmap = { 0 };
448  rdpGlyph glyph = { 0 };
449  bitmap.size = sizeof(gdiBitmap);
450  bitmap.New = gdi_Bitmap_New;
451  bitmap.Free = gdi_Bitmap_Free;
452  bitmap.Paint = gdi_Bitmap_Paint;
453  bitmap.Decompress = gdi_Bitmap_Decompress;
454  bitmap.SetSurface = gdi_Bitmap_SetSurface;
455  graphics_register_bitmap(graphics, &bitmap);
456  glyph.size = sizeof(gdiGlyph);
457  glyph.New = gdi_Glyph_New;
458  glyph.Free = gdi_Glyph_Free;
459  glyph.Draw = gdi_Glyph_Draw;
460  glyph.BeginDraw = gdi_Glyph_BeginDraw;
461  glyph.EndDraw = gdi_Glyph_EndDraw;
462  graphics_register_glyph(graphics, &glyph);
463  return TRUE;
464 }
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.