svg_status_t
_svg_android_render_line (void *closure,
			  svg_length_t *x1_len, svg_length_t *y1_len,
			  svg_length_t *x2_len, svg_length_t *y2_len)
{
	svg_android_t *svg_android = closure;
	svg_status_t status;
	double x1, y1, x2, y2;

	DEBUG_ENTRY("render_line");
	_svg_android_length_to_pixel (svg_android, x1_len, &x1);
	_svg_android_length_to_pixel (svg_android, y1_len, &y1);
	_svg_android_length_to_pixel (svg_android, x2_len, &x2);
	_svg_android_length_to_pixel (svg_android, y2_len, &y2);

	status = _svg_android_move_to (svg_android, x1, y1);
	if (status)
		return status;

	status = _svg_android_line_to (svg_android, x2, y2);
	if (status)
		return status;

	status = _svg_android_render_path (svg_android);
	if (status)
		return status;

	DEBUG_EXIT("render_line");
	return SVG_ANDROID_STATUS_SUCCESS;

}
svg_status_t _svg_android_set_pattern (svg_android_t *svg_android,
				       svg_element_t *pattern_element,
				       svg_android_render_type_t type)
{
	svg_pattern_t *pattern = svg_element_pattern (pattern_element);
	jobject pattern_bitmap;
	jobject pattern_shader;
	double x_px, y_px, width_px, height_px;
	jobject path;

	_svg_android_length_to_pixel (svg_android, &pattern->x, &x_px);
	_svg_android_length_to_pixel (svg_android, &pattern->y, &y_px);
	_svg_android_length_to_pixel (svg_android, &pattern->width, &width_px);
	_svg_android_length_to_pixel (svg_android, &pattern->height, &height_px);

	/* OK. We've got the final path to be filled/stroked inside the
	 * android context right now. But we're also going to re-use that
	 * same context to draw the pattern. And since the path is no
	 * longer in the graphics state, android_save/restore will not help
	 * us here.
	 *
	 * Currently we deal with this by manually saving/restoring the
	 * path.
	 *
	 */
	path = svg_android->state->path;
	svg_android->state->path = ANDROID_PATH_CREATE(svg_android);
	ANDROID_SAVE(svg_android);

	pattern_bitmap = ANDROID_CREATE_BITMAP(svg_android,
					       (int) (width_px + 0.5),
					       (int) (height_px + 0.5));
	
	_svg_android_push_state (svg_android, pattern_bitmap, NULL);

	svg_android->state->matrix = ANDROID_IDENTITY_MATRIX(svg_android);
    
	svg_android->state->fill_paint.type = SVG_PAINT_TYPE_NONE;
	svg_android->state->stroke_paint.type = SVG_PAINT_TYPE_NONE;
    
	svg_element_render (pattern->group_element, &SVG_ANDROID_RENDER_ENGINE, svg_android);
	_svg_android_pop_state (svg_android);

	ANDROID_RESTORE(svg_android);

	svg_android->state->path = path ;

	pattern_shader = ANDROID_CREATE_BITMAP_SHADER(svg_android, pattern_bitmap);
	ANDROID_PAINT_SET_SHADER(svg_android, pattern_shader);
	
	return SVG_STATUS_SUCCESS;
}
svg_status_t
_svg_android_render_text (void *closure,
			  svg_length_t *x_len,
			  svg_length_t *y_len,
			  const char *utf8)
{
	svg_android_t *svg_android = closure;
	double x, y;
	svg_status_t status;
	svg_paint_t *fill_paint, *stroke_paint;

	DEBUG_ENTRY("render_text");
	fill_paint = &svg_android->state->fill_paint;
	stroke_paint = &svg_android->state->stroke_paint;

	_svg_android_select_font (svg_android);

	_svg_android_length_to_pixel (svg_android, x_len, &x);
	_svg_android_length_to_pixel (svg_android, y_len, &y);
	
	status = _svg_android_move_to (svg_android, x, y);
	if (status)
		return status;

	ANDROID_TEXT_PATH(svg_android, utf8, x, y);
	_svg_android_render_path (svg_android);
	
#if 0 // this code doesn't work with renderToArea
	if (fill_paint->type) {
		_svg_android_set_paint_and_opacity (svg_android, fill_paint,
						    svg_android->state->fill_opacity,
						    SVG_ANDROID_RENDER_TYPE_FILL);

//		ANDROID_DRAW_TEXT(svg_android, utf8, 0.0, 0.0);
		ANDROID_DRAW_TEXT(svg_android, utf8, x, y);
	}

	if (stroke_paint->type) {
		_svg_android_set_paint_and_opacity (svg_android, stroke_paint,
						    svg_android->state->stroke_opacity,
						    SVG_ANDROID_RENDER_TYPE_STROKE);

		ANDROID_DRAW_TEXT(svg_android, utf8, x, y);
	}

#endif
	DEBUG_EXIT("render_text");
	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_render_image (void		*closure,
			   unsigned char	*data,
			   unsigned int	data_width,
			   unsigned int	data_height,
			   svg_length_t	*x_len,
			   svg_length_t	*y_len,
			   svg_length_t	*width_len,
			   svg_length_t	*height_len)
{
	svg_android_t *svg_android = closure;
	double x, y, width, height;

	jintArray iarr;
	jobject bitmap;
	jobject matrix;

	DEBUG_ENTRY("render_image");
	ANDROID_SAVE(svg_android);

	_svg_android_length_to_pixel (svg_android, x_len, &x);
	_svg_android_length_to_pixel (svg_android, y_len, &y);
	_svg_android_length_to_pixel (svg_android, width_len, &width);
	_svg_android_length_to_pixel (svg_android, height_len, &height);

	// copy bitmap into an java int array
	iarr = (*(svg_android->env))->NewIntArray(svg_android->env, data_width * data_height);
	(*(svg_android->env))->SetIntArrayRegion(svg_android->env, iarr, 0, data_width * data_height , (jint *)data);

	// create bitmap
	bitmap = ANDROID_DATA_2_BITMAP(svg_android, iarr, data_width, data_height);

	// prepare matrix
	matrix = ANDROID_IDENTITY_MATRIX(svg_android);
	ANDROID_MATRIX_TRANSLATE(svg_android, matrix, x, y);
	ANDROID_MATRIX_SCALE(svg_android, matrix, width / data_width, height / data_height);

	// and draw!
	ANDROID_DRAW_BITMAP(svg_android, bitmap, matrix);	

	ANDROID_RESTORE(svg_android);

	DEBUG_EXIT("render_image");
	return SVG_ANDROID_STATUS_SUCCESS;
}
svg_status_t
_svg_android_set_stroke_dash_offset (void *closure, svg_length_t *offset_len)
{
	svg_android_t *svg_android = closure;
	double offset;
	
	DEBUG_ENTRY("set_stroke_dash_offset");

	_svg_android_length_to_pixel (svg_android, offset_len, &offset);

	svg_android->state->dash_offset = offset;

	if (svg_android->state->num_dashes) {
		jfloatArray farr;

		// prepare Android float array with dashes, make sure the array is even in length..
		{
			int max_k;
			int k;
			jfloat *buf;

			max_k = svg_android->state->num_dashes;
			if(max_k & 0x1) max_k++; // make even

			buf = (jfloat *)malloc(sizeof(jfloat) * max_k);
			if(buf == NULL)
				return SVG_STATUS_NO_MEMORY;
			
			farr = (*(svg_android->env))->NewFloatArray(svg_android->env, max_k);
			
			if (farr == NULL) {
				free(buf);
				return SVG_ANDROID_STATUS_NO_MEMORY; /* out of memory error thrown */
			}
			
			for(k = 0; k < svg_android->state->num_dashes; k++) {
				buf[k] = svg_android->state->dash[k];
			}
			for(; k < max_k; k++) buf[k] = 0.0;
			
			(*(svg_android->env))->SetFloatArrayRegion(svg_android->env, farr, 0, max_k, buf);

			free(buf);
		}

		jobject effect = ANDROID_GET_DASHEFFECT(
			svg_android, farr,
			svg_android->state->dash_offset);
		ANDROID_PAINT_SET_EFFECT(svg_android, effect);
	}
	
	DEBUG_EXIT("set_stroke_dash_offset");
	return SVG_ANDROID_STATUS_SUCCESS;
}
svg_status_t
_svg_android_render_ellipse (void *closure,
			     svg_length_t *cx_len,
			     svg_length_t *cy_len,
			     svg_length_t *rx_len,
			     svg_length_t *ry_len)
{
	svg_android_t *svg_android = closure;

	double cx, cy, rx, ry;

	DEBUG_ENTRY("render_ellipse");

	_svg_android_length_to_pixel (svg_android, cx_len, &cx);
	_svg_android_length_to_pixel (svg_android, cy_len, &cy);
	_svg_android_length_to_pixel (svg_android, rx_len, &rx);
	_svg_android_length_to_pixel (svg_android, ry_len, &ry);

	ANDROID_DRAW_ELLIPSE(svg_android, cx, cy, rx, ry);

	DEBUG_EXIT("render_ellipse");
	return SVG_ANDROID_STATUS_SUCCESS;
}
svg_status_t
_svg_android_render_rect (void *closure,
			  svg_length_t *x_len,
			  svg_length_t *y_len,
			  svg_length_t *width_len,
			  svg_length_t *height_len,
			  svg_length_t *rx_len,
			  svg_length_t *ry_len)
{
	svg_android_t *svg_android = closure;

	double x, y, width, height, rx, ry;
 
	DEBUG_ENTRY("render_rect");
	_svg_android_length_to_pixel (svg_android, x_len, &x);
	_svg_android_length_to_pixel (svg_android, y_len, &y);
	_svg_android_length_to_pixel (svg_android, width_len, &width);
	_svg_android_length_to_pixel (svg_android, height_len, &height);
	_svg_android_length_to_pixel (svg_android, rx_len, &rx);
	_svg_android_length_to_pixel (svg_android, ry_len, &ry);
 
	if (rx > width / 2.0)
		rx = width / 2.0;
	if (ry > height / 2.0)
		ry = height / 2.0;

	if (rx > 0 || ry > 0)
	{
		_svg_android_move_to (svg_android, x + rx, y);
		_svg_android_line_to (svg_android, x + width - rx, y);
		_svg_android_arc_to  (svg_android, rx, ry, 0, 0, 1, x + width, y + ry);
		_svg_android_line_to (svg_android, x + width, y + height - ry);
		_svg_android_arc_to  (svg_android, rx, ry, 0, 0, 1, x + width - rx, y + height);
		_svg_android_line_to (svg_android, x + rx, y + height);
		_svg_android_arc_to  (svg_android, rx, ry, 0, 0, 1, x, y + height - ry);
		_svg_android_line_to (svg_android, x, y + ry);
		_svg_android_arc_to  (svg_android, rx, ry, 0, 0, 1, x + rx, y);
	}
	else
	{
		_svg_android_move_to (svg_android, x, y);
		_svg_android_line_to (svg_android, x + width, y);
		_svg_android_line_to (svg_android, x + width, y + height);
		_svg_android_line_to (svg_android, x, y + height);
	}
	_svg_android_close_path (svg_android);

	_svg_android_render_path (svg_android);

	DEBUG_EXIT("render_rect");
	return SVG_ANDROID_STATUS_SUCCESS;
}
svg_status_t
_svg_android_set_stroke_width (void *closure, svg_length_t *width_len)
{
	svg_android_t *svg_android = closure;
	double width;

	DEBUG_ENTRY("set_stroke_width");
	_svg_android_length_to_pixel (svg_android, width_len, &width);
	
	svg_android->state->width_len.unit = width_len->unit;
	svg_android->state->width_len.value = width_len->value;

	// make sure stroke width is also scaled to fit area...
	ANDROID_PAINT_SET_STROKE_WIDTH(svg_android, width * svg_android->fit_to_scale);
	DEBUG_EXIT("set_stroke_width");

	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_CREATE(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;
}
Esempio n. 11
0
svg_status_t
_svg_android_apply_view_box (void *closure,
			     svg_view_box_t view_box,
			     svg_length_t *width,
			     svg_length_t *height)
{
	svg_android_t *svg_android = closure;
	double vpar, svgar;
	double logic_width, logic_height;
	double logic_x, logic_y;
	double phys_width, phys_height;

	DEBUG_ENTRY("apply_view_box");
	_svg_android_length_to_pixel (svg_android, width, &phys_width);
	_svg_android_length_to_pixel (svg_android, height, &phys_height);

	vpar = view_box.box.width / view_box.box.height;
	svgar = phys_width / phys_height;
	logic_x = view_box.box.x;
	logic_y = view_box.box.y;
	logic_width = view_box.box.width;
	logic_height = view_box.box.height;

	
	
	if (view_box.aspect_ratio == SVG_PRESERVE_ASPECT_RATIO_NONE)
	{
		ANDROID_MATRIX_SCALE(svg_android,svg_android->state->matrix,
				     phys_width / logic_width,
				     phys_height / logic_height);
		ANDROID_MATRIX_TRANSLATE(svg_android, svg_android->state->matrix, -logic_x, -logic_y);
	}
	else if ((vpar < svgar && view_box.meet_or_slice == SVG_MEET_OR_SLICE_MEET) ||
		 (vpar >= svgar && view_box.meet_or_slice == SVG_MEET_OR_SLICE_SLICE))
	{
		ANDROID_MATRIX_SCALE(svg_android, svg_android->state->matrix,
				     phys_height / logic_height, phys_height / logic_height);

		if (view_box.aspect_ratio == SVG_PRESERVE_ASPECT_RATIO_XMINYMIN ||
		    view_box.aspect_ratio == SVG_PRESERVE_ASPECT_RATIO_XMINYMID ||
		    view_box.aspect_ratio == SVG_PRESERVE_ASPECT_RATIO_XMINYMAX)
			ANDROID_MATRIX_TRANSLATE(
				svg_android, svg_android->state->matrix, -logic_x, -logic_y);
		else if(view_box.aspect_ratio == SVG_PRESERVE_ASPECT_RATIO_XMIDYMIN ||
			view_box.aspect_ratio == SVG_PRESERVE_ASPECT_RATIO_XMIDYMID ||
			view_box.aspect_ratio == SVG_PRESERVE_ASPECT_RATIO_XMIDYMAX)
			ANDROID_MATRIX_TRANSLATE(
				svg_android, svg_android->state->matrix,
				-logic_x -
				(logic_width - phys_width * logic_height / phys_height) / 2,
				-logic_y);
		else
			ANDROID_MATRIX_TRANSLATE(
				svg_android, svg_android->state->matrix,
				-logic_x - (logic_width - phys_width * logic_height / phys_height),
				-logic_y);
	}
	else
	{
		ANDROID_MATRIX_SCALE(svg_android, svg_android->state->matrix,
				     phys_width / logic_width, phys_width / logic_width);

		if (view_box.aspect_ratio == SVG_PRESERVE_ASPECT_RATIO_XMINYMIN ||
		    view_box.aspect_ratio == SVG_PRESERVE_ASPECT_RATIO_XMIDYMIN ||
		    view_box.aspect_ratio == SVG_PRESERVE_ASPECT_RATIO_XMAXYMIN)
			ANDROID_MATRIX_TRANSLATE(
				svg_android, svg_android->state->matrix,
				-logic_x, -logic_y);
		else if(view_box.aspect_ratio == SVG_PRESERVE_ASPECT_RATIO_XMINYMID ||
			view_box.aspect_ratio == SVG_PRESERVE_ASPECT_RATIO_XMIDYMID ||
			view_box.aspect_ratio == SVG_PRESERVE_ASPECT_RATIO_XMAXYMID)
			ANDROID_MATRIX_TRANSLATE(
				svg_android, svg_android->state->matrix,
				-logic_x,
				-logic_y - (logic_height - phys_height * logic_width / phys_width) / 2);
		else
			ANDROID_MATRIX_TRANSLATE(
				svg_android, svg_android->state->matrix,
				-logic_x,
				-logic_y - (logic_height - phys_height * logic_width / phys_width));
	}

	DEBUG_EXIT("apply_view_box");
	return SVG_STATUS_SUCCESS;
}
svg_status_t _svg_android_set_pattern (svg_android_t *svg_android,
			  svg_element_t *pattern_element,
			  svg_android_render_type_t type)
{
	svg_pattern_t *pattern = svg_element_pattern (pattern_element);
	jobject pattern_bitmap;
	jobject pattern_shader;
	double x_px, y_px, width_px, height_px;
	jobject path;

	_svg_android_length_to_pixel (svg_android, &pattern->x, &x_px);
	_svg_android_length_to_pixel (svg_android, &pattern->y, &y_px);
	_svg_android_length_to_pixel (svg_android, &pattern->width, &width_px);
	_svg_android_length_to_pixel (svg_android, &pattern->height, &height_px);

	/* OK. We've got the final path to be filled/stroked inside the
	 * android context right now. But we're also going to re-use that
	 * same context to draw the pattern. And since the path is no
	 * longer in the graphics state, android_save/restore will not help
	 * us here.
	 *
	 * Currently we deal with this by manually saving/restoring the
	 * path.
	 *
	 * It might be simpler to just use a new cairo_t for drawing the
	 * pattern.
	 */
	path = svg_android->state->path; //cairo_copy_path (svg_android->cr);
	svg_android->state->path = ANDROID_PATH_CREATE(svg_android); // cairo_new_path (svg_android->cr);
	ANDROID_SAVE(svg_android);

	pattern_bitmap = ANDROID_CREATE_BITMAP(svg_android,
					       (int) (width_px + 0.5),
					       (int) (height_px + 0.5));
#if 0
	pattern_surface = cairo_surface_create_similar (cairo_get_target (svg_android->cr),
							CAIRO_FORMAT_ARGB32,
							(int) (width_px + 0.5),
							(int) (height_px + 0.5));
#endif
	
	_svg_android_push_state (svg_android, pattern_bitmap);

	svg_android->state->matrix = ANDROID_IDENTITY_MATRIX(svg_android);
	//cairo_identity_matrix (svg_android->cr);
    
	svg_android->state->fill_paint.type = SVG_PAINT_TYPE_NONE;
	svg_android->state->stroke_paint.type = SVG_PAINT_TYPE_NONE;
    
	svg_element_render (pattern->group_element, &SVG_ANDROID_RENDER_ENGINE, svg_android);
	_svg_android_pop_state (svg_android);

	ANDROID_RESTORE(svg_android);

	svg_android->state->path = path ;
#if 0
	cairo_new_path (svg_android->cr);
	cairo_append_path (svg_android->cr, path);
	cairo_path_destroy (path);
#endif

	pattern_shader = ANDROID_CREATE_BITMAP_SHADER(svg_android, pattern_bitmap);
	ANDROID_PAINT_SET_SHADER(svg_android, pattern_shader);

#if 0
	surface_pattern = cairo_pattern_create_for_surface (pattern_surface);
	cairo_surface_destroy (pattern_surface);
    
	cairo_pattern_set_extend (surface_pattern, CAIRO_EXTEND_REPEAT);
    
	cairo_set_source (svg_android->cr, surface_pattern);
    
	cairo_pattern_destroy (surface_pattern);
#endif
	
	return SVG_STATUS_SUCCESS;
}