Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / client / Windows / wf_gdi.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * Windows GDI
4  *
5  * Copyright 2009-2011 Jay Sorg
6  * Copyright 2010-2011 Vic Lee
7  * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *     http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <conio.h>
26
27 #include <freerdp/gdi/gdi.h>
28 #include <freerdp/constants.h>
29 #include <freerdp/codec/color.h>
30 #include <freerdp/codec/bitmap.h>
31 #include <freerdp/utils/memory.h>
32 #include <freerdp/codec/rfx.h>
33 #include <freerdp/codec/nsc.h>
34
35 #include "wfreerdp.h"
36 #include "wf_graphics.h"
37
38 const uint8 wf_rop2_table[] =
39 {
40         R2_BLACK,       /* 0 */
41         R2_NOTMERGEPEN, /* DPon */
42         R2_MASKNOTPEN,  /* DPna */
43         R2_NOTCOPYPEN,  /* Pn */
44         R2_MASKPENNOT,  /* PDna */
45         R2_NOT,         /* Dn */
46         R2_XORPEN,      /* DPx */
47         R2_NOTMASKPEN,  /* DPan */
48         R2_MASKPEN,     /* DPa */
49         R2_NOTXORPEN,   /* DPxn */
50         R2_NOP,         /* D */
51         R2_MERGENOTPEN, /* DPno */
52         R2_COPYPEN,     /* P */
53         R2_MERGEPENNOT, /* PDno */
54         R2_MERGEPEN,    /* PDo */
55         R2_WHITE,       /* 1 */
56 };
57
58 boolean wf_set_rop2(HDC hdc, int rop2)
59 {
60         if ((rop2 < 0x01) || (rop2 > 0x10))
61         {
62                 printf("Unsupported ROP2: %d\n", rop2);
63                 return false;
64         }
65
66         SetROP2(hdc, wf_rop2_table[rop2 - 1]);
67
68         return true;
69 }
70
71 wfBitmap* wf_glyph_new(wfInfo* wfi, GLYPH_DATA* glyph)
72 {
73         wfBitmap* glyph_bmp;
74         glyph_bmp = wf_image_new(wfi, glyph->cx, glyph->cy, 1, glyph->aj);
75         return glyph_bmp;
76 }
77
78 void wf_glyph_free(wfBitmap* glyph)
79 {
80         wf_image_free(glyph);
81 }
82
83 uint8* wf_glyph_convert(wfInfo* wfi, int width, int height, uint8* data)
84 {
85         int indexx;
86         int indexy;
87         uint8* src;
88         uint8* dst;
89         uint8* cdata;
90         int src_bytes_per_row;
91         int dst_bytes_per_row;
92
93         src_bytes_per_row = (width + 7) / 8;
94         dst_bytes_per_row = src_bytes_per_row + (src_bytes_per_row % 2);
95         cdata = (uint8 *) malloc(dst_bytes_per_row * height);
96
97         src = data;
98         for (indexy = 0; indexy < height; indexy++)
99         {
100                 dst = cdata + indexy * dst_bytes_per_row;
101
102                 for (indexx = 0; indexx < dst_bytes_per_row; indexx++)
103                 {
104                         if (indexx < src_bytes_per_row)
105                                 *dst++ = *src++;
106                         else
107                                 *dst++ = 0;
108                 }
109         }
110
111         return cdata;
112 }
113
114 HBRUSH wf_create_brush(wfInfo * wfi, rdpBrush* brush, uint32 color, int bpp)
115 {
116         int i;
117         HBRUSH br;
118         LOGBRUSH lbr;
119         uint8* cdata;
120         uint8 ipattern[8];
121         HBITMAP pattern = NULL;
122
123         lbr.lbStyle = brush->style;
124
125         if (lbr.lbStyle == BS_DIBPATTERN || lbr.lbStyle == BS_DIBPATTERN8X8 || lbr.lbStyle == BS_DIBPATTERNPT)
126                 lbr.lbColor = DIB_RGB_COLORS;
127         else
128                 lbr.lbColor = color;
129
130         if (lbr.lbStyle == BS_PATTERN || lbr.lbStyle == BS_PATTERN8X8)
131         {
132                 if (brush->bpp > 1)
133                 {
134                         pattern = wf_create_dib(wfi, 8, 8, bpp, brush->data, NULL);
135                         lbr.lbHatch = (ULONG_PTR) pattern;
136                 }
137                 else
138                 {
139                         for (i = 0; i != 8; i++)
140                                 ipattern[7 - i] = brush->data[i];
141         
142                         cdata = wf_glyph_convert(wfi, 8, 8, ipattern);
143                         pattern = CreateBitmap(8, 8, 1, 1, cdata);
144                         lbr.lbHatch = (ULONG_PTR) pattern;
145                         free(cdata);
146                 }
147         }
148         else if (lbr.lbStyle == BS_HATCHED)
149         {
150                 lbr.lbHatch = brush->hatch;
151         }
152         else
153         {
154                 lbr.lbHatch = 0;
155         }
156
157         br = CreateBrushIndirect(&lbr);
158         SetBrushOrgEx(wfi->drawing->hdc, brush->x, brush->y, NULL);
159
160         if (pattern != NULL)
161                 DeleteObject(pattern);
162
163         return br;
164 }
165
166 void wf_invalidate_region(wfInfo* wfi, int x, int y, int width, int height)
167 {
168         wfi->update_rect.left = x;
169         wfi->update_rect.top = y;
170         wfi->update_rect.right = x + width;
171         wfi->update_rect.bottom = y + height;
172         InvalidateRect(wfi->hwnd, &(wfi->update_rect), FALSE);
173         gdi_InvalidateRegion(wfi->hdc, x, y, width, height);
174 }
175
176 void wf_toggle_fullscreen(wfInfo* wfi)
177 {
178         ShowWindow(wfi->hwnd, SW_HIDE);
179         wfi->fullscreen = !wfi->fullscreen;
180         SetForegroundWindow(wfi->hwnd);
181 }
182
183 void wf_gdi_palette_update(rdpContext* context, PALETTE_UPDATE* palette)
184 {
185
186 }
187
188 void wf_set_null_clip_rgn(wfInfo* wfi)
189 {
190         SelectClipRgn(wfi->drawing->hdc, NULL);
191 }
192
193 void wf_set_clip_rgn(wfInfo* wfi, int x, int y, int width, int height)
194 {
195         HRGN clip;
196         clip = CreateRectRgn(x, y, x + width, y + height);
197         SelectClipRgn(wfi->drawing->hdc, clip);
198         DeleteObject(clip);
199 }
200
201 void wf_gdi_set_bounds(rdpContext* context, rdpBounds* bounds)
202 {
203         HRGN hrgn;
204         wfInfo* wfi = ((wfContext*) context)->wfi;
205
206         if (bounds != NULL)
207         {
208                 hrgn = CreateRectRgn(bounds->left, bounds->top, bounds->right + 1, bounds->bottom + 1);
209                 SelectClipRgn(wfi->drawing->hdc, hrgn);
210                 DeleteObject(hrgn);
211         }
212         else
213         {
214                 SelectClipRgn(wfi->drawing->hdc, NULL);
215         }
216 }
217
218 void wf_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt)
219 {
220         wfInfo* wfi = ((wfContext*) context)->wfi;
221
222         BitBlt(wfi->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect,
223                         dstblt->nWidth, dstblt->nHeight, NULL, 0, 0, gdi_rop3_code(dstblt->bRop));
224
225         wf_invalidate_region(wfi, dstblt->nLeftRect, dstblt->nTopRect,
226                         dstblt->nWidth, dstblt->nHeight);
227 }
228
229 void wf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
230 {
231         HBRUSH brush;
232         HBRUSH org_brush;
233         int org_bkmode;
234         uint32 fgcolor;
235         uint32 bgcolor;
236         COLORREF org_bkcolor;
237         COLORREF org_textcolor;
238         wfInfo* wfi = ((wfContext*) context)->wfi;
239
240         fgcolor = freerdp_color_convert_bgr(patblt->foreColor, wfi->srcBpp, 32, wfi->clrconv);
241         bgcolor = freerdp_color_convert_bgr(patblt->backColor, wfi->srcBpp, 32, wfi->clrconv);
242
243         brush = wf_create_brush(wfi, &patblt->brush, fgcolor, wfi->srcBpp);
244         org_bkmode = SetBkMode(wfi->drawing->hdc, OPAQUE);
245         org_bkcolor = SetBkColor(wfi->drawing->hdc, bgcolor);
246         org_textcolor = SetTextColor(wfi->drawing->hdc, fgcolor);
247         org_brush = (HBRUSH)SelectObject(wfi->drawing->hdc, brush);
248
249         PatBlt(wfi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect,
250                 patblt->nWidth, patblt->nHeight, gdi_rop3_code(patblt->bRop));
251
252         SelectObject(wfi->drawing->hdc, org_brush);
253         DeleteObject(brush);
254
255         SetBkMode(wfi->drawing->hdc, org_bkmode);
256         SetBkColor(wfi->drawing->hdc, org_bkcolor);
257         SetTextColor(wfi->drawing->hdc, org_textcolor);
258
259         if (wfi->drawing == wfi->primary)
260                 wf_invalidate_region(wfi, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight);
261 }
262
263 void wf_gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt)
264 {
265         wfInfo* wfi = ((wfContext*) context)->wfi;
266
267         BitBlt(wfi->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect,
268                         scrblt->nWidth, scrblt->nHeight, wfi->primary->hdc,
269                         scrblt->nXSrc, scrblt->nYSrc, gdi_rop3_code(scrblt->bRop));
270
271         wf_invalidate_region(wfi, scrblt->nLeftRect, scrblt->nTopRect,
272                         scrblt->nWidth, scrblt->nHeight);
273 }
274
275 void wf_gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect)
276 {
277         RECT rect;
278         HBRUSH brush;
279         uint32 brush_color;
280         wfInfo* wfi = ((wfContext*) context)->wfi;
281
282         brush_color = freerdp_color_convert_var_bgr(opaque_rect->color, wfi->srcBpp, 24, wfi->clrconv);
283
284         rect.left = opaque_rect->nLeftRect;
285         rect.top = opaque_rect->nTopRect;
286         rect.right = opaque_rect->nLeftRect + opaque_rect->nWidth;
287         rect.bottom = opaque_rect->nTopRect + opaque_rect->nHeight;
288         brush = CreateSolidBrush(brush_color);
289         FillRect(wfi->drawing->hdc, &rect, brush);
290         DeleteObject(brush);
291
292         if (wfi->drawing == wfi->primary)
293                 wf_invalidate_region(wfi, rect.left, rect.top, rect.right - rect.left + 1, rect.bottom - rect.top + 1);
294 }
295
296 void wf_gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
297 {
298         int i;
299         RECT rect;
300         HBRUSH brush;
301         uint32 brush_color;
302         DELTA_RECT* rectangle;
303         wfInfo* wfi = ((wfContext*) context)->wfi;
304
305         for (i = 1; i < (int) multi_opaque_rect->numRectangles + 1; i++)
306         {
307                 rectangle = &multi_opaque_rect->rectangles[i];
308
309                 brush_color = freerdp_color_convert_var_bgr(multi_opaque_rect->color, wfi->srcBpp, 32, wfi->clrconv);
310
311                 rect.left = rectangle->left;
312                 rect.top = rectangle->top;
313                 rect.right = rectangle->left + rectangle->width;
314                 rect.bottom = rectangle->top + rectangle->height;
315                 brush = CreateSolidBrush(brush_color);
316
317                 brush = CreateSolidBrush(brush_color);
318                 FillRect(wfi->drawing->hdc, &rect, brush);
319
320                 if (wfi->drawing == wfi->primary)
321                         wf_invalidate_region(wfi, rect.left, rect.top, rect.right - rect.left + 1, rect.bottom - rect.top + 1);
322
323                 DeleteObject(brush);
324         }
325 }
326
327 void wf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to)
328 {
329         HPEN pen;
330         HPEN org_pen;
331         int x, y, w, h;
332         uint32 pen_color;
333         wfInfo* wfi = ((wfContext*) context)->wfi;
334
335         pen_color = freerdp_color_convert_bgr(line_to->penColor, wfi->srcBpp, wfi->dstBpp, wfi->clrconv);
336
337         pen = CreatePen(line_to->penStyle, line_to->penWidth, pen_color);
338
339         wf_set_rop2(wfi->drawing->hdc, line_to->bRop2);
340         org_pen = (HPEN) SelectObject(wfi->drawing->hdc, pen);
341         
342         MoveToEx(wfi->drawing->hdc, line_to->nXStart, line_to->nYStart, NULL);
343         LineTo(wfi->drawing->hdc, line_to->nXEnd, line_to->nYEnd);
344
345         x = (line_to->nXStart < line_to->nXEnd) ? line_to->nXStart : line_to->nXEnd;
346         y = (line_to->nYStart < line_to->nYEnd) ? line_to->nYStart : line_to->nYEnd;
347         w = (line_to->nXStart < line_to->nXEnd) ? (line_to->nXEnd - line_to->nXStart) : (line_to->nXStart - line_to->nXEnd);
348         h = (line_to->nYStart < line_to->nYEnd) ? (line_to->nYEnd - line_to->nYStart) : (line_to->nYStart - line_to->nYEnd);
349
350         if (wfi->drawing == wfi->primary)
351                 wf_invalidate_region(wfi, x, y, w, h);
352
353         SelectObject(wfi->drawing->hdc, org_pen);
354         DeleteObject(pen);
355 }
356
357 void wf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline)
358 {
359         int i;
360         POINT* pts;
361         int org_rop2;
362         HPEN hpen;
363         HPEN org_hpen;
364         uint32 pen_color;
365         wfInfo* wfi = ((wfContext*) context)->wfi;
366
367         pen_color = freerdp_color_convert_bgr(polyline->penColor, wfi->srcBpp, wfi->dstBpp, wfi->clrconv);
368
369         hpen = CreatePen(0, 1, pen_color);
370         org_rop2 = wf_set_rop2(wfi->drawing->hdc, polyline->bRop2);
371         org_hpen = (HPEN) SelectObject(wfi->drawing->hdc, hpen);
372
373         if (polyline->numPoints > 0)
374         {
375                 pts = (POINT*) xmalloc(sizeof(POINT) * polyline->numPoints);
376
377                 for (i = 0; i < (int) polyline->numPoints; i++)
378                 {
379                         pts[i].x = polyline->points[i].x;
380                         pts[i].y = polyline->points[i].y;
381
382                         if (wfi->drawing == wfi->primary)
383                                 wf_invalidate_region(wfi, pts[i].x, pts[i].y, pts[i].x + 1, pts[i].y + 1);
384                 }
385
386                 Polyline(wfi->drawing->hdc, pts, polyline->numPoints);
387                 xfree(pts);
388         }
389
390         SelectObject(wfi->drawing->hdc, org_hpen);
391         wf_set_rop2(wfi->drawing->hdc, org_rop2);
392         DeleteObject(hpen);
393 }
394
395 void wf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
396 {
397         wfBitmap* bitmap;
398         wfInfo* wfi = ((wfContext*) context)->wfi;
399
400         bitmap = (wfBitmap*) memblt->bitmap;
401
402         BitBlt(wfi->drawing->hdc, memblt->nLeftRect, memblt->nTopRect,
403                         memblt->nWidth, memblt->nHeight, bitmap->hdc,
404                         memblt->nXSrc, memblt->nYSrc, gdi_rop3_code(memblt->bRop));
405
406         if (wfi->drawing == wfi->primary)
407                 wf_invalidate_region(wfi, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth, memblt->nHeight);
408 }
409
410 void wf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_command)
411 {
412         int i, j;
413         int tx, ty;
414         char* tile_bitmap;
415         RFX_MESSAGE* message;
416         wfInfo* wfi = ((wfContext*) context)->wfi;
417
418         RFX_CONTEXT* rfx_context = (RFX_CONTEXT*) wfi->rfx_context;
419         NSC_CONTEXT* nsc_context = (NSC_CONTEXT*) wfi->nsc_context;
420
421         tile_bitmap = (char*) xzalloc(32);
422
423         if (surface_bits_command->codecID == CODEC_ID_REMOTEFX)
424         {
425                 message = rfx_process_message(rfx_context, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength);
426
427                 /* blit each tile */
428                 for (i = 0; i < message->num_tiles; i++)
429                 {
430                         tx = message->tiles[i]->x + surface_bits_command->destLeft;
431                         ty = message->tiles[i]->y + surface_bits_command->destTop;
432
433                         freerdp_image_convert(message->tiles[i]->data, wfi->tile->pdata, 64, 64, 32, 32, wfi->clrconv);
434
435                         for (j = 0; j < message->num_rects; j++)
436                         {
437                                 wf_set_clip_rgn(wfi,
438                                         surface_bits_command->destLeft + message->rects[j].x,
439                                         surface_bits_command->destTop + message->rects[j].y,
440                                         message->rects[j].width, message->rects[j].height);
441
442                                 BitBlt(wfi->primary->hdc, tx, ty, 64, 64, wfi->tile->hdc, 0, 0, SRCCOPY);
443                         }
444                 }
445
446                 wf_set_null_clip_rgn(wfi);
447
448                 /* invalidate regions */
449                 for (i = 0; i < message->num_rects; i++)
450                 {
451                         tx = surface_bits_command->destLeft + message->rects[i].x;
452                         ty = surface_bits_command->destTop + message->rects[i].y;
453                         wf_invalidate_region(wfi, tx, ty, message->rects[i].width, message->rects[i].height);
454                 }
455
456                 rfx_message_free(rfx_context, message);
457         }
458         else if (surface_bits_command->codecID == CODEC_ID_NSCODEC)
459         {
460                 nsc_context->width = surface_bits_command->width;
461                 nsc_context->height = surface_bits_command->height;
462                 nsc_process_message(nsc_context, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength);
463                 wfi->image->_bitmap.width = surface_bits_command->width;
464                 wfi->image->_bitmap.height = surface_bits_command->height;
465                 wfi->image->_bitmap.bpp = surface_bits_command->bpp;
466                 wfi->image->_bitmap.data = (uint8*) xrealloc(wfi->image->_bitmap.data, wfi->image->_bitmap.width * wfi->image->_bitmap.height * 4);
467                 freerdp_image_flip(nsc_context->bmpdata, wfi->image->_bitmap.data, wfi->image->_bitmap.width, wfi->image->_bitmap.height, 32);
468                 BitBlt(wfi->primary->hdc, surface_bits_command->destLeft, surface_bits_command->destTop, surface_bits_command->width, surface_bits_command->height, wfi->image->hdc, 0, 0, GDI_SRCCOPY);
469                 nsc_context_destroy(nsc_context);
470         } 
471         else if (surface_bits_command->codecID == CODEC_ID_NONE)
472         {
473                 wfi->image->_bitmap.width = surface_bits_command->width;
474                 wfi->image->_bitmap.height = surface_bits_command->height;
475                 wfi->image->_bitmap.bpp = surface_bits_command->bpp;
476
477                 wfi->image->_bitmap.data = (uint8*) xrealloc(wfi->image->_bitmap.data,
478                                 wfi->image->_bitmap.width * wfi->image->_bitmap.height * 4);
479
480                 if ((surface_bits_command->bpp != 32) || (wfi->clrconv->alpha == true))
481                 {
482                         uint8* temp_image;
483
484                         freerdp_image_convert(surface_bits_command->bitmapData, wfi->image->_bitmap.data,
485                                 wfi->image->_bitmap.width, wfi->image->_bitmap.height,
486                                 wfi->image->_bitmap.bpp, 32, wfi->clrconv);
487
488                         surface_bits_command->bpp = 32;
489                         surface_bits_command->bitmapData = wfi->image->_bitmap.data;
490
491                         temp_image = (uint8*) xmalloc(wfi->image->_bitmap.width * wfi->image->_bitmap.height * 4);
492                         freerdp_image_flip(wfi->image->_bitmap.data, temp_image, wfi->image->_bitmap.width, wfi->image->_bitmap.height, 32);
493                         xfree(wfi->image->_bitmap.data);
494                         wfi->image->_bitmap.data = temp_image;
495                 }
496                 else
497                 {
498                         freerdp_image_flip(surface_bits_command->bitmapData, wfi->image->_bitmap.data,
499                                         wfi->image->_bitmap.width, wfi->image->_bitmap.height, 32);
500                 }
501
502                 BitBlt(wfi->primary->hdc, surface_bits_command->destLeft, surface_bits_command->destTop,
503                                 surface_bits_command->width, surface_bits_command->height, wfi->image->hdc, 0, 0, SRCCOPY);
504         }
505         else
506         {
507                 printf("Unsupported codecID %d\n", surface_bits_command->codecID);
508         }
509
510         if (tile_bitmap != NULL)
511                 xfree(tile_bitmap);
512 }
513
514 void wf_gdi_register_update_callbacks(rdpUpdate* update)
515 {
516         rdpPrimaryUpdate* primary = update->primary;
517
518         update->Palette = wf_gdi_palette_update;
519         update->SetBounds = wf_gdi_set_bounds;
520
521         primary->DstBlt = wf_gdi_dstblt;
522         primary->PatBlt = wf_gdi_patblt;
523         primary->ScrBlt = wf_gdi_scrblt;
524         primary->OpaqueRect = wf_gdi_opaque_rect;
525         primary->DrawNineGrid = NULL;
526         primary->MultiDstBlt = NULL;
527         primary->MultiPatBlt = NULL;
528         primary->MultiScrBlt = NULL;
529         primary->MultiOpaqueRect = wf_gdi_multi_opaque_rect;
530         primary->MultiDrawNineGrid = NULL;
531         primary->LineTo = wf_gdi_line_to;
532         primary->Polyline = wf_gdi_polyline;
533         primary->MemBlt = wf_gdi_memblt;
534         primary->Mem3Blt = NULL;
535         primary->SaveBitmap = NULL;
536         primary->GlyphIndex = NULL;
537         primary->FastIndex = NULL;
538         primary->FastGlyph = NULL;
539         primary->PolygonSC = NULL;
540         primary->PolygonCB = NULL;
541         primary->EllipseSC = NULL;
542         primary->EllipseCB = NULL;
543
544         update->SurfaceBits = wf_gdi_surface_bits;
545 }