2 * FreeRDP: A Remote Desktop Protocol Implementation
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
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
26 #include <winpr/crt.h>
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>
39 #define TAG FREERDP_TAG("gdi")
42 HGDI_BITMAP gdi_create_bitmap(rdpGdi* gdi, UINT32 nWidth, UINT32 nHeight, UINT32 SrcFormat,
54 nDstStep = nWidth * GetBytesPerPixel(gdi->dstFormat);
55 pDstData = _aligned_malloc(nHeight * nDstStep, 16);
61 nSrcStep = nWidth * GetBytesPerPixel(SrcFormat);
63 if (!freerdp_image_copy(pDstData, gdi->dstFormat, nDstStep, 0, 0, nWidth, nHeight, pSrcData,
64 SrcFormat, nSrcStep, 0, 0, &gdi->palette, FREERDP_FLIP_NONE))
66 _aligned_free(pDstData);
70 bitmap = gdi_CreateBitmap(nWidth, nHeight, gdi->dstFormat, pDstData);
74 static BOOL gdi_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
76 gdiBitmap* gdi_bitmap;
77 rdpGdi* gdi = context->gdi;
78 gdi_bitmap = (gdiBitmap*)bitmap;
79 gdi_bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc);
85 gdi_bitmap->bitmap = gdi_CreateCompatibleBitmap(gdi->hdc, bitmap->width, bitmap->height);
88 UINT32 format = bitmap->format;
90 gdi_create_bitmap(gdi, bitmap->width, bitmap->height, format, bitmap->data);
93 if (!gdi_bitmap->bitmap)
95 gdi_DeleteDC(gdi_bitmap->hdc);
99 gdi_bitmap->hdc->format = gdi_bitmap->bitmap->format;
100 gdi_SelectObject(gdi_bitmap->hdc, (HGDIOBJECT)gdi_bitmap->bitmap);
101 gdi_bitmap->org_bitmap = NULL;
105 static void gdi_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap)
107 gdiBitmap* gdi_bitmap = (gdiBitmap*)bitmap;
112 gdi_SelectObject(gdi_bitmap->hdc, (HGDIOBJECT)gdi_bitmap->org_bitmap);
114 gdi_DeleteObject((HGDIOBJECT)gdi_bitmap->bitmap);
115 gdi_DeleteDC(gdi_bitmap->hdc);
116 _aligned_free(bitmap->data);
122 static BOOL gdi_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
124 gdiBitmap* gdi_bitmap = (gdiBitmap*)bitmap;
125 UINT32 width = bitmap->right - bitmap->left + 1;
126 UINT32 height = bitmap->bottom - bitmap->top + 1;
127 return gdi_BitBlt(context->gdi->primary->hdc, bitmap->left, bitmap->top, width, height,
128 gdi_bitmap->hdc, 0, 0, GDI_SRCCOPY, &context->gdi->palette);
131 static BOOL gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, const BYTE* pSrcData,
132 UINT32 DstWidth, UINT32 DstHeight, UINT32 bpp, UINT32 length,
133 BOOL compressed, UINT32 codecId)
135 UINT32 SrcSize = length;
136 rdpGdi* gdi = context->gdi;
137 UINT32 size = DstWidth * DstHeight;
138 bitmap->compressed = FALSE;
139 bitmap->format = gdi->dstFormat;
141 if ((GetBytesPerPixel(bitmap->format) == 0) || (DstWidth == 0) || (DstHeight == 0) ||
142 (DstWidth > UINT32_MAX / DstHeight) ||
143 (size > (UINT32_MAX / GetBytesPerPixel(bitmap->format))))
146 size *= GetBytesPerPixel(bitmap->format);
147 bitmap->length = size;
148 bitmap->data = (BYTE*)_aligned_malloc(bitmap->length, 16);
157 if (!interleaved_decompress(context->codecs->interleaved, pSrcData, SrcSize, DstWidth,
158 DstHeight, bpp, bitmap->data, bitmap->format, 0, 0, 0,
159 DstWidth, DstHeight, &gdi->palette))
164 if (!planar_decompress(context->codecs->planar, pSrcData, SrcSize, DstWidth, DstHeight,
165 bitmap->data, bitmap->format, 0, 0, 0, DstWidth, DstHeight,
172 const UINT32 SrcFormat = gdi_get_pixel_format(bpp);
173 const size_t sbpp = GetBytesPerPixel(SrcFormat);
174 const size_t dbpp = GetBytesPerPixel(bitmap->format);
176 if ((sbpp == 0) || (dbpp == 0))
180 const size_t dstSize = SrcSize * dbpp / sbpp;
182 if (dstSize < bitmap->length)
186 if (!freerdp_image_copy(bitmap->data, bitmap->format, 0, 0, 0, DstWidth, DstHeight,
187 pSrcData, SrcFormat, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
194 static BOOL gdi_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary)
207 gdi->drawing = gdi->primary;
209 gdi->drawing = (gdiBitmap*)bitmap;
215 static BOOL gdi_Glyph_New(rdpContext* context, const rdpGlyph* glyph)
220 if (!context || !glyph)
223 gdi_glyph = (gdiGlyph*)glyph;
224 gdi_glyph->hdc = gdi_GetDC();
229 gdi_glyph->hdc->format = PIXEL_FORMAT_MONO;
230 data = freerdp_glyph_convert(glyph->cx, glyph->cy, glyph->aj);
234 gdi_DeleteDC(gdi_glyph->hdc);
238 gdi_glyph->bitmap = gdi_CreateBitmap(glyph->cx, glyph->cy, PIXEL_FORMAT_MONO, data);
240 if (!gdi_glyph->bitmap)
242 gdi_DeleteDC(gdi_glyph->hdc);
247 gdi_SelectObject(gdi_glyph->hdc, (HGDIOBJECT)gdi_glyph->bitmap);
248 gdi_glyph->org_bitmap = NULL;
252 static void gdi_Glyph_Free(rdpContext* context, rdpGlyph* glyph)
255 gdi_glyph = (gdiGlyph*)glyph;
259 gdi_SelectObject(gdi_glyph->hdc, (HGDIOBJECT)gdi_glyph->org_bitmap);
260 gdi_DeleteObject((HGDIOBJECT)gdi_glyph->bitmap);
261 gdi_DeleteDC(gdi_glyph->hdc);
267 static BOOL gdi_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x, INT32 y, INT32 w,
268 INT32 h, INT32 sx, INT32 sy, BOOL fOpRedundant)
275 if (!context || !glyph)
279 gdi_glyph = (gdiGlyph*)glyph;
281 if (!fOpRedundant && 0)
283 GDI_RECT rect = { 0 };
292 rect.right = x + w - 1;
295 rect.bottom = y + h - 1;
297 if ((rect.left < rect.right) && (rect.top < rect.bottom))
299 brush = gdi_CreateSolidBrush(gdi->drawing->hdc->bkColor);
304 gdi_FillRect(gdi->drawing->hdc, &rect, brush);
305 gdi_DeleteObject((HGDIOBJECT)brush);
309 brush = gdi_CreateSolidBrush(gdi->drawing->hdc->textColor);
314 gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT)brush);
315 rc = gdi_BitBlt(gdi->drawing->hdc, x, y, w, h, gdi_glyph->hdc, sx, sy, GDI_GLYPH_ORDER,
316 &context->gdi->palette);
317 gdi_DeleteObject((HGDIOBJECT)brush);
321 static BOOL gdi_Glyph_SetBounds(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height)
325 if (!context || !context->gdi)
330 if (!gdi->drawing || !gdi->drawing->hdc)
333 return gdi_SetClipRgn(gdi->drawing->hdc, x, y, width, height);
336 static BOOL gdi_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height,
337 UINT32 bgcolor, UINT32 fgcolor, BOOL fOpRedundant)
341 if (!context || !context->gdi)
346 if (!gdi->drawing || !gdi->drawing->hdc)
351 if (!gdi_decode_color(gdi, bgcolor, &bgcolor, NULL))
354 if (!gdi_decode_color(gdi, fgcolor, &fgcolor, NULL))
357 gdi_SetClipRgn(gdi->drawing->hdc, x, y, width, height);
358 gdi_SetTextColor(gdi->drawing->hdc, bgcolor);
359 gdi_SetBkColor(gdi->drawing->hdc, fgcolor);
363 GDI_RECT rect = { 0 };
364 HGDI_BRUSH brush = gdi_CreateSolidBrush(fgcolor);
375 rect.right = x + width - 1;
376 rect.bottom = y + height - 1;
378 if ((x + width > rect.left) && (y + height > rect.top))
379 gdi_FillRect(gdi->drawing->hdc, &rect, brush);
381 gdi_DeleteObject((HGDIOBJECT)brush);
384 return gdi_SetNullClipRgn(gdi->drawing->hdc);
390 static BOOL gdi_Glyph_EndDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height,
391 UINT32 bgcolor, UINT32 fgcolor)
395 if (!context || !context->gdi)
400 if (!gdi->drawing || !gdi->drawing->hdc)
403 gdi_SetNullClipRgn(gdi->drawing->hdc);
407 /* Graphics Module */
408 BOOL gdi_register_graphics(rdpGraphics* graphics)
412 bitmap.size = sizeof(gdiBitmap);
413 bitmap.New = gdi_Bitmap_New;
414 bitmap.Free = gdi_Bitmap_Free;
415 bitmap.Paint = gdi_Bitmap_Paint;
416 bitmap.Decompress = gdi_Bitmap_Decompress;
417 bitmap.SetSurface = gdi_Bitmap_SetSurface;
418 graphics_register_bitmap(graphics, &bitmap);
419 glyph.size = sizeof(gdiGlyph);
420 glyph.New = gdi_Glyph_New;
421 glyph.Free = gdi_Glyph_Free;
422 glyph.Draw = gdi_Glyph_Draw;
423 glyph.BeginDraw = gdi_Glyph_BeginDraw;
424 glyph.EndDraw = gdi_Glyph_EndDraw;
425 glyph.SetBounds = gdi_Glyph_SetBounds;
426 graphics_register_glyph(graphics, &glyph);