1
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3
Copyright (C) 2009,2010 Red Hat, Inc.
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.
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.
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/>.
25
#include "common/lz_common.h"
26
#include "red_common.h"
27
#include "red_memslots.h"
28
#include "red_parse_qxl.h"
30
/* Max size in bytes for any data field used in a QXL command.
31
* This will for example be useful to prevent the guest from saturating the
32
* host memory if it tries to send overlapping chunks.
33
* This value should be big enough for all requests but limited
34
* to 32 bits. Even better if it fits on 31 bits to detect integer overflows.
36
#define MAX_DATA_CHUNK 0x7ffffffflu
38
G_STATIC_ASSERT(MAX_DATA_CHUNK <= G_MAXINT32);
41
static void hexdump_qxl(RedMemSlotInfo *slots, int group_id,
42
QXLPHYSICAL addr, uint8_t bytes)
47
hex = (uint8_t*)get_virt(slots, addr, bytes, group_id);
48
for (i = 0; i < bytes; i++) {
50
fprintf(stderr, "%lx: ", addr+i);
55
fprintf(stderr, " %02x", hex[i]);
57
fprintf(stderr, "\n");
63
static inline uint32_t color_16_to_32(uint32_t color)
67
ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
68
ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
69
ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
74
static uint8_t *red_linearize_chunk(RedDataChunk *head, size_t size, bool *free_chunk)
80
if (head->next_chunk == NULL) {
81
spice_assert(size <= head->data_size);
86
ptr = data = spice_malloc(size);
88
for (chunk = head; chunk != NULL && size > 0; chunk = chunk->next_chunk) {
89
copy = MIN(chunk->data_size, size);
90
memcpy(ptr, chunk->data, copy);
94
spice_assert(size == 0);
98
static size_t red_get_data_chunks_ptr(RedMemSlotInfo *slots, int group_id,
100
RedDataChunk *red, QXLDataChunk *qxl)
102
RedDataChunk *red_prev;
103
size_t data_size = 0;
106
red->data_size = qxl->data_size;
107
data_size += red->data_size;
108
if (!validate_virt(slots, (intptr_t)qxl->data, memslot_id, red->data_size, group_id)) {
111
red->data = qxl->data;
112
red->prev_chunk = NULL;
114
while (qxl->next_chunk) {
116
red = spice_new(RedDataChunk, 1);
117
memslot_id = get_memslot_id(slots, qxl->next_chunk);
118
qxl = (QXLDataChunk *)get_virt(slots, qxl->next_chunk, sizeof(*qxl), group_id,
123
red->data_size = qxl->data_size;
124
data_size += red->data_size;
125
if (!validate_virt(slots, (intptr_t)qxl->data, memslot_id, red->data_size, group_id)) {
128
red->data = qxl->data;
129
red->prev_chunk = red_prev;
130
red_prev->next_chunk = red;
133
red->next_chunk = NULL;
137
static size_t red_get_data_chunks(RedMemSlotInfo *slots, int group_id,
138
RedDataChunk *red, QXLPHYSICAL addr)
142
int memslot_id = get_memslot_id(slots, addr);
144
qxl = (QXLDataChunk *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
148
return red_get_data_chunks_ptr(slots, group_id, memslot_id, red, qxl);
151
static void red_put_data_chunks(RedDataChunk *red)
155
red = red->next_chunk;
158
red = red->next_chunk;
163
static void red_get_point_ptr(SpicePoint *red, QXLPoint *qxl)
169
static void red_get_point16_ptr(SpicePoint16 *red, QXLPoint16 *qxl)
175
void red_get_rect_ptr(SpiceRect *red, const QXLRect *qxl)
178
red->left = qxl->left;
179
red->bottom = qxl->bottom;
180
red->right = qxl->right;
183
static SpicePath *red_get_path(RedMemSlotInfo *slots, int group_id,
187
QXLPathSeg *start, *end;
193
size_t size, mem_size, mem_size2, dsize, segment_size;
199
qxl = (QXLPath *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
203
size = red_get_data_chunks_ptr(slots, group_id,
204
get_memslot_id(slots, addr),
205
&chunks, &qxl->chunk);
206
data = red_linearize_chunk(&chunks, size, &free_data);
207
red_put_data_chunks(&chunks);
210
mem_size = sizeof(*red);
212
start = (QXLPathSeg*)data;
213
end = (QXLPathSeg*)(data + size);
214
while (start < end) {
216
count = start->count;
217
segment_size = sizeof(SpicePathSeg) + count * sizeof(SpicePointFix);
218
mem_size += sizeof(SpicePathSeg *) + SPICE_ALIGN(segment_size, 4);
219
start = (QXLPathSeg*)(&start->points[count]);
222
red = spice_malloc(mem_size);
223
red->num_segments = n_segments;
225
start = (QXLPathSeg*)data;
226
end = (QXLPathSeg*)(data + size);
227
seg = (SpicePathSeg*)&red->segments[n_segments];
229
mem_size2 = sizeof(*red);
230
while (start < end) {
231
red->segments[n_segments++] = seg;
232
count = start->count;
234
/* Protect against overflow in size calculations before
236
spice_assert(mem_size2 + sizeof(SpicePathSeg) > mem_size2);
237
mem_size2 += sizeof(SpicePathSeg);
238
spice_assert(count < UINT32_MAX / sizeof(SpicePointFix));
239
dsize = count * sizeof(SpicePointFix);
240
spice_assert(mem_size2 + dsize > mem_size2);
243
/* Verify that we didn't overflow due to guest changing data */
244
spice_assert(mem_size2 <= mem_size);
246
seg->flags = start->flags;
248
for (i = 0; i < seg->count; i++) {
249
seg->points[i].x = start->points[i].x;
250
seg->points[i].y = start->points[i].y;
252
start = (QXLPathSeg*)(&start->points[i]);
253
seg = (SpicePathSeg*)(&seg->points[i]);
255
/* Ensure guest didn't tamper with segment count */
256
spice_assert(n_segments == red->num_segments);
264
static SpiceClipRects *red_get_clip_rects(RedMemSlotInfo *slots, int group_id,
277
qxl = (QXLClipRects *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
281
size = red_get_data_chunks_ptr(slots, group_id,
282
get_memslot_id(slots, addr),
283
&chunks, &qxl->chunk);
284
data = red_linearize_chunk(&chunks, size, &free_data);
285
red_put_data_chunks(&chunks);
287
spice_assert(qxl->num_rects * sizeof(QXLRect) == size);
288
red = spice_malloc(sizeof(*red) + qxl->num_rects * sizeof(SpiceRect));
289
red->num_rects = qxl->num_rects;
291
start = (QXLRect*)data;
292
for (i = 0; i < red->num_rects; i++) {
293
red_get_rect_ptr(red->rects + i, start++);
302
static SpiceChunks *red_get_image_data_flat(RedMemSlotInfo *slots, int group_id,
303
QXLPHYSICAL addr, size_t size)
308
data = spice_chunks_new(1);
309
data->data_size = size;
310
data->chunk[0].data = (void*)get_virt(slots, addr, size, group_id, &error);
314
data->chunk[0].len = size;
318
static SpiceChunks *red_get_image_data_chunked(RedMemSlotInfo *slots, int group_id,
325
for (i = 0, chunk = head; chunk != NULL; chunk = chunk->next_chunk) {
329
data = spice_chunks_new(i);
331
for (i = 0, chunk = head;
332
chunk != NULL && i < data->num_chunks;
333
chunk = chunk->next_chunk, i++) {
334
data->chunk[i].data = chunk->data;
335
data->chunk[i].len = chunk->data_size;
336
data->data_size += chunk->data_size;
338
spice_assert(i == data->num_chunks);
342
static const char *bitmap_format_to_string(int format)
345
case SPICE_BITMAP_FMT_INVALID: return "SPICE_BITMAP_FMT_INVALID";
346
case SPICE_BITMAP_FMT_1BIT_LE: return "SPICE_BITMAP_FMT_1BIT_LE";
347
case SPICE_BITMAP_FMT_1BIT_BE: return "SPICE_BITMAP_FMT_1BIT_BE";
348
case SPICE_BITMAP_FMT_4BIT_LE: return "SPICE_BITMAP_FMT_4BIT_LE";
349
case SPICE_BITMAP_FMT_4BIT_BE: return "SPICE_BITMAP_FMT_4BIT_BE";
350
case SPICE_BITMAP_FMT_8BIT: return "SPICE_BITMAP_FMT_8BIT";
351
case SPICE_BITMAP_FMT_16BIT: return "SPICE_BITMAP_FMT_16BIT";
352
case SPICE_BITMAP_FMT_24BIT: return "SPICE_BITMAP_FMT_24BIT";
353
case SPICE_BITMAP_FMT_32BIT: return "SPICE_BITMAP_FMT_32BIT";
354
case SPICE_BITMAP_FMT_RGBA: return "SPICE_BITMAP_FMT_RGBA";
355
case SPICE_BITMAP_FMT_8BIT_A: return "SPICE_BITMAP_FMT_8BIT_A";
360
static const int MAP_BITMAP_FMT_TO_BITS_PER_PIXEL[] = {0, 1, 1, 4, 4, 8, 16, 24, 32, 32, 8};
362
static int bitmap_consistent(SpiceBitmap *bitmap)
364
int bpp = MAP_BITMAP_FMT_TO_BITS_PER_PIXEL[bitmap->format];
366
if (bitmap->stride < ((bitmap->x * bpp + 7) / 8)) {
367
spice_warning("image stride too small for width: %d < ((%d * %d + 7) / 8) (%s=%d)\n",
368
bitmap->stride, bitmap->x, bpp,
369
bitmap_format_to_string(bitmap->format),
376
// This is based on SPICE_BITMAP_FMT_*, copied from server/red_worker.c
377
// to avoid a possible unoptimization from making it non static.
378
static const int BITMAP_FMT_IS_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
380
static SpiceImage *red_get_image(RedMemSlotInfo *slots, int group_id,
381
QXLPHYSICAL addr, uint32_t flags, int is_mask)
385
SpiceImage *red = NULL;
386
SpicePalette *rp = NULL;
387
uint64_t bitmap_size, size;
395
qxl = (QXLImage *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
399
red = spice_new0(SpiceImage, 1);
400
red->descriptor.id = qxl->descriptor.id;
401
red->descriptor.type = qxl->descriptor.type;
402
red->descriptor.flags = 0;
403
if (qxl->descriptor.flags & QXL_IMAGE_HIGH_BITS_SET) {
404
red->descriptor.flags |= SPICE_IMAGE_FLAGS_HIGH_BITS_SET;
406
if (qxl->descriptor.flags & QXL_IMAGE_CACHE) {
407
red->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME;
409
red->descriptor.width = qxl->descriptor.width;
410
red->descriptor.height = qxl->descriptor.height;
412
switch (red->descriptor.type) {
413
case SPICE_IMAGE_TYPE_BITMAP:
414
red->u.bitmap.format = qxl->bitmap.format;
415
if (!bitmap_fmt_is_rgb(qxl->bitmap.format) && !qxl->bitmap.palette && !is_mask) {
416
spice_warning("guest error: missing palette on bitmap format=%d\n",
417
red->u.bitmap.format);
420
if (qxl->bitmap.x == 0 || qxl->bitmap.y == 0) {
421
spice_warning("guest error: zero area bitmap\n");
424
qxl_flags = qxl->bitmap.flags;
425
if (qxl_flags & QXL_BITMAP_TOP_DOWN) {
426
red->u.bitmap.flags = SPICE_BITMAP_FLAGS_TOP_DOWN;
428
red->u.bitmap.x = qxl->bitmap.x;
429
red->u.bitmap.y = qxl->bitmap.y;
430
red->u.bitmap.stride = qxl->bitmap.stride;
431
if (!bitmap_consistent(&red->u.bitmap)) {
434
if (qxl->bitmap.palette) {
437
qp = (QXLPalette *)get_virt(slots, qxl->bitmap.palette,
438
sizeof(*qp), group_id, &error);
442
num_ents = qp->num_ents;
443
if (!validate_virt(slots, (intptr_t)qp->ents,
444
get_memslot_id(slots, qxl->bitmap.palette),
445
num_ents * sizeof(qp->ents[0]), group_id)) {
448
rp = spice_malloc_n_m(num_ents, sizeof(rp->ents[0]), sizeof(*rp));
449
rp->unique = qp->unique;
450
rp->num_ents = num_ents;
451
if (flags & QXL_COMMAND_FLAG_COMPAT_16BPP) {
452
for (i = 0; i < num_ents; i++) {
453
rp->ents[i] = color_16_to_32(qp->ents[i]);
456
for (i = 0; i < num_ents; i++) {
457
rp->ents[i] = qp->ents[i];
460
red->u.bitmap.palette = rp;
461
red->u.bitmap.palette_id = rp->unique;
463
bitmap_size = (uint64_t) red->u.bitmap.y * red->u.bitmap.stride;
464
if (bitmap_size > MAX_DATA_CHUNK) {
467
if (qxl_flags & QXL_BITMAP_DIRECT) {
468
red->u.bitmap.data = red_get_image_data_flat(slots, group_id,
472
size = red_get_data_chunks(slots, group_id,
473
&chunks, qxl->bitmap.data);
474
spice_assert(size == bitmap_size);
475
if (size != bitmap_size) {
478
red->u.bitmap.data = red_get_image_data_chunked(slots, group_id,
480
red_put_data_chunks(&chunks);
482
if (qxl_flags & QXL_BITMAP_UNSTABLE) {
483
red->u.bitmap.data->flags |= SPICE_CHUNKS_FLAGS_UNSTABLE;
486
case SPICE_IMAGE_TYPE_SURFACE:
487
red->u.surface.surface_id = qxl->surface_image.surface_id;
489
case SPICE_IMAGE_TYPE_QUIC:
490
red->u.quic.data_size = qxl->quic.data_size;
491
size = red_get_data_chunks_ptr(slots, group_id,
492
get_memslot_id(slots, addr),
493
&chunks, (QXLDataChunk *)qxl->quic.data);
494
spice_assert(size == red->u.quic.data_size);
495
if (size != red->u.quic.data_size) {
498
red->u.quic.data = red_get_image_data_chunked(slots, group_id,
500
red_put_data_chunks(&chunks);
503
spice_warning("unknown type %d", red->descriptor.type);
513
void red_put_image(SpiceImage *red)
518
switch (red->descriptor.type) {
519
case SPICE_IMAGE_TYPE_BITMAP:
520
free(red->u.bitmap.palette);
521
spice_chunks_destroy(red->u.bitmap.data);
523
case SPICE_IMAGE_TYPE_QUIC:
524
spice_chunks_destroy(red->u.quic.data);
530
static void red_get_brush_ptr(RedMemSlotInfo *slots, int group_id,
531
SpiceBrush *red, QXLBrush *qxl, uint32_t flags)
533
red->type = qxl->type;
535
case SPICE_BRUSH_TYPE_SOLID:
536
if (flags & QXL_COMMAND_FLAG_COMPAT_16BPP) {
537
red->u.color = color_16_to_32(qxl->u.color);
539
red->u.color = qxl->u.color;
542
case SPICE_BRUSH_TYPE_PATTERN:
543
red->u.pattern.pat = red_get_image(slots, group_id, qxl->u.pattern.pat, flags, FALSE);
548
static void red_put_brush(SpiceBrush *red)
551
case SPICE_BRUSH_TYPE_PATTERN:
552
red_put_image(red->u.pattern.pat);
557
static void red_get_qmask_ptr(RedMemSlotInfo *slots, int group_id,
558
SpiceQMask *red, QXLQMask *qxl, uint32_t flags)
560
red->flags = qxl->flags;
561
red_get_point_ptr(&red->pos, &qxl->pos);
562
red->bitmap = red_get_image(slots, group_id, qxl->bitmap, flags, TRUE);
565
static void red_put_qmask(SpiceQMask *red)
567
red_put_image(red->bitmap);
570
static void red_get_fill_ptr(RedMemSlotInfo *slots, int group_id,
571
SpiceFill *red, QXLFill *qxl, uint32_t flags)
573
red_get_brush_ptr(slots, group_id, &red->brush, &qxl->brush, flags);
574
red->rop_descriptor = qxl->rop_descriptor;
575
red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
578
static void red_put_fill(SpiceFill *red)
580
red_put_brush(&red->brush);
581
red_put_qmask(&red->mask);
584
static void red_get_opaque_ptr(RedMemSlotInfo *slots, int group_id,
585
SpiceOpaque *red, QXLOpaque *qxl, uint32_t flags)
587
red->src_bitmap = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
588
red_get_rect_ptr(&red->src_area, &qxl->src_area);
589
red_get_brush_ptr(slots, group_id, &red->brush, &qxl->brush, flags);
590
red->rop_descriptor = qxl->rop_descriptor;
591
red->scale_mode = qxl->scale_mode;
592
red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
595
static void red_put_opaque(SpiceOpaque *red)
597
red_put_image(red->src_bitmap);
598
red_put_brush(&red->brush);
599
red_put_qmask(&red->mask);
602
static int red_get_copy_ptr(RedMemSlotInfo *slots, int group_id,
603
SpiceCopy *red, QXLCopy *qxl, uint32_t flags)
605
red->src_bitmap = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
606
if (!red->src_bitmap) {
609
red_get_rect_ptr(&red->src_area, &qxl->src_area);
610
red->rop_descriptor = qxl->rop_descriptor;
611
red->scale_mode = qxl->scale_mode;
612
red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
616
static void red_put_copy(SpiceCopy *red)
618
red_put_image(red->src_bitmap);
619
red_put_qmask(&red->mask);
622
static void red_get_blend_ptr(RedMemSlotInfo *slots, int group_id,
623
SpiceBlend *red, QXLBlend *qxl, uint32_t flags)
625
red->src_bitmap = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
626
red_get_rect_ptr(&red->src_area, &qxl->src_area);
627
red->rop_descriptor = qxl->rop_descriptor;
628
red->scale_mode = qxl->scale_mode;
629
red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
632
static void red_put_blend(SpiceBlend *red)
634
red_put_image(red->src_bitmap);
635
red_put_qmask(&red->mask);
638
static void red_get_transparent_ptr(RedMemSlotInfo *slots, int group_id,
639
SpiceTransparent *red, QXLTransparent *qxl,
642
red->src_bitmap = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
643
red_get_rect_ptr(&red->src_area, &qxl->src_area);
644
red->src_color = qxl->src_color;
645
red->true_color = qxl->true_color;
648
static void red_put_transparent(SpiceTransparent *red)
650
red_put_image(red->src_bitmap);
653
static void red_get_alpha_blend_ptr(RedMemSlotInfo *slots, int group_id,
654
SpiceAlphaBlend *red, QXLAlphaBlend *qxl,
657
red->alpha_flags = qxl->alpha_flags;
658
red->alpha = qxl->alpha;
659
red->src_bitmap = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
660
red_get_rect_ptr(&red->src_area, &qxl->src_area);
663
static void red_get_alpha_blend_ptr_compat(RedMemSlotInfo *slots, int group_id,
664
SpiceAlphaBlend *red, QXLCompatAlphaBlend *qxl,
667
red->alpha = qxl->alpha;
668
red->src_bitmap = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
669
red_get_rect_ptr(&red->src_area, &qxl->src_area);
672
static void red_put_alpha_blend(SpiceAlphaBlend *red)
674
red_put_image(red->src_bitmap);
677
static bool get_transform(RedMemSlotInfo *slots,
679
QXLPHYSICAL qxl_transform,
680
SpiceTransform *dst_transform)
682
const uint32_t *t = NULL;
685
if (qxl_transform == 0)
688
t = (uint32_t *)get_virt(slots, qxl_transform, sizeof(*dst_transform), group_id, &error);
693
memcpy(dst_transform, t, sizeof(*dst_transform));
697
static void red_get_composite_ptr(RedMemSlotInfo *slots, int group_id,
698
SpiceComposite *red, QXLComposite *qxl, uint32_t flags)
700
red->flags = qxl->flags;
702
red->src_bitmap = red_get_image(slots, group_id, qxl->src, flags, FALSE);
703
if (get_transform(slots, group_id, qxl->src_transform, &red->src_transform))
704
red->flags |= SPICE_COMPOSITE_HAS_SRC_TRANSFORM;
707
red->mask_bitmap = red_get_image(slots, group_id, qxl->mask, flags, FALSE);
708
red->flags |= SPICE_COMPOSITE_HAS_MASK;
709
if (get_transform(slots, group_id, qxl->mask_transform, &red->mask_transform))
710
red->flags |= SPICE_COMPOSITE_HAS_MASK_TRANSFORM;
712
red->mask_bitmap = NULL;
714
red->src_origin.x = qxl->src_origin.x;
715
red->src_origin.y = qxl->src_origin.y;
716
red->mask_origin.x = qxl->mask_origin.x;
717
red->mask_origin.y = qxl->mask_origin.y;
720
static void red_put_composite(SpiceComposite *red)
722
red_put_image(red->src_bitmap);
723
if (red->mask_bitmap)
724
red_put_image(red->mask_bitmap);
727
static void red_get_rop3_ptr(RedMemSlotInfo *slots, int group_id,
728
SpiceRop3 *red, QXLRop3 *qxl, uint32_t flags)
730
red->src_bitmap = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
731
red_get_rect_ptr(&red->src_area, &qxl->src_area);
732
red_get_brush_ptr(slots, group_id, &red->brush, &qxl->brush, flags);
733
red->rop3 = qxl->rop3;
734
red->scale_mode = qxl->scale_mode;
735
red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
738
static void red_put_rop3(SpiceRop3 *red)
740
red_put_image(red->src_bitmap);
741
red_put_brush(&red->brush);
742
red_put_qmask(&red->mask);
745
static int red_get_stroke_ptr(RedMemSlotInfo *slots, int group_id,
746
SpiceStroke *red, QXLStroke *qxl, uint32_t flags)
750
red->path = red_get_path(slots, group_id, qxl->path);
754
red->attr.flags = qxl->attr.flags;
755
if (red->attr.flags & SPICE_LINE_FLAGS_STYLED) {
759
style_nseg = qxl->attr.style_nseg;
760
red->attr.style = spice_malloc_n(style_nseg, sizeof(SPICE_FIXED28_4));
761
red->attr.style_nseg = style_nseg;
762
spice_assert(qxl->attr.style);
763
buf = (uint8_t *)get_virt(slots, qxl->attr.style,
764
style_nseg * sizeof(QXLFIXED), group_id, &error);
768
memcpy(red->attr.style, buf, style_nseg * sizeof(QXLFIXED));
770
red->attr.style_nseg = 0;
771
red->attr.style = NULL;
773
red_get_brush_ptr(slots, group_id, &red->brush, &qxl->brush, flags);
774
red->fore_mode = qxl->fore_mode;
775
red->back_mode = qxl->back_mode;
779
static void red_put_stroke(SpiceStroke *red)
781
red_put_brush(&red->brush);
783
if (red->attr.flags & SPICE_LINE_FLAGS_STYLED) {
784
free(red->attr.style);
788
static SpiceString *red_get_string(RedMemSlotInfo *slots, int group_id,
793
QXLRasterGlyph *start, *end;
795
SpiceRasterGlyph *glyph;
798
size_t chunk_size, qxl_size, red_size, glyph_size;
799
int glyphs, bpp = 0, i;
802
qxl = (QXLString *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
806
chunk_size = red_get_data_chunks_ptr(slots, group_id,
807
get_memslot_id(slots, addr),
808
&chunks, &qxl->chunk);
810
/* XXX could be a zero sized string.. */
813
data = red_linearize_chunk(&chunks, chunk_size, &free_data);
814
red_put_data_chunks(&chunks);
816
qxl_size = qxl->data_size;
817
spice_assert(chunk_size == qxl_size);
819
if (qxl->flags & SPICE_STRING_FLAGS_RASTER_A1) {
821
} else if (qxl->flags & SPICE_STRING_FLAGS_RASTER_A4) {
823
} else if (qxl->flags & SPICE_STRING_FLAGS_RASTER_A8) {
826
spice_assert(bpp != 0);
828
start = (QXLRasterGlyph*)data;
829
end = (QXLRasterGlyph*)(data + chunk_size);
830
red_size = sizeof(SpiceString);
832
while (start < end) {
833
spice_assert((QXLRasterGlyph*)(&start->data[0]) <= end);
835
glyph_size = start->height * ((start->width * bpp + 7) / 8);
836
red_size += sizeof(SpiceRasterGlyph *) + SPICE_ALIGN(sizeof(SpiceRasterGlyph) + glyph_size, 4);
837
start = (QXLRasterGlyph*)(&start->data[glyph_size]);
839
spice_assert(start <= end);
840
spice_assert(glyphs == qxl->length);
842
red = spice_malloc(red_size);
843
red->length = qxl->length;
844
red->flags = qxl->flags;
846
start = (QXLRasterGlyph*)data;
847
end = (QXLRasterGlyph*)(data + chunk_size);
848
glyph = (SpiceRasterGlyph *)&red->glyphs[red->length];
849
for (i = 0; i < red->length; i++) {
850
spice_assert((QXLRasterGlyph*)(&start->data[0]) <= end);
851
red->glyphs[i] = glyph;
852
glyph->width = start->width;
853
glyph->height = start->height;
854
red_get_point_ptr(&glyph->render_pos, &start->render_pos);
855
red_get_point_ptr(&glyph->glyph_origin, &start->glyph_origin);
856
glyph_size = glyph->height * ((glyph->width * bpp + 7) / 8);
857
spice_assert((QXLRasterGlyph*)(&start->data[glyph_size]) <= end);
858
memcpy(glyph->data, start->data, glyph_size);
859
start = (QXLRasterGlyph*)(&start->data[glyph_size]);
860
glyph = (SpiceRasterGlyph*)
861
(((uint8_t *)glyph) +
862
SPICE_ALIGN(sizeof(SpiceRasterGlyph) + glyph_size, 4));
871
static void red_get_text_ptr(RedMemSlotInfo *slots, int group_id,
872
SpiceText *red, QXLText *qxl, uint32_t flags)
874
red->str = red_get_string(slots, group_id, qxl->str);
875
red_get_rect_ptr(&red->back_area, &qxl->back_area);
876
red_get_brush_ptr(slots, group_id, &red->fore_brush, &qxl->fore_brush, flags);
877
red_get_brush_ptr(slots, group_id, &red->back_brush, &qxl->back_brush, flags);
878
red->fore_mode = qxl->fore_mode;
879
red->back_mode = qxl->back_mode;
882
static void red_put_text_ptr(SpiceText *red)
885
red_put_brush(&red->fore_brush);
886
red_put_brush(&red->back_brush);
889
static void red_get_whiteness_ptr(RedMemSlotInfo *slots, int group_id,
890
SpiceWhiteness *red, QXLWhiteness *qxl, uint32_t flags)
892
red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
895
static void red_put_whiteness(SpiceWhiteness *red)
897
red_put_qmask(&red->mask);
900
static void red_get_blackness_ptr(RedMemSlotInfo *slots, int group_id,
901
SpiceBlackness *red, QXLBlackness *qxl, uint32_t flags)
903
red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
906
static void red_put_blackness(SpiceWhiteness *red)
908
red_put_qmask(&red->mask);
911
static void red_get_invers_ptr(RedMemSlotInfo *slots, int group_id,
912
SpiceInvers *red, QXLInvers *qxl, uint32_t flags)
914
red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
917
static void red_put_invers(SpiceWhiteness *red)
919
red_put_qmask(&red->mask);
922
static void red_get_clip_ptr(RedMemSlotInfo *slots, int group_id,
923
SpiceClip *red, QXLClip *qxl)
925
red->type = qxl->type;
927
case SPICE_CLIP_TYPE_RECTS:
928
red->rects = red_get_clip_rects(slots, group_id, qxl->data);
933
static void red_put_clip(SpiceClip *red)
936
case SPICE_CLIP_TYPE_RECTS:
942
static int red_get_native_drawable(RedMemSlotInfo *slots, int group_id,
943
RedDrawable *red, QXLPHYSICAL addr, uint32_t flags)
949
qxl = (QXLDrawable *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
953
red->release_info = &qxl->release_info;
955
red_get_rect_ptr(&red->bbox, &qxl->bbox);
956
red_get_clip_ptr(slots, group_id, &red->clip, &qxl->clip);
957
red->effect = qxl->effect;
958
red->mm_time = qxl->mm_time;
959
red->self_bitmap = qxl->self_bitmap;
960
red_get_rect_ptr(&red->self_bitmap_area, &qxl->self_bitmap_area);
961
red->surface_id = qxl->surface_id;
963
for (i = 0; i < 3; i++) {
964
red->surfaces_dest[i] = qxl->surfaces_dest[i];
965
red_get_rect_ptr(&red->surfaces_rects[i], &qxl->surfaces_rects[i]);
968
red->type = qxl->type;
970
case QXL_DRAW_ALPHA_BLEND:
971
red_get_alpha_blend_ptr(slots, group_id,
972
&red->u.alpha_blend, &qxl->u.alpha_blend, flags);
974
case QXL_DRAW_BLACKNESS:
975
red_get_blackness_ptr(slots, group_id,
976
&red->u.blackness, &qxl->u.blackness, flags);
979
red_get_blend_ptr(slots, group_id, &red->u.blend, &qxl->u.blend, flags);
982
error = red_get_copy_ptr(slots, group_id, &red->u.copy, &qxl->u.copy, flags);
985
red_get_point_ptr(&red->u.copy_bits.src_pos, &qxl->u.copy_bits.src_pos);
988
red_get_fill_ptr(slots, group_id, &red->u.fill, &qxl->u.fill, flags);
990
case QXL_DRAW_OPAQUE:
991
red_get_opaque_ptr(slots, group_id, &red->u.opaque, &qxl->u.opaque, flags);
993
case QXL_DRAW_INVERS:
994
red_get_invers_ptr(slots, group_id, &red->u.invers, &qxl->u.invers, flags);
999
red_get_rop3_ptr(slots, group_id, &red->u.rop3, &qxl->u.rop3, flags);
1001
case QXL_DRAW_COMPOSITE:
1002
red_get_composite_ptr(slots, group_id, &red->u.composite, &qxl->u.composite, flags);
1004
case QXL_DRAW_STROKE:
1005
error = red_get_stroke_ptr(slots, group_id, &red->u.stroke, &qxl->u.stroke, flags);
1008
red_get_text_ptr(slots, group_id, &red->u.text, &qxl->u.text, flags);
1010
case QXL_DRAW_TRANSPARENT:
1011
red_get_transparent_ptr(slots, group_id,
1012
&red->u.transparent, &qxl->u.transparent, flags);
1014
case QXL_DRAW_WHITENESS:
1015
red_get_whiteness_ptr(slots, group_id,
1016
&red->u.whiteness, &qxl->u.whiteness, flags);
1019
spice_warning("unknown type %d", red->type);
1026
static int red_get_compat_drawable(RedMemSlotInfo *slots, int group_id,
1027
RedDrawable *red, QXLPHYSICAL addr, uint32_t flags)
1029
QXLCompatDrawable *qxl;
1032
qxl = (QXLCompatDrawable *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
1036
red->release_info = &qxl->release_info;
1038
red_get_rect_ptr(&red->bbox, &qxl->bbox);
1039
red_get_clip_ptr(slots, group_id, &red->clip, &qxl->clip);
1040
red->effect = qxl->effect;
1041
red->mm_time = qxl->mm_time;
1043
red->self_bitmap = (qxl->bitmap_offset != 0);
1044
red_get_rect_ptr(&red->self_bitmap_area, &qxl->bitmap_area);
1046
red->surfaces_dest[0] = -1;
1047
red->surfaces_dest[1] = -1;
1048
red->surfaces_dest[2] = -1;
1050
red->type = qxl->type;
1051
switch (red->type) {
1052
case QXL_DRAW_ALPHA_BLEND:
1053
red_get_alpha_blend_ptr_compat(slots, group_id,
1054
&red->u.alpha_blend, &qxl->u.alpha_blend, flags);
1056
case QXL_DRAW_BLACKNESS:
1057
red_get_blackness_ptr(slots, group_id,
1058
&red->u.blackness, &qxl->u.blackness, flags);
1060
case QXL_DRAW_BLEND:
1061
red_get_blend_ptr(slots, group_id, &red->u.blend, &qxl->u.blend, flags);
1064
error = red_get_copy_ptr(slots, group_id, &red->u.copy, &qxl->u.copy, flags);
1067
red_get_point_ptr(&red->u.copy_bits.src_pos, &qxl->u.copy_bits.src_pos);
1068
red->surfaces_dest[0] = 0;
1069
red->surfaces_rects[0].left = red->u.copy_bits.src_pos.x;
1070
red->surfaces_rects[0].right = red->u.copy_bits.src_pos.x +
1071
(red->bbox.right - red->bbox.left);
1072
red->surfaces_rects[0].top = red->u.copy_bits.src_pos.y;
1073
red->surfaces_rects[0].bottom = red->u.copy_bits.src_pos.y +
1074
(red->bbox.bottom - red->bbox.top);
1077
red_get_fill_ptr(slots, group_id, &red->u.fill, &qxl->u.fill, flags);
1079
case QXL_DRAW_OPAQUE:
1080
red_get_opaque_ptr(slots, group_id, &red->u.opaque, &qxl->u.opaque, flags);
1082
case QXL_DRAW_INVERS:
1083
red_get_invers_ptr(slots, group_id, &red->u.invers, &qxl->u.invers, flags);
1088
red_get_rop3_ptr(slots, group_id, &red->u.rop3, &qxl->u.rop3, flags);
1090
case QXL_DRAW_STROKE:
1091
error = red_get_stroke_ptr(slots, group_id, &red->u.stroke, &qxl->u.stroke, flags);
1094
red_get_text_ptr(slots, group_id, &red->u.text, &qxl->u.text, flags);
1096
case QXL_DRAW_TRANSPARENT:
1097
red_get_transparent_ptr(slots, group_id,
1098
&red->u.transparent, &qxl->u.transparent, flags);
1100
case QXL_DRAW_WHITENESS:
1101
red_get_whiteness_ptr(slots, group_id,
1102
&red->u.whiteness, &qxl->u.whiteness, flags);
1105
spice_warning("unknown type %d", red->type);
1112
int red_get_drawable(RedMemSlotInfo *slots, int group_id,
1113
RedDrawable *red, QXLPHYSICAL addr, uint32_t flags)
1117
if (flags & QXL_COMMAND_FLAG_COMPAT) {
1118
ret = red_get_compat_drawable(slots, group_id, red, addr, flags);
1120
ret = red_get_native_drawable(slots, group_id, red, addr, flags);
1125
void red_put_drawable(RedDrawable *red)
1127
red_put_clip(&red->clip);
1128
if (red->self_bitmap_image) {
1129
red_put_image(red->self_bitmap_image);
1131
switch (red->type) {
1132
case QXL_DRAW_ALPHA_BLEND:
1133
red_put_alpha_blend(&red->u.alpha_blend);
1135
case QXL_DRAW_BLACKNESS:
1136
red_put_blackness(&red->u.blackness);
1138
case QXL_DRAW_BLEND:
1139
red_put_blend(&red->u.blend);
1142
red_put_copy(&red->u.copy);
1145
red_put_fill(&red->u.fill);
1147
case QXL_DRAW_OPAQUE:
1148
red_put_opaque(&red->u.opaque);
1150
case QXL_DRAW_INVERS:
1151
red_put_invers(&red->u.invers);
1154
red_put_rop3(&red->u.rop3);
1156
case QXL_DRAW_COMPOSITE:
1157
red_put_composite(&red->u.composite);
1159
case QXL_DRAW_STROKE:
1160
red_put_stroke(&red->u.stroke);
1163
red_put_text_ptr(&red->u.text);
1165
case QXL_DRAW_TRANSPARENT:
1166
red_put_transparent(&red->u.transparent);
1168
case QXL_DRAW_WHITENESS:
1169
red_put_whiteness(&red->u.whiteness);
1174
int red_get_update_cmd(RedMemSlotInfo *slots, int group_id,
1175
RedUpdateCmd *red, QXLPHYSICAL addr)
1180
qxl = (QXLUpdateCmd *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
1184
red->release_info = &qxl->release_info;
1186
red_get_rect_ptr(&red->area, &qxl->area);
1187
red->update_id = qxl->update_id;
1188
red->surface_id = qxl->surface_id;
1192
void red_put_update_cmd(RedUpdateCmd *red)
1197
int red_get_message(RedMemSlotInfo *slots, int group_id,
1198
RedMessage *red, QXLPHYSICAL addr)
1205
* qxl->data[0] size isn't specified anywhere -> can't verify
1206
* luckily this is for debug logging only,
1207
* so we can just ignore it by default.
1209
qxl = (QXLMessage *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
1213
red->release_info = &qxl->release_info;
1214
red->data = qxl->data;
1218
void red_put_message(RedMessage *red)
1223
int red_get_surface_cmd(RedMemSlotInfo *slots, int group_id,
1224
RedSurfaceCmd *red, QXLPHYSICAL addr)
1230
qxl = (QXLSurfaceCmd *)get_virt(slots, addr, sizeof(*qxl), group_id,
1235
red->release_info = &qxl->release_info;
1237
red->surface_id = qxl->surface_id;
1238
red->type = qxl->type;
1239
red->flags = qxl->flags;
1241
switch (red->type) {
1242
case QXL_SURFACE_CMD_CREATE:
1243
red->u.surface_create.format = qxl->u.surface_create.format;
1244
red->u.surface_create.width = qxl->u.surface_create.width;
1245
red->u.surface_create.height = qxl->u.surface_create.height;
1246
red->u.surface_create.stride = qxl->u.surface_create.stride;
1247
/* the multiplication can overflow, also abs(-2^31) may return a negative value */
1248
size = (uint64_t) red->u.surface_create.height * abs(red->u.surface_create.stride);
1249
if (size > MAX_DATA_CHUNK || red->u.surface_create.stride == G_MININT32) {
1252
red->u.surface_create.data =
1253
(uint8_t*)get_virt(slots, qxl->u.surface_create.data, size, group_id, &error);
1262
void red_put_surface_cmd(RedSurfaceCmd *red)
1267
static int red_get_cursor(RedMemSlotInfo *slots, int group_id,
1268
SpiceCursor *red, QXLPHYSICAL addr)
1271
RedDataChunk chunks;
1277
qxl = (QXLCursor *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
1282
red->header.unique = qxl->header.unique;
1283
red->header.type = qxl->header.type;
1284
red->header.width = qxl->header.width;
1285
red->header.height = qxl->header.height;
1286
red->header.hot_spot_x = qxl->header.hot_spot_x;
1287
red->header.hot_spot_y = qxl->header.hot_spot_y;
1290
red->data_size = qxl->data_size;
1291
size = red_get_data_chunks_ptr(slots, group_id,
1292
get_memslot_id(slots, addr),
1293
&chunks, &qxl->chunk);
1294
data = red_linearize_chunk(&chunks, size, &free_data);
1295
red_put_data_chunks(&chunks);
1299
red->data = spice_malloc(size);
1300
memcpy(red->data, data, size);
1305
static void red_put_cursor(SpiceCursor *red)
1310
int red_get_cursor_cmd(RedMemSlotInfo *slots, int group_id,
1311
RedCursorCmd *red, QXLPHYSICAL addr)
1316
qxl = (QXLCursorCmd *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
1320
red->release_info = &qxl->release_info;
1322
red->type = qxl->type;
1323
switch (red->type) {
1324
case QXL_CURSOR_SET:
1325
red_get_point16_ptr(&red->u.set.position, &qxl->u.set.position);
1326
red->u.set.visible = qxl->u.set.visible;
1327
error = red_get_cursor(slots, group_id, &red->u.set.shape, qxl->u.set.shape);
1329
case QXL_CURSOR_MOVE:
1330
red_get_point16_ptr(&red->u.position, &qxl->u.position);
1332
case QXL_CURSOR_TRAIL:
1333
red->u.trail.length = qxl->u.trail.length;
1334
red->u.trail.frequency = qxl->u.trail.frequency;
1340
void red_put_cursor_cmd(RedCursorCmd *red)
1342
switch (red->type) {
1343
case QXL_CURSOR_SET:
1344
red_put_cursor(&red->u.set.shape);