2 * FreeRDP: A Remote Desktop Protocol Client
5 * Copyright 2009-2011 Jay Sorg
6 * Copyright 2010-2011 Vic Lee
7 * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
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>
36 #include "wf_graphics.h"
38 const uint8 wf_rop2_table[] =
41 R2_NOTMERGEPEN, /* DPon */
42 R2_MASKNOTPEN, /* DPna */
43 R2_NOTCOPYPEN, /* Pn */
44 R2_MASKPENNOT, /* PDna */
47 R2_NOTMASKPEN, /* DPan */
49 R2_NOTXORPEN, /* DPxn */
51 R2_MERGENOTPEN, /* DPno */
53 R2_MERGEPENNOT, /* PDno */
54 R2_MERGEPEN, /* PDo */
58 boolean wf_set_rop2(HDC hdc, int rop2)
60 if ((rop2 < 0x01) || (rop2 > 0x10))
62 printf("Unsupported ROP2: %d\n", rop2);
66 SetROP2(hdc, wf_rop2_table[rop2 - 1]);
71 wfBitmap* wf_glyph_new(wfInfo* wfi, GLYPH_DATA* glyph)
74 glyph_bmp = wf_image_new(wfi, glyph->cx, glyph->cy, 1, glyph->aj);
78 void wf_glyph_free(wfBitmap* glyph)
83 uint8* wf_glyph_convert(wfInfo* wfi, int width, int height, uint8* data)
90 int src_bytes_per_row;
91 int dst_bytes_per_row;
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);
98 for (indexy = 0; indexy < height; indexy++)
100 dst = cdata + indexy * dst_bytes_per_row;
102 for (indexx = 0; indexx < dst_bytes_per_row; indexx++)
104 if (indexx < src_bytes_per_row)
114 HBRUSH wf_create_brush(wfInfo * wfi, rdpBrush* brush, uint32 color, int bpp)
121 HBITMAP pattern = NULL;
123 lbr.lbStyle = brush->style;
125 if (lbr.lbStyle == BS_DIBPATTERN || lbr.lbStyle == BS_DIBPATTERN8X8 || lbr.lbStyle == BS_DIBPATTERNPT)
126 lbr.lbColor = DIB_RGB_COLORS;
130 if (lbr.lbStyle == BS_PATTERN || lbr.lbStyle == BS_PATTERN8X8)
134 pattern = wf_create_dib(wfi, 8, 8, bpp, brush->data, NULL);
135 lbr.lbHatch = (ULONG_PTR) pattern;
139 for (i = 0; i != 8; i++)
140 ipattern[7 - i] = brush->data[i];
142 cdata = wf_glyph_convert(wfi, 8, 8, ipattern);
143 pattern = CreateBitmap(8, 8, 1, 1, cdata);
144 lbr.lbHatch = (ULONG_PTR) pattern;
148 else if (lbr.lbStyle == BS_HATCHED)
150 lbr.lbHatch = brush->hatch;
157 br = CreateBrushIndirect(&lbr);
158 SetBrushOrgEx(wfi->drawing->hdc, brush->x, brush->y, NULL);
161 DeleteObject(pattern);
166 void wf_invalidate_region(wfInfo* wfi, int x, int y, int width, int height)
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);
176 void wf_toggle_fullscreen(wfInfo* wfi)
178 ShowWindow(wfi->hwnd, SW_HIDE);
179 wfi->fullscreen = !wfi->fullscreen;
180 SetForegroundWindow(wfi->hwnd);
183 void wf_gdi_palette_update(rdpContext* context, PALETTE_UPDATE* palette)
188 void wf_set_null_clip_rgn(wfInfo* wfi)
190 SelectClipRgn(wfi->drawing->hdc, NULL);
193 void wf_set_clip_rgn(wfInfo* wfi, int x, int y, int width, int height)
196 clip = CreateRectRgn(x, y, x + width, y + height);
197 SelectClipRgn(wfi->drawing->hdc, clip);
201 void wf_gdi_set_bounds(rdpContext* context, rdpBounds* bounds)
204 wfInfo* wfi = ((wfContext*) context)->wfi;
208 hrgn = CreateRectRgn(bounds->left, bounds->top, bounds->right + 1, bounds->bottom + 1);
209 SelectClipRgn(wfi->drawing->hdc, hrgn);
214 SelectClipRgn(wfi->drawing->hdc, NULL);
218 void wf_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt)
220 wfInfo* wfi = ((wfContext*) context)->wfi;
222 BitBlt(wfi->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect,
223 dstblt->nWidth, dstblt->nHeight, NULL, 0, 0, gdi_rop3_code(dstblt->bRop));
225 wf_invalidate_region(wfi, dstblt->nLeftRect, dstblt->nTopRect,
226 dstblt->nWidth, dstblt->nHeight);
229 void wf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
236 COLORREF org_bkcolor;
237 COLORREF org_textcolor;
238 wfInfo* wfi = ((wfContext*) context)->wfi;
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);
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);
249 PatBlt(wfi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect,
250 patblt->nWidth, patblt->nHeight, gdi_rop3_code(patblt->bRop));
252 SelectObject(wfi->drawing->hdc, org_brush);
255 SetBkMode(wfi->drawing->hdc, org_bkmode);
256 SetBkColor(wfi->drawing->hdc, org_bkcolor);
257 SetTextColor(wfi->drawing->hdc, org_textcolor);
259 if (wfi->drawing == wfi->primary)
260 wf_invalidate_region(wfi, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight);
263 void wf_gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt)
265 wfInfo* wfi = ((wfContext*) context)->wfi;
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));
271 wf_invalidate_region(wfi, scrblt->nLeftRect, scrblt->nTopRect,
272 scrblt->nWidth, scrblt->nHeight);
275 void wf_gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect)
280 wfInfo* wfi = ((wfContext*) context)->wfi;
282 brush_color = freerdp_color_convert_var_bgr(opaque_rect->color, wfi->srcBpp, 24, wfi->clrconv);
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);
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);
296 void wf_gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
302 DELTA_RECT* rectangle;
303 wfInfo* wfi = ((wfContext*) context)->wfi;
305 for (i = 1; i < (int) multi_opaque_rect->numRectangles + 1; i++)
307 rectangle = &multi_opaque_rect->rectangles[i];
309 brush_color = freerdp_color_convert_var_bgr(multi_opaque_rect->color, wfi->srcBpp, 32, wfi->clrconv);
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);
317 brush = CreateSolidBrush(brush_color);
318 FillRect(wfi->drawing->hdc, &rect, brush);
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);
327 void wf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to)
333 wfInfo* wfi = ((wfContext*) context)->wfi;
335 pen_color = freerdp_color_convert_bgr(line_to->penColor, wfi->srcBpp, wfi->dstBpp, wfi->clrconv);
337 pen = CreatePen(line_to->penStyle, line_to->penWidth, pen_color);
339 wf_set_rop2(wfi->drawing->hdc, line_to->bRop2);
340 org_pen = (HPEN) SelectObject(wfi->drawing->hdc, pen);
342 MoveToEx(wfi->drawing->hdc, line_to->nXStart, line_to->nYStart, NULL);
343 LineTo(wfi->drawing->hdc, line_to->nXEnd, line_to->nYEnd);
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);
350 if (wfi->drawing == wfi->primary)
351 wf_invalidate_region(wfi, x, y, w, h);
353 SelectObject(wfi->drawing->hdc, org_pen);
357 void wf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline)
365 wfInfo* wfi = ((wfContext*) context)->wfi;
367 pen_color = freerdp_color_convert_bgr(polyline->penColor, wfi->srcBpp, wfi->dstBpp, wfi->clrconv);
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);
373 if (polyline->numPoints > 0)
375 pts = (POINT*) xmalloc(sizeof(POINT) * polyline->numPoints);
377 for (i = 0; i < (int) polyline->numPoints; i++)
379 pts[i].x = polyline->points[i].x;
380 pts[i].y = polyline->points[i].y;
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);
386 Polyline(wfi->drawing->hdc, pts, polyline->numPoints);
390 SelectObject(wfi->drawing->hdc, org_hpen);
391 wf_set_rop2(wfi->drawing->hdc, org_rop2);
395 void wf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
398 wfInfo* wfi = ((wfContext*) context)->wfi;
400 bitmap = (wfBitmap*) memblt->bitmap;
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));
406 if (wfi->drawing == wfi->primary)
407 wf_invalidate_region(wfi, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth, memblt->nHeight);
410 void wf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_command)
415 RFX_MESSAGE* message;
416 wfInfo* wfi = ((wfContext*) context)->wfi;
418 RFX_CONTEXT* rfx_context = (RFX_CONTEXT*) wfi->rfx_context;
419 NSC_CONTEXT* nsc_context = (NSC_CONTEXT*) wfi->nsc_context;
421 tile_bitmap = (char*) xzalloc(32);
423 if (surface_bits_command->codecID == CODEC_ID_REMOTEFX)
425 message = rfx_process_message(rfx_context, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength);
428 for (i = 0; i < message->num_tiles; i++)
430 tx = message->tiles[i]->x + surface_bits_command->destLeft;
431 ty = message->tiles[i]->y + surface_bits_command->destTop;
433 freerdp_image_convert(message->tiles[i]->data, wfi->tile->pdata, 64, 64, 32, 32, wfi->clrconv);
435 for (j = 0; j < message->num_rects; j++)
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);
442 BitBlt(wfi->primary->hdc, tx, ty, 64, 64, wfi->tile->hdc, 0, 0, SRCCOPY);
446 wf_set_null_clip_rgn(wfi);
448 /* invalidate regions */
449 for (i = 0; i < message->num_rects; i++)
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);
456 rfx_message_free(rfx_context, message);
458 else if (surface_bits_command->codecID == CODEC_ID_NSCODEC)
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);
471 else if (surface_bits_command->codecID == CODEC_ID_NONE)
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;
477 wfi->image->_bitmap.data = (uint8*) xrealloc(wfi->image->_bitmap.data,
478 wfi->image->_bitmap.width * wfi->image->_bitmap.height * 4);
480 if ((surface_bits_command->bpp != 32) || (wfi->clrconv->alpha == true))
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);
488 surface_bits_command->bpp = 32;
489 surface_bits_command->bitmapData = wfi->image->_bitmap.data;
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;
498 freerdp_image_flip(surface_bits_command->bitmapData, wfi->image->_bitmap.data,
499 wfi->image->_bitmap.width, wfi->image->_bitmap.height, 32);
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);
507 printf("Unsupported codecID %d\n", surface_bits_command->codecID);
510 if (tile_bitmap != NULL)
514 void wf_gdi_register_update_callbacks(rdpUpdate* update)
516 rdpPrimaryUpdate* primary = update->primary;
518 update->Palette = wf_gdi_palette_update;
519 update->SetBounds = wf_gdi_set_bounds;
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;
544 update->SurfaceBits = wf_gdi_surface_bits;