IoObject *IoCairoSurface_getContent(IoCairoSurface *self, IoObject *locals, IoMessage *m) { return IONUMBER(cairo_surface_get_content(SURFACE(self))); }
static int surface_get_content (lua_State *L) { cairo_surface_t **obj = luaL_checkudata(L, 1, OOCAIRO_MT_NAME_SURFACE); return content_to_lua(L, cairo_surface_get_content(*obj)); }
/* 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; }
bool nativeImageHasAlpha(const NativeImagePtr& image) { return !image || cairo_surface_get_content(image.get()) != CAIRO_CONTENT_COLOR; }
static void _gtk_pixel_cache_create_surface_if_needed (GtkPixelCache *cache, GdkWindow *window, cairo_rectangle_int_t *view_rect, cairo_rectangle_int_t *canvas_rect) { cairo_rectangle_int_t rect; int surface_w, surface_h; cairo_content_t content; #ifdef G_ENABLE_DEBUG if (GTK_DISPLAY_DEBUG_CHECK (gdk_window_get_display (window), NO_PIXEL_CACHE)) return; #endif content = cache->content; if (!content) { if (cache->is_opaque) content = CAIRO_CONTENT_COLOR; else content = CAIRO_CONTENT_COLOR_ALPHA; } surface_w = view_rect->width; if (canvas_rect->width > surface_w) surface_w = MIN (surface_w + cache->extra_width, canvas_rect->width); surface_h = view_rect->height; if (canvas_rect->height > surface_h) surface_h = MIN (surface_h + cache->extra_height, canvas_rect->height); /* If current surface can't fit view_rect or is too large, kill it */ if (cache->surface != NULL && (cairo_surface_get_content (cache->surface) != content || cache->surface_w < MAX(view_rect->width, surface_w * ALLOW_SMALLER_SIZE_FACTOR) || cache->surface_w > surface_w * ALLOW_LARGER_SIZE_FACTOR || cache->surface_h < MAX(view_rect->height, surface_h * ALLOW_SMALLER_SIZE_FACTOR) || cache->surface_h > surface_h * ALLOW_LARGER_SIZE_FACTOR || cache->surface_scale != gdk_window_get_scale_factor (window))) { cairo_surface_destroy (cache->surface); cache->surface = NULL; if (cache->surface_dirty) cairo_region_destroy (cache->surface_dirty); cache->surface_dirty = NULL; } /* Don't allocate a surface if view >= canvas, as we won't * be scrolling then anyway, unless the widget requested it. */ if (cache->surface == NULL && (cache->always_cache || (view_rect->width < canvas_rect->width || view_rect->height < canvas_rect->height))) { cache->surface_x = -canvas_rect->x; cache->surface_y = -canvas_rect->y; cache->surface_w = surface_w; cache->surface_h = surface_h; cache->surface_scale = gdk_window_get_scale_factor (window); cache->surface = gdk_window_create_similar_surface (window, content, surface_w, surface_h); rect.x = 0; rect.y = 0; rect.width = surface_w; rect.height = surface_h; cache->surface_dirty = cairo_region_create_rectangle (&rect); } }
static void _gtk_pixel_cache_create_surface_if_needed (GtkPixelCache *cache, GdkWindow *window, cairo_rectangle_int_t *view_rect, cairo_rectangle_int_t *canvas_rect) { cairo_rectangle_int_t rect; int surface_w, surface_h; cairo_content_t content; cairo_pattern_t *bg; double red, green, blue, alpha; content = CAIRO_CONTENT_COLOR_ALPHA; bg = gdk_window_get_background_pattern (window); if (bg != NULL && cairo_pattern_get_type (bg) == CAIRO_PATTERN_TYPE_SOLID && cairo_pattern_get_rgba (bg, &red, &green, &blue, &alpha) == CAIRO_STATUS_SUCCESS && alpha == 1.0) content = CAIRO_CONTENT_COLOR; surface_w = view_rect->width; if (canvas_rect->width > surface_w) surface_w = MIN (surface_w + EXTRA_SIZE, canvas_rect->width); surface_h = view_rect->height; if (canvas_rect->height > surface_h) surface_h = MIN (surface_h + EXTRA_SIZE, canvas_rect->height); /* If current surface can't fit view_rect or is too large, kill it */ if (cache->surface != NULL && (cairo_surface_get_content (cache->surface) != content || cache->surface_w < view_rect->width || cache->surface_w > surface_w + ALLOW_LARGER_SIZE || cache->surface_h < view_rect->height || cache->surface_h > surface_h + ALLOW_LARGER_SIZE || cache->surface_scale != gdk_window_get_scale_factor (window))) { cairo_surface_destroy (cache->surface); cache->surface = NULL; if (cache->surface_dirty) cairo_region_destroy (cache->surface_dirty); cache->surface_dirty = NULL; } /* Don't allocate a surface if view >= canvas, as we won't be scrolling then anyway */ if (cache->surface == NULL && (view_rect->width < canvas_rect->width || view_rect->height < canvas_rect->height)) { cache->surface_x = -canvas_rect->x; cache->surface_y = -canvas_rect->y; cache->surface_w = surface_w; cache->surface_h = surface_h; cache->surface_scale = gdk_window_get_scale_factor (window); cache->surface = gdk_window_create_similar_surface (window, content, surface_w, surface_h); rect.x = 0; rect.y = 0; rect.width = surface_w; rect.height = surface_h; cache->surface_dirty = cairo_region_create_rectangle (&rect); } }
static cairo_int_status_t _cairo_user_scaled_glyph_init (void *abstract_font, cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_glyph_info_t info) { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_user_scaled_font_t *scaled_font = abstract_font; cairo_surface_t *meta_surface = scaled_glyph->meta_surface; if (!scaled_glyph->meta_surface) { cairo_user_font_face_t *face = (cairo_user_font_face_t *) scaled_font->base.font_face; cairo_text_extents_t extents = scaled_font->default_glyph_extents; cairo_t *cr; cr = _cairo_user_scaled_font_create_meta_context (scaled_font); if (face->scaled_font_methods.render_glyph) status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font, _cairo_scaled_glyph_index(scaled_glyph), cr, &extents); else status = CAIRO_STATUS_USER_FONT_ERROR; if (status == CAIRO_STATUS_SUCCESS) status = cairo_status (cr); meta_surface = cairo_surface_reference (cairo_get_target (cr)); cairo_destroy (cr); if (status) { cairo_surface_destroy (meta_surface); return status; } _cairo_scaled_glyph_set_meta_surface (scaled_glyph, &scaled_font->base, meta_surface); /* set metrics */ if (extents.width == 0.) { /* Compute extents.x/y/width/height from meta_surface, in font space */ cairo_box_t bbox; double x1, y1, x2, y2; double x_scale, y_scale; cairo_surface_t *null_surface; cairo_surface_t *analysis_surface; null_surface = _cairo_null_surface_create (cairo_surface_get_content (meta_surface)); analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1); cairo_surface_destroy (null_surface); _cairo_analysis_surface_set_ctm (analysis_surface, &scaled_font->extent_scale); status = _cairo_meta_surface_replay (meta_surface, analysis_surface); _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox); cairo_surface_destroy (analysis_surface); if (status) return status; _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2); x_scale = scaled_font->extent_x_scale; y_scale = scaled_font->extent_y_scale; extents.x_bearing = x1 * x_scale; extents.y_bearing = y1 * y_scale; extents.width = (x2 - x1) * x_scale; extents.height = (y2 - y1) * y_scale; } if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) { extents.x_advance = _cairo_lround (extents.x_advance / scaled_font->snap_x_scale) * scaled_font->snap_x_scale; extents.y_advance = _cairo_lround (extents.y_advance / scaled_font->snap_y_scale) * scaled_font->snap_y_scale; } _cairo_scaled_glyph_set_metrics (scaled_glyph, &scaled_font->base, &extents); } if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) { cairo_surface_t *surface; cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_format_t format; int width, height; /* TODO * extend the glyph cache to support argb glyphs. * need to figure out the semantics and interaction with subpixel * rendering first. */ width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); switch (scaled_font->base.options.antialias) { default: case CAIRO_ANTIALIAS_DEFAULT: case CAIRO_ANTIALIAS_GRAY: format = CAIRO_FORMAT_A8; break; case CAIRO_ANTIALIAS_NONE: format = CAIRO_FORMAT_A1; break; case CAIRO_ANTIALIAS_SUBPIXEL: format = CAIRO_FORMAT_ARGB32; break; } surface = cairo_image_surface_create (format, width, height); cairo_surface_set_device_offset (surface, - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x), - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y)); status = _cairo_meta_surface_replay (meta_surface, surface); if (status) { cairo_surface_destroy(surface); return status; } _cairo_scaled_glyph_set_surface (scaled_glyph, &scaled_font->base, (cairo_image_surface_t *) surface); } if (info & CAIRO_SCALED_GLYPH_INFO_PATH) { cairo_path_fixed_t *path = _cairo_path_fixed_create (); if (!path) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_meta_surface_get_path (meta_surface, path); if (status) { _cairo_path_fixed_destroy (path); return status; } _cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base, path); } return status; }
static VALUE cr_surface_get_content (VALUE self) { return INT2NUM (cairo_surface_get_content (_SELF)); }
static cairo_test_status_t cairo_test_for_target (cairo_test_t *test, 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; 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%s", test->name, target->name, format, similar ? "-similar" : "", 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%s", test->name, target->name, format, similar ? "-similar" : "", 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); if (similar) cairo_push_group_with_content (cr, target->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); status = (test->draw) (cr, test->width, test->height); cairo_restore (cr); /* 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 (similar) { cairo_pop_group_to_source (cr); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); } 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); cairo_test_log ("OUTPUT: %s\n", 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 ("REFERENCE: %s\n", ref_name); cairo_test_log ("DIFFERENCE: %s\n", diff_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; }
static PyObject * surface_get_content (PycairoSurface *o) { return PyInt_FromLong (cairo_surface_get_content (o->surface)); }
static already_AddRefed<gfxXlibSurface> CreateTempXlibSurface (gfxASurface *destination, nsIntSize size, PRBool canDrawOverBackground, PRUint32 flags, Screen *screen, Visual *visual, DrawingMethod *method) { PRBool drawIsOpaque = (flags & gfxXlibNativeRenderer::DRAW_IS_OPAQUE) != 0; PRBool supportsAlternateVisual = (flags & gfxXlibNativeRenderer::DRAW_SUPPORTS_ALTERNATE_VISUAL) != 0; PRBool 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. PRBool 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 = PR_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(); }
already_AddRefed<DrawTarget> PrintTarget::GetReferenceDrawTarget(DrawEventRecorder* aRecorder) { if (!mRefDT) { const IntSize size(1, 1); cairo_surface_t* similar; switch (cairo_surface_get_type(mCairoSurface)) { #ifdef CAIRO_HAS_WIN32_SURFACE case CAIRO_SURFACE_TYPE_WIN32: similar = cairo_win32_surface_create_with_dib( CairoContentToCairoFormat(cairo_surface_get_content(mCairoSurface)), size.width, size.height); break; #endif #ifdef CAIRO_HAS_QUARTZ_SURFACE case CAIRO_SURFACE_TYPE_QUARTZ: similar = cairo_quartz_surface_create_cg_layer( mCairoSurface, cairo_surface_get_content(mCairoSurface), size.width, size.height); break; #endif default: similar = cairo_surface_create_similar( mCairoSurface, cairo_surface_get_content(mCairoSurface), size.width, size.height); break; } if (cairo_surface_status(similar)) { return nullptr; } RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForCairoSurface(similar, size); // The DT addrefs the surface, so we need drop our own reference to it: cairo_surface_destroy(similar); if (!dt || !dt->IsValid()) { return nullptr; } mRefDT = dt.forget(); } if (aRecorder) { if (!mRecordingRefDT) { RefPtr<DrawTarget> dt = CreateRecordingDrawTarget(aRecorder, mRefDT); if (!dt || !dt->IsValid()) { return nullptr; } mRecordingRefDT = dt.forget(); #ifdef DEBUG mRecorder = aRecorder; #endif } #ifdef DEBUG else { MOZ_ASSERT(aRecorder == mRecorder, "Caching mRecordingRefDT assumes the aRecorder is an invariant"); } #endif return do_AddRef(mRecordingRefDT); } return do_AddRef(mRefDT); }
void swfdec_bitmap_data_copyPixels (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { SwfdecBitmapData *bitmap, *source, *alpha = NULL; SwfdecAsObject *recto = NULL, *pt, *apt = NULL, *so, *ao = NULL; SwfdecRectangle rect; gboolean copy_alpha = FALSE; cairo_t *cr; int x, y; SWFDEC_AS_CHECK (SWFDEC_TYPE_BITMAP_DATA, &bitmap, "ooo|oob", &so, &recto, &pt, &ao, &apt, ©_alpha); if (bitmap->surface == NULL || !SWFDEC_IS_BITMAP_DATA (so) || (source = SWFDEC_BITMAP_DATA (so))->surface == NULL || (ao != NULL && (!SWFDEC_IS_BITMAP_DATA (ao) || (alpha = SWFDEC_BITMAP_DATA (ao))->surface == NULL)) || !swfdec_rectangle_from_as_object (&rect, recto)) return; x = rect.x; y = rect.y; swfdec_point_from_as_object (&rect.x, &rect.y, pt); cr = cairo_create (bitmap->surface); if (bitmap == source) { cairo_surface_t *copy = cairo_surface_create_similar (source->surface, cairo_surface_get_content (source->surface), rect.width, rect.height); cairo_t *cr2 = cairo_create (copy); cairo_set_source_surface (cr2, source->surface, x, y); cairo_paint (cr2); cairo_destroy (cr2); cairo_set_source_surface (cr, copy, rect.x, rect.y); cairo_surface_destroy (copy); } else { cairo_set_source_surface (cr, source->surface, rect.x - x, rect.y - y); } if (swfdec_surface_has_alpha (bitmap->surface) && !copy_alpha) { cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); } cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height); if (alpha) { cairo_surface_t *mask = cairo_surface_create_similar (alpha->surface, CAIRO_CONTENT_COLOR_ALPHA, rect.width, rect.height); cairo_t *cr2 = cairo_create (mask); cairo_surface_set_device_offset (mask, -rect.x, -rect.y); cairo_set_source (cr2, cairo_get_source (cr)); if (apt) { swfdec_point_from_as_object (&x, &y, apt); } else { x = y = 0; } cairo_mask_surface (cr2, alpha->surface, rect.x - x, rect.y - y); cairo_destroy (cr2); cairo_set_source_surface (cr, mask, 0, 0); cairo_surface_destroy (mask); } cairo_fill (cr); cairo_destroy (cr); cairo_surface_mark_dirty_rectangle (bitmap->surface, rect.x, rect.y, rect.width, rect.height); }
static void update_icon(ShowDesktopData* sdd) { GtkStyleContext *context; GtkStateFlags state; GtkBorder padding; int width, height; cairo_surface_t* icon; cairo_surface_t* scaled; int icon_size, icon_scale; GError* error; int thickness = 0; if (!sdd->icon_theme) return; state = gtk_widget_get_state_flags (sdd->button); context = gtk_widget_get_style_context (sdd->button); gtk_style_context_get_padding (context, state, &padding); switch (sdd->orient) { case GTK_ORIENTATION_HORIZONTAL: thickness = padding.top + padding.bottom; break; case GTK_ORIENTATION_VERTICAL: thickness = padding.left + padding.right; break; } icon_scale = gtk_widget_get_scale_factor (sdd->button); icon_size = sdd->size * icon_scale - thickness; if (icon_size < 22) icon_size = 16; else if (icon_size < 24) icon_size = 22; else if (icon_size < 32) icon_size = 24; else if (icon_size < 48) icon_size = 32; else if (icon_size < 64) icon_size = 48; else if (icon_size < 128) icon_size = 64; error = NULL; icon = gtk_icon_theme_load_surface (sdd->icon_theme, SHOW_DESKTOP_ICON, icon_size, icon_scale, NULL, 0, &error); if (icon == NULL) { g_printerr(_("Failed to load %s: %s\n"), SHOW_DESKTOP_ICON, error ? error->message : _("Icon not found")); if (error) { g_error_free(error); error = NULL; } gtk_image_set_from_icon_name (GTK_IMAGE (sdd->image), "image-missing", GTK_ICON_SIZE_SMALL_TOOLBAR); return; } width = cairo_image_surface_get_width (icon); height = cairo_image_surface_get_height (icon); scaled = NULL; /* Make it fit on the given panel */ switch (sdd->orient) { case GTK_ORIENTATION_HORIZONTAL: width = (icon_size / icon_scale * width) / height; height = icon_size / icon_scale; break; case GTK_ORIENTATION_VERTICAL: height = (icon_size / icon_scale * height) / width; width = icon_size / icon_scale; break; } scaled = cairo_surface_create_similar (icon, cairo_surface_get_content (icon), width, height); if (scaled != NULL) { cairo_t *cr; cr = cairo_create (scaled); cairo_scale (cr, (double) width / icon_size, (double) height / icon_size); cairo_set_source_surface (cr, icon, 0, 0); cairo_paint (cr); gtk_image_set_from_surface (GTK_IMAGE(sdd->image), scaled); cairo_surface_destroy (scaled); } else { gtk_image_set_from_surface (GTK_IMAGE (sdd->image), icon); } cairo_surface_destroy (icon); }
bool hasAlpha(const RefPtr<cairo_surface_t>& image) { return cairo_surface_get_content(image.get()) != CAIRO_CONTENT_COLOR; }
static cairo_test_status_t draw (cairo_t *cr, int width, int height) { const cairo_test_context_t *ctx = cairo_test_get_context (cr); cairo_surface_t *similar, *target; cairo_test_status_t test_status; cairo_status_t status; unsigned int i; target = cairo_get_target (cr); /* Test a finished similar surface */ for (i = 0; i < ARRAY_LENGTH (tests); i++) { similar = cairo_surface_create_similar (target, cairo_surface_get_content (target), 10, 10); cairo_surface_finish (similar); test_status = tests[i].func (similar); status = cairo_surface_status (similar); cairo_surface_destroy (similar); if (test_status != CAIRO_TEST_SUCCESS) { cairo_test_log (ctx, "Failed test %s with %d\n", tests[i].name, (int) test_status); return test_status; } if (tests[i].modifies_surface && strcmp (tests[i].name, "cairo_surface_finish") && strcmp (tests[i].name, "cairo_surface_flush") && status != CAIRO_STATUS_SURFACE_FINISHED) { cairo_test_log (ctx, "Failed test %s: Finished surface not set into error state\n", tests[i].name); return CAIRO_TEST_ERROR; } } /* Test a normal surface for functions that have the wrong type */ for (i = 0; i < ARRAY_LENGTH (tests); i++) { cairo_status_t desired_status; if (tests[i].surface_type == -1) continue; similar = cairo_surface_create_similar (target, cairo_surface_get_content (target), 10, 10); if (cairo_surface_get_type (similar) == (cairo_surface_type_t) tests[i].surface_type) { cairo_surface_destroy (similar); continue; } test_status = tests[i].func (similar); status = cairo_surface_status (similar); cairo_surface_destroy (similar); if (test_status != CAIRO_TEST_SUCCESS) { cairo_test_log (ctx, "Failed test %s with %d\n", tests[i].name, (int) test_status); return test_status; } desired_status = tests[i].modifies_surface ? CAIRO_STATUS_SURFACE_TYPE_MISMATCH : CAIRO_STATUS_SUCCESS; if (status != desired_status) { cairo_test_log (ctx, "Failed test %s: Surface status should be %u (%s), but is %u (%s)\n", tests[i].name, desired_status, cairo_status_to_string (desired_status), status, cairo_status_to_string (status)); return CAIRO_TEST_ERROR; } } /* 565-compatible gray background */ cairo_set_source_rgb (cr, 0.51613, 0.55555, 0.51613); cairo_paint (cr); return CAIRO_TEST_SUCCESS; }
void PluginView::paint(GraphicsContext* context, const IntRect& rect) { if (!m_isStarted || m_status != PluginStatusLoadedSuccessfully) { paintMissingPluginIcon(context, rect); return; } if (context->paintingDisabled()) return; setNPWindowIfNeeded(); if (m_isWindowed) return; if (!m_drawable) return; Display* display = getPluginDisplay(nullptr); const bool syncX = m_pluginDisplay && m_pluginDisplay != display; IntRect exposedRect(rect); exposedRect.intersect(frameRect()); exposedRect.move(-frameRect().x(), -frameRect().y()); RefPtr<cairo_surface_t> drawableSurface = adoptRef(cairo_xlib_surface_create(display, m_drawable, m_visual, m_windowRect.width(), m_windowRect.height())); if (m_isTransparent) { // If we have a 32 bit drawable and the plugin wants transparency, // we'll clear the exposed area to transparent first. Otherwise, // we'd end up with junk in there from the last paint, or, worse, // uninitialized data. RefPtr<cairo_t> cr = adoptRef(cairo_create(drawableSurface.get())); if (!(cairo_surface_get_content(drawableSurface.get()) & CAIRO_CONTENT_ALPHA)) { // Attempt to fake it when we don't have an alpha channel on our // pixmap. If that's not possible, at least clear the window to // avoid drawing artifacts. // This Would not work without double buffering, but we always use it. cairo_set_source_surface(cr.get(), cairo_get_group_target(context->platformContext()->cr()), -m_windowRect.x(), -m_windowRect.y()); cairo_set_operator(cr.get(), CAIRO_OPERATOR_SOURCE); } else cairo_set_operator(cr.get(), CAIRO_OPERATOR_CLEAR); cairo_rectangle(cr.get(), exposedRect.x(), exposedRect.y(), exposedRect.width(), exposedRect.height()); cairo_fill(cr.get()); } XEvent xevent; memset(&xevent, 0, sizeof(XEvent)); XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose; exposeEvent.type = GraphicsExpose; exposeEvent.display = display; exposeEvent.drawable = m_drawable; exposeEvent.x = exposedRect.x(); exposeEvent.y = exposedRect.y(); exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode dispatchNPEvent(xevent); if (syncX) XSync(m_pluginDisplay, false); // sync changes by plugin cairo_t* cr = context->platformContext()->cr(); cairo_save(cr); cairo_set_source_surface(cr, drawableSurface.get(), frameRect().x(), frameRect().y()); cairo_rectangle(cr, frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y(), exposedRect.width(), exposedRect.height()); cairo_clip(cr); if (m_isTransparent) cairo_set_operator(cr, CAIRO_OPERATOR_OVER); else cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_paint(cr); cairo_restore(cr); }
/** * Create a surface that differs only in pixel content. * Creates a surface that has the same type, content type and dimensions * as the specified surface. Pixel contents are not copied. */ cairo_surface_t * ink_cairo_surface_create_identical(cairo_surface_t *s) { cairo_surface_t *ns = ink_cairo_surface_create_same_size(s, cairo_surface_get_content(s)); return ns; }
cairo_status_t _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup, cairo_gl_context_t **ctx_out, cairo_bool_t multisampling) { unsigned int dst_size, src_size, mask_size, vertex_size; cairo_gl_context_t *ctx; cairo_status_t status; cairo_bool_t component_alpha; cairo_gl_shader_t *shader; cairo_operator_t op = setup->op; cairo_surface_t *mask_surface = NULL; assert (setup->dst); status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx); if (unlikely (status)) return status; _cairo_gl_context_set_destination (ctx, setup->dst, multisampling); if (ctx->states_cache.blend_enabled == FALSE) { glEnable (GL_BLEND); ctx->states_cache.blend_enabled = TRUE; } component_alpha = setup->mask.type == CAIRO_GL_OPERAND_TEXTURE && setup->mask.texture.attributes.has_component_alpha; /* Do various magic for component alpha */ if (component_alpha) { status = _cairo_gl_composite_begin_component_alpha (ctx, setup); if (unlikely (status)) goto FAIL; } else { if (ctx->pre_shader) { _cairo_gl_composite_flush (ctx); ctx->pre_shader = NULL; } } status = _cairo_gl_get_shader_by_type (ctx, &setup->src, &setup->mask, setup->spans, component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE : CAIRO_GL_SHADER_IN_NORMAL, &shader); if (unlikely (status)) { ctx->pre_shader = NULL; goto FAIL; } if (ctx->current_shader != shader) _cairo_gl_composite_flush (ctx); status = CAIRO_STATUS_SUCCESS; dst_size = 2 * sizeof (GLfloat); src_size = _cairo_gl_operand_get_vertex_size (&setup->src); mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask); vertex_size = dst_size + src_size + mask_size; if (setup->spans) vertex_size += sizeof (GLfloat); _cairo_gl_composite_setup_vbo (ctx, vertex_size); _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size); _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size); if (setup->spans) _cairo_gl_context_setup_spans (ctx, vertex_size, dst_size + src_size + mask_size); else { ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COVERAGE_ATTRIB_INDEX); ctx->spans = FALSE; } /* XXX: Shoot me - we have converted CLEAR to DEST_OUT, so the dst_factor would be GL_ONE_MINUS_SRC_ALPHA, if the mask is a surface and mask content not content_alpha, we want to use GL_ONE_MINUS_SRC_COLOR, otherwise, we use GL_ONE_MINUS_SRC_ALPHA */ if (setup->mask.type == CAIRO_GL_OPERAND_TEXTURE) mask_surface = &setup->mask.texture.surface->base; if (op == CAIRO_OPERATOR_CLEAR && component_alpha && mask_surface != NULL && cairo_surface_get_content (mask_surface) == CAIRO_CONTENT_ALPHA) component_alpha = FALSE; _cairo_gl_set_operator (ctx, setup->op, component_alpha); if (_cairo_gl_context_is_flushed (ctx)) { if (ctx->pre_shader) { _cairo_gl_set_shader (ctx, ctx->pre_shader); _cairo_gl_composite_bind_to_shader (ctx, setup); } _cairo_gl_set_shader (ctx, shader); _cairo_gl_composite_bind_to_shader (ctx, setup); } status = _cairo_gl_composite_setup_clipping (setup, ctx, vertex_size); if (unlikely (status)) goto FAIL; *ctx_out = ctx; FAIL: if (unlikely (status)) status = _cairo_gl_context_release (ctx, status); return status; }
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; }
void FilterTile::render_cairo(FilterSlot &slot) { // FIX ME! static bool tile_warning = false; if (!tile_warning) { g_warning("Renderer for feTile has non-optimal implementation, expect slowness and bugs."); tile_warning = true; } // Fixing isn't so easy as the Inkscape renderer breaks the canvas into "rendering" tiles for // faster rendering. (The "rendering" tiles are not the same as the tiles in this primitive.) // Only if the the feTile tile source falls inside the current "rendering" tile will the tile // image be available. // This input source contains only the "rendering" tile. cairo_surface_t *in = slot.getcairo(_input); // For debugging // static int i = 0; // ++i; // std::stringstream filename; // filename << "dump." << i << ".png"; // cairo_surface_write_to_png( in, filename.str().c_str() ); // This is the feTile source area as determined by the input primitive area (see SVG spec). Geom::Rect tile_area = slot.get_primitive_area(_input); if( tile_area.width() == 0.0 || tile_area.height() == 0.0 ) { slot.set(_output, in); std::cerr << "FileTile::render_cairo: tile has zero width or height" << std::endl; } else { cairo_surface_t *out = ink_cairo_surface_create_identical(in); // color_interpolation_filters for out same as in. copy_cairo_surface_ci(in, out); cairo_t *ct = cairo_create(out); // The rectangle of the "rendering" tile. Geom::Rect sa = slot.get_slot_area(); Geom::Affine trans = slot.get_units().get_matrix_user2pb(); // Create feTile tile ---------------- // Get tile area in pixbuf units (tile transformed). Geom::Rect tt = tile_area * trans; // Shift between "rendering" tile and feTile tile Geom::Point shift = sa.min() - tt.min(); // Create feTile tile surface cairo_surface_t *tile = cairo_surface_create_similar(in, cairo_surface_get_content(in), tt.width(), tt.height()); cairo_t *ct_tile = cairo_create(tile); cairo_set_source_surface(ct_tile, in, shift[Geom::X], shift[Geom::Y]); cairo_paint(ct_tile); // Paint tiles ------------------ // For debugging // std::stringstream filename; // filename << "tile." << i << ".png"; // cairo_surface_write_to_png( tile, filename.str().c_str() ); // Determine number of feTile rows and columns Geom::Rect pr = filter_primitive_area( slot.get_units() ); int tile_cols = ceil( pr.width() / tile_area.width() ); int tile_rows = ceil( pr.height() / tile_area.height() ); // Do tiling (TO DO: restrict to slot area.) for( int col=0; col < tile_cols; ++col ) { for( int row=0; row < tile_rows; ++row ) { Geom::Point offset( col*tile_area.width(), row*tile_area.height() ); offset *= trans; offset[Geom::X] -= trans[4]; offset[Geom::Y] -= trans[5]; cairo_set_source_surface(ct, tile, offset[Geom::X], offset[Geom::Y]); cairo_paint(ct); } } slot.set(_output, out); // Clean up cairo_destroy(ct); cairo_surface_destroy(out); cairo_destroy(ct_tile); cairo_surface_destroy(tile); } }
static void gimp_view_renderer_real_draw (GimpViewRenderer *renderer, GtkWidget *widget, cairo_t *cr, gint available_width, gint available_height) { if (renderer->needs_render) GIMP_VIEW_RENDERER_GET_CLASS (renderer)->render (renderer, widget); if (renderer->pixbuf) { gint width = gdk_pixbuf_get_width (renderer->pixbuf); gint height = gdk_pixbuf_get_height (renderer->pixbuf); gint x, y; if (renderer->bg_icon_name) { if (! renderer->pattern) { renderer->pattern = gimp_view_renderer_create_background (renderer, widget); } cairo_set_source (cr, renderer->pattern); cairo_paint (cr); } x = (available_width - width) / 2; y = (available_height - height) / 2; gdk_cairo_set_source_pixbuf (cr, renderer->pixbuf, x, y); cairo_rectangle (cr, x, y, width, height); cairo_fill (cr); } else if (renderer->surface) { cairo_content_t content = cairo_surface_get_content (renderer->surface); gint width = renderer->width; gint height = renderer->height; gint offset_x = (available_width - width) / 2; gint offset_y = (available_height - height) / 2; cairo_translate (cr, offset_x, offset_y); cairo_rectangle (cr, 0, 0, width, height); if (content == CAIRO_CONTENT_COLOR_ALPHA) { if (! renderer->pattern) renderer->pattern = gimp_cairo_checkerboard_create (cr, GIMP_CHECK_SIZE_SM, gimp_render_light_check_color (), gimp_render_dark_check_color ()); cairo_set_source (cr, renderer->pattern); cairo_fill_preserve (cr); } cairo_set_source_surface (cr, renderer->surface, 0, 0); cairo_fill (cr); cairo_translate (cr, - offset_x, - offset_y); } }