package com.iiordanov.android.drawing;
import com.iiordanov.util.ObjectPool;
import com.iiordanov.util.SafeObjectPool;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
public class OverlappingCopy
{
private static SafeObjectPool<Rect> ocRectPool = new SafeObjectPool<Rect>() {
@Override
protected Rect itemForPool()
{
return new Rect();
}
};
private static void transformRect(Rect source, Rect transformedSource, int deltaX, int deltaY)
{
transformedSource.set(deltaX < 0 ? source.right * -1 : source.left,
deltaY < 0 ? source.bottom * -1 : source.top,
deltaX < 0 ? source.left * -1 : source.right,
deltaY < 0 ? source.top * -1 : source.bottom);
}
private static void copyTransformedRect(Rect stepSourceRect, Rect stepDestRect, int deltaX, int deltaY, Bitmap data, Canvas bitmapBackedCanvas, Paint paint)
{
transformRect(stepSourceRect,stepSourceRect,deltaX,deltaY);
stepDestRect.set(stepSourceRect);
stepDestRect.offset(deltaX,deltaY);
bitmapBackedCanvas.drawBitmap(data, stepSourceRect, stepDestRect, paint);
}
public static void Copy(Bitmap data, Canvas bitmapBackedCanvas, Paint paint, Rect source, int destX, int destY)
{
Copy(data,bitmapBackedCanvas,paint,source,destX,destY,ocRectPool);
}
public static void Copy(Bitmap data, Canvas bitmapBackedCanvas, Paint paint, Rect source, int destX, int destY, ObjectPool<Rect> rectPool)
{
//android.util.Log.i("LBM","Copy "+source.toString()+" to "+destX+","+destY);
int deltaX = destX - source.left;
int deltaY = destY - source.top;
int absDeltaX = deltaX < 0 ? -deltaX : deltaX;
int absDeltaY = deltaY < 0 ? -deltaY : deltaY;
// Look for degenerate case
if (absDeltaX == 0 && absDeltaY == 0)
return;
// Look for non-overlap case
if (absDeltaX >= source.right - source.left || absDeltaY >= source.bottom - source.top)
{
// Non-overlapping copy
ObjectPool.Entry<Rect> entry = rectPool.reserve();
Rect dest = entry.get();
dest.set(source.left + deltaX, source.top + deltaY, source.right + deltaX, source.bottom + deltaY);
bitmapBackedCanvas.drawBitmap(data, source, dest, paint);
rectPool.release(entry);
return;
}
// Determine coordinate transform so that dest rectangle is always down and to the right.
ObjectPool.Entry<Rect> transformedSourceEntry = rectPool.reserve();
Rect transformedSource = transformedSourceEntry.get();
transformRect(source,transformedSource,deltaX,deltaY);
ObjectPool.Entry<Rect> transformedDestEntry = rectPool.reserve();
Rect transformedDest = transformedDestEntry.get();
transformedDest.set(transformedSource);
transformedDest.offset(absDeltaX, absDeltaY);
ObjectPool.Entry<Rect> intersectEntry = rectPool.reserve();
Rect intersect = intersectEntry.get();
intersect.setIntersect(transformedSource, transformedDest);
boolean xStepDone = false;
int xStepWidth;
int yStepHeight;
if (absDeltaX > absDeltaY)
{
xStepWidth = absDeltaX;
yStepHeight = source.bottom - source.top - absDeltaY;
}
else
{
xStepWidth = source.right - source.left - absDeltaX;
yStepHeight = absDeltaY;
}
ObjectPool.Entry<Rect> stepSourceEntry = rectPool.reserve();
Rect stepSourceRect = stepSourceEntry.get();
ObjectPool.Entry<Rect> stepDestEntry = rectPool.reserve();
Rect stepDestRect = stepDestEntry.get();
for (int xStep = 0; ! xStepDone; xStep++)
{
int stepRight = intersect.right - xStep * xStepWidth;
int stepLeft = stepRight - xStepWidth;
if (stepLeft <= intersect.left)
{
stepLeft = intersect.left;
xStepDone = true;
}
boolean yStepDone = false;
for (int yStep = 0; ! yStepDone; yStep++)
{
int stepBottom = intersect.bottom - yStep * yStepHeight;
int stepTop = stepBottom - yStepHeight;
if (stepTop <= intersect.top)
{
stepTop = intersect.top;
yStepDone = true;
}
stepSourceRect.set(stepLeft,stepTop,stepRight,stepBottom);
//android.util.Log.i("LBM","Copy transformed "+stepSourceRect.toString()+" "+deltaX+" "+deltaY);
copyTransformedRect(stepSourceRect, stepDestRect, deltaX, deltaY, data, bitmapBackedCanvas, paint);
}
}
if (absDeltaX>0)
{
// Copy left edge
stepSourceRect.set(transformedSource.left,transformedSource.top,intersect.left,transformedSource.bottom);
copyTransformedRect(stepSourceRect, stepDestRect, deltaX, deltaY, data, bitmapBackedCanvas, paint);
}
if (absDeltaY>0)
{
// Copy top excluding left edge
stepSourceRect.set(intersect.left,transformedSource.top,transformedSource.right,intersect.top);
copyTransformedRect(stepSourceRect, stepDestRect, deltaX, deltaY, data, bitmapBackedCanvas, paint);
}
rectPool.release(stepDestEntry);
rectPool.release(stepSourceEntry);
rectPool.release(intersectEntry);
rectPool.release(transformedDestEntry);
rectPool.release(transformedSourceEntry);
}
}