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_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; }