svg_status_t
_svg_android_transform (void *closure,
			double xx, double yx,
			double xy, double yy,
			double x0, double y0)
{
	svg_android_t *svg_android = closure;

	jobject new_matrix;
	jobject old_matrix = svg_android->state->matrix;
	
	DEBUG_ENTRY("transform");
	new_matrix = ANDROID_MATRIX_INIT(svg_android, xx, yx, xy, yy, x0, y0);

	ANDROID_MATRIX_MULTIPLY(svg_android, new_matrix, old_matrix);

	svg_android->state->matrix =
		(*(svg_android->env))->NewGlobalRef(
			svg_android->env, new_matrix);
	(*(svg_android->env))->DeleteGlobalRef(svg_android->env, old_matrix);

	DEBUG_EXIT("transform");
	
	return SVG_ANDROID_STATUS_SUCCESS;
}
svg_status_t
_svg_android_set_viewport_dimension (void *closure,
				     svg_length_t *width,
				     svg_length_t *height)
{
	svg_android_t *svg_android = closure;
	double vwidth, vheight;

	DEBUG_ENTRY("set_viewpoert_dimension");

	_svg_android_length_to_pixel (svg_android, width, &vwidth);
	_svg_android_length_to_pixel (svg_android, height, &vheight);

	svg_android->state->viewport_width  = vwidth;
	svg_android->state->viewport_height = vheight;

	if(svg_android->fit_to_area) {
		// calculate fit_to_MATRIX values
		double xx, x0, w;
		double yy, y0, h;

		w = (double)(svg_android->fit_to_w);
		h = (double)(svg_android->fit_to_h);
		
		xx = w / vwidth;
		yy = h / vheight;

		// Do equal scaling if needed...
		if (svg_android->fit_uniform) {
			if(xx < yy) yy = xx;
			if(xx > yy) xx = yy;
		}

		svg_android->fit_to_scale = xx;
		
		x0 = (double)(svg_android->fit_to_x);
		y0 = (double)(svg_android->fit_to_y);

		svg_android->fit_to_MATRIX =
			ANDROID_MATRIX_INIT(svg_android, xx, 0.0, 0.0, yy, x0, y0);
		
	} else svg_android->fit_to_scale = 1.0;

	DEBUG_EXIT("set_viewpoert_dimension");
	return SVG_ANDROID_STATUS_SUCCESS;
}
svg_status_t _svg_android_set_gradient (svg_android_t *svg_android,
			   svg_gradient_t *gradient,
			   svg_android_render_type_t type)
{
	svg_gradient_stop_t *stop;
	int i;
	jobject matrix, gradient_matrix;
	jobject gradient_shader = NULL;

	matrix = ANDROID_IDENTITY_MATRIX(svg_android);

	switch (gradient->units) {
	case SVG_GRADIENT_UNITS_USER:
		break;
	case SVG_GRADIENT_UNITS_BBOX:
	{
		jfloatArray farr;
		jfloat *coords;
		
		farr = ANDROID_PATH_GET_BOUNDS(svg_android, svg_android->state->path);
		
		coords = (*(svg_android->env))->GetFloatArrayElements((svg_android->env), farr, 0);

		// Maybe we need to add the stroke width to be correct here? (if type == SVG_ANDROID_RENDER_TYPE_STROKE)
		ANDROID_MATRIX_TRANSLATE(svg_android, matrix, coords[0], coords[1]);
		ANDROID_MATRIX_SCALE(svg_android, matrix, coords[2] - coords[0], coords[3] - coords[1]);
		(*(svg_android->env))->ReleaseFloatArrayElements(svg_android->env, farr, coords, 0);		
		
#if 0 // note here how the cairo version checks for fill or stroke, the extents might be different.. but for android I use the bounds of the path, this doesn't account for stroke painting outside..
		double x1, y1, x2, y2;

		if (type == SVG_ANDROID_RENDER_TYPE_FILL)
			cairo_fill_extents (svg_android->cr, &x1, &y1, &x2, &y2);
		else
			cairo_stroke_extents (svg_android->cr, &x1, &y1, &x2, &y2);

		cairo_matrix_translate (&matrix, x1, y1);
		cairo_matrix_scale (&matrix, x2 - x1, y2 - y1);

#endif
		svg_android->state->bbox = 1;
	} break;
	}

	// create java float array for the stops offsets, and int array for the colors
	jfloat offsets[gradient->num_stops];
	jint colors[gradient->num_stops];
	for (i = 0; i < gradient->num_stops; i++) {
		stop = &gradient->stops[i];
		offsets[i] = stop->offset;
		unsigned long r, g, b, o;
		r = svg_color_get_red (&stop->color);
		g = svg_color_get_green (&stop->color);
		b = svg_color_get_blue (&stop->color);
		o = (unsigned long)(stop->opacity * 255.0);
		colors[i] =
			(o & 0xff) << 24 |
			(r & 0xff) << 16 |
			(g & 0xff) << 8 |
			(b & 0xff);		
	}
	jfloatArray offsets_a;
	jintArray colors_a;
	offsets_a = (*(svg_android->env))->NewFloatArray(svg_android->env, gradient->num_stops);
	colors_a = (*(svg_android->env))->NewIntArray(svg_android->env, gradient->num_stops);

	(*(svg_android->env))->SetFloatArrayRegion(svg_android->env, offsets_a, 0, gradient->num_stops, offsets);
	(*(svg_android->env))->SetIntArrayRegion(svg_android->env, colors_a, 0, gradient->num_stops, colors);

	int spreadType = 2;
	
	switch (gradient->spread) {
	case SVG_GRADIENT_SPREAD_REPEAT:
		spreadType = 0;
		break;
	case SVG_GRADIENT_SPREAD_REFLECT:
		spreadType = 1;
		break;
	default:
		spreadType = 2;
		break;
	}
	    
	switch (gradient->type) {
	case SVG_GRADIENT_LINEAR:
	{
		double x1, y1, x2, y2;

		_svg_android_length_to_pixel (svg_android, &gradient->u.linear.x1, &x1);
		_svg_android_length_to_pixel (svg_android, &gradient->u.linear.y1, &y1);
		_svg_android_length_to_pixel (svg_android, &gradient->u.linear.x2, &x2);
		_svg_android_length_to_pixel (svg_android, &gradient->u.linear.y2, &y2);

		if((*(svg_android->env))->ExceptionOccurred(svg_android->env)) {
			(*(svg_android->env))->ExceptionDescribe(svg_android->env);
		}
		gradient_shader = ANDROID_CREATE_LINEAR_GRADIENT(svg_android, x1, y1, x2, y2, colors_a, offsets_a, spreadType);
		if((*(svg_android->env))->ExceptionOccurred(svg_android->env)) {
			(*(svg_android->env))->ExceptionDescribe(svg_android->env);
		}
	}
	break;
	case SVG_GRADIENT_RADIAL:
	{
		double cx, cy, r, fx, fy;
      
		_svg_android_length_to_pixel (svg_android, &gradient->u.radial.cx, &cx);
		_svg_android_length_to_pixel (svg_android, &gradient->u.radial.cy, &cy);
		_svg_android_length_to_pixel (svg_android, &gradient->u.radial.r, &r);
		_svg_android_length_to_pixel (svg_android, &gradient->u.radial.fx, &fx);
		_svg_android_length_to_pixel (svg_android, &gradient->u.radial.fy, &fy);

		gradient_shader = ANDROID_CREATE_RADIAL_GRADIENT(svg_android, fx, fy, r, colors_a, offsets_a, spreadType);
#if 0 // note here that there is a start and an end circel, android doesn't support that. The end circle in Android always have the same coords as the start circle
		pattern = cairo_pattern_create_radial (fx, fy, 0.0, cx, cy, r);
#endif
	} break;
	}    

	gradient_matrix = ANDROID_MATRIX_INIT(svg_android,
					      gradient->transform[0], gradient->transform[1],
					      gradient->transform[2], gradient->transform[3],
					      gradient->transform[4], gradient->transform[5]);
	ANDROID_MATRIX_MULTIPLY(svg_android, matrix, gradient_matrix);

	ANDROID_MATRIX_MULTIPLY(svg_android, matrix, svg_android->state->matrix);
	
	if(svg_android->fit_to_area)
		ANDROID_MATRIX_MULTIPLY(svg_android, matrix, svg_android->fit_to_MATRIX);

	if(gradient_shader) {
		ANDROID_SHADER_SET_MATRIX(svg_android, gradient_shader, matrix);
		ANDROID_PAINT_SET_SHADER(svg_android, gradient_shader);
	}
	
	svg_android->state->bbox = 0;
    
	return SVG_STATUS_SUCCESS;
}