ba66fed00d5b8acf7e93535b018cd52d07304d25
[platform/upstream/freerdp.git] / libfreerdp-gdi / gdi.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * GDI Library
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 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <freerdp/api.h>
24 #include <freerdp/freerdp.h>
25 #include <freerdp/constants.h>
26 #include <freerdp/utils/bitmap.h>
27 #include <freerdp/codec/color.h>
28 #include <freerdp/codec/bitmap.h>
29 #include <freerdp/codec/rfx.h>
30 #include <freerdp/codec/nsc.h>
31
32 #include <freerdp/gdi/dc.h>
33 #include <freerdp/gdi/pen.h>
34 #include <freerdp/gdi/line.h>
35 #include <freerdp/gdi/shape.h>
36 #include <freerdp/gdi/brush.h>
37 #include <freerdp/gdi/region.h>
38 #include <freerdp/gdi/bitmap.h>
39 #include <freerdp/gdi/palette.h>
40 #include <freerdp/gdi/drawing.h>
41 #include <freerdp/gdi/clipping.h>
42
43 #include <freerdp/gdi/gdi.h>
44
45 /* Ternary Raster Operation Table */
46 const uint32 rop3_code_table[] =
47 {
48         0x00000042, /* 0 */
49         0x00010289, /* DPSoon */
50         0x00020C89, /* DPSona */
51         0x000300AA, /* PSon */
52         0x00040C88, /* SDPona */
53         0x000500A9, /* DPon */
54         0x00060865, /* PDSxnon */
55         0x000702C5, /* PDSaon */
56         0x00080F08, /* SDPnaa */
57         0x00090245, /* PDSxon */
58         0x000A0329, /* DPna */
59         0x000B0B2A, /* PSDnaon */
60         0x000C0324, /* SPna */
61         0x000D0B25, /* PDSnaon */
62         0x000E08A5, /* PDSonon */
63         0x000F0001, /* Pn */
64         0x00100C85, /* PDSona */
65         0x001100A6, /* DSon */
66         0x00120868, /* SDPxnon */
67         0x001302C8, /* SDPaon */
68         0x00140869, /* DPSxnon */
69         0x001502C9, /* DPSaon */
70         0x00165CCA, /* PSDPSanaxx */
71         0x00171D54, /* SSPxDSxaxn */
72         0x00180D59, /* SPxPDxa */
73         0x00191CC8, /* SDPSanaxn */
74         0x001A06C5, /* PDSPaox */
75         0x001B0768, /* SDPSxaxn */
76         0x001C06CA, /* PSDPaox */
77         0x001D0766, /* DSPDxaxn */
78         0x001E01A5, /* PDSox */
79         0x001F0385, /* PDSoan */
80         0x00200F09, /* DPSnaa */
81         0x00210248, /* SDPxon */
82         0x00220326, /* DSna */
83         0x00230B24, /* SPDnaon */
84         0x00240D55, /* SPxDSxa */
85         0x00251CC5, /* PDSPanaxn */
86         0x002606C8, /* SDPSaox */
87         0x00271868, /* SDPSxnox */
88         0x00280369, /* DPSxa */
89         0x002916CA, /* PSDPSaoxxn */
90         0x002A0CC9, /* DPSana */
91         0x002B1D58, /* SSPxPDxaxn */
92         0x002C0784, /* SPDSoax */
93         0x002D060A, /* PSDnox */
94         0x002E064A, /* PSDPxox */
95         0x002F0E2A, /* PSDnoan */
96         0x0030032A, /* PSna */
97         0x00310B28, /* SDPnaon */
98         0x00320688, /* SDPSoox */
99         0x00330008, /* Sn */
100         0x003406C4, /* SPDSaox */
101         0x00351864, /* SPDSxnox */
102         0x003601A8, /* SDPox */
103         0x00370388, /* SDPoan */
104         0x0038078A, /* PSDPoax */
105         0x00390604, /* SPDnox */
106         0x003A0644, /* SPDSxox */
107         0x003B0E24, /* SPDnoan */
108         0x003C004A, /* PSx */
109         0x003D18A4, /* SPDSonox */
110         0x003E1B24, /* SPDSnaox */
111         0x003F00EA, /* PSan */
112         0x00400F0A, /* PSDnaa */
113         0x00410249, /* DPSxon */
114         0x00420D5D, /* SDxPDxa */
115         0x00431CC4, /* SPDSanaxn */
116         0x00440328, /* SDna */
117         0x00450B29, /* DPSnaon */
118         0x004606C6, /* DSPDaox */
119         0x0047076A, /* PSDPxaxn */
120         0x00480368, /* SDPxa */
121         0x004916C5, /* PDSPDaoxxn */
122         0x004A0789, /* DPSDoax */
123         0x004B0605, /* PDSnox */
124         0x004C0CC8, /* SDPana */
125         0x004D1954, /* SSPxDSxoxn */
126         0x004E0645, /* PDSPxox */
127         0x004F0E25, /* PDSnoan */
128         0x00500325, /* PDna */
129         0x00510B26, /* DSPnaon */
130         0x005206C9, /* DPSDaox */
131         0x00530764, /* SPDSxaxn */
132         0x005408A9, /* DPSonon */
133         0x00550009, /* Dn */
134         0x005601A9, /* DPSox */
135         0x00570389, /* DPSoan */
136         0x00580785, /* PDSPoax */
137         0x00590609, /* DPSnox */
138         0x005A0049, /* DPx */
139         0x005B18A9, /* DPSDonox */
140         0x005C0649, /* DPSDxox */
141         0x005D0E29, /* DPSnoan */
142         0x005E1B29, /* DPSDnaox */
143         0x005F00E9, /* DPan */
144         0x00600365, /* PDSxa */
145         0x006116C6, /* DSPDSaoxxn */
146         0x00620786, /* DSPDoax */
147         0x00630608, /* SDPnox */
148         0x00640788, /* SDPSoax */
149         0x00650606, /* DSPnox */
150         0x00660046, /* DSx */
151         0x006718A8, /* SDPSonox */
152         0x006858A6, /* DSPDSonoxxn */
153         0x00690145, /* PDSxxn */
154         0x006A01E9, /* DPSax */
155         0x006B178A, /* PSDPSoaxxn */
156         0x006C01E8, /* SDPax */
157         0x006D1785, /* PDSPDoaxxn */
158         0x006E1E28, /* SDPSnoax */
159         0x006F0C65, /* PDSxnan */
160         0x00700CC5, /* PDSana */
161         0x00711D5C, /* SSDxPDxaxn */
162         0x00720648, /* SDPSxox */
163         0x00730E28, /* SDPnoan */
164         0x00740646, /* DSPDxox */
165         0x00750E26, /* DSPnoan */
166         0x00761B28, /* SDPSnaox */
167         0x007700E6, /* DSan */
168         0x007801E5, /* PDSax */
169         0x00791786, /* DSPDSoaxxn */
170         0x007A1E29, /* DPSDnoax */
171         0x007B0C68, /* SDPxnan */
172         0x007C1E24, /* SPDSnoax */
173         0x007D0C69, /* DPSxnan */
174         0x007E0955, /* SPxDSxo */
175         0x007F03C9, /* DPSaan */
176         0x008003E9, /* DPSaa */
177         0x00810975, /* SPxDSxon */
178         0x00820C49, /* DPSxna */
179         0x00831E04, /* SPDSnoaxn */
180         0x00840C48, /* SDPxna */
181         0x00851E05, /* PDSPnoaxn */
182         0x008617A6, /* DSPDSoaxx */
183         0x008701C5, /* PDSaxn */
184         0x008800C6, /* DSa */
185         0x00891B08, /* SDPSnaoxn */
186         0x008A0E06, /* DSPnoa */
187         0x008B0666, /* DSPDxoxn */
188         0x008C0E08, /* SDPnoa */
189         0x008D0668, /* SDPSxoxn */
190         0x008E1D7C, /* SSDxPDxax */
191         0x008F0CE5, /* PDSanan */
192         0x00900C45, /* PDSxna */
193         0x00911E08, /* SDPSnoaxn */
194         0x009217A9, /* DPSDPoaxx */
195         0x009301C4, /* SPDaxn */
196         0x009417AA, /* PSDPSoaxx */
197         0x009501C9, /* DPSaxn */
198         0x00960169, /* DPSxx */
199         0x0097588A, /* PSDPSonoxx */
200         0x00981888, /* SDPSonoxn */
201         0x00990066, /* DSxn */
202         0x009A0709, /* DPSnax */
203         0x009B07A8, /* SDPSoaxn */
204         0x009C0704, /* SPDnax */
205         0x009D07A6, /* DSPDoaxn */
206         0x009E16E6, /* DSPDSaoxx */
207         0x009F0345, /* PDSxan */
208         0x00A000C9, /* DPa */
209         0x00A11B05, /* PDSPnaoxn */
210         0x00A20E09, /* DPSnoa */
211         0x00A30669, /* DPSDxoxn */
212         0x00A41885, /* PDSPonoxn */
213         0x00A50065, /* PDxn */
214         0x00A60706, /* DSPnax */
215         0x00A707A5, /* PDSPoaxn */
216         0x00A803A9, /* DPSoa */
217         0x00A90189, /* DPSoxn */
218         0x00AA0029, /* D */
219         0x00AB0889, /* DPSono */
220         0x00AC0744, /* SPDSxax */
221         0x00AD06E9, /* DPSDaoxn */
222         0x00AE0B06, /* DSPnao */
223         0x00AF0229, /* DPno */
224         0x00B00E05, /* PDSnoa */
225         0x00B10665, /* PDSPxoxn */
226         0x00B21974, /* SSPxDSxox */
227         0x00B30CE8, /* SDPanan */
228         0x00B4070A, /* PSDnax */
229         0x00B507A9, /* DPSDoaxn */
230         0x00B616E9, /* DPSDPaoxx */
231         0x00B70348, /* SDPxan */
232         0x00B8074A, /* PSDPxax */
233         0x00B906E6, /* DSPDaoxn */
234         0x00BA0B09, /* DPSnao */
235         0x00BB0226, /* DSno */
236         0x00BC1CE4, /* SPDSanax */
237         0x00BD0D7D, /* SDxPDxan */
238         0x00BE0269, /* DPSxo */
239         0x00BF08C9, /* DPSano */
240         0x00C000CA, /* PSa */
241         0x00C11B04, /* SPDSnaoxn */
242         0x00C21884, /* SPDSonoxn */
243         0x00C3006A, /* PSxn */
244         0x00C40E04, /* SPDnoa */
245         0x00C50664, /* SPDSxoxn */
246         0x00C60708, /* SDPnax */
247         0x00C707AA, /* PSDPoaxn */
248         0x00C803A8, /* SDPoa */
249         0x00C90184, /* SPDoxn */
250         0x00CA0749, /* DPSDxax */
251         0x00CB06E4, /* SPDSaoxn */
252         0x00CC0020, /* S */
253         0x00CD0888, /* SDPono */
254         0x00CE0B08, /* SDPnao */
255         0x00CF0224, /* SPno */
256         0x00D00E0A, /* PSDnoa */
257         0x00D1066A, /* PSDPxoxn */
258         0x00D20705, /* PDSnax */
259         0x00D307A4, /* SPDSoaxn */
260         0x00D41D78, /* SSPxPDxax */
261         0x00D50CE9, /* DPSanan */
262         0x00D616EA, /* PSDPSaoxx */
263         0x00D70349, /* DPSxan */
264         0x00D80745, /* PDSPxax */
265         0x00D906E8, /* SDPSaoxn */
266         0x00DA1CE9, /* DPSDanax */
267         0x00DB0D75, /* SPxDSxan */
268         0x00DC0B04, /* SPDnao */
269         0x00DD0228, /* SDno */
270         0x00DE0268, /* SDPxo */
271         0x00DF08C8, /* SDPano */
272         0x00E003A5, /* PDSoa */
273         0x00E10185, /* PDSoxn */
274         0x00E20746, /* DSPDxax */
275         0x00E306EA, /* PSDPaoxn */
276         0x00E40748, /* SDPSxax */
277         0x00E506E5, /* PDSPaoxn */
278         0x00E61CE8, /* SDPSanax */
279         0x00E70D79, /* SPxPDxan */
280         0x00E81D74, /* SSPxDSxax */
281         0x00E95CE6, /* DSPDSanaxxn */
282         0x00EA02E9, /* DPSao */
283         0x00EB0849, /* DPSxno */
284         0x00EC02E8, /* SDPao */
285         0x00ED0848, /* SDPxno */
286         0x00EE0086, /* DSo */
287         0x00EF0A08, /* SDPnoo */
288         0x00F00021, /* P */
289         0x00F10885, /* PDSono */
290         0x00F20B05, /* PDSnao */
291         0x00F3022A, /* PSno */
292         0x00F40B0A, /* PSDnao */
293         0x00F50225, /* PDno */
294         0x00F60265, /* PDSxo */
295         0x00F708C5, /* PDSano */
296         0x00F802E5, /* PDSao */
297         0x00F90845, /* PDSxno */
298         0x00FA0089, /* DPo */
299         0x00FB0A09, /* DPSnoo */
300         0x00FC008A, /* PSo */
301         0x00FD0A0A, /* PSDnoo */
302         0x00FE02A9, /* DPSoo */
303         0x00FF0062  /* 1 */
304 };
305
306 /* GDI Helper Functions */
307
308 INLINE uint32 gdi_rop3_code(uint8 code)
309 {
310         return rop3_code_table[code];
311 }
312
313 INLINE uint8* gdi_get_bitmap_pointer(HGDI_DC hdcBmp, int x, int y)
314 {
315         uint8 * p;
316         HGDI_BITMAP hBmp = (HGDI_BITMAP) hdcBmp->selectedObject;
317         
318         if (x >= 0 && x < hBmp->width && y >= 0 && y < hBmp->height)
319         {
320                 p = hBmp->data + (y * hBmp->width * hdcBmp->bytesPerPixel) + (x * hdcBmp->bytesPerPixel);
321                 return p;
322         }
323         else
324         {
325                 printf("gdi_get_bitmap_pointer: requesting invalid pointer: (%d,%d) in %dx%d\n", x, y, hBmp->width, hBmp->height);
326                 return 0;
327         }
328 }
329
330 INLINE uint8* gdi_get_brush_pointer(HGDI_DC hdcBrush, int x, int y)
331 {
332         uint8 * p;
333
334         if (hdcBrush->brush != NULL)
335         {
336                 if (hdcBrush->brush->style == GDI_BS_PATTERN)
337                 {
338                         HGDI_BITMAP hBmpBrush = hdcBrush->brush->pattern;
339         
340                         if (x >= 0 && y >= 0)
341                         {
342                                 x = x % hBmpBrush->width;
343                                 y = y % hBmpBrush->height;
344                                 p = hBmpBrush->data + (y * hBmpBrush->scanline) + (x * hBmpBrush->bytesPerPixel);
345                                 return p;
346                         }
347                 }
348         }
349
350         p = (uint8*) &(hdcBrush->textColor);
351         return p;
352 }
353
354 INLINE int gdi_is_mono_pixel_set(uint8* data, int x, int y, int width)
355 {
356         int byte;
357         int shift;
358
359         width = (width + 7) / 8;
360         byte = (y * width) + (x / 8);
361         shift = x % 8;
362
363         return (data[byte] & (0x80 >> shift)) != 0;
364 }
365
366 HGDI_BITMAP gdi_create_bitmap(GDI* gdi, int width, int height, int bpp, uint8* data)
367 {
368         uint8* bmpData;
369         HGDI_BITMAP bitmap;
370         
371         bmpData = freerdp_image_convert(data, NULL, width, height, gdi->srcBpp, bpp, gdi->clrconv);
372         bitmap = gdi_CreateBitmap(width, height, gdi->dstBpp, bmpData);
373         
374         return bitmap;
375 }
376
377 GDI_IMAGE* gdi_bitmap_new(GDI* gdi, int width, int height, int bpp, uint8* data)
378 {
379         GDI_IMAGE *gdi_bmp;
380         
381         gdi_bmp = (GDI_IMAGE*) malloc(sizeof(GDI_IMAGE));
382         gdi_bmp->hdc = gdi_CreateCompatibleDC(gdi->hdc);
383         
384         DEBUG_GDI("gdi_bitmap_new: width:%d height:%d bpp:%d", width, height, bpp);
385
386         if (data == NULL)
387         {
388                 gdi_bmp->bitmap = gdi_CreateCompatibleBitmap(gdi->hdc, width, height);
389         }
390         else
391         {
392                 gdi_bmp->bitmap = gdi_create_bitmap(gdi, width, height, bpp, data);
393         }
394         
395         gdi_SelectObject(gdi_bmp->hdc, (HGDIOBJECT) gdi_bmp->bitmap);
396         gdi_bmp->org_bitmap = NULL;
397
398         return gdi_bmp;
399 }
400
401 void gdi_bitmap_free(GDI_IMAGE *gdi_bmp)
402 {
403         if (gdi_bmp != 0)
404         {
405                 gdi_SelectObject(gdi_bmp->hdc, (HGDIOBJECT) gdi_bmp->org_bitmap);
406                 gdi_DeleteObject((HGDIOBJECT) gdi_bmp->bitmap);
407                 gdi_DeleteDC(gdi_bmp->hdc);
408                 free(gdi_bmp);
409         }
410 }
411
412 GDI_IMAGE* gdi_glyph_new(GDI* gdi, GLYPH_DATA* glyph)
413 {
414         uint8* extra;
415         GDI_IMAGE* gdi_bmp;
416
417         gdi_bmp = (GDI_IMAGE*) malloc(sizeof(GDI_IMAGE));
418
419         gdi_bmp->hdc = gdi_GetDC();
420         gdi_bmp->hdc->bytesPerPixel = 1;
421         gdi_bmp->hdc->bitsPerPixel = 1;
422
423         extra = freerdp_glyph_convert(glyph->cx, glyph->cy, glyph->aj);
424         gdi_bmp->bitmap = gdi_CreateBitmap(glyph->cx, glyph->cy, 1, extra);
425         gdi_bmp->bitmap->bytesPerPixel = 1;
426         gdi_bmp->bitmap->bitsPerPixel = 1;
427
428         gdi_SelectObject(gdi_bmp->hdc, (HGDIOBJECT) gdi_bmp->bitmap);
429         gdi_bmp->org_bitmap = NULL;
430
431         return gdi_bmp;
432 }
433
434 void gdi_glyph_free(GDI_IMAGE *gdi_bmp)
435 {
436         if (gdi_bmp != 0)
437         {
438                 gdi_SelectObject(gdi_bmp->hdc, (HGDIOBJECT) gdi_bmp->org_bitmap);
439                 gdi_DeleteObject((HGDIOBJECT) gdi_bmp->bitmap);
440                 gdi_DeleteDC(gdi_bmp->hdc);
441                 free(gdi_bmp);
442         }
443 }
444
445 void gdi_bitmap_update(rdpUpdate* update, BITMAP_UPDATE* bitmap)
446 {
447         int i;
448         BITMAP_DATA* bmp;
449         GDI_IMAGE* gdi_bmp;
450         GDI* gdi = GET_GDI(update);
451
452         for (i = 0; i < bitmap->number; i++)
453         {
454                 bmp = &bitmap->bitmaps[i];
455
456                 gdi_bmp = gdi_bitmap_new(gdi, bmp->width, bmp->height, gdi->dstBpp, bmp->dstData);
457
458                 gdi_BitBlt(gdi->primary->hdc,
459                                 bmp->left, bmp->top, bmp->right - bmp->left + 1,
460                                 bmp->bottom - bmp->top + 1, gdi_bmp->hdc, 0, 0, GDI_SRCCOPY);
461
462                 gdi_bitmap_free((GDI_IMAGE*) gdi_bmp);
463         }
464 }
465
466 void gdi_palette_update(rdpUpdate* update, PALETTE_UPDATE* palette)
467 {
468
469 }
470
471 void gdi_set_bounds(rdpUpdate* update, BOUNDS* bounds)
472 {
473         GDI* gdi = GET_GDI(update);
474
475         if (bounds != NULL)
476         {
477                 gdi_SetClipRgn(gdi->drawing->hdc, bounds->left, bounds->top,
478                                 bounds->right - bounds->left + 1, bounds->bottom - bounds->top + 1);
479         }
480         else
481         {
482                 gdi_SetNullClipRgn(gdi->drawing->hdc);
483         }
484 }
485
486 void gdi_dstblt(rdpUpdate* update, DSTBLT_ORDER* dstblt)
487 {
488         GDI* gdi = GET_GDI(update);
489
490         gdi_BitBlt(gdi->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect,
491                         dstblt->nWidth, dstblt->nHeight, NULL, 0, 0, gdi_rop3_code(dstblt->bRop));
492 }
493
494 void gdi_patblt(rdpUpdate* update, PATBLT_ORDER* patblt)
495 {
496         uint8* data;
497         BRUSH* brush;
498         HGDI_BRUSH originalBrush;
499         GDI* gdi = GET_GDI(update);
500
501         brush = &patblt->brush;
502
503         if (brush->style & CACHED_BRUSH)
504         {
505                 brush->data = brush_get(gdi->cache->brush, brush->index, &brush->bpp);
506                 brush->style = GDI_BS_PATTERN;
507         }
508
509         if (brush->style == GDI_BS_SOLID)
510         {
511                 uint32 color;
512                 originalBrush = gdi->drawing->hdc->brush;
513
514                 color = freerdp_color_convert(patblt->foreColor, gdi->srcBpp, 32, gdi->clrconv);
515                 gdi->drawing->hdc->brush = gdi_CreateSolidBrush(color);
516
517                 gdi_PatBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect,
518                                 patblt->nWidth, patblt->nHeight, gdi_rop3_code(patblt->bRop));
519
520                 gdi_DeleteObject((HGDIOBJECT) gdi->drawing->hdc->brush);
521                 gdi->drawing->hdc->brush = originalBrush;
522         }
523         else if (brush->style == GDI_BS_PATTERN)
524         {
525                 HGDI_BITMAP hBmp;
526
527                 if (brush->bpp > 1)
528                 {
529                         data = freerdp_image_convert(brush->data, NULL, 8, 8, gdi->srcBpp, gdi->dstBpp, gdi->clrconv);
530                 }
531                 else
532                 {
533                         data = freerdp_mono_image_convert(brush->data, 8, 8, gdi->srcBpp, gdi->dstBpp,
534                                 patblt->backColor, patblt->foreColor, gdi->clrconv);
535                 }
536
537                 hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->bitsPerPixel, data);
538
539                 originalBrush = gdi->drawing->hdc->brush;
540                 gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);
541
542                 gdi_PatBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect,
543                                 patblt->nWidth, patblt->nHeight, gdi_rop3_code(patblt->bRop));
544
545                 gdi_DeleteObject((HGDIOBJECT) gdi->drawing->hdc->brush);
546                 gdi->drawing->hdc->brush = originalBrush;
547         }
548         else
549         {
550                 printf("unimplemented brush style:%d\n", brush->style);
551         }
552 }
553
554 void gdi_scrblt(rdpUpdate* update, SCRBLT_ORDER* scrblt)
555 {
556         GDI* gdi = GET_GDI(update);
557
558         gdi_BitBlt(gdi->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect,
559                         scrblt->nWidth, scrblt->nHeight, gdi->primary->hdc,
560                         scrblt->nXSrc, scrblt->nYSrc, gdi_rop3_code(scrblt->bRop));
561 }
562
563 void gdi_opaque_rect(rdpUpdate* update, OPAQUE_RECT_ORDER* opaque_rect)
564 {
565         GDI_RECT rect;
566         HGDI_BRUSH hBrush;
567         uint32 brush_color;
568         GDI *gdi = GET_GDI(update);
569
570         gdi_CRgnToRect(opaque_rect->nLeftRect, opaque_rect->nTopRect,
571                         opaque_rect->nWidth, opaque_rect->nHeight, &rect);
572
573         brush_color = freerdp_color_convert(opaque_rect->color, gdi->srcBpp, 32, gdi->clrconv);
574
575         hBrush = gdi_CreateSolidBrush(brush_color);
576         gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
577
578         gdi_DeleteObject((HGDIOBJECT) hBrush);
579 }
580
581 void gdi_multi_opaque_rect(rdpUpdate* update, MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
582 {
583         int i;
584         GDI_RECT rect;
585         HGDI_BRUSH hBrush;
586         uint32 brush_color;
587         DELTA_RECT* rectangle;
588         GDI *gdi = GET_GDI(update);
589
590         for (i = 1; i < multi_opaque_rect->numRectangles + 1; i++)
591         {
592                 rectangle = &multi_opaque_rect->rectangles[i];
593
594                 gdi_CRgnToRect(rectangle->left, rectangle->top,
595                                 rectangle->width, rectangle->height, &rect);
596
597                 brush_color = freerdp_color_convert(multi_opaque_rect->color, gdi->srcBpp, 32, gdi->clrconv);
598
599                 hBrush = gdi_CreateSolidBrush(brush_color);
600                 gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
601
602                 gdi_DeleteObject((HGDIOBJECT) hBrush);
603         }
604 }
605
606 void gdi_line_to(rdpUpdate* update, LINE_TO_ORDER* line_to)
607 {
608         uint32 color;
609         HGDI_PEN hPen;
610         GDI *gdi = GET_GDI(update);
611
612         color = freerdp_color_convert(line_to->penColor, gdi->srcBpp, 32, gdi->clrconv);
613         hPen = gdi_CreatePen(line_to->penStyle, line_to->penWidth, (GDI_COLOR) color);
614         gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT) hPen);
615         gdi_SetROP2(gdi->drawing->hdc, line_to->bRop2);
616
617         gdi_MoveToEx(gdi->drawing->hdc, line_to->nXStart, line_to->nYStart, NULL);
618         gdi_LineTo(gdi->drawing->hdc, line_to->nXEnd, line_to->nYEnd);
619
620         gdi_DeleteObject((HGDIOBJECT) hPen);
621 }
622
623 void gdi_polyline(rdpUpdate* update, POLYLINE_ORDER* polyline)
624 {
625         int i;
626         uint32 color;
627         HGDI_PEN hPen;
628         DELTA_POINT* points;
629         GDI *gdi = GET_GDI(update);
630
631         color = freerdp_color_convert(polyline->penColor, gdi->srcBpp, 32, gdi->clrconv);
632         hPen = gdi_CreatePen(0, 1, (GDI_COLOR) color);
633         gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT) hPen);
634         gdi_SetROP2(gdi->drawing->hdc, polyline->bRop2);
635
636         gdi_MoveToEx(gdi->drawing->hdc, polyline->xStart, polyline->yStart, NULL);
637
638         points = polyline->points;
639         for (i = 0; i < polyline->numPoints; i++)
640         {
641                 gdi_LineTo(gdi->drawing->hdc, points[i].x, points[i].y);
642                 gdi_MoveToEx(gdi->drawing->hdc, points[i].x, points[i].y, NULL);
643         }
644
645         gdi_DeleteObject((HGDIOBJECT) hPen);
646 }
647
648 void gdi_fast_index(rdpUpdate* update, FAST_INDEX_ORDER* fast_index)
649 {
650         int i, j;
651         int x, y;
652         GDI_RECT rect;
653         uint32 bgcolor;
654         uint32 fgcolor;
655         HGDI_BRUSH brush;
656         GDI_IMAGE* bmp;
657         GDI_IMAGE** bmps;
658         GLYPH_DATA* glyph;
659         GLYPH_DATA** glyphs;
660         GLYPH_FRAGMENT* fragment;
661         GDI* gdi = GET_GDI(update);
662
663         x = fast_index->bkLeft;
664         y = fast_index->y;
665
666         bgcolor = freerdp_color_convert(fast_index->backColor, gdi->srcBpp, 32, gdi->clrconv);
667         fgcolor = freerdp_color_convert(fast_index->foreColor, gdi->srcBpp, 32, gdi->clrconv);
668         gdi->textColor = gdi_SetTextColor(gdi->drawing->hdc, bgcolor);
669         gdi_SetNullClipRgn(gdi->drawing->hdc);
670         brush = gdi_CreateSolidBrush(fgcolor);
671
672         if (fast_index->opaqueRect)
673         {
674                 gdi_SetRect(&rect, fast_index->opLeft, fast_index->opTop, fast_index->opRight, fast_index->opBottom);
675                 gdi_FillRect(gdi->drawing->hdc, &rect, brush);
676         }
677
678         for (i = 0; i < fast_index->nfragments; i++)
679         {
680                 fragment = &fast_index->fragments[i];
681
682                 if (fragment->operation == GLYPH_FRAGMENT_USE)
683                 {
684                         fragment->indices = (GLYPH_FRAGMENT_INDEX*) glyph_fragment_get(gdi->cache->glyph,
685                                                         fragment->index, &fragment->nindices, (void**) &bmps);
686
687                         glyphs = (GLYPH_DATA**) xmalloc(sizeof(GLYPH_DATA*) * fragment->nindices);
688
689                         for (j = 0; j < fragment->nindices; j++)
690                         {
691                                 glyphs[j] = glyph_get(gdi->cache->glyph, fast_index->cacheId, fragment->indices[j].index, (void**) &bmps[j]);
692                         }
693                 }
694                 else
695                 {
696                         bmps = (GDI_IMAGE**) xmalloc(sizeof(GDI_IMAGE*) * fragment->nindices);
697                         glyphs = (GLYPH_DATA**) xmalloc(sizeof(GLYPH_DATA*) * fragment->nindices);
698
699                         for (j = 0; j < fragment->nindices; j++)
700                         {
701                                 glyphs[j] = glyph_get(gdi->cache->glyph, fast_index->cacheId, fragment->indices[j].index, (void**) &bmps[j]);
702                         }
703                 }
704
705                 for (j = 0; j < fragment->nindices; j++)
706                 {
707                         bmp = bmps[j];
708                         glyph = glyphs[j];
709
710                         if (bmp == NULL || glyph == NULL)
711                                 continue;
712
713                         gdi_BitBlt(gdi->drawing->hdc, glyph->x + x, glyph->y + y, bmp->bitmap->width,
714                                         bmp->bitmap->height, bmp->hdc, 0, 0, GDI_DSPDxax);
715
716                         if ((j + 1) < fragment->nindices)
717                         {
718                                 if (!(fast_index->flAccel & SO_CHAR_INC_EQUAL_BM_BASE))
719                                 {
720                                         if (fast_index->flAccel & SO_VERTICAL)
721                                         {
722                                                 y += fragment->indices[j + 1].delta;
723                                         }
724                                         else
725                                         {
726                                                 x += fragment->indices[j + 1].delta;
727                                         }
728                                 }
729                                 else
730                                 {
731                                         x += glyph->cx;
732                                 }
733                         }
734                 }
735
736                 if (fragment->operation == GLYPH_FRAGMENT_ADD)
737                 {
738                         glyph_fragment_put(gdi->cache->glyph, fragment->index,
739                                         fragment->nindices, (void*) fragment->indices, (void*) bmps);
740                 }
741         }
742
743         gdi_SetTextColor(gdi->drawing->hdc, gdi->textColor);
744         gdi_DeleteObject((HGDIOBJECT) brush);
745 }
746
747 void gdi_create_offscreen_bitmap(rdpUpdate* update, CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)
748 {
749         GDI_IMAGE* gdi_bmp;
750         GDI* gdi = GET_GDI(update);
751
752         gdi_bmp = gdi_bitmap_new(gdi, create_offscreen_bitmap->cx, create_offscreen_bitmap->cy, gdi->dstBpp, NULL);
753
754         offscreen_put(gdi->cache->offscreen, create_offscreen_bitmap->id, (void*) gdi_bmp);
755 }
756
757 void gdi_switch_surface(rdpUpdate* update, SWITCH_SURFACE_ORDER* switch_surface)
758 {
759         GDI_IMAGE* gdi_bmp;
760         GDI* gdi = GET_GDI(update);
761
762         if (switch_surface->bitmapId == SCREEN_BITMAP_SURFACE)
763         {
764                 gdi->drawing = (GDI_IMAGE*) gdi->primary;
765         }
766         else
767         {
768                 gdi_bmp = (GDI_IMAGE*) offscreen_get(gdi->cache->offscreen, switch_surface->bitmapId);
769                 gdi->drawing = gdi_bmp;
770         }
771 }
772
773 void gdi_cache_bitmap_v2(rdpUpdate* update, CACHE_BITMAP_V2_ORDER* cache_bitmap_v2)
774 {
775         GDI* gdi = GET_GDI(update);
776
777         bitmap_v2_put(gdi->cache->bitmap_v2, cache_bitmap_v2->cacheId,
778                         cache_bitmap_v2->cacheIndex, cache_bitmap_v2->bitmapDataStream);
779 }
780
781 void gdi_cache_color_table(rdpUpdate* update, CACHE_COLOR_TABLE_ORDER* cache_color_table)
782 {
783         GDI* gdi = GET_GDI(update);
784         color_table_put(gdi->cache->color_table, cache_color_table->cacheIndex, (void*) cache_color_table->colorTable);
785 }
786
787 void gdi_cache_glyph(rdpUpdate* update, CACHE_GLYPH_ORDER* cache_glyph)
788 {
789         int i;
790         GLYPH_DATA* glyph;
791         GDI_IMAGE* gdi_bmp;
792         GDI* gdi = GET_GDI(update);
793
794         for (i = 0; i < cache_glyph->cGlyphs; i++)
795         {
796                 glyph = cache_glyph->glyphData[i];
797                 gdi_bmp = gdi_glyph_new(gdi, glyph);
798                 glyph_put(gdi->cache->glyph, cache_glyph->cacheId, glyph->cacheIndex, glyph, (void*) gdi_bmp);
799         }
800 }
801
802 void gdi_cache_glyph_v2(rdpUpdate* update, CACHE_GLYPH_V2_ORDER* cache_glyph_v2)
803 {
804         int i;
805         uint8* extra;
806         GLYPH_DATA_V2* glyph;
807         GDI_IMAGE* gdi_bmp;
808         GDI* gdi = GET_GDI(update);
809
810         for (i = 0; i < cache_glyph_v2->cGlyphs; i++)
811         {
812                 glyph = cache_glyph_v2->glyphData[i];
813                 gdi_bmp = (GDI_IMAGE*) malloc(sizeof(GDI_IMAGE));
814
815                 gdi_bmp->hdc = gdi_GetDC();
816                 gdi_bmp->hdc->bytesPerPixel = 1;
817                 gdi_bmp->hdc->bitsPerPixel = 1;
818
819                 extra = freerdp_glyph_convert(glyph->cx, glyph->cy, glyph->aj);
820                 gdi_bmp->bitmap = gdi_CreateBitmap(glyph->cx, glyph->cy, 1, extra);
821                 gdi_bmp->bitmap->bytesPerPixel = 1;
822                 gdi_bmp->bitmap->bitsPerPixel = 1;
823
824                 gdi_SelectObject(gdi_bmp->hdc, (HGDIOBJECT) gdi_bmp->bitmap);
825                 gdi_bmp->org_bitmap = NULL;
826
827                 glyph_put(gdi->cache->glyph, cache_glyph_v2->cacheId, glyph->cacheIndex, glyph, (void*) gdi_bmp);
828         }
829 }
830
831 void gdi_cache_brush(rdpUpdate* update, CACHE_BRUSH_ORDER* cache_brush)
832 {
833         GDI* gdi = GET_GDI(update);
834         brush_put(gdi->cache->brush, cache_brush->index, cache_brush->data, cache_brush->bpp);
835 }
836
837 int tilenum = 0;
838
839 void gdi_surface_bits(rdpUpdate* update, SURFACE_BITS_COMMAND* surface_bits_command)
840 {
841         int i, j;
842         int tx, ty;
843         char* tile_bitmap;
844         RFX_MESSAGE* message;
845         GDI* gdi = GET_GDI(update);
846         RFX_CONTEXT* context = (RFX_CONTEXT*) gdi->rfx_context;
847         NSC_CONTEXT* ncontext = (NSC_CONTEXT*) gdi->nsc_context;
848
849
850         DEBUG_GDI("destLeft %d destTop %d destRight %d destBottom %d "
851                 "bpp %d codecID %d width %d height %d length %d",
852                 surface_bits_command->destLeft, surface_bits_command->destTop,
853                 surface_bits_command->destRight, surface_bits_command->destBottom,
854                 surface_bits_command->bpp, surface_bits_command->codecID,
855                 surface_bits_command->width, surface_bits_command->height,
856                 surface_bits_command->bitmapDataLength);
857
858         tile_bitmap = (char*) xzalloc(32);
859
860         if (surface_bits_command->codecID == CODEC_ID_REMOTEFX)
861         {
862                 message = rfx_process_message(context, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength);
863
864                 DEBUG_GDI("num_rects %d num_tiles %d", message->num_rects, message->num_tiles);
865
866                 /* blit each tile */
867                 for (i = 0; i < message->num_tiles; i++)
868                 {
869                         tx = message->tiles[i]->x + surface_bits_command->destLeft;
870                         ty = message->tiles[i]->y + surface_bits_command->destTop;
871
872                         freerdp_image_convert(message->tiles[i]->data, gdi->tile->bitmap->data, 64, 64, 32, 32, gdi->clrconv);
873
874 #ifdef DUMP_REMOTEFX_TILES
875                         sprintf(tile_bitmap, "/tmp/rfx/tile_%d.bmp", tilenum++);
876                         freerdp_bitmap_write(tile_bitmap, gdi->tile->bitmap->data, 64, 64, 32);
877 #endif
878
879                         for (j = 0; j < message->num_rects; j++)
880                         {
881                                 gdi_SetClipRgn(gdi->primary->hdc,
882                                         surface_bits_command->destLeft + message->rects[j].x,
883                                         surface_bits_command->destTop + message->rects[j].y,
884                                         message->rects[j].width, message->rects[j].height);
885
886                                 gdi_BitBlt(gdi->primary->hdc, tx, ty, 64, 64, gdi->tile->hdc, 0, 0, GDI_SRCCOPY);
887                         }
888                 }
889
890                 gdi_SetNullClipRgn(gdi->primary->hdc);
891                 rfx_message_free(context, message);
892         }
893         else if (surface_bits_command->codecID == CODEC_ID_NSCODEC)
894         {
895                 ncontext->width = surface_bits_command->width;
896                 ncontext->height = surface_bits_command->height;
897                 nsc_process_message(ncontext, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength);
898                 gdi->image->bitmap->width = surface_bits_command->width;
899                 gdi->image->bitmap->height = surface_bits_command->height;
900                 gdi->image->bitmap->bitsPerPixel = surface_bits_command->bpp;
901                 gdi->image->bitmap->bytesPerPixel = gdi->image->bitmap->bitsPerPixel / 8;
902                 gdi->image->bitmap->data = (uint8*) xrealloc(gdi->image->bitmap->data, gdi->image->bitmap->width * gdi->image->bitmap->height * 4);
903                 freerdp_image_invert(ncontext->bmpdata, gdi->image->bitmap->data, gdi->image->bitmap->width, gdi->image->bitmap->height, 32);
904                 gdi_BitBlt(gdi->primary->hdc, surface_bits_command->destLeft, surface_bits_command->destTop, surface_bits_command->width, surface_bits_command->height, gdi->image->hdc, 0, 0, GDI_SRCCOPY);
905                 nsc_context_destroy(ncontext);
906         } 
907         else if (surface_bits_command->codecID == CODEC_ID_NONE)
908         {
909                 gdi->image->bitmap->width = surface_bits_command->width;
910                 gdi->image->bitmap->height = surface_bits_command->height;
911                 gdi->image->bitmap->bitsPerPixel = surface_bits_command->bpp;
912                 gdi->image->bitmap->bytesPerPixel = gdi->image->bitmap->bitsPerPixel / 8;
913
914                 gdi->image->bitmap->data = (uint8*) xrealloc(gdi->image->bitmap->data,
915                                 gdi->image->bitmap->width * gdi->image->bitmap->height * 4);
916
917                 if ((surface_bits_command->bpp != 32) || (gdi->clrconv->alpha == True))
918                 {
919                         uint8* temp_image;
920
921                         freerdp_image_convert(surface_bits_command->bitmapData, gdi->image->bitmap->data,
922                                 gdi->image->bitmap->width, gdi->image->bitmap->height,
923                                 gdi->image->bitmap->bitsPerPixel, 32, gdi->clrconv);
924
925                         surface_bits_command->bpp = 32;
926                         surface_bits_command->bitmapData = gdi->image->bitmap->data;
927
928                         temp_image = (uint8*) xmalloc(gdi->image->bitmap->width * gdi->image->bitmap->height * 4);
929                         freerdp_image_invert(gdi->image->bitmap->data, temp_image, gdi->image->bitmap->width, gdi->image->bitmap->height, 32);
930                         xfree(gdi->image->bitmap->data);
931                         gdi->image->bitmap->data = temp_image;
932                 }
933                 else
934                 {
935                         freerdp_image_invert(surface_bits_command->bitmapData, gdi->image->bitmap->data,
936                                         gdi->image->bitmap->width, gdi->image->bitmap->height, 32);
937                 }
938
939                 gdi_BitBlt(gdi->primary->hdc, surface_bits_command->destLeft, surface_bits_command->destTop,
940                                 surface_bits_command->width, surface_bits_command->height, gdi->image->hdc, 0, 0, GDI_SRCCOPY);
941         }
942         else
943         {
944                 printf("Unsupported codecID %d\n", surface_bits_command->codecID);
945         }
946
947         if (tile_bitmap != NULL)
948                 xfree(tile_bitmap);
949 }
950
951 void gdi_bitmap_decompress(rdpUpdate* update, BITMAP_DATA* bitmap_data)
952 {
953         uint16 dstSize;
954
955         dstSize = bitmap_data->width * bitmap_data->height * (bitmap_data->bpp / 8);
956
957         if (bitmap_data->dstData == NULL)
958                 bitmap_data->dstData = (uint8*) xmalloc(dstSize);
959         else
960                 bitmap_data->dstData = (uint8*) xrealloc(bitmap_data->dstData, dstSize);
961
962         if (bitmap_data->compressed)
963         {
964                 bitmap_decompress(bitmap_data->srcData, bitmap_data->dstData,
965                                 bitmap_data->width, bitmap_data->height, bitmap_data->length,
966                                 bitmap_data->bpp, bitmap_data->bpp);
967         }
968         else
969         {
970                 freerdp_image_invert(bitmap_data->srcData, bitmap_data->dstData,
971                                 bitmap_data->width, bitmap_data->height, bitmap_data->bpp);
972         }
973
974         bitmap_data->compressed = False;
975 }
976
977 /**
978  * Register GDI callbacks with libfreerdp-core.
979  * @param inst current instance
980  * @return
981  */
982
983 void gdi_register_update_callbacks(rdpUpdate* update)
984 {
985         update->Bitmap = gdi_bitmap_update;
986         update->Palette = gdi_palette_update;
987         update->SetBounds = gdi_set_bounds;
988         update->DstBlt = gdi_dstblt;
989         update->PatBlt = gdi_patblt;
990         update->ScrBlt = gdi_scrblt;
991         update->OpaqueRect = gdi_opaque_rect;
992         update->DrawNineGrid = NULL;
993         update->MultiDstBlt = NULL;
994         update->MultiPatBlt = NULL;
995         update->MultiScrBlt = NULL;
996         update->MultiOpaqueRect = gdi_multi_opaque_rect;
997         update->MultiDrawNineGrid = NULL;
998         update->LineTo = gdi_line_to;
999         update->Polyline = NULL;
1000         update->MemBlt = NULL;
1001         update->Mem3Blt = NULL;
1002         update->SaveBitmap = NULL;
1003         update->GlyphIndex = NULL;
1004         update->FastIndex = gdi_fast_index;
1005         update->FastGlyph = NULL;
1006         update->PolygonSC = NULL;
1007         update->PolygonCB = NULL;
1008         update->EllipseSC = NULL;
1009         update->EllipseCB = NULL;
1010         update->CreateOffscreenBitmap = gdi_create_offscreen_bitmap;
1011         update->SwitchSurface = gdi_switch_surface;
1012
1013         update->CacheBitmapV2 = gdi_cache_bitmap_v2;
1014         update->CacheColorTable = gdi_cache_color_table;
1015         update->CacheGlyph = gdi_cache_glyph;
1016         update->CacheGlyphV2 = gdi_cache_glyph_v2;
1017         update->CacheBrush = gdi_cache_brush;
1018
1019         update->SurfaceBits = gdi_surface_bits;
1020         update->BitmapDecompress = gdi_bitmap_decompress;
1021 }
1022
1023 void gdi_init_primary(GDI* gdi)
1024 {
1025         gdi->primary = gdi_bitmap_new(gdi, gdi->width, gdi->height, gdi->dstBpp, gdi->primary_buffer);
1026         gdi->primary_buffer = gdi->primary->bitmap->data;
1027
1028         if (gdi->drawing == NULL)
1029                 gdi->drawing = gdi->primary;
1030
1031         gdi->primary->hdc->hwnd = (HGDI_WND) malloc(sizeof(GDI_WND));
1032         gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0);
1033         gdi->primary->hdc->hwnd->invalid->null = 1;
1034
1035         gdi->primary->hdc->hwnd->count = 32;
1036         gdi->primary->hdc->hwnd->cinvalid = (HGDI_RGN) malloc(sizeof(GDI_RGN) * gdi->primary->hdc->hwnd->count);
1037         gdi->primary->hdc->hwnd->ninvalid = 0;
1038 }
1039
1040 void gdi_resize(GDI* gdi, int width, int height)
1041 {
1042         if (gdi && gdi->primary)
1043         {
1044                 if (gdi->width != width || gdi->height != height)
1045                 {
1046                         if (gdi->drawing == gdi->primary)
1047                                 gdi->drawing = NULL;
1048
1049                         gdi->width = width;
1050                         gdi->height = height;
1051                         gdi_bitmap_free(gdi->primary);
1052                         gdi_init_primary(gdi);
1053                 }
1054         }
1055 }
1056
1057 /**
1058  * Initialize GDI
1059  * @param inst current instance
1060  * @return
1061  */
1062
1063 int gdi_init(freerdp* instance, uint32 flags, uint8* buffer)
1064 {
1065         GDI* gdi = (GDI*) malloc(sizeof(GDI));
1066         memset(gdi, 0, sizeof(GDI));
1067         SET_GDI(instance->update, gdi);
1068
1069         gdi->width = instance->settings->width;
1070         gdi->height = instance->settings->height;
1071         gdi->srcBpp = instance->settings->color_depth;
1072         gdi->primary_buffer = buffer;
1073
1074         /* default internal buffer format */
1075         gdi->dstBpp = 32;
1076         gdi->bytesPerPixel = 4;
1077
1078         if (gdi->srcBpp > 16)
1079         {
1080                 if (flags & CLRBUF_32BPP)
1081                 {
1082                         gdi->dstBpp = 32;
1083                         gdi->bytesPerPixel = 4;
1084                 }
1085                 else if (flags & CLRBUF_24BPP)
1086                 {
1087                         gdi->dstBpp = 24;
1088                         gdi->bytesPerPixel = 3;
1089                 }
1090                 else if (flags & CLRBUF_16BPP)
1091                 {
1092                         gdi->dstBpp = 16;
1093                         gdi->bytesPerPixel = 2;
1094                 }
1095         }
1096         else
1097         {
1098                 if (flags & CLRBUF_16BPP)
1099                 {
1100                         gdi->dstBpp = 16;
1101                         gdi->bytesPerPixel = 2;
1102                 }
1103                 else if (flags & CLRBUF_32BPP)
1104                 {
1105                         gdi->dstBpp = 32;
1106                         gdi->bytesPerPixel = 4;
1107                 }
1108         }
1109         
1110         gdi->hdc = gdi_GetDC();
1111         gdi->hdc->bitsPerPixel = gdi->dstBpp;
1112         gdi->hdc->bytesPerPixel = gdi->bytesPerPixel;
1113
1114         gdi->clrconv = (HCLRCONV) malloc(sizeof(CLRCONV));
1115         gdi->clrconv->palette = NULL;
1116         gdi->clrconv->alpha = (flags & CLRCONV_ALPHA) ? 1 : 0;
1117         gdi->clrconv->invert = (flags & CLRCONV_INVERT) ? 1 : 0;
1118         gdi->clrconv->rgb555 = (flags & CLRCONV_RGB555) ? 1 : 0;
1119
1120         gdi->hdc->alpha = gdi->clrconv->alpha;
1121         gdi->hdc->invert = gdi->clrconv->invert;
1122         gdi->hdc->rgb555 = gdi->clrconv->rgb555;
1123
1124         gdi_init_primary(gdi);
1125
1126         gdi->tile = gdi_bitmap_new(gdi, 64, 64, 32, NULL);
1127         gdi->image = gdi_bitmap_new(gdi, 64, 64, 32, NULL);
1128
1129         gdi_register_update_callbacks(instance->update);
1130
1131         gdi->cache = cache_new(instance->settings);
1132
1133         gdi->rfx_context = rfx_context_new();
1134         gdi->nsc_context = nsc_context_new();
1135
1136         return 0;
1137 }
1138
1139 void gdi_free(freerdp* instance)
1140 {
1141         GDI *gdi = GET_GDI(instance->update);
1142
1143         if (gdi)
1144         {
1145                 gdi_bitmap_free(gdi->primary);
1146                 gdi_bitmap_free(gdi->tile);
1147                 gdi_bitmap_free(gdi->image);
1148                 gdi_DeleteDC(gdi->hdc);
1149                 cache_free(gdi->cache);
1150                 rfx_context_free((RFX_CONTEXT*)gdi->rfx_context);
1151                 free(gdi->clrconv);
1152                 free(gdi);
1153         }
1154         
1155         SET_GDI(instance->update, NULL);
1156 }
1157