JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSurfaceSetFilter (JNIEnv *env, jobject obj, jint filter) { struct graphics2d *gr = NULL; gdk_threads_enter(); if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; } gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); g_assert (gr != NULL); if (gr->debug) printf ("cairo_surface_set_filter %d\n", filter); switch ((enum java_awt_rendering_hints_filter) filter) { case java_awt_rendering_hints_VALUE_INTERPOLATION_NEAREST_NEIGHBOR: cairo_surface_set_filter (gr->surface, CAIRO_FILTER_NEAREST); break; case java_awt_rendering_hints_VALUE_INTERPOLATION_BILINEAR: cairo_surface_set_filter (gr->surface, CAIRO_FILTER_BILINEAR); break; case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_SPEED: cairo_surface_set_filter (gr->surface, CAIRO_FILTER_FAST); break; case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_DEFAULT: cairo_surface_set_filter (gr->surface, CAIRO_FILTER_NEAREST); break; case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_QUALITY: cairo_surface_set_filter (gr->surface, CAIRO_FILTER_BEST); break; } gdk_threads_leave(); }
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_drawPixels (JNIEnv *env, jobject obj, jintArray java_pixels, jint w, jint h, jint stride, jdoubleArray java_matrix) { struct graphics2d *gr = NULL; jint *native_pixels = NULL; jdouble *native_matrix = NULL; gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); g_assert (gr != NULL); if (gr->debug) printf ("drawPixels (%d pixels, %dx%d, stride: %d)\n", (*env)->GetArrayLength (env, java_pixels), w, h, stride); native_pixels = (*env)->GetIntArrayElements (env, java_pixels, NULL); native_matrix = (*env)->GetDoubleArrayElements (env, java_matrix, NULL); g_assert (native_pixels != NULL); g_assert (native_matrix != NULL); g_assert ((*env)->GetArrayLength (env, java_matrix) == 6); begin_drawing_operation (gr); { cairo_matrix_t *mat = NULL; cairo_surface_t *surf = cairo_surface_create_for_image ((char *)native_pixels, CAIRO_FORMAT_ARGB32, w, h, stride * 4); mat = cairo_matrix_create (); cairo_matrix_set_affine (mat, native_matrix[0], native_matrix[1], native_matrix[2], native_matrix[3], native_matrix[4], native_matrix[5]); cairo_surface_set_matrix (surf, mat); if (native_matrix[0] != 1. || native_matrix[1] != 0. || native_matrix[2] != 0. || native_matrix[3] != 1.) { cairo_surface_set_filter (surf, CAIRO_FILTER_BILINEAR); cairo_surface_set_filter (gr->surface, CAIRO_FILTER_BILINEAR); } else { cairo_surface_set_filter (surf, CAIRO_FILTER_FAST); cairo_surface_set_filter (gr->surface, CAIRO_FILTER_FAST); } cairo_show_surface (gr->cr, surf, w, h); cairo_surface_set_filter (gr->surface, CAIRO_FILTER_FAST); cairo_matrix_destroy (mat); cairo_surface_destroy (surf); } end_drawing_operation (gr); (*env)->ReleaseIntArrayElements (env, java_pixels, native_pixels, 0); (*env)->ReleaseDoubleArrayElements (env, java_matrix, native_matrix, 0); }
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_copyState (JNIEnv *env, jobject obj, jobject old) { struct graphics2d *g = NULL, *g_old = NULL; g = (struct graphics2d *) malloc (sizeof (struct graphics2d)); g_assert (g != NULL); memset (g, 0, sizeof(struct graphics2d)); g_old = (struct graphics2d *) NSA_GET_G2D_PTR (env, old); g_assert (g_old != NULL); if (g_old->debug) printf ("copying state from existing graphics2d\n"); g->drawable = g_old->drawable; g->debug = g_old->debug; gdk_threads_enter (); g_object_ref (g->drawable); g->cr = cairo_create(); g_assert (g->cr != NULL); if (x_server_has_render_extension ()) init_graphics2d_as_renderable (g); else init_graphics2d_as_pixbuf (g); cairo_surface_set_filter (g->surface, CAIRO_FILTER_FAST); gdk_threads_leave (); NSA_SET_G2D_PTR (env, obj, g); }
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_setGradient (JNIEnv *env, jobject obj, jdouble x1, jdouble y1, jdouble x2, jdouble y2, jint r1, jint g1, jint b1, jint a1, jint r2, jint g2, jint b2, jint a2, jboolean cyclic) { struct graphics2d *gr = NULL; cairo_surface_t *surf = NULL; cairo_matrix_t *mat = NULL; gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); g_assert (gr != NULL); if (gr->debug) printf ("setGradient (%f,%f) -> (%f,%f); (%d,%d,%d,%d) -> (%d,%d,%d,%d)\n", x1, y1, x2, y2, r1, g1, b1, a1, r2, g2, b2, a2); cairo_save (gr->cr); if (cyclic) surf = cairo_surface_create_similar (gr->surface, CAIRO_FORMAT_ARGB32, 3, 2); else surf = cairo_surface_create_similar (gr->surface, CAIRO_FORMAT_ARGB32, 2, 2); g_assert (surf != NULL); cairo_set_target_surface (gr->cr, surf); cairo_identity_matrix (gr->cr); cairo_set_rgb_color (gr->cr, r1 / 255.0, g1 / 255.0, b1 / 255.0); cairo_set_alpha (gr->cr, a1 / 255.0); cairo_rectangle (gr->cr, 0, 0, 1, 2); cairo_fill (gr->cr); cairo_set_rgb_color (gr->cr, r2 / 255.0, g2 / 255.0, b2 / 255.0); cairo_set_alpha (gr->cr, a2 / 255.0); cairo_rectangle (gr->cr, 1, 0, 1, 2); cairo_fill (gr->cr); if (cyclic) { cairo_set_rgb_color (gr->cr, r1 / 255.0, g1 / 255.0, b1 / 255.0); cairo_set_alpha (gr->cr, a1 / 255.0); cairo_rectangle (gr->cr, 2, 0, 1, 2); cairo_fill (gr->cr); } mat = cairo_matrix_create (); g_assert (mat != NULL); /* consider the vector [x2 - x1, y2 - y1] = [p,q] this is a line in space starting at an 'origin' x1, y1. it can also be thought of as a "transformed" unit vector in either the x or y directions. we have just *drawn* our gradient as a unit vector (well, a 2-3x unit vector) in the x dimension. so what we want to know is which transformation turns our existing unit vector into [p,q]. which means solving for M in [p,q] = M[1,0] [p,q] = |a b| [1,0] |c d| [p,q] = [a,c], with b = d = 0. what does this mean? it means that our gradient is 1-dimensional; as you move through the x axis of our 2 or 3 pixel gradient from logical x positions 0 to 1, the transformation of your x coordinate under the matrix M causes you to accumulate both x and y values in fill space. the y value of a gradient coordinate is ignored, since the gradient is one dimensional. which is correct. unfortunately we want the opposite transformation, it seems, because of the way cairo is going to use this transformation. I'm a bit confused by that, but it seems to work right, so we take reciprocals of values and negate offsets. oh well. */ double a = (x2 - x1 == 0.) ? 0. : ((cyclic ? 3.0 : 2.0) / (x2 - x1)); double c = (y2 - y1 == 0.) ? 0. : (1. / (y2 - y1)); double dx = (x1 == 0.) ? 0. : 1. / x1; double dy = (y1 == 0.) ? 0. : 1. / y1; cairo_matrix_set_affine (mat, a, 0., c, 0., dx, dy); cairo_surface_set_matrix (surf, mat); cairo_matrix_destroy (mat); cairo_surface_set_filter (surf, CAIRO_FILTER_BILINEAR); /* FIXME: repeating gradients (not to mention hold gradients) don't seem to work. */ /* cairo_surface_set_repeat (surf, cyclic ? 1 : 0); */ if (gr->pattern) cairo_surface_destroy (gr->pattern); if (gr->pattern_pixels) { free (gr->pattern_pixels); gr->pattern_pixels = NULL; } gr->pattern = surf; cairo_restore (gr->cr); cairo_set_pattern (gr->cr, gr->pattern); }
static void draw_image(DiaRenderer *self, Point *point, real width, real height, DiaImage *image) { DiaCairoRenderer *renderer = DIA_CAIRO_RENDERER (self); cairo_surface_t *surface; guint8 *data; int w = dia_image_width(image); int h = dia_image_height(image); int rs = dia_image_rowstride(image); DIAG_NOTE(g_message("draw_image %fx%f [%d(%d),%d] @%f,%f", width, height, w, rs, h, point->x, point->y)); if (dia_image_rgba_data (image)) { const guint8 *p1 = dia_image_rgba_data (image); /* we need to make a copy to rearrange channels * (also need to use malloc, cause Cairo insists to free() it) */ guint8 *p2 = data = g_malloc (h * rs); int i; for (i = 0; i < (h * rs) / 4; i++) { # if G_BYTE_ORDER == G_LITTLE_ENDIAN p2[0] = p1[2]; /* b */ p2[1] = p1[1]; /* g */ p2[2] = p1[0]; /* r */ p2[3] = p1[3]; /* a */ # else p2[3] = p1[2]; /* b */ p2[2] = p1[1]; /* g */ p2[1] = p1[0]; /* r */ p2[0] = p1[3]; /* a */ # endif p1+=4; p2+=4; } surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, w, h, rs); } else { guint8 *p, *p2; guint8 *p1 = data = dia_image_rgb_data (image); /* need to copy to be owned by cairo/pixman, urgh. * Also cairo wants RGB24 32 bit aligned */ int x, y; p = p2 = g_malloc(h*w*4); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN /* apparently BGR is required */ p2[x*4 ] = p1[x*3+2]; p2[x*4+1] = p1[x*3+1]; p2[x*4+2] = p1[x*3 ]; p2[x*4+3] = 0x80; /* should not matter */ #else p2[x*4+3] = p1[x*3+2]; p2[x*4+2] = p1[x*3+1]; p2[x*4+1] = p1[x*3 ]; p2[x*4+0] = 0x80; /* should not matter */ #endif } p2 += (w*4); p1 += rs; } surface = cairo_image_surface_create_for_data (p, CAIRO_FORMAT_RGB24, w, h, w*4); g_free (data); data = p; } cairo_save (renderer->cr); cairo_translate (renderer->cr, point->x, point->y); cairo_scale (renderer->cr, width/w, height/h); cairo_move_to (renderer->cr, 0.0, 0.0); /* maybe just the second set_filter is required */ #if 0 cairo_surface_set_filter (renderer->surface, CAIRO_FILTER_BEST); cairo_surface_set_filter (surface, CAIRO_FILTER_BEST); #endif cairo_set_source_surface (renderer->cr, surface, 0.0, 0.0); cairo_paint (renderer->cr); cairo_restore (renderer->cr); cairo_surface_destroy (surface); g_free (data); DIAG_STATE(renderer->cr); }