bitmap.c (5325B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include "bitmap.h" 21#include "common/display.h" 22#include "common/surface.h" 23#include "config.h" 24#include "rdp.h" 25 26#include <cairo/cairo.h> 27#include <freerdp/freerdp.h> 28#include <guacamole/client.h> 29#include <winpr/crt.h> 30#include <winpr/wtypes.h> 31 32#include <stdio.h> 33#include <stdlib.h> 34 35void guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap) { 36 37 guac_client* client = ((rdp_freerdp_context*) context)->client; 38 guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; 39 40 /* Allocate buffer */ 41 guac_common_display_layer* buffer = guac_common_display_alloc_buffer( 42 rdp_client->display, bitmap->width, bitmap->height); 43 44 /* Cache image data if present */ 45 if (bitmap->data != NULL) { 46 47 /* Create surface from image data */ 48 cairo_surface_t* image = cairo_image_surface_create_for_data( 49 bitmap->data, CAIRO_FORMAT_RGB24, 50 bitmap->width, bitmap->height, 4*bitmap->width); 51 52 /* Send surface to buffer */ 53 guac_common_surface_draw(buffer->surface, 0, 0, image); 54 55 /* Free surface */ 56 cairo_surface_destroy(image); 57 58 } 59 60 /* Store buffer reference in bitmap */ 61 ((guac_rdp_bitmap*) bitmap)->layer = buffer; 62 63} 64 65BOOL guac_rdp_bitmap_new(rdpContext* context, rdpBitmap* bitmap) { 66 67 /* No corresponding surface yet - caching is deferred. */ 68 ((guac_rdp_bitmap*) bitmap)->layer = NULL; 69 70 /* Start at zero usage */ 71 ((guac_rdp_bitmap*) bitmap)->used = 0; 72 73 return TRUE; 74 75} 76 77BOOL guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap) { 78 79 guac_client* client = ((rdp_freerdp_context*) context)->client; 80 guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; 81 82 guac_common_display_layer* buffer = ((guac_rdp_bitmap*) bitmap)->layer; 83 84 int width = bitmap->right - bitmap->left + 1; 85 int height = bitmap->bottom - bitmap->top + 1; 86 87 /* If not cached, cache if necessary */ 88 if (buffer == NULL && ((guac_rdp_bitmap*) bitmap)->used >= 1) 89 guac_rdp_cache_bitmap(context, bitmap); 90 91 /* If cached, retrieve from cache */ 92 if (buffer != NULL) 93 guac_common_surface_copy(buffer->surface, 0, 0, width, height, 94 rdp_client->display->default_surface, 95 bitmap->left, bitmap->top); 96 97 /* Otherwise, draw with stored image data */ 98 else if (bitmap->data != NULL) { 99 100 /* Create surface from image data */ 101 cairo_surface_t* image = cairo_image_surface_create_for_data( 102 bitmap->data, CAIRO_FORMAT_RGB24, 103 width, height, 4*bitmap->width); 104 105 /* Draw image on default surface */ 106 guac_common_surface_draw(rdp_client->display->default_surface, 107 bitmap->left, bitmap->top, image); 108 109 /* Free surface */ 110 cairo_surface_destroy(image); 111 112 } 113 114 /* Increment usage counter */ 115 ((guac_rdp_bitmap*) bitmap)->used++; 116 117 return TRUE; 118 119} 120 121void guac_rdp_bitmap_free(rdpContext* context, rdpBitmap* bitmap) { 122 123 guac_client* client = ((rdp_freerdp_context*) context)->client; 124 guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; 125 guac_common_display_layer* buffer = ((guac_rdp_bitmap*) bitmap)->layer; 126 127 /* If cached, free buffer */ 128 if (buffer != NULL) 129 guac_common_display_free_buffer(rdp_client->display, buffer); 130 131#ifndef FREERDP_BITMAP_FREE_FREES_BITMAP 132 /* NOTE: Except in FreeRDP 2.0.0-rc0 and earlier, FreeRDP-allocated memory 133 * for the rdpBitmap will NOT be automatically released after this free 134 * handler is invoked, thus we must do so manually here */ 135 136 _aligned_free(bitmap->data); 137 free(bitmap); 138#endif 139 140} 141 142BOOL guac_rdp_bitmap_setsurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary) { 143 144 guac_client* client = ((rdp_freerdp_context*) context)->client; 145 guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; 146 147 if (primary) 148 rdp_client->current_surface = rdp_client->display->default_surface; 149 150 else { 151 152 /* Make sure that the received bitmap is not NULL before processing */ 153 if (bitmap == NULL) { 154 guac_client_log(client, GUAC_LOG_INFO, "NULL bitmap found in bitmap_setsurface instruction."); 155 return TRUE; 156 } 157 158 /* If not available as a surface, make available. */ 159 if (((guac_rdp_bitmap*) bitmap)->layer == NULL) 160 guac_rdp_cache_bitmap(context, bitmap); 161 162 rdp_client->current_surface = 163 ((guac_rdp_bitmap*) bitmap)->layer->surface; 164 165 } 166 167 return TRUE; 168 169} 170