[Spice-devel] [PATCH 15/30] Convert cairo canvas draw_text to using pixman

Alexander Larsson alexl at redhat.com
Thu Feb 18 12:58:41 PST 2010


---
 common/cairo_canvas.c |  170 ++++++++++++++++++++++++++++--------------------
 1 files changed, 99 insertions(+), 71 deletions(-)

diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c
index 109a07c..b837a1f 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -840,6 +840,43 @@ static pixman_image_t* canvas_surface_from_self(CairoCanvas *canvas, SpicePoint
     return surface;
 }
 
+static pixman_image_t *canvas_get_pixman_brush(CairoCanvas *canvas,
+                                               SpiceBrush *brush)
+{
+    switch (brush->type) {
+    case SPICE_BRUSH_TYPE_SOLID: {
+        uint32_t color = brush->u.color;
+        pixman_color_t c;
+
+        c.blue = ((color & canvas->base.color_mask) * 0xffff) / canvas->base.color_mask;
+        color >>= canvas->base.color_shift;
+        c.green = ((color & canvas->base.color_mask) * 0xffff) / canvas->base.color_mask;
+        color >>= canvas->base.color_shift;
+        c.red = ((color & canvas->base.color_mask) * 0xffff) / canvas->base.color_mask;
+        c.alpha = 0xffff;
+
+        return pixman_image_create_solid_fill (&c);
+    }
+    case SPICE_BRUSH_TYPE_PATTERN: {
+        pixman_image_t* surface;
+        pixman_transform_t t;
+
+        surface = canvas_get_image(&canvas->base, brush->u.pattern.pat);
+        pixman_transform_init_translate (&t,
+                                         pixman_int_to_fixed(-brush->u.pattern.pos.x),
+                                         pixman_int_to_fixed(-brush->u.pattern.pos.y));
+        pixman_image_set_transform (surface, &t);
+        pixman_image_set_repeat (surface, PIXMAN_REPEAT_NORMAL);
+        return surface;
+    }
+    case SPICE_BRUSH_TYPE_NONE:
+        return NULL;
+    default:
+        CANVAS_ERROR("invalid brush type");
+    }
+}
+
+
 static cairo_pattern_t *canvas_get_brush(CairoCanvas *canvas, SpiceBrush *brush, uint32_t invers)
 {
     switch (brush->type) {
@@ -981,16 +1018,6 @@ static cairo_pattern_t *canvas_get_mask_pattern(CairoCanvas *canvas, SpiceQMask
     return pattern;
 }
 
-typedef struct DrawMaskData {
-    cairo_t *cairo;
-    cairo_pattern_t *mask;
-} DrawMaskData;
-
-static void __draw_mask(void *data)
-{
-    cairo_mask(((DrawMaskData *)data)->cairo, ((DrawMaskData *)data)->mask);
-}
-
 static void copy_region (CairoCanvas *canvas,
                          pixman_region32_t *dest_region,
                          int dx, int dy)
@@ -1970,83 +1997,84 @@ void canvas_copy_bits(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
     pixman_region32_fini (&dest_region);
 }
 
-static void canvas_draw_raster_str(CairoCanvas *canvas, SpiceString *str, int bpp,
-                                   SpiceBrush *brush, uint16_t rop_decriptor)
+void canvas_draw_text(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text)
 {
-    pixman_image_t *str_mask;
-    cairo_surface_t *cairo_str_mask;
-    DrawMaskData draw_data;
-    cairo_matrix_t matrix;
+    pixman_region32_t dest_region;
+    pixman_image_t *str_mask, *brush;
+    SpiceString *str;
     SpicePoint pos;
+    int depth;
 
-    str_mask = canvas_get_str_mask(&canvas->base, str, bpp, &pos);
-    cairo_str_mask = surface_from_pixman_image (str_mask);
-    draw_data.cairo = canvas->cairo;
-    draw_data.mask = cairo_pattern_create_for_surface(cairo_str_mask);
-    if (cairo_pattern_status(draw_data.mask) != CAIRO_STATUS_SUCCESS) {
-        cairo_surface_destroy(cairo_str_mask);
-        CANVAS_ERROR("create pattern failed, %s",
-                     cairo_status_to_string(cairo_pattern_status(draw_data.mask)));
-    }
-    cairo_matrix_init_translate(&matrix, -pos.x, -pos.y);
-    cairo_pattern_set_matrix(draw_data.mask, &matrix);
-    canvas_draw(canvas, brush, rop_decriptor, __draw_mask, &draw_data);
-    cairo_pattern_destroy(draw_data.mask);
-    pixman_image_unref(str_mask);
-    cairo_surface_destroy(cairo_str_mask);
-}
+    pixman_region32_init_rect (&dest_region,
+                               bbox->left, bbox->top,
+                               bbox->right - bbox->left,
+                               bbox->bottom - bbox->top);
 
-static void canvas_draw_vector_str(CairoCanvas *canvas, SpiceString *str, SpiceBrush *brush,
-                                   uint16_t rop_decriptor)
-{
-    SpiceVectorGlyph *glyph = (SpiceVectorGlyph *)str->data;
-    int i;
+    canvas_clip_pixman (canvas, &dest_region, clip);
 
-    for (i = 0; i < str->length; i++) {
-        SpiceVectorGlyph *next_glyph = canvas_next_vector_glyph(glyph);
-        access_test(&canvas->base, glyph, (uint8_t *)next_glyph - (uint8_t *)glyph);
-        canvas_set_path(canvas, glyph->data);
-        glyph = next_glyph;
+    if (pixman_region32_n_rects (&dest_region) == 0) {
+        touch_brush (canvas, &text->fore_brush);
+        touch_brush (canvas, &text->back_brush);
+        pixman_region32_fini (&dest_region);
+        return;
     }
-    canvas_draw(canvas, brush, rop_decriptor, (DrawMethod)cairo_fill_preserve, canvas->cairo);
-    cairo_new_path(canvas->cairo);
-}
 
-void canvas_draw_text(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text)
-{
-    cairo_t *cairo = canvas->cairo;
-    SpiceString *str;
-
-    cairo_save(cairo);
-    canvas_clip(canvas, clip);
     if (!rect_is_empty(&text->back_area)) {
-        cairo_rectangle(cairo,
-                        text->back_area.left,
-                        text->back_area.top,
-                        text->back_area.right - text->back_area.left,
-                        text->back_area.bottom - text->back_area.top);
-        canvas_draw(canvas, &text->back_brush, text->back_mode,
-                    (DrawMethod)cairo_fill_preserve, cairo);
-        cairo_new_path(cairo);
+        pixman_region32_t back_region;
+
+        /* Nothing else makes sense for text and we should deprecate it
+         * and actually it means OVER really */
+        ASSERT(text->fore_mode == SPICE_ROPD_OP_PUT);
+
+        pixman_region32_init_rect (&back_region,
+                                   text->back_area.left,
+                                   text->back_area.top,
+                                   text->back_area.right - text->back_area.left,
+                                   text->back_area.bottom - text->back_area.top);
+
+        pixman_region32_intersect (&back_region, &back_region, &dest_region);
+
+        if (pixman_region32_not_empty (&back_region))
+            draw_brush(canvas, &back_region, &text->back_brush, SPICE_ROP_COPY);
+
+        pixman_region32_fini (&back_region);
     }
     str = (SpiceString *)SPICE_GET_ADDRESS(text->str);
 
     if (str->flags & SPICE_STRING_FLAGS_RASTER_A1) {
-        canvas_draw_raster_str(canvas, str, 1, &text->fore_brush, text->fore_mode);
+        depth = 1;
     } else if (str->flags & SPICE_STRING_FLAGS_RASTER_A4) {
-        canvas_draw_raster_str(canvas, str, 4, &text->fore_brush, text->fore_mode);
+        depth = 4;
     } else if (str->flags & SPICE_STRING_FLAGS_RASTER_A8) {
-        WARN("untested path A8 glyphs, doing nothing");
-        if (0) {
-            canvas_draw_raster_str(canvas, str, 8, &text->fore_brush, text->fore_mode);
-        }
+        WARN("untested path A8 glyphs");
+        depth = 8;
     } else {
-        WARN("untested path vector glyphs, doing nothing");
-        if (0) {
-            canvas_draw_vector_str(canvas, str, &text->fore_brush, text->fore_mode);
-        }
+        WARN("unsupported path vector glyphs");
+        pixman_region32_fini (&dest_region);
+        return;
     }
-    cairo_restore(cairo);
+
+    brush = canvas_get_pixman_brush(canvas, &text->fore_brush);
+
+    str_mask = canvas_get_str_mask(&canvas->base, str, depth, &pos);
+    if (brush) {
+        pixman_image_set_clip_region32 (canvas->image, &dest_region);
+
+        pixman_image_composite32 (PIXMAN_OP_OVER,
+                                  brush,
+                                  str_mask,
+                                  canvas->image,
+                                  0, 0,
+                                  0, 0,
+                                  pos.x, pos.y,
+                                  pixman_image_get_width (str_mask),
+                                  pixman_image_get_height (str_mask));
+        pixman_image_unref (brush);
+
+        pixman_image_set_clip_region32 (canvas->image, NULL);
+    }
+    pixman_image_unref (str_mask);
+    pixman_region32_fini (&dest_region);
 }
 
 void canvas_draw_stroke(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke)
-- 
1.6.6



More information about the Spice-devel mailing list