[Spice-commits] 11 commits - client/display_channel.cpp common/canvas_base.c common/gdi_canvas.c common/gl_canvas.c common/marshaller.c common/marshaller.h python_modules/demarshal.py python_modules/marshal.py python_modules/ptypes.py python_modules/spice_parser.py server/Makefile.am server/red_parse_qxl.c server/red_parse_qxl.h server/red_worker.c spice.proto spice1.proto

Gerd Hoffmann kraxel at kemper.freedesktop.org
Wed Jun 30 13:37:49 PDT 2010


 client/display_channel.cpp     |    5 
 common/canvas_base.c           |   20 --
 common/gdi_canvas.c            |   60 +-----
 common/gl_canvas.c             |   28 +-
 common/marshaller.c            |   29 ++-
 common/marshaller.h            |   18 +
 python_modules/demarshal.py    |   51 ++++-
 python_modules/marshal.py      |   66 ++++--
 python_modules/ptypes.py       |   44 +++-
 python_modules/spice_parser.py |    2 
 server/Makefile.am             |    2 
 server/red_parse_qxl.c         |  256 +++++++++++++++++++++++++-
 server/red_parse_qxl.h         |    8 
 server/red_worker.c            |  392 +++++++----------------------------------
 spice.proto                    |   36 +--
 spice1.proto                   |   16 -
 16 files changed, 522 insertions(+), 511 deletions(-)

New commits:
commit 00e1caf45d1a5d40f428c3e43d2c79578c841e75
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Jun 30 16:49:50 2010 +0200

    Simplify SpiceLineAttr by removing unsed stuff
    
    Also in new protocol don't send style data if not needed.

diff --git a/common/gdi_canvas.c b/common/gdi_canvas.c
index 0c99097..c5c7462 100644
--- a/common/gdi_canvas.c
+++ b/common/gdi_canvas.c
@@ -1593,34 +1593,6 @@ static void gdi_canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spi
     }
 }
 
-static int get_join_style(uint8_t join_style)
-{
-    switch (join_style) {
-    case SPICE_LINE_JOIN_ROUND:
-        return PS_JOIN_ROUND;
-    case SPICE_LINE_JOIN_BEVEL:
-        return PS_JOIN_BEVEL;
-    case SPICE_LINE_JOIN_MITER:
-        return PS_JOIN_MITER;
-    default:
-        CANVAS_ERROR("bad join style %d", join_style);
-    }
-}
-
-static int get_cap(int end_style)
-{
-    switch (end_style) {
-    case SPICE_LINE_CAP_ROUND:
-        return PS_ENDCAP_ROUND;
-    case SPICE_LINE_CAP_SQUARE:
-        return PS_ENDCAP_SQUARE;
-    case SPICE_LINE_CAP_BUTT:
-        return PS_ENDCAP_FLAT;
-    default:
-        CANVAS_ERROR("bad end style %d", end_style);
-    }
-}
-
 static uint32_t *gdi_get_userstyle(GdiCanvas *canvas, uint8_t nseg, SPICE_ADDRESS addr, int start_is_gap)
 {
     SPICE_FIXED28_4* style = (SPICE_FIXED28_4*)SPICE_GET_ADDRESS(addr);
@@ -1656,8 +1628,6 @@ static void gdi_canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, S
     HPEN hpen;
     HPEN prev_hpen;
     LOGBRUSH logbrush;
-    int ps_join = 0;
-    int line_cap = 0;
     uint32_t *user_style = NULL;
     pixman_image_t *surface = NULL;
 
@@ -1775,23 +1745,16 @@ static void gdi_canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, S
         pixman_image_unref(surface);
     }
 
