/* * Copyright 2009 Chris Wilson * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation, and that the name of * Chris Wilson not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior * permission. Chris Wilson makes no representations about the * suitability of this software for any purpose. It is provided "as * is" without express or implied warranty. * * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Chris Wilson */ #include "cairo-test.h" #include static const char *png_filename = "romedalen.png"; #define WIDTH 800 #define HEIGHT 600 static cairo_status_t _image_to_glyphs (cairo_surface_t *image, int channel, int level, cairo_scaled_font_t *scaled_font, double tx, double ty, cairo_glyph_t *glyphs, int *num_glyphs) { int width, height, stride; const unsigned char *data; cairo_format_t format; int x, y, z, n; width = cairo_image_surface_get_width (image); height = cairo_image_surface_get_height (image); stride = cairo_image_surface_get_stride (image); format = cairo_image_surface_get_format (image); data = cairo_image_surface_get_data (image); n = 0; for (y = 0; y < height; y++) { const uint32_t *row = (uint32_t *) (data + y * stride); for (x = 0; x < width; x++) { z = (row[x] >> channel) & 0xff; if (z == level) { double xx, yy, zz; char c = n % 26 + 'a'; int count = 1; cairo_glyph_t *glyphs_p = &glyphs[n]; cairo_status_t status; xx = 4 * (x - width/2.) + width/2.; yy = 4 * (y - height/2.) + height/2.; zz = z / 1000.; xx = xx + zz*(width/2. - xx); yy = yy + zz*(height/2. - yy); cairo_scaled_font_text_to_glyphs (scaled_font, tx + xx, ty + yy, &c, 1, &glyphs_p, &count, NULL, NULL, NULL); status = cairo_scaled_font_status (scaled_font); if (status) return status; assert (glyphs_p == &glyphs[n]); assert (count == 1); n++; } } } *num_glyphs = n; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _render_image (cairo_t *cr, int width, int height, cairo_surface_t *image) { int ww, hh; cairo_glyph_t *glyphs; cairo_pattern_t *mask; cairo_scaled_font_t *scaled_font; double tx, ty; const struct { int shift; double red; double green; double blue; } channel[3] = { { 0, 0.9, 0.3, 0.4 }, { 8, 0.4, 0.9, 0.3 }, { 16, 0.3, 0.4, 0.9 }, }; unsigned int n, i; ww = cairo_image_surface_get_width (image); hh = cairo_image_surface_get_height (image); glyphs = cairo_glyph_allocate (ww * hh); if (glyphs == NULL) return CAIRO_STATUS_NO_MEMORY; tx = (width - ww) / 2.; ty = (height - hh) / 2.; cairo_set_font_size (cr, 5); scaled_font = cairo_get_scaled_font (cr); for (i = 0; i < sizeof (channel) / sizeof (channel[0]); i++) { cairo_push_group_with_content (cr, CAIRO_CONTENT_ALPHA); for (n = 0; n < 256; n++) { cairo_status_t status; int num_glyphs; status = _image_to_glyphs (image, channel[i].shift, n, scaled_font, tx, ty, glyphs, &num_glyphs); if (status) { cairo_glyph_free (glyphs); return status; } cairo_set_source_rgba (cr, 0, 0, 0, .15 + .85 * n / 255.); cairo_show_glyphs (cr, glyphs, num_glyphs); } mask = cairo_pop_group (cr); cairo_set_source_rgb (cr, channel[i].red, channel[i].green, channel[i].blue); cairo_mask (cr, mask); cairo_pattern_destroy (mask); } cairo_glyph_free (glyphs); return CAIRO_STATUS_SUCCESS; } static cairo_test_status_t draw (cairo_t *cr, int width, int height) { const cairo_test_context_t *ctx = cairo_test_get_context (cr); cairo_surface_t *image; cairo_status_t status; cairo_set_source_rgb (cr, 0, 0, 0); cairo_paint (cr); image = cairo_test_create_surface_from_png (ctx, png_filename); status = cairo_surface_status (image); if (status) return cairo_test_status_from_status (ctx, status); status = _render_image (cr, width, height, image); cairo_surface_destroy (image); return cairo_test_status_from_status (ctx, status); } CAIRO_TEST (mask_glyphs, "Creates a mask using a distorted array of overlapping glyphs", "mask, glyphs", /* keywords */ "slow", /* requirements */ WIDTH, HEIGHT, NULL, draw)