/* * functions to create different wrapmodes. */ static GpStatus draw_tile_texture (cairo_t *ct, GpBitmap *bitmap, GpTexture *brush) { cairo_surface_t *original = NULL; cairo_surface_t *texture; cairo_pattern_t *pat; GpStatus status; GpRect *rect = &brush->rectangle; cairo_t *ct2; BYTE *premul = NULL; if (!rect) return InvalidParameter; gdip_bitmap_ensure_surface (bitmap); if (gdip_bitmap_format_needs_premultiplication (bitmap)) { premul = gdip_bitmap_get_premultiplied_scan0 (bitmap); if (premul) { ActiveBitmapData *data = bitmap->active_bitmap; original = cairo_image_surface_create_for_data (premul, CAIRO_FORMAT_ARGB32, data->width, data->height, data->stride); } } /* if premul isn't required (or couldn't be computed, e.g. out of memory) */ if (!original) original = bitmap->surface; /* Use the original as a pattern */ pat = cairo_pattern_create_for_surface (original); status = gdip_get_pattern_status (pat); if (status != Ok) goto cleanup; cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT); /* texture surface to be created */ texture = cairo_surface_create_similar (original, from_cairoformat_to_content (bitmap->cairo_format), rect->Width, rect->Height); status = gdip_get_status (cairo_surface_status (texture)); if (status != Ok) { cairo_pattern_destroy (pat); goto cleanup; } /* Draw the texture */ ct2 = cairo_create (texture); cairo_set_source (ct2, pat); cairo_rectangle (ct2, 0, 0, rect->Width, rect->Height); cairo_fill (ct2); cairo_destroy (ct2); brush->pattern = cairo_pattern_create_for_surface (texture); status = gdip_get_pattern_status (brush->pattern); if (status == Ok) cairo_pattern_set_extend (brush->pattern, CAIRO_EXTEND_REPEAT); cairo_pattern_destroy (pat); cairo_surface_destroy (texture); status = gdip_get_status (cairo_status (ct)); cleanup: if (premul) { cairo_surface_destroy (original); GdipFree (premul); } return status; }
static cairo_int_status_t _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font, cairo_scaled_glyph_t *scaled_glyph) { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font); cairo_image_surface_t *surface = NULL; CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph); int advance; CGRect bbox; double width, height; double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont); CGContextRef cgContext = NULL; CGAffineTransform textMatrix; CGRect glyphRect, glyphRectInt; CGPoint glyphOrigin; //fprintf (stderr, "scaled_glyph: %p surface: %p\n", scaled_glyph, scaled_glyph->surface); /* Create blank 2x2 image if we don't have this character. * Maybe we should draw a better missing-glyph slug or something, * but this is ok for now. */ if (glyph == INVALID_GLYPH) { surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2); status = cairo_surface_status ((cairo_surface_t *) surface); if (status) return status; _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface); return CAIRO_STATUS_SUCCESS; } if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) || !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox)) { return CAIRO_INT_STATUS_UNSUPPORTED; } /* scale(1,-1) * font->base.scale * scale(1,-1) */ textMatrix = CGAffineTransformMake (font->base.scale.xx, -font->base.scale.yx, -font->base.scale.xy, font->base.scale.yy, 0, -0); glyphRect = CGRectMake (bbox.origin.x / emscale, bbox.origin.y / emscale, bbox.size.width / emscale, bbox.size.height / emscale); glyphRect = CGRectApplyAffineTransform (glyphRect, textMatrix); /* Round the rectangle outwards, so that we don't have to deal * with non-integer-pixel origins or dimensions. */ glyphRectInt = CGRectIntegral (glyphRect); #if 0 fprintf (stderr, "glyphRect[o]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height); fprintf (stderr, "glyphRectInt: %f %f %f %f\n", glyphRectInt.origin.x, glyphRectInt.origin.y, glyphRectInt.size.width, glyphRectInt.size.height); #endif glyphOrigin = glyphRectInt.origin; //textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformInvert (ctm)); width = glyphRectInt.size.width; height = glyphRectInt.size.height; //fprintf (stderr, "glyphRect[n]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height); surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); if (surface->base.status) return surface->base.status; if (surface->width != 0 && surface->height != 0) { cgContext = CGBitmapContextCreate (surface->data, surface->width, surface->height, 8, surface->stride, NULL, kCGImageAlphaOnly); if (cgContext == NULL) { cairo_surface_destroy (&surface->base); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } CGContextSetFont (cgContext, font_face->cgFont); CGContextSetFontSize (cgContext, 1.0); CGContextSetTextMatrix (cgContext, textMatrix); switch (font->base.options.antialias) { case CAIRO_ANTIALIAS_SUBPIXEL: case CAIRO_ANTIALIAS_BEST: CGContextSetShouldAntialias (cgContext, TRUE); CGContextSetShouldSmoothFonts (cgContext, TRUE); if (CGContextSetAllowsFontSmoothingPtr && !CGContextGetAllowsFontSmoothingPtr (cgContext)) CGContextSetAllowsFontSmoothingPtr (cgContext, TRUE); break; case CAIRO_ANTIALIAS_NONE: CGContextSetShouldAntialias (cgContext, FALSE); break; case CAIRO_ANTIALIAS_GRAY: case CAIRO_ANTIALIAS_GOOD: case CAIRO_ANTIALIAS_FAST: CGContextSetShouldAntialias (cgContext, TRUE); CGContextSetShouldSmoothFonts (cgContext, FALSE); break; case CAIRO_ANTIALIAS_DEFAULT: default: /* Don't do anything */ break; } CGContextSetAlpha (cgContext, 1.0); CGContextShowGlyphsAtPoint (cgContext, - glyphOrigin.x, - glyphOrigin.y, &glyph, 1); CGContextRelease (cgContext); } cairo_surface_set_device_offset (&surface->base, - glyphOrigin.x, height + glyphOrigin.y); _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface); return status; }
static cairo_test_status_t preamble (cairo_test_context_t *ctx) { cairo_t *cr; cairo_test_status_t ret = CAIRO_TEST_UNTESTED; struct { double x, y; } ppi[] = { { 600, 600 }, { 600, 72 }, { 300, 300 }, { 300, 72 }, { 150, 150 }, { 150, 72 }, { 75, 75 }, { 75, 72 }, { 72, 600 }, { 72, 300 }, { 72, 150 }, { 72, 75 }, { 72, 72 }, { 72, 37.5 }, { 37.5, 72 }, { 37.5, 37.5 }, }; unsigned int i; int n, num_ppi; num_ppi = sizeof (ppi) / sizeof (ppi[0]); #if GENERATE_REFERENCE for (n = 0; n < num_ppi; n++) { char *ref_name; xasprintf (&ref_name, "fallback-resolution.ppi%gx%g.ref.png", ppi[n].x, ppi[n].y); generate_reference (ppi[n].x, ppi[n].y, ref_name); free (ref_name); } #endif for (i = 0; i < ctx->num_targets; i++) { const cairo_boilerplate_target_t *target = ctx->targets_to_test[i]; cairo_surface_t *surface = NULL; char *base_name; void *closure; const char *format; cairo_status_t status; if (! target->is_vector) continue; if (! cairo_test_is_target_enabled (ctx, target->name)) continue; format = cairo_boilerplate_content_name (target->content); xasprintf (&base_name, "fallback-resolution.%s.%s", target->name, format); surface = (target->create_surface) (base_name, target->content, SIZE, SIZE, SIZE, SIZE, CAIRO_BOILERPLATE_MODE_TEST, 0, &closure); if (surface == NULL) { free (base_name); continue; } if (ret == CAIRO_TEST_UNTESTED) ret = CAIRO_TEST_SUCCESS; cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); free (base_name); /* we need to recreate the surface for each resolution as we include * SVG in testing which does not support the paginated interface. */ for (n = 0; n < num_ppi; n++) { char *test_name; cairo_bool_t pass; xasprintf (&test_name, "fallback-resolution.ppi%gx%g", ppi[n].x, ppi[n].y); xasprintf (&base_name, "%s.%s.%s", test_name, target->name, format); surface = (target->create_surface) (base_name, target->content, SIZE + 25, SIZE + 25, SIZE + 25, SIZE + 25, CAIRO_BOILERPLATE_MODE_TEST, 0, &closure); if (surface == NULL || cairo_surface_status (surface)) { cairo_test_log (ctx, "Failed to generate surface: %s.%s\n", target->name, format); free (base_name); free (test_name); ret = CAIRO_TEST_FAILURE; continue; } cairo_test_log (ctx, "Testing fallback-resolution %gx%g with %s target\n", ppi[n].x, ppi[n].y, target->name); printf ("%s:\t", base_name); fflush (stdout); if (target->force_fallbacks != NULL) target->force_fallbacks (surface, ~0U); cr = cairo_create (surface); #if SET_TOLERANCE cairo_set_tolerance (cr, 3.0); #endif cairo_surface_set_device_offset (surface, 25, 25); cairo_surface_set_fallback_resolution (surface, ppi[n].x, ppi[n].y); cairo_save (cr); { cairo_set_source_rgb (cr, 1, 1, 1); cairo_paint (cr); } cairo_restore (cr); /* First draw the top half in a conventional way. */ cairo_save (cr); { cairo_rectangle (cr, 0, 0, SIZE, SIZE / 2.0); cairo_clip (cr); draw (cr, SIZE, SIZE); } cairo_restore (cr); /* Then draw the bottom half in a separate group, * (exposing a bug in 1.6.4 with the group not being * rendered with the correct fallback resolution). */ cairo_save (cr); { cairo_rectangle (cr, 0, SIZE / 2.0, SIZE, SIZE / 2.0); cairo_clip (cr); cairo_push_group (cr); { draw (cr, SIZE, SIZE); } cairo_pop_group_to_source (cr); cairo_paint (cr); } cairo_restore (cr); status = cairo_status (cr); cairo_destroy (cr); pass = FALSE; if (status) { cairo_test_log (ctx, "Error: Failed to create target surface: %s\n", cairo_status_to_string (status)); ret = CAIRO_TEST_FAILURE; } else { /* extract the image and compare it to our reference */ if (! check_result (ctx, target, test_name, base_name, surface)) ret = CAIRO_TEST_FAILURE; else pass = TRUE; } cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); free (base_name); free (test_name); if (pass) { printf ("PASS\n"); } else { printf ("FAIL\n"); } fflush (stdout); } } return ret; }
void MediaPlayerPrivateEA::paint(GraphicsContext* context, const IntRect& r) { if (!context) return; // Can get a NULL platform context so need to verify. Seems that UpdateControlTints does what is called a "fake" paint // with a null platform context just to get an invalidate. PlatformContextCairo* pPlatformContext = context->platformContext(); if (!pPlatformContext) return; cairo_t* cr = context->platformContext()->cr(); if (!cr) return; MediaUpdateInfo& info = GetMediaUpdateInfo(); const FrameView* pFV = mpWebCorePlayer->frameView(); if (!pFV) return; // Convert and store movie rect to device coords using the graphic context. double x = (double) r.x(); double y = (double) r.y(); double w = (double) r.width(); double h = (double) r.height(); cairo_user_to_device (cr, &x, &y); cairo_user_to_device_distance(cr, &w, &h); const IntRect rect((int) x, (int) y, (int) w, (int) h); // The intersection of frameView contents and the movie is used as clip rect for we just want to know what part of the movie is visible. IntRect clip = pFV->windowClipRect(true); clip.intersect(rect); // Find controls intersection HTMLMediaElement* element = static_cast<HTMLMediaElement*>(mpWebCorePlayer->mediaPlayerClient()); if(element && element->controls()) { MediaControls* pControls = element->mediaControls(); bool hideControls = pControls->shouldHideControls(); if (!hideControls) { const int kControlHeight = 16; // EAWebKitTODO: Consider finding a way to extract this info directly from the controls or pass as a theme param. IntRect boundingRect = pControls->getRect(); x = (double) boundingRect.x(); y = (double) boundingRect.y(); w = (double) boundingRect.width(); h = (double) (boundingRect.height() - kControlHeight); cairo_user_to_device (cr, &x, &y); cairo_user_to_device_distance(cr, &w, &h); const IntRect ctrlRect((int) x, (int) y, (int) w, (int) h); clip.intersect(ctrlRect); } } if ((rect != mMovieRect) || (clip != mWindowRect)) { mMovieRect = rect; // Store copy locally to detect changes. mWindowRect = clip; info.mMovieRect = rect; info.mWindowRect = clip; ClientUpdate(MediaUpdateInfo::kWindowSize); } ClientUpdate(MediaUpdateInfo::kPaint); if (info.mReturnData) { // Draw surface to view #ifndef NDEBUG static bool sAssertChecked = false; if(!sAssertChecked) { EAW_ASSERT(!info.mReturnData); sAssertChecked = true; } #endif context->save(); RefPtr<cairo_surface_t> cairoSurface = adoptRef(cairo_image_surface_create_for_data((unsigned char*) info.mReturnData, CAIRO_FORMAT_ARGB32, w, h, w * sizeof(uint32_t))); EAW_ASSERT(cairo_surface_status(cairoSurface.get()) == CAIRO_STATUS_SUCCESS); cairo_set_source_surface(cr, cairoSurface.get(), rect.x(), rect.y()); cairo_paint(cr); context->restore(); } else { // Draw a default black background. context->save(); context->setStrokeStyle(NoStroke); context->setFillColor(Color::black, ColorSpaceDeviceRGB); context->drawRect(r); context->restore(); } }
int main(int argc, char** argv) { int c; float col_r, col_g, col_b = -1.0f; Options opt; while ((c = getopt(argc, argv, "a:x:y:f:s:t:n:w:r:g:b:c:")) != -1) { switch(c) { /* color */ /* ------------------------------------------------------- */ case 'r': { col_r = convert_type<float>(optarg); break; } case 'g': { col_g = convert_type<float>(optarg); break; } case 'b': { col_b = convert_type<float>(optarg); break; } /* ------------------------------------------------------- */ /* foreground */ case 'c': { opt.foreground_file = convert_type<std::string>(optarg); break; } /* ------------------------------------------------------- */ /* background */ case 'x': { opt.background_x = convert_type<int>(optarg); break; } case 'y': { opt.background_y = convert_type<int>(optarg); break; } case 'f': { //printf("Got: %s", optarg); opt.background_file = convert_type<std::string>(optarg); break; } /* ------------------------------------------------------- */ /* visible size */ case 'a': { opt.visible_size = convert_type<float>(optarg); break; } /* ------------------------------------------------------- */ /* name */ case 'n': { opt.name = convert_type<std::string>(optarg); /* we expect that r,g,b has been set */ if (0 > col_r) { printf("Error: you haven't set -r -g -b for the name.\n"); exit(EXIT_FAILURE); } opt.name_r = col_r; opt.name_g = col_g; opt.name_b = col_b; break; } /* name x position */ case 's': { opt.name_x = convert_type<int>(optarg); break; } /* name y position */ case 't': { opt.name_y = convert_type<int>(optarg); break; } /* name font size */ case 'w': { opt.name_font_size = convert_type<float>(optarg); break; } default: { printf("Unkown option\n"); break; } } } if (false == opt.validate()) { printf("+ error: cannot validate the given options.\n"); exit(EXIT_FAILURE); } opt.print(); /* ------------------------------------------------------------------------------------ */ Image img; std::string path; std::string ext; cairo_surface_t* surf_bg = NULL; cairo_format_t img_format = CAIRO_FORMAT_INVALID; path = opt.foreground_file; if (false == rx_file_exists(path)) { printf("+ error: cannot find the file: %s\n", path.c_str()); exit(EXIT_FAILURE); } cairo_surface_t* surf_overlay = cairo_image_surface_create_from_png(path.c_str()); if (NULL == surf_overlay) { printf("Error: cannot create s1\n"); exit(EXIT_FAILURE); } path = opt.background_file; if (false == rx_file_exists(path)) { printf("Error: file doesn't exist: %s\n", path.c_str()); exit(EXIT_FAILURE); } /* check what file type was given. */ ext = rx_get_file_ext(path); if (ext == "jpg") { printf("+ warning: jpg as input doesn't seem to work\n"); /* cairo doesn't have support for PNG? */ if (0 > rx_load_jpg(path, &img.pixels, img.width, img.height, img.channels)) { printf("Error: failed to load: %s\n", path.c_str()); exit(EXIT_FAILURE); } if (0 == img.width || 0 == img.height || 0 == img.channels) { printf("Error: image has invalid flags: %d x %d, channels: %d\n", img.width, img.height, img.channels); exit(EXIT_FAILURE); } if (3 == img.channels) { img_format = CAIRO_FORMAT_RGB24; printf("+ Using RGB24\n"); } else if(4 == img.channels) { img_format = CAIRO_FORMAT_ARGB32; printf("+ Using ARGB32\n"); } else { printf("Error: unsupported number of channels: %d.\n", img.channels); exit(EXIT_FAILURE); } if (NULL != img.pixels && NULL == surf_bg) { printf("Stride: %d\n", cairo_format_stride_for_width(img_format, img.width)); printf("Info: creating %d x %d, channels: %d\n", img.width, img.height, img.channels); surf_bg = cairo_image_surface_create_for_data(img.pixels, img_format, img.width, img.height, cairo_format_stride_for_width(img_format, img.width)); #if 0 /* TESTING */ cairo_t* cr = cairo_create(surf_bg); if (NULL == cr) { printf("Error: cannot create the cairo"); exit(EXIT_FAILURE); } path = rx_get_exe_path() +"/generated_polaroid.png"; cairo_surface_write_to_png(surf_bg, path.c_str()); printf("Created\n"); exit(0); /* END TESTING */ #endif } } else if (ext == "png") { /* use cairo png load feature. */ surf_bg = cairo_image_surface_create_from_png(path.c_str()); if (NULL == surf_bg) { printf("Error: cannot create s2\n"); exit(EXIT_FAILURE); } } else { printf("Error: unsupported file format: %s\n", ext.c_str()); exit(EXIT_FAILURE); } /* make sure the background is loaded correctly (aka the photo) */ if (NULL == surf_bg) { printf("Error: cannot create background surface.\n"); exit(EXIT_FAILURE); } if (CAIRO_STATUS_SUCCESS != cairo_surface_status(surf_bg)) { printf("Error: something went wrong: %d\n", cairo_surface_status(surf_bg)); exit(EXIT_FAILURE); } float source_width = cairo_image_surface_get_width(surf_bg); float source_height = cairo_image_surface_get_height(surf_bg); /* create output */ int dest_width = cairo_image_surface_get_width(surf_overlay); int dest_height = cairo_image_surface_get_height(surf_overlay); printf("+ Output size: %d x %d\n", dest_width, dest_height); cairo_surface_t* surf_out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dest_width, dest_height); if (NULL == surf_out) { printf("Error: cannot create cairo_surface_t\n"); exit(EXIT_FAILURE); } printf("+ Info: creating output surface: %d x %d\n", dest_width, dest_height); cairo_t* cr = cairo_create(surf_out); if (NULL == cr) { printf("Error: cannot create the cairo"); exit(EXIT_FAILURE); } /* fill background. */ cairo_set_source_rgba(cr, 1, 1, 1, 1); cairo_paint(cr); float scale_factor = opt.visible_size / source_width; printf("+ Scale factor: %f\n", scale_factor); /* paint background */ cairo_save(cr); cairo_scale(cr, scale_factor, scale_factor); cairo_set_source_surface(cr, surf_bg, opt.background_x, opt.background_y); cairo_rectangle(cr, 0, 0, img.width, img.height); cairo_paint(cr); cairo_restore(cr); /* paint overlay */ cairo_set_source_surface(cr, surf_overlay, 0, 0); cairo_paint(cr); cairo_surface_flush(surf_out); /* font */ cairo_select_font_face(cr, "Open Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_source_rgba(cr, opt.name_r, opt.name_g, opt.name_b, 1.0); cairo_move_to(cr, opt.name_x, opt.name_y); cairo_set_font_size(cr, opt.name_font_size); cairo_show_text(cr, opt.name.c_str()); cairo_stroke(cr); cairo_fill(cr); cairo_surface_flush(surf_out); /* write out */ path = rx_get_exe_path() +"/generated_polaroid.png"; cairo_surface_write_to_png(surf_out, path.c_str()); /* cleanup */ cairo_surface_destroy(surf_out); cairo_surface_destroy(surf_bg); cairo_surface_destroy(surf_overlay); cairo_destroy(cr); printf("\n"); return 0; }
static int surface_status (lua_State *L) { cairo_surface_t **obj = luaL_checkudata(L, 1, OOCAIRO_MT_NAME_SURFACE); return push_cairo_status(L, cairo_surface_status(*obj)); }
int main(int argc, char** argv) { cairo_t *cr; cairo_status_t status; cairo_surface_t *surface; //FT_Bitmap bmp = {0}; int stride = 0; int width = 640; int height = 480; bool ok = FcConfigAppFontAddFile(NULL, (FcChar8*)"fonts/ComicSansAfrica.ttf"); if (!ok) { printf("Failed to load ComicSansAfrica.ttf\n"); } FcChar8 *configName = FcConfigFilename(NULL); printf("%s", (const char*)configName); printf("\n"); FcConfig* config = FcConfigCreate(); FcConfigParseAndLoad(config, configName, true); FcConfigSetCurrent(config); /* FT buffer */ //FT_Bitmap_New(&bmp); //bmp.rows = height; //bmp.width = width; //bmp.buffer = (unsigned char*)malloc(bmp.rows * bmp.width * 4); // if (NULL == bmp.buffer) // { // printf("+ error: cannot allocate the buffer for the output bitmap.\n"); // exit(EXIT_FAILURE); // } //bmp.pitch = ((width+3) & -4) * 4; //bmp.pixel_mode = FT_PIXEL_MODE_BGRA; //printf("%d\n", bmp.pitch); //stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); //printf("%d\n", stride); //surface = cairo_image_surface_create_for_data(bmp.buffer, CAIRO_FORMAT_ARGB32, width, height, stride); surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); if (CAIRO_STATUS_SUCCESS != cairo_surface_status(surface)) { printf("+ error: couldn't create the surface.\n"); exit(EXIT_FAILURE); } cr = cairo_create(surface); if (CAIRO_STATUS_NO_MEMORY == cairo_status(cr)) { printf("+ error: out of memory, cannot create cairo_t*\n"); exit(EXIT_FAILURE); } cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); cairo_paint(cr); rendertext(cr); status = cairo_surface_write_to_png(surface, "out.png"); cairo_surface_destroy(surface); cairo_destroy(cr); return 0; }
static cairo_int_status_t _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font, cairo_scaled_glyph_t *scaled_glyph) { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font); cairo_image_surface_t *surface = NULL; CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph); int advance; CGRect bbox; double width, height; double xscale, yscale; double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont); CGColorSpaceRef gray; CGContextRef cgContext = NULL; CGAffineTransform textMatrix; CGRect glyphRect, glyphRectInt; CGPoint glyphOrigin; //fprintf (stderr, "scaled_glyph: %p surface: %p\n", scaled_glyph, scaled_glyph->surface); /* Create blank 2x2 image if we don't have this character. * Maybe we should draw a better missing-glyph slug or something, * but this is ok for now. */ if (glyph == INVALID_GLYPH) { surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2); status = cairo_surface_status ((cairo_surface_t *) surface); if (status) return status; _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface); return CAIRO_STATUS_SUCCESS; } if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) || !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox)) { return CAIRO_INT_STATUS_UNSUPPORTED; } status = _cairo_matrix_compute_basis_scale_factors (&font->base.scale, &xscale, &yscale, 1); if (status) return status; textMatrix = CGAffineTransformMake (font->base.scale.xx, -font->base.scale.yx, -font->base.scale.xy, font->base.scale.yy, 0.0f, 0.0f); glyphRect = CGRectMake (bbox.origin.x / emscale, bbox.origin.y / emscale, bbox.size.width / emscale, bbox.size.height / emscale); glyphRect = CGRectApplyAffineTransform (glyphRect, textMatrix); /* Round the rectangle outwards, so that we don't have to deal * with non-integer-pixel origins or dimensions. */ glyphRectInt = CGRectIntegral (glyphRect); #if 0 fprintf (stderr, "glyphRect[o]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height); fprintf (stderr, "glyphRectInt: %f %f %f %f\n", glyphRectInt.origin.x, glyphRectInt.origin.y, glyphRectInt.size.width, glyphRectInt.size.height); #endif glyphOrigin = glyphRectInt.origin; //textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformInvert (ctm)); width = glyphRectInt.size.width; height = glyphRectInt.size.height; //fprintf (stderr, "glyphRect[n]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height); surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); if (surface->base.status) return surface->base.status; gray = CGColorSpaceCreateDeviceGray (); cgContext = CGBitmapContextCreate (surface->data, surface->width, surface->height, 8, surface->stride, gray, kCGImageAlphaNone); CGColorSpaceRelease (gray); CGContextSetFont (cgContext, font_face->cgFont); CGContextSetFontSize (cgContext, 1.0); CGContextSetTextMatrix (cgContext, textMatrix); CGContextClearRect (cgContext, CGRectMake (0.0f, 0.0f, width, height)); if (font->base.options.antialias == CAIRO_ANTIALIAS_NONE) CGContextSetShouldAntialias (cgContext, false); CGContextSetRGBFillColor (cgContext, 1.0, 1.0, 1.0, 1.0); CGContextShowGlyphsAtPoint (cgContext, - glyphOrigin.x, - glyphOrigin.y, &glyph, 1); CGContextRelease (cgContext); cairo_surface_set_device_offset (&surface->base, - glyphOrigin.x, height + glyphOrigin.y); _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface); return status; }
void draw_shadow (cairo_t* cr, gdouble width, gdouble height, gint shadow_radius, gint corner_radius) { cairo_surface_t* tmp_surface = NULL; cairo_surface_t* new_surface = NULL; cairo_pattern_t* pattern = NULL; cairo_t* cr_surf = NULL; cairo_matrix_t matrix; raico_blur_t* blur = NULL; tmp_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 4 * shadow_radius, 4 * shadow_radius); if (cairo_surface_status (tmp_surface) != CAIRO_STATUS_SUCCESS) return; cr_surf = cairo_create (tmp_surface); if (cairo_status (cr_surf) != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy (tmp_surface); return; } cairo_scale (cr_surf, 1.0f, 1.0f); cairo_set_operator (cr_surf, CAIRO_OPERATOR_CLEAR); cairo_paint (cr_surf); cairo_set_operator (cr_surf, CAIRO_OPERATOR_OVER); cairo_set_source_rgba (cr_surf, 0.0f, 0.0f, 0.0f, 0.75f); cairo_arc (cr_surf, 2 * shadow_radius, 2 * shadow_radius, 2.0f * corner_radius, 0.0f, 360.0f * (G_PI / 180.f)); cairo_fill (cr_surf); cairo_destroy (cr_surf); // create and setup blur blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW); raico_blur_set_radius (blur, shadow_radius); // now blur it raico_blur_apply (blur, tmp_surface); // blur no longer needed raico_blur_destroy (blur); new_surface = cairo_image_surface_create_for_data ( cairo_image_surface_get_data (tmp_surface), cairo_image_surface_get_format (tmp_surface), cairo_image_surface_get_width (tmp_surface) / 2, cairo_image_surface_get_height (tmp_surface) / 2, cairo_image_surface_get_stride (tmp_surface)); pattern = cairo_pattern_create_for_surface (new_surface); if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy (tmp_surface); cairo_surface_destroy (new_surface); return; } // top left cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); cairo_set_source (cr, pattern); cairo_rectangle (cr, 0.0f, 0.0f, width - 2 * shadow_radius, 2 * shadow_radius); cairo_fill (cr); // bottom left cairo_matrix_init_scale (&matrix, 1.0f, -1.0f); cairo_matrix_translate (&matrix, 0.0f, -height); cairo_pattern_set_matrix (pattern, &matrix); cairo_rectangle (cr, 0.0f, 2 * shadow_radius, 2 * shadow_radius, height - 2 * shadow_radius); cairo_fill (cr); // top right cairo_matrix_init_scale (&matrix, -1.0f, 1.0f); cairo_matrix_translate (&matrix, -width, 0.0f); cairo_pattern_set_matrix (pattern, &matrix); cairo_rectangle (cr, width - 2 * shadow_radius, 0.0f, 2 * shadow_radius, height - 2 * shadow_radius); cairo_fill (cr); // bottom right cairo_matrix_init_scale (&matrix, -1.0f, -1.0f); cairo_matrix_translate (&matrix, -width, -height); cairo_pattern_set_matrix (pattern, &matrix); cairo_rectangle (cr, 2 * shadow_radius, height - 2 * shadow_radius, width - 2 * shadow_radius, 2 * shadow_radius); cairo_fill (cr); // clean up cairo_pattern_destroy (pattern); cairo_surface_destroy (tmp_surface); cairo_surface_destroy (new_surface); }
static cairo_surface_t * _cairo_boilerplate_gl_create_window (const char *name, cairo_content_t content, double width, double height, double max_width, double max_height, cairo_boilerplate_mode_t mode, void **closure) { int rgba_attribs[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_ALPHA_SIZE, 1, GLX_DOUBLEBUFFER, None }; int msaa_attribs[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_ALPHA_SIZE, 1, GLX_STENCIL_SIZE, 1, GLX_SAMPLES, 4, GLX_SAMPLE_BUFFERS, 1, GLX_DOUBLEBUFFER, None }; XVisualInfo *vi; GLXContext ctx; gl_target_closure_t *gltc; cairo_surface_t *surface; Display *dpy; XSetWindowAttributes attr; gltc = calloc (1, sizeof (gl_target_closure_t)); *closure = gltc; if (width == 0) width = 1; if (height == 0) height = 1; dpy = XOpenDisplay (NULL); gltc->dpy = dpy; if (!gltc->dpy) { fprintf (stderr, "Failed to open display: %s\n", XDisplayName(0)); free (gltc); return NULL; } if (mode == CAIRO_BOILERPLATE_MODE_TEST) XSynchronize (gltc->dpy, 1); vi = glXChooseVisual (dpy, DefaultScreen (dpy), msaa_attribs); if (vi == NULL) vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs); if (vi == NULL) { fprintf (stderr, "Failed to create RGBA, double-buffered visual\n"); XCloseDisplay (dpy); free (gltc); return NULL; } attr.colormap = XCreateColormap (dpy, RootWindow (dpy, vi->screen), vi->visual, AllocNone); attr.border_pixel = 0; attr.override_redirect = True; gltc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy), 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, CWOverrideRedirect | CWBorderPixel | CWColormap, &attr); XMapWindow (dpy, gltc->drawable); ctx = glXCreateContext (dpy, vi, NULL, True); XFree (vi); gltc->ctx = ctx; gltc->device = cairo_glx_device_create (dpy, ctx); gltc->surface = surface = cairo_gl_surface_create_for_window (gltc->device, gltc->drawable, ceil (width), ceil (height)); if (cairo_surface_status (surface)) _cairo_boilerplate_gl_cleanup (gltc); return surface; }
static cairo_surface_t * _cairo_boilerplate_gl_create_surface (const char *name, cairo_content_t content, double width, double height, double max_width, double max_height, cairo_boilerplate_mode_t mode, void **closure) { int rgba_attribs[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_ALPHA_SIZE, 1, GLX_DOUBLEBUFFER, None }; int rgb_attribs[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, None }; XVisualInfo *visinfo; GLXContext ctx; gl_target_closure_t *gltc; cairo_surface_t *surface; Display *dpy; gltc = calloc (1, sizeof (gl_target_closure_t)); *closure = gltc; if (width == 0) width = 1; if (height == 0) height = 1; dpy = XOpenDisplay (NULL); gltc->dpy = dpy; if (!gltc->dpy) { fprintf (stderr, "Failed to open display: %s\n", XDisplayName(0)); free (gltc); return NULL; } if (mode == CAIRO_BOILERPLATE_MODE_TEST) XSynchronize (gltc->dpy, 1); if (content == CAIRO_CONTENT_COLOR) visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgb_attribs); else visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs); if (visinfo == NULL) { fprintf (stderr, "Failed to create RGB, double-buffered visual\n"); XCloseDisplay (dpy); free (gltc); return NULL; } ctx = glXCreateContext (dpy, visinfo, NULL, True); XFree (visinfo); gltc->ctx = ctx; gltc->device = cairo_glx_device_create (dpy, ctx); gltc->surface = surface = cairo_gl_surface_create (gltc->device, content, ceil (width), ceil (height)); if (cairo_surface_status (surface)) _cairo_boilerplate_gl_cleanup (gltc); return surface; }
static cairo_test_status_t draw (cairo_t *cr, int width, int height) { const cairo_test_context_t *ctx = cairo_test_get_context (cr); char *filename; FILE *file; cairo_surface_t *surface; cairo_status_t status; xasprintf (&filename, "%s/reference/%s", ctx->srcdir, "create-from-png-stream.ref.png"); file = fopen (filename, "rb"); if (file == NULL) { cairo_test_status_t ret; ret = CAIRO_TEST_FAILURE; if (errno == ENOMEM) ret = cairo_test_status_from_status (ctx, CAIRO_STATUS_NO_MEMORY); if (ret != CAIRO_TEST_NO_MEMORY) cairo_test_log (ctx, "Error: failed to open file: %s\n", filename); free (filename); return ret; } surface = cairo_image_surface_create_from_png_stream (read_png_from_file, file); fclose (file); status = cairo_surface_status (surface); if (status) { cairo_test_status_t ret; cairo_surface_destroy (surface); ret = cairo_test_status_from_status (ctx, status); if (ret != CAIRO_TEST_NO_MEMORY) { cairo_test_log (ctx, "Error: failed to create surface from PNG: %s - %s\n", filename, cairo_status_to_string (status)); } free (filename); return ret; } free (filename); /* Pretend we modify the surface data (which detaches the PNG mime data) */ cairo_surface_flush (surface); cairo_surface_mark_dirty (surface); cairo_set_source_surface (cr, surface, 0, 0); cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); cairo_paint (cr); cairo_surface_destroy (surface); return CAIRO_TEST_SUCCESS; }
static void redraw_handler(struct widget *widget, void *data) { struct fullscreen *fullscreen = data; struct rectangle allocation; cairo_surface_t *surface; cairo_t *cr; int i; double x, y, border; const char *method_name[] = { "default", "center", "zoom", "zoom_crop", "stretch"}; surface = window_get_surface(fullscreen->window); if (surface == NULL || cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { fprintf(stderr, "failed to create cairo egl surface\n"); return; } widget_get_allocation(fullscreen->widget, &allocation); cr = widget_cairo_create(widget); cairo_set_source_rgb(cr, 0, 0, 0); cairo_paint (cr); cairo_set_source_rgb(cr, 0, 0, 1); cairo_set_line_width (cr, 10); cairo_rectangle(cr, 5, 5, allocation.width - 10, allocation.height - 10); cairo_stroke (cr); cairo_move_to(cr, allocation.x + 15, allocation.y + 25); cairo_set_source_rgb(cr, 1, 1, 1); if (fullscreen->fshell) { draw_string(cr, "Surface size: %d, %d\n" "Scale: %d, transform: %d\n" "Pointer: %f,%f\n" "Output: %s, present method: %s\n" "Keys: (s)cale, (t)ransform, si(z)e, (m)ethod,\n" " (o)utput, modes(w)itch, (q)uit\n", fullscreen->width, fullscreen->height, window_get_buffer_scale (fullscreen->window), window_get_buffer_transform (fullscreen->window), fullscreen->pointer_x, fullscreen->pointer_y, method_name[fullscreen->present_method], fullscreen->current_output ? output_get_model(fullscreen->current_output->output): "null"); } else { draw_string(cr, "Surface size: %d, %d\n" "Scale: %d, transform: %d\n" "Pointer: %f,%f\n" "Fullscreen: %d\n" "Keys: (s)cale, (t)ransform, si(z)e, (f)ullscreen, (q)uit\n", fullscreen->width, fullscreen->height, window_get_buffer_scale (fullscreen->window), window_get_buffer_transform (fullscreen->window), fullscreen->pointer_x, fullscreen->pointer_y, fullscreen->fullscreen); } y = 100; i = 0; while (y + 60 < fullscreen->height) { border = (i++ % 2 == 0) ? 1 : 0.5; x = 50; cairo_set_line_width (cr, border); while (x + 70 < fullscreen->width) { if (window_has_focus(fullscreen->window) && fullscreen->pointer_x >= x && fullscreen->pointer_x < x + 50 && fullscreen->pointer_y >= y && fullscreen->pointer_y < y + 40) { cairo_set_source_rgb(cr, 1, 0, 0); cairo_rectangle(cr, x, y, 50, 40); cairo_fill(cr); } cairo_set_source_rgb(cr, 0, 1, 0); cairo_rectangle(cr, x + border/2.0, y + border/2.0, 50, 40); cairo_stroke(cr); x += 60; } y += 50; } if (window_has_focus(fullscreen->window) && fullscreen->draw_cursor) { cairo_set_source_rgb(cr, 1, 1, 1); cairo_set_line_width (cr, 8); cairo_move_to(cr, fullscreen->pointer_x - 12, fullscreen->pointer_y - 12); cairo_line_to(cr, fullscreen->pointer_x + 12, fullscreen->pointer_y + 12); cairo_stroke(cr); cairo_move_to(cr, fullscreen->pointer_x + 12, fullscreen->pointer_y - 12); cairo_line_to(cr, fullscreen->pointer_x - 12, fullscreen->pointer_y + 12); cairo_stroke(cr); cairo_set_source_rgb(cr, 0, 0, 0); cairo_set_line_width (cr, 4); cairo_move_to(cr, fullscreen->pointer_x - 10, fullscreen->pointer_y - 10); cairo_line_to(cr, fullscreen->pointer_x + 10, fullscreen->pointer_y + 10); cairo_stroke(cr); cairo_move_to(cr, fullscreen->pointer_x + 10, fullscreen->pointer_y - 10); cairo_line_to(cr, fullscreen->pointer_x - 10, fullscreen->pointer_y + 10); cairo_stroke(cr); } cairo_destroy(cr); }
static cairo_test_status_t preamble (cairo_test_context_t *ctx) { char *filename; cairo_surface_t *surface; cairo_status_t status; cairo_test_status_t result = CAIRO_TEST_SUCCESS; surface = cairo_image_surface_create_from_png ("___THIS_FILE_DOES_NOT_EXIST___"); if (cairo_surface_status (surface) != CAIRO_STATUS_FILE_NOT_FOUND) { result = cairo_test_status_from_status (ctx, cairo_surface_status (surface)); if (result == CAIRO_TEST_FAILURE) { cairo_test_log (ctx, "Error: expected \"file not found\", but got: %s\n", cairo_status_to_string (cairo_surface_status (surface))); } } cairo_surface_destroy (surface); if (result != CAIRO_TEST_SUCCESS) return result; surface = cairo_image_surface_create_from_png_stream (no_memory_error, NULL); if (cairo_surface_status (surface) != CAIRO_STATUS_NO_MEMORY) { result = cairo_test_status_from_status (ctx, cairo_surface_status (surface)); if (result == CAIRO_TEST_FAILURE) { cairo_test_log (ctx, "Error: expected \"out of memory\", but got: %s\n", cairo_status_to_string (cairo_surface_status (surface))); } } cairo_surface_destroy (surface); if (result != CAIRO_TEST_SUCCESS) return result; surface = cairo_image_surface_create_from_png_stream (read_error, NULL); if (cairo_surface_status (surface) != CAIRO_STATUS_READ_ERROR) { result = cairo_test_status_from_status (ctx, cairo_surface_status (surface)); if (result == CAIRO_TEST_FAILURE) { cairo_test_log (ctx, "Error: expected \"read error\", but got: %s\n", cairo_status_to_string (cairo_surface_status (surface))); } } cairo_surface_destroy (surface); if (result != CAIRO_TEST_SUCCESS) return result; /* cheekily test error propagation from the user write funcs as well ... */ xasprintf (&filename, "%s/%s", ctx->srcdir, "create-from-png.ref.png"); surface = cairo_image_surface_create_from_png (filename); if (cairo_surface_status (surface)) { result = cairo_test_status_from_status (ctx, cairo_surface_status (surface)); if (result == CAIRO_TEST_FAILURE) { cairo_test_log (ctx, "Error reading PNG image %s: %s\n", filename, cairo_status_to_string (cairo_surface_status (surface))); } } else { status = cairo_surface_write_to_png_stream (surface, (cairo_write_func_t) no_memory_error, NULL); if (status != CAIRO_STATUS_NO_MEMORY) { result = cairo_test_status_from_status (ctx, status); if (result == CAIRO_TEST_FAILURE) { cairo_test_log (ctx, "Error: expected \"out of memory\", but got: %s\n", cairo_status_to_string (status)); } } status = cairo_surface_write_to_png_stream (surface, (cairo_write_func_t) read_error, NULL); if (status != CAIRO_STATUS_READ_ERROR) { result = cairo_test_status_from_status (ctx, status); if (result == CAIRO_TEST_FAILURE) { cairo_test_log (ctx, "Error: expected \"read error\", but got: %s\n", cairo_status_to_string (status)); } } /* and check that error has not propagated to the surface */ if (cairo_surface_status (surface)) { result = cairo_test_status_from_status (ctx, cairo_surface_status (surface)); if (result == CAIRO_TEST_FAILURE) { cairo_test_log (ctx, "Error: user write error propagated to surface: %s", cairo_status_to_string (cairo_surface_status (surface))); } } } cairo_surface_destroy (surface); free (filename); if (result != CAIRO_TEST_SUCCESS) return result; /* check that loading alpha/opaque PNGs generate the correct surfaces */ xasprintf (&filename, "%s/%s", ctx->srcdir, "create-from-png.alpha.ref.png"); surface = cairo_image_surface_create_from_png (filename); if (cairo_surface_status (surface)) { result = cairo_test_status_from_status (ctx, cairo_surface_status (surface)); if (result == CAIRO_TEST_FAILURE) { cairo_test_log (ctx, "Error reading PNG image %s: %s\n", filename, cairo_status_to_string (cairo_surface_status (surface))); } } else if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_ARGB32) { cairo_test_log (ctx, "Error reading PNG image %s: did not create an ARGB32 image\n", filename); result = CAIRO_TEST_FAILURE; } free (filename); cairo_surface_destroy (surface); if (result != CAIRO_TEST_SUCCESS) return result; xasprintf (&filename, "%s/%s", ctx->srcdir, "create-from-png.ref.png"); surface = cairo_image_surface_create_from_png (filename); if (cairo_surface_status (surface)) { result = cairo_test_status_from_status (ctx, cairo_surface_status (surface)); if (result == CAIRO_TEST_FAILURE) { cairo_test_log (ctx, "Error reading PNG image %s: %s\n", filename, cairo_status_to_string (cairo_surface_status (surface))); } } else if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_RGB24) { cairo_test_log (ctx, "Error reading PNG image %s: did not create an RGB24 image\n", filename); result = CAIRO_TEST_FAILURE; } free (filename); cairo_surface_destroy (surface); if (result != CAIRO_TEST_SUCCESS) return result; /* check paletted PNGs */ xasprintf (&filename, "%s/%s", ctx->srcdir, "create-from-png.indexed-alpha.ref.png"); surface = cairo_image_surface_create_from_png (filename); if (cairo_surface_status (surface)) { result = cairo_test_status_from_status (ctx, cairo_surface_status (surface)); if (result == CAIRO_TEST_FAILURE) { cairo_test_log (ctx, "Error reading PNG image %s: %s\n", filename, cairo_status_to_string (cairo_surface_status (surface))); } } else if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_ARGB32) { cairo_test_log (ctx, "Error reading PNG image %s: did not create an ARGB32 image\n", filename); result = CAIRO_TEST_FAILURE; } free (filename); cairo_surface_destroy (surface); if (result != CAIRO_TEST_SUCCESS) return result; xasprintf (&filename, "%s/%s", ctx->srcdir, "create-from-png.indexed.ref.png"); surface = cairo_image_surface_create_from_png (filename); if (cairo_surface_status (surface)) { result = cairo_test_status_from_status (ctx, cairo_surface_status (surface)); if (result == CAIRO_TEST_FAILURE) { cairo_test_log (ctx, "Error reading PNG image %s: %s\n", filename, cairo_status_to_string (cairo_surface_status (surface))); } } else if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_RGB24) { cairo_test_log (ctx, "Error reading PNG image %s: did not create an RGB24 image\n", filename); result = CAIRO_TEST_FAILURE; } free (filename); cairo_surface_destroy (surface); if (result != CAIRO_TEST_SUCCESS) return result; /* check grayscale PNGs */ xasprintf (&filename, "%s/%s", ctx->srcdir, "create-from-png.gray-alpha.ref.png"); surface = cairo_image_surface_create_from_png (filename); if (cairo_surface_status (surface)) { result = cairo_test_status_from_status (ctx, cairo_surface_status (surface)); if (result == CAIRO_TEST_FAILURE) { cairo_test_log (ctx, "Error reading PNG image %s: %s\n", filename, cairo_status_to_string (cairo_surface_status (surface))); } } else if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_ARGB32) { cairo_test_log (ctx, "Error reading PNG image %s: did not create an ARGB32 image\n", filename); result = CAIRO_TEST_FAILURE; } free (filename); cairo_surface_destroy (surface); if (result != CAIRO_TEST_SUCCESS) return result; xasprintf (&filename, "%s/%s", ctx->srcdir, "create-from-png.gray.ref.png"); surface = cairo_image_surface_create_from_png (filename); if (cairo_surface_status (surface)) { result = cairo_test_status_from_status (ctx, cairo_surface_status (surface)); if (result == CAIRO_TEST_FAILURE) { cairo_test_log (ctx, "Error reading PNG image %s: %s\n", filename, cairo_status_to_string (cairo_surface_status (surface))); } } else if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_RGB24) { cairo_test_log (ctx, "Error reading PNG image %s: did not create an RGB24 image\n", filename); result = CAIRO_TEST_FAILURE; } free (filename); cairo_surface_destroy (surface); return result; }
static void cairogen_begin_page(GVJ_t * job) { cairo_t *cr = (cairo_t *) job->context; cairo_surface_t *surface; cairo_status_t status; if (cr == NULL) { switch (job->render.id) { case FORMAT_PS: #ifdef CAIRO_HAS_PS_SURFACE surface = cairo_ps_surface_create_for_stream (writer, job, job->width, job->height); #endif break; case FORMAT_PDF: #ifdef CAIRO_HAS_PDF_SURFACE surface = cairo_pdf_surface_create_for_stream (writer, job, job->width, job->height); #endif break; case FORMAT_SVG: #ifdef CAIRO_HAS_SVG_SURFACE surface = cairo_svg_surface_create_for_stream (writer, job, job->width, job->height); #endif break; case FORMAT_CAIRO: case FORMAT_PNG: default: if (job->width >= CAIRO_XMAX || job->height >= CAIRO_YMAX) { double scale = MIN((double)CAIRO_XMAX / job->width, (double)CAIRO_YMAX / job->height); job->width *= scale; job->height *= scale; job->scale.x *= scale; job->scale.y *= scale; fprintf(stderr, "%s: graph is too large for cairo-renderer bitmaps. Scaling by %g to fit\n", job->common->cmdname, scale); } surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, job->width, job->height); if (job->common->verbose) fprintf(stderr, "%s: allocating a %dK cairo image surface (%d x %d pixels)\n", job->common->cmdname, ROUND(job->width * job->height * 4 / 1024.), job->width, job->height); break; } status = cairo_surface_status(surface); if (status != CAIRO_STATUS_SUCCESS) { fprintf(stderr, "%s: failure to create cairo surface: %s\n", job->common->cmdname, cairo_status_to_string(status)); cairo_surface_destroy (surface); return; } cr = cairo_create(surface); cairo_surface_destroy (surface); job->context = (void *) cr; } cairo_scale(cr, job->scale.x, job->scale.y); cairo_rotate(cr, -job->rotation * M_PI / 180.); cairo_translate(cr, job->translation.x, -job->translation.y); cairo_rectangle(cr, job->clip.LL.x, - job->clip.LL.y, job->clip.UR.x - job->clip.LL.x, - (job->clip.UR.y - job->clip.LL.y)); cairo_clip(cr); /* cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); */ }
void setup_tile (gint w, gint h) { cairo_status_t status; cairo_t* cr = NULL; cairo_surface_t* cr_surf = NULL; cairo_surface_t* tmp = NULL; cairo_surface_t* dummy_surf = NULL; cairo_surface_t* norm_surf = NULL; cairo_surface_t* blur_surf = NULL; gdouble width = (gdouble) w; gdouble height = (gdouble) h; raico_blur_t* blur = NULL; cr_surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 3 * BUBBLE_SHADOW_SIZE, 3 * BUBBLE_SHADOW_SIZE); status = cairo_surface_status (cr_surf); if (status != CAIRO_STATUS_SUCCESS) g_print ("Error: \"%s\"\n", cairo_status_to_string (status)); cr = cairo_create (cr_surf); status = cairo_status (cr); if (status != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy (cr_surf); g_print ("Error: \"%s\"\n", cairo_status_to_string (status)); } // clear and render drop-shadow and bubble-background cairo_scale (cr, 1.0f, 1.0f); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); if (g_composited) { draw_shadow (cr, width, height, BUBBLE_SHADOW_SIZE, CORNER_RADIUS); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); draw_round_rect (cr, 1.0f, (gdouble) BUBBLE_SHADOW_SIZE, (gdouble) BUBBLE_SHADOW_SIZE, (gdouble) CORNER_RADIUS, (gdouble) (width - 2.0f * BUBBLE_SHADOW_SIZE), (gdouble) (height - 2.0f* BUBBLE_SHADOW_SIZE)); cairo_fill (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_set_source_rgba (cr, BUBBLE_BG_COLOR_R, BUBBLE_BG_COLOR_G, BUBBLE_BG_COLOR_B, 0.95f); } else cairo_set_source_rgb (cr, BUBBLE_BG_COLOR_R, BUBBLE_BG_COLOR_G, BUBBLE_BG_COLOR_B); draw_round_rect (cr, 1.0f, BUBBLE_SHADOW_SIZE, BUBBLE_SHADOW_SIZE, CORNER_RADIUS, (gdouble) (width - 2.0f * BUBBLE_SHADOW_SIZE), (gdouble) (height - 2.0f * BUBBLE_SHADOW_SIZE)); cairo_fill (cr); tmp = cairo_image_surface_create_for_data ( cairo_image_surface_get_data (cr_surf), cairo_image_surface_get_format (cr_surf), 3 * BUBBLE_SHADOW_SIZE, 3 * BUBBLE_SHADOW_SIZE, cairo_image_surface_get_stride (cr_surf)); dummy_surf = copy_surface (tmp); cairo_surface_destroy (tmp); tmp = cairo_image_surface_create_for_data ( cairo_image_surface_get_data (dummy_surf), cairo_image_surface_get_format (dummy_surf), 2 * BUBBLE_SHADOW_SIZE, 2 * BUBBLE_SHADOW_SIZE, cairo_image_surface_get_stride (dummy_surf)); norm_surf = copy_surface (tmp); cairo_surface_destroy (tmp); blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW); raico_blur_set_radius (blur, 6); raico_blur_apply (blur, dummy_surf); raico_blur_destroy (blur); tmp = cairo_image_surface_create_for_data ( cairo_image_surface_get_data (dummy_surf), cairo_image_surface_get_format (dummy_surf), 2 * BUBBLE_SHADOW_SIZE, 2 * BUBBLE_SHADOW_SIZE, cairo_image_surface_get_stride (dummy_surf)); blur_surf = copy_surface (tmp); cairo_surface_destroy (tmp); cairo_surface_destroy (dummy_surf); g_tile = tile_new_for_padding (norm_surf, blur_surf); cairo_surface_destroy (norm_surf); cairo_surface_destroy (blur_surf); cairo_surface_destroy (cr_surf); cairo_destroy (cr); }
#include <cairo-pdf.h> #include <cairo-ps.h> #include <cairo-svg.h> #include "c_surface.h" BEGIN_METHOD_VOID(CairoSurface_free) GB.FreeString(&THIS->path); cairo_surface_destroy(THIS->surface); END_METHOD BEGIN_PROPERTY(CairoSurface_Status) GB.ReturnInteger(cairo_surface_status(THIS->surface)); END_PROPERTY BEGIN_PROPERTY(CairoSurface_Path) GB.ReturnString(THIS->path); END_PROPERTY BEGIN_METHOD(CairoSurface_Save, GB_STRING path) GB.ReturnInteger(cairo_surface_write_to_png(THIS->surface, GB.FileName(STRING(path), LENGTH(path)))); END_METHOD
static Eina_Bool _ewk_view_single_smart_repaints_process(Ewk_View_Smart_Data *sd) { Ewk_View_Paint_Context *ctxt; Evas_Coord ow, oh; void *pixels; Eina_Rectangle r = {0, 0, 0, 0}; const Eina_Rectangle *pr; const Eina_Rectangle *pr_end; Eina_Tiler *tiler; Eina_Iterator *itr; cairo_status_t status; cairo_surface_t *surface; cairo_format_t format; cairo_t *cairo; size_t count; Eina_Bool ret = EINA_TRUE; if (sd->animated_zoom.zoom.current < 0.00001) { Evas_Object *clip = evas_object_clip_get(sd->backing_store); Evas_Coord w, h, cw, ch; // reset effects of zoom_weak_set() evas_object_image_fill_set (sd->backing_store, 0, 0, sd->view.w, sd->view.h); evas_object_move(clip, sd->view.x, sd->view.y); w = sd->view.w; h = sd->view.h; ewk_frame_contents_size_get(sd->main_frame, &cw, &ch); if (w > cw) w = cw; if (h > ch) h = ch; evas_object_resize(clip, w, h); } pixels = evas_object_image_data_get(sd->backing_store, 1); evas_object_image_size_get(sd->backing_store, &ow, &oh); if (sd->bg_color.a < 255) format = CAIRO_FORMAT_ARGB32; else format = CAIRO_FORMAT_RGB24; surface = cairo_image_surface_create_for_data ((unsigned char*)pixels, format, ow, oh, ow * 4); status = cairo_surface_status(surface); if (status != CAIRO_STATUS_SUCCESS) { ERR("could not create surface from data %dx%d: %s", ow, oh, cairo_status_to_string(status)); ret = EINA_FALSE; goto error_cairo_surface; } cairo = cairo_create(surface); status = cairo_status(cairo); if (status != CAIRO_STATUS_SUCCESS) { ERR("could not create cairo from surface %dx%d: %s", ow, oh, cairo_status_to_string(status)); ret = EINA_FALSE; goto error_cairo; } ctxt = ewk_view_paint_context_new(sd->_priv, cairo); if (!ctxt) { ERR("could not create paint context"); ret = EINA_FALSE; goto error_paint_context; } tiler = eina_tiler_new(ow, oh); if (!tiler) { ERR("could not create tiler %dx%d", ow, oh); ret = EINA_FALSE; goto error_tiler; } pr = ewk_view_repaints_get(sd->_priv, &count); pr_end = pr + count; for (; pr < pr_end; pr++) eina_tiler_rect_add(tiler, pr); itr = eina_tiler_iterator_new(tiler); if (!itr) { ERR("could not get iterator for tiler"); ret = EINA_FALSE; goto error_iterator; } int sx, sy; ewk_frame_scroll_pos_get(sd->main_frame, &sx, &sy); EINA_ITERATOR_FOREACH(itr, r) { Eina_Rectangle scrolled_rect = { r.x + sx, r.y + sy, r.w, r.h }; ewk_view_paint_context_save(ctxt); if ((sx) || (sy)) ewk_view_paint_context_translate(ctxt, -sx, -sy); ewk_view_paint_context_clip(ctxt, &scrolled_rect); ewk_view_paint_context_paint_contents(ctxt, &scrolled_rect); ewk_view_paint_context_restore(ctxt); evas_object_image_data_update_add (sd->backing_store, r.x, r.y, r.w, r.h); }
static void set_source_pixbuf(cairo_t *cr, const GdkPixbuf *pixbuf, double src_x, double src_y, double src_width, double src_height) { gint width = gdk_pixbuf_get_width (pixbuf); gint height = gdk_pixbuf_get_height (pixbuf); guchar *gdk_pixels = gdk_pixbuf_get_pixels (pixbuf); int gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf); int n_channels = gdk_pixbuf_get_n_channels (pixbuf); int cairo_stride; guchar *cairo_pixels; cairo_format_t format; cairo_surface_t *surface; int j; if (n_channels == 3) format = CAIRO_FORMAT_RGB24; else format = CAIRO_FORMAT_ARGB32; surface = cairo_image_surface_create(format, width, height); if (cairo_surface_status(surface)) { cairo_set_source_surface(cr, surface, 0, 0); return; } cairo_stride = cairo_image_surface_get_stride(surface); cairo_pixels = cairo_image_surface_get_data(surface); for (j = height; j; j--) { guchar *p = gdk_pixels; guchar *q = cairo_pixels; if (n_channels == 3) { guchar *end = p + 3 * width; while (p < end) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN q[0] = p[2]; q[1] = p[1]; q[2] = p[0]; #else q[1] = p[0]; q[2] = p[1]; q[3] = p[2]; #endif p += 3; q += 4; } } else { guchar *end = p + 4 * width; guint t1,t2,t3; #define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END while (p < end) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN MULT(q[0], p[2], p[3], t1); MULT(q[1], p[1], p[3], t2); MULT(q[2], p[0], p[3], t3); q[3] = p[3]; #else q[0] = p[3]; MULT(q[1], p[0], p[3], t1); MULT(q[2], p[1], p[3], t2); MULT(q[3], p[2], p[3], t3); #endif p += 4; q += 4; } #undef MULT } gdk_pixels += gdk_rowstride; cairo_pixels += cairo_stride; } cairo_surface_mark_dirty(surface); cairo_set_source_surface(cr, surface, src_x + .5 * (src_width - width), src_y + .5 * (src_height - height)); cairo_surface_destroy(surface); }
cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf(const GdkPixbuf *gdkbuf) { int chan = gdk_pixbuf_get_n_channels(gdkbuf); if (chan < 3) return NULL; #if GDK_PIXBUF_CHECK_VERSION(2,32,0) const guint8* gdkpix = gdk_pixbuf_read_pixels(gdkbuf); #else const guint8* gdkpix = gdk_pixbuf_get_pixels(gdkbuf); #endif if (!gdkpix) { return NULL; } gint w = gdk_pixbuf_get_width(gdkbuf); gint h = gdk_pixbuf_get_height(gdkbuf); int stride = gdk_pixbuf_get_rowstride(gdkbuf); cairo_format_t fmt = (chan == 3) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32; cairo_surface_t * cs = cairo_image_surface_create (fmt, w, h); cairo_surface_flush (cs); if ( !cs || cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) { return NULL; } int cstride = cairo_image_surface_get_stride(cs); unsigned char * cpix = cairo_image_surface_get_data(cs); if (chan == 3) { int i; for (i = h; i; --i) { const guint8 *gp = gdkpix; unsigned char *cp = cpix; const guint8* end = gp + 3*w; while (gp < end) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN cp[0] = gp[2]; cp[1] = gp[1]; cp[2] = gp[0]; #else cp[1] = gp[0]; cp[2] = gp[1]; cp[3] = gp[2]; #endif gp += 3; cp += 4; } gdkpix += stride; cpix += cstride; } } else { /* premul-color = alpha/255 * color/255 * 255 = (alpha*color)/255 * (z/255) = z/256 * 256/255 = z/256 (1 + 1/255) * = z/256 + (z/256)/255 = (z + z/255)/256 * # recurse once * = (z + (z + z/255)/256)/256 * = (z + z/256 + z/256/255) / 256 * # only use 16bit uint operations, loose some precision, * # result is floored. * -> (z + z>>8)>>8 * # add 0x80/255 = 0.5 to convert floor to round * => (z+0x80 + (z+0x80)>>8 ) >> 8 * ------ * tested as equal to lround(z/255.0) for uint z in [0..0xfe02] */ #define PREMUL_ALPHA(x,a,b,z) G_STMT_START { z = a * b + 0x80; x = (z + (z >> 8)) >> 8; } G_STMT_END int i; for (i = h; i; --i) { const guint8 *gp = gdkpix; unsigned char *cp = cpix; const guint8* end = gp + 4*w; guint z1, z2, z3; while (gp < end) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN PREMUL_ALPHA(cp[0], gp[2], gp[3], z1); PREMUL_ALPHA(cp[1], gp[1], gp[3], z2); PREMUL_ALPHA(cp[2], gp[0], gp[3], z3); cp[3] = gp[3]; #else PREMUL_ALPHA(cp[1], gp[0], gp[3], z1); PREMUL_ALPHA(cp[2], gp[1], gp[3], z2); PREMUL_ALPHA(cp[3], gp[2], gp[3], z3); cp[0] = gp[3]; #endif gp += 4; cp += 4; } gdkpix += stride; cpix += cstride; } #undef PREMUL_ALPHA } cairo_surface_mark_dirty(cs); return cs; }
static cairo_surface_t * print_surface_from_drawable (gint32 drawable_ID, GError **error) { GeglBuffer *buffer = gimp_drawable_get_buffer (drawable_ID); const Babl *format; cairo_surface_t *surface; cairo_status_t status; const gint width = gimp_drawable_width (drawable_ID); const gint height = gimp_drawable_height (drawable_ID); GeglBufferIterator *iter; guchar *pixels; gint stride; guint count = 0; guint done = 0; if (gimp_drawable_has_alpha (drawable_ID)) format = babl_format ("cairo-ARGB32"); else format = babl_format ("cairo-RGB24"); surface = cairo_image_surface_create (gimp_drawable_has_alpha (drawable_ID) ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, width, height); status = cairo_surface_status (surface); if (status != CAIRO_STATUS_SUCCESS) { switch (status) { case CAIRO_STATUS_INVALID_SIZE: g_set_error_literal (error, GIMP_PLUGIN_PRINT_ERROR, GIMP_PLUGIN_PRINT_ERROR_FAILED, _("Cannot handle the size (either width or height) of the image.")); break; default: g_set_error (error, GIMP_PLUGIN_PRINT_ERROR, GIMP_PLUGIN_PRINT_ERROR_FAILED, "Cairo error: %s", cairo_status_to_string (status)); break; } return NULL; } pixels = cairo_image_surface_get_data (surface); stride = cairo_image_surface_get_stride (surface); iter = gegl_buffer_iterator_new (buffer, GEGL_RECTANGLE (0, 0, width, height), 0, format, GEGL_BUFFER_READ, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { const guchar *src = iter->data[0]; guchar *dest = pixels + iter->roi->y * stride + iter->roi->x * 4; gint y; for (y = 0; y < iter->roi->height; y++) { memcpy (dest, src, iter->roi->width * 4); src += iter->roi->width * 4; dest += stride; } done += iter->roi->height * iter->roi->width; if (count++ % 16 == 0) gimp_progress_update ((gdouble) done / (width * height)); } g_object_unref (buffer); cairo_surface_mark_dirty (surface); gimp_progress_update (1.0); return surface; }
cairo_test_similar_t cairo_test_target_has_similar (const cairo_test_context_t *ctx, const cairo_boilerplate_target_t *target) { cairo_surface_t *surface; cairo_test_similar_t has_similar; cairo_t * cr; cairo_surface_t *similar; cairo_status_t status; void *closure; char *path; /* ignore image intermediate targets */ if (target->expected_type == CAIRO_SURFACE_TYPE_IMAGE) return DIRECT; if (getenv ("CAIRO_TEST_IGNORE_SIMILAR")) return DIRECT; xasprintf (&path, "%s/%s", _cairo_test_mkdir (ctx->output) ? ctx->output : ".", ctx->test_name); has_similar = DIRECT; do { do { surface = (target->create_surface) (path, target->content, ctx->test->width, ctx->test->height, ctx->test->width + 25 * NUM_DEVICE_OFFSETS, ctx->test->height + 25 * NUM_DEVICE_OFFSETS, CAIRO_BOILERPLATE_MODE_TEST, &closure); if (surface == NULL) goto out; } while (cairo_test_malloc_failure (ctx, cairo_surface_status (surface))); if (cairo_surface_status (surface)) goto out; cr = cairo_create (surface); cairo_push_group_with_content (cr, cairo_boilerplate_content (target->content)); similar = cairo_get_group_target (cr); status = cairo_surface_status (similar); if (cairo_surface_get_type (similar) == cairo_surface_get_type (surface)) has_similar = SIMILAR; else has_similar = DIRECT; cairo_destroy (cr); cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); } while (! has_similar && cairo_test_malloc_failure (ctx, status)); out: free (path); return has_similar; }
void gui_init(dt_lib_module_t *self) { char filename[PATH_MAX] = { 0 }; char datadir[PATH_MAX] = { 0 }; /* initialize ui widgets */ dt_lib_darktable_t *d = (dt_lib_darktable_t *)g_malloc0(sizeof(dt_lib_darktable_t)); self->data = (void *)d; /* create drawing area */ self->widget = gtk_event_box_new(); /* connect callbacks */ g_signal_connect(G_OBJECT(self->widget), "draw", G_CALLBACK(_lib_darktable_draw_callback), self); g_signal_connect(G_OBJECT(self->widget), "button-press-event", G_CALLBACK(_lib_darktable_button_press_callback), self); /* create a cairo surface of dt icon */ char *logo; dt_logo_season_t season = get_logo_season(); if(season != DT_LOGO_SEASON_NONE) logo = g_strdup_printf("%%s/pixmaps/idbutton-%d.%%s", (int)season); else logo = g_strdup("%s/pixmaps/idbutton.%s"); dt_loc_get_datadir(datadir, sizeof(datadir)); snprintf(filename, sizeof(filename), logo, datadir, "svg"); // first we try the SVG { GError *error = NULL; RsvgHandle *svg = rsvg_handle_new_from_file(filename, &error); if(!svg || error) { fprintf(stderr, "warning: can't load darktable logo from SVG file `%s', falling back to PNG version\n%s\n", filename, error->message); g_error_free(error); error = NULL; goto png_fallback; } cairo_surface_t *surface; cairo_t *cr; RsvgDimensionData dimension; rsvg_handle_get_dimensions(svg, &dimension); int width = DT_PIXEL_APPLY_DPI(dimension.width) * darktable.gui->ppd, height = DT_PIXEL_APPLY_DPI(dimension.height) * darktable.gui->ppd; int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); d->image_buffer = (guint8 *)calloc(stride * height, sizeof(guint8)); surface = dt_cairo_image_surface_create_for_data(d->image_buffer, CAIRO_FORMAT_ARGB32, width, height, stride); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { free(d->image_buffer); d->image_buffer = NULL; g_object_unref(svg); fprintf(stderr, "warning: can't load darktable logo from SVG file `%s', falling back to PNG version\n", filename); goto png_fallback; } cr = cairo_create(surface); cairo_scale(cr, darktable.gui->dpi_factor, darktable.gui->dpi_factor); rsvg_handle_render_cairo(svg, cr); cairo_destroy(cr); cairo_surface_flush(surface); d->image = surface; g_object_unref(svg); } goto done; png_fallback: // let's fall back to the PNG { cairo_surface_t *surface; cairo_t *cr; snprintf(filename, sizeof(filename), logo, datadir, "png"); surface = cairo_image_surface_create_from_png(filename); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { fprintf(stderr, "warning: can't load darktable logo from PNG file `%s'\n", filename); d->image = NULL; goto done; } int png_width = cairo_image_surface_get_width(surface), png_height = cairo_image_surface_get_height(surface); // blow up the PNG. Ugly, but at least it has the correct size afterwards :-/ int width = DT_PIXEL_APPLY_DPI(png_width) * darktable.gui->ppd, height = DT_PIXEL_APPLY_DPI(png_height) * darktable.gui->ppd; int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); d->image_buffer = (guint8 *)calloc(stride * height, sizeof(guint8)); d->image = dt_cairo_image_surface_create_for_data(d->image_buffer, CAIRO_FORMAT_ARGB32, width, height, stride); if(cairo_surface_status(d->image) != CAIRO_STATUS_SUCCESS) { free(d->image_buffer); d->image_buffer = NULL; cairo_surface_destroy(surface); fprintf(stderr, "warning: can't load darktable logo from PNG file `%s'\n", filename); d->image = NULL; goto done; } cr = cairo_create(d->image); cairo_rectangle(cr, 0, 0, width, height); cairo_scale(cr, darktable.gui->dpi_factor, darktable.gui->dpi_factor); cairo_set_source_surface(cr, surface, 0, 0); cairo_fill(cr); cairo_destroy(cr); cairo_surface_flush(d->image); cairo_surface_destroy(surface); } done: g_free(logo); d->image_width = d->image ? dt_cairo_image_surface_get_width(d->image) : 0; d->image_height = d->image ? dt_cairo_image_surface_get_height(d->image) : 0; /* set size of drawing area */ gtk_widget_set_size_request(self->widget, d->image_width + (int)DT_PIXEL_APPLY_DPI(180), d->image_height + (int)DT_PIXEL_APPLY_DPI(8)); }
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; }
// maybe this should be (partly) in common/imageio.[c|h]? static void _lib_import_update_preview(GtkFileChooser *file_chooser, gpointer data) { GtkWidget *preview; char *filename; GdkPixbuf *pixbuf = NULL; gboolean have_preview = FALSE, no_preview_fallback = FALSE; preview = GTK_WIDGET(data); filename = gtk_file_chooser_get_preview_filename(file_chooser); if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { no_preview_fallback = TRUE; } else { // don't create dng thumbnails to avoid crashes in libtiff when these are hdr: char *c = filename + strlen(filename); while(c > filename && *c != '.') c--; if(!strcasecmp(c, ".dng")) no_preview_fallback = TRUE; } // unfortunately we can not use following, because frequently it uses wrong orientation // pixbuf = gdk_pixbuf_new_from_file_at_size(filename, 128, 128, NULL); have_preview = (pixbuf != NULL); if(!have_preview && !no_preview_fallback) { uint8_t *buffer = NULL; size_t size; char *mime_type = NULL; if(!dt_exif_get_thumbnail(filename, &buffer, &size, &mime_type)) { // Scale the image to the correct size GdkPixbuf *tmp; GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); if (!gdk_pixbuf_loader_write(loader, buffer, size, NULL)) goto cleanup; if (!(tmp = gdk_pixbuf_loader_get_pixbuf(loader))) goto cleanup; float ratio = 1.0 * gdk_pixbuf_get_height(tmp) / gdk_pixbuf_get_width(tmp); int width = 128, height = 128 * ratio; pixbuf = gdk_pixbuf_scale_simple(tmp, width, height, GDK_INTERP_BILINEAR); have_preview = TRUE; cleanup: gdk_pixbuf_loader_close(loader, NULL); free(mime_type); free(buffer); g_object_unref(loader); // This should clean up tmp as well } } if(have_preview && !no_preview_fallback) { // get image orientation dt_image_t img = { 0 }; (void)dt_exif_read(&img, filename); // Rotate the image to the correct orientation GdkPixbuf *tmp = pixbuf; if(img.orientation == ORIENTATION_ROTATE_CCW_90_DEG) { tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE); } else if(img.orientation == ORIENTATION_ROTATE_CW_90_DEG) { tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE); } else if(img.orientation == ORIENTATION_ROTATE_180_DEG) { tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN); } if(pixbuf != tmp) { g_object_unref(pixbuf); pixbuf = tmp; } } if(no_preview_fallback || !have_preview) { /* load the dt logo as a brackground */ char dtlogo[PATH_MAX] = { 0 }; char datadir[PATH_MAX] = { 0 }; char *logo; dt_logo_season_t season = get_logo_season(); if(season != DT_LOGO_SEASON_NONE) logo = g_strdup_printf("%%s/pixmaps/idbutton-%d.svg", (int)season); else logo = g_strdup("%s/pixmaps/idbutton.svg"); dt_loc_get_datadir(datadir, sizeof(datadir)); snprintf(dtlogo, sizeof(dtlogo), logo, datadir); g_free(logo); RsvgHandle *svg = rsvg_handle_new_from_file(dtlogo, NULL); if(svg) { cairo_surface_t *surface; cairo_t *cr; RsvgDimensionData dimension; rsvg_handle_get_dimensions(svg, &dimension); float svg_size = MAX(dimension.width, dimension.height); float final_size = 128; float factor = final_size / svg_size; float final_width = dimension.width * factor * darktable.gui->ppd, final_height = dimension.height * factor * darktable.gui->ppd; int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, final_width); guint8 *image_buffer = (guint8 *)calloc(stride * final_height, sizeof(guint8)); surface = dt_cairo_image_surface_create_for_data(image_buffer, CAIRO_FORMAT_ARGB32, final_width, final_height, stride); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { free(image_buffer); image_buffer = NULL; } else { cr = cairo_create(surface); cairo_scale(cr, factor, factor); rsvg_handle_render_cairo(svg, cr); cairo_destroy(cr); cairo_surface_flush(surface); pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, final_width / darktable.gui->ppd, final_height / darktable.gui->ppd); cairo_surface_destroy(surface); free(image_buffer); } g_object_unref(svg); } have_preview = TRUE; } if(have_preview) gtk_image_set_from_pixbuf(GTK_IMAGE(preview), pixbuf); if(pixbuf) g_object_unref(pixbuf); g_free(filename); gtk_file_chooser_set_preview_widget_active(file_chooser, have_preview); }
static cairo_status_t png_diff (const char *filename_a, const char *filename_b, const char *filename_diff, int ax, int ay, int bx, int by, buffer_diff_result_t *result) { cairo_surface_t *surface_a; cairo_surface_t *surface_b; cairo_surface_t *surface_diff; cairo_status_t status; surface_a = cairo_image_surface_create_from_png (filename_a); status = cairo_surface_status (surface_a); if (status) { fprintf (stderr, "Error: Failed to create surface from %s: %s\n", filename_a, cairo_status_to_string (status)); return status; } surface_b = cairo_image_surface_create_from_png (filename_b); status = cairo_surface_status (surface_b); if (status) { fprintf (stderr, "Error: Failed to create surface from %s: %s\n", filename_b, cairo_status_to_string (status)); cairo_surface_destroy (surface_a); return status; } if (ax || ay) { extract_sub_surface (&surface_a, ax, ay); ax = ay = 0; } if (bx || by) { extract_sub_surface (&surface_b, bx, by); bx = by = 0; } status = cairo_surface_status (surface_a); if (status) { fprintf (stderr, "Error: Failed to extract surface from %s: %s\n", filename_a, cairo_status_to_string (status)); cairo_surface_destroy (surface_a); cairo_surface_destroy (surface_b); return status; } status = cairo_surface_status (surface_b); if (status) { fprintf (stderr, "Error: Failed to extract surface from %s: %s\n", filename_b, cairo_status_to_string (status)); cairo_surface_destroy (surface_a); cairo_surface_destroy (surface_b); return status; } surface_diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, cairo_image_surface_get_width (surface_a), cairo_image_surface_get_height (surface_a)); status = cairo_surface_status (surface_diff); if (status) { fprintf (stderr, "Error: Failed to allocate surface to hold differences\n"); cairo_surface_destroy (surface_a); cairo_surface_destroy (surface_b); return CAIRO_STATUS_NO_MEMORY; } status = image_diff (NULL, surface_a, surface_b, surface_diff, result); cairo_surface_destroy (surface_a); cairo_surface_destroy (surface_b); cairo_surface_destroy (surface_diff); _xunlink (filename_diff); if (status == CAIRO_STATUS_SUCCESS && result->pixels_changed) { status = write_png (surface_diff, filename_diff); } return status; }
static cairo_bool_t check_result (cairo_test_context_t *ctx, const cairo_boilerplate_target_t *target, const char *test_name, const char *base_name, cairo_surface_t *surface) { const char *format; char *ref_name; char *png_name; char *diff_name; cairo_surface_t *test_image, *ref_image, *diff_image; buffer_diff_result_t result; cairo_status_t status; cairo_bool_t ret; /* XXX log target, OUTPUT, REFERENCE, DIFFERENCE for index.html */ if (target->finish_surface != NULL) { status = target->finish_surface (surface); if (status) { cairo_test_log (ctx, "Error: Failed to finish surface: %s\n", cairo_status_to_string (status)); cairo_surface_destroy (surface); return FALSE; } } xasprintf (&png_name, "%s.out.png", base_name); xasprintf (&diff_name, "%s.diff.png", base_name); test_image = target->get_image_surface (surface, 0, SIZE, SIZE); if (cairo_surface_status (test_image)) { cairo_test_log (ctx, "Error: Failed to extract page: %s\n", cairo_status_to_string (cairo_surface_status (test_image))); cairo_surface_destroy (test_image); free (png_name); free (diff_name); return FALSE; } _xunlink (ctx, png_name); status = cairo_surface_write_to_png (test_image, png_name); if (status) { cairo_test_log (ctx, "Error: Failed to write output image: %s\n", cairo_status_to_string (status)); cairo_surface_destroy (test_image); free (png_name); free (diff_name); return FALSE; } format = cairo_boilerplate_content_name (target->content); ref_name = cairo_test_reference_filename (ctx, base_name, test_name, target->name, target->basename, format, CAIRO_TEST_REF_SUFFIX, CAIRO_TEST_PNG_EXTENSION); if (ref_name == NULL) { cairo_test_log (ctx, "Error: Cannot find reference image for %s\n", base_name); cairo_surface_destroy (test_image); free (png_name); free (diff_name); return FALSE; } ref_image = cairo_test_get_reference_image (ctx, ref_name, 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_name, cairo_status_to_string (cairo_surface_status (ref_image))); cairo_surface_destroy (ref_image); cairo_surface_destroy (test_image); free (png_name); free (diff_name); free (ref_name); return FALSE; } diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, SIZE, SIZE); ret = TRUE; status = image_diff (ctx, test_image, ref_image, diff_image, &result); _xunlink (ctx, diff_name); if (status) { cairo_test_log (ctx, "Error: Failed to compare images: %s\n", cairo_status_to_string (status)); ret = FALSE; } else if (result.pixels_changed && result.max_diff > target->error_tolerance) { ret = FALSE; status = cairo_surface_write_to_png (diff_image, diff_name); if (status) { cairo_test_log (ctx, "Error: Failed to write differences image: %s\n", cairo_status_to_string (status)); } } cairo_surface_destroy (test_image); cairo_surface_destroy (diff_image); free (png_name); free (diff_name); free (ref_name); return ret; }
int main(int argc, char *argv[]) { struct passwd *pw; char *username; char *image_path = NULL; int ret; struct pam_conv conv = {conv_callback, NULL}; int curs_choice = CURS_NONE; int o; int optind = 0; struct option longopts[] = { {"version", no_argument, NULL, 'v'}, {"nofork", no_argument, NULL, 'n'}, {"beep", no_argument, NULL, 'b'}, {"dpms", no_argument, NULL, 'd'}, {"color", required_argument, NULL, 'c'}, {"pointer", required_argument, NULL, 'p'}, {"debug", no_argument, NULL, 0}, {"help", no_argument, NULL, 'h'}, {"no-unlock-indicator", no_argument, NULL, 'u'}, {"image", required_argument, NULL, 'i'}, {"tiling", no_argument, NULL, 't'}, {"ignore-empty-password", no_argument, NULL, 'e'}, {"inactivity-timeout", required_argument, NULL, 'I'}, {"show-failed-attempts", no_argument, NULL, 'f'}, {"login_failed_execute", required_argument, NULL, 0}, {NULL, no_argument, NULL, 0}}; if ((pw = getpwuid(getuid())) == NULL) err(EXIT_FAILURE, "getpwuid() failed"); if ((username = pw->pw_name) == NULL) errx(EXIT_FAILURE, "pw->pw_name is NULL.\n"); char *optstring = "hvnbdc:p:ui:teI:f"; while ((o = getopt_long(argc, argv, optstring, longopts, &optind)) != -1) { switch (o) { case 'v': errx(EXIT_SUCCESS, "version " VERSION " © 2010 Michael Stapelberg"); case 'n': dont_fork = true; break; case 'b': beep = true; break; case 'd': fprintf(stderr, "DPMS support has been removed from i3lock. Please see the manpage i3lock(1).\n"); break; case 'I': { int time = 0; if (sscanf(optarg, "%d", &time) != 1 || time < 0) errx(EXIT_FAILURE, "invalid timeout, it must be a positive integer\n"); inactivity_timeout = time; break; } case 'c': { char *arg = optarg; /* Skip # if present */ if (arg[0] == '#') arg++; if (strlen(arg) != 6 || sscanf(arg, "%06[0-9a-fA-F]", color) != 1) errx(EXIT_FAILURE, "color is invalid, it must be given in 3-byte hexadecimal format: rrggbb\n"); break; } case 'u': unlock_indicator = false; break; case 'i': image_path = strdup(optarg); break; case 't': tile = true; break; case 'p': if (!strcmp(optarg, "win")) { curs_choice = CURS_WIN; } else if (!strcmp(optarg, "default")) { curs_choice = CURS_DEFAULT; } else { errx(EXIT_FAILURE, "i3lock: Invalid pointer type given. Expected one of \"win\" or \"default\".\n"); } break; case 'e': ignore_empty_password = true; break; case 0: if (strcmp(longopts[optind].name, "debug") == 0) debug_mode = true; if ((strcmp(longopts[optind].name, "login_failed_execute") == 0) && optarg) login_failed_execute = optarg; break; case 'f': show_failed_attempts = true; break; default: errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]" " [-i image.png] [-t] [-e] [-I timeout] [-f] [--login_failed_execute command]"); } } /* We need (relatively) random numbers for highlighting a random part of * the unlock indicator upon keypresses. */ srand(time(NULL)); /* Initialize PAM */ if ((ret = pam_start("i3lock", username, &conv, &pam_handle)) != PAM_SUCCESS) errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret)); if ((ret = pam_set_item(pam_handle, PAM_TTY, getenv("DISPLAY"))) != PAM_SUCCESS) errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret)); /* Using mlock() as non-super-user seems only possible in Linux. Users of other * operating systems should use encrypted swap/no swap (or remove the ifdef and * run i3lock as super-user). */ #if defined(__linux__) /* Lock the area where we store the password in memory, we don’t want it to * be swapped to disk. Since Linux 2.6.9, this does not require any * privileges, just enough bytes in the RLIMIT_MEMLOCK limit. */ if (mlock(password, sizeof(password)) != 0) err(EXIT_FAILURE, "Could not lock page in memory, check RLIMIT_MEMLOCK"); #endif /* Double checking that connection is good and operatable with xcb */ int screennr; if ((conn = xcb_connect(NULL, &screennr)) == NULL || xcb_connection_has_error(conn)) errx(EXIT_FAILURE, "Could not connect to X11, maybe you need to set DISPLAY?"); if (xkb_x11_setup_xkb_extension(conn, XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION, 0, NULL, NULL, &xkb_base_event, &xkb_base_error) != 1) errx(EXIT_FAILURE, "Could not setup XKB extension."); static const xcb_xkb_map_part_t required_map_parts = (XCB_XKB_MAP_PART_KEY_TYPES | XCB_XKB_MAP_PART_KEY_SYMS | XCB_XKB_MAP_PART_MODIFIER_MAP | XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS | XCB_XKB_MAP_PART_KEY_ACTIONS | XCB_XKB_MAP_PART_VIRTUAL_MODS | XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP); static const xcb_xkb_event_type_t required_events = (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | XCB_XKB_EVENT_TYPE_MAP_NOTIFY | XCB_XKB_EVENT_TYPE_STATE_NOTIFY); xcb_xkb_select_events( conn, xkb_x11_get_core_keyboard_device_id(conn), required_events, 0, required_events, required_map_parts, required_map_parts, 0); /* When we cannot initially load the keymap, we better exit */ if (!load_keymap()) errx(EXIT_FAILURE, "Could not load keymap"); const char *locale = getenv("LC_ALL"); if (!locale) locale = getenv("LC_CTYPE"); if (!locale) locale = getenv("LANG"); if (!locale) { if (debug_mode) fprintf(stderr, "Can't detect your locale, fallback to C\n"); locale = "C"; } load_compose_table(locale); xinerama_init(); xinerama_query_screens(); screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; last_resolution[0] = screen->width_in_pixels; last_resolution[1] = screen->height_in_pixels; xcb_change_window_attributes(conn, screen->root, XCB_CW_EVENT_MASK, (uint32_t[]){XCB_EVENT_MASK_STRUCTURE_NOTIFY}); if (image_path) { /* Create a pixmap to render on, fill it with the background color */ img = cairo_image_surface_create_from_png(image_path); /* In case loading failed, we just pretend no -i was specified. */ if (cairo_surface_status(img) != CAIRO_STATUS_SUCCESS) { fprintf(stderr, "Could not load image \"%s\": %s\n", image_path, cairo_status_to_string(cairo_surface_status(img))); img = NULL; } } /* Pixmap on which the image is rendered to (if any) */ xcb_pixmap_t bg_pixmap = draw_image(last_resolution); /* open the fullscreen window, already with the correct pixmap in place */ win = open_fullscreen_window(conn, screen, color, bg_pixmap); xcb_free_pixmap(conn, bg_pixmap); pid_t pid = fork(); /* The pid == -1 case is intentionally ignored here: * While the child process is useful for preventing other windows from * popping up while i3lock blocks, it is not critical. */ if (pid == 0) { /* Child */ close(xcb_get_file_descriptor(conn)); raise_loop(win); exit(EXIT_SUCCESS); } cursor = create_cursor(conn, screen, win, curs_choice); grab_pointer_and_keyboard(conn, screen, cursor); /* Load the keymap again to sync the current modifier state. Since we first * loaded the keymap, there might have been changes, but starting from now, * we should get all key presses/releases due to having grabbed the * keyboard. */ (void)load_keymap(); /* Initialize the libev event loop. */ main_loop = EV_DEFAULT; if (main_loop == NULL) errx(EXIT_FAILURE, "Could not initialize libev. Bad LIBEV_FLAGS?\n"); struct ev_io *xcb_watcher = calloc(sizeof(struct ev_io), 1); struct ev_check *xcb_check = calloc(sizeof(struct ev_check), 1); struct ev_prepare *xcb_prepare = calloc(sizeof(struct ev_prepare), 1); ev_io_init(xcb_watcher, xcb_got_event, xcb_get_file_descriptor(conn), EV_READ); ev_io_start(main_loop, xcb_watcher); ev_check_init(xcb_check, xcb_check_cb); ev_check_start(main_loop, xcb_check); ev_prepare_init(xcb_prepare, xcb_prepare_cb); ev_prepare_start(main_loop, xcb_prepare); /* Invoke the event callback once to catch all the events which were * received up until now. ev will only pick up new events (when the X11 * file descriptor becomes readable). */ ev_invoke(main_loop, xcb_check, 0); ev_loop(main_loop, 0); }
static GObject* hippo_image_cache_parse(HippoObjectCache *cache, const char *url, const char *content_type, GString *content, GError **error_p) { cairo_surface_t *csurface; HippoSurface *surface; g_debug("image cache parse '%s'", url); if (has_prefix(content, PNG_MAGIC_PREFIX)) { GStringReader reader; reader.str = content; reader.already_read = 0; csurface = cairo_image_surface_create_from_png_stream(gstring_read_func, &reader); if (csurface != NULL && cairo_surface_status(csurface) == CAIRO_STATUS_SUCCESS) { surface = hippo_surface_new(csurface); cairo_surface_destroy(csurface); } else { const char *msg; if (csurface) { msg = cairo_status_to_string(cairo_surface_status(csurface)); cairo_surface_destroy(csurface); } else { msg = _("Corrupt image"); } surface = NULL; g_set_error(error_p, g_quark_from_string("cairo-surface-error"), 0, msg); goto failed; } } else if (has_prefix(content, JPEG_MAGIC_PREFIX)) { csurface = hippo_parse_jpeg(content->str, content->len, error_p); if (csurface == NULL) { g_debug("JPEG parse failed for '%s'", url); goto failed; } surface = hippo_surface_new(csurface); cairo_surface_destroy(csurface); } else { g_debug("Unknown image format for '%s'", url); g_set_error(error_p, HIPPO_ERROR, HIPPO_ERROR_FAILED, _("Unknown image format")); goto failed; } return G_OBJECT(surface); failed: g_debug("Image parse failed for '%s'", url); g_assert(error_p == NULL || *error_p != NULL); return NULL; }
static GpStatus draw_tile_flipXY_texture (cairo_t *ct, GpBitmap *bitmap, GpTexture *brush) { cairo_surface_t *original = NULL; cairo_surface_t *texture; cairo_pattern_t *pat; GpMatrix tempMatrix; GpRect *rect = &brush->rectangle; GpStatus status; cairo_t *ct2; BYTE *premul = NULL; if (!rect) return InvalidParameter; gdip_bitmap_ensure_surface (bitmap); if (gdip_bitmap_format_needs_premultiplication (bitmap)) { premul = gdip_bitmap_get_premultiplied_scan0 (bitmap); if (premul) { ActiveBitmapData *data = bitmap->active_bitmap; original = cairo_image_surface_create_for_data (premul, CAIRO_FORMAT_ARGB32, data->width, data->height, data->stride); } } /* if premul isn't required (or couldn't be computed, e.g. out of memory) */ if (!original) original = bitmap->surface; /* Use the original as a pattern */ pat = cairo_pattern_create_for_surface (original); status = gdip_get_pattern_status(pat); if (status != Ok) goto cleanup; cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT); /* texture surface to be created */ texture = cairo_surface_create_similar (original, from_cairoformat_to_content (bitmap->cairo_format), 2 * rect->Width, 2 * rect->Height); status = gdip_get_status (cairo_surface_status (texture)); if (status != Ok) { cairo_pattern_destroy (pat); goto cleanup; } /* Draw upper left part of the texture */ ct2 = cairo_create (texture); cairo_set_source (ct2, pat); cairo_rectangle (ct2, 0, 0, rect->Width, rect->Height); cairo_fill (ct2); /* Not sure if this is a bug, but using rect->Height - 1 avoids the seam. */ cairo_matrix_init_identity (&tempMatrix); cairo_matrix_translate (&tempMatrix, 0, rect->Height - 1); /* scale in -Y direction to flip along Y */ cairo_matrix_scale (&tempMatrix, 1.0, -1.0); cairo_pattern_set_matrix (pat, &tempMatrix); /* Draw lower left part of the texture */ cairo_translate (ct2, 0, rect->Height); cairo_set_source (ct2, pat); cairo_rectangle (ct2, 0, 0, rect->Width, rect->Height); cairo_fill (ct2); /* Reset the pattern matrix and do fresh transformation */ cairo_matrix_init_identity (&tempMatrix); /* Not sure if this is a bug, but using rect->Width - 1 avoids the seam. */ cairo_matrix_translate (&tempMatrix, rect->Width - 1, 0); /* scale in -X direction to flip along X */ cairo_matrix_scale (&tempMatrix, -1.0, 1.0); cairo_pattern_set_matrix (pat, &tempMatrix); /* Draw upper right part of the texture */ cairo_translate (ct2, rect->Width, -rect->Height); cairo_set_source (ct2, pat); cairo_rectangle (ct2, 0, 0, rect->Width, rect->Height); cairo_fill (ct2); /* Not sure if this is a bug, but using rect->Height - 1 avoids the seam. */ cairo_matrix_translate (&tempMatrix, 0, rect->Height - 1); /* scale in -Y direction to flip along Y */ cairo_matrix_scale (&tempMatrix, 1.0, -1.0); cairo_pattern_set_matrix (pat, &tempMatrix); /* Draw lower right part of the texture */ cairo_translate (ct2, 0, rect->Height); cairo_set_source (ct2, pat); cairo_rectangle (ct2, 0, 0, rect->Width, rect->Height); cairo_fill (ct2); cairo_destroy(ct2); brush->pattern = cairo_pattern_create_for_surface (texture); status = gdip_get_pattern_status(brush->pattern); if (status != Ok) { cairo_pattern_destroy (pat); cairo_surface_destroy (texture); goto cleanup; } cairo_pattern_set_extend (brush->pattern, CAIRO_EXTEND_REPEAT); cairo_pattern_destroy (pat); cairo_surface_destroy (texture); status = gdip_get_status (cairo_status (ct)); cleanup: if (premul) { cairo_surface_destroy (original); GdipFree (premul); } return status; }