diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2010-06-30 22:19:12 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2010-07-02 16:47:51 +0200 |
commit | 3764a3647224a5e9dde021828d3b17fe5fc9fdeb (patch) | |
tree | 7ed113c9743447bcd43d03bc2df388f4864ef996 | |
parent | 7e0099e18e98452d909d76997258ed0f44cf9a19 (diff) |
Properly parse and marshall SpiceString
-rw-r--r-- | common/canvas_base.c | 23 | ||||
-rw-r--r-- | python_modules/demarshal.py | 44 | ||||
-rw-r--r-- | python_modules/marshal.py | 20 | ||||
-rw-r--r-- | python_modules/ptypes.py | 8 | ||||
-rw-r--r-- | server/red_parse_qxl.c | 87 | ||||
-rw-r--r-- | server/red_worker.c | 66 | ||||
-rw-r--r-- | spice.proto | 10 | ||||
-rw-r--r-- | spice1.proto | 8 |
8 files changed, 159 insertions, 107 deletions
diff --git a/common/canvas_base.c b/common/canvas_base.c index 319c4fd..53d13f2 100644 --- a/common/canvas_base.c +++ b/common/canvas_base.c @@ -1591,12 +1591,6 @@ static pixman_image_t *canvas_get_mask(CanvasBase *canvas, SpiceQMask *mask, int return surface; } -static inline SpiceRasterGlyph *canvas_next_raster_glyph(const SpiceRasterGlyph *glyph, int bpp) -{ - return (SpiceRasterGlyph *)((uint8_t *)(glyph + 1) + - (SPICE_ALIGN(glyph->width * bpp, 8) * glyph->height >> 3)); -} - static inline void canvas_raster_glyph_box(const SpiceRasterGlyph *glyph, SpiceRect *r) { ASSERT(r); @@ -1742,8 +1736,7 @@ static void canvas_put_glyph_bits(SpiceRasterGlyph *glyph, int bpp, uint8_t *des static pixman_image_t *canvas_get_str_mask(CanvasBase *canvas, SpiceString *str, int bpp, SpicePoint *pos) { - SpiceRasterGlyph *glyph = (SpiceRasterGlyph *)str->data; - SpiceRasterGlyph *next_glyph; + SpiceRasterGlyph *glyph; SpiceRect bounds; pixman_image_t *str_mask; uint8_t *dest; @@ -1752,15 +1745,13 @@ static pixman_image_t *canvas_get_str_mask(CanvasBase *canvas, SpiceString *str, ASSERT(str->length > 0); - next_glyph = canvas_next_raster_glyph(glyph, bpp); + glyph = str->glyphs[0]; canvas_raster_glyph_box(glyph, &bounds); for (i = 1; i < str->length; i++) { SpiceRect glyph_box; - glyph = next_glyph; - next_glyph = canvas_next_raster_glyph(glyph, bpp); - canvas_raster_glyph_box(glyph, &glyph_box); + canvas_raster_glyph_box(str->glyphs[i], &glyph_box); rect_union(&bounds, &glyph_box); } @@ -1772,15 +1763,14 @@ static pixman_image_t *canvas_get_str_mask(CanvasBase *canvas, SpiceString *str, } dest = (uint8_t *)pixman_image_get_data(str_mask); dest_stride = pixman_image_get_stride(str_mask); - glyph = (SpiceRasterGlyph *)str->data; for (i = 0; i < str->length; i++) { + glyph = str->glyphs[i]; #if defined(GL_CANVAS) canvas_put_glyph_bits(glyph, bpp, dest + (bounds.bottom - bounds.top - 1) * dest_stride, -dest_stride, &bounds); #else canvas_put_glyph_bits(glyph, bpp, dest, dest_stride, &bounds); #endif - glyph = canvas_next_raster_glyph(glyph, bpp); } pos->x = bounds.left; @@ -1788,11 +1778,6 @@ static pixman_image_t *canvas_get_str_mask(CanvasBase *canvas, SpiceString *str, return str_mask; } -static inline SpiceVectorGlyph *canvas_next_vector_glyph(const SpiceVectorGlyph *glyph) -{ - return (SpiceVectorGlyph *)((uint8_t *)(glyph + 1) + glyph->data_size); -} - static pixman_image_t *canvas_scale_surface(pixman_image_t *src, const SpiceRect *src_area, int width, int height, int scale_mode) { diff --git a/python_modules/demarshal.py b/python_modules/demarshal.py index 023c3f6..4d3e79b 100644 --- a/python_modules/demarshal.py +++ b/python_modules/demarshal.py @@ -125,7 +125,7 @@ def write_validate_switch_member(writer, container, switch_member, scope, parent item.subprefix = item.prefix + "_" + m.name item.non_null = c.member.has_attr("nonnull") sub_want_extra_size = want_extra_size - if sub_want_extra_size and not m.contains_extra_size(): + if sub_want_extra_size and not m.contains_extra_size() and not m.is_extra_size(): writer.assign(item.extra_size(), 0) sub_want_extra_size = False @@ -309,10 +309,13 @@ def write_validate_array_item(writer, container, item, scope, parent_scope, star if element_type.is_fixed_sizeof() and want_mem_size and not is_byte_size: # TODO: Overflow check the multiplication - writer.assign(mem_size, "%s * %s" % (element_type.sizeof(), nelements)) + if array.ptr_array: + writer.assign(mem_size, "sizeof(void *) + SPICE_ALIGN(%s * %s, 4)" % (element_type.sizeof(), nelements)) + else: + writer.assign(mem_size, "%s * %s" % (element_type.sizeof(), nelements)) want_mem_size = False - if not element_type.contains_extra_size() and want_extra_size: + if not element_type.contains_extra_size() and not array.is_extra_size() and want_extra_size: writer.assign(extra_size, 0) want_extra_size = False @@ -329,14 +332,24 @@ def write_validate_array_item(writer, container, item, scope, parent_scope, star element_nw_size = element_item.nw_size() element_mem_size = element_item.mem_size() + element_extra_size = element_item.extra_size() scope.variable_def("uint32_t", element_nw_size) scope.variable_def("uint32_t", element_mem_size) + want_is_extra_size = False + want_element_mem_size = want_mem_size + if want_extra_size: + if array.is_extra_size(): + want_is_extra_size = True + want_extra_size = False + want_element_mem_size = True + else: + scope.variable_def("uint32_t", element_extra_size) if want_nw_size: writer.assign(nw_size, 0) if want_mem_size: writer.assign(mem_size, 0) - if want_extra_size: + if want_extra_size or want_is_extra_size: writer.assign(extra_size, 0) want_element_nw_size = want_nw_size @@ -352,13 +365,19 @@ def write_validate_array_item(writer, container, item, scope, parent_scope, star with writer.index(no_block = is_byte_size) as index: with writer.while_loop("%s < %s" % (start2, start2_end) ) if is_byte_size else writer.for_loop(index, nelements) as scope: write_validate_item(writer, container, element_item, scope, parent_scope, start2, - want_element_nw_size, want_mem_size, want_extra_size) + want_element_nw_size, want_element_mem_size, want_extra_size) if want_nw_size: writer.increment(nw_size, element_nw_size) if want_mem_size: - writer.increment(mem_size, element_mem_size) - if want_extra_size: + if not array.is_extra_size(): + writer.increment(mem_size, element_mem_size) + if want_is_extra_size: + if array.ptr_array: + writer.increment(extra_size, "sizeof(void *) + SPICE_ALIGN(%s, 4)" % element_mem_size) + else: + writer.increment(extra_size, "%s + %s" % (element_mem_size, element_extra_size)) + elif want_extra_size: writer.increment(extra_size, element_extra_size) writer.increment(start2, start_increment) @@ -722,8 +741,16 @@ def write_array_parser(writer, nelements, array, dest, scope): scope.variable_def("uint32_t", real_nelements) writer.assign("array_end", "end + %s" % nelements) writer.assign(real_nelements, 0) + if array.ptr_array: + scope.variable_def("void **", "ptr_array") + scope.variable_def("int", "ptr_array_index") + writer.assign("ptr_array_index", 0) + writer.assign("ptr_array", "(void **)end") + writer.increment("end", "sizeof(void *) * %s" % nelements) with writer.index(no_block = is_byte_size) as index: with writer.while_loop("end < array_end") if is_byte_size else writer.for_loop(index, nelements) as array_scope: + if array.ptr_array: + writer.statement("ptr_array[ptr_array_index++] = end") if is_byte_size: writer.increment(real_nelements, 1) if element_type.is_primitive(): @@ -733,6 +760,9 @@ def write_array_parser(writer, nelements, array, dest, scope): dest2 = dest.child_at_end(writer, element_type) dest2.reuse_scope = array_scope write_container_parser(writer, element_type, dest2) + if array.ptr_array: + writer.comment("Align ptr_array element to 4 bytes").newline() + writer.assign("end", "(uint8_t *)SPICE_ALIGN((size_t)end, 4)") if is_byte_size: writer.assign(dest.get_ref(array.size[2]), real_nelements) diff --git a/python_modules/marshal.py b/python_modules/marshal.py index da9b0d8..95413fc 100644 --- a/python_modules/marshal.py +++ b/python_modules/marshal.py @@ -50,6 +50,7 @@ class RootMarshallingSource(MarshallingSource): self.c_type = c_type self.sizeof = sizeof self.pointer = pointer # None == at "end" + self.update_end = False def get_self_ref(self): return self.base_var @@ -70,6 +71,8 @@ class RootMarshallingSource(MarshallingSource): if self.pointer: writer.assign(self.base_var, "(%s *)%s" % (self.c_type, self.pointer)) + if self.update_end: + writer.assign("end", "((uint8_t *)%s) + %s" % (self.base_var, self.sizeof)) else: writer.assign(self.base_var, "(%s *)end" % self.c_type) writer.increment("end", "%s" % self.sizeof) @@ -182,8 +185,18 @@ def write_array_marshaller(writer, at_end, member, array, container_src, scope): element = "%s__element" % member.name + if not scope.variable_defined(element): + if array.ptr_array: + stars = " **" + else: + stars = " *" + scope.variable_def(element_type.c_type() + stars, element) + element_array = element + if array.ptr_array: + element = "*" + element + if not at_end: - writer.assign(element, container_src.get_ref(member.name)) + writer.assign(element_array, container_src.get_ref(member.name)) if is_byte_size: size_start_var = "%s__size_start" % member.name @@ -192,7 +205,6 @@ def write_array_marshaller(writer, at_end, member, array, container_src, scope): with writer.index() as index: with writer.for_loop(index, nelements) as array_scope: - array_scope.variable_def(element_type.c_type() + " *", element) if at_end: writer.assign(element, "(%s *)end" % element_type.c_type()) writer.increment("end", element_type.sizeof()) @@ -201,13 +213,15 @@ def write_array_marshaller(writer, at_end, member, array, container_src, scope): writer.statement("spice_marshaller_add_%s(m, *%s)" % (element_type.primitive_type(), element)) elif element_type.is_struct(): src2 = RootMarshallingSource(container_src, element_type.c_type(), element_type.sizeof(), element) + if array.is_extra_size(): + src2.update_end = True src2.reuse_scope = array_scope write_container_marshaller(writer, element_type, src2) else: writer.todo("array element unhandled type").newline() if not at_end: - writer.statement("%s++" % element) + writer.statement("%s++" % element_array) if is_byte_size: size_var = member.container.lookup_member(array.size[1]) diff --git a/python_modules/ptypes.py b/python_modules/ptypes.py index b7bcac9..055034e 100644 --- a/python_modules/ptypes.py +++ b/python_modules/ptypes.py @@ -353,6 +353,7 @@ class ArrayType(Type): self.element_type = element_type self.size = size + self.ptr_array = False def __str__(self): if self.size == None: @@ -414,6 +415,9 @@ class ArrayType(Type): return [] raise Exception, "Pointer names in arrays not supported" + def is_extra_size(self): + return self.ptr_array + def contains_extra_size(self): return self.element_type.contains_extra_size() @@ -512,6 +516,8 @@ class Member(Containee): self.member_type.register() if self.has_attr("ptr32") and self.member_type.is_pointer(): self.member_type.set_ptr_size(4) + if self.has_attr("ptr_array") and self.member_type.is_array(): + self.member_type.ptr_array = True return self def is_primitive(self): @@ -523,7 +529,7 @@ class Member(Containee): return self.member_type.is_fixed_sizeof() def is_extra_size(self): - return self.has_end_attr() + return self.has_end_attr() or self.member_type.is_extra_size() def is_fixed_nw_size(self): if self.has_attr("virtual"): diff --git a/server/red_parse_qxl.c b/server/red_parse_qxl.c index 3530de1..d38cad7 100644 --- a/server/red_parse_qxl.c +++ b/server/red_parse_qxl.c @@ -375,10 +375,85 @@ static void red_put_stroke_ptr(SpiceStroke *red) free(red->path); } +static SpiceString *red_get_string(RedMemSlotInfo *slots, int group_id, + SPICE_ADDRESS addr) +{ + RedDataChunk chunks; + QXLString *qxl; + QXLRasterGlyph *start, *end; + SpiceString *red; + SpiceRasterGlyph *glyph; + uint8_t *data; + bool free_data; + size_t chunk_size, qxl_size, red_size, glyph_size; + int glyphs, bpp = 0, i; + + qxl = (QXLString *)get_virt(slots, addr, sizeof(*qxl), group_id); + chunk_size = red_get_data_chunks_ptr(slots, group_id, + get_memslot_id(slots, addr), + &chunks, &qxl->chunk); + data = red_linearize_chunk(&chunks, chunk_size, &free_data); + red_put_data_chunks(&chunks); + + qxl_size = qxl->data_size; + ASSERT(chunk_size == qxl_size); + + if (qxl->flags & SPICE_STRING_FLAGS_RASTER_A1) { + bpp = 1; + } else if (qxl->flags & SPICE_STRING_FLAGS_RASTER_A4) { + bpp = 4; + } else if (qxl->flags & SPICE_STRING_FLAGS_RASTER_A8) { + bpp = 8; + } + ASSERT(bpp != 0); + + start = (QXLRasterGlyph*)data; + end = (QXLRasterGlyph*)(data + chunk_size); + red_size = sizeof(SpiceString); + glyphs = 0; + while (start < end) { + ASSERT((QXLRasterGlyph*)(&start->data[0]) <= end); + glyphs++; + glyph_size = start->height * ((start->width * bpp + 7) / 8); + red_size += sizeof(SpiceRasterGlyph *) + SPICE_ALIGN(sizeof(SpiceRasterGlyph) + glyph_size, 4); + start = (QXLRasterGlyph*)(&start->data[glyph_size]); + } + ASSERT(start <= end); + ASSERT(glyphs == qxl->length); + + red = spice_malloc(red_size); + red->length = qxl->length; + red->flags = qxl->flags; + + start = (QXLRasterGlyph*)data; + end = (QXLRasterGlyph*)(data + chunk_size); + glyph = (SpiceRasterGlyph *)&red->glyphs[red->length]; + for (i = 0; i < red->length; i++) { + ASSERT((QXLRasterGlyph*)(&start->data[0]) <= end); + red->glyphs[i] = glyph; + glyph->width = start->width; + glyph->height = start->height; + red_get_point_ptr(&glyph->render_pos, &start->render_pos); + red_get_point_ptr(&glyph->glyph_origin, &start->glyph_origin); + glyph_size = glyph->height * ((glyph->width * bpp + 7) / 8); + ASSERT((QXLRasterGlyph*)(&start->data[glyph_size]) <= end); + memcpy(glyph->data, start->data, glyph_size); + start = (QXLRasterGlyph*)(&start->data[glyph_size]); + glyph = (SpiceRasterGlyph*) + (((uint8_t *)glyph) + + SPICE_ALIGN(sizeof(SpiceRasterGlyph) + glyph_size, 4)); + } + + if (free_data) { + free(data); + } + return red; +} + static void red_get_text_ptr(RedMemSlotInfo *slots, int group_id, - SpiceText *red, QXLText *qxl) + SpiceText *red, QXLText *qxl) { - red->str = qxl->str; + red->str = red_get_string(slots, group_id, qxl->str); red_get_rect_ptr(&red->back_area, &qxl->back_area); red_get_brush_ptr(slots, group_id, &red->fore_brush, &qxl->fore_brush); red_get_brush_ptr(slots, group_id, &red->back_brush, &qxl->back_brush); @@ -386,6 +461,11 @@ static void red_get_text_ptr(RedMemSlotInfo *slots, int group_id, red->back_mode = qxl->back_mode; } +static void red_put_text_ptr(SpiceText *red) +{ + free(red->str); +} + static void red_get_whiteness_ptr(RedMemSlotInfo *slots, int group_id, SpiceWhiteness *red, QXLWhiteness *qxl) { @@ -568,6 +648,9 @@ void red_put_drawable(RedDrawable *red) case QXL_DRAW_STROKE: red_put_stroke_ptr(&red->u.stroke); break; + case QXL_DRAW_TEXT: + red_put_text_ptr(&red->u.text); + break; } } diff --git a/server/red_worker.c b/server/red_worker.c index ee81fcf..ff0a049 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -3948,45 +3948,6 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface free(surface); } -static void localize_str(RedWorker *worker, QXLPHYSICAL *in_str, uint32_t group_id) -{ - QXLString *qxl_str = (QXLString *)get_virt(&worker->mem_slots, *in_str, sizeof(QXLString), group_id); - QXLDataChunk *chunk; - SpiceString *str; - uint8_t *dest; - uint32_t data_size; - int memslot_id = get_memslot_id(&worker->mem_slots, *in_str); - - ASSERT(in_str); - str = spice_malloc_n_m(1, qxl_str->data_size, sizeof(uint32_t)); - *in_str = (QXLPHYSICAL)str; - str->length = qxl_str->length; - str->flags = qxl_str->flags; - dest = str->data; - chunk = &qxl_str->chunk; - for (;;) { - QXLPHYSICAL next_chunk; - - data_size = chunk->data_size; - validate_virt(&worker->mem_slots, (unsigned long)chunk->data, memslot_id, data_size, group_id); - memcpy(dest, chunk->data, data_size); - if (!chunk->next_chunk) { - return; - } - dest += data_size; - next_chunk = chunk->next_chunk; - memslot_id = get_memslot_id(&worker->mem_slots, next_chunk); - chunk = (QXLDataChunk *)get_virt(&worker->mem_slots, next_chunk, sizeof(QXLDataChunk), group_id); - } -} - -static void unlocalize_str(QXLPHYSICAL *str) -{ - ASSERT(str && *str); - free((void *)*str); - *str = 0; -} - static LocalImage *alloc_local_image(RedWorker *worker) { ASSERT(worker->local_images_pos < MAX_BITMAPS); @@ -4450,10 +4411,8 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable) SpiceText text = drawable->red_drawable->u.text; localize_brush(worker, &text.fore_brush, drawable->group_id); localize_brush(worker, &text.back_brush, drawable->group_id); - localize_str(worker, &text.str, drawable->group_id); canvas->ops->draw_text(canvas, &drawable->red_drawable->bbox, &clip, &text); - unlocalize_str(&text.str); unlocalize_brush(&text.back_brush); unlocalize_brush(&text.fore_brush); break; @@ -5159,27 +5118,6 @@ static void add_buf_from_info(RedChannel *channel, SpiceMarshaller *m, AddBufInf } -static void fill_str(DisplayChannel *display_channel, SpiceMarshaller *m, - QXLPHYSICAL in_str, uint32_t group_id) -{ - RedWorker *worker; - RedChannel *channel = &display_channel->base; - int memslot_id; - SpiceString string; - - worker = channel->worker; - - ASSERT(in_str); - memslot_id = get_memslot_id(&worker->mem_slots, in_str); - QXLString *str = (QXLString *)get_virt(&worker->mem_slots, in_str, sizeof(QXLString), group_id); - string.length = str->length; - string.flags = str->flags; - spice_marshall_String(m, &string); - /* TODO: This doesn't properly marshal the glyph data */ - marshaller_add_chunk(worker, m, &str->chunk, - str->data_size, memslot_id, group_id); -} - static inline void fill_rects_clip(SpiceMarshaller *m, SpiceClipRects *data) { int i; @@ -8092,7 +8030,6 @@ static void red_send_qxl_draw_text(RedWorker *worker, SpiceText text; SpiceMarshaller *brush_pat_out; SpiceMarshaller *back_brush_pat_out; - SpiceMarshaller *str_out; fill_base(display_channel, item); @@ -8100,7 +8037,6 @@ static void red_send_qxl_draw_text(RedWorker *worker, text = drawable->u.text; spice_marshall_Text(channel->send_data.marshaller, &text, - &str_out, &brush_pat_out, &back_brush_pat_out); @@ -8110,8 +8046,6 @@ static void red_send_qxl_draw_text(RedWorker *worker, if (back_brush_pat_out) { fill_bits(display_channel, back_brush_pat_out, text.back_brush.u.pattern.pat, item, FALSE); } - - fill_str(display_channel, str_out, text.str, item->group_id); } static void red_lossy_send_qxl_draw_text(RedWorker *worker, diff --git a/spice.proto b/spice.proto index 7528208..8df1238 100644 --- a/spice.proto +++ b/spice.proto @@ -564,12 +564,12 @@ struct String { string_flags flags; /* Special: Only one of a1/a4/a8 set */ switch (flags) { case RASTER_A1: - RasterGlyphA1 glyphs[length] @ctype(SpiceRasterGlyph); + RasterGlyphA1 glyphs[length] @ctype(SpiceRasterGlyph) @ptr_array; case RASTER_A4: - RasterGlyphA4 glyphs[length] @ctype(SpiceRasterGlyph); + RasterGlyphA4 glyphs[length] @ctype(SpiceRasterGlyph) @ptr_array; case RASTER_A8: - RasterGlyphA8 glyphs[length] @ctype(SpiceRasterGlyph); - } u @end @nomarshal; + RasterGlyphA8 glyphs[length] @ctype(SpiceRasterGlyph) @ptr_array; + } u @anon; }; channel DisplayChannel : BaseChannel { @@ -727,7 +727,7 @@ channel DisplayChannel : BaseChannel { message { DisplayBase base; struct Text { - String *str; + String *str @marshall @nonnull; Rect back_area; Brush fore_brush @outvar(fore_brush); Brush back_brush @outvar(back_brush); diff --git a/spice1.proto b/spice1.proto index c9a18d9..982f666 100644 --- a/spice1.proto +++ b/spice1.proto @@ -522,12 +522,12 @@ struct String { string_flags flags; /* Special: Only one of a1/a4/a8 set */ switch (flags) { case RASTER_A1: - RasterGlyphA1 glyphs[length] @ctype(SpiceRasterGlyph); + RasterGlyphA1 glyphs[length] @ctype(SpiceRasterGlyph) @ptr_array; case RASTER_A4: - RasterGlyphA4 glyphs[length] @ctype(SpiceRasterGlyph); + RasterGlyphA4 glyphs[length] @ctype(SpiceRasterGlyph) @ptr_array; case RASTER_A8: - RasterGlyphA8 glyphs[length] @ctype(SpiceRasterGlyph); - } u @end @nomarshal; + RasterGlyphA8 glyphs[length] @ctype(SpiceRasterGlyph) @ptr_array; + } u @anon; }; channel DisplayChannel : BaseChannel { |