void guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap) { guac_client* client = ((rdp_freerdp_context*) context)->client; guac_socket* socket = client->socket; /* Allocate surface */ guac_layer* buffer = guac_client_alloc_buffer(client); guac_common_surface* surface = guac_common_surface_alloc(socket, buffer, bitmap->width, bitmap->height); /* Cache image data if present */ if (bitmap->data != NULL) { /* Create surface from image data */ cairo_surface_t* image = cairo_image_surface_create_for_data( bitmap->data, CAIRO_FORMAT_RGB24, bitmap->width, bitmap->height, 4*bitmap->width); /* Send surface to buffer */ guac_common_surface_draw(surface, 0, 0, image); /* Free surface */ cairo_surface_destroy(image); } /* Store buffer reference in bitmap */ ((guac_rdp_bitmap*) bitmap)->buffer = buffer; ((guac_rdp_bitmap*) bitmap)->surface = surface; }
void guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap) { guac_client* client = ((rdp_freerdp_context*) context)->client; rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data; guac_common_surface* surface = ((guac_rdp_bitmap*) bitmap)->surface; int width = bitmap->right - bitmap->left + 1; int height = bitmap->bottom - bitmap->top + 1; /* If not cached, cache if necessary */ if (surface == NULL && ((guac_rdp_bitmap*) bitmap)->used >= 1) guac_rdp_cache_bitmap(context, bitmap); /* If cached, retrieve from cache */ if (surface != NULL) guac_common_surface_copy(surface, 0, 0, width, height, client_data->default_surface, bitmap->left, bitmap->top); /* Otherwise, draw with stored image data */ else if (bitmap->data != NULL) { /* Create surface from image data */ cairo_surface_t* image = cairo_image_surface_create_for_data( bitmap->data, CAIRO_FORMAT_RGB24, width, height, 4*bitmap->width); /* Draw image on default surface */ guac_common_surface_draw(client_data->default_surface, bitmap->left, bitmap->top, image); /* Free surface */ cairo_surface_destroy(image); } /* Increment usage counter */ ((guac_rdp_bitmap*) bitmap)->used++; }
void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) { guac_client* client = ((rdp_freerdp_context*) context)->client; guac_common_surface* current_surface = ((rdp_guac_client_data*) client->data)->current_surface; guac_rdp_bitmap* bitmap = (guac_rdp_bitmap*) memblt->bitmap; int x = memblt->nLeftRect; int y = memblt->nTopRect; int w = memblt->nWidth; int h = memblt->nHeight; int x_src = memblt->nXSrc; int y_src = memblt->nYSrc; /* Make sure that the recieved bitmap is not NULL before processing */ if (bitmap == NULL) { guac_client_log(client, GUAC_LOG_INFO, "NULL bitmap found in memblt instruction."); return; } switch (memblt->bRop) { /* If blackness, send black rectangle */ case 0x00: guac_common_surface_rect(current_surface, x, y, w, h, 0, 0, 0); break; /* If NOP, do nothing */ case 0xAA: break; /* If operation is just SRC, simply copy */ case 0xCC: /* If not cached, cache if necessary */ if (bitmap->surface == NULL && bitmap->used >= 1) guac_rdp_cache_bitmap(context, memblt->bitmap); /* If not cached, send as PNG */ if (bitmap->surface == NULL) { if (memblt->bitmap->data != NULL) { /* Create surface from image data */ cairo_surface_t* surface = cairo_image_surface_create_for_data( memblt->bitmap->data + 4*(x_src + y_src*memblt->bitmap->width), CAIRO_FORMAT_RGB24, w, h, 4*memblt->bitmap->width); /* Send surface to buffer */ guac_common_surface_draw(current_surface, x, y, surface); /* Free surface */ cairo_surface_destroy(surface); } } /* Otherwise, copy */ else guac_common_surface_copy(bitmap->surface, x_src, y_src, w, h, current_surface, x, y); /* Increment usage counter */ ((guac_rdp_bitmap*) bitmap)->used++; break; /* If whiteness, send white rectangle */ case 0xFF: guac_common_surface_rect(current_surface, x, y, w, h, 0xFF, 0xFF, 0xFF); break; /* Otherwise, use transfer */ default: /* If not available as a surface, make available. */ if (bitmap->surface == NULL) guac_rdp_cache_bitmap(context, memblt->bitmap); guac_common_surface_transfer(bitmap->surface, x_src, y_src, w, h, guac_rdp_rop3_transfer_function(client, memblt->bRop), current_surface, x, y); /* Increment usage counter */ ((guac_rdp_bitmap*) bitmap)->used++; } }
/** * Sends the given character to the terminal at the given row and column, * rendering the character immediately. This bypasses the guac_terminal_display * mechanism and is intended for flushing of updates only. */ int __guac_terminal_set(guac_terminal_display* display, int row, int col, int codepoint) { int width; int bytes; char utf8[4]; /* Use foreground color */ const guac_terminal_color* color = &guac_terminal_palette[display->glyph_foreground]; /* Use background color */ const guac_terminal_color* background = &guac_terminal_palette[display->glyph_background]; cairo_surface_t* surface; cairo_t* cairo; int surface_width, surface_height; PangoLayout* layout; int layout_width, layout_height; int ideal_layout_width, ideal_layout_height; /* Calculate width in columns */ width = wcwidth(codepoint); if (width < 0) width = 1; /* Do nothing if glyph is empty */ if (width == 0) return 0; /* Convert to UTF-8 */ bytes = guac_terminal_encode_utf8(codepoint, utf8); surface_width = width * display->char_width; surface_height = display->char_height; ideal_layout_width = surface_width * PANGO_SCALE; ideal_layout_height = surface_height * PANGO_SCALE; /* Prepare surface */ surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, surface_width, surface_height); cairo = cairo_create(surface); /* Fill background */ cairo_set_source_rgb(cairo, background->red / 255.0, background->green / 255.0, background->blue / 255.0); cairo_rectangle(cairo, 0, 0, surface_width, surface_height); cairo_fill(cairo); /* Get layout */ layout = pango_cairo_create_layout(cairo); pango_layout_set_font_description(layout, display->font_desc); pango_layout_set_text(layout, utf8, bytes); pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); pango_layout_get_size(layout, &layout_width, &layout_height); /* If layout bigger than available space, scale it back */ if (layout_width > ideal_layout_width || layout_height > ideal_layout_height) { double scale = fmin(ideal_layout_width / (double) layout_width, ideal_layout_height / (double) layout_height); cairo_scale(cairo, scale, scale); /* Update layout to reflect scaled surface */ pango_layout_set_width(layout, ideal_layout_width / scale); pango_layout_set_height(layout, ideal_layout_height / scale); pango_cairo_update_layout(cairo, layout); } /* Draw */ cairo_set_source_rgb(cairo, color->red / 255.0, color->green / 255.0, color->blue / 255.0); cairo_move_to(cairo, 0.0, 0.0); pango_cairo_show_layout(cairo, layout); /* Draw */ guac_common_surface_draw(display->display_surface, display->char_width * col, display->char_height * row, surface); /* Free all */ g_object_unref(layout); cairo_destroy(cairo); cairo_surface_destroy(surface); return 0; }