[Spice-commits] common/canvas_base.c python_modules/demarshal.py python_modules/marshal.py python_modules/ptypes.py server/red_parse_qxl.c server/red_worker.c spice1.proto spice.proto

Alexander Larsson alexl at kemper.freedesktop.org
Fri Jul 2 07:54:17 PDT 2010


 common/canvas_base.c        |   23 ++---------
 python_modules/demarshal.py |   44 ++++++++++++++++++----
 python_modules/marshal.py   |   20 ++++++++--
 python_modules/ptypes.py    |    8 +++-
 server/red_parse_qxl.c      |   87 ++++++++++++++++++++++++++++++++++++++++++--
 server/red_worker.c         |   66 ---------------------------------
 spice.proto                 |   10 ++---
 spice1.proto                |    8 ++--
 8 files changed, 159 insertions(+), 107 deletions(-)

New commits:
commit 3764a3647224a5e9dde021828d3b17fe5fc9fdeb
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jun 30 22:19:12 2010 +0200

    Properly parse and marshall SpiceString

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 {


More information about the Spice-commits mailing list