JSObject * gjs_cairo_ps_surface_from_surface(JSContext *context, cairo_surface_t *surface) { JSObject *object; g_return_val_if_fail(context != NULL, NULL); g_return_val_if_fail(surface != NULL, NULL); g_return_val_if_fail(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_PS, NULL); object = JS_NewObject(context, &gjs_cairo_ps_surface_class, NULL, NULL); if (!object) { gjs_throw(context, "failed to create ps surface"); return NULL; } gjs_cairo_surface_construct(context, object, surface); return object; }
void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) { ASSERT(cairo_surface_get_type(m_data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE); unsigned char* dataSrc = cairo_image_surface_get_data(m_data.m_surface); int stride = cairo_image_surface_get_stride(m_data.m_surface); for (int y = 0; y < m_size.height(); ++y) { unsigned* row = reinterpret_cast<unsigned*>(dataSrc + stride * y); for (int x = 0; x < m_size.width(); x++) { unsigned* pixel = row + x; Color pixelColor = colorFromPremultipliedARGB(*pixel); pixelColor = Color(lookUpTable[pixelColor.red()], lookUpTable[pixelColor.green()], lookUpTable[pixelColor.blue()], pixelColor.alpha()); *pixel = premultipliedARGBFromColor(pixelColor); } } cairo_surface_mark_dirty_rectangle (m_data.m_surface, 0, 0, m_size.width(), m_size.height()); }
static int surface_set_size (lua_State *L) { cairo_surface_t **obj = luaL_checkudata(L, 1, OOCAIRO_MT_NAME_SURFACE); cairo_surface_type_t type = cairo_surface_get_type(*obj); double width = luaL_checknumber(L, 2), height = luaL_checknumber(L, 3); #ifdef CAIRO_HAS_PDF_SURFACE if (type == CAIRO_SURFACE_TYPE_PDF) cairo_pdf_surface_set_size(*obj, width, height); #endif #if defined(CAIRO_HAS_PDF_SURFACE) && defined(CAIRO_HAS_PS_SURFACE) else #endif #ifdef CAIRO_HAS_PS_SURFACE if (type == CAIRO_SURFACE_TYPE_PS) cairo_ps_surface_set_size(*obj, width, height); #endif else return luaL_error(L, "method 'set_size' only works on PostScript and" " PDF surfaces"); return 0; }
gfxOS2Surface::gfxOS2Surface(HDC aDC, const gfxIntSize& aSize) : mWnd(0), mDC(aDC), mBitmap(nullptr), mSize(aSize) { #ifdef DEBUG_thebes_2 printf("gfxOS2Surface[%#x]::gfxOS2Surface(HDC=%#x, Size=%dx%d)\n", (unsigned int)this, (unsigned int)aDC, aSize.width, aSize.height); #endif SIZEL sizel = { 0, 0 }; // use same page size as device mPS = GpiCreatePS(0, mDC, &sizel, PU_PELS | GPIT_MICRO | GPIA_ASSOC); NS_ASSERTION(mPS != GPI_ERROR, "Could not create PS on print DC!"); // now create a bitmap of the right size BITMAPINFOHEADER2 hdr = { 0 }; hdr.cbFix = sizeof(BITMAPINFOHEADER2); hdr.cx = mSize.width; hdr.cy = mSize.height; hdr.cPlanes = 1; // find bit depth LONG lBitCount = 0; DevQueryCaps(mDC, CAPS_COLOR_BITCOUNT, 1, &lBitCount); hdr.cBitCount = (USHORT)lBitCount; mBitmap = GpiCreateBitmap(mPS, &hdr, 0, 0, 0); NS_ASSERTION(mBitmap != GPI_ERROR, "Could not create bitmap for printer!"); // set final stats & select bitmap into PS GpiSetBitmap(mPS, mBitmap); // now we can finally create the cairo surface on the in-memory PS cairo_surface_t *surf = cairo_os2_surface_create(mPS, mSize.width, mSize.height); #ifdef DEBUG_thebes_2 printf(" type(%#x)=%d (ID=%#x, h/w=%d/%d)\n", (unsigned int)surf, cairo_surface_get_type(surf), (unsigned int)mPS, mSize.width, mSize.height); #endif // Normally, OS/2 cairo surfaces have to be forced to redraw completely // by calling cairo_surface_mark_dirty(surf), but Mozilla paints them in // full, so that is not necessary here. Init(surf); }
LsmFilterSurface * lsm_filter_surface_new_with_content (const char *name, unsigned int x0, unsigned int y0, cairo_surface_t *surface) { LsmFilterSurface *filter_surface; g_return_val_if_fail (surface != NULL, NULL); g_return_val_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE, NULL); g_return_val_if_fail (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32, NULL); cairo_surface_reference (surface); filter_surface = g_new (LsmFilterSurface, 1); filter_surface->name = g_strdup (name); filter_surface->x0 = x0; filter_surface->y0 = y0; filter_surface->x1 = x0 + cairo_image_surface_get_width (surface); filter_surface->y1 = y0 + cairo_image_surface_get_height (surface); filter_surface->surface = surface; filter_surface->ref_count = 1; return filter_surface; }
cairo_surface_t * _rescaleTo(cairo_surface_t * surf, double width, double height) { cairo_surface_t * dest; #if 0 dest = cairo_surface_create_similar(surf, CAIRO_CONTENT_COLOR_ALPHA, width, height); UT_ASSERT(CAIRO_SURFACE_TYPE_IMAGE == cairo_surface_get_type(surf)); double ow = cairo_image_surface_get_width(surf); double oh = cairo_image_surface_get_height(surf); cairo_t *cr = cairo_create(dest); cairo_set_source_surface(cr, dest, 0, 0); cairo_scale(cr, width/ow, height/oh); cairo_paint(cr); cairo_destroy(cr); #else // NO-OP as this do not work. cairo_surface_reference(surf); dest = surf; #endif return dest; }
static SEXP CairoGD_Cap(NewDevDesc *dd) { SEXP raster = R_NilValue, dim; CairoGDDesc *xd = (CairoGDDesc *) dd->deviceSpecific; cairo_surface_t *s; if(!xd || !xd->cb || !(s = xd->cb->cs)) return raster; cairo_surface_flush(s); /* we have defined way of getting the contents only from image back-ends */ if (cairo_surface_get_type(s) == CAIRO_SURFACE_TYPE_IMAGE) { int w = cairo_image_surface_get_width(s); int h = cairo_image_surface_get_height(s); unsigned int *dst, size = w * h, i; unsigned int *img = (unsigned int*) cairo_image_surface_get_data(s); cairo_format_t fmt = cairo_image_surface_get_format(s); /* we only support RGB or ARGB */ if (fmt != CAIRO_FORMAT_RGB24 && fmt != CAIRO_FORMAT_ARGB32) return raster; raster = PROTECT(allocVector(INTSXP, size)); dst = (unsigned int*) INTEGER(raster); #ifdef JGD_DEBUG Rprintf("format = %s (%d x %d)\n", (fmt == CAIRO_FORMAT_ARGB32) ? "ARGB" : "RGB", w, h); #endif if (fmt == CAIRO_FORMAT_ARGB32) /* ARGB is the default we use in most cases */ /* annoyingly Cairo uses pre-multiplied storage so we have to reverse that */ for (i = 0; i < size; i++) { unsigned int v = *(img++), a = v >> 24; dst[i] = (a == 0) ? 0 : /* special cases for alpha = 0.0 and 1.0 */ ((a == 255) ? R_RGB((v >> 16) & 255, (v >> 8) & 255, v & 255) : R_RGBA(((v >> 16) & 255) * 255 / a, ((v >> 8) & 255) * 255 / a, (v & 255) * 255 / a, a)); } else for (i = 0; i < size; i++)
char * panel_background_make_string (PanelBackground *background, int x, int y) { PanelBackgroundType effective_type; char *retval; retval = NULL; effective_type = panel_background_effective_type (background); if (effective_type == PANEL_BACK_IMAGE || (effective_type == PANEL_BACK_COLOR && background->has_alpha && (!gdk_window_check_composited_wm(background->window)))) { cairo_surface_t *surface; if (!background->composited_pattern) return NULL; if (cairo_pattern_get_surface (background->composited_pattern, &surface) != CAIRO_STATUS_SUCCESS) return NULL; if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_XLIB) return NULL; retval = g_strdup_printf ("pixmap:%d,%d,%d", (guint32)cairo_xlib_surface_get_drawable (surface), x, y); } else if (effective_type == PANEL_BACK_COLOR) { gchar *rgba = gdk_rgba_to_string (&background->color); retval = g_strdup_printf ( "color:%s", rgba); g_free (rgba); } else retval = g_strdup ("none:"); return retval; }
static bool getType_func(JSContext *context, unsigned argc, JS::Value *vp) { GJS_GET_THIS(context, argc, vp, rec, obj); cairo_surface_t *surface; cairo_surface_type_t type; if (argc > 1) { gjs_throw(context, "Surface.getType() takes no arguments"); return false; } surface = gjs_cairo_surface_get_surface(context, obj); type = cairo_surface_get_type(surface); if (!gjs_cairo_check_status(context, cairo_surface_status(surface), "surface")) return false; rec.rval().setInt32(type); return true; }
/** * Create an exact copy of a surface. * Creates a surface that has the same type, content type, dimensions and contents * as the specified surface. */ cairo_surface_t * ink_cairo_surface_copy(cairo_surface_t *s) { cairo_surface_t *ns = ink_cairo_surface_create_identical(s); if (cairo_surface_get_type(s) == CAIRO_SURFACE_TYPE_IMAGE) { // use memory copy instead of using a Cairo context cairo_surface_flush(s); int stride = cairo_image_surface_get_stride(s); int h = cairo_image_surface_get_height(s); memcpy(cairo_image_surface_get_data(ns), cairo_image_surface_get_data(s), stride * h); cairo_surface_mark_dirty(ns); } else { // generic implementation cairo_t *ct = cairo_create(ns); cairo_set_source_surface(ct, s, 0, 0); cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); cairo_paint(ct); cairo_destroy(ct); } return ns; }
TemporaryRef<DataSourceSurface> SourceSurfaceCairo::GetDataSurface() { RefPtr<DataSourceSurfaceCairo> dataSurf; if (cairo_surface_get_type(mSurface) == CAIRO_SURFACE_TYPE_IMAGE) { dataSurf = new DataSourceSurfaceCairo(mSurface); } else { cairo_surface_t* imageSurf = cairo_image_surface_create(GfxFormatToCairoFormat(mFormat), mSize.width, mSize.height); // Fill the new image surface with the contents of our surface. cairo_t* ctx = cairo_create(imageSurf); cairo_set_source_surface(ctx, mSurface, 0, 0); cairo_paint(ctx); cairo_destroy(ctx); dataSurf = new DataSourceSurfaceCairo(imageSurf); cairo_surface_destroy(imageSurf); } return dataSurf; }
GeglBuffer * gimp_cairo_surface_create_buffer (cairo_surface_t *surface) { const Babl *format; gint width; gint height; g_return_val_if_fail (surface != NULL, NULL); g_return_val_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE, NULL); format = gimp_cairo_surface_get_format (surface); width = cairo_image_surface_get_width (surface); height = cairo_image_surface_get_height (surface); return gegl_buffer_linear_new_from_data (cairo_image_surface_get_data (surface), format, GEGL_RECTANGLE (0, 0, width, height), cairo_image_surface_get_stride (surface), (GDestroyNotify) cairo_surface_destroy, cairo_surface_reference (surface)); }
static JSBool getType_func(JSContext *context, uintN argc, jsval *vp) { JSObject *obj = JS_THIS_OBJECT(context, vp); cairo_surface_t *surface; cairo_surface_type_t type; if (argc > 1) { gjs_throw(context, "Surface.getType() takes no arguments"); return JS_FALSE; } surface = gjs_cairo_surface_get_surface(context, obj); type = cairo_surface_get_type(surface); if (!gjs_cairo_check_status(context, cairo_surface_status(surface), "surface")) return JS_FALSE; JS_SET_RVAL(context, vp, INT_TO_JSVAL(type)); return JS_TRUE; }
static void _gl_pattern_fix_reference_count (const cairo_pattern_t *pattern) { cairo_pattern_type_t pattern_type = cairo_pattern_get_type ((cairo_pattern_t *)pattern); /* We need to increase reference count on surface and gradient if the original_source_pattern is a cairo_gl_source_t type. */ if (pattern_type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)pattern; cairo_surface_t *pattern_surface = surface_pattern->surface; if (cairo_surface_get_type (pattern_surface) == CAIRO_SURFACE_TYPE_GL && ! pattern_surface->device && ! _cairo_surface_is_subsurface (pattern_surface)) { cairo_gl_source_t *_source = (cairo_gl_source_t *)pattern_surface; switch (_source->operand.type) { case CAIRO_GL_OPERAND_TEXTURE: cairo_surface_reference (&(_source->operand.texture.owns_surface)->base); break; case CAIRO_GL_OPERAND_LINEAR_GRADIENT: case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: _cairo_gl_gradient_reference (_source->operand.gradient.gradient); break; default: case CAIRO_GL_OPERAND_NONE: case CAIRO_GL_OPERAND_CONSTANT: case CAIRO_GL_OPERAND_COUNT: break; } } } }
static void unix_start_page (GtkPrintOperation *op, GtkPrintContext *print_context, GtkPageSetup *page_setup) { GtkPrintOperationUnix *op_unix; GtkPaperSize *paper_size; cairo_surface_type_t type; gdouble w, h; op_unix = op->priv->platform_data; paper_size = gtk_page_setup_get_paper_size (page_setup); w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS); h = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS); type = cairo_surface_get_type (op_unix->surface); if (type == CAIRO_SURFACE_TYPE_PS) cairo_ps_surface_set_size (op_unix->surface, w, h); else if (type == CAIRO_SURFACE_TYPE_PDF) cairo_pdf_surface_set_size (op_unix->surface, w, h); }
static void get_surface_size (GtkIconHelper *self, GtkStyleContext *context, cairo_surface_t *surface, int *width, int *height) { double x_scale, y_scale; if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE) { x_scale = y_scale = 1; cairo_surface_get_device_scale (surface, &x_scale, &y_scale); /* Assume any set scaling is icon scale */ *width = ceil (cairo_image_surface_get_width (surface) / x_scale); *height = ceil (cairo_image_surface_get_height (surface) / y_scale); } else ensure_icon_size (self, context, width, height); }
cairo_status_t cairo_boilerplate_xlib_surface_disable_render (cairo_surface_t *abstract_surface) { #if 0 /* The following stunt doesn't work with xlib-xcb because it doesn't use * cairo_xlib_surface_t for its surfaces. Sadly, there is no sane * alternative, so we can't disable render with xlib-xcb. * FIXME: Find an alternative. */ #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS cairo_xlib_surface_t *surface = (cairo_xlib_surface_t*) abstract_surface; if (cairo_surface_get_type (abstract_surface) != CAIRO_SURFACE_TYPE_XLIB) return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; surface->render_major = surface->render_minor = -1; surface->xrender_format = NULL; /* The content type is forced by _xrender_format_to_content() during * non-Render surface creation, so repeat the procedure here. */ surface->base.content = CAIRO_CONTENT_COLOR; /* These flags are set based on known bugs and lack of RENDER support */ #if CAIRO_XLIB_SURFACE_HAS_BUGGY_GRADIENTS surface->buggy_gradients = TRUE; #endif #if CAIRO_XLIB_SURFACE_HAS_BUGGY_PAD_REFLECT surface->buggy_pad_reflect = TRUE; #endif #if CAIRO_XLIB_SURFACE_HAS_BUGGY_REPEAT surface->buggy_repeat = TRUE; #endif #endif #endif return CAIRO_STATUS_SUCCESS; }
/** * cairo_quartz_image_surface_create * @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 (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_IMAGE) 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_NO_MEMORY; if (width == 0 || height == 0) return SURFACE_ERROR_NO_MEMORY; 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 = _cairo_quartz_create_cgimage (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, _cairo_content_from_format (format)); qisurf->extents.x = qisurf->extents.y = 0; qisurf->extents.width = width; qisurf->extents.height = height; qisurf->image = image; qisurf->imageSurface = image_surface; return &qisurf->base; }
cairo_surface_t * _cairo_boilerplate_get_image_surface (cairo_surface_t *src, int page, int width, int height) { cairo_surface_t *surface, *image; cairo_t *cr; cairo_status_t status; cairo_format_t format; if (cairo_surface_status (src)) return cairo_surface_reference (src); if (page != 0) return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); /* extract sub-surface */ switch (cairo_surface_get_content (src)) { case CAIRO_CONTENT_ALPHA: format = CAIRO_FORMAT_A8; break; case CAIRO_CONTENT_COLOR: format = CAIRO_FORMAT_RGB24; break; default: case CAIRO_CONTENT_COLOR_ALPHA: format = CAIRO_FORMAT_ARGB32; break; } surface = cairo_image_surface_create (format, width, height); assert (cairo_surface_get_content (surface) == cairo_surface_get_content (src)); image = cairo_surface_reference (surface); /* open a logging channel (only interesting for recording surfaces) */ #if CAIRO_HAS_SCRIPT_SURFACE && CAIRO_HAS_RECORDING_SURFACE if (cairo_surface_get_type (src) == CAIRO_SURFACE_TYPE_RECORDING) { const char *test_name; test_name = cairo_surface_get_user_data (src, &cairo_boilerplate_output_basename_key); if (test_name != NULL) { cairo_device_t *ctx; char *filename; cairo_surface_destroy (surface); xasprintf (&filename, "%s.out.trace", test_name); ctx = cairo_script_create (filename); surface = cairo_script_surface_create_for_target (ctx, image); cairo_device_destroy (ctx); free (filename); } } #endif cr = cairo_create (surface); cairo_surface_destroy (surface); cairo_set_source_surface (cr, src, 0, 0); cairo_paint (cr); status = cairo_status (cr); if (status) { cairo_surface_destroy (image); image = cairo_surface_reference (cairo_get_target (cr)); } cairo_destroy (cr); return image; }
static cairo_test_status_t cairo_test_for_target (cairo_test_context_t *ctx, const cairo_boilerplate_target_t *target, int dev_offset, cairo_bool_t similar) { cairo_test_status_t status; cairo_surface_t *surface = NULL; cairo_t *cr; const char *empty_str = ""; char *offset_str; char *base_name, *base_path; char *out_png_path; char *ref_path = NULL, *ref_png_path, *cmp_png_path = NULL; char *new_path = NULL, *new_png_path; char *xfail_path = NULL, *xfail_png_path; char *base_ref_png_path; char *base_new_png_path; char *base_xfail_png_path; char *diff_png_path; char *test_filename = NULL, *pass_filename = NULL, *fail_filename = NULL; cairo_test_status_t ret; cairo_content_t expected_content; cairo_font_options_t *font_options; const char *format; cairo_bool_t have_output = FALSE; cairo_bool_t have_result = FALSE; void *closure; double width, height; cairo_bool_t have_output_dir; #if HAVE_MEMFAULT int malloc_failure_iterations = ctx->malloc_failure; int last_fault_count = 0; #endif /* Get the strings ready that we'll need. */ format = cairo_boilerplate_content_name (target->content); if (dev_offset) xasprintf (&offset_str, ".%d", dev_offset); else offset_str = (char *) empty_str; xasprintf (&base_name, "%s.%s.%s%s%s", ctx->test_name, target->name, format, similar ? ".similar" : "", offset_str); if (offset_str != empty_str) free (offset_str); ref_png_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, target->name, target->basename, format, CAIRO_TEST_REF_SUFFIX, CAIRO_TEST_PNG_EXTENSION); new_png_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, target->name, target->basename, format, CAIRO_TEST_NEW_SUFFIX, CAIRO_TEST_PNG_EXTENSION); xfail_png_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, target->name, target->basename, format, CAIRO_TEST_XFAIL_SUFFIX, CAIRO_TEST_PNG_EXTENSION); base_ref_png_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, NULL, NULL, format, CAIRO_TEST_REF_SUFFIX, CAIRO_TEST_PNG_EXTENSION); base_new_png_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, NULL, NULL, format, CAIRO_TEST_NEW_SUFFIX, CAIRO_TEST_PNG_EXTENSION); base_xfail_png_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, NULL, NULL, format, CAIRO_TEST_XFAIL_SUFFIX, CAIRO_TEST_PNG_EXTENSION); if (target->file_extension != NULL) { ref_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, target->name, target->basename, format, CAIRO_TEST_REF_SUFFIX, target->file_extension); new_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, target->name, target->basename, format, CAIRO_TEST_NEW_SUFFIX, target->file_extension); xfail_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, target->name, target->basename, format, CAIRO_TEST_XFAIL_SUFFIX, target->file_extension); } have_output_dir = _cairo_test_mkdir (ctx->output); xasprintf (&base_path, "%s/%s", have_output_dir ? ctx->output : ".", base_name); xasprintf (&out_png_path, "%s" CAIRO_TEST_OUT_PNG, base_path); xasprintf (&diff_png_path, "%s" CAIRO_TEST_DIFF_PNG, base_path); if (ctx->test->requirements != NULL) { const char *required; required = target->is_vector ? "target=raster" : "target=vector"; if (strstr (ctx->test->requirements, required) != NULL) { cairo_test_log (ctx, "Error: Skipping for %s target %s\n", target->is_vector ? "vector" : "raster", target->name); ret = CAIRO_TEST_UNTESTED; goto UNWIND_STRINGS; } required = target->is_recording ? "target=!recording" : "target=recording"; if (strstr (ctx->test->requirements, required) != NULL) { cairo_test_log (ctx, "Error: Skipping for %s target %s\n", target->is_recording ? "recording" : "non-recording", target->name); ret = CAIRO_TEST_UNTESTED; goto UNWIND_STRINGS; } } width = ctx->test->width; height = ctx->test->height; if (width && height) { width += dev_offset; height += dev_offset; } #if HAVE_MEMFAULT REPEAT: MEMFAULT_CLEAR_FAULTS (); MEMFAULT_RESET_LEAKS (); ctx->last_fault_count = 0; last_fault_count = MEMFAULT_COUNT_FAULTS (); /* Pre-initialise fontconfig so that the configuration is loaded without * malloc failures (our primary goal is to test cairo fault tolerance). */ #if HAVE_FCINIT FcInit (); #endif MEMFAULT_ENABLE_FAULTS (); #endif have_output = FALSE; have_result = FALSE; /* Run the actual drawing code. */ ret = CAIRO_TEST_SUCCESS; surface = (target->create_surface) (base_path, target->content, width, height, ctx->test->width + 25 * NUM_DEVICE_OFFSETS, ctx->test->height + 25 * NUM_DEVICE_OFFSETS, CAIRO_BOILERPLATE_MODE_TEST, &closure); if (surface == NULL) { cairo_test_log (ctx, "Error: Failed to set %s target\n", target->name); ret = CAIRO_TEST_UNTESTED; goto UNWIND_STRINGS; } #if HAVE_MEMFAULT if (ctx->malloc_failure && MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 && cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY) { goto REPEAT; } #endif if (cairo_surface_status (surface)) { MF (MEMFAULT_PRINT_FAULTS ()); cairo_test_log (ctx, "Error: Created an error surface: %s\n", cairo_status_to_string (cairo_surface_status (surface))); ret = CAIRO_TEST_FAILURE; goto UNWIND_STRINGS; } /* Check that we created a surface of the expected type. */ if (cairo_surface_get_type (surface) != target->expected_type) { MF (MEMFAULT_PRINT_FAULTS ()); cairo_test_log (ctx, "Error: Created surface is of type %d (expected %d)\n", cairo_surface_get_type (surface), target->expected_type); ret = CAIRO_TEST_UNTESTED; goto UNWIND_SURFACE; } /* Check that we created a surface of the expected content, * (ignore the artificial CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED value). */ expected_content = cairo_boilerplate_content (target->content); if (cairo_surface_get_content (surface) != expected_content) { MF (MEMFAULT_PRINT_FAULTS ()); cairo_test_log (ctx, "Error: Created surface has content %d (expected %d)\n", cairo_surface_get_content (surface), expected_content); ret = CAIRO_TEST_FAILURE; goto UNWIND_SURFACE; } if (cairo_surface_set_user_data (surface, &cairo_boilerplate_output_basename_key, base_path, NULL)) { #if HAVE_MEMFAULT cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); goto REPEAT; #else ret = CAIRO_TEST_FAILURE; goto UNWIND_SURFACE; #endif } cairo_surface_set_device_offset (surface, dev_offset, dev_offset); cr = cairo_create (surface); if (cairo_set_user_data (cr, &_cairo_test_context_key, (void*) ctx, NULL)) { #if HAVE_MEMFAULT cairo_destroy (cr); cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); goto REPEAT; #else ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; #endif } if (similar) cairo_push_group_with_content (cr, expected_content); /* Clear to transparent (or black) depending on whether the target * surface supports alpha. */ cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_restore (cr); /* Set all components of font_options to avoid backend differences * and reduce number of needed reference images. */ font_options = cairo_font_options_create (); cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON); cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY); cairo_set_font_options (cr, font_options); cairo_font_options_destroy (font_options); cairo_save (cr); alarm (ctx->timeout); status = (ctx->test->draw) (cr, ctx->test->width, ctx->test->height); alarm (0); cairo_restore (cr); if (similar) { cairo_pop_group_to_source (cr); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); } #if HAVE_MEMFAULT MEMFAULT_DISABLE_FAULTS (); /* repeat test after malloc failure injection */ if (ctx->malloc_failure && MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 && (status == CAIRO_TEST_NO_MEMORY || cairo_status (cr) == CAIRO_STATUS_NO_MEMORY || cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY)) { cairo_destroy (cr); cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); cairo_debug_reset_static_data (); #if HAVE_FCFINI FcFini (); #endif if (MEMFAULT_COUNT_LEAKS () > 0) { MEMFAULT_PRINT_FAULTS (); MEMFAULT_PRINT_LEAKS (); } goto REPEAT; } #endif /* Then, check all the different ways it could fail. */ if (status) { cairo_test_log (ctx, "Error: Function under test failed\n"); ret = status; goto UNWIND_CAIRO; } #if HAVE_MEMFAULT if (MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 && MEMFAULT_HAS_FAULTS ()) { VALGRIND_PRINTF ("Unreported memfaults..."); MEMFAULT_PRINT_FAULTS (); } #endif if (target->finish_surface != NULL) { #if HAVE_MEMFAULT /* We need to re-enable faults as most recording-surface processing * is done during cairo_surface_finish(). */ MEMFAULT_CLEAR_FAULTS (); last_fault_count = MEMFAULT_COUNT_FAULTS (); MEMFAULT_ENABLE_FAULTS (); #endif /* also check for infinite loops whilst replaying */ alarm (ctx->timeout); status = target->finish_surface (surface); alarm (0); #if HAVE_MEMFAULT MEMFAULT_DISABLE_FAULTS (); if (ctx->malloc_failure && MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 && status == CAIRO_STATUS_NO_MEMORY) { cairo_destroy (cr); cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); cairo_debug_reset_static_data (); #if HAVE_FCFINI FcFini (); #endif if (MEMFAULT_COUNT_LEAKS () > 0) { MEMFAULT_PRINT_FAULTS (); MEMFAULT_PRINT_LEAKS (); } goto REPEAT; } #endif if (status) { cairo_test_log (ctx, "Error: Failed to finish surface: %s\n", cairo_status_to_string (status)); ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } } /* Skip image check for tests with no image (width,height == 0,0) */ if (ctx->test->width != 0 && ctx->test->height != 0) { cairo_surface_t *ref_image; cairo_surface_t *test_image; cairo_surface_t *diff_image; buffer_diff_result_t result; cairo_status_t diff_status; if (ref_png_path == NULL) { cairo_test_log (ctx, "Error: Cannot find reference image for %s\n", base_name); /* we may be running this test to generate reference images */ _xunlink (ctx, out_png_path); /* be more generous as we may need to use external renderers */ alarm (4 * ctx->timeout); test_image = target->get_image_surface (surface, 0, ctx->test->width, ctx->test->height); alarm (0); diff_status = cairo_surface_write_to_png (test_image, out_png_path); cairo_surface_destroy (test_image); if (diff_status) { if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS) ret = CAIRO_TEST_CRASHED; else ret = CAIRO_TEST_FAILURE; cairo_test_log (ctx, "Error: Failed to write output image: %s\n", cairo_status_to_string (diff_status)); } have_output = TRUE; ret = CAIRO_TEST_XFAILURE; goto UNWIND_CAIRO; } if (target->file_extension != NULL) { /* compare vector surfaces */ char *filenames[] = { ref_png_path, ref_path, new_png_path, new_path, xfail_png_path, xfail_path, base_ref_png_path, base_new_png_path, base_xfail_png_path, }; xasprintf (&test_filename, "%s.out%s", base_path, target->file_extension); xasprintf (&pass_filename, "%s.pass%s", base_path, target->file_extension); xasprintf (&fail_filename, "%s.fail%s", base_path, target->file_extension); if (cairo_test_file_is_older (pass_filename, filenames, ARRAY_SIZE (filenames))) { _xunlink (ctx, pass_filename); } if (cairo_test_file_is_older (fail_filename, filenames, ARRAY_SIZE (filenames))) { _xunlink (ctx, fail_filename); } if (cairo_test_files_equal (out_png_path, ref_path)) { cairo_test_log (ctx, "Vector surface matches reference.\n"); have_output = FALSE; ret = CAIRO_TEST_SUCCESS; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, new_path)) { cairo_test_log (ctx, "Vector surface matches current failure.\n"); have_output = FALSE; ret = CAIRO_TEST_NEW; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, xfail_path)) { cairo_test_log (ctx, "Vector surface matches known failure.\n"); have_output = FALSE; ret = CAIRO_TEST_XFAILURE; goto UNWIND_CAIRO; } if (cairo_test_files_equal (test_filename, pass_filename)) { /* identical output as last known PASS */ cairo_test_log (ctx, "Vector surface matches last pass.\n"); have_output = TRUE; ret = CAIRO_TEST_SUCCESS; goto UNWIND_CAIRO; } if (cairo_test_files_equal (test_filename, fail_filename)) { /* identical output as last known FAIL, fail */ cairo_test_log (ctx, "Vector surface matches last fail.\n"); have_result = TRUE; /* presume these were kept around as well */ have_output = TRUE; ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } } /* be more generous as we may need to use external renderers */ alarm (4 * ctx->timeout); test_image = target->get_image_surface (surface, 0, ctx->test->width, ctx->test->height); alarm (0); if (cairo_surface_status (test_image)) { cairo_test_log (ctx, "Error: Failed to extract image: %s\n", cairo_status_to_string (cairo_surface_status (test_image))); if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS) ret = CAIRO_TEST_CRASHED; else ret = CAIRO_TEST_FAILURE; cairo_surface_destroy (test_image); goto UNWIND_CAIRO; } _xunlink (ctx, out_png_path); diff_status = cairo_surface_write_to_png (test_image, out_png_path); if (diff_status) { cairo_test_log (ctx, "Error: Failed to write output image: %s\n", cairo_status_to_string (diff_status)); cairo_surface_destroy (test_image); ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } have_output = TRUE; /* binary compare png files (no decompression) */ if (target->file_extension == NULL) { char *filenames[] = { ref_png_path, new_png_path, xfail_png_path, base_ref_png_path, base_new_png_path, base_xfail_png_path, }; xasprintf (&test_filename, "%s", out_png_path); xasprintf (&pass_filename, "%s.pass.png", base_path); xasprintf (&fail_filename, "%s.fail.png", base_path); if (cairo_test_file_is_older (pass_filename, filenames, ARRAY_SIZE (filenames))) { _xunlink (ctx, pass_filename); } if (cairo_test_file_is_older (fail_filename, filenames, ARRAY_SIZE (filenames))) { _xunlink (ctx, fail_filename); } if (cairo_test_files_equal (test_filename, pass_filename)) { cairo_test_log (ctx, "PNG file exactly matches last pass.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_SUCCESS; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, ref_png_path)) { cairo_test_log (ctx, "PNG file exactly matches reference image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_SUCCESS; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, new_png_path)) { cairo_test_log (ctx, "PNG file exactly matches current failure image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_NEW; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, xfail_png_path)) { cairo_test_log (ctx, "PNG file exactly matches known failure image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_XFAILURE; goto UNWIND_CAIRO; } if (cairo_test_files_equal (test_filename, fail_filename)) { cairo_test_log (ctx, "PNG file exactly matches last fail.\n"); have_result = TRUE; /* presume these were kept around as well */ cairo_surface_destroy (test_image); ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } } else { if (cairo_test_files_equal (out_png_path, ref_png_path)) { cairo_test_log (ctx, "PNG file exactly matches reference image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_SUCCESS; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, new_png_path)) { cairo_test_log (ctx, "PNG file exactly matches current failure image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_NEW; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, xfail_png_path)) { cairo_test_log (ctx, "PNG file exactly matches known failure image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_XFAILURE; goto UNWIND_CAIRO; } } if (cairo_test_files_equal (out_png_path, base_ref_png_path)) { cairo_test_log (ctx, "PNG file exactly reference image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_SUCCESS; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, base_new_png_path)) { cairo_test_log (ctx, "PNG file exactly current failure image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_NEW; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, base_xfail_png_path)) { cairo_test_log (ctx, "PNG file exactly known failure image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_XFAILURE; goto UNWIND_CAIRO; } /* first compare against the ideal reference */ ref_image = cairo_test_get_reference_image (ctx, base_ref_png_path, target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED); if (cairo_surface_status (ref_image)) { cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n", base_ref_png_path, cairo_status_to_string (cairo_surface_status (ref_image))); cairo_surface_destroy (test_image); ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ctx->test->width, ctx->test->height); cmp_png_path = base_ref_png_path; diff_status = image_diff (ctx, test_image, ref_image, diff_image, &result); _xunlink (ctx, diff_png_path); if (diff_status || image_diff_is_failure (&result, target->error_tolerance)) { /* that failed, so check against the specific backend */ ref_image = cairo_test_get_reference_image (ctx, ref_png_path, target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED); if (cairo_surface_status (ref_image)) { cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n", ref_png_path, cairo_status_to_string (cairo_surface_status (ref_image))); cairo_surface_destroy (test_image); ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } cmp_png_path = ref_png_path; diff_status = image_diff (ctx, test_image, ref_image, diff_image, &result); if (diff_status) { cairo_test_log (ctx, "Error: Failed to compare images: %s\n", cairo_status_to_string (diff_status)); ret = CAIRO_TEST_FAILURE; } else if (image_diff_is_failure (&result, target->error_tolerance)) { ret = CAIRO_TEST_FAILURE; diff_status = cairo_surface_write_to_png (diff_image, diff_png_path); if (diff_status) { cairo_test_log (ctx, "Error: Failed to write differences image: %s\n", cairo_status_to_string (diff_status)); } else { have_result = TRUE; } cairo_test_copy_file (test_filename, fail_filename); } else { /* success */ cairo_test_copy_file (test_filename, pass_filename); } } else { /* success */ cairo_test_copy_file (test_filename, pass_filename); } /* If failed, compare against the current image output, * and attempt to detect systematic failures. */ if (ret == CAIRO_TEST_FAILURE) { char *image_out_path; image_out_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, "image", "image", format, CAIRO_TEST_OUT_SUFFIX, CAIRO_TEST_PNG_EXTENSION); if (image_out_path != NULL) { if (cairo_test_files_equal (out_png_path, image_out_path)) { ret = CAIRO_TEST_XFAILURE; } else { ref_image = cairo_image_surface_create_from_png (image_out_path); if (cairo_surface_status (ref_image) == CAIRO_STATUS_SUCCESS) { diff_status = image_diff (ctx, test_image, ref_image, diff_image, &result); if (diff_status == CAIRO_STATUS_SUCCESS && !image_diff_is_failure (&result, target->error_tolerance)) { ret = CAIRO_TEST_XFAILURE; } cairo_surface_destroy (ref_image); } } free (image_out_path); } } cairo_surface_destroy (test_image); cairo_surface_destroy (diff_image); } if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) { cairo_test_log (ctx, "Error: Function under test left cairo status in an error state: %s\n", cairo_status_to_string (cairo_status (cr))); ret = CAIRO_TEST_ERROR; goto UNWIND_CAIRO; } UNWIND_CAIRO: free (test_filename); free (fail_filename); free (pass_filename); test_filename = fail_filename = pass_filename = NULL; #if HAVE_MEMFAULT if (ret == CAIRO_TEST_FAILURE) MEMFAULT_PRINT_FAULTS (); #endif cairo_destroy (cr); UNWIND_SURFACE: cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); #if HAVE_MEMFAULT cairo_debug_reset_static_data (); #if HAVE_FCFINI FcFini (); #endif if (MEMFAULT_COUNT_LEAKS () > 0) { if (ret != CAIRO_TEST_FAILURE) MEMFAULT_PRINT_FAULTS (); MEMFAULT_PRINT_LEAKS (); } if (ret == CAIRO_TEST_SUCCESS && --malloc_failure_iterations > 0) goto REPEAT; #endif if (have_output) cairo_test_log (ctx, "OUTPUT: %s\n", out_png_path); if (have_result) { if (cmp_png_path == NULL) { /* XXX presume we matched the normal ref last time */ cmp_png_path = ref_png_path; } cairo_test_log (ctx, "REFERENCE: %s\nDIFFERENCE: %s\n", cmp_png_path, diff_png_path); } UNWIND_STRINGS: free (out_png_path); free (ref_png_path); free (base_ref_png_path); free (ref_path); free (new_png_path); free (base_new_png_path); free (new_path); free (xfail_png_path); free (base_xfail_png_path); free (xfail_path); free (diff_png_path); free (base_path); free (base_name); return ret; }
static cairo_test_status_t cairo_test_for_target (cairo_test_t *test, cairo_boilerplate_target_t *target, int dev_offset) { cairo_test_status_t status; cairo_surface_t *surface = NULL; cairo_t *cr; char *png_name, *ref_name, *diff_name, *offset_str; cairo_test_status_t ret = CAIRO_TEST_SUCCESS; cairo_content_t expected_content; cairo_font_options_t *font_options; const char *format; /* Get the strings ready that we'll need. */ format = cairo_boilerplate_content_name (target->content); if (dev_offset) xasprintf (&offset_str, "-%d", dev_offset); else offset_str = strdup(""); xasprintf (&png_name, "%s-%s-%s%s%s", test->name, target->name, format, offset_str, CAIRO_TEST_PNG_SUFFIX); ref_name = cairo_ref_name_for_test_target_format (test->name, target->name, format); xasprintf (&diff_name, "%s-%s-%s%s%s", test->name, target->name, format, offset_str, CAIRO_TEST_DIFF_SUFFIX); if (target->is_vector) { int i; for (i = 0; vector_ignored_tests[i] != NULL; i++) if (strcmp (test->name, vector_ignored_tests[i]) == 0) { cairo_test_log ("Error: Skipping for vector target %s\n", target->name); ret = CAIRO_TEST_UNTESTED; goto UNWIND_STRINGS; } } if (ret == CAIRO_TEST_SUCCESS) { /* Run the actual drawing code. */ if (test->width && test->height) { test->width += dev_offset; test->height += dev_offset; } surface = (target->create_surface) (test->name, target->content, test->width, test->height, CAIRO_BOILERPLATE_MODE_TEST, &target->closure); if (test->width && test->height) { test->width -= dev_offset; test->height -= dev_offset;; } } if (surface == NULL) { cairo_test_log ("Error: Failed to set %s target\n", target->name); ret = CAIRO_TEST_UNTESTED; goto UNWIND_STRINGS; } /* Check that we created a surface of the expected type. */ if (cairo_surface_get_type (surface) != target->expected_type) { cairo_test_log ("Error: Created surface is of type %d (expected %d)\n", cairo_surface_get_type (surface), target->expected_type); ret = CAIRO_TEST_FAILURE; goto UNWIND_SURFACE; } /* Check that we created a surface of the expected content, * (ignore the articifical * CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED value). */ expected_content = target->content; if (expected_content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED) expected_content = CAIRO_CONTENT_COLOR_ALPHA; if (cairo_surface_get_content (surface) != expected_content) { cairo_test_log ("Error: Created surface has content %d (expected %d)\n", cairo_surface_get_content (surface), expected_content); ret = CAIRO_TEST_FAILURE; goto UNWIND_SURFACE; } cairo_surface_set_device_offset (surface, dev_offset, dev_offset); cr = cairo_create (surface); /* Clear to transparent (or black) depending on whether the target * surface supports alpha. */ cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_restore (cr); /* Set all components of font_options to avoid backend differences * and reduce number of needed reference images. */ font_options = cairo_font_options_create (); cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON); cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY); cairo_set_font_options (cr, font_options); cairo_font_options_destroy (font_options); status = (test->draw) (cr, test->width, test->height); /* Then, check all the different ways it could fail. */ if (status) { cairo_test_log ("Error: Function under test failed\n"); ret = status; goto UNWIND_CAIRO; } if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) { cairo_test_log ("Error: Function under test left cairo status in an error state: %s\n", cairo_status_to_string (cairo_status (cr))); ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } /* Skip image check for tests with no image (width,height == 0,0) */ if (test->width != 0 && test->height != 0) { buffer_diff_result_t result; cairo_status_t diff_status; xunlink (png_name); (target->write_to_png) (surface, png_name); if (!ref_name) { cairo_test_log ("Error: Cannot find reference image for %s/%s-%s-%s%s\n",srcdir, test->name, target->name, format, CAIRO_TEST_REF_SUFFIX); ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } cairo_test_log ("Comparing result against reference image: %s\n", ref_name); if (target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED) { diff_status= image_diff_flattened (png_name, ref_name, diff_name, dev_offset, dev_offset, 0, 0, &result); } else { diff_status = image_diff (png_name, ref_name, diff_name, dev_offset, dev_offset, 0, 0, &result); } if (diff_status) { cairo_test_log ("Error: Failed to compare images: %s\n", cairo_status_to_string (diff_status)); ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } if (result.pixels_changed && result.max_diff > target->error_tolerance) { ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } } UNWIND_CAIRO: cairo_destroy (cr); UNWIND_SURFACE: cairo_surface_destroy (surface); cairo_debug_reset_static_data (); if (target->cleanup) target->cleanup (target->closure); UNWIND_STRINGS: if (png_name) free (png_name); if (ref_name) free (ref_name); if (diff_name) free (diff_name); if (offset_str) free (offset_str); return ret; }
bool GraphicsContext::isAcceleratedContext() const { return cairo_surface_get_type(cairo_get_target(platformContext()->cr())) == CAIRO_SURFACE_TYPE_GL; }
static int surface_get_gdk_pixbuf (lua_State *L) { cairo_surface_t **surface; cairo_format_t format; int width, height, stridei, strideo; unsigned char *buffer, *rowpo, *po; const char *rowpi, *pi; size_t buffer_len; int x, y; int has_alpha; surface = luaL_checkudata(L, 1, OOCAIRO_MT_NAME_SURFACE); if (cairo_surface_get_type(*surface) != CAIRO_SURFACE_TYPE_IMAGE) return luaL_error(L, "pixbufs can only be made from image surfaces"); format = cairo_image_surface_get_format(*surface); if (format != CAIRO_FORMAT_ARGB32 && format != CAIRO_FORMAT_RGB24) return luaL_error(L, "can't make pixbuf from this image format"); has_alpha = (format == CAIRO_FORMAT_ARGB32); width = cairo_image_surface_get_width(*surface); height = cairo_image_surface_get_height(*surface); stridei = cairo_image_surface_get_stride(*surface); if (has_alpha) strideo = stridei; /* might as well keep Cairo stride */ else strideo = ((3 * width) + 7) & ~7; /* align to 8 bytes */ buffer_len = strideo * height; buffer = malloc(buffer_len); assert(buffer); rowpi = (const char *) cairo_image_surface_get_data(*surface); rowpo = buffer; /* Copy pixels from Cairo's pixel format to GdkPixbuf's, which is slightly * different. */ if (IS_BIG_ENDIAN) { for (y = 0; y < height; ++y) { pi = rowpi; po = rowpo; for (x = 0; x < width; ++x) { *po++ = pi[1]; *po++ = pi[2]; *po++ = pi[3]; if (has_alpha) *po++ = pi[0]; pi += 4; } rowpi += stridei; rowpo += strideo; } } else { for (y = 0; y < height; ++y) { pi = rowpi; po = rowpo; for (x = 0; x < width; ++x) { *po++ = pi[2]; *po++ = pi[1]; *po++ = pi[0]; if (has_alpha) *po++ = pi[3]; pi += 4; } rowpi += stridei; rowpo += strideo; } } /* The buffer needs to be copied in to a Lua string so that it can * be passed to Lua-Gnome. */ lua_pushlstring(L, (const char *) buffer, buffer_len); free(buffer); /* Use Lua-Gnome function to construct the GdkPixbuf object, so that we * don't have to link directly with GDK, and so that the resulting object * can be used with the rest of Lua-Gnome. */ get_gtk_module_function(L, "gdk_pixbuf_new_from_data"); lua_pushvalue(L, -2); get_gtk_module_function(L, "GDK_COLORSPACE_RGB"); lua_pushboolean(L, has_alpha); lua_pushnumber(L, 8); lua_pushnumber(L, width); lua_pushnumber(L, height); lua_pushnumber(L, strideo); lua_pushnil(L); lua_pushnil(L); lua_call(L, 9, 1); /* Keep a reference to the Lua string used to store the data, since * it needs to be kept around for as long as the object is in use. */ lua_pushvalue(L, -2); lua_setfield(L, -2, "_pixbuf_buffer_string"); return 1; }
already_AddRefed<gfxASurface> gfxASurface::Wrap (cairo_surface_t *csurf) { gfxASurface *result; /* Do we already have a wrapper for this surface? */ result = GetSurfaceWrapper(csurf); if (result) { // fprintf(stderr, "Existing wrapper for %p -> %p\n", csurf, result); NS_ADDREF(result); return result; } /* No wrapper; figure out the surface type and create it */ cairo_surface_type_t stype = cairo_surface_get_type(csurf); if (stype == CAIRO_SURFACE_TYPE_IMAGE) { result = new gfxImageSurface(csurf); } #ifdef CAIRO_HAS_WIN32_SURFACE else if (stype == CAIRO_SURFACE_TYPE_WIN32 || stype == CAIRO_SURFACE_TYPE_WIN32_PRINTING) { result = new gfxWindowsSurface(csurf); } #endif #ifdef CAIRO_HAS_D2D_SURFACE else if (stype == CAIRO_SURFACE_TYPE_D2D) { result = new gfxD2DSurface(csurf); } #endif #ifdef MOZ_X11 else if (stype == CAIRO_SURFACE_TYPE_XLIB) { result = new gfxXlibSurface(csurf); } #endif #ifdef CAIRO_HAS_QUARTZ_SURFACE else if (stype == CAIRO_SURFACE_TYPE_QUARTZ) { result = new gfxQuartzSurface(csurf); } else if (stype == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) { result = new gfxQuartzImageSurface(csurf); } #endif #ifdef MOZ_DFB else if (stype == CAIRO_SURFACE_TYPE_DIRECTFB) { result = new gfxDirectFBSurface(csurf); } #endif #ifdef CAIRO_HAS_QT_SURFACE else if (stype == CAIRO_SURFACE_TYPE_QT) { result = new gfxQPainterSurface(csurf); } #endif #ifdef CAIRO_HAS_DDRAW_SURFACE else if (stype == CAIRO_SURFACE_TYPE_DDRAW) { result = new gfxDDrawSurface(csurf); } #endif else { result = new gfxUnknownSurface(csurf); } // fprintf(stderr, "New wrapper for %p -> %p\n", csurf, result); NS_ADDREF(result); return result; }
static int surface_get_type (lua_State *L) { cairo_surface_t **obj = luaL_checkudata(L, 1, OOCAIRO_MT_NAME_SURFACE); return surface_type_to_lua(L, cairo_surface_get_type(*obj)); }
void joy_gfx3d_screen_set_cursor(JoyScreen *self, JoyCursor *cursor) { g_return_if_fail(JOY_IS_GFX3D_SCREEN(self)); g_return_if_fail(JOY_IS_CURSOR(cursor)); struct Private *priv = GET_PRIVATE(self); cairo_surface_t *surface = joy_cursor_get_image(cursor); if (!surface) { return; } #if CAIRO_HAS_GFX3D_SURFACE cairo_surface_type_t type = cairo_surface_get_type(surface); if (CAIRO_SURFACE_TYPE_GFX3D != type) { if (CAIRO_SURFACE_TYPE_IMAGE != type) { return; } gint width = cairo_image_surface_get_width(surface); gint height = cairo_image_surface_get_height(surface); cairo_surface_t *gfx3d_surface = joy_screen_cairo_surface_create(self, width, height); if (G_UNLIKELY(!gfx3d_surface)) { return; } cairo_t *cr = cairo_create(gfx3d_surface); cairo_set_source_surface(cr, surface, 0., 0.); cairo_paint(cr); cairo_destroy(cr); joy_cursor_set_image(cursor, gfx3d_surface); surface = gfx3d_surface; } GFX3D_Image image = cairo_gfx3d_surface_get_image(surface); #else // CAIRO_HAS_GFX3D_SURFACE struct Data *data = cairo_surface_get_user_data(surface, &key); if (!data) { cairo_surface_type_t type = cairo_surface_get_type(surface); if (CAIRO_SURFACE_TYPE_IMAGE != type) { return; } gint width = cairo_image_surface_get_width(surface); gint height = cairo_image_surface_get_height(surface); cairo_surface_t *gfx3d_surface = joy_screen_cairo_surface_create(self, width, height); if (G_UNLIKELY(!gfx3d_surface)) { return; } cairo_t *cr = cairo_create(gfx3d_surface); cairo_set_source_surface(cr, surface, 0., 0.); cairo_paint(cr); cairo_destroy(cr); joy_cursor_set_image(cursor, gfx3d_surface); data = cairo_surface_get_user_data(gfx3d_surface, &key); if (G_UNLIKELY(!data)) { return; } } GFX3D_Image image = data->image; #endif // CAIRO_HAS_GFX3D_SURFACE GFX3D_Rect rect; GFX3D_Image_GetRect(image, &rect); if (!priv->cursor) { gint width = joy_screen_get_width(self); gint height = joy_screen_get_height(self); gint n = joy_screen_get_id(self); priv->cursor = GFX3D_Cursor_Create_Ext(width, height, image, &rect, n); if (!priv->cursor) { return; } } else { GFX3D_Cursor_Image_Swap(priv->cursor, image, &rect); } priv->x_hot = joy_cursor_get_hotspot_x(cursor); priv->y_hot = joy_cursor_get_hotspot_y(cursor); priv->moved = TRUE; }
/** * Try the direct path. * @return True if we took the direct path */ bool gfxXlibNativeRenderer::DrawDirect(gfxContext *ctx, nsIntSize size, PRUint32 flags, Screen *screen, Visual *visual) { cairo_t *cr = ctx->GetCairo(); /* Check that the target surface is an xlib surface. */ cairo_surface_t *target = cairo_get_group_target (cr); if (cairo_surface_get_type (target) != CAIRO_SURFACE_TYPE_XLIB) { NATIVE_DRAWING_NOTE("FALLBACK: non-X surface"); return false; } cairo_matrix_t matrix; cairo_get_matrix (cr, &matrix); double device_offset_x, device_offset_y; cairo_surface_get_device_offset (target, &device_offset_x, &device_offset_y); /* Draw() checked that the matrix contained only a very-close-to-integer translation. Here (and in several other places and thebes) device offsets are assumed to be integer. */ NS_ASSERTION(PRInt32(device_offset_x) == device_offset_x && PRInt32(device_offset_y) == device_offset_y, "Expected integer device offsets"); nsIntPoint offset(NS_lroundf(matrix.x0 + device_offset_x), NS_lroundf(matrix.y0 + device_offset_y)); int max_rectangles = 0; if (flags & DRAW_SUPPORTS_CLIP_RECT) { max_rectangles = 1; } if (flags & DRAW_SUPPORTS_CLIP_LIST) { max_rectangles = MAX_STATIC_CLIP_RECTANGLES; } /* The client won't draw outside the surface so consider this when analysing clip rectangles. */ nsIntRect bounds(offset, size); bounds.IntersectRect(bounds, nsIntRect(0, 0, cairo_xlib_surface_get_width(target), cairo_xlib_surface_get_height(target))); bool needs_clip = true; nsIntRect rectangles[MAX_STATIC_CLIP_RECTANGLES]; int rect_count = 0; /* Check that the clip is rectangular and aligned on unit boundaries. */ /* Temporarily set the matrix for _get_rectangular_clip. It's basically the identity matrix, but we must adjust for the fact that our offset-rect is in device coordinates. */ cairo_identity_matrix (cr); cairo_translate (cr, -device_offset_x, -device_offset_y); bool have_rectangular_clip = _get_rectangular_clip (cr, bounds, &needs_clip, rectangles, max_rectangles, &rect_count); cairo_set_matrix (cr, &matrix); if (!have_rectangular_clip) return false; /* Stop now if everything is clipped out */ if (needs_clip && rect_count == 0) return true; /* Check that the screen is supported. Visuals belong to screens, so, if alternate visuals are not supported, then alternate screens cannot be supported. */ bool supports_alternate_visual = (flags & DRAW_SUPPORTS_ALTERNATE_VISUAL) != 0; bool supports_alternate_screen = supports_alternate_visual && (flags & DRAW_SUPPORTS_ALTERNATE_SCREEN); if (!supports_alternate_screen && cairo_xlib_surface_get_screen (target) != screen) { NATIVE_DRAWING_NOTE("FALLBACK: non-default screen"); return false; } /* Check that there is a visual */ Visual *target_visual = cairo_xlib_surface_get_visual (target); if (!target_visual) { NATIVE_DRAWING_NOTE("FALLBACK: no Visual for surface"); return false; } /* Check that the visual is supported */ if (!supports_alternate_visual && target_visual != visual) { // Only the format of the visual is important (not the GLX properties) // for Xlib or XRender drawing. XRenderPictFormat *target_format = cairo_xlib_surface_get_xrender_format (target); if (!target_format || (target_format != XRenderFindVisualFormat (DisplayOfScreen(screen), visual))) { NATIVE_DRAWING_NOTE("FALLBACK: unsupported Visual"); return false; } } /* we're good to go! */ NATIVE_DRAWING_NOTE("TAKING FAST PATH\n"); cairo_surface_flush (target); nsRefPtr<gfxASurface> surface = gfxASurface::Wrap(target); nsresult rv = DrawWithXlib(static_cast<gfxXlibSurface*>(surface.get()), offset, rectangles, needs_clip ? rect_count : 0); if (NS_SUCCEEDED(rv)) { cairo_surface_mark_dirty (target); return true; } return false; }
bool GraphicsContext3D::ImageExtractor::extractImage(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) { if (!m_image) return false; // We need this to stay in scope because the native image is just a shallow copy of the data. m_decoder = new ImageSource(premultiplyAlpha ? ImageSource::AlphaPremultiplied : ImageSource::AlphaNotPremultiplied, ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); if (!m_decoder) return false; ImageSource& decoder = *m_decoder; m_alphaOp = AlphaDoNothing; if (m_image->data()) { decoder.setData(m_image->data(), true); if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0)) return false; m_imageSurface = decoder.createFrameAtIndex(0); } else { m_imageSurface = m_image->nativeImageForCurrentFrame(); // 1. For texImage2D with HTMLVideoElment input, assume no PremultiplyAlpha had been applied and the alpha value is 0xFF for each pixel, // which is true at present and may be changed in the future and needs adjustment accordingly. // 2. For texImage2D with HTMLCanvasElement input in which Alpha is already Premultiplied in this port, // do AlphaDoUnmultiply if UNPACK_PREMULTIPLY_ALPHA_WEBGL is set to false. if (!premultiplyAlpha && m_imageHtmlDomSource != HtmlDomVideo) m_alphaOp = AlphaDoUnmultiply; // if m_imageSurface is not an image, extract a copy of the surface if (m_imageSurface && cairo_surface_get_type(m_imageSurface.get()) != CAIRO_SURFACE_TYPE_IMAGE) { RefPtr<cairo_surface_t> tmpSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, m_imageWidth, m_imageHeight)); copyRectFromOneSurfaceToAnother(m_imageSurface.get(), tmpSurface.get(), IntSize(), IntRect(0, 0, m_imageWidth, m_imageHeight), IntSize(), CAIRO_OPERATOR_SOURCE); m_imageSurface = tmpSurface.release(); } } if (!m_imageSurface) return false; ASSERT(cairo_surface_get_type(m_imageSurface.get()) == CAIRO_SURFACE_TYPE_IMAGE); IntSize imageSize = cairoSurfaceSize(m_imageSurface.get()); m_imageWidth = imageSize.width(); m_imageHeight = imageSize.height(); if (!m_imageWidth || !m_imageHeight) return false; if (cairo_image_surface_get_format(m_imageSurface.get()) != CAIRO_FORMAT_ARGB32) return false; unsigned int srcUnpackAlignment = 1; size_t bytesPerRow = cairo_image_surface_get_stride(m_imageSurface.get()); size_t bitsPerPixel = 32; unsigned padding = bytesPerRow - bitsPerPixel / 8 * m_imageWidth; if (padding) { srcUnpackAlignment = padding + 1; while (bytesPerRow % srcUnpackAlignment) ++srcUnpackAlignment; } m_imagePixelData = cairo_image_surface_get_data(m_imageSurface.get()); m_imageSourceFormat = DataFormatBGRA8; m_imageSourceUnpackAlignment = srcUnpackAlignment; return true; }
static already_AddRefed<gfxXlibSurface> CreateTempXlibSurface (gfxASurface *destination, nsIntSize size, bool canDrawOverBackground, PRUint32 flags, Screen *screen, Visual *visual, DrawingMethod *method) { bool drawIsOpaque = (flags & gfxXlibNativeRenderer::DRAW_IS_OPAQUE) != 0; bool supportsAlternateVisual = (flags & gfxXlibNativeRenderer::DRAW_SUPPORTS_ALTERNATE_VISUAL) != 0; bool supportsAlternateScreen = supportsAlternateVisual && (flags & gfxXlibNativeRenderer::DRAW_SUPPORTS_ALTERNATE_SCREEN); cairo_surface_t *target = destination->CairoSurface(); cairo_surface_type_t target_type = cairo_surface_get_type (target); cairo_content_t target_content = cairo_surface_get_content (target); Screen *target_screen = target_type == CAIRO_SURFACE_TYPE_XLIB ? cairo_xlib_surface_get_screen (target) : screen; // When the background has an alpha channel, we need to draw with an alpha // channel anyway, so there is no need to copy the background. If // doCopyBackground is set here, we'll also need to check below that the // background can copied without any loss in format conversions. bool doCopyBackground = !drawIsOpaque && canDrawOverBackground && target_content == CAIRO_CONTENT_COLOR; if (supportsAlternateScreen && screen != target_screen && drawIsOpaque) { // Prefer a visual on the target screen. // (If !drawIsOpaque, we'll need doCopyBackground or an alpha channel.) visual = DefaultVisualOfScreen(target_screen); screen = target_screen; } else if (doCopyBackground || (supportsAlternateVisual && drawIsOpaque)) { // Analyse the pixel formats either to check whether we can // doCopyBackground or to see if we can find a better visual for // opaque drawing. Visual *target_visual = NULL; XRenderPictFormat *target_format = NULL; switch (target_type) { case CAIRO_SURFACE_TYPE_XLIB: target_visual = cairo_xlib_surface_get_visual (target); target_format = cairo_xlib_surface_get_xrender_format (target); break; case CAIRO_SURFACE_TYPE_IMAGE: { gfxASurface::gfxImageFormat imageFormat = static_cast<gfxImageSurface*>(destination)->Format(); target_visual = gfxXlibSurface::FindVisual(screen, imageFormat); Display *dpy = DisplayOfScreen(screen); if (target_visual) { target_format = XRenderFindVisualFormat(dpy, target_visual); } else { target_format = gfxXlibSurface::FindRenderFormat(dpy, imageFormat); } break; } default: break; } if (supportsAlternateVisual && (supportsAlternateScreen || screen == target_screen)) { if (target_visual) { visual = target_visual; screen = target_screen; } } // Could try harder to match formats across screens for background // copying when !supportsAlternateScreen, if we cared. Preferably // we'll find a visual below with an alpha channel anyway; if so, the // background won't need to be copied. if (doCopyBackground && visual != target_visual && !FormatConversionIsExact(screen, visual, target_format)) { doCopyBackground = false; } } if (supportsAlternateVisual && !drawIsOpaque && (screen != target_screen || !(doCopyBackground || VisualHasAlpha(screen, visual)))) { // Try to find a visual with an alpha channel. Screen *visualScreen = supportsAlternateScreen ? target_screen : screen; Visual *argbVisual = gfxXlibSurface::FindVisual(visualScreen, gfxASurface::ImageFormatARGB32); if (argbVisual) { visual = argbVisual; screen = visualScreen; } else if (!doCopyBackground && gfxXlibSurface::DepthOfVisual(screen, visual) != 24) { // Will need to do alpha extraction; prefer a 24-bit visual. // No advantage in using the target screen. Visual *rgb24Visual = gfxXlibSurface::FindVisual(screen, gfxASurface::ImageFormatRGB24); if (rgb24Visual) { visual = rgb24Visual; } } } Drawable drawable = (screen == target_screen && target_type == CAIRO_SURFACE_TYPE_XLIB) ? cairo_xlib_surface_get_drawable (target) : RootWindowOfScreen(screen); nsRefPtr<gfxXlibSurface> surface = gfxXlibSurface::Create(screen, visual, gfxIntSize(size.width, size.height), drawable); if (drawIsOpaque || surface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) { NATIVE_DRAWING_NOTE(drawIsOpaque ? ", SIMPLE OPAQUE\n" : ", SIMPLE WITH ALPHA"); *method = eSimple; } else if (doCopyBackground) { NATIVE_DRAWING_NOTE(", COPY BACKGROUND\n"); *method = eCopyBackground; } else { NATIVE_DRAWING_NOTE(", SLOW ALPHA EXTRACTION\n"); *method = eAlphaExtraction; } return surface.forget(); }
/* This function originally from Jean-Edouard Lachand-Robert, and * available at www.codeguru.com. Simplified for our needs, not sure * how much of the original code left any longer. Now handles just * one-bit deep bitmaps (in Window parlance, ie those that GDK calls * bitmaps (and not pixmaps), with zero pixels being transparent. * * Changed again here from the GDK version to use an 8-bit surface instead * of a 1-bit bitmap. */ static cairo_region_t * _gdk_cairo_region_create_from_surface (cairo_surface_t *surface) { cairo_region_t *region; GdkRectangle extents, rect; cairo_surface_t *image; cairo_t *cr; gint x, y, stride; guchar *data; _gdk_cairo_surface_extents (surface, &extents); if (cairo_surface_get_content (surface) == CAIRO_CONTENT_COLOR) return cairo_region_create_rectangle (&extents); if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_IMAGE || cairo_image_surface_get_format (surface) != CAIRO_FORMAT_A8) { /* coerce to an A8 image */ image = cairo_image_surface_create (CAIRO_FORMAT_A8, extents.width, extents.height); cr = cairo_create (image); cairo_set_source_surface (cr, surface, -extents.x, -extents.y); cairo_paint (cr); cairo_destroy (cr); } else image = cairo_surface_reference (surface); data = cairo_image_surface_get_data (image); stride = cairo_image_surface_get_stride (image); region = cairo_region_create (); for (y = 0; y < extents.height; y++) { for (x = 0; x < extents.width; x++) { /* Search for a continuous range of "non transparent pixels"*/ gint x0 = x; while (x < extents.width) { guint8 alpha = data[x]; if (alpha < 24) /* This pixel is "transparent"*/ break; x++; } if (x > x0) { /* Add the pixels (x0, y) to (x, y+1) as a new rectangle * in the region */ rect.x = x0; rect.width = x - x0; rect.y = y; rect.height = 1; cairo_region_union_rectangle (region, &rect); } } data += stride; } cairo_surface_destroy (image); cairo_region_translate (region, extents.x, extents.y); return region; }