static cairo_int_status_t _cairo_type3_glyph_surface_paint (void *abstract_surface, cairo_operator_t op, cairo_pattern_t *source) { cairo_type3_glyph_surface_t *surface = abstract_surface; cairo_surface_pattern_t *pattern; cairo_image_surface_t *image; void *image_extra; cairo_status_t status; if (source->type != CAIRO_PATTERN_TYPE_SURFACE) return CAIRO_INT_STATUS_IMAGE_FALLBACK; pattern = (cairo_surface_pattern_t *) source; status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra); if (status) goto fail; status = _cairo_type3_glyph_surface_emit_image_pattern (surface, image, &pattern->base.matrix); fail: _cairo_surface_release_source_image (pattern->surface, image, image_extra); return status; }
static cairo_status_t _cairo_xml_emit_surface (cairo_xml_t *xml, const cairo_surface_pattern_t *pattern) { cairo_surface_t *source = pattern->surface; cairo_status_t status; if (_cairo_surface_is_recording (source)) { status = cairo_xml_for_recording_surface (&xml->base, source); } else { cairo_image_surface_t *image; void *image_extra; status = _cairo_surface_acquire_source_image (source, &image, &image_extra); if (unlikely (status)) return status; status = _cairo_xml_emit_image (xml, image); _cairo_surface_release_source_image (source, image, image_extra); } return status; }
static cairo_status_t _cairo_surface_snapshot_acquire_source_image (void *abstract_surface, cairo_image_surface_t **image_out, void **extra_out) { cairo_surface_snapshot_t *surface = abstract_surface; return _cairo_surface_acquire_source_image (surface->target, image_out, extra_out); }
static cairo_status_t _test_fallback_surface_acquire_source_image (void *abstract_surface, cairo_image_surface_t **image_out, void **image_extra) { test_fallback_surface_t *surface = abstract_surface; return _cairo_surface_acquire_source_image (surface->backing, image_out, image_extra); }
cairo_status_t _cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper, cairo_image_surface_t **image_out, void **image_extra) { if (unlikely (wrapper->target->status)) return wrapper->target->status; return _cairo_surface_acquire_source_image (wrapper->target, image_out, image_extra); }
static void _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface) { cairo_surface_snapshot_t *snapshot = (cairo_surface_snapshot_t *) surface; cairo_image_surface_t *image; cairo_image_surface_t *clone; void *extra; cairo_status_t status; /* We need to make an image copy of the original surface since the * snapshot may exceed the lifetime of the original device, i.e. * when we later need to use the snapshot the data may have already * been lost. */ status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra); if (unlikely (status)) { snapshot->target = _cairo_surface_create_in_error (status); status = _cairo_surface_set_error (surface, status); return; } clone = (cairo_image_surface_t *) _cairo_image_surface_create_with_pixman_format (NULL, image->pixman_format, image->width, image->height, 0); if (likely (clone->base.status == CAIRO_STATUS_SUCCESS)) { if (clone->stride == image->stride) { memcpy (clone->data, image->data, image->stride * image->height); } else { pixman_image_composite32 (PIXMAN_OP_SRC, image->pixman_image, NULL, clone->pixman_image, 0, 0, 0, 0, 0, 0, image->width, image->height); } clone->base.is_clear = FALSE; snapshot->clone = &clone->base; } else { snapshot->clone = &clone->base; status = _cairo_surface_set_error (surface, clone->base.status); } _cairo_surface_release_source_image (snapshot->target, image, extra); snapshot->target = snapshot->clone; snapshot->base.type = snapshot->target->type; }
cairo_surface_t * _cairo_surface_fallback_snapshot (cairo_surface_t *surface) { cairo_surface_t *snapshot; cairo_status_t status; cairo_pattern_union_t pattern; cairo_image_surface_t *image; void *image_extra; status = _cairo_surface_acquire_source_image (surface, &image, &image_extra); if (status) return _cairo_surface_create_in_error (status); snapshot = cairo_image_surface_create (image->format, image->width, image->height); if (cairo_surface_status (snapshot)) { _cairo_surface_release_source_image (surface, image, image_extra); return snapshot; } _cairo_pattern_init_for_surface (&pattern.surface, &image->base); status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, &pattern.base, NULL, snapshot, 0, 0, 0, 0, 0, 0, image->width, image->height); _cairo_pattern_fini (&pattern.base); _cairo_surface_release_source_image (surface, image, image_extra); if (status) { cairo_surface_destroy (snapshot); return _cairo_surface_create_in_error (status); } snapshot->device_transform = surface->device_transform; snapshot->device_transform_inverse = surface->device_transform_inverse; snapshot->is_snapshot = TRUE; return snapshot; }
cairo_surface_t * _cairo_surface_fallback_snapshot (cairo_surface_t *surface) { cairo_surface_t *snapshot; cairo_status_t status; cairo_format_t format; cairo_surface_pattern_t pattern; cairo_image_surface_t *image; void *image_extra; status = _cairo_surface_acquire_source_image (surface, &image, &image_extra); if (unlikely (status)) return _cairo_surface_create_in_error (status); format = image->format; if (format == CAIRO_FORMAT_INVALID) { /* Non-standard images formats can be generated when retrieving * images from unusual xservers, for example. */ format = _cairo_format_from_content (image->base.content); } snapshot = cairo_image_surface_create (format, image->width, image->height); if (cairo_surface_status (snapshot)) { _cairo_surface_release_source_image (surface, image, image_extra); return snapshot; } _cairo_pattern_init_for_surface (&pattern, &image->base); status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, &pattern.base, NULL, snapshot, 0, 0, 0, 0, 0, 0, image->width, image->height); _cairo_pattern_fini (&pattern.base); _cairo_surface_release_source_image (surface, image, image_extra); if (unlikely (status)) { cairo_surface_destroy (snapshot); return _cairo_surface_create_in_error (status); } return snapshot; }
static void _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface) { cairo_surface_snapshot_t *snapshot = (cairo_surface_snapshot_t *) surface; cairo_image_surface_t *image; cairo_surface_t *clone; void *extra; cairo_status_t status; TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, snapshot->target->unique_id)); /* We need to make an image copy of the original surface since the * snapshot may exceed the lifetime of the original device, i.e. * when we later need to use the snapshot the data may have already * been lost. */ CAIRO_MUTEX_LOCK (snapshot->mutex); if (snapshot->target->backend->snapshot != NULL) { clone = snapshot->target->backend->snapshot (snapshot->target); if (clone != NULL) { assert (clone->status || ! _cairo_surface_is_snapshot (clone)); goto done; } } /* XXX copy to a similar surface, leave acquisition till later? * We should probably leave such decisions to the backend in case we * rely upon devices/connections like Xlib. */ status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra); if (unlikely (status)) { snapshot->target = _cairo_surface_create_in_error (status); status = _cairo_surface_set_error (surface, status); goto unlock; } clone = image->base.backend->snapshot (&image->base); _cairo_surface_release_source_image (snapshot->target, image, extra); done: status = _cairo_surface_set_error (surface, clone->status); snapshot->target = snapshot->clone = clone; snapshot->base.type = clone->type; unlock: CAIRO_MUTEX_UNLOCK (snapshot->mutex); }
static SkBitmap * pattern_to_sk_bitmap (cairo_skia_surface_t *dst, const cairo_pattern_t *pattern, SkMatrix *matrix, cairo_image_surface_t **image, void **image_extra) { if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE) return NULL; if (pattern->extend != CAIRO_EXTEND_NONE) return NULL; cairo_surface_t *surface = surface_from_pattern (pattern); SkBitmap *bitmap; if (surface->type == CAIRO_SURFACE_TYPE_SKIA) { bitmap = new SkBitmap (*((cairo_skia_surface_t *) surface)->bitmap); } else { if (surface->type != CAIRO_SURFACE_TYPE_IMAGE) { cairo_status_t status; status = _cairo_surface_acquire_source_image (surface, image, image_extra); if (unlikely (status)) return NULL; surface = &(*image)->base; } bitmap = new SkBitmap; if (unlikely (! surface_to_sk_bitmap (surface, *bitmap))) return NULL; } *matrix = matrix_inverse_to_sk (pattern->matrix); return bitmap; }
static cairo_status_t _cairo_xcb_surface_acquire_source_image (void *abstract_surface, cairo_image_surface_t **image_out, void **image_extra) { cairo_xcb_surface_t *surface = abstract_surface; cairo_image_surface_t *image; cairo_status_t status; if (surface->drm != NULL && ! surface->marked_dirty) { return _cairo_surface_acquire_source_image (surface->drm, image_out, image_extra); } if (surface->fallback != NULL) { image = (cairo_image_surface_t *) cairo_surface_reference (surface->fallback); goto DONE; } image = (cairo_image_surface_t *) _cairo_surface_has_snapshot (&surface->base, &_cairo_image_surface_backend); if (image != NULL) { image = (cairo_image_surface_t *) cairo_surface_reference (&image->base); goto DONE; } status = _get_image (surface, FALSE, &image); if (unlikely (status)) return status; _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL); DONE: *image_out = image; *image_extra = NULL; return CAIRO_STATUS_SUCCESS; }
static cairo_status_t _cairo_surface_snapshot_acquire_source_image (void *abstract_surface, cairo_image_surface_t **image_out, void **extra_out) { cairo_surface_snapshot_t *surface = abstract_surface; struct snapshot_extra *extra; cairo_status_t status; extra = malloc (sizeof (*extra)); if (unlikely (extra == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); extra->target = _cairo_surface_snapshot_get_target (&surface->base); status = _cairo_surface_acquire_source_image (extra->target, image_out, &extra->extra); if (unlikely (status)) { cairo_surface_destroy (extra->target); free (extra); } *extra_out = extra; return status; }
static SkShader* source_to_sk_shader (cairo_skia_context_t *cr, const cairo_pattern_t *pattern) { SkShader *shader = NULL; if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; return new SkColorShader (color_to_sk (solid->color)); } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_t *surface = surface_from_pattern (pattern); cr->source = cairo_surface_reference (surface); if (surface->type == CAIRO_SURFACE_TYPE_SKIA) { cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface; shader = SkShader::CreateBitmapShader (*esurf->bitmap, extend_to_sk (pattern->extend), extend_to_sk (pattern->extend)); } else { SkBitmap bitmap; if (! _cairo_surface_is_image (surface)) { cairo_status_t status; status = _cairo_surface_acquire_source_image (surface, &cr->source_image, &cr->source_extra); if (status) return NULL; surface = &cr->source_image->base; } if (unlikely (! surface_to_sk_bitmap (surface, bitmap))) return NULL; shader = SkShader::CreateBitmapShader (bitmap, extend_to_sk (pattern->extend), extend_to_sk (pattern->extend)); } } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR /* || pattern->type == CAIRO_PATTERN_TYPE_RADIAL */) { cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern; SkColor colors_stack[10]; SkScalar pos_stack[10]; SkColor *colors = colors_stack; SkScalar *pos = pos_stack; if (gradient->n_stops > 10) { colors = new SkColor[gradient->n_stops]; pos = new SkScalar[gradient->n_stops]; } for (unsigned int i = 0; i < gradient->n_stops; i++) { pos[i] = CAIRO_FIXED_TO_SK_SCALAR (gradient->stops[i].offset); colors[i] = color_stop_to_sk (gradient->stops[i].color); } if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) { cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; SkPoint points[2]; points[0].set (SkFloatToScalar (linear->pd1.x), SkFloatToScalar (linear->pd1.y)); points[1].set (SkFloatToScalar (linear->pd2.x), SkFloatToScalar (linear->pd2.y)); shader = SkGradientShader::CreateLinear (points, colors, pos, gradient->n_stops, extend_to_sk (pattern->extend)); } else { // XXX todo -- implement real radial shaders in Skia } if (gradient->n_stops > 10) { delete [] colors; delete [] pos; } } if (shader && ! _cairo_matrix_is_identity (&pattern->matrix)) shader->setLocalMatrix (matrix_inverse_to_sk (pattern->matrix)); return shader; }
static cairo_status_t upload_boxes (cairo_win32_display_surface_t *dst, const cairo_pattern_t *source, cairo_boxes_t *boxes) { const cairo_surface_pattern_t *pattern; struct upload_box cb; cairo_surface_t *surface; cairo_image_surface_t *image; void *image_extra; cairo_status_t status; TRACE ((stderr, "%s\n", __FUNCTION__)); if ((dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB) == 0) return CAIRO_INT_STATUS_UNSUPPORTED; if (! _cairo_matrix_is_integer_translation (&source->matrix, &cb.tx, &cb.ty)) return CAIRO_INT_STATUS_UNSUPPORTED; pattern = (const cairo_surface_pattern_t *) source; surface = _cairo_surface_get_source (pattern->surface, &cb.limit); /* First check that the data is entirely within the image */ if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb)) return CAIRO_INT_STATUS_UNSUPPORTED; if (surface->type != CAIRO_SURFACE_TYPE_IMAGE) { status = _cairo_surface_acquire_source_image (surface, &image, &image_extra); if (status) return status; } else image = to_image_surface(surface); status = CAIRO_INT_STATUS_UNSUPPORTED; if (!(image->format == CAIRO_FORMAT_ARGB32 || image->format == CAIRO_FORMAT_RGB24)) goto err; if (image->stride != 4*image->width) goto err; cb.dst = dst->win32.dc; cb.data = image->data; cb.bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); cb.bi.bmiHeader.biWidth = image->width; cb.bi.bmiHeader.biHeight = -image->height; cb.bi.bmiHeader.biSizeImage = 0; cb.bi.bmiHeader.biXPelsPerMeter = PELS_72DPI; cb.bi.bmiHeader.biYPelsPerMeter = PELS_72DPI; cb.bi.bmiHeader.biPlanes = 1; cb.bi.bmiHeader.biBitCount = 32; cb.bi.bmiHeader.biCompression = BI_RGB; cb.bi.bmiHeader.biClrUsed = 0; cb.bi.bmiHeader.biClrImportant = 0; cb.tx += cb.limit.x; cb.ty += cb.limit.y; status = CAIRO_STATUS_SUCCESS; if (! _cairo_boxes_for_each_box (boxes, upload_box, &cb)) status = CAIRO_INT_STATUS_UNSUPPORTED; _cairo_win32_display_surface_discard_fallback (dst); err: if (&image->base != surface) _cairo_surface_release_source_image (surface, image, image_extra); return status; }
PatternToBrushConverter (const cairo_pattern_t *pattern) : mAcquiredImageParent(0), mAcquiredImage(0), mAcquiredImageExtra(0) { if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { cairo_solid_pattern_t *solid = (cairo_solid_pattern_t*) pattern; QColor color; color.setRgbF(solid->color.red, solid->color.green, solid->color.blue, solid->color.alpha); mBrush = QBrush(color); } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t*) pattern; cairo_surface_t *surface = spattern->surface; if (surface->type == CAIRO_SURFACE_TYPE_QT) { cairo_qt_surface_t *qs = (cairo_qt_surface_t*) surface; if (qs->image) { mBrush = QBrush(*qs->image); } else if (qs->pixmap) { mBrush = QBrush(*qs->pixmap); } else { // do something smart mBrush = QBrush(0xff0000ff); } } else { cairo_image_surface_t *isurf = NULL; if (surface->type == CAIRO_SURFACE_TYPE_IMAGE) { isurf = (cairo_image_surface_t*) surface; } else { void *image_extra; if (_cairo_surface_acquire_source_image (surface, &isurf, &image_extra) == CAIRO_STATUS_SUCCESS) { mAcquiredImageParent = surface; mAcquiredImage = isurf; mAcquiredImageExtra = image_extra; } else { isurf = NULL; } } if (isurf) { mBrush = QBrush (QImage ((const uchar *) isurf->data, isurf->width, isurf->height, isurf->stride, _qimage_format_from_cairo_format (isurf->format))); } else { mBrush = QBrush(0x0000ffff); } } } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || pattern->type == CAIRO_PATTERN_TYPE_RADIAL) { QGradient *grad; cairo_bool_t reverse_stops = FALSE; cairo_bool_t emulate_reflect = FALSE; double offset = 0.0; cairo_extend_t extend = pattern->extend; cairo_gradient_pattern_t *gpat = (cairo_gradient_pattern_t *) pattern; if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) { cairo_linear_pattern_t *lpat = (cairo_linear_pattern_t *) pattern; grad = new QLinearGradient (lpat->pd1.x, lpat->pd1.y, lpat->pd2.x, lpat->pd2.y); } else if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) { cairo_radial_pattern_t *rpat = (cairo_radial_pattern_t *) pattern; /* Based on the SVG surface code */ cairo_circle_double_t *c0, *c1; double x0, y0, r0, x1, y1, r1; if (rpat->cd1.radius < rpat->cd2.radius) { c0 = &rpat->cd1; c1 = &rpat->cd2; reverse_stops = FALSE; } else { c0 = &rpat->cd2; c1 = &rpat->cd1; reverse_stops = TRUE; } x0 = c0->center.x; y0 = c0->center.y; r0 = c0->radius; x1 = c1->center.x; y1 = c1->center.y; r1 = c1->radius; if (r0 == r1) { grad = new QRadialGradient (x1, y1, r1, x1, y1); } else { double fx = (r1 * x0 - r0 * x1) / (r1 - r0); double fy = (r1 * y0 - r0 * y1) / (r1 - r0); /* QPainter doesn't support the inner circle and use instead a gradient focal. * That means we need to emulate the cairo behaviour by processing the * cairo gradient stops. * The CAIRO_EXTENT_NONE and CAIRO_EXTENT_PAD modes are quite easy to handle, * it's just a matter of stop position translation and calculation of * the corresponding SVG radial gradient focal. * The CAIRO_EXTENT_REFLECT and CAIRO_EXTEND_REPEAT modes require to compute a new * radial gradient, with an new outer circle, equal to r1 - r0 in the CAIRO_EXTEND_REPEAT * case, and 2 * (r1 - r0) in the CAIRO_EXTENT_REFLECT case, and a new gradient stop * list that maps to the original cairo stop list. */ if ((extend == CAIRO_EXTEND_REFLECT || extend == CAIRO_EXTEND_REPEAT) && r0 > 0.0) { double r_org = r1; double r, x, y; if (extend == CAIRO_EXTEND_REFLECT) { r1 = 2 * r1 - r0; emulate_reflect = TRUE; } offset = fmod (r1, r1 - r0) / (r1 - r0) - 1.0; r = r1 - r0; /* New position of outer circle. */ x = r * (x1 - fx) / r_org + fx; y = r * (y1 - fy) / r_org + fy; x1 = x; y1 = y; r1 = r; r0 = 0.0; } else { offset = r0 / r1; } grad = new QRadialGradient (x1, y1, r1, fx, fy); if (extend == CAIRO_EXTEND_NONE && r0 != 0.0) grad->setColorAt (r0 / r1, Qt::transparent); } } switch (extend) { case CAIRO_EXTEND_NONE: case CAIRO_EXTEND_PAD: grad->setSpread(QGradient::PadSpread); grad->setColorAt (0.0, Qt::transparent); grad->setColorAt (1.0, Qt::transparent); break; case CAIRO_EXTEND_REFLECT: grad->setSpread(QGradient::ReflectSpread); break; case CAIRO_EXTEND_REPEAT: grad->setSpread(QGradient::RepeatSpread); break; } for (unsigned int i = 0; i < gpat->n_stops; i++) { int index = i; if (reverse_stops) index = gpat->n_stops - i - 1; double offset = gpat->stops[i].offset; QColor color; color.setRgbF (gpat->stops[i].color.red, gpat->stops[i].color.green, gpat->stops[i].color.blue, gpat->stops[i].color.alpha); if (emulate_reflect) { offset = offset / 2.0; grad->setColorAt (1.0 - offset, color); } grad->setColorAt (offset, color); } mBrush = QBrush(*grad); delete grad; } if (mBrush.style() != Qt::NoBrush && pattern->type != CAIRO_PATTERN_TYPE_SOLID && ! _cairo_matrix_is_identity (&pattern->matrix)) { cairo_matrix_t pm = pattern->matrix; cairo_status_t status = cairo_matrix_invert (&pm); assert (status == CAIRO_STATUS_SUCCESS); mBrush.setMatrix (_qmatrix_from_cairo_matrix (pm)); } }