diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-02-03 12:51:13 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-02-03 12:51:13 +0000 |
commit | d15a71f128c73ce1da19e6ff5a4e2fe044b58749 (patch) | |
tree | 913c314cdf14ddaef8998e23e6321b8fdacc36f7 | |
parent | 10110d58cee179cded8e4c4ff8a8d02c477585bd (diff) |
qt: Update for fallback compositor
We now need to explicitly manage fallbacks and to provide an
implementation for map-to-image/unmap-image.
-rw-r--r-- | src/cairo-qt-surface.cpp | 210 |
1 files changed, 140 insertions, 70 deletions
diff --git a/src/cairo-qt-surface.cpp b/src/cairo-qt-surface.cpp index b75f5223..ce05dba7 100644 --- a/src/cairo-qt-surface.cpp +++ b/src/cairo-qt-surface.cpp @@ -48,6 +48,7 @@ #include "cairo-image-surface-private.h" #include "cairo-pattern-private.h" #include "cairo-surface-backend-private.h" +#include "cairo-surface-fallback-private.h" #include "cairo-ft.h" #include "cairo-qt.h" @@ -64,7 +65,7 @@ #include <QWidget> #include <QtCore/QVarLengthArray> -#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) || defined(QT_GLYPHS_API_BACKPORT) +#if ((QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) || defined(QT_GLYPHS_API_BACKPORT)) && 0 extern void qt_draw_glyphs(QPainter *, const quint32 *glyphs, const QPointF *positions, int count); #endif @@ -197,6 +198,9 @@ _qpainter_compositionmode_from_cairo_op (cairo_operator_t op) static bool _op_is_supported (cairo_qt_surface_t *qs, cairo_operator_t op) { + if (qs->p == NULL) + return false; + if (qs->supports_porter_duff) { switch (op) { case CAIRO_OPERATOR_CLEAR: @@ -555,32 +559,105 @@ _cairo_qt_surface_release_source_image (void *abstract_surface, cairo_surface_destroy (&image->base); } -static cairo_status_t -_cairo_qt_surface_acquire_dest_image (void *abstract_surface, - cairo_rectangle_int_t *interest_rect, - cairo_image_surface_t **image_out, - cairo_rectangle_int_t *image_rect, - void **image_extra) +struct _qimage_surface { + cairo_image_surface_t image; + QImage *qimg; +}; + +static cairo_surface_t * +map_qimage_to_image (QImage *qimg, const cairo_rectangle_int_t *extents) { - cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface; - QImage *qimg = NULL; + struct _qimage_surface *surface; + pixman_image_t *pixman_image; + pixman_format_code_t pixman_format; + uint8_t *data; - D(fprintf(stderr, "q[%p] acquire_dest_image\n", abstract_surface)); + if (qimg == NULL) + return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); - *image_extra = NULL; + switch (qimg->format()) { + case QImage::Format_ARGB32_Premultiplied: + pixman_format = PIXMAN_a8r8g8b8; + break; + case QImage::Format_RGB32: + pixman_format = PIXMAN_x8r8g8b8; + break; + case QImage::Format_Indexed8: // XXX not quite + pixman_format = PIXMAN_a8; + break; +#ifdef WORDS_BIGENDIAN + case QImage::Format_Mono: +#else + case QImage::Format_MonoLSB: +#endif + pixman_format = PIXMAN_a1; + break; - if (qs->image_equiv) { - *image_out = (cairo_image_surface_t*) - cairo_surface_reference (qs->image_equiv); + case QImage::Format_Invalid: +#ifdef WORDS_BIGENDIAN + case QImage::Format_MonoLSB: +#else + case QImage::Format_Mono: +#endif + case QImage::Format_ARGB32: + case QImage::Format_RGB16: + case QImage::Format_ARGB8565_Premultiplied: + case QImage::Format_RGB666: + case QImage::Format_ARGB6666_Premultiplied: + case QImage::Format_RGB555: + case QImage::Format_ARGB8555_Premultiplied: + case QImage::Format_RGB888: + case QImage::Format_RGB444: + case QImage::Format_ARGB4444_Premultiplied: + case QImage::NImageFormats: + default: + delete qimg; + return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_FORMAT); + } - image_rect->x = qs->window.x(); - image_rect->y = qs->window.y(); - image_rect->width = qs->window.width(); - image_rect->height = qs->window.height(); + data = qimg->bits(); + data += extents->y * qimg->bytesPerLine(); + data += extents->x * PIXMAN_FORMAT_BPP (pixman_format) / 8; + + pixman_image = pixman_image_create_bits (pixman_format, + extents->width, + extents->height, + (uint32_t *)data, + qimg->bytesPerLine()); + if (pixman_image == NULL) { + delete qimg; + return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + } - return CAIRO_STATUS_SUCCESS; + surface = (struct _qimage_surface *) malloc (sizeof(*surface)); + if (unlikely (surface == NULL)) { + pixman_image_unref (pixman_image); + delete qimg; + return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); } + _cairo_image_surface_init (&surface->image, pixman_image, pixman_format); + surface->qimg = qimg; + + cairo_surface_set_device_offset (&surface->image.base, + -extents->x, -extents->y); + + return &surface->image.base; +} + +static cairo_image_surface_t * +_cairo_qt_surface_map_to_image (void *abstract_surface, + const cairo_rectangle_int_t *extents) +{ + cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface; + QImage *qimg = NULL; + + D(fprintf(stderr, "q[%p] acquire_dest_image\n", abstract_surface)); + + if (qs->image_equiv) + return _cairo_image_surface_map_to_image (qs->image_equiv, + extents); + QPoint offset; if (qs->pixmap) { @@ -590,7 +667,7 @@ _cairo_qt_surface_acquire_dest_image (void *abstract_surface, // how we can grab an image from it QPaintDevice *pd = qs->p->device(); if (!pd) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_image_surface_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); QPaintDevice *rpd = QPainter::redirected(pd, &offset); if (rpd) @@ -605,50 +682,42 @@ _cairo_qt_surface_acquire_dest_image (void *abstract_surface, } } - if (qimg == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - *image_out = (cairo_image_surface_t*) - cairo_image_surface_create_for_data (qimg->bits(), - _cairo_format_from_qimage_format (qimg->format()), - qimg->width(), qimg->height(), - qimg->bytesPerLine()); - *image_extra = qimg; - - image_rect->x = qs->window.x() + offset.x(); - image_rect->y = qs->window.y() + offset.y(); - image_rect->width = qs->window.width() - offset.x(); - image_rect->height = qs->window.height() - offset.y(); - - return CAIRO_STATUS_SUCCESS; + return (cairo_image_surface_t *) map_qimage_to_image (qimg, extents); } -static void -_cairo_qt_surface_release_dest_image (void *abstract_surface, - cairo_rectangle_int_t *interest_rect, - cairo_image_surface_t *image, - cairo_rectangle_int_t *image_rect, - void *image_extra) +static cairo_int_status_t +_cairo_qt_surface_unmap_image (void *abstract_surface, + cairo_image_surface_t *image) { cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface; - D(fprintf(stderr, "q[%p] release_dest_image\n", abstract_surface)); - cairo_surface_destroy (&image->base); + D(fprintf(stderr, "q[%p] release_dest_image\n", abstract_surface)); - if (image_extra) { - QImage *qimg = (QImage*) image_extra; + if (!qs->image_equiv) { + struct _qimage_surface *qimage = (struct _qimage_surface *)image; // XXX should I be using setBackgroundMode here instead of setCompositionMode? if (qs->supports_porter_duff) qs->p->setCompositionMode (QPainter::CompositionMode_Source); - qs->p->drawImage (image_rect->x, image_rect->y, *qimg); + qs->p->drawImage ((int)qimage->image.base.device_transform.x0, + (int)qimage->image.base.device_transform.y0, + *qimage->qimg, + (int)qimage->image.base.device_transform.x0, + (int)qimage->image.base.device_transform.y0, + (int)qimage->image.width, + (int)qimage->image.height); if (qs->supports_porter_duff) qs->p->setCompositionMode (QPainter::CompositionMode_SourceOver); - delete qimg; + delete qimage->qimg; } + + cairo_surface_finish (&image->base); + cairo_surface_destroy (&image->base); + + return CAIRO_INT_STATUS_SUCCESS; } static cairo_bool_t @@ -1212,11 +1281,8 @@ _cairo_qt_surface_paint (void *abstract_surface, D(fprintf(stderr, "q[%p] paint op:%s\n", abstract_surface, _opstr(op))); - if (!qs->p) - return CAIRO_INT_STATUS_UNSUPPORTED; - if (! _op_is_supported (qs, op)) - return CAIRO_INT_STATUS_UNSUPPORTED; + return _cairo_surface_fallback_paint (abstract_surface, op, source, clip); status = _cairo_qt_surface_set_clip (qs, clip); if (unlikely (status)) @@ -1250,11 +1316,10 @@ _cairo_qt_surface_fill (void *abstract_surface, D(fprintf(stderr, "q[%p] fill op:%s\n", abstract_surface, _opstr(op))); - if (!qs->p) - return CAIRO_INT_STATUS_UNSUPPORTED; - if (! _op_is_supported (qs, op)) - return CAIRO_INT_STATUS_UNSUPPORTED; + return _cairo_surface_fallback_fill (abstract_surface, op, + source, path, fill_rule, + tolerance, antialias, clip); cairo_int_status_t status = _cairo_qt_surface_set_clip (qs, clip); if (unlikely (status)) @@ -1297,17 +1362,16 @@ _cairo_qt_surface_stroke (void *abstract_surface, D(fprintf(stderr, "q[%p] stroke op:%s\n", abstract_surface, _opstr(op))); - if (!qs->p) - return CAIRO_INT_STATUS_UNSUPPORTED; - if (! _op_is_supported (qs, op)) - return CAIRO_INT_STATUS_UNSUPPORTED; + return _cairo_surface_fallback_stroke (abstract_surface, op, + source, path, style, ctm, + ctm_inverse, tolerance, + antialias, clip); cairo_int_status_t int_status = _cairo_qt_surface_set_clip (qs, clip); if (unlikely (int_status)) return int_status; - QMatrix savedMatrix = qs->p->worldMatrix(); if (qs->supports_porter_duff) @@ -1342,7 +1406,7 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface, cairo_scaled_font_t *scaled_font, const cairo_clip_t *clip) { -#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) || defined(QT_GLYPHS_API_BACKPORT) +#if ((QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) || defined(QT_GLYPHS_API_BACKPORT)) && 0 cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface; // pick out the colour to use from the cairo source @@ -1374,7 +1438,9 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface, _cairo_scaled_font_thaw_cache(scaled_font); return CAIRO_INT_STATUS_SUCCESS; #else - return CAIRO_INT_STATUS_UNSUPPORTED; + return _cairo_surface_fallback_glyphs (abstract_surface, op, + source, glyphs, num_glyphs, + scaled_font, clip); #endif } @@ -1389,10 +1455,7 @@ _cairo_qt_surface_mask (void *abstract_surface, D(fprintf(stderr, "q[%p] mask op:%s\n", abstract_surface, _opstr(op))); - if (!qs->p) - return CAIRO_INT_STATUS_UNSUPPORTED; - - if (mask->type == CAIRO_PATTERN_TYPE_SOLID) { + if (qs->p && mask->type == CAIRO_PATTERN_TYPE_SOLID) { cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask; cairo_int_status_t result; @@ -1406,7 +1469,7 @@ _cairo_qt_surface_mask (void *abstract_surface, } // otherwise skip for now - return CAIRO_INT_STATUS_UNSUPPORTED; + return _cairo_surface_fallback_mask (abstract_surface, op, source, mask, clip); } static cairo_status_t @@ -1429,21 +1492,28 @@ _cairo_qt_surface_mark_dirty (void *abstract_surface, static const cairo_surface_backend_t cairo_qt_surface_backend = { CAIRO_SURFACE_TYPE_QT, _cairo_qt_surface_finish, + _cairo_default_context_create, /* XXX */ + _cairo_qt_surface_create_similar, NULL, /* similar image */ - NULL, /* map to image */ - NULL, /* unmap image */ + _cairo_qt_surface_map_to_image, + _cairo_qt_surface_unmap_image, + _cairo_surface_default_source, _cairo_qt_surface_acquire_source_image, _cairo_qt_surface_release_source_image, NULL, /* snapshot */ + NULL, /* copy_page */ NULL, /* show_page */ + _cairo_qt_surface_get_extents, NULL, /* get_font_options */ + NULL, /* flush */ _cairo_qt_surface_mark_dirty, + _cairo_qt_surface_paint, _cairo_qt_surface_mask, _cairo_qt_surface_stroke, |