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