-#if 0
-    ps_join = get_join_style(stroke->attr.join_style);
-    line_cap = get_cap(stroke->attr.end_style);
-
-    SetMiterLimit(canvas->dc, (FLOAT)fix_to_double(stroke->attr.miter_limit), &old_miter);
-#endif
-
     if (stroke->attr.flags & SPICE_LINE_FLAGS_STYLED) {
         user_style = gdi_get_userstyle(canvas, stroke->attr.style_nseg,
                                        stroke->attr.style,
                                        !!(stroke->attr.flags & SPICE_LINE_FLAGS_START_WITH_GAP));
-        hpen = ExtCreatePen(PS_GEOMETRIC | ps_join | line_cap | PS_USERSTYLE,
-                            (uint32_t)fix_to_double(stroke->attr.width),
+        hpen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE,
+                            1.0,
                             &logbrush, stroke->attr.style_nseg, (DWORD *)user_style);
     } else {
-        hpen = ExtCreatePen(PS_GEOMETRIC | ps_join | line_cap,
-                            (uint32_t)fix_to_double(stroke->attr.width),
+        hpen = ExtCreatePen(PS_GEOMETRIC,
+                            1.0,
                             &logbrush, 0, NULL);
     }
     prev_hpen = (HPEN)SelectObject(canvas->dc, hpen);
diff --git a/common/gl_canvas.c b/common/gl_canvas.c
index 5a03d15..10745b4 100644
--- a/common/gl_canvas.c
+++ b/common/gl_canvas.c
@@ -617,7 +617,7 @@ static void gl_canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, Sp
     if (stroke->attr.flags & SPICE_LINE_FLAGS_STYLED) {
         WARN("SPICE_LINE_FLAGS_STYLED");
     }
-    glc_set_line_width(canvas->glc, fix_to_double(stroke->attr.width));
+    glc_set_line_width(canvas->glc, 1.0);
 
     path = get_path(canvas, stroke->path);
     glc_stroke_path(canvas->glc, path);
diff --git a/python_modules/demarshal.py b/python_modules/demarshal.py
index 48b4e73..b819513 100644
--- a/python_modules/demarshal.py
+++ b/python_modules/demarshal.py
@@ -62,7 +62,8 @@ def write_read_primitive(writer, start, container, name, scope):
     writer.error_check("pos + %s > message_end" % m.member_type.get_fixed_nw_size())
 
     var = "%s__value" % (name)
-    scope.variable_def(m.member_type.c_type(), var)
+    if not scope.variable_defined(var):
+        scope.variable_def(m.member_type.c_type(), var)
     writer.assign(var, "read_%s(pos)" % (m.member_type.primitive_type()))
     return var
 
@@ -639,7 +640,9 @@ def write_switch_parser(writer, container, switch, dest, scope):
             elif t.is_pointer():
                 write_parse_pointer(writer, t, False, m.has_attr("c_ptr"), dest2, m.name, block)
             elif t.is_primitive():
-                if not m.has_attr("zero"):
+                if m.has_attr("zero"):
+                    writer.statement("consume_%s(&in)" % (t.primitive_type()))
+                else:
                     writer.assign(dest2.get_ref(m.name), "consume_%s(&in)" % (t.primitive_type()))
                 #TODO validate e.g. flags and enums
             elif t.is_array():
@@ -768,8 +771,8 @@ def write_member_parser(writer, container, member, dest, scope):
             write_parse_pointer(writer, t, member.has_end_attr(), member.has_attr("c_ptr"), dest, member.name, scope)
     elif t.is_primitive():
         if member.has_attr("zero"):
-            pass
-        if member.has_end_attr():
+            writer.statement("consume_%s(&in)" % t.primitive_type())
+        elif member.has_end_attr():
             writer.statement("*(%s *)end = consume_%s(&in)" % (t.c_type(), t.primitive_type()))
             writer.increment("end", t.sizeof())
         else:
diff --git a/python_modules/ptypes.py b/python_modules/ptypes.py
index bef5432..b7bcac9 100644
--- a/python_modules/ptypes.py
+++ b/python_modules/ptypes.py
@@ -610,6 +610,12 @@ class Switch(Containee):
     def is_switch(self):
         return True
 
+    def lookup_case_member(self, name):
+        for c in self.cases:
+            if c.member.name == name:
+                return c.member
+        return None
+
     def has_switch_member(self, member):
         for c in self.cases:
             if c.member == member:
@@ -767,7 +773,14 @@ class ContainerType(Type):
             return str(fixed)
 
     def lookup_member(self, name):
-        return self.members_by_name[name]
+        if self.members_by_name.has_key(name):
+            return self.members_by_name[name]
+        for m in self.members:
+            if m.is_switch():
+                member = m.lookup_case_member(name)
+                if member:
+                    return member
+        raise Exception, "No member called %s found" % name
 
 class StructType(ContainerType):
     def __init__(self, name, members, attribute_list):
diff --git a/server/red_parse_qxl.c b/server/red_parse_qxl.c
index 6fb439e..7e87776 100644
--- a/server/red_parse_qxl.c
+++ b/server/red_parse_qxl.c
@@ -358,12 +358,13 @@ static void red_get_stroke_ptr(RedMemSlotInfo *slots, int group_id,
 {
    red->path = red_get_path(slots, group_id, qxl->path);
    red->attr.flags       = qxl->attr.flags;
-   red->attr.join_style  = qxl->attr.join_style;
-   red->attr.end_style   = qxl->attr.end_style;
-   red->attr.style_nseg  = qxl->attr.style_nseg;
-   red->attr.width       = qxl->attr.width;
-   red->attr.miter_limit = qxl->attr.miter_limit;
-   red->attr.style       = qxl->attr.style;
+   if (red->attr.flags & SPICE_LINE_FLAGS_STYLED) {
+       red->attr.style_nseg  = qxl->attr.style_nseg;
+       red->attr.style       = qxl->attr.style;
+   } else {
+       red->attr.style_nseg  = 0;
+       red->attr.style       = 0;
+   }
    red_get_brush_ptr(slots, group_id, &red->brush, &qxl->brush);
    red->fore_mode        = qxl->fore_mode;
    red->back_mode        = qxl->back_mode;
diff --git a/server/red_worker.c b/server/red_worker.c
index 712ede8..fa1ca44 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -2324,9 +2324,8 @@ static int is_equal_brush(SpiceBrush *b1, SpiceBrush *b2)
 // partial imp
 static int is_equal_line_attr(SpiceLineAttr *a1, SpiceLineAttr *a2)
 {
-    return a1->flags == a2->flags && a1->join_style == a2->join_style &&
-           a1->end_style == a2->end_style && a1->style_nseg == a2->style_nseg &&
-           a1->width == a2->width && a1->miter_limit == a2->miter_limit &&
+    return a1->flags == a2->flags &&
+           a1->style_nseg == a2->style_nseg &&
            a1->style_nseg == 0;
 }
 
diff --git a/spice.proto b/spice.proto
index 67acb67..7528208 100644
--- a/spice.proto
+++ b/spice.proto
@@ -131,7 +131,7 @@ channel BaseChannel {
 	uint32 what; /* error_code/warn_code/info_code */
 	uint32 message_len;
 	uint8 message[message_len] @end @nomarshal;
-	uint8 zero @end @ctype(uint8_t) @zero  @nomarshal;
+	uint8 zero @end @ctype(uint8_t) @nomarshal;
     } notify;
 
  client:
@@ -349,18 +349,6 @@ flags8 line_flags {
     START_WITH_GAP = 2,
 };
 
-enum8 line_cap {
-    ROUND,
-    SQUARE,
-    BUTT,
-};
-
-enum8 line_join {
-    ROUND,
-    BEVEL,
-    MITER,
-};
-
 flags8 string_flags {
     RASTER_A1,
     RASTER_A4,
@@ -537,12 +525,14 @@ struct QMask {
 
 struct LineAttr {
     line_flags flags;
-    line_join join_style;
-    line_cap end_style;
-    uint8 style_nseg;
-    fixed28_4 width;
-    fixed28_4 miter_limit;
-    fixed28_4 *style[style_nseg];
+    switch (flags) {
+    case STYLED:
+        uint8 style_nseg;
+   } u1 @anon;
+   switch (flags) {
+   case STYLED:
+        fixed28_4 *style[style_nseg];
+   } u2 @anon;
 };
 
 struct RasterGlyphA1 {
diff --git a/spice1.proto b/spice1.proto
index 0150de2..c9a18d9 100644
--- a/spice1.proto
+++ b/spice1.proto
@@ -131,7 +131,7 @@ channel BaseChannel {
 	uint32 what; /* error_code/warn_code/info_code */
 	uint32 message_len;
 	uint8 message[message_len] @end @nomarshal;
-	uint8 zero @end @ctype(uint8_t) @zero  @nomarshal;
+	uint8 zero @end @ctype(uint8_t) @nomarshal;
     } notify;
 
  client:
@@ -485,11 +485,11 @@ struct QMask {
 
 struct LineAttr {
     line_flags flags;
-    line_join join_style;
-    line_cap end_style;
+    line_join join_style @zero;
+    line_cap end_style @zero;
     uint8 style_nseg;
-    fixed28_4 width;
-    fixed28_4 miter_limit;
+    fixed28_4 width @zero;
+    fixed28_4 miter_limit @zero;
     fixed28_4 *style[style_nseg];
 };
 
commit 62d0c076eb2eb0f9954c3870f31b4dd685e5f95c
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Jun 30 14:05:14 2010 +0200

    Automatically marshall SpiceClipRects

diff --git a/server/red_worker.c b/server/red_worker.c
index 6fd92a7..712ede8 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -451,8 +451,7 @@ typedef struct StreamClipItem {
     int refs;
     StreamAgent *stream_agent;
     int clip_type;
-    SpiceRect *rects;
-    uint32_t n_rects;
+    SpiceClipRects *rects;
 } StreamClipItem;
 
 typedef struct RedCompressBuf RedCompressBuf;
@@ -850,8 +849,7 @@ typedef struct UpgradeItem {
     PipeItem base;
     int refs;
     Drawable *drawable;
-    SpiceRect *rects;
-    uint32_t n_rects;
+    SpiceClipRects *rects;
 } UpgradeItem;
 
 typedef struct DrawContext {
@@ -2413,18 +2411,23 @@ static void push_stream_clip_by_drawable(DisplayChannel* channel, StreamAgent *a
                                          Drawable *drawable)
 {
     StreamClipItem *item = __new_stream_clip(channel, agent);
+    int n_rects;
+
     if (!item) {
         PANIC("alloc failed");
     }
 
     if (drawable->red_drawable->clip.type == SPICE_CLIP_TYPE_NONE) {
-        item->n_rects = 0;
         item->rects = NULL;
         item->clip_type = SPICE_CLIP_TYPE_NONE;
+        item->rects = NULL;
     } else {
         item->clip_type = SPICE_CLIP_TYPE_RECTS;
-        item->rects = region_dup_rects(&drawable->tree_item.base.rgn,
-                                       &item->n_rects);
+        n_rects = pixman_region32_n_rects(&drawable->tree_item.base.rgn);
+
+        item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
+        item->rects->num_rects = n_rects;
+        region_ret_rects(&drawable->tree_item.base.rgn, item->rects->rects, n_rects);
     }
     red_pipe_add((RedChannel*)channel, (PipeItem *)item);
 }
@@ -2432,12 +2435,18 @@ static void push_stream_clip_by_drawable(DisplayChannel* channel, StreamAgent *a
 static void push_stream_clip(DisplayChannel* channel, StreamAgent *agent)
 {
     StreamClipItem *item = __new_stream_clip(channel, agent);
+    int n_rects;
+
     if (!item) {
         PANIC("alloc failed");
     }
     item->clip_type = SPICE_CLIP_TYPE_RECTS;
-    item->rects = region_dup_rects(&agent->vis_region,
-                                   &item->n_rects);
+
+    n_rects = pixman_region32_n_rects(&agent->vis_region);
+
+    item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
+    item->rects->num_rects = n_rects;
+    region_ret_rects(&agent->vis_region, item->rects->rects, n_rects);
     red_pipe_add((RedChannel*)channel, (PipeItem *)item);
 }
 
@@ -2507,14 +2516,17 @@ static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *strea
 
     if ((channel = worker->display_channel) && !pipe_item_is_linked(&stream->current->pipe_item)) {
         UpgradeItem *upgrade_item;
+        int n_rects;
 
         upgrade_item = spice_new(UpgradeItem, 1);
         upgrade_item->refs = 1;
         red_pipe_item_init(&upgrade_item->base, PIPE_ITEM_TYPE_UPGRADE);
         upgrade_item->drawable = stream->current;
         upgrade_item->drawable->refs++;
-        upgrade_item->rects = region_dup_rects(&upgrade_item->drawable->tree_item.base.rgn,
-                                               &upgrade_item->n_rects);
+        n_rects = pixman_region32_n_rects(&upgrade_item->drawable->tree_item.base.rgn);
+        upgrade_item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
+        upgrade_item->rects->num_rects = n_rects;
+        region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn, upgrade_item->rects->rects, n_rects);
         red_pipe_add((RedChannel *)channel, &upgrade_item->base);
     }
     red_detach_stream(worker, stream);
@@ -2526,12 +2538,15 @@ static inline void red_stop_stream_gracefully(RedWorker *worker, Stream *stream)
     ASSERT(stream->current);
     if (worker->display_channel && !pipe_item_is_linked(&stream->current->pipe_item)) {
         UpgradeItem *item = spice_new(UpgradeItem, 1);
+        int n_rects;
         item->refs = 1;
         red_pipe_item_init(&item->base, PIPE_ITEM_TYPE_UPGRADE);
         item->drawable = stream->current;
         item->drawable->refs++;
-        item->rects = region_dup_rects(&item->drawable->tree_item.base.rgn,
-                                       &item->n_rects);
+        n_rects = pixman_region32_n_rects(&item->drawable->tree_item.base.rgn);
+        item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
+        item->rects->num_rects = n_rects;
+        region_ret_rects(&item->drawable->tree_item.base.rgn, item->rects->rects, n_rects);
         red_pipe_add((RedChannel *)worker->display_channel, &item->base);
     }
     red_stop_stream(worker, stream);
@@ -5175,17 +5190,12 @@ static void fill_base(DisplayChannel *display_channel, Drawable *drawable)
 {
     RedChannel *channel = &display_channel->base;
     SpiceMsgDisplayBase base;
-    SpiceMarshaller *cliprects_data_out;
 
     base.surface_id = drawable->surface_id;
     base.box = drawable->red_drawable->bbox;
     base.clip = drawable->red_drawable->clip;
 
-    spice_marshall_DisplayBase(channel->send_data.marshaller, &base,
-                              &cliprects_data_out);
-    if (cliprects_data_out) {
-        fill_rects_clip(cliprects_data_out, base.clip.rects);
-    }
+    spice_marshall_DisplayBase(channel->send_data.marshaller, &base);
 }
 
 /* io_palette is relative address of the palette*/
@@ -8866,7 +8876,7 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
     int lz_comp = FALSE;
     spice_image_compression_t comp_mode;
     SpiceMsgDisplayDrawCopy copy;
-    SpiceMarshaller *cliprects_data_out, *src_bitmap_out, *mask_bitmap_out;
+    SpiceMarshaller *src_bitmap_out, *mask_bitmap_out;
     SpiceMarshaller *bitmap_palette_out, *data_out, *lzplt_palette_out;
 
     ASSERT(display_channel && item);
@@ -8912,7 +8922,6 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
     SpiceMarshaller *m = channel->send_data.marshaller;
 
     spice_marshall_msg_display_draw_copy(m, &copy,
-                                         &cliprects_data_out,
                                          &src_bitmap_out, &mask_bitmap_out);
 
     compress_send_data_t comp_send_data = {0};
@@ -8990,8 +8999,7 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
     RedChannel *channel;
     RedDrawable *red_drawable;
     SpiceMsgDisplayDrawCopy copy;
-    SpiceMarshaller *cliprects_data_out, *src_bitmap_out, *mask_bitmap_out;
-    int i;
+    SpiceMarshaller *src_bitmap_out, *mask_bitmap_out;
 
     ASSERT(display_channel && item && item->drawable);
     channel = &display_channel->base;
@@ -9006,19 +9014,14 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
     copy.base.surface_id = 0;
     copy.base.box = red_drawable->bbox;
     copy.base.clip.type = SPICE_CLIP_TYPE_RECTS;
-    copy.base.clip.rects = NULL;
+    copy.base.clip.rects = item->rects;
     copy.data = red_drawable->u.copy;
 
     SpiceMarshaller *m = channel->send_data.marshaller;
 
     spice_marshall_msg_display_draw_copy(m, &copy,
-                                         &cliprects_data_out,
                                          &src_bitmap_out, &mask_bitmap_out);
 
-    spice_marshaller_add_uint32(cliprects_data_out, item->n_rects);
-    for (i = 0; i < item->n_rects; i++) {
-        spice_marshall_Rect(cliprects_data_out, &item->rects[i]);
-    }
     fill_bits(display_channel, src_bitmap_out, copy.data.src_bitmap, item->drawable, FALSE);
 
     display_begin_send_massage(display_channel, &item->base);
@@ -9033,7 +9036,7 @@ static void red_display_send_stream_start(DisplayChannel *display_channel, Strea
     ASSERT(stream);
     channel->send_data.header->type = SPICE_MSG_DISPLAY_STREAM_CREATE;
     SpiceMsgDisplayStreamCreate stream_create;
-    SpiceMarshaller *cliprects_data_out;
+    SpiceClipRects clip_rects;
 
     stream_create.surface_id = 0;
     stream_create.id = agent - display_channel->stream_agents;
@@ -9051,23 +9054,16 @@ static void red_display_send_stream_start(DisplayChannel *display_channel, Strea
         stream_create.clip = red_drawable->clip;
     } else {
         stream_create.clip.type = SPICE_CLIP_TYPE_RECTS;
-        stream_create.clip.rects = NULL;
+        clip_rects.num_rects = 0;
+        stream_create.clip.rects = &clip_rects;
     }
 
-    spice_marshall_msg_display_stream_create(channel->send_data.marshaller, &stream_create,
-                                             &cliprects_data_out);
+    spice_marshall_msg_display_stream_create(channel->send_data.marshaller, &stream_create);
 
 
     if (stream->current) {
-        RedDrawable *red_drawable = stream->current->red_drawable;
-        if (red_drawable->clip.type == SPICE_CLIP_TYPE_RECTS) {
-            fill_rects_clip(cliprects_data_out, stream_create.clip.rects);
-        } else {
-            ASSERT(red_drawable->clip.type == SPICE_CLIP_TYPE_NONE);
-        }
         display_begin_send_massage(display_channel, &stream->current->pipe_item);
     } else {
-        spice_marshaller_add_uint32(cliprects_data_out, 0);
         display_begin_send_massage(display_channel, NULL);
     }
 }
@@ -9079,29 +9075,18 @@ static void red_display_send_stream_clip(DisplayChannel *display_channel,
 
     StreamAgent *agent = item->stream_agent;
     Stream *stream = agent->stream;
-    int i;
 
     ASSERT(stream);
 
     channel->send_data.header->type = SPICE_MSG_DISPLAY_STREAM_CLIP;
     SpiceMsgDisplayStreamClip stream_clip;
-    SpiceMarshaller *cliprects_data_out;
 
     stream_clip.id = agent - display_channel->stream_agents;
     stream_clip.clip.type = item->clip_type;
-#if 0 /* FIXME */
-    stream_clip.clip.data = 0;
-#endif
+    stream_clip.clip.rects = item->rects;
 
-    spice_marshall_msg_display_stream_clip(channel->send_data.marshaller, &stream_clip,
-                                           &cliprects_data_out);
+    spice_marshall_msg_display_stream_clip(channel->send_data.marshaller, &stream_clip);
 
-    if (stream_clip.clip.type == SPICE_CLIP_TYPE_RECTS) {
-        spice_marshaller_add_uint32(cliprects_data_out, item->n_rects);
-        for (i = 0; i < item->n_rects; i++) {
-            spice_marshall_Rect(cliprects_data_out, &item->rects[i]);
-        }
-    }
     display_begin_send_massage(display_channel, item);
 }
 
diff --git a/spice.proto b/spice.proto
index 0773f0a..67acb67 100644
--- a/spice.proto
+++ b/spice.proto
@@ -412,7 +412,7 @@ struct Clip {
     clip_type type;
     switch (type) {
     case RECTS:
-        ClipRects *rects @outvar(cliprects) @c_ptr;
+        ClipRects *rects @outvar(cliprects) @c_ptr @marshall @nonnull;
     } u @anon;
 };
 
commit 99f581ae561599d6c2684b96775da4f56484c68a
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Jun 30 14:05:04 2010 +0200

    Automatically marshall SpicePath

diff --git a/server/red_worker.c b/server/red_worker.c
index 6d821c9..6fd92a7 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -7998,7 +7998,6 @@ static void red_send_qxl_draw_stroke(RedWorker *worker,
     RedChannel *channel = &display_channel->base;
     SpiceStroke stroke;
     SpiceMarshaller *brush_pat_out;
-    SpiceMarshaller *path_out;
     SpiceMarshaller *style_out;
 
     fill_base(display_channel, item);
@@ -8007,11 +8006,9 @@ static void red_send_qxl_draw_stroke(RedWorker *worker,
     stroke = drawable->u.stroke;
     spice_marshall_Stroke(channel->send_data.marshaller,
                           &stroke,
-                          &path_out,
                           &style_out,
                           &brush_pat_out);
 
-    spice_marshall_Path(path_out, stroke.path);
     fill_attr(display_channel, style_out, &stroke.attr, item->group_id);
     if (brush_pat_out) {
         fill_bits(display_channel, brush_pat_out, stroke.brush.u.pattern.pat, item, FALSE);
diff --git a/spice.proto b/spice.proto
index dedf950..0773f0a 100644
--- a/spice.proto
+++ b/spice.proto
@@ -726,7 +726,7 @@ channel DisplayChannel : BaseChannel {
     message {
 	DisplayBase base;
 	struct Stroke {
-	    Path *path;
+	    Path *path @c_ptr @marshall @nonnull;
 	    LineAttr attr;
 	    Brush brush;
 	    uint16 fore_mode;
commit 1be4d5d26cd6c27bdcd3e8e905da79437626148b
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Jun 30 13:24:59 2010 +0200

    Support @marshall to automatically marshall pointers

diff --git a/python_modules/marshal.py b/python_modules/marshal.py
index 250147f..da9b0d8 100644
--- a/python_modules/marshal.py
+++ b/python_modules/marshal.py
@@ -104,10 +104,10 @@ def write_marshal_ptr_function(writer, target_type):
 
     writer.set_is_generated("marshaller", marshal_function)
 
-    names = target_type.get_pointer_names()
+    names = target_type.get_pointer_names(False)
     names_args = ""
     if len(names) > 0:
-        n = map(lambda name: ", SpiceMarshaller **%s" % name, names)
+        n = map(lambda name: ", SpiceMarshaller **%s_out" % name, names)
         names_args = "".join(n)
 
     header = writer.header
@@ -120,9 +120,10 @@ def write_marshal_ptr_function(writer, target_type):
         scope = writer.function(marshal_function, "void *", "SpiceMarshaller *m, %s *ptr" % target_type.c_type() + names_args)
         header.writeln("void *" + marshal_function + "(SpiceMarshaller *m, %s *msg" % target_type.c_type() + names_args + ");")
     scope.variable_def("SPICE_GNUC_UNUSED uint8_t *", "end")
+    scope.variable_def("SPICE_GNUC_UNUSED SpiceMarshaller *", "m2")
 
     for n in names:
-        writer.assign("*%s" % n, "NULL")
+        writer.assign("*%s_out" % n, "NULL")
 
     writer.newline()
     writer.assign("end", "(uint8_t *)(ptr+1)")
@@ -214,6 +215,20 @@ def write_array_marshaller(writer, at_end, member, array, container_src, scope):
         var = "%s__ref" % array.size[1]
         writer.statement("spice_marshaller_set_%s(m, %s, spice_marshaller_get_size(m) - %s)" % (size_var_type.primitive_type(), var, size_start_var))
 
+def write_pointer_marshaller(writer, member, src):
+    t = member.member_type
+    ptr_func = write_marshal_ptr_function(writer, t.target_type)
+    submarshaller = "spice_marshaller_get_ptr_submarshaller(m, %d)" % (1 if member.get_fixed_nw_size() == 8 else 0)
+    if member.has_attr("marshall"):
+        writer.assign("m2", submarshaller)
+        if member.has_attr("nonnull"):
+            writer.statement("%s(m2, %s)" % (ptr_func, src.get_ref(member.name)))
+        else:
+            with writer.if_block("%s != NULL" % src.get_ref(member.name)) as block:
+                writer.statement("%s(m2, %s)" % (ptr_func, src.get_ref(member.name)))
+    else:
+        writer.assign("*%s_out" % (writer.out_prefix + member.name), submarshaller)
+
 def write_switch_marshaller(writer, container, switch, src, scope):
     var = container.lookup_member(switch.variable)
     var_type = var.member_type
@@ -242,8 +257,7 @@ def write_switch_marshaller(writer, container, switch, src, scope):
             if t.is_struct():
                 write_container_marshaller(writer, t, src2)
             elif t.is_pointer():
-                ptr_func = write_marshal_ptr_function(writer, t.target_type)
-                writer.assign("*%s_out" % (writer.out_prefix + m.name), "spice_marshaller_get_ptr_submarshaller(m, %d)" % (1 if m.get_fixed_nw_size() == 8 else 0))
+                write_pointer_marshaller(writer, m, src2)
             elif t.is_primitive():
                 if m.has_attr("zero"):
                     writer.statement("spice_marshaller_add_%s(m, 0)" % (t.primitive_type()))
@@ -283,13 +297,7 @@ def write_member_marshaller(writer, container, member, src, scope):
     t = member.member_type
 
     if t.is_pointer():
-#        if member.has_attr("nocopy"):
-#            writer.comment("Reuse data from network message").newline()
-#            writer.assign(src.get_ref(member.name), "(size_t)(message_start + consume_uint64(&in))")
-#        else:
-#            write_parse_pointer(writer, t, member.has_end_attr(), src, member.name, scope)
-        ptr_func = write_marshal_ptr_function(writer, t.target_type)
-        writer.assign("*%s_out" % (writer.out_prefix + member.name), "spice_marshaller_get_ptr_submarshaller(m, %d)" % (1 if member.get_fixed_nw_size() == 8 else 0))
+        write_pointer_marshaller(writer, member, src)
     elif t.is_primitive():
         if member.has_attr("zero"):
             writer.statement("spice_marshaller_add_%s(m, 0)" % (t.primitive_type()))
@@ -329,10 +337,10 @@ def write_message_marshaller(writer, message, is_server, private):
         return function_name
     writer.set_is_generated("marshaller", function_name)
 
-    names = message.get_pointer_names()
+    names = message.get_pointer_names(False)
     names_args = ""
     if len(names) > 0:
-        n = map(lambda name: ", SpiceMarshaller **%s" % name, names)
+        n = map(lambda name: ", SpiceMarshaller **%s_out" % name, names)
         names_args = "".join(n)
 
     if not private:
@@ -342,9 +350,10 @@ def write_message_marshaller(writer, message, is_server, private):
                             "static void" if private else "void",
                             "SpiceMarshaller *m, %s *msg" % message.c_type() + names_args)
     scope.variable_def("SPICE_GNUC_UNUSED uint8_t *", "end")
+    scope.variable_def("SPICE_GNUC_UNUSED SpiceMarshaller *", "m2")
 
     for n in names:
-        writer.assign("*%s" % n, "NULL")
+        writer.assign("*%s_out" % n, "NULL")
 
     src = RootMarshallingSource(None, message.c_type(), message.sizeof(), "msg")
     src.reuse_scope = scope
diff --git a/python_modules/ptypes.py b/python_modules/ptypes.py
index f4126a5..bef5432 100644
--- a/python_modules/ptypes.py
+++ b/python_modules/ptypes.py
@@ -94,7 +94,7 @@ class Type:
     def get_num_pointers(self):
         return 0
 
-    def get_pointer_names(self):
+    def get_pointer_names(self, marshalled):
         return []
 
     def sizeof(self):
@@ -205,8 +205,8 @@ class TypeAlias(Type):
     def get_num_pointers(self):
         return self.the_type.get_num_pointers()
 
-    def get_pointer_names(self):
-        return self.the_type.get_pointer_names()
+    def get_pointer_names(self, marshalled):
+        return self.the_type.get_pointer_names(marshalled)
 
     def c_type(self):
         if self.has_attr("ctype"):
@@ -408,7 +408,7 @@ class ArrayType(Type):
             return element_count * self.size
         raise Exception, "Pointers in dynamic arrays not supported"
 
-    def get_pointer_names(self):
+    def get_pointer_names(self, marshalled):
         element_count = self.element_type.get_num_pointers()
         if element_count  == 0:
             return []
@@ -554,11 +554,14 @@ class Member(Containee):
     def get_num_pointers(self):
         return self.member_type.get_num_pointers()
 
-    def get_pointer_names(self):
+    def get_pointer_names(self, marshalled):
         if self.member_type.is_pointer():
-            names = [self.name + "_out"]
+            if self.has_attr("marshall") == marshalled:
+                names = [self.name]
+            else:
+                names = []
         else:
-            names = self.member_type.get_pointer_names()
+            names = self.member_type.get_pointer_names(marshalled)
         if self.has_attr("outvar"):
             prefix = self.attributes["outvar"][0]
             names = map(lambda name: prefix + "_" + name, names)
@@ -592,8 +595,8 @@ class SwitchCase:
     def get_num_pointers(self):
         return self.member.get_num_pointers()
 
-    def get_pointer_names(self):
-        return self.member.get_pointer_names()
+    def get_pointer_names(self, marshalled):
+        return self.member.get_pointer_names(marshalled)
 
 class Switch(Containee):
     def __init__(self, variable, cases, name, attribute_list):
@@ -684,10 +687,10 @@ class Switch(Containee):
             count = max(count, c.get_num_pointers())
         return count
 
-    def get_pointer_names(self):
+    def get_pointer_names(self, marshalled):
         names = []
         for c in self.cases:
-            names = names + c.get_pointer_names()
+            names = names + c.get_pointer_names(marshalled)
         return names
 
 class ContainerType(Type):
@@ -736,10 +739,10 @@ class ContainerType(Type):
             count = count + m.get_num_pointers()
         return count
 
-    def get_pointer_names(self):
+    def get_pointer_names(self, marshalled):
         names = []
         for m in self.members:
-            names = names + m.get_pointer_names()
+            names = names + m.get_pointer_names(marshalled)
         return names
 
     def has_pointer(self):
commit a24a8ff72ae40432f2ffe246f973057e38b042b0
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue Jun 29 21:42:59 2010 +0200

    Store SpicePath segment count rather than size
    
    Internally and in the network protocol (for the new version) we
    now store the actual number of segments rather than the size of the
    full segments array in bytes. This change consists of multiple changes
    to handle this:
    
    * Make the qxl parser calculate num_segments
    * Make the canvas stroke code handle the new SpicePath layout.
    * Fix up is_equal_path in red_worker.c for the new layout
    * replace multiple calls to spice_marshall_PathSegment with a single
      spice_marshall_Path call
    * Make the byte_size() array size handling do the conversion from
      network size to number of elements when marshalling/demarshalling.
    * Update the current spice protocol to send the segment count rather than
      the size
    * Update the old spice protocol to use the new byte_size functionallity
      to calculate the size sent and the number of elements recieved

diff --git a/common/canvas_base.c b/common/canvas_base.c
index ba0fb21..b8a42e6 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -3077,8 +3077,6 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox,
         stroke_fill_spans,
         stroke_fill_rects
     };
-    uint32_t *data_size;
-    uint32_t more;
     SpicePathSeg *seg;
     StrokeLines lines;
     int i;
@@ -3182,18 +3180,15 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox,
         CANVAS_ERROR("invalid brush type");
     }
 
-    data_size = (uint32_t*)SPICE_GET_ADDRESS(stroke->path);
-    more = *data_size;
-    seg = (SpicePathSeg*)(data_size + 1);
+    seg = stroke->path->segments;
 
     stroke_lines_init(&lines);
 
-    do {
+    for (i = 0; i < stroke->path->num_segments; i++) {
         uint32_t flags = seg->flags;
         SpicePointFix* point = seg->points;
         SpicePointFix* end_point = point + seg->count;
         ASSERT(point < end_point);
-        more -= ((unsigned long)end_point - (unsigned long)seg);
         seg = (SpicePathSeg*)end_point;
 
         if (flags & SPICE_PATH_BEGIN) {
@@ -3223,7 +3218,7 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox,
             }
             stroke_lines_draw(&lines, (lineGC *)&gc, dashed);
         }
-    } while (more);
+    }
 
     stroke_lines_draw(&lines, (lineGC *)&gc, dashed);
 
diff --git a/common/gdi_canvas.c b/common/gdi_canvas.c
index 594eacf..0c99097 100644
--- a/common/gdi_canvas.c
+++ b/common/gdi_canvas.c
@@ -308,19 +308,16 @@ uint32_t raster_ops[] = {
     0x00FF0062 // 1 WHITENESS
 };
 
-static void set_path(GdiCanvas *canvas, void *addr)
+static void set_path(GdiCanvas *canvas, SpicePath *s)
 {
-    uint32_t* data_size = (uint32_t*)addr;
-    uint32_t more = *data_size;
-
-    SpicePathSeg* seg = (SpicePathSeg*)(data_size + 1);
+    SpicePathSeg* seg = s->segments;
+    int i;
 
-    do {
+    for (i = 0; i < s->num_segments; i++) {
         uint32_t flags = seg->flags;
         SpicePointFix* point = (SpicePointFix*)seg->data;
         SpicePointFix* end_point = point + seg->count;
         ASSERT(point < end_point);
-        more -= ((unsigned long)end_point - (unsigned long)seg);
         seg = (SpicePathSeg*)end_point;
 
         if (flags & SPICE_PATH_BEGIN) {
@@ -371,7 +368,7 @@ static void set_path(GdiCanvas *canvas, void *addr)
             }
         }
 
-    } while (more);
+    }
 }
 
 static void set_scale_mode(GdiCanvas *canvas, uint8_t scale_mode)
@@ -1799,7 +1796,7 @@ static void gdi_canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, S
     }
     prev_hpen = (HPEN)SelectObject(canvas->dc, hpen);
 
-    set_path(canvas, SPICE_GET_ADDRESS(stroke->path));
+    set_path(canvas, stroke->path);
 
     StrokePath(canvas->dc);
 
diff --git a/common/gl_canvas.c b/common/gl_canvas.c
index 59fb1a7..5a03d15 100644
--- a/common/gl_canvas.c
+++ b/common/gl_canvas.c
@@ -114,15 +114,13 @@ static pixman_image_t *canvas_surf_to_trans_surf(GLCImage *image,
 static GLCPath get_path(GLCanvas *canvas, SpicePath *s)
 {
     GLCPath path = glc_path_create(canvas->glc);
-    uint32_t more = s->size;
+    int i;
     SpicePathSeg* seg = s->segments;
 
-    do {
+    for (i = 0; i < s->num_segments; i++) {
         uint32_t flags = seg->flags;
         SpicePointFix* point = seg->points;
         SpicePointFix* end_point = point + seg->count;
-        ASSERT(point < end_point);
-        more -= ((unsigned long)end_point - (unsigned long)seg);
         seg = (SpicePathSeg*)end_point;
 
         if (flags & SPICE_PATH_BEGIN) {
@@ -148,7 +146,7 @@ static GLCPath get_path(GLCanvas *canvas, SpicePath *s)
                 glc_path_close(path);
             }
         }
-    } while (more);
+    }
 
     return path;
 }
@@ -621,7 +619,7 @@ static void gl_canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, Sp
     }
     glc_set_line_width(canvas->glc, fix_to_double(stroke->attr.width));
 
-    path = get_path(canvas, SPICE_GET_ADDRESS(stroke->path));
+    path = get_path(canvas, stroke->path);
     glc_stroke_path(canvas->glc, path);
     glc_path_destroy(path);
 }
diff --git a/python_modules/demarshal.py b/python_modules/demarshal.py
index faaf862..48b4e73 100644
--- a/python_modules/demarshal.py
+++ b/python_modules/demarshal.py
@@ -604,7 +604,7 @@ def read_array_len(writer, prefix, array, dest, scope, handles_bytes = False):
     elif array.is_bytes_length():
         if not handles_bytes:
             raise NotImplementedError("handling of bytes() not supported here yet")
-        writer.assign(nelements, dest.get_ref(array.size[1]))
+        writer.assign(nelements, array.size[1])
     else:
         raise NotImplementedError("TODO array size type not handled yet")
     return nelements
@@ -714,10 +714,15 @@ def write_array_parser(writer, nelements, array, dest, scope):
         writer.increment("end", nelements)
     else:
         if is_byte_size:
+            real_nelements = nelements[:-len("nbytes")] + "nelements"
             scope.variable_def("uint8_t *", "array_end")
+            scope.variable_def("uint32_t", real_nelements)
             writer.assign("array_end", "end + %s" % nelements)
+            writer.assign(real_nelements, 0)
         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 is_byte_size:
+                    writer.increment(real_nelements, 1)
                 if element_type.is_primitive():
                     writer.statement("*(%s *)end = consume_%s(&in)" % (element_type.c_type(), element_type.primitive_type()))
                     writer.increment("end", element_type.sizeof())
@@ -725,6 +730,8 @@ 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 is_byte_size:
+            writer.assign(dest.get_ref(array.size[2]), real_nelements)
 
 def write_parse_pointer(writer, t, at_end, as_c_ptr, dest, member_name, scope):
         target_type = t.target_type
@@ -766,7 +773,12 @@ def write_member_parser(writer, container, member, dest, scope):
             writer.statement("*(%s *)end = consume_%s(&in)" % (t.c_type(), t.primitive_type()))
             writer.increment("end", t.sizeof())
         else:
-            writer.assign(dest.get_ref(member.name), "consume_%s(&in)" % (t.primitive_type()))
+            if member.has_attr("bytes_count"):
+                scope.variable_def("uint32_t", member.name);
+                dest_var = member.name
+            else:
+                dest_var = dest.get_ref(member.name)
+            writer.assign(dest_var, "consume_%s(&in)" % (t.primitive_type()))
         #TODO validate e.g. flags and enums
     elif t.is_array():
         nelements = read_array_len(writer, member.name, t, dest, scope, handles_bytes = True)
diff --git a/python_modules/marshal.py b/python_modules/marshal.py
index 1eb3675..250147f 100644
--- a/python_modules/marshal.py
+++ b/python_modules/marshal.py
@@ -165,7 +165,7 @@ def get_array_size(array, container_src):
         else:
             return "(((%s * %s + 7) / 8 ) * %s)" % (bpp, width_v, rows_v)
     elif array.is_bytes_length():
-        return container_src.get_ref(array.size[1])
+        return container_src.get_ref(array.size[2])
     else:
         raise NotImplementedError("TODO array size type not handled yet")
 
@@ -179,20 +179,18 @@ def write_array_marshaller(writer, at_end, member, array, container_src, scope):
     nelements = get_array_size(array, container_src)
     is_byte_size = array.is_bytes_length()
 
-    if is_byte_size:
-        element = "%s__bytes" % member.name
-    else:
-        element = "%s__element" % member.name
+    element = "%s__element" % member.name
 
     if not at_end:
         writer.assign(element, container_src.get_ref(member.name))
 
     if is_byte_size:
-        scope.variable_def("size_t", "array_end")
-        writer.assign("array_end", "spice_marshaller_get_size(m) + %s" % nelements)
+        size_start_var = "%s__size_start" % member.name
+        scope.variable_def("size_t", size_start_var)
+        writer.assign(size_start_var, "spice_marshaller_get_size(m)")
 
-    with writer.index(no_block = is_byte_size) as index:
-        with writer.while_loop("spice_marshaller_get_size(m) < array_end") if is_byte_size else writer.for_loop(index, nelements) as array_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())
@@ -210,6 +208,12 @@ def write_array_marshaller(writer, at_end, member, array, container_src, scope):
             if not at_end:
                 writer.statement("%s++" % element)
 
+    if is_byte_size:
+        size_var = member.container.lookup_member(array.size[1])
+        size_var_type = size_var.member_type
+        var = "%s__ref" % array.size[1]
+        writer.statement("spice_marshaller_set_%s(m, %s, spice_marshaller_get_size(m) - %s)" % (size_var_type.primitive_type(), var, size_start_var))
+
 def write_switch_marshaller(writer, container, switch, src, scope):
     var = container.lookup_member(switch.variable)
     var_type = var.member_type
@@ -289,6 +293,11 @@ def write_member_marshaller(writer, container, member, src, scope):
     elif t.is_primitive():
         if member.has_attr("zero"):
             writer.statement("spice_marshaller_add_%s(m, 0)" % (t.primitive_type()))
+        if member.has_attr("bytes_count"):
+            var = "%s__ref" % member.name
+            scope.variable_def("void *", var)
+            writer.statement("%s = spice_marshaller_add_%s(m, %s)" % (var, t.primitive_type(), 0))
+
         elif member.has_end_attr():
             writer.statement("spice_marshaller_add_%s(m, *(%s_t *)end)" % (t.primitive_type(), t.primitive_type()))
             writer.increment("end", t.sizeof())
diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py
index 65916b3..61ef458 100644
--- a/python_modules/spice_parser.py
+++ b/python_modules/spice_parser.py
@@ -87,7 +87,7 @@ def SPICE_BNF():
         attribute = Group(Combine ("@" + identifier) + Optional(lparen + delimitedList(attributeValue) + rparen))
         attributes = Group(ZeroOrMore(attribute))
         arraySizeSpecImage = Group(image_size_ + lparen + integer + comma + identifier + comma + identifier + rparen)
-        arraySizeSpecBytes = Group(bytes_ + lparen + identifier + rparen)
+        arraySizeSpecBytes = Group(bytes_ + lparen + identifier + comma + identifier + rparen)
         arraySizeSpecCString = Group(cstring_ + lparen + rparen)
         arraySizeSpec = lbrack + Optional(identifier ^ integer ^ arraySizeSpecImage ^ arraySizeSpecBytes ^arraySizeSpecCString, default="") + rbrack
         variableDef = Group(typeSpec + Optional("*", default=None) + identifier + Optional(arraySizeSpec, default=None) + attributes - semi) \
diff --git a/server/Makefile.am b/server/Makefile.am
index dc3070f..d82f4cf 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -22,7 +22,7 @@ spice_built_sources = generated_marshallers.c generated_marshallers.h generated_
 generated_demarshallers.c: $(top_srcdir)/spice.proto
 	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --server --include red_common.h $(top_srcdir)/spice.proto generated_demarshallers.c
 
-STRUCTS=-M String -M Rect -M Point -M DisplayBase -M Fill -M Opaque -M Copy -M Blend -M Blackness -M Whiteness -M Invers -M Rop3 -M Stroke -M Text -M Transparent -M AlphaBlnd -M PathSegment
+STRUCTS=-M String -M Rect -M Point -M DisplayBase -M Fill -M Opaque -M Copy -M Blend -M Blackness -M Whiteness -M Invers -M Rop3 -M Stroke -M Text -M Transparent -M AlphaBlnd
 generated_marshallers.c: $(top_srcdir)/spice.proto
 	$(PYTHON) $(top_srcdir)/spice_codegen.py --include red_common.h --generate-marshallers $(STRUCTS) --server $(top_srcdir)/spice.proto generated_marshallers.c
 
diff --git a/server/red_parse_qxl.c b/server/red_parse_qxl.c
index de5501b..6fb439e 100644
--- a/server/red_parse_qxl.c
+++ b/server/red_parse_qxl.c
@@ -153,8 +153,10 @@ static SpicePath *red_get_path(RedMemSlotInfo *slots, int group_id,
     bool free_data;
     QXLPath *qxl;
     SpicePath *red;
-    size_t size;
+    size_t size, mem_size, mem_size2, dsize;
+    int n_segments;
     int i;
+    uint32_t count;
 
     qxl = (QXLPath *)get_virt(slots, addr, sizeof(*qxl), group_id);
     size = red_get_data_chunks_ptr(slots, group_id,
@@ -163,17 +165,44 @@ static SpicePath *red_get_path(RedMemSlotInfo *slots, int group_id,
     data = red_linearize_chunk(&chunks, size, &free_data);
     red_put_data_chunks(&chunks);
 
-    ASSERT(qxl->data_size == size);
-    ASSERT(sizeof(QXLPathSeg) == sizeof(SpicePathSeg)); /* FIXME */
-    red = spice_malloc(sizeof(*red) + size);
-    red->size = qxl->data_size;
+    n_segments = 0;
+    mem_size = sizeof(*red);
+
+    start = (QXLPathSeg*)data;
+    end = (QXLPathSeg*)(data + size);
+    while (start < end) {
+        n_segments++;
+        count = start->count;
+        mem_size += sizeof(SpicePathSeg) + count * sizeof(SpicePointFix);
+        start = (QXLPathSeg*)(&start->points[count]);
+    }
+
+    red = spice_malloc(mem_size);
+    red->num_segments = n_segments;
 
     start = (QXLPathSeg*)data;
     end = (QXLPathSeg*)(data + size);
     seg = red->segments;
+    n_segments = 0;
+    mem_size2 = sizeof(*red);
     while (start < end) {
+        n_segments++;
+        count = start->count;
+
+        /* Protect against overflow in size calculations before
+           writing to memory */
+        ASSERT(mem_size2 + sizeof(SpicePathSeg) > mem_size2);
+        mem_size2  += sizeof(SpicePathSeg);
+        ASSERT(count < UINT32_MAX / sizeof(SpicePointFix));
+        dsize = count * sizeof(SpicePointFix);
+        ASSERT(mem_size2 + dsize > mem_size2);
+        mem_size2  += dsize;
+
+        /* Verify that we didn't overflow due to guest changing data */
+        ASSERT(mem_size2 <= mem_size);
+
         seg->flags = start->flags;
-        seg->count = start->count;
+        seg->count = count;
         for (i = 0; i < seg->count; i++) {
             seg->points[i].x = start->points[i].x;
             seg->points[i].y = start->points[i].y;
@@ -181,6 +210,8 @@ static SpicePath *red_get_path(RedMemSlotInfo *slots, int group_id,
         start = (QXLPathSeg*)(&start->points[i]);
         seg = (SpicePathSeg*)(&seg->points[i]);
     }
+    /* Ensure guest didn't tamper with segment count */
+    ASSERT(n_segments == red->num_segments);
 
     if (free_data) {
         free(data);
diff --git a/server/red_worker.c b/server/red_worker.c
index 272b68d..6d821c9 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -2291,10 +2291,29 @@ static inline void __current_add_drawable(RedWorker *worker, Drawable *drawable,
 
 static int is_equal_path(RedWorker *worker, SpicePath *path1, SpicePath *path2)
 {
-    if (path1->size != path2->size)
-        return FALSE;
-    if (memcmp(path1->segments, path2->segments, path1->size) != 0)
+    SpicePathSeg *seg1, *seg2;
+    int i, j;
+
+    if (path1->num_segments != path2->num_segments)
         return FALSE;
+
+    seg1 = &path1->segments[0];
+    seg2 = &path2->segments[0];
+    for (i = 0; i < path1->num_segments; i++) {
+        if (seg1->flags != seg2->flags ||
+            seg1->count != seg2->count) {
+            return FALSE;
+        }
+        for (j = 0; j < seg1->count; j++) {
+            if (seg1->points[j].x != seg2->points[j].x ||
+                seg1->points[j].y != seg2->points[j].y) {
+                return FALSE;
+            }
+        }
+        seg1 = (SpicePathSeg*)(&seg1->points[seg1->count]);
+        seg2 = (SpicePathSeg*)(&seg2->points[seg2->count]);
+    }
+
     return TRUE;
 }
 
@@ -5121,18 +5140,6 @@ static void add_buf_from_info(RedChannel *channel, SpiceMarshaller *m, AddBufInf
 }
 
 
-static void fill_path(SpiceMarshaller *m, SpicePath *path)
-{
-    SpicePathSeg *start, *end;
-
-    spice_marshaller_add_uint32(m, path->size);
-    start = path->segments;
-    end = (SpicePathSeg*)((uint8_t*)(path->segments) + path->size);
-    while (start < end) {
-        start = spice_marshall_PathSegment(m, start);
-    }
-}
-
 static void fill_str(DisplayChannel *display_channel, SpiceMarshaller *m,
                      QXLPHYSICAL in_str, uint32_t group_id)
 {
@@ -8004,7 +8011,7 @@ static void red_send_qxl_draw_stroke(RedWorker *worker,
                           &style_out,
                           &brush_pat_out);
 
-    fill_path(path_out, stroke.path);
+    spice_marshall_Path(path_out, stroke.path);
     fill_attr(display_channel, style_out, &stroke.attr, item->group_id);
     if (brush_pat_out) {
         fill_bits(display_channel, brush_pat_out, stroke.brush.u.pattern.pat, item, FALSE);
diff --git a/spice.proto b/spice.proto
index c399150..dedf950 100644
--- a/spice.proto
+++ b/spice.proto
@@ -404,8 +404,8 @@ struct PathSegment {
 }  @ctype(SpicePathSeg);
 
 struct Path {
-    uint32 size;
-    PathSegment segments[bytes(size)] @end;
+    uint32 num_segments;
+    PathSegment segments[num_segments] @end;
 };
 
 struct Clip {
diff --git a/spice1.proto b/spice1.proto
index 75749af..0150de2 100644
--- a/spice1.proto
+++ b/spice1.proto
@@ -374,8 +374,8 @@ struct PathSegment {
 }  @ctype(SpicePathSeg);
 
 struct Path {
-    uint32 size;
-    PathSegment segments[bytes(size)] @end;
+    uint32 segments_size @bytes_count;
+    PathSegment segments[bytes(segments_size, num_segments)] @end;
 };
 
 struct Clip {
commit 0f5a6f57b70bb7c94e15e908db4627d44c339b9c
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue Jun 29 21:23:55 2010 +0200

    Add spice_marshaller_set_uint32
    
    With this function you can update an added uint32 after it being added.
    To make this possible all the spice_marshaller_add_add_foo functions
    now return a pointer that can be used as a reference when later
    setting a value.

diff --git a/common/marshaller.c b/common/marshaller.c
index ece4f48..be6198d 100644
--- a/common/marshaller.c
+++ b/common/marshaller.c
@@ -526,66 +526,79 @@ int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
 }
 #endif
 
-void spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v)
+void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v)
 {
     uint8_t *ptr;
 
     ptr = spice_marshaller_reserve_space(m, sizeof(uint64_t));
     write_uint64(ptr, v);
+    return (void *)ptr;
 }
 
-void spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v)
+void *spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v)
 {
     uint8_t *ptr;
 
     ptr = spice_marshaller_reserve_space(m, sizeof(int64_t));
     write_int64(ptr, v);
+    return (void *)ptr;
 }
 
-void spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v)
+void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v)
 {
     uint8_t *ptr;
 
     ptr = spice_marshaller_reserve_space(m, sizeof(uint32_t));
     write_uint32(ptr, v);
+    return (void *)ptr;
 }
 
-void spice_marshaller_add_int32(SpiceMarshaller *m, int32_t v)
+void spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v)
+{
+    write_uint32((uint8_t *)ref, v);
+}
+
+void *spice_marshaller_add_int32(SpiceMarshaller *m, int32_t v)
 {
     uint8_t *ptr;
 
     ptr = spice_marshaller_reserve_space(m, sizeof(int32_t));
     write_int32(ptr, v);
+    return (void *)ptr;
 }
 
-void spice_marshaller_add_uint16(SpiceMarshaller *m, uint16_t v)
+void *spice_marshaller_add_uint16(SpiceMarshaller *m, uint16_t v)
 {
     uint8_t *ptr;
 
     ptr = spice_marshaller_reserve_space(m, sizeof(uint16_t));
     write_uint16(ptr, v);
+    return (void *)ptr;
 }
 
-void spice_marshaller_add_int16(SpiceMarshaller *m, int16_t v)
+void *spice_marshaller_add_int16(SpiceMarshaller *m, int16_t v)
 {
     uint8_t *ptr;
 
     ptr = spice_marshaller_reserve_space(m, sizeof(int16_t));
     write_int16(ptr, v);
+    return (void *)ptr;
 }
 
-void spice_marshaller_add_uint8(SpiceMarshaller *m, uint8_t v)
+void *spice_marshaller_add_uint8(SpiceMarshaller *m, uint8_t v)
 {
     uint8_t *ptr;
 
     ptr = spice_marshaller_reserve_space(m, sizeof(uint8_t));
     write_uint8(ptr, v);
+    return (void *)ptr;
 }
 
-void spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v)
+void *spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v)
 {
     uint8_t *ptr;
 
     ptr = spice_marshaller_reserve_space(m, sizeof(int8_t));
     write_int8(ptr, v);
+    return (void *)ptr;
 }
diff --git a/common/marshaller.h b/common/marshaller.h
index a60e97b..59a190d 100644
--- a/common/marshaller.h
+++ b/common/marshaller.h
@@ -50,13 +50,15 @@ SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int
 int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
                                 int n_vec, size_t skip_bytes);
 #endif
-void spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v);
-void spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v);
-void spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v);
-void spice_marshaller_add_int32(SpiceMarshaller *m, int32_t v);
-void spice_marshaller_add_uint16(SpiceMarshaller *m, uint16_t v);
-void spice_marshaller_add_int16(SpiceMarshaller *m, int16_t v);
-void spice_marshaller_add_uint8(SpiceMarshaller *m, uint8_t v);
-void spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v);
+void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v);
+void *spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v);
+void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v);
+void *spice_marshaller_add_int32(SpiceMarshaller *m, int32_t v);
+void *spice_marshaller_add_uint16(SpiceMarshaller *m, uint16_t v);
+void *spice_marshaller_add_int16(SpiceMarshaller *m, int16_t v);
+void *spice_marshaller_add_uint8(SpiceMarshaller *m, uint8_t v);
+void *spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v);
+
+void  spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v);
 
 #endif
