static cairo_status_t _cairo_tee_surface_acquire_source_image (void *abstract_surface, cairo_image_surface_t **image_out, void **image_extra) { cairo_tee_surface_t *surface = abstract_surface; cairo_surface_wrapper_t *slaves; int num_slaves, n; /* we prefer to use a real image surface if available */ if (_cairo_surface_is_image (surface->master.target)) { return _cairo_surface_wrapper_acquire_source_image (&surface->master, image_out, image_extra); } num_slaves = _cairo_array_num_elements (&surface->slaves); slaves = _cairo_array_index (&surface->slaves, 0); for (n = 0; n < num_slaves; n++) { if (_cairo_surface_is_image (slaves[n].target)) { return _cairo_surface_wrapper_acquire_source_image (&slaves[n], image_out, image_extra); } } return _cairo_surface_wrapper_acquire_source_image (&surface->master, image_out, image_extra); }
static cairo_status_t _cairo_xynth_surface_clone_similar (void *abstract_surface, cairo_surface_t *src, int src_x, int src_y, int width, int height, cairo_surface_t **clone_out) { s_render_t *tmp; cairo_status_t status; cairo_xynth_surface_t *clone; cairo_xynth_surface_t *surface; ENTER(); surface = (cairo_xynth_surface_t *) abstract_surface; if (src->backend == surface->cairo.backend) { *clone_out = cairo_surface_reference(src); status = CAIRO_STATUS_SUCCESS; } else if (_cairo_surface_is_image(src)) { cairo_image_surface_t *image_src = (cairo_image_surface_t *) src; if (!CAIRO_FORMAT_VALID(image_src->format)) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto out; } clone = (cairo_xynth_surface_t *) cairo_xynth_surface_create(image_src->width, image_src->height, image_src->format); if (clone->cairo.status) { status = CAIRO_STATUS_NO_MEMORY; goto out; } s_render_init_for_data(&tmp, image_src->data, _cairo_xynth_format_from_cairo_format(image_src->format), image_src->width, image_src->height, image_src->depth, image_src->stride); s_render_composite(S_RENDER_OPERATOR_SRC, tmp, NULL, clone->render, src_x, src_y, 0, 0, src_x, src_y, width, height); s_render_uninit(tmp); *clone_out = &clone->cairo; status = CAIRO_STATUS_SUCCESS; } else { status = CAIRO_INT_STATUS_UNSUPPORTED; } out: LEAVE(); return status; }
cairo_status_t _cairo_gl_surface_clone_similar (void *abstract_surface, cairo_surface_t *src, int src_x, int src_y, int width, int height, int *clone_offset_x, int *clone_offset_y, cairo_surface_t **clone_out) { cairo_gl_surface_t *surface = abstract_surface; cairo_int_status_t status; /* XXX: Use GLCopyTexImage2D to clone non-texture-surfaces */ if (src->device == surface->base.device && _cairo_gl_surface_is_texture ((cairo_gl_surface_t *) src)) { status = _cairo_gl_surface_deferred_clear ((cairo_gl_surface_t *)src); if (unlikely (status)) return status; *clone_offset_x = 0; *clone_offset_y = 0; *clone_out = cairo_surface_reference (src); return CAIRO_STATUS_SUCCESS; } else if (_cairo_surface_is_image (src)) { cairo_image_surface_t *image_src = (cairo_image_surface_t *)src; cairo_gl_surface_t *clone; clone = (cairo_gl_surface_t *) _cairo_gl_surface_create_similar (&surface->base, src->content, width, height); if (clone == NULL) return UNSUPPORTED ("create_similar failed"); if (clone->base.status) return clone->base.status; status = _cairo_gl_surface_draw_image (clone, image_src, src_x, src_y, width, height, 0, 0); if (status) { cairo_surface_destroy (&clone->base); return status; } *clone_out = &clone->base; *clone_offset_x = src_x; *clone_offset_y = src_y; return CAIRO_STATUS_SUCCESS; } return UNSUPPORTED ("unknown src surface type in clone_similar"); }
/** * cairo_image_surface_get_height: * @surface: a #cairo_image_surface_t * * Get the height of the image surface in pixels. * * Return value: the height of the surface in pixels. * * Since: 1.0 **/ int cairo_image_surface_get_height (cairo_surface_t *surface) { cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; if (! _cairo_surface_is_image (surface)) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return 0; } return image_surface->height; }
/** * cairo_image_surface_get_format: * @surface: a #cairo_image_surface_t * * Get the format of the surface. * * Return value: the format of the surface * * Since: 1.2 **/ cairo_format_t cairo_image_surface_get_format (cairo_surface_t *surface) { cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; if (! _cairo_surface_is_image (surface)) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return CAIRO_FORMAT_INVALID; } return image_surface->format; }
/** * cairo_image_surface_get_data: * @surface: a #cairo_image_surface_t * * Get a pointer to the data of the image surface, for direct * inspection or modification. * * A call to cairo_surface_flush() is required before accessing the * pixel data to ensure that all pending drawing operations are * finished. A call to cairo_surface_mark_dirty() is required after * the data is modified. * * Return value: a pointer to the image data of this surface or %NULL * if @surface is not an image surface, or if cairo_surface_finish() * has been called. * * Since: 1.2 **/ unsigned char * cairo_image_surface_get_data (cairo_surface_t *surface) { cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; if (! _cairo_surface_is_image (surface)) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return NULL; } return image_surface->data; }
/** * cairo_image_surface_get_width: * @surface: a #cairo_image_surface_t * * Get the width of the image surface in pixels. * * Return value: the width of the surface in pixels. **/ int cairo_image_surface_get_width (cairo_surface_t *surface) { cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; if (!_cairo_surface_is_image (surface)) { _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return 0; } return image_surface->width; }
static cairo_status_t _cairo_skia_surface_clone_similar (void *asurface, cairo_surface_t *src, cairo_content_t content, int src_x, int src_y, int width, int height, int *clone_offset_x, int *clone_offset_y, cairo_surface_t **clone_out) { if (src->type == CAIRO_SURFACE_TYPE_SKIA || _cairo_surface_is_image (src)) { *clone_offset_x = 0; *clone_offset_y = 0; *clone_out = cairo_surface_reference (src); return CAIRO_STATUS_SUCCESS; } return (cairo_status_t) CAIRO_INT_STATUS_UNSUPPORTED; }
static cairo_status_t _cairo_xcb_surface_clone_similar (void *abstract_surface, cairo_surface_t *src, cairo_surface_t **clone_out) { cairo_xcb_surface_t *surface = abstract_surface; cairo_xcb_surface_t *clone; if (src->backend == surface->base.backend ) { cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src; if (_cairo_xcb_surface_same_screen(surface, xcb_src)) { *clone_out = cairo_surface_reference (src); return CAIRO_STATUS_SUCCESS; } } else if (_cairo_surface_is_image (src)) { cairo_image_surface_t *image_src = (cairo_image_surface_t *)src; cairo_content_t content = _cairo_content_from_format (image_src->format); if (surface->base.status) return surface->base.status; clone = (cairo_xcb_surface_t *) _cairo_xcb_surface_create_similar (surface, content, image_src->width, image_src->height); if (clone->base.status) return CAIRO_STATUS_NO_MEMORY; _draw_image_surface (clone, image_src, 0, 0); *clone_out = &clone->base; return CAIRO_STATUS_SUCCESS; } return CAIRO_INT_STATUS_UNSUPPORTED; }
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; }
cairo_int_status_t _cairo_gl_surface_composite (cairo_operator_t op, const cairo_pattern_t *src, const cairo_pattern_t *mask, void *abstract_dst, int src_x, int src_y, int mask_x, int mask_y, int dst_x, int dst_y, unsigned int width, unsigned int height, cairo_region_t *clip_region) { cairo_gl_surface_t *dst = abstract_dst; cairo_gl_context_t *ctx; cairo_status_t status; cairo_gl_composite_t setup; cairo_rectangle_int_t rect = { dst_x, dst_y, width, height }; int dx, dy; status = _cairo_gl_surface_deferred_clear (dst); if (unlikely (status)) return status; if (op == CAIRO_OPERATOR_SOURCE && mask == NULL && src->type == CAIRO_PATTERN_TYPE_SURFACE && _cairo_surface_is_image (((cairo_surface_pattern_t *) src)->surface) && _cairo_matrix_is_integer_translation (&src->matrix, &dx, &dy)) { cairo_image_surface_t *image = (cairo_image_surface_t *) ((cairo_surface_pattern_t *) src)->surface; dx += src_x; dy += src_y; if (dx >= 0 && dy >= 0 && dx + width <= (unsigned int) image->width && dy + height <= (unsigned int) image->height) { status = _cairo_gl_surface_draw_image (dst, image, dx, dy, width, height, dst_x, dst_y); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } } status = _cairo_gl_composite_init (&setup, op, dst, mask && mask->has_component_alpha, &rect); if (unlikely (status)) goto CLEANUP; status = _cairo_gl_composite_set_source (&setup, src, src_x, src_y, dst_x, dst_y, width, height); if (unlikely (status)) goto CLEANUP; status = _cairo_gl_composite_set_mask (&setup, mask, mask_x, mask_y, dst_x, dst_y, width, height); if (unlikely (status)) goto CLEANUP; status = _cairo_gl_composite_begin (&setup, &ctx); if (unlikely (status)) goto CLEANUP; if (clip_region != NULL) { int i, num_rectangles; num_rectangles = cairo_region_num_rectangles (clip_region); for (i = 0; i < num_rectangles; i++) { cairo_rectangle_int_t rect; cairo_region_get_rectangle (clip_region, i, &rect); _cairo_gl_composite_emit_rect (ctx, rect.x, rect.y, rect.x + rect.width, rect.y + rect.height, 0); } } else { _cairo_gl_composite_emit_rect (ctx, dst_x, dst_y, dst_x + width, dst_y + height, 0); } status = _cairo_gl_context_release (ctx, status); CLEANUP: _cairo_gl_composite_fini (&setup); return status; }
static cairo_int_status_t _cairo_beos_surface_composite (cairo_operator_t op, cairo_pattern_t *src, cairo_pattern_t *mask, void *dst, int src_x, int src_y, int mask_x, int mask_y, int dst_x, int dst_y, unsigned int width, unsigned int height) { cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( dst); AutoLockView locker(surface->view); if (!locker) return CAIRO_INT_STATUS_SUCCESS; drawing_mode mode; if (!_cairo_op_to_be_op(op, &mode)) return CAIRO_INT_STATUS_UNSUPPORTED; // XXX Masks are not yet supported if (mask) return CAIRO_INT_STATUS_UNSUPPORTED; // XXX should eventually support the others if (src->type != CAIRO_PATTERN_TYPE_SURFACE || src->extend != CAIRO_EXTEND_NONE) { return CAIRO_INT_STATUS_UNSUPPORTED; } // Can we maybe support other matrices as well? (scale? if the filter is right) int itx, ity; if (!_cairo_matrix_is_integer_translation(&src->matrix, &itx, &ity)) return CAIRO_INT_STATUS_UNSUPPORTED; BRect srcRect(src_x + itx, src_y + ity, src_x + itx + width - 1, src_y + ity + height - 1); BRect dstRect(dst_x, dst_y, dst_x + width - 1, dst_y + height - 1); cairo_surface_t* src_surface = reinterpret_cast<cairo_surface_pattern_t*>(src)-> surface; // Get a bitmap BBitmap* bmp = NULL; bool free_bmp = false; if (_cairo_surface_is_image(src_surface)) { cairo_image_surface_t* img_surface = reinterpret_cast<cairo_image_surface_t*>(src_surface); bmp = _cairo_image_surface_to_bitmap(img_surface); free_bmp = true; } else if (src_surface->backend == surface->base.backend) { cairo_beos_surface_t *beos_surface = reinterpret_cast<cairo_beos_surface_t*>(src_surface); if (beos_surface->bitmap) { AutoLockView locker(beos_surface->view); if (locker) beos_surface->view->Sync(); bmp = beos_surface->bitmap; } else { _cairo_beos_view_to_bitmap(surface->view, &bmp); free_bmp = true; } } if (!bmp) return CAIRO_INT_STATUS_UNSUPPORTED; // So, BeOS seems to screw up painting an opaque bitmap onto a // translucent one (it makes them partly transparent). Just return // unsupported. if (bmp->ColorSpace() == B_RGB32 && surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32 && (mode == B_OP_COPY || mode == B_OP_ALPHA)) { if (free_bmp) delete bmp; return CAIRO_INT_STATUS_UNSUPPORTED; } fprintf(stderr, "Composite\n"); // Draw it on screen. surface->view->PushState(); // If our image rect is only a subrect of the desired size, and we // aren't using B_OP_ALPHA, then we need to fill the rect first. if (mode == B_OP_COPY && !bmp->Bounds().Contains(srcRect)) { rgb_color black = { 0, 0, 0, 0 }; surface->view->SetDrawingMode(mode); surface->view->SetHighColor(black); surface->view->FillRect(dstRect); } if (mode == B_OP_ALPHA && bmp->ColorSpace() == B_RGB32) { mode = B_OP_COPY; } surface->view->SetDrawingMode(mode); if (surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32) surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); else surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); surface->view->DrawBitmap(bmp, srcRect, dstRect); surface->view->PopState(); if (free_bmp) delete bmp; return CAIRO_INT_STATUS_SUCCESS; }
static cairo_int_status_t _cairo_beos_composite (cairo_operator_t op, cairo_pattern_t *src, cairo_pattern_t *mask, void *dst, int src_x, int src_y, int mask_x, int mask_y, int dst_x, int dst_y, unsigned int width, unsigned int height) { cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( dst); AutoLockView locker(surface->view); if (!locker) return CAIRO_INT_STATUS_SUCCESS; drawing_mode mode; if (!_cairo_op_to_be_op(op, &mode)) return CAIRO_INT_STATUS_UNSUPPORTED; // XXX Masks are not yet supported if (mask) return CAIRO_INT_STATUS_UNSUPPORTED; // XXX should eventually support the others if (src->type != CAIRO_PATTERN_SURFACE || src->extend != CAIRO_EXTEND_NONE) { return CAIRO_INT_STATUS_UNSUPPORTED; } // Can we maybe support other matrices as well? (scale? if the filter is right) int itx, ity; if (!_cairo_matrix_is_integer_translation(&src->matrix, &itx, &ity)) return CAIRO_INT_STATUS_UNSUPPORTED; BRect srcRect(src_x + itx, src_y + ity, src_x + itx + width - 1, src_y + ity + height - 1); BRect dstRect(dst_x, dst_y, dst_x + width - 1, dst_y + height - 1); cairo_surface_t* src_surface = reinterpret_cast<cairo_surface_pattern_t*>(src)-> surface; if (_cairo_surface_is_image(src_surface)) { fprintf(stderr, "Composite\n"); // Draw it on screen. cairo_image_surface_t* img_surface = reinterpret_cast<cairo_image_surface_t*>(src_surface); BBitmap* bmp = _cairo_image_surface_to_bitmap(img_surface); surface->view->PushState(); // If our image rect is only a subrect of the desired size, and we // aren't using B_OP_ALPHA, then we need to fill the rect first. if (mode == B_OP_COPY && !bmp->Bounds().Contains(srcRect)) { rgb_color black = { 0, 0, 0, 0 }; surface->view->SetDrawingMode(mode); surface->view->SetHighColor(black); surface->view->FillRect(dstRect); } if (mode == B_OP_ALPHA && img_surface->format != CAIRO_FORMAT_ARGB32) { mode = B_OP_COPY; } surface->view->SetDrawingMode(mode); if (surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32) surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); else surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); surface->view->DrawBitmap(bmp, srcRect, dstRect); surface->view->PopState(); delete bmp; return CAIRO_INT_STATUS_SUCCESS; } return CAIRO_INT_STATUS_UNSUPPORTED; }
/** * cairo_quartz_image_surface_create: * @image_surface: a cairo image surface to wrap with a quartz image surface * * Creates a Quartz surface backed by a CGImageRef that references the * given image surface. The resulting surface can be rendered quickly * when used as a source when rendering to a #cairo_quartz_surface. If * the data in the image surface is ever updated, cairo_surface_flush() * must be called on the #cairo_quartz_image_surface to ensure that the * CGImageRef refers to the updated data. * * Return value: the newly created surface. * * Since: 1.6 **/ cairo_surface_t * cairo_quartz_image_surface_create (cairo_surface_t *surface) { cairo_quartz_image_surface_t *qisurf; CGImageRef image; cairo_image_surface_t *image_surface; int width, height, stride; cairo_format_t format; unsigned char *data; if (surface->status) return surface; if (! _cairo_surface_is_image (surface)) return SURFACE_ERROR_TYPE_MISMATCH; image_surface = (cairo_image_surface_t*) surface; width = image_surface->width; height = image_surface->height; stride = image_surface->stride; format = image_surface->format; data = image_surface->data; if (!_cairo_quartz_verify_surface_size(width, height)) return SURFACE_ERROR_INVALID_SIZE; if (width == 0 || height == 0) return SURFACE_ERROR_INVALID_SIZE; if (format != CAIRO_FORMAT_ARGB32 && format != CAIRO_FORMAT_RGB24) return SURFACE_ERROR_INVALID_FORMAT; qisurf = malloc(sizeof(cairo_quartz_image_surface_t)); if (qisurf == NULL) return SURFACE_ERROR_NO_MEMORY; memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t)); /* In case the create_cgimage fails, this ref will * be released via the callback (which will be called in * case of failure.) */ cairo_surface_reference (surface); image = CairoQuartzCreateCGImage (format, width, height, stride, data, TRUE, NULL, DataProviderReleaseCallback, image_surface); if (!image) { free (qisurf); return SURFACE_ERROR_NO_MEMORY; } _cairo_surface_init (&qisurf->base, &cairo_quartz_image_surface_backend, NULL, /* device */ _cairo_content_from_format (format)); qisurf->width = width; qisurf->height = height; qisurf->image = image; qisurf->imageSurface = image_surface; return &qisurf->base; }