1 /* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 Copyright (C) 2009 Red Hat, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <config.h>
19
20 #include "canvas_utils.h"
21 #include "mem.h"
22
23 typedef struct PixmanData {
24 uint8_t *data;
25 pixman_format_code_t format;
26 } PixmanData;
27
release_data(SPICE_GNUC_UNUSED pixman_image_t * image,void * release_data)28 static void release_data(SPICE_GNUC_UNUSED pixman_image_t *image,
29 void *release_data)
30 {
31 PixmanData *data = (PixmanData *)release_data;
32
33 free(data->data);
34
35 free(data);
36 }
37
38 static PixmanData *
pixman_image_add_data(pixman_image_t * image)39 pixman_image_add_data(pixman_image_t *image)
40 {
41 PixmanData *data;
42
43 data = (PixmanData *)pixman_image_get_destroy_data(image);
44 if (data == NULL) {
45 data = (PixmanData *)calloc(1, sizeof(PixmanData));
46 if (data == NULL) {
47 spice_error("out of memory");
48 }
49 pixman_image_set_destroy_function(image,
50 release_data,
51 data);
52 }
53
54 return data;
55 }
56
57 void
spice_pixman_image_set_format(pixman_image_t * image,pixman_format_code_t format)58 spice_pixman_image_set_format(pixman_image_t *image,
59 pixman_format_code_t format)
60 {
61 PixmanData *data;
62
63 data = pixman_image_add_data(image);
64 data->format = format;
65 }
66
67
spice_pixman_image_get_format(pixman_image_t * image,pixman_format_code_t * format)68 int spice_pixman_image_get_format(pixman_image_t *image, pixman_format_code_t *format)
69 {
70 PixmanData *data;
71
72 spice_return_val_if_fail(format != NULL, 0);
73
74 data = (PixmanData *)pixman_image_get_destroy_data(image);
75 if (data != NULL && data->format != 0) {
76 *format = data->format;
77 return 1;
78 }
79
80 spice_warn_if_reached();
81 return 0;
82 }
83
surface_create_stride(pixman_format_code_t format,int width,int height,int stride)84 pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
85 int stride)
86 {
87 uint8_t *data;
88 uint8_t *stride_data;
89 pixman_image_t *surface;
90 PixmanData *pixman_data;
91
92 data = (uint8_t *)spice_malloc_n(abs(stride), height);
93 if (stride < 0) {
94 stride_data = data + (-stride) * (height - 1);
95 } else {
96 stride_data = data;
97 }
98
99 surface = pixman_image_create_bits(format, width, height, (uint32_t *)stride_data, stride);
100
101 if (surface == NULL) {
102 free(data);
103 data = NULL;
104 spice_error("create surface failed, out of memory");
105 }
106
107 pixman_data = pixman_image_add_data(surface);
108 pixman_data->data = data;
109 pixman_data->format = format;
110
111 return surface;
112 }
113
surface_create(pixman_format_code_t format,int width,int height,int top_down)114 pixman_image_t * surface_create(pixman_format_code_t format, int width, int height, int top_down)
115 {
116 if (top_down) {
117 pixman_image_t *surface;
118 PixmanData *data;
119
120 surface = pixman_image_create_bits(format, width, height, NULL, 0);
121 data = pixman_image_add_data(surface);
122 data->format = format;
123 return surface;
124 } else {
125 // NOTE: we assume here that the lz decoders always decode to RGB32.
126 int stride = 0;
127 switch (format) {
128 case PIXMAN_a8r8g8b8:
129 case PIXMAN_x8r8g8b8:
130 #ifdef WORDS_BIGENDIAN
131 case PIXMAN_b8g8r8a8:
132 case PIXMAN_b8g8r8x8:
133 #endif
134 stride = width * 4;
135 break;
136 case PIXMAN_r8g8b8:
137 #ifdef WORDS_BIGENDIAN
138 case PIXMAN_b8g8r8:
139 #endif
140 // NOTE: LZ4 also decodes to RGB24
141 stride = SPICE_ALIGN(width * 3, 4);
142 break;
143 case PIXMAN_x1r5g5b5:
144 case PIXMAN_r5g6b5:
145 stride = SPICE_ALIGN(width * 2, 4);
146 break;
147 case PIXMAN_a8:
148 stride = SPICE_ALIGN(width, 4);
149 break;
150 case PIXMAN_a1:
151 stride = SPICE_ALIGN(width, 32) / 8;
152 break;
153 default:
154 spice_error("invalid format");
155 }
156 stride = -stride;
157 return surface_create_stride(format, width, height, stride);
158 }
159 }
160
alloc_lz_image_surface(LzDecodeUsrData * canvas_data,pixman_format_code_t pixman_format,int width,int height,int gross_pixels,int top_down)161 pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
162 pixman_format_code_t pixman_format, int width,
163 int height, int gross_pixels, int top_down)
164 {
165 int stride;
166 pixman_image_t *surface = NULL;
167
168 stride = (gross_pixels / height) * (PIXMAN_FORMAT_BPP (pixman_format) / 8);
169
170 /* pixman requires strides to be 4-byte aligned */
171 stride = SPICE_ALIGN(stride, 4);
172
173 if (!top_down) {
174 stride = -stride;
175 }
176
177 surface = surface_create_stride(pixman_format, width, height, stride);
178 canvas_data->out_surface = surface;
179 return surface;
180 }
181