cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

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