Merge pull request #2091 from ptsekov/software-gdi-improvements
[platform/upstream/freerdp.git] / client / Windows / wf_graphics.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * Windows Graphical Objects
4  *
5  * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <winpr/crt.h>
25
26 #include <freerdp/codecs.h>
27
28 #include "wf_gdi.h"
29 #include "wf_graphics.h"
30
31 HBITMAP wf_create_dib(wfContext* wfc, int width, int height, int bpp, BYTE* data, BYTE** pdata)
32 {
33         HDC hdc;
34         int negHeight;
35         HBITMAP bitmap;
36         BITMAPINFO bmi;
37         BYTE* cdata = NULL;
38
39         /**
40          * See: http://msdn.microsoft.com/en-us/library/dd183376
41          * if biHeight is positive, the bitmap is bottom-up
42          * if biHeight is negative, the bitmap is top-down
43          * Since we get top-down bitmaps, let's keep it that way
44          */
45
46         negHeight = (height < 0) ? height : height * (-1);
47
48         hdc = GetDC(NULL);
49         bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
50         bmi.bmiHeader.biWidth = width;
51         bmi.bmiHeader.biHeight = negHeight;
52         bmi.bmiHeader.biPlanes = 1;
53         bmi.bmiHeader.biBitCount = wfc->dstBpp;
54         bmi.bmiHeader.biCompression = BI_RGB;
55         bitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**) &cdata, NULL, 0);
56
57         if (data != NULL)
58                 freerdp_image_convert(data, cdata, width, height, bpp, wfc->dstBpp, wfc->clrconv);
59
60         if (pdata != NULL)
61                 *pdata = cdata;
62
63         ReleaseDC(NULL, hdc);
64         GdiFlush();
65
66         return bitmap;
67 }
68
69 wfBitmap* wf_image_new(wfContext* wfc, int width, int height, int bpp, BYTE* data)
70 {
71         HDC hdc;
72         wfBitmap* image;
73
74         hdc = GetDC(NULL);
75         image = (wfBitmap*) malloc(sizeof(wfBitmap));
76         image->hdc = CreateCompatibleDC(hdc);
77
78         image->bitmap = wf_create_dib(wfc, width, height, bpp, data, &(image->pdata));
79
80         image->org_bitmap = (HBITMAP) SelectObject(image->hdc, image->bitmap);
81         ReleaseDC(NULL, hdc);
82
83         return image;
84 }
85
86 void wf_image_free(wfBitmap* image)
87 {
88         if (image != 0)
89         {
90                 SelectObject(image->hdc, image->org_bitmap);
91                 DeleteObject(image->bitmap);
92                 DeleteDC(image->hdc);
93                 free(image);
94         }
95 }
96
97 /* Bitmap Class */
98
99 void wf_Bitmap_New(wfContext* wfc, rdpBitmap* bitmap)
100 {
101         HDC hdc;
102         wfBitmap* wf_bitmap = (wfBitmap*) bitmap;
103
104         wf_bitmap = (wfBitmap*) bitmap;
105
106         hdc = GetDC(NULL);
107         wf_bitmap->hdc = CreateCompatibleDC(hdc);
108
109         if (!bitmap->data)
110                 wf_bitmap->bitmap = CreateCompatibleBitmap(hdc, bitmap->width, bitmap->height);
111         else
112                 wf_bitmap->bitmap = wf_create_dib(wfc, bitmap->width, bitmap->height, bitmap->bpp, bitmap->data, NULL);
113
114         wf_bitmap->org_bitmap = (HBITMAP) SelectObject(wf_bitmap->hdc, wf_bitmap->bitmap);
115         ReleaseDC(NULL, hdc);
116 }
117
118 void wf_Bitmap_Free(wfContext* wfc, rdpBitmap* bitmap)
119 {
120         wfBitmap* wf_bitmap = (wfBitmap*) bitmap;
121
122         if (wf_bitmap != 0)
123         {
124                 SelectObject(wf_bitmap->hdc, wf_bitmap->org_bitmap);
125                 DeleteObject(wf_bitmap->bitmap);
126                 DeleteDC(wf_bitmap->hdc);
127         }
128 }
129
130 void wf_Bitmap_Paint(wfContext* wfc, rdpBitmap* bitmap)
131 {
132         int width, height;
133         wfBitmap* wf_bitmap = (wfBitmap*) bitmap;
134
135         width = bitmap->right - bitmap->left + 1;
136         height = bitmap->bottom - bitmap->top + 1;
137
138         BitBlt(wfc->primary->hdc, bitmap->left, bitmap->top,
139                 width, height, wf_bitmap->hdc, 0, 0, SRCCOPY);
140
141         wf_invalidate_region(wfc, bitmap->left, bitmap->top, width, height);
142 }
143
144 void wf_Bitmap_Decompress(wfContext* wfc, rdpBitmap* bitmap,
145                 BYTE* data, int width, int height, int bpp, int length, BOOL compressed, int codecId)
146 {
147         int status;
148         UINT16 size;
149
150         size = width * height * (bpp / 8);
151
152         if (!bitmap->data)
153                 bitmap->data = (BYTE*) _aligned_malloc(size, 16);
154         else
155                 bitmap->data = (BYTE*) _aligned_realloc(bitmap->data, size, 16);
156
157         if (compressed)
158         {
159                 BYTE* pDstData;
160                 UINT32 SrcSize;
161
162                 SrcSize = (UINT32) length;
163                 pDstData = bitmap->data;
164
165                 if (bpp < 32)
166                 {
167                         freerdp_client_codecs_prepare(wfc->codecs, FREERDP_CODEC_INTERLEAVED);
168
169                         status = interleaved_decompress(wfc->codecs->interleaved, data, SrcSize, bpp,
170                                         &pDstData, PIXEL_FORMAT_XRGB32_VF, width * 4, 0, 0, width, height);
171
172                         if (status < 0)
173                         {
174                                 DEBUG_WARN("wf_Bitmap_Decompress: Bitmap Decompression Failed\n");
175                         }
176                 }
177                 else
178                 {
179                         freerdp_client_codecs_prepare(wfc->codecs, FREERDP_CODEC_PLANAR);
180
181                         status = planar_decompress(wfc->codecs->planar, data, SrcSize, &pDstData,
182                                         PIXEL_FORMAT_XRGB32_VF, width * 4, 0, 0, width, height);
183
184                         if (status < 0)
185                         {
186                                 DEBUG_WARN("wf_Bitmap_Decompress: Bitmap Decompression Failed\n");
187                         }
188                 }
189         }
190         else
191         {
192                 freerdp_image_flip(data, bitmap->data, width, height, bpp);
193         }
194
195         bitmap->compressed = FALSE;
196         bitmap->length = size;
197         bitmap->bpp = bpp;
198 }
199
200 void wf_Bitmap_SetSurface(wfContext* wfc, rdpBitmap* bitmap, BOOL primary)
201 {
202         if (primary)
203                 wfc->drawing = wfc->primary;
204         else
205                 wfc->drawing = (wfBitmap*) bitmap;
206 }
207
208 /* Pointer Class */
209
210 void wf_Pointer_New(wfContext* wfc, rdpPointer* pointer)
211 {
212         HCURSOR hCur;
213         ICONINFO info;
214         BYTE *data;
215
216         info.fIcon = FALSE;
217         info.xHotspot = pointer->xPos;
218         info.yHotspot = pointer->yPos;
219         if (pointer->xorBpp == 1)
220         {
221                 data = (BYTE*) malloc(pointer->lengthAndMask + pointer->lengthXorMask);
222                 CopyMemory(data, pointer->andMaskData, pointer->lengthAndMask);
223                 CopyMemory(data + pointer->lengthAndMask, pointer->xorMaskData, pointer->lengthXorMask);
224                 info.hbmMask = CreateBitmap(pointer->width, pointer->height * 2, 1, 1, data);
225                 free(data);
226                 info.hbmColor = NULL;
227         }
228         else
229         {
230                 data = (BYTE*) malloc(pointer->lengthAndMask);
231                 freerdp_bitmap_flip(pointer->andMaskData, data, (pointer->width + 7) / 8, pointer->height);
232                 info.hbmMask = CreateBitmap(pointer->width, pointer->height, 1, 1, data);
233                 free(data);
234                 data = (BYTE*) malloc(pointer->lengthXorMask);
235                 freerdp_image_flip(pointer->xorMaskData, data, pointer->width, pointer->height, pointer->xorBpp);
236                 info.hbmColor = CreateBitmap(pointer->width, pointer->height, 1, pointer->xorBpp, data);
237                 free(data);
238         }
239         hCur = CreateIconIndirect(&info);
240         ((wfPointer*) pointer)->cursor = hCur;
241         if (info.hbmMask)
242                 DeleteObject(info.hbmMask);
243         if (info.hbmColor)
244                 DeleteObject(info.hbmColor);
245 }
246
247 void wf_Pointer_Free(wfContext* wfc, rdpPointer* pointer)
248 {
249         HCURSOR hCur;
250
251         hCur = ((wfPointer*) pointer)->cursor;
252
253         if (hCur != 0)
254                 DestroyIcon(hCur);
255 }
256
257 void wf_Pointer_Set(wfContext* wfc, rdpPointer* pointer)
258 {
259         HCURSOR hCur;
260
261         hCur = ((wfPointer*) pointer)->cursor;
262
263         if (hCur != NULL)
264         {
265                 SetCursor(hCur);
266                 wfc->cursor = hCur;
267         }
268 }
269
270 void wf_Pointer_SetNull(wfContext* wfc)
271 {
272
273 }
274
275 void wf_Pointer_SetDefault(wfContext* wfc)
276 {
277
278 }
279
280 /* Graphics Module */
281
282 void wf_register_graphics(rdpGraphics* graphics)
283 {
284         wfContext* wfc;
285         rdpPointer pointer;
286
287         wfc = (wfContext*) graphics->context;
288
289         if (wfc->sw_gdi == FALSE)
290         {
291                 rdpBitmap bitmap;
292
293                 ZeroMemory(&bitmap, sizeof(rdpBitmap));
294                 bitmap.size = sizeof(wfBitmap);
295                 bitmap.New = (pBitmap_New) wf_Bitmap_New;
296                 bitmap.Free = (pBitmap_Free) wf_Bitmap_Free;
297                 bitmap.Paint = (pBitmap_Paint) wf_Bitmap_Paint;
298                 bitmap.Decompress = (pBitmap_Decompress) wf_Bitmap_Decompress;
299                 bitmap.SetSurface = (pBitmap_SetSurface) wf_Bitmap_SetSurface;
300
301                 graphics_register_bitmap(graphics, &bitmap);
302         }
303
304         ZeroMemory(&pointer, sizeof(rdpPointer));
305         pointer.size = sizeof(wfPointer);
306         pointer.New = (pPointer_New) wf_Pointer_New;
307         pointer.Free = (pPointer_Free) wf_Pointer_Free;
308         pointer.Set = (pPointer_Set) wf_Pointer_Set;
309         pointer.SetNull = (pPointer_SetNull) wf_Pointer_SetNull;
310         pointer.SetDefault = (pPointer_SetDefault) wf_Pointer_SetDefault;
311
312         graphics_register_pointer(graphics, &pointer);
313 }