1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * Graphical Objects
4 *
5 * Copyright 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 <winpr/crt.h>
27
28 #include <freerdp/log.h>
29 #include <freerdp/gdi/dc.h>
30 #include <freerdp/gdi/shape.h>
31 #include <freerdp/gdi/region.h>
32 #include <freerdp/gdi/bitmap.h>
33
34 #include "clipping.h"
35 #include "drawing.h"
36 #include "brush.h"
37 #include "graphics.h"
38
39 #define TAG FREERDP_TAG("gdi")
40 /* Bitmap Class */
41
gdi_create_bitmap(rdpGdi * gdi,UINT32 nWidth,UINT32 nHeight,UINT32 SrcFormat,BYTE * data)42 HGDI_BITMAP gdi_create_bitmap(rdpGdi* gdi, UINT32 nWidth, UINT32 nHeight, UINT32 SrcFormat,
43 BYTE* data)
44 {
45 UINT32 nSrcStep;
46 UINT32 nDstStep;
47 BYTE* pSrcData;
48 BYTE* pDstData;
49 HGDI_BITMAP bitmap;
50
51 if (!gdi)
52 return NULL;
53
54 nDstStep = nWidth * GetBytesPerPixel(gdi->dstFormat);
55 pDstData = _aligned_malloc(nHeight * nDstStep * 1ULL, 16);
56
57 if (!pDstData)
58 return NULL;
59
60 pSrcData = data;
61 nSrcStep = nWidth * GetBytesPerPixel(SrcFormat);
62
63 if (!freerdp_image_copy(pDstData, gdi->dstFormat, nDstStep, 0, 0, nWidth, nHeight, pSrcData,
64 SrcFormat, nSrcStep, 0, 0, &gdi->palette, FREERDP_FLIP_NONE))
65 {
66 _aligned_free(pDstData);
67 return NULL;
68 }
69
70 bitmap = gdi_CreateBitmap(nWidth, nHeight, gdi->dstFormat, pDstData);
71 return bitmap;
72 }
73
gdi_Bitmap_New(rdpContext * context,rdpBitmap * bitmap)74 static BOOL gdi_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
75 {
76 gdiBitmap* gdi_bitmap;
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
gdi_Bitmap_Free(rdpContext * context,rdpBitmap * bitmap)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 _aligned_free(bitmap->data);
118 }
119
120 free(bitmap);
121 }
122
gdi_Bitmap_Paint(rdpContext * context,rdpBitmap * bitmap)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, bitmap->left, bitmap->top, width, height,
129 gdi_bitmap->hdc, 0, 0, GDI_SRCCOPY, &context->gdi->palette);
130 }
131
gdi_Bitmap_Decompress(rdpContext * context,rdpBitmap * bitmap,const BYTE * pSrcData,UINT32 DstWidth,UINT32 DstHeight,UINT32 bpp,UINT32 length,BOOL compressed,UINT32 codecId)132 static BOOL gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, const BYTE* pSrcData,
133 UINT32 DstWidth, UINT32 DstHeight, UINT32 bpp, UINT32 length,
134 BOOL compressed, UINT32 codecId)
135 {
136 UINT32 SrcSize = length;
137 rdpGdi* gdi = context->gdi;
138 UINT32 size = DstWidth * DstHeight;
139 bitmap->compressed = FALSE;
140 bitmap->format = gdi->dstFormat;
141
142 if ((GetBytesPerPixel(bitmap->format) == 0) || (DstWidth == 0) || (DstHeight == 0) ||
143 (DstWidth > UINT32_MAX / DstHeight) ||
144 (size > (UINT32_MAX / GetBytesPerPixel(bitmap->format))))
145 return FALSE;
146
147 size *= GetBytesPerPixel(bitmap->format);
148 bitmap->length = size;
149 bitmap->data = (BYTE*)_aligned_malloc(bitmap->length, 16);
150
151 if (!bitmap->data)
152 return FALSE;
153
154 if (compressed)
155 {
156 if (bpp < 32)
157 {
158 if (!interleaved_decompress(context->codecs->interleaved, pSrcData, SrcSize, DstWidth,
159 DstHeight, bpp, bitmap->data, bitmap->format, 0, 0, 0,
160 DstWidth, DstHeight, &gdi->palette))
161 return FALSE;
162 }
163 else
164 {
165 freerdp_planar_switch_bgr(context->codecs->planar,
166 context->settings->DrawAllowDynamicColorFidelity);
167 if (!planar_decompress(context->codecs->planar, pSrcData, SrcSize, DstWidth, DstHeight,
168 bitmap->data, bitmap->format, 0, 0, 0, DstWidth, DstHeight,
169 TRUE))
170 return FALSE;
171 }
172 }
173 else
174 {
175 const UINT32 SrcFormat = gdi_get_pixel_format(bpp);
176 const size_t sbpp = GetBytesPerPixel(SrcFormat);
177 const size_t dbpp = GetBytesPerPixel(bitmap->format);
178
179 if ((sbpp == 0) || (dbpp == 0))
180 return FALSE;
181 else
182 {
183 const size_t dstSize = SrcSize * dbpp / sbpp;
184
185 if (dstSize < bitmap->length)
186 return FALSE;
187 }
188
189 if (!freerdp_image_copy(bitmap->data, bitmap->format, 0, 0, 0, DstWidth, DstHeight,
190 pSrcData, SrcFormat, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
191 return FALSE;
192 }
193
194 return TRUE;
195 }
196
gdi_Bitmap_SetSurface(rdpContext * context,rdpBitmap * bitmap,BOOL primary)197 static BOOL gdi_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary)
198 {
199 rdpGdi* gdi;
200
201 if (!context)
202 return FALSE;
203
204 gdi = context->gdi;
205
206 if (!gdi)
207 return FALSE;
208
209 if (primary)
210 gdi->drawing = gdi->primary;
211 else
212 gdi->drawing = (gdiBitmap*)bitmap;
213
214 return TRUE;
215 }
216
217 /* Glyph Class */
gdi_Glyph_New(rdpContext * context,const rdpGlyph * glyph)218 static BOOL gdi_Glyph_New(rdpContext* context, const rdpGlyph* glyph)
219 {
220 BYTE* data;
221 gdiGlyph* gdi_glyph;
222
223 if (!context || !glyph)
224 return FALSE;
225
226 gdi_glyph = (gdiGlyph*)glyph;
227 gdi_glyph->hdc = gdi_GetDC();
228
229 if (!gdi_glyph->hdc)
230 return FALSE;
231
232 gdi_glyph->hdc->format = PIXEL_FORMAT_MONO;
233 data = freerdp_glyph_convert(glyph->cx, glyph->cy, glyph->aj);
234
235 if (!data)
236 {
237 gdi_DeleteDC(gdi_glyph->hdc);
238 return FALSE;
239 }
240
241 gdi_glyph->bitmap = gdi_CreateBitmap(glyph->cx, glyph->cy, PIXEL_FORMAT_MONO, data);
242
243 if (!gdi_glyph->bitmap)
244 {
245 gdi_DeleteDC(gdi_glyph->hdc);
246 _aligned_free(data);
247 return FALSE;
248 }
249
250 gdi_SelectObject(gdi_glyph->hdc, (HGDIOBJECT)gdi_glyph->bitmap);
251 gdi_glyph->org_bitmap = NULL;
252 return TRUE;
253 }
254
gdi_Glyph_Free(rdpContext * context,rdpGlyph * glyph)255 static void gdi_Glyph_Free(rdpContext* context, rdpGlyph* glyph)
256 {
257 gdiGlyph* gdi_glyph;
258 gdi_glyph = (gdiGlyph*)glyph;
259
260 if (gdi_glyph)
261 {
262 gdi_SelectObject(gdi_glyph->hdc, (HGDIOBJECT)gdi_glyph->org_bitmap);
263 gdi_DeleteObject((HGDIOBJECT)gdi_glyph->bitmap);
264 gdi_DeleteDC(gdi_glyph->hdc);
265 free(glyph->aj);
266 free(glyph);
267 }
268 }
269
gdi_Glyph_Draw(rdpContext * context,const rdpGlyph * glyph,INT32 x,INT32 y,INT32 w,INT32 h,INT32 sx,INT32 sy,BOOL fOpRedundant)270 static BOOL gdi_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x, INT32 y, INT32 w,
271 INT32 h, INT32 sx, INT32 sy, BOOL fOpRedundant)
272 {
273 gdiGlyph* gdi_glyph;
274 rdpGdi* gdi;
275 HGDI_BRUSH brush;
276 BOOL rc = FALSE;
277
278 if (!context || !glyph)
279 return FALSE;
280
281 gdi = context->gdi;
282 gdi_glyph = (gdiGlyph*)glyph;
283
284 if (!fOpRedundant && 0)
285 {
286 GDI_RECT rect = { 0 };
287
288 if (x > 0)
289 rect.left = x;
290
291 if (y > 0)
292 rect.top = y;
293
294 if (x + w > 0)
295 rect.right = x + w - 1;
296
297 if (y + h > 0)
298 rect.bottom = y + h - 1;
299
300 if ((rect.left < rect.right) && (rect.top < rect.bottom))
301 {
302 brush = gdi_CreateSolidBrush(gdi->drawing->hdc->bkColor);
303
304 if (!brush)
305 return FALSE;
306
307 gdi_FillRect(gdi->drawing->hdc, &rect, brush);
308 gdi_DeleteObject((HGDIOBJECT)brush);
309 }
310 }
311
312 brush = gdi_CreateSolidBrush(gdi->drawing->hdc->textColor);
313
314 if (!brush)
315 return FALSE;
316
317 gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT)brush);
318 rc = gdi_BitBlt(gdi->drawing->hdc, x, y, w, h, gdi_glyph->hdc, sx, sy, GDI_GLYPH_ORDER,
319 &context->gdi->palette);
320 gdi_DeleteObject((HGDIOBJECT)brush);
321 return rc;
322 }
323
gdi_Glyph_SetBounds(rdpContext * context,INT32 x,INT32 y,INT32 width,INT32 height)324 static BOOL gdi_Glyph_SetBounds(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height)
325 {
326 rdpGdi* gdi;
327
328 if (!context || !context->gdi)
329 return FALSE;
330
331 gdi = context->gdi;
332
333 if (!gdi->drawing || !gdi->drawing->hdc)
334 return FALSE;
335
336 return gdi_SetClipRgn(gdi->drawing->hdc, x, y, width, height);
337 }
338
gdi_Glyph_BeginDraw(rdpContext * context,INT32 x,INT32 y,INT32 width,INT32 height,UINT32 bgcolor,UINT32 fgcolor,BOOL fOpRedundant)339 static BOOL gdi_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height,
340 UINT32 bgcolor, UINT32 fgcolor, BOOL fOpRedundant)
341 {
342 rdpGdi* gdi;
343
344 if (!context || !context->gdi)
345 return FALSE;
346
347 gdi = context->gdi;
348
349 if (!gdi->drawing || !gdi->drawing->hdc)
350 return FALSE;
351
352 if (!fOpRedundant)
353 {
354 if (!gdi_decode_color(gdi, bgcolor, &bgcolor, NULL))
355 return FALSE;
356
357 if (!gdi_decode_color(gdi, fgcolor, &fgcolor, NULL))
358 return FALSE;
359
360 gdi_SetClipRgn(gdi->drawing->hdc, x, y, width, height);
361 gdi_SetTextColor(gdi->drawing->hdc, bgcolor);
362 gdi_SetBkColor(gdi->drawing->hdc, fgcolor);
363
364 if (1)
365 {
366 GDI_RECT rect = { 0 };
367 HGDI_BRUSH brush = gdi_CreateSolidBrush(fgcolor);
368
369 if (!brush)
370 return FALSE;
371
372 if (x > 0)
373 rect.left = x;
374
375 if (y > 0)
376 rect.top = y;
377
378 rect.right = x + width - 1;
379 rect.bottom = y + height - 1;
380
381 if ((x + width > rect.left) && (y + height > rect.top))
382 gdi_FillRect(gdi->drawing->hdc, &rect, brush);
383
384 gdi_DeleteObject((HGDIOBJECT)brush);
385 }
386
387 return gdi_SetNullClipRgn(gdi->drawing->hdc);
388 }
389
390 return TRUE;
391 }
392
gdi_Glyph_EndDraw(rdpContext * context,INT32 x,INT32 y,INT32 width,INT32 height,UINT32 bgcolor,UINT32 fgcolor)393 static BOOL gdi_Glyph_EndDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height,
394 UINT32 bgcolor, UINT32 fgcolor)
395 {
396 rdpGdi* gdi;
397
398 if (!context || !context->gdi)
399 return FALSE;
400
401 gdi = context->gdi;
402
403 if (!gdi->drawing || !gdi->drawing->hdc)
404 return FALSE;
405
406 gdi_SetNullClipRgn(gdi->drawing->hdc);
407 return TRUE;
408 }
409
410 /* Graphics Module */
gdi_register_graphics(rdpGraphics * graphics)411 BOOL gdi_register_graphics(rdpGraphics* graphics)
412 {
413 rdpBitmap bitmap;
414 rdpGlyph glyph;
415 bitmap.size = sizeof(gdiBitmap);
416 bitmap.New = gdi_Bitmap_New;
417 bitmap.Free = gdi_Bitmap_Free;
418 bitmap.Paint = gdi_Bitmap_Paint;
419 bitmap.Decompress = gdi_Bitmap_Decompress;
420 bitmap.SetSurface = gdi_Bitmap_SetSurface;
421 graphics_register_bitmap(graphics, &bitmap);
422 glyph.size = sizeof(gdiGlyph);
423 glyph.New = gdi_Glyph_New;
424 glyph.Free = gdi_Glyph_Free;
425 glyph.Draw = gdi_Glyph_Draw;
426 glyph.BeginDraw = gdi_Glyph_BeginDraw;
427 glyph.EndDraw = gdi_Glyph_EndDraw;
428 glyph.SetBounds = gdi_Glyph_SetBounds;
429 graphics_register_glyph(graphics, &glyph);
430 return TRUE;
431 }
432