commit 5cd86fc45dfa94cb08c3316c614923ff50b94b0f
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue Jun 29 18:17:35 2010 +0200

    Update client and protocol to support the new SpiceClipRects

diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index 1bf0744..e66f845 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -1291,9 +1291,8 @@ void DisplayChannel::set_clip_rects(const SpiceClip& clip, uint32_t& num_clip_re
 {
     switch (clip.type) {
     case SPICE_CLIP_TYPE_RECTS: {
-        uint32_t* n = (uint32_t*)SPICE_GET_ADDRESS(clip.data);
-        num_clip_rects = *n;
-        clip_rects = (SpiceRect *)(n + 1);
+        num_clip_rects = clip.rects->num_rects;
+        clip_rects = clip.rects->rects;
         break;
     }
     case SPICE_CLIP_TYPE_NONE:
diff --git a/spice.proto b/spice.proto
index e1062eb..c399150 100644
--- a/spice.proto
+++ b/spice.proto
@@ -412,7 +412,7 @@ struct Clip {
     clip_type type;
     switch (type) {
     case RECTS:
-        ClipRects *data @outvar(cliprects);
+        ClipRects *rects @outvar(cliprects) @c_ptr;
     } u @anon;
 };
 
diff --git a/spice1.proto b/spice1.proto
index 98ffb49..75749af 100644
--- a/spice1.proto
+++ b/spice1.proto
@@ -382,7 +382,7 @@ struct Clip {
     clip_type type;
     switch (type) {
     case RECTS:
-        ClipRects *data @outvar(cliprects);
+        ClipRects *rects @outvar(cliprects) @c_ptr;
     default:
         uint64 data @zero;
     } u @anon;
commit bb851317657e68239bedf2d3d4c23bea26156278
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue Jun 29 18:14:49 2010 +0200

    demarshaller: Support @c_ptr attributes for pointers
    
    A @c_ptr pointer is stored in memory as a real pointer rather than a
    SPICE_ADDRESS. This is a temporary thing that will be removed again
    when all SPICE_ADDRESSes have been converted to real pointer.

diff --git a/python_modules/demarshal.py b/python_modules/demarshal.py
index d8b8ea9..faaf862 100644
--- a/python_modules/demarshal.py
+++ b/python_modules/demarshal.py
@@ -50,8 +50,9 @@ def write_parser_helpers(writer):
     writer.begin_block("struct PointerInfo")
     writer.variable_def("uint64_t", "offset")
     writer.variable_def("parse_func_t", "parse")
-    writer.variable_def("SPICE_ADDRESS *", "dest")
+    writer.variable_def("void *", "dest")
     writer.variable_def("uint32_t", "nelements")
+    writer.variable_def("int", "is_ptr")
     writer.end_block(semicolon=True)
 
 def write_read_primitive(writer, start, container, name, scope):
@@ -636,7 +637,7 @@ def write_switch_parser(writer, container, switch, dest, scope):
             if t.is_struct():
                 write_container_parser(writer, t, dest2)
             elif t.is_pointer():
-                write_parse_pointer(writer, t, False, dest2, m.name, block)
+                write_parse_pointer(writer, t, False, m.has_attr("c_ptr"), dest2, m.name, block)
             elif t.is_primitive():
                 if not m.has_attr("zero"):
                     writer.assign(dest2.get_ref(m.name), "consume_%s(&in)" % (t.primitive_type()))
@@ -725,15 +726,16 @@ def write_array_parser(writer, nelements, array, dest, scope):
                     dest2.reuse_scope = array_scope
                     write_container_parser(writer, element_type, dest2)
 
-def write_parse_pointer(writer, t, at_end, dest, member_name, scope):
+def write_parse_pointer(writer, t, at_end, as_c_ptr, dest, member_name, scope):
         target_type = t.target_type
         writer.assign("ptr_info[n_ptr].offset", "consume_%s(&in)" % t.primitive_type())
         writer.assign("ptr_info[n_ptr].parse", write_parse_ptr_function(writer, target_type))
         if at_end:
             writer.assign("ptr_info[n_ptr].dest", "end")
-            writer.increment("end", "sizeof(SPICE_ADDRESS)");
+            writer.increment("end", "sizeof(void *)" if as_c_ptr else "sizeof(SPICE_ADDRESS)");
         else:
             writer.assign("ptr_info[n_ptr].dest", "&%s" % dest.get_ref(member_name))
+        writer.assign("ptr_info[n_ptr].is_ptr", "1" if as_c_ptr else "0")
         if target_type.is_array():
             nelements = read_array_len(writer, member_name, target_type, dest, scope)
             writer.assign("ptr_info[n_ptr].nelements", nelements)
@@ -756,7 +758,7 @@ def write_member_parser(writer, container, member, dest, scope):
             writer.comment("Reuse data from network message").newline()
             writer.assign(dest.get_ref(member.name), "(size_t)(message_start + consume_%s(&in))" % t.primitive_type())
         else:
-            write_parse_pointer(writer, t, member.has_end_attr(), dest, member.name, scope)
+            write_parse_pointer(writer, t, member.has_end_attr(), member.has_attr("c_ptr"), dest, member.name, scope)
     elif t.is_primitive():
         if member.has_attr("zero"):
             pass
@@ -817,13 +819,20 @@ def write_ptr_info_check(writer):
         with writer.for_loop(index, "n_ptr") as scope:
             offset = "ptr_info[%s].offset" % index
             function = "ptr_info[%s].parse" % index
+            is_ptr = "ptr_info[%s].is_ptr" % index
             dest = "ptr_info[%s].dest" % index
             with writer.if_block("%s == 0" % offset, newline=False):
-                writer.assign("*%s" % dest, "0")
+                with writer.if_block("%s == 0" % is_ptr, newline=False):
+                    writer.assign("*(void **)(%s)" % dest, "NULL")
+                with writer.block(" else"):
+                    writer.assign("*(SPICE_ADDRESS *)(%s)" % dest, "0")
             with writer.block(" else"):
                 writer.comment("Align to 32 bit").newline()
                 writer.assign("end", "(uint8_t *)SPICE_ALIGN((size_t)end, 4)")
-                writer.assign("*%s" % dest, "(size_t)end")
+                with writer.if_block("%s == 0" % is_ptr, newline=False):
+                    writer.assign("*(void **)(%s)" % dest, "(void *)end")
+                with writer.block(" else"):
+                    writer.assign("*(SPICE_ADDRESS *)(%s)" % dest, "(SPICE_ADDRESS)end")
                 writer.assign("end", "%s(message_start, message_end, end, &ptr_info[%s], minor)" % (function, index))
                 writer.error_check("end == NULL")
     writer.newline()
commit a93351f3674feddfc9a9716e94acd4c4b131a5f2
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue Jun 29 18:13:07 2010 +0200

    demarshaller: Don't parse @zero members
    
    These just write zeros at the right place in the network protocol
    typically for old back-compat things. We don't want to read these
    back in.

diff --git a/python_modules/demarshal.py b/python_modules/demarshal.py
index 0138ebe..d8b8ea9 100644
--- a/python_modules/demarshal.py
+++ b/python_modules/demarshal.py
@@ -638,7 +638,8 @@ def write_switch_parser(writer, container, switch, dest, scope):
             elif t.is_pointer():
                 write_parse_pointer(writer, t, False, dest2, m.name, block)
             elif t.is_primitive():
-                writer.assign(dest2.get_ref(m.name), "consume_%s(&in)" % (t.primitive_type()))
+                if not m.has_attr("zero"):
+                    writer.assign(dest2.get_ref(m.name), "consume_%s(&in)" % (t.primitive_type()))
                 #TODO validate e.g. flags and enums
             elif t.is_array():
                 nelements = read_array_len(writer, m.name, t, dest, block)
@@ -757,6 +758,8 @@ def write_member_parser(writer, container, member, dest, scope):
         else:
             write_parse_pointer(writer, t, member.has_end_attr(), dest, member.name, scope)
     elif t.is_primitive():
+        if member.has_attr("zero"):
+            pass
         if member.has_end_attr():
             writer.statement("*(%s *)end = consume_%s(&in)" % (t.c_type(), t.primitive_type()))
             writer.increment("end", t.sizeof())
commit f87f63fdf58a16e62c6fcb3c4c7e11f801292ea9
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jun 25 16:20:25 2010 +0200

    qxl-abi: handle clip rect and path references.
    
    red_parse_qxl.c starts to follow QXLPHYSICAL references and build up
    data structures.  Can zap a bunch of get_virt calls in red_worker.c,
    followed by cleanups.
    
    (de-) marshaller needs updates to deal with that.  Also I suspect with
    the get_virt() calls being gone we can offload more work to generated
    marshaller code.
    
    client doesn't build.

diff --git a/common/canvas_base.c b/common/canvas_base.c
index c5ab88a..ba0fb21 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -1991,13 +1991,12 @@ static void canvas_clip_pixman(CanvasBase *canvas,
     case SPICE_CLIP_TYPE_NONE:
         break;
     case SPICE_CLIP_TYPE_RECTS: {
-        uint32_t *n = (uint32_t *)SPICE_GET_ADDRESS(clip->data);
-
-        SpiceRect *now = (SpiceRect *)(n + 1);
+        uint32_t n = clip->rects->num_rects;
+        SpiceRect *now = clip->rects->rects;
 
         pixman_region32_t clip;
 
-        if (spice_pixman_region32_init_rects(&clip, now, *n)) {
+        if (spice_pixman_region32_init_rects(&clip, now, n)) {
             pixman_region32_intersect(dest_region, dest_region, &clip);
             pixman_region32_fini(&clip);
         }
@@ -3191,7 +3190,7 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox,
 
     do {
         uint32_t flags = seg->flags;
-        SpicePointFix* point = (SpicePointFix*)seg->data;
+        SpicePointFix* point = seg->points;
         SpicePointFix* end_point = point + seg->count;
         ASSERT(point < end_point);
         more -= ((unsigned long)end_point - (unsigned long)seg);
diff --git a/common/gl_canvas.c b/common/gl_canvas.c
index 059bd04..59fb1a7 100644
--- a/common/gl_canvas.c
+++ b/common/gl_canvas.c
@@ -111,17 +111,15 @@ static pixman_image_t *canvas_surf_to_trans_surf(GLCImage *image,
     return ret;
 }
 
-static GLCPath get_path(GLCanvas *canvas, void *addr)
+static GLCPath get_path(GLCanvas *canvas, SpicePath *s)
 {
     GLCPath path = glc_path_create(canvas->glc);
-    uint32_t* data_size = (uint32_t*)addr;
-    uint32_t more = *data_size;
-
-    SpicePathSeg* seg = (SpicePathSeg*)(data_size + 1);
+    uint32_t more = s->size;
+    SpicePathSeg* seg = s->segments;
 
     do {
         uint32_t flags = seg->flags;
-        SpicePointFix* point = (SpicePointFix*)seg->data;
+        SpicePointFix* point = seg->points;
         SpicePointFix* end_point = point + seg->count;
         ASSERT(point < end_point);
         more -= ((unsigned long)end_point - (unsigned long)seg);
@@ -178,11 +176,11 @@ static void set_clip(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip)
     case SPICE_CLIP_TYPE_NONE:
         break;
     case SPICE_CLIP_TYPE_RECTS: {
-        uint32_t *n = (uint32_t *)SPICE_GET_ADDRESS(clip->data);
-        SpiceRect *now = (SpiceRect *)(n + 1);
-        SpiceRect *end = now + *n;
+        uint32_t n = clip->rects->num_rects;
+        SpiceRect *now = clip->rects->rects;
+        SpiceRect *end = now + n;
 
-        if (*n == 0) {
+        if (n == 0) {
             rect.x = rect.y = 0;
             rect.width = rect.height = 0;
             glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
diff --git a/server/red_parse_qxl.c b/server/red_parse_qxl.c
index 37aafad..de5501b 100644
--- a/server/red_parse_qxl.c
+++ b/server/red_parse_qxl.c
@@ -16,33 +16,80 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <stdbool.h>
 #include "red_common.h"
 #include "red_memslots.h"
 #include "red_parse_qxl.h"
 
-static size_t red_get_data_chunks(RedMemSlotInfo *slots, int group_id,
-                                RedDataChunk *red, SPICE_ADDRESS addr)
+#if 0
+static void hexdump_qxl(RedMemSlotInfo *slots, int group_id,
+                        SPICE_ADDRESS addr, uint8_t bytes)
+{
+    uint8_t *hex;
+    int i;
+
+    hex = (uint8_t*)get_virt(slots, addr, bytes, group_id);
+    for (i = 0; i < bytes; i++) {
+        if (0 == i % 16) {
+            fprintf(stderr, "%lx: ", addr+i);
+        }
+        if (0 == i % 4) {
+            fprintf(stderr, " ");
+        }
+        fprintf(stderr, " %02x", hex[i]);
+        if (15 == i % 16) {
+            fprintf(stderr, "\n");
+        }
+    }
+}
+#endif
+
+static uint8_t *red_linearize_chunk(RedDataChunk *head, size_t size, bool *free_chunk)
+{
+    uint8_t *data, *ptr;
+    RedDataChunk *chunk;
+    uint32_t copy;
+
+    if (head->next_chunk == NULL) {
+        ASSERT(size <= head->data_size);
+        *free_chunk = false;
+        return head->data;
+    }
+
+    ptr = data = spice_malloc(size);
+    *free_chunk = true;
+    for (chunk = head; chunk != NULL && size > 0; chunk = chunk->next_chunk) {
+        copy = MIN(chunk->data_size, size);
+        memcpy(ptr, chunk->data, copy);
+        ptr += copy;
+        size -= copy;
+    }
+    ASSERT(size == 0);
+    return data;
+}
+
+static size_t red_get_data_chunks_ptr(RedMemSlotInfo *slots, int group_id,
+                                      int memslot_id,
+                                      RedDataChunk *red, QXLDataChunk *qxl)
 {
-    QXLDataChunk *qxl;
     RedDataChunk *red_prev;
     size_t data_size = 0;
 
-    qxl = (QXLDataChunk*)get_virt(slots, addr, sizeof(*qxl), group_id);
     red->data_size = qxl->data_size;
     data_size += red->data_size;
-    validate_virt(slots, (intptr_t)qxl->data, get_memslot_id(slots, addr),
-                  red->data_size, group_id);
+    validate_virt(slots, (intptr_t)qxl->data, memslot_id, red->data_size, group_id);
     red->data = qxl->data;
     red->prev_chunk = NULL;
 
     while (qxl->next_chunk) {
         red_prev = red;
         red = spice_new(RedDataChunk, 1);
+        memslot_id = get_memslot_id(slots, qxl->next_chunk);
         qxl = (QXLDataChunk*)get_virt(slots, qxl->next_chunk, sizeof(*qxl), group_id);
+
         red->data_size = qxl->data_size;
         data_size += red->data_size;
-        validate_virt(slots, (intptr_t)qxl->data, get_memslot_id(slots, addr),
-                      red->data_size, group_id);
+        validate_virt(slots, (intptr_t)qxl->data, memslot_id, red->data_size, group_id);
         red->data = qxl->data;
         red->prev_chunk = red_prev;
         red_prev->next_chunk = red;
@@ -52,6 +99,18 @@ static size_t red_get_data_chunks(RedMemSlotInfo *slots, int group_id,
     return data_size;
 }
 
+#if 0
+static size_t red_get_data_chunks(RedMemSlotInfo *slots, int group_id,
+                                  RedDataChunk *red, SPICE_ADDRESS addr)
+{
+    QXLDataChunk *qxl;
+    int memslot_id = get_memslot_id(slots, addr);
+
+    qxl = (QXLDataChunk*)get_virt(slots, addr, sizeof(*qxl), group_id);
+    return red_get_data_chunks_ptr(slots, group_id, memslot_id, red, qxl);
+}
+#endif
+
 static void red_put_data_chunks(RedDataChunk *red)
 {
     RedDataChunk *tmp;
@@ -84,6 +143,86 @@ void red_get_rect_ptr(SpiceRect *red, QXLRect *qxl)
     red->right  = qxl->right;
 }
 
+static SpicePath *red_get_path(RedMemSlotInfo *slots, int group_id,
+                               SPICE_ADDRESS addr)
+{
+    RedDataChunk chunks;
+    QXLPathSeg *start, *end;
+    SpicePathSeg *seg;
+    uint8_t *data;
+    bool free_data;
+    QXLPath *qxl;
+    SpicePath *red;
+    size_t size;
+    int i;
+
+    qxl = (QXLPath *)get_virt(slots, addr, sizeof(*qxl), group_id);
+    size = red_get_data_chunks_ptr(slots, group_id,
+                                   get_memslot_id(slots, addr),
+                                   &chunks, &qxl->chunk);
+    data = red_linearize_chunk(&chunks, size, &free_data);
+    red_put_data_chunks(&chunks);
+
+    ASSERT(qxl->data_size == size);
+    ASSERT(sizeof(QXLPathSeg) == sizeof(SpicePathSeg)); /* FIXME */
+    red = spice_malloc(sizeof(*red) + size);
+    red->size = qxl->data_size;
+
+    start = (QXLPathSeg*)data;
+    end = (QXLPathSeg*)(data + size);
+    seg = red->segments;
+    while (start < end) {
+        seg->flags = start->flags;
+        seg->count = start->count;
+        for (i = 0; i < seg->count; i++) {
+            seg->points[i].x = start->points[i].x;
+            seg->points[i].y = start->points[i].y;
+        }
+        start = (QXLPathSeg*)(&start->points[i]);
+        seg = (SpicePathSeg*)(&seg->points[i]);
+    }
+
+    if (free_data) {
+        free(data);
+    }
+    return red;
+}
+
+static SpiceClipRects *red_get_clip_rects(RedMemSlotInfo *slots, int group_id,
+                                          SPICE_ADDRESS addr)
+{
+    RedDataChunk chunks;
+    QXLClipRects *qxl;
+    SpiceClipRects *red;
+    QXLRect *start, *end;
+    uint8_t *data;
+    bool free_data;
+    size_t size;
+    int i;
+
+    qxl = (QXLClipRects *)get_virt(slots, addr, sizeof(*qxl), group_id);
+    size = red_get_data_chunks_ptr(slots, group_id,
+                                   get_memslot_id(slots, addr),
+                                   &chunks, &qxl->chunk);
+    data = red_linearize_chunk(&chunks, size, &free_data);
+    red_put_data_chunks(&chunks);
+
+    ASSERT(qxl->num_rects * sizeof(QXLRect) == size);
+    red = spice_malloc(sizeof(*red) + qxl->num_rects * sizeof(SpiceRect));
+    red->num_rects = qxl->num_rects;
+
+    start = (QXLRect*)data;
+    end = (QXLRect*)(data + size);
+    for (i = 0; i < red->num_rects; i++) {
+        red_get_rect_ptr(red->rects + i, start++);
+    }
+
+    if (free_data) {
+        free(data);
+    }
+    return red;
+}
+
 static void red_get_brush_ptr(RedMemSlotInfo *slots, int group_id,
                               SpiceBrush *red, QXLBrush *qxl)
 {
@@ -186,7 +325,7 @@ static void red_get_rop3_ptr(RedMemSlotInfo *slots, int group_id,
 static void red_get_stroke_ptr(RedMemSlotInfo *slots, int group_id,
                                SpiceStroke *red, QXLStroke *qxl)
 {
-   red->path             = qxl->path;
+   red->path = red_get_path(slots, group_id, qxl->path);
    red->attr.flags       = qxl->attr.flags;
    red->attr.join_style  = qxl->attr.join_style;
    red->attr.end_style   = qxl->attr.end_style;
@@ -199,6 +338,11 @@ static void red_get_stroke_ptr(RedMemSlotInfo *slots, int group_id,
    red->back_mode        = qxl->back_mode;
 }
 
+static void red_put_stroke_ptr(SpiceStroke *red)
+{
+    free(red->path);
+}
+
 static void red_get_text_ptr(RedMemSlotInfo *slots, int group_id,
                                SpiceText *red, QXLText *qxl)
 {
@@ -232,7 +376,20 @@ static void red_get_clip_ptr(RedMemSlotInfo *slots, int group_id,
                              SpiceClip *red, QXLClip *qxl)
 {
     red->type = qxl->type;
-    red->data = qxl->data;
+    switch (red->type) {
+    case SPICE_CLIP_TYPE_RECTS:
+        red->rects = red_get_clip_rects(slots, group_id, qxl->data);
+        break;
+    }
+}
+
+static void red_put_clip(SpiceClip *red)
+{
+    switch (red->type) {
+    case SPICE_CLIP_TYPE_RECTS:
+        free(red->rects);
+        break;
+    }
 }
 
 void red_get_drawable(RedMemSlotInfo *slots, int group_id,
@@ -374,7 +531,12 @@ void red_get_compat_drawable(RedMemSlotInfo *slots, int group_id,
 
 void red_put_drawable(RedDrawable *red)
 {
-    /* nothing yet */
+    red_put_clip(&red->clip);
+    switch (red->type) {
+    case QXL_DRAW_STROKE:
+        red_put_stroke_ptr(&red->u.stroke);
+        break;
+    }
 }
 
 void red_get_update_cmd(RedMemSlotInfo *slots, int group_id,
diff --git a/server/red_worker.c b/server/red_worker.c
index 9ff852c..272b68d 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -2289,66 +2289,13 @@ static inline void __current_add_drawable(RedWorker *worker, Drawable *drawable,
 
 #ifdef USE_EXCLUDE_RGN
 
-static int is_equal_path(RedWorker *worker, SPICE_ADDRESS p1, SPICE_ADDRESS p2, uint32_t group_id1,
-                         uint32_t group_id2)
-{
-    QXLPath *path1;
-    QXLPath *path2;
-    QXLDataChunk *chunk1;
-    QXLDataChunk *chunk2;
-    uint8_t *data1;
-    uint8_t *data2;
-    int size;
-    int size1;
-    int size2;
-
-    ASSERT(p1 && p2);
-
-    path1 = (QXLPath *)get_virt(&worker->mem_slots, p1, sizeof(QXLPath), group_id1);
-    path2 = (QXLPath *)get_virt(&worker->mem_slots, p2, sizeof(QXLPath), group_id2);
-
-    if ((size = path1->data_size) != path2->data_size) {
+static int is_equal_path(RedWorker *worker, SpicePath *path1, SpicePath *path2)
+{
+    if (path1->size != path2->size)
         return FALSE;
-    }
-    ASSERT(size);
-
-    chunk1 = &path1->chunk;
-    size1 = chunk1->data_size;
-    data1 = chunk1->data;
-
-    chunk2 = &path2->chunk;
-    size2 = chunk2->data_size;
-    data2 = chunk2->data;
-
-    for (;;) {
-        int now = MIN(size1, size2);
-        ASSERT(now);
-        if (memcmp(data1, data2, now)) {
-            return FALSE;
-        }
-        if (!(size -= now)) {
-            return TRUE;
-        }
-        if ((size1 -= now) == 0) {
-            ASSERT(chunk1->next_chunk)
-            chunk1 = (QXLDataChunk *)get_virt(&worker->mem_slots, chunk1->next_chunk, sizeof(QXLDataChunk),
-                                              group_id1);
-            size1 = chunk1->data_size;
-            data1 = chunk1->data;
-        } else {
-            data1 += now;
-        }
-
-        if ((size2 -= now) == 0) {
-            ASSERT(chunk2->next_chunk)
-            chunk2 = (QXLDataChunk *)get_virt(&worker->mem_slots, chunk2->next_chunk, sizeof(QXLDataChunk),
-                                              group_id2);
-            size2 = chunk2->data_size;
-            data2 = chunk2->data;
-        } else {
-            data2 += now;
-        }
-    }
+    if (memcmp(path1->segments, path2->segments, path1->size) != 0)
+        return FALSE;
+    return TRUE;
 }
 
 // partial imp
@@ -2378,8 +2325,7 @@ static int is_same_geometry(RedWorker *worker, Drawable *d1, Drawable *d2)
         return is_equal_line_attr(&d1->red_drawable->u.stroke.attr,
                                   &d2->red_drawable->u.stroke.attr) &&
                is_equal_path(worker, d1->red_drawable->u.stroke.path,
-                             d2->red_drawable->u.stroke.path, d1->group_id,
-                             d2->group_id);
+                             d2->red_drawable->u.stroke.path);
     case QXL_DRAW_FILL:
         return rect_is_equal(&d1->red_drawable->bbox, &d2->red_drawable->bbox);
     default:
@@ -3445,26 +3391,12 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
 
 #endif
 
-static void add_clip_rects(RedWorker *worker, QRegion *rgn, QXLPHYSICAL data, uint32_t group_id)
+static void add_clip_rects(QRegion *rgn, SpiceClipRects *data)
 {
-    while (data) {
-        SpiceRect *now;
-        SpiceRect *end;
-        uint32_t data_size;
-
-        now = (SpiceRect *)validate_chunk(&worker->mem_slots, data, group_id, &data_size, &data);
-        end = now + data_size / sizeof(SpiceRect);
-
-        for (; now < end; now++) {
-            SpiceRect* r = (SpiceRect *)now;
+    int i;
 
-            ASSERT(now->top == r->top && now->left == r->left &&
-                   now->bottom == r->bottom && now->right == r->right);
-#ifdef PIPE_DEBUG
-            printf("TEST: DRAWABLE: RECT: %u %u %u %u\n", r->top, r->left, r->bottom, r->right);
-#endif
-            region_add(rgn, r);
-        }
+    for (i = 0; i < data->num_rects; i++) {
+        region_add(rgn, data->rects + i);
     }
 }
 
@@ -3888,9 +3820,8 @@ static inline void red_process_drawable(RedWorker *worker, RedDrawable *drawable
     if (drawable->clip.type == SPICE_CLIP_TYPE_RECTS) {
         QRegion rgn;
 
-        region_init(&
-		    rgn);
-        add_clip_rects(worker, &rgn, drawable->clip.data + SPICE_OFFSETOF(QXLClipRects, chunk), group_id);
+        region_init(&rgn);
+        add_clip_rects(&rgn, drawable->clip.rects);
         region_and(&item->tree_item.base.rgn, &rgn);
         region_destroy(&rgn);
     }
@@ -3983,38 +3914,6 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
     free(surface);
 }
 
-static void localize_path(RedWorker *worker, QXLPHYSICAL *in_path, uint32_t group_id)
-{
-    QXLPath *path;
-    uint8_t *data;
-    uint32_t data_size;
-    QXLDataChunk *chunk;
-    int memslot_id = get_memslot_id(&worker->mem_slots, *in_path);
-
-    ASSERT(in_path && *in_path);
-    path = (QXLPath *)get_virt(&worker->mem_slots, *in_path, sizeof(QXLPath), group_id);
-    data = spice_malloc_n_m(1, path->data_size, sizeof(uint32_t));
-    *in_path = (QXLPHYSICAL)data;
-    *(uint32_t *)data = path->data_size;
-    data += sizeof(uint32_t);
-    chunk = &path->chunk;
-    do {
-        data_size = chunk->data_size;
-        validate_virt(&worker->mem_slots, (unsigned long)chunk->data, memslot_id, data_size, group_id);
-        memcpy(data, chunk->data, data_size);
-        data += data_size;
-        chunk = chunk->next_chunk ? (QXLDataChunk *)get_virt(&worker->mem_slots, chunk->next_chunk,
-                                                             sizeof(QXLDataChunk), group_id) : NULL;
-    } while (chunk);
-}
-
-static void unlocalize_path(QXLPHYSICAL *path)
-{
-    ASSERT(path && *path);
-    free((void *)*path);
-    *path = 0;
-}
-
 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);
@@ -4054,54 +3953,6 @@ static void unlocalize_str(QXLPHYSICAL *str)
     *str = 0;
 }
 
-static void localize_clip(RedWorker *worker, SpiceClip *clip, uint32_t group_id)
-{
-    switch (clip->type) {
-    case SPICE_CLIP_TYPE_NONE:
-        return;
-    case SPICE_CLIP_TYPE_RECTS: {
-        QXLClipRects *clip_rects;
-        QXLDataChunk *chunk;
-        int memslot_id = get_memslot_id(&worker->mem_slots, clip->data);
-        uint8_t *data;
-        uint32_t data_size;
-        clip_rects = (QXLClipRects *)get_virt(&worker->mem_slots, clip->data, sizeof(QXLClipRects), group_id);
-        chunk = &clip_rects->chunk;
-        ASSERT(clip->data);
-        data = spice_malloc_n_m(clip_rects->num_rects, sizeof(SpiceRect), sizeof(uint32_t));
-        clip->data = (QXLPHYSICAL)data;
-        *(uint32_t *)(data) = clip_rects->num_rects;
-        data += sizeof(uint32_t);
-        do {
-            data_size = chunk->data_size;
-            validate_virt(&worker->mem_slots, (unsigned long)chunk->data, memslot_id, data_size, group_id);
-            memcpy(data, chunk->data, data_size);
-            data += data_size;
-            chunk = chunk->next_chunk ? (QXLDataChunk *)get_virt(&worker->mem_slots, chunk->next_chunk,
-                                                                 sizeof(QXLDataChunk), group_id) :
-                                         NULL;
-        } while (chunk);
-        break;
-    }
-    default:
-        red_printf("invalid clip type");
-    }
-}
-
-static void unlocalize_clip(SpiceClip *clip)
-{
-    switch (clip->type) {
-    case SPICE_CLIP_TYPE_NONE:
-        return;
-    case SPICE_CLIP_TYPE_RECTS:
-        free((void *)clip->data);
-        clip->data = 0;
-        break;
-    default:
-        red_printf("invalid clip type");
-    }
-}
-
 static LocalImage *alloc_local_image(RedWorker *worker)
 {
     ASSERT(worker->local_images_pos < MAX_BITMAPS);
@@ -4454,7 +4305,6 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
 
     region_add(&surface->draw_dirty_region, &drawable->red_drawable->bbox);
 
-    localize_clip(worker, &clip, drawable->group_id);
     switch (drawable->red_drawable->type) {
     case QXL_DRAW_FILL: {
         SpiceFill fill = drawable->red_drawable->u.fill;
@@ -4555,12 +4405,10 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
     case QXL_DRAW_STROKE: {
         SpiceStroke stroke = drawable->red_drawable->u.stroke;
         localize_brush(worker, &stroke.brush, drawable->group_id);
-        localize_path(worker, &stroke.path, drawable->group_id);
         localize_attr(worker, &stroke.attr, drawable->group_id);
         canvas->ops->draw_stroke(canvas,
                                  &drawable->red_drawable->bbox, &clip, &stroke);
         unlocalize_attr(&stroke.attr);
-        unlocalize_path(&stroke.path);
         unlocalize_brush(&stroke.brush);
         break;
     }
@@ -4579,7 +4427,6 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
     default:
         red_printf("invalid type");
     }
-    unlocalize_clip(&clip);
 }
 
 #ifndef DRAW_ALL
@@ -5212,55 +5059,6 @@ static void red_add_surface_image(RedWorker *worker, int surface_id)
     display_channel_push(worker);
 }
 
-static uint8_t *chunk_linearize(RedWorker *worker, QXLDataChunk *first_chunk,
-                                int memslot_id, uint32_t group_id, size_t expected_size,
-                                int *free_chunk)
-{
-    uint8_t *data, *ptr;
-    QXLDataChunk *chunk;
-    int data_size;
-    QXLPHYSICAL next_chunk;
-
-    data_size = first_chunk->data_size;
-    next_chunk = first_chunk->next_chunk;
-
-    if (next_chunk == 0) {
-        ASSERT(expected_size <= data_size);
-        validate_virt(&worker->mem_slots, (unsigned long)first_chunk->data, memslot_id, data_size, group_id);
-        *free_chunk = FALSE;
-        return first_chunk->data;
-    }
-
-    data = spice_malloc(expected_size);
-    *free_chunk = TRUE;
-
-    ptr = data;
-    chunk = first_chunk;
-    while (chunk != NULL && expected_size > 0) {
-        data_size = chunk->data_size;
-        next_chunk = chunk->next_chunk;
-
-        if (data_size > expected_size) {
-            data_size = expected_size;
-        }
-        expected_size -= data_size;
-
-        if (data_size) {
-            validate_virt(&worker->mem_slots, (unsigned long)chunk->data, memslot_id, data_size, group_id);
-            memcpy(ptr, chunk->data, data_size);
-            ptr += data_size;
-        }
-
-        chunk = next_chunk ?
-            (QXLDataChunk *)get_virt(&worker->mem_slots, next_chunk, sizeof(QXLDataChunk),
-                                     group_id) :
-            NULL;
-    }
-    ASSERT(expected_size == 0)
-
-    return data;
-}
-
 typedef struct {
     uint32_t type;
     void *data;
@@ -5323,34 +5121,15 @@ static void add_buf_from_info(RedChannel *channel, SpiceMarshaller *m, AddBufInf
 }
 
 
-static void fill_path(DisplayChannel *display_channel, SpiceMarshaller *m,
-                      QXLPHYSICAL in_path, uint32_t group_id)
+static void fill_path(SpiceMarshaller *m, SpicePath *path)
 {
-    RedWorker *worker;
-    RedChannel *channel = &display_channel->base;
-    int memslot_id;
-    uint8_t *path_data, *p;
-    int free_path_data;
-    worker = channel->worker;
-    size_t data_size;
-    ASSERT(in_path);
-    memslot_id  = get_memslot_id(&worker->mem_slots, in_path);
-
-    QXLPath *path = (QXLPath *)get_virt(&worker->mem_slots, in_path, sizeof(QXLPath), group_id);
-
-    data_size = path->data_size;
-    spice_marshaller_add_uint32(m, data_size);
-    path_data = chunk_linearize(worker, &path->chunk,
-                                memslot_id, group_id, data_size,
-                                &free_path_data);
+    SpicePathSeg *start, *end;
 
-    p = path_data;
-    while (p < path_data + data_size) {
-        p = spice_marshall_PathSegment(m, (SpicePathSeg *)p);
-    }
-
-    if (free_path_data) {
-        free(path_data);
+    spice_marshaller_add_uint32(m, path->size);
+    start = path->segments;
+    end = (SpicePathSeg*)((uint8_t*)(path->segments) + path->size);
+    while (start < end) {
+        start = spice_marshall_PathSegment(m, start);
     }
 }
 
@@ -5375,28 +5154,13 @@ static void fill_str(DisplayChannel *display_channel, SpiceMarshaller *m,
                          str->data_size, memslot_id, group_id);
 }
 
-static inline void fill_rects_clip(RedChannel *channel, SpiceMarshaller *m, QXLPHYSICAL in_clip, uint32_t group_id)
+static inline void fill_rects_clip(SpiceMarshaller *m, SpiceClipRects *data)
 {
-    RedWorker *worker = channel->worker;
-    QXLClipRects *clip;
-    uint8_t *rects, *r;
-    int free_rects, i;
-    int memslot_id = get_memslot_id(&worker->mem_slots, in_clip);
-
-    ASSERT(in_clip);
-    clip = (QXLClipRects *)get_virt(&worker->mem_slots, in_clip, sizeof(QXLClipRects), group_id);
-    spice_marshaller_add_uint32(m, clip->num_rects);
-    rects = chunk_linearize(worker, &clip->chunk,
-                            memslot_id, group_id, clip->num_rects * sizeof(SpiceRect),
-                            &free_rects);
-
-    r = rects;
-    for (i = 0; i < clip->num_rects; i++) {
-        r = spice_marshall_Rect(m, (SpiceRect *)r);
-    }
+    int i;
 
-    if (free_rects) {
-        free(rects);
+    spice_marshaller_add_uint32(m, data->num_rects);
+    for (i = 0; i < data->num_rects; i++) {
+        spice_marshall_Rect(m, data->rects + i);
     }
 }
 
@@ -5413,7 +5177,7 @@ static void fill_base(DisplayChannel *display_channel, Drawable *drawable)
     spice_marshall_DisplayBase(channel->send_data.marshaller, &base,
                               &cliprects_data_out);
     if (cliprects_data_out) {
-        fill_rects_clip(channel, cliprects_data_out, base.clip.data, drawable->group_id);
+        fill_rects_clip(cliprects_data_out, base.clip.rects);
     }
 }
 
@@ -7369,9 +7133,7 @@ static void surface_lossy_region_update(RedWorker *worker, DisplayChannel *displ
         region_init(&clip_rgn);
         region_init(&draw_region);
         region_add(&draw_region, &drawable->bbox);
-        add_clip_rects(worker, &clip_rgn,
-                       drawable->clip.data + SPICE_OFFSETOF(QXLClipRects, chunk),
-                       item->group_id);
+        add_clip_rects(&clip_rgn, drawable->clip.rects);
         region_and(&draw_region, &clip_rgn);
         if (lossy) {
             region_or(surface_lossy_region, &draw_region);
@@ -8242,7 +8004,7 @@ static void red_send_qxl_draw_stroke(RedWorker *worker,
                           &style_out,
                           &brush_pat_out);
 
-    fill_path(display_channel, path_out, stroke.path, item->group_id);
+    fill_path(path_out, stroke.path);
     fill_attr(display_channel, style_out, &stroke.attr, item->group_id);
     if (brush_pat_out) {
         fill_bits(display_channel, brush_pat_out, stroke.brush.u.pattern.pat, item, FALSE);
@@ -9130,7 +8892,6 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
     copy.base.box.right = item->pos.x + bitmap.x;
     copy.base.box.bottom = item->pos.y + bitmap.y;
     copy.base.clip.type = SPICE_CLIP_TYPE_NONE;
-    copy.base.clip.data = 0;
     copy.data.rop_descriptor = SPICE_ROPD_OP_PUT;
     copy.data.src_area.left = 0;
     copy.data.src_area.top = 0;
@@ -9241,7 +9002,7 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
     copy.base.surface_id = 0;
     copy.base.box = red_drawable->bbox;
     copy.base.clip.type = SPICE_CLIP_TYPE_RECTS;
-    copy.base.clip.data = 0;
+    copy.base.clip.rects = NULL;
     copy.data = red_drawable->u.copy;
 
     SpiceMarshaller *m = channel->send_data.marshaller;
@@ -9286,7 +9047,7 @@ static void red_display_send_stream_start(DisplayChannel *display_channel, Strea
         stream_create.clip = red_drawable->clip;
     } else {
         stream_create.clip.type = SPICE_CLIP_TYPE_RECTS;
-        stream_create.clip.data = 0;
+        stream_create.clip.rects = NULL;
     }
 
     spice_marshall_msg_display_stream_create(channel->send_data.marshaller, &stream_create,
@@ -9296,8 +9057,7 @@ static void red_display_send_stream_start(DisplayChannel *display_channel, Strea
     if (stream->current) {
         RedDrawable *red_drawable = stream->current->red_drawable;
         if (red_drawable->clip.type == SPICE_CLIP_TYPE_RECTS) {
-            fill_rects_clip(channel, cliprects_data_out, stream_create.clip.data,
-                            stream->current->group_id);
+            fill_rects_clip(cliprects_data_out, stream_create.clip.rects);
         } else {
             ASSERT(red_drawable->clip.type == SPICE_CLIP_TYPE_NONE);
         }
@@ -9325,7 +9085,9 @@ static void red_display_send_stream_clip(DisplayChannel *display_channel,
 
     stream_clip.id = agent - display_channel->stream_agents;
     stream_clip.clip.type = item->clip_type;
+#if 0 /* FIXME */
     stream_clip.clip.data = 0;
+#endif
 
     spice_marshall_msg_display_stream_clip(channel->send_data.marshaller, &stream_clip,
                                            &cliprects_data_out);
commit 905c6283d5f6c50ffe637f4dcb315c1345c0a0b2
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Jun 24 17:38:35 2010 +0200

    add qxl chunk parser

diff --git a/server/red_parse_qxl.c b/server/red_parse_qxl.c
index c5a8f56..37aafad 100644
--- a/server/red_parse_qxl.c
+++ b/server/red_parse_qxl.c
@@ -20,6 +20,50 @@
 #include "red_memslots.h"
 #include "red_parse_qxl.h"
 
+static size_t red_get_data_chunks(RedMemSlotInfo *slots, int group_id,
+                                RedDataChunk *red, SPICE_ADDRESS addr)
+{
+    QXLDataChunk *qxl;
+    RedDataChunk *red_prev;
+    size_t data_size = 0;
+
+    qxl = (QXLDataChunk*)get_virt(slots, addr, sizeof(*qxl), group_id);
+    red->data_size = qxl->data_size;
+    data_size += red->data_size;
+    validate_virt(slots, (intptr_t)qxl->data, get_memslot_id(slots, addr),
+                  red->data_size, group_id);
+    red->data = qxl->data;
+    red->prev_chunk = NULL;
+
+    while (qxl->next_chunk) {
+        red_prev = red;
+        red = spice_new(RedDataChunk, 1);
+        qxl = (QXLDataChunk*)get_virt(slots, qxl->next_chunk, sizeof(*qxl), group_id);
+        red->data_size = qxl->data_size;
+        data_size += red->data_size;
+        validate_virt(slots, (intptr_t)qxl->data, get_memslot_id(slots, addr),
+                      red->data_size, group_id);
+        red->data = qxl->data;
+        red->prev_chunk = red_prev;
+        red_prev->next_chunk = red;
+    }
+
+    red->next_chunk = NULL;
+    return data_size;
+}
+
+static void red_put_data_chunks(RedDataChunk *red)
+{
+    RedDataChunk *tmp;
+
+    red = red->next_chunk;
+    while (red) {
+        tmp = red;
+        red = red->next_chunk;
+        free(tmp);
+    }
+}
+
 static void red_get_point_ptr(SpicePoint *red, QXLPoint *qxl)
 {
     red->x = qxl->x;
diff --git a/server/red_parse_qxl.h b/server/red_parse_qxl.h
index aece6a9..079cf06 100644
--- a/server/red_parse_qxl.h
+++ b/server/red_parse_qxl.h
@@ -67,6 +67,14 @@ typedef struct SPICE_ATTR_PACKED RedMessage {
     uint8_t *data;
 } RedMessage;
 
+typedef struct SPICE_ATTR_PACKED RedDataChunk RedDataChunk;
+struct SPICE_ATTR_PACKED RedDataChunk {
+    uint32_t data_size;
+    RedDataChunk *prev_chunk;
+    RedDataChunk *next_chunk;
+    uint8_t *data;
+};
+
 typedef struct SPICE_ATTR_PACKED RedSurfaceCreate {
     uint32_t format;
     uint32_t width;


More information about the Spice-commits mailing list