package carbon.shadow;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.v8.renderscript.Allocation;
import android.support.v8.renderscript.Element;
import android.support.v8.renderscript.RenderScript;
import android.support.v8.renderscript.ScriptIntrinsicBlur;
import android.view.View;
import carbon.internal.MathUtils;
import carbon.internal.WeakHashSet;
import carbon.widget.RoundedCornersView;
public class ShadowGenerator {
private static Object renderScript;
private static Object blurShader;
private static Paint paint = new Paint();
private static boolean software = false;
private static RectF roundRect = new RectF();
private static WeakHashSet shadowSet = new WeakHashSet();
private static void blur(Bitmap bitmap, float radius) {
if (software) {
blurSoftware(bitmap, radius);
} else {
blurRenderScript(bitmap, radius);
}
}
private static void blurSoftware(Bitmap bitmap, float radius) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
int[] halfResult = new int[width * height];
int rad = (int) Math.ceil(radius);
int rad2plus1 = rad * 2 + 1;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int sumBlack = 0, sumAlpha = 0;
for (int i = -rad; i <= rad; i++) {
int pixel = pixels[y * width + MathUtils.constrain(x + i, 0, width - 1)];
sumBlack += pixel & 0xff;
sumAlpha += (pixel >> 24) & 0xff;
}
int blurredBlack = sumBlack / rad2plus1;
int blurredAlpha = sumAlpha / rad2plus1;
halfResult[y * width + x] = Color.argb(blurredAlpha, blurredBlack, blurredBlack, blurredBlack);
}
}
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int sumBlack = 0, sumAlpha = 0;
for (int i = -rad; i <= rad; i++) {
int pixel = halfResult[MathUtils.constrain(y + i, 0, height - 1) * height + x];
sumBlack += pixel & 0xff;
sumAlpha += (pixel >> 24) & 0xff;
}
int blurredBlack = sumBlack / rad2plus1;
int blurredAlpha = sumAlpha / rad2plus1;
pixels[y * width + x] = Color.argb(blurredAlpha, blurredBlack, blurredBlack, blurredBlack);
}
}
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
}
private static void blurRenderScript(Bitmap bitmap, float radius) {
Allocation inAllocation = Allocation.createFromBitmap((RenderScript) renderScript, bitmap,
Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
Allocation outAllocation = Allocation.createTyped((RenderScript) renderScript, inAllocation.getType());
((ScriptIntrinsicBlur) blurShader).setRadius(radius);
((ScriptIntrinsicBlur) blurShader).setInput(inAllocation);
((ScriptIntrinsicBlur) blurShader).forEach(outAllocation);
outAllocation.copyTo(bitmap);
}
public static Shadow generateShadow(View view, float elevation) {
elevation = MathUtils.constrain(elevation, 0, 25);
if (!software && renderScript == null) {
try {
renderScript = RenderScript.create(view.getContext());
blurShader = ScriptIntrinsicBlur.create((RenderScript) renderScript, Element.U8_4((RenderScript) renderScript));
} catch (Error ignore) {
software = true;
}
}
RoundedCornersView roundedCornersView = (RoundedCornersView) view;
int e = (int) Math.ceil(elevation);
int c = (int) Math.max(e, roundedCornersView.getCornerRadius());
for (Object o : shadowSet) {
Shadow s = (Shadow) o;
if (s != null && s.elevation == elevation && s.cornerRadius == c)
return s;
}
Bitmap bitmap;
int bitmapSize = e * 2 + 2 * c + 1;
bitmap = Bitmap.createBitmap(bitmapSize, bitmapSize, Bitmap.Config.ARGB_8888);
Canvas shadowCanvas = new Canvas(bitmap);
paint.setStyle(Paint.Style.FILL);
paint.setColor(0xffffffff);
roundRect.set(e, e, bitmapSize - e, bitmapSize - e);
shadowCanvas.drawRoundRect(roundRect, c, c, paint);
blur(bitmap, elevation);
Shadow shadow = new Shadow(bitmap, elevation, c, view.getContext().getResources().getDisplayMetrics().density);
shadowSet.add(shadow);
return shadow;
}
}