buffer.c (4923B)
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 "config.h" 21#include "buffer.h" 22 23#include <cairo/cairo.h> 24#include <guacamole/mem.h> 25 26#include <assert.h> 27#include <stdlib.h> 28 29guacenc_buffer* guacenc_buffer_alloc() { 30 return guac_mem_zalloc(sizeof(guacenc_buffer)); 31} 32 33/** 34 * Frees the underlying image data, surface, and graphics context of the given 35 * buffer, marking each as unallocated. 36 * 37 * @param buffer 38 * The guacenc_buffer whose image data, surface, and graphics context 39 * should be freed. 40 */ 41static void guacenc_buffer_free_image(guacenc_buffer* buffer) { 42 43 /* Free graphics context */ 44 if (buffer->cairo != NULL) { 45 cairo_destroy(buffer->cairo); 46 buffer->cairo = NULL; 47 } 48 49 /* Free Cairo surface */ 50 if (buffer->surface != NULL) { 51 cairo_surface_destroy(buffer->surface); 52 buffer->surface = NULL; 53 } 54 55 /* Free image data (previously wrapped by Cairo surface */ 56 guac_mem_free(buffer->image); 57 buffer->image = NULL; 58 59} 60 61void guacenc_buffer_free(guacenc_buffer* buffer) { 62 63 /* Ignore NULL buffer */ 64 if (buffer == NULL) 65 return; 66 67 /* Free buffer and underlying image */ 68 guacenc_buffer_free_image(buffer); 69 guac_mem_free(buffer); 70 71} 72 73int guacenc_buffer_resize(guacenc_buffer* buffer, int width, int height) { 74 75 /* Ignore requests which do not change the size */ 76 if (buffer->width == width && buffer->height == height) 77 return 0; 78 79 /* Simply deallocate if new image has absolutely no pixels */ 80 if (width == 0 || height == 0) { 81 guacenc_buffer_free_image(buffer); 82 buffer->width = width; 83 buffer->height = height; 84 buffer->stride = 0; 85 return 0; 86 } 87 88 /* Allocate data for new image */ 89 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); 90 unsigned char* image = guac_mem_zalloc(stride, height); 91 92 /* Wrap data in surface */ 93 cairo_surface_t* surface = cairo_image_surface_create_for_data(image, 94 CAIRO_FORMAT_ARGB32, width, height, stride); 95 96 /* Obtain graphics context of new surface */ 97 cairo_t* cairo = cairo_create(surface); 98 99 /* Copy old surface, if defined */ 100 if (buffer->surface != NULL) { 101 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); 102 cairo_set_source_surface(cairo, buffer->surface, 0, 0); 103 cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); 104 cairo_paint(cairo); 105 } 106 107 /* Update properties */ 108 buffer->width = width; 109 buffer->height = height; 110 buffer->stride = stride; 111 112 /* Replace old image */ 113 guacenc_buffer_free_image(buffer); 114 buffer->image = image; 115 buffer->surface = surface; 116 buffer->cairo = cairo; 117 118 return 0; 119 120} 121 122int guacenc_buffer_fit(guacenc_buffer* buffer, int x, int y) { 123 124 /* Increase width to fit X (if necessary) */ 125 int new_width = buffer->width; 126 if (new_width < x+1) 127 new_width = x+1; 128 129 /* Increase height to fit Y (if necessary) */ 130 int new_height = buffer->height; 131 if (new_height < y+1) 132 new_height = y+1; 133 134 /* Resize buffer if size needs to change to fit X/Y coordinate */ 135 if (new_width != buffer->width || new_height != buffer->height) 136 return guacenc_buffer_resize(buffer, new_width, new_height); 137 138 /* No change necessary */ 139 return 0; 140 141} 142 143int guacenc_buffer_copy(guacenc_buffer* dst, guacenc_buffer* src) { 144 145 /* Resize destination to exactly fit source */ 146 if (guacenc_buffer_resize(dst, src->width, src->height)) 147 return 1; 148 149 /* Copy surface contents identically */ 150 if (src->surface != NULL) { 151 152 /* Destination must be non-NULL as its size is that of the source */ 153 assert(dst->cairo != NULL); 154 155 /* Reset state of destination */ 156 cairo_t* cairo = dst->cairo; 157 cairo_reset_clip(cairo); 158 159 /* Overwrite destination with contents of source */ 160 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); 161 cairo_set_source_surface(cairo, src->surface, 0, 0); 162 cairo_paint(cairo); 163 164 /* Reset operator of destination to default */ 165 cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); 166 167 } 168 169 return 0; 170 171} 172