Merge "LayoutLib: support for layers."
This commit is contained in:
committed by
Android (Google) Code Review
commit
afd8d608cf
6
tests/HwAccelerationTest/res/layout/_layers.xml
Normal file
6
tests/HwAccelerationTest/res/layout/_layers.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.android.test.hwui.LayersActivity.LayersView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
</com.android.test.hwui.LayersActivity.LayersView>
|
||||
6
tests/HwAccelerationTest/res/layout/_newlayers.xml
Normal file
6
tests/HwAccelerationTest/res/layout/_newlayers.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.android.test.hwui.NewLayersActivity.LayersView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
</com.android.test.hwui.NewLayersActivity.LayersView>
|
||||
@@ -33,11 +33,11 @@ public class LayersActivity extends Activity {
|
||||
setContentView(new LayersView(this));
|
||||
}
|
||||
|
||||
static class LayersView extends View {
|
||||
public static class LayersView extends View {
|
||||
private Paint mLayerPaint;
|
||||
private final Paint mRectPaint;
|
||||
|
||||
LayersView(Context c) {
|
||||
public LayersView(Context c) {
|
||||
super(c);
|
||||
|
||||
mLayerPaint = new Paint();
|
||||
@@ -47,11 +47,11 @@ public class LayersActivity extends Activity {
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
|
||||
canvas.translate(140.0f, 100.0f);
|
||||
|
||||
//canvas.drawRGB(255, 255, 255);
|
||||
|
||||
|
||||
int count = canvas.saveLayer(0.0f, 0.0f, 200.0f, 100.0f, mLayerPaint,
|
||||
Canvas.ALL_SAVE_FLAG);
|
||||
|
||||
@@ -59,9 +59,9 @@ public class LayersActivity extends Activity {
|
||||
canvas.drawRect(0.0f, 0.0f, 200.0f, 100.0f, mRectPaint);
|
||||
|
||||
canvas.restoreToCount(count);
|
||||
|
||||
|
||||
canvas.translate(0.0f, 125.0f);
|
||||
|
||||
|
||||
count = canvas.saveLayer(0.0f, 0.0f, 200.0f, 100.0f, mLayerPaint,
|
||||
Canvas.ALL_SAVE_FLAG);
|
||||
|
||||
@@ -75,8 +75,8 @@ public class LayersActivity extends Activity {
|
||||
|
||||
mRectPaint.setColor(0xff0000ff);
|
||||
mRectPaint.setAlpha(255);
|
||||
canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mRectPaint);
|
||||
|
||||
canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mRectPaint);
|
||||
|
||||
mLayerPaint.setAlpha(127);
|
||||
mLayerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
|
||||
count = canvas.saveLayer(50.0f, 25.0f, 150.0f, 75.0f, mLayerPaint,
|
||||
@@ -86,13 +86,13 @@ public class LayersActivity extends Activity {
|
||||
canvas.drawRect(50.0f, 25.0f, 150.0f, 75.0f, mRectPaint);
|
||||
|
||||
canvas.restoreToCount(count);
|
||||
|
||||
|
||||
canvas.translate(0.0f, 125.0f);
|
||||
|
||||
mRectPaint.setColor(0xff0000ff);
|
||||
mRectPaint.setAlpha(255);
|
||||
canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mRectPaint);
|
||||
|
||||
canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mRectPaint);
|
||||
|
||||
mLayerPaint.setColor(0xffff0000);
|
||||
mLayerPaint.setAlpha(127);
|
||||
mLayerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
|
||||
@@ -103,7 +103,7 @@ public class LayersActivity extends Activity {
|
||||
canvas.drawRect(50.0f, 25.0f, 150.0f, 75.0f, mRectPaint);
|
||||
|
||||
canvas.restoreToCount(count);
|
||||
|
||||
|
||||
mLayerPaint = new Paint();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ public class NewLayersActivity extends Activity {
|
||||
setContentView(new LayersView(this));
|
||||
}
|
||||
|
||||
static class LayersView extends View {
|
||||
public static class LayersView extends View {
|
||||
private Paint mLayerPaint;
|
||||
private final Paint mRectPaint;
|
||||
|
||||
LayersView(Context c) {
|
||||
public LayersView(Context c) {
|
||||
super(c);
|
||||
|
||||
mLayerPaint = new Paint();
|
||||
@@ -57,7 +57,7 @@ public class NewLayersActivity extends Activity {
|
||||
|
||||
canvas.translate(0.0f, 200.0f);
|
||||
drawStuff(canvas, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);
|
||||
|
||||
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
|
||||
@@ -23,14 +23,12 @@ import com.android.layoutlib.bridge.impl.GcSnapshot;
|
||||
import android.graphics.Paint_Delegate.FontInfo;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.List;
|
||||
@@ -57,13 +55,9 @@ public final class Canvas_Delegate {
|
||||
|
||||
// ---- delegate helper data ----
|
||||
|
||||
private interface Drawable {
|
||||
void draw(Graphics2D graphics, Paint_Delegate paint);
|
||||
}
|
||||
|
||||
// ---- delegate data ----
|
||||
private BufferedImage mBufferedImage;
|
||||
private GcSnapshot mSnapshot = new GcSnapshot();
|
||||
private GcSnapshot mSnapshot;
|
||||
|
||||
// ---- Public Helper methods ----
|
||||
|
||||
@@ -84,7 +78,7 @@ public final class Canvas_Delegate {
|
||||
/**
|
||||
* Returns the current {@link Graphics2D} used to draw.
|
||||
*/
|
||||
public GcSnapshot getGcSnapshot() {
|
||||
public GcSnapshot getSnapshot() {
|
||||
return mSnapshot;
|
||||
}
|
||||
|
||||
@@ -125,7 +119,7 @@ public final class Canvas_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
canvasDelegate.getGcSnapshot().translate(dx, dy);
|
||||
canvasDelegate.getSnapshot().translate(dx, dy);
|
||||
}
|
||||
|
||||
/*package*/ static void rotate(Canvas thisCanvas, float degrees) {
|
||||
@@ -136,7 +130,7 @@ public final class Canvas_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
canvasDelegate.getGcSnapshot().rotate(Math.toRadians(degrees));
|
||||
canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
|
||||
}
|
||||
|
||||
/*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
|
||||
@@ -147,7 +141,7 @@ public final class Canvas_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
canvasDelegate.getGcSnapshot().scale(sx, sy);
|
||||
canvasDelegate.getSnapshot().scale(sx, sy);
|
||||
}
|
||||
|
||||
/*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
|
||||
@@ -159,7 +153,7 @@ public final class Canvas_Delegate {
|
||||
}
|
||||
|
||||
// get the current top graphics2D object.
|
||||
GcSnapshot g = canvasDelegate.getGcSnapshot();
|
||||
GcSnapshot g = canvasDelegate.getSnapshot();
|
||||
|
||||
// get its current matrix
|
||||
AffineTransform currentTx = g.getTransform();
|
||||
@@ -235,7 +229,7 @@ public final class Canvas_Delegate {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return canvasDelegate.getGcSnapshot().size();
|
||||
return canvasDelegate.getSnapshot().size();
|
||||
}
|
||||
|
||||
/*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
|
||||
@@ -260,33 +254,18 @@ public final class Canvas_Delegate {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/*package*/ static void drawLines(Canvas thisCanvas, float[] pts, int offset, int count,
|
||||
/*package*/ static void drawLines(Canvas thisCanvas,
|
||||
final float[] pts, final int offset, final int count,
|
||||
Paint paint) {
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
|
||||
Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint.mNativePaint);
|
||||
if (paintDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
|
||||
// get a Graphics2D object configured with the drawing parameters.
|
||||
Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate);
|
||||
|
||||
try {
|
||||
for (int i = 0 ; i < count ; i += 4) {
|
||||
g.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
|
||||
(int)pts[i + offset + 2], (int)pts[i + offset + 3]);
|
||||
}
|
||||
} finally {
|
||||
// dispose Graphics2D object
|
||||
g.dispose();
|
||||
}
|
||||
draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
|
||||
new GcSnapshot.Drawable() {
|
||||
public void draw(Graphics2D graphics, Paint_Delegate paint) {
|
||||
for (int i = 0 ; i < count ; i += 4) {
|
||||
graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
|
||||
(int)pts[i + offset + 2], (int)pts[i + offset + 3]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*package*/ static void freeCaches() {
|
||||
@@ -331,29 +310,66 @@ public final class Canvas_Delegate {
|
||||
|
||||
/*package*/ static int native_saveLayer(int nativeCanvas, RectF bounds,
|
||||
int paint, int layerFlags) {
|
||||
// FIXME
|
||||
throw new UnsupportedOperationException();
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
assert false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
|
||||
if (paintDelegate == null) {
|
||||
assert false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return canvasDelegate.saveLayer(bounds, paintDelegate, layerFlags);
|
||||
}
|
||||
|
||||
/*package*/ static int native_saveLayer(int nativeCanvas, float l,
|
||||
float t, float r, float b,
|
||||
int paint, int layerFlags) {
|
||||
// FIXME
|
||||
throw new UnsupportedOperationException();
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
assert false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
|
||||
if (paintDelegate == null) {
|
||||
assert false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return canvasDelegate.saveLayer(new RectF(l, t, r, b),
|
||||
paintDelegate, layerFlags);
|
||||
}
|
||||
|
||||
/*package*/ static int native_saveLayerAlpha(int nativeCanvas,
|
||||
RectF bounds, int alpha,
|
||||
int layerFlags) {
|
||||
// FIXME
|
||||
throw new UnsupportedOperationException();
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
assert false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return canvasDelegate.saveLayerAlpha(bounds, alpha, layerFlags);
|
||||
}
|
||||
|
||||
/*package*/ static int native_saveLayerAlpha(int nativeCanvas, float l,
|
||||
float t, float r, float b,
|
||||
int alpha, int layerFlags) {
|
||||
// FIXME
|
||||
throw new UnsupportedOperationException();
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
assert false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags);
|
||||
}
|
||||
|
||||
|
||||
@@ -372,7 +388,7 @@ public final class Canvas_Delegate {
|
||||
}
|
||||
|
||||
// get the current top graphics2D object.
|
||||
GcSnapshot snapshot = canvasDelegate.getGcSnapshot();
|
||||
GcSnapshot snapshot = canvasDelegate.getSnapshot();
|
||||
|
||||
// get its current matrix
|
||||
AffineTransform currentTx = snapshot.getTransform();
|
||||
@@ -399,7 +415,7 @@ public final class Canvas_Delegate {
|
||||
}
|
||||
|
||||
// get the current top graphics2D object.
|
||||
GcSnapshot snapshot = canvasDelegate.getGcSnapshot();
|
||||
GcSnapshot snapshot = canvasDelegate.getSnapshot();
|
||||
|
||||
// get the AffineTransform of the given matrix
|
||||
AffineTransform matrixTx = matrixDelegate.getAffineTransform();
|
||||
@@ -458,7 +474,7 @@ public final class Canvas_Delegate {
|
||||
return false;
|
||||
}
|
||||
|
||||
Rectangle rect = canvasDelegate.getGcSnapshot().getClip().getBounds();
|
||||
Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds();
|
||||
if (rect != null) {
|
||||
bounds.left = rect.x;
|
||||
bounds.top = rect.y;
|
||||
@@ -511,7 +527,7 @@ public final class Canvas_Delegate {
|
||||
native_drawColor(nativeCanvas, color, PorterDuff.Mode.SRC_OVER.nativeInt);
|
||||
}
|
||||
|
||||
/*package*/ static void native_drawColor(int nativeCanvas, int color, int mode) {
|
||||
/*package*/ static void native_drawColor(int nativeCanvas, final int color, final int mode) {
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
@@ -519,27 +535,26 @@ public final class Canvas_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
// get a new graphics context.
|
||||
Graphics2D graphics = (Graphics2D)canvasDelegate.getGcSnapshot().create();
|
||||
try {
|
||||
// reset its transform just in case
|
||||
graphics.setTransform(new AffineTransform());
|
||||
final int w = canvasDelegate.mBufferedImage.getWidth();
|
||||
final int h = canvasDelegate.mBufferedImage.getHeight();
|
||||
draw(nativeCanvas, new GcSnapshot.Drawable() {
|
||||
|
||||
// set the color
|
||||
graphics.setColor(new Color(color, true /*alpha*/));
|
||||
public void draw(Graphics2D graphics, Paint_Delegate paint) {
|
||||
// reset its transform just in case
|
||||
graphics.setTransform(new AffineTransform());
|
||||
|
||||
Composite composite = PorterDuffXfermode_Delegate.getComposite(
|
||||
PorterDuffXfermode_Delegate.getPorterDuffMode(mode), 0xFF);
|
||||
if (composite != null) {
|
||||
graphics.setComposite(composite);
|
||||
// set the color
|
||||
graphics.setColor(new Color(color, true /*alpha*/));
|
||||
|
||||
Composite composite = PorterDuffXfermode_Delegate.getComposite(
|
||||
PorterDuffXfermode_Delegate.getPorterDuffMode(mode), 0xFF);
|
||||
if (composite != null) {
|
||||
graphics.setComposite(composite);
|
||||
}
|
||||
|
||||
graphics.fillRect(0, 0, w, h);
|
||||
}
|
||||
|
||||
graphics.fillRect(0, 0, canvasDelegate.mBufferedImage.getWidth(),
|
||||
canvasDelegate.mBufferedImage.getHeight());
|
||||
} finally {
|
||||
// dispose Graphics2D object
|
||||
graphics.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*package*/ static void native_drawPaint(int nativeCanvas, int paint) {
|
||||
@@ -547,32 +562,15 @@ public final class Canvas_Delegate {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/*package*/ static void native_drawLine(int nativeCanvas, float startX,
|
||||
float startY, float stopX,
|
||||
float stopY, int paint) {
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
/*package*/ static void native_drawLine(int nativeCanvas,
|
||||
final float startX, final float startY, final float stopX, final float stopY,
|
||||
int paint) {
|
||||
|
||||
// get the delegate from the native int.
|
||||
Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
|
||||
if (paintDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
|
||||
// get a Graphics2D object configured with the drawing parameters.
|
||||
Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate);
|
||||
|
||||
try {
|
||||
g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
|
||||
} finally {
|
||||
// dispose Graphics2D object
|
||||
g.dispose();
|
||||
}
|
||||
draw(nativeCanvas, paint, false /*compositeOnly*/, new GcSnapshot.Drawable() {
|
||||
public void draw(Graphics2D graphics, Paint_Delegate paint) {
|
||||
graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*package*/ static void native_drawRect(int nativeCanvas, RectF rect,
|
||||
@@ -580,82 +578,47 @@ public final class Canvas_Delegate {
|
||||
native_drawRect(nativeCanvas, rect.left, rect.top, rect.right, rect.bottom, paint);
|
||||
}
|
||||
|
||||
/*package*/ static void native_drawRect(int nativeCanvas, float left,
|
||||
float top, float right,
|
||||
float bottom, int paint) {
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
/*package*/ static void native_drawRect(int nativeCanvas,
|
||||
final float left, final float top, final float right, final float bottom, int paint) {
|
||||
|
||||
// get the delegate from the native int.
|
||||
Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
|
||||
if (paintDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (right > left && bottom > top) {
|
||||
// get a Graphics2D object configured with the drawing parameters.
|
||||
Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate);
|
||||
|
||||
try {
|
||||
int style = paintDelegate.getStyle();
|
||||
draw(nativeCanvas, paint, false /*compositeOnly*/, new GcSnapshot.Drawable() {
|
||||
public void draw(Graphics2D graphics, Paint_Delegate paint) {
|
||||
int style = paint.getStyle();
|
||||
|
||||
// draw
|
||||
if (style == Paint.Style.FILL.nativeInt ||
|
||||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
|
||||
g.fillRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
|
||||
graphics.fillRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
|
||||
}
|
||||
|
||||
if (style == Paint.Style.STROKE.nativeInt ||
|
||||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
|
||||
g.drawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
|
||||
graphics.drawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
|
||||
}
|
||||
} finally {
|
||||
// dispose Graphics2D object
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*package*/ static void native_drawOval(int nativeCanvas, RectF oval,
|
||||
int paint) {
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
|
||||
// get the delegate from the native int.
|
||||
Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
|
||||
if (paintDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
|
||||
/*package*/ static void native_drawOval(int nativeCanvas, final RectF oval, int paint) {
|
||||
if (oval.right > oval.left && oval.bottom > oval.top) {
|
||||
// get a Graphics2D object configured with the drawing parameters.
|
||||
Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate);
|
||||
draw(nativeCanvas, paint, false /*compositeOnly*/, new GcSnapshot.Drawable() {
|
||||
public void draw(Graphics2D graphics, Paint_Delegate paint) {
|
||||
int style = paint.getStyle();
|
||||
|
||||
int style = paintDelegate.getStyle();
|
||||
// draw
|
||||
if (style == Paint.Style.FILL.nativeInt ||
|
||||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
|
||||
graphics.fillOval((int)oval.left, (int)oval.top,
|
||||
(int)oval.width(), (int)oval.height());
|
||||
}
|
||||
|
||||
// draw
|
||||
if (style == Paint.Style.FILL.nativeInt ||
|
||||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
|
||||
g.fillOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
|
||||
}
|
||||
|
||||
if (style == Paint.Style.STROKE.nativeInt ||
|
||||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
|
||||
g.drawOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
|
||||
}
|
||||
|
||||
// dispose Graphics2D object
|
||||
g.dispose();
|
||||
if (style == Paint.Style.STROKE.nativeInt ||
|
||||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
|
||||
graphics.drawOval((int)oval.left, (int)oval.top,
|
||||
(int)oval.width(), (int)oval.height());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -675,46 +638,29 @@ public final class Canvas_Delegate {
|
||||
}
|
||||
|
||||
/*package*/ static void native_drawRoundRect(int nativeCanvas,
|
||||
RectF rect, float rx,
|
||||
float ry, int paint) {
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
final RectF rect, final float rx, final float ry, int paint) {
|
||||
|
||||
// get the delegate from the native int.
|
||||
Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
|
||||
if (paintDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
draw(nativeCanvas, paint, false /*compositeOnly*/, new GcSnapshot.Drawable() {
|
||||
|
||||
if (rect.right > rect.left && rect.bottom > rect.top) {
|
||||
// get a Graphics2D object configured with the drawing parameters.
|
||||
Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate);
|
||||
public void draw(Graphics2D graphics, Paint_Delegate paint) {
|
||||
int style = paint.getStyle();
|
||||
|
||||
int style = paintDelegate.getStyle();
|
||||
// draw
|
||||
if (style == Paint.Style.FILL.nativeInt ||
|
||||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
|
||||
graphics.fillRoundRect(
|
||||
(int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
|
||||
(int)rx, (int)ry);
|
||||
}
|
||||
|
||||
// draw
|
||||
if (style == Paint.Style.FILL.nativeInt ||
|
||||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
|
||||
g.fillRoundRect(
|
||||
(int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
|
||||
(int)rx, (int)ry);
|
||||
if (style == Paint.Style.STROKE.nativeInt ||
|
||||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
|
||||
graphics.drawRoundRect(
|
||||
(int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
|
||||
(int)rx, (int)ry);
|
||||
}
|
||||
}
|
||||
|
||||
if (style == Paint.Style.STROKE.nativeInt ||
|
||||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
|
||||
g.drawRoundRect(
|
||||
(int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
|
||||
(int)rx, (int)ry);
|
||||
}
|
||||
|
||||
// dispose Graphics2D object
|
||||
g.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*package*/ static void native_drawPath(int nativeCanvas, int path,
|
||||
@@ -725,7 +671,7 @@ public final class Canvas_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
draw(nativeCanvas, paint, new Drawable() {
|
||||
draw(nativeCanvas, paint, false /*compositeOnly*/, new GcSnapshot.Drawable() {
|
||||
public void draw(Graphics2D graphics, Paint_Delegate paint) {
|
||||
Shape shape = pathDelegate.getJavaShape();
|
||||
int style = paint.getStyle();
|
||||
@@ -846,116 +792,103 @@ public final class Canvas_Delegate {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/*package*/ static void native_drawText(int nativeCanvas, char[] text,
|
||||
int index, int count, float x,
|
||||
float y, int flags, int paint) {
|
||||
// WARNING: the logic in this method is similar to Paint.measureText.
|
||||
// Any change to this method should be reflected in Paint.measureText
|
||||
/*package*/ static void native_drawText(int nativeCanvas,
|
||||
final char[] text, final int index, final int count,
|
||||
final float startX, final float startY, int flags, int paint) {
|
||||
draw(nativeCanvas, paint, false /*compositeOnly*/, new GcSnapshot.Drawable() {
|
||||
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
|
||||
// get the delegate from the native int.
|
||||
Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
|
||||
if (paintDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
|
||||
Graphics2D g = (Graphics2D) canvasDelegate.createCustomGraphics(paintDelegate);
|
||||
try {
|
||||
// Paint.TextAlign indicates how the text is positioned relative to X.
|
||||
// LEFT is the default and there's nothing to do.
|
||||
if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
|
||||
float m = paintDelegate.measureText(text, index, count);
|
||||
if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
|
||||
x -= m / 2;
|
||||
} else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
|
||||
x -= m;
|
||||
}
|
||||
}
|
||||
|
||||
List<FontInfo> fonts = paintDelegate.getFonts();
|
||||
|
||||
if (fonts.size() > 0) {
|
||||
FontInfo mainFont = fonts.get(0);
|
||||
int i = index;
|
||||
int lastIndex = index + count;
|
||||
while (i < lastIndex) {
|
||||
// always start with the main font.
|
||||
int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
|
||||
if (upTo == -1) {
|
||||
// draw all the rest and exit.
|
||||
g.setFont(mainFont.mFont);
|
||||
g.drawChars(text, i, lastIndex - i, (int)x, (int)y);
|
||||
return;
|
||||
} else if (upTo > 0) {
|
||||
// draw what's possible
|
||||
g.setFont(mainFont.mFont);
|
||||
g.drawChars(text, i, upTo - i, (int)x, (int)y);
|
||||
|
||||
// compute the width that was drawn to increase x
|
||||
x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
|
||||
|
||||
// move index to the first non displayed char.
|
||||
i = upTo;
|
||||
|
||||
// don't call continue at this point. Since it is certain the main font
|
||||
// cannot display the font a index upTo (now ==i), we move on to the
|
||||
// fallback fonts directly.
|
||||
public void draw(Graphics2D graphics, Paint_Delegate paint) {
|
||||
// WARNING: the logic in this method is similar to Paint.measureText.
|
||||
// Any change to this method should be reflected in Paint.measureText
|
||||
// Paint.TextAlign indicates how the text is positioned relative to X.
|
||||
// LEFT is the default and there's nothing to do.
|
||||
float x = startX;
|
||||
float y = startY;
|
||||
if (paint.getTextAlign() != Paint.Align.LEFT.nativeInt) {
|
||||
float m = paint.measureText(text, index, count);
|
||||
if (paint.getTextAlign() == Paint.Align.CENTER.nativeInt) {
|
||||
x -= m / 2;
|
||||
} else if (paint.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
|
||||
x -= m;
|
||||
}
|
||||
}
|
||||
|
||||
// no char supported, attempt to read the next char(s) with the
|
||||
// fallback font. In this case we only test the first character
|
||||
// and then go back to test with the main font.
|
||||
// Special test for 2-char characters.
|
||||
boolean foundFont = false;
|
||||
for (int f = 1 ; f < fonts.size() ; f++) {
|
||||
FontInfo fontInfo = fonts.get(f);
|
||||
List<FontInfo> fonts = paint.getFonts();
|
||||
|
||||
// need to check that the font can display the character. We test
|
||||
// differently if the char is a high surrogate.
|
||||
int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
|
||||
upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
|
||||
if (fonts.size() > 0) {
|
||||
FontInfo mainFont = fonts.get(0);
|
||||
int i = index;
|
||||
int lastIndex = index + count;
|
||||
while (i < lastIndex) {
|
||||
// always start with the main font.
|
||||
int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
|
||||
if (upTo == -1) {
|
||||
// draw that char
|
||||
g.setFont(fontInfo.mFont);
|
||||
g.drawChars(text, i, charCount, (int)x, (int)y);
|
||||
// draw all the rest and exit.
|
||||
graphics.setFont(mainFont.mFont);
|
||||
graphics.drawChars(text, i, lastIndex - i, (int)x, (int)y);
|
||||
return;
|
||||
} else if (upTo > 0) {
|
||||
// draw what's possible
|
||||
graphics.setFont(mainFont.mFont);
|
||||
graphics.drawChars(text, i, upTo - i, (int)x, (int)y);
|
||||
|
||||
// update x
|
||||
x += fontInfo.mMetrics.charsWidth(text, i, charCount);
|
||||
// compute the width that was drawn to increase x
|
||||
x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
|
||||
|
||||
// update the index in the text, and move on
|
||||
// move index to the first non displayed char.
|
||||
i = upTo;
|
||||
|
||||
// don't call continue at this point. Since it is certain the main font
|
||||
// cannot display the font a index upTo (now ==i), we move on to the
|
||||
// fallback fonts directly.
|
||||
}
|
||||
|
||||
// no char supported, attempt to read the next char(s) with the
|
||||
// fallback font. In this case we only test the first character
|
||||
// and then go back to test with the main font.
|
||||
// Special test for 2-char characters.
|
||||
boolean foundFont = false;
|
||||
for (int f = 1 ; f < fonts.size() ; f++) {
|
||||
FontInfo fontInfo = fonts.get(f);
|
||||
|
||||
// need to check that the font can display the character. We test
|
||||
// differently if the char is a high surrogate.
|
||||
int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
|
||||
upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
|
||||
if (upTo == -1) {
|
||||
// draw that char
|
||||
graphics.setFont(fontInfo.mFont);
|
||||
graphics.drawChars(text, i, charCount, (int)x, (int)y);
|
||||
|
||||
// update x
|
||||
x += fontInfo.mMetrics.charsWidth(text, i, charCount);
|
||||
|
||||
// update the index in the text, and move on
|
||||
i += charCount;
|
||||
foundFont = true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// in case no font can display the char, display it with the main font.
|
||||
// (it'll put a square probably)
|
||||
if (foundFont == false) {
|
||||
int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
|
||||
|
||||
graphics.setFont(mainFont.mFont);
|
||||
graphics.drawChars(text, i, charCount, (int)x, (int)y);
|
||||
|
||||
// measure it to advance x
|
||||
x += mainFont.mMetrics.charsWidth(text, i, charCount);
|
||||
|
||||
// and move to the next chars.
|
||||
i += charCount;
|
||||
foundFont = true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// in case no font can display the char, display it with the main font.
|
||||
// (it'll put a square probably)
|
||||
if (foundFont == false) {
|
||||
int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
|
||||
|
||||
g.setFont(mainFont.mFont);
|
||||
g.drawChars(text, i, charCount, (int)x, (int)y);
|
||||
|
||||
// measure it to advance x
|
||||
x += mainFont.mMetrics.charsWidth(text, i, charCount);
|
||||
|
||||
// and move to the next chars.
|
||||
i += charCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*package*/ static void native_drawText(int nativeCanvas, String text,
|
||||
@@ -1042,8 +975,11 @@ public final class Canvas_Delegate {
|
||||
|
||||
/**
|
||||
* Executes a {@link Drawable} with a given canvas and paint.
|
||||
* <p>Note that the drawable may actually be executed several times if there are
|
||||
* layers involved (see {@link #saveLayer(RectF, int, int)}.
|
||||
*/
|
||||
private static void draw(int nCanvas, int nPaint, Drawable drawable) {
|
||||
private static void draw(int nCanvas, int nPaint, boolean compositeOnly,
|
||||
GcSnapshot.Drawable drawable) {
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
@@ -1051,28 +987,42 @@ public final class Canvas_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
|
||||
if (paintDelegate == null) {
|
||||
// paint could be 0 meaning no paint
|
||||
Paint_Delegate paintDelegate = null;
|
||||
if (nPaint > 0) {
|
||||
paintDelegate = Paint_Delegate.getDelegate(nPaint);
|
||||
if (paintDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a {@link Drawable} with a given canvas. No paint object will be provided
|
||||
* to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}.
|
||||
* <p>Note that the drawable may actually be executed several times if there are
|
||||
* layers involved (see {@link #saveLayer(RectF, int, int)}.
|
||||
*/
|
||||
private static void draw(int nCanvas, GcSnapshot.Drawable drawable) {
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
|
||||
// get a Graphics2D object configured with the drawing parameters.
|
||||
Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate);
|
||||
|
||||
try {
|
||||
drawable.draw(g, paintDelegate);
|
||||
} finally {
|
||||
// dispose Graphics2D object
|
||||
g.dispose();
|
||||
}
|
||||
canvasDelegate.mSnapshot.draw(drawable);
|
||||
}
|
||||
|
||||
private Canvas_Delegate(BufferedImage image) {
|
||||
setBitmap(image);
|
||||
mSnapshot = GcSnapshot.createDefaultSnapshot(mBufferedImage = image);
|
||||
}
|
||||
|
||||
private Canvas_Delegate() {
|
||||
mSnapshot = GcSnapshot.createDefaultSnapshot(null /*image*/);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1086,8 +1036,23 @@ public final class Canvas_Delegate {
|
||||
// get the current save count
|
||||
int count = mSnapshot.size();
|
||||
|
||||
// create a new snapshot and add it to the stack
|
||||
mSnapshot = new GcSnapshot(mSnapshot, saveFlags);
|
||||
mSnapshot = mSnapshot.save(saveFlags);
|
||||
|
||||
// return the old save count
|
||||
return count;
|
||||
}
|
||||
|
||||
private int saveLayerAlpha(RectF rect, int alpha, int saveFlags) {
|
||||
Paint_Delegate paint = new Paint_Delegate();
|
||||
paint.setAlpha(alpha);
|
||||
return saveLayer(rect, paint, saveFlags);
|
||||
}
|
||||
|
||||
private int saveLayer(RectF rect, Paint_Delegate paint, int saveFlags) {
|
||||
// get the current save count
|
||||
int count = mSnapshot.size();
|
||||
|
||||
mSnapshot = mSnapshot.saveLayer(rect, paint, saveFlags);
|
||||
|
||||
// return the old save count
|
||||
return count;
|
||||
@@ -1116,126 +1081,16 @@ public final class Canvas_Delegate {
|
||||
private void setBitmap(BufferedImage image) {
|
||||
mBufferedImage = image;
|
||||
assert mSnapshot.size() == 1;
|
||||
mSnapshot.setGraphics2D(mBufferedImage.createGraphics());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Graphics2D} based on the {@link Paint} parameters.
|
||||
* <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
|
||||
*/
|
||||
/*package*/ Graphics2D createCustomGraphics(Paint_Delegate paint) {
|
||||
// make new one
|
||||
Graphics2D g = getGcSnapshot().create();
|
||||
|
||||
// configure it
|
||||
|
||||
if (paint.isAntiAliased()) {
|
||||
g.setRenderingHint(
|
||||
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setRenderingHint(
|
||||
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
}
|
||||
|
||||
// get the shader first, as it'll replace the color if it can be used it.
|
||||
boolean customShader = false;
|
||||
int nativeShader = paint.getShader();
|
||||
if (nativeShader > 0) {
|
||||
Shader_Delegate shaderDelegate = Shader_Delegate.getDelegate(nativeShader);
|
||||
assert shaderDelegate != null;
|
||||
if (shaderDelegate != null) {
|
||||
if (shaderDelegate.isSupported()) {
|
||||
java.awt.Paint shaderPaint = shaderDelegate.getJavaPaint();
|
||||
assert shaderPaint != null;
|
||||
if (shaderPaint != null) {
|
||||
g.setPaint(shaderPaint);
|
||||
customShader = true;
|
||||
}
|
||||
} else {
|
||||
Bridge.getLog().fidelityWarning(null,
|
||||
shaderDelegate.getSupportMessage(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no shader, use the paint color
|
||||
if (customShader == false) {
|
||||
g.setColor(new Color(paint.getColor(), true /*hasAlpha*/));
|
||||
}
|
||||
|
||||
boolean customStroke = false;
|
||||
int pathEffect = paint.getPathEffect();
|
||||
if (pathEffect > 0) {
|
||||
PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(pathEffect);
|
||||
assert effectDelegate != null;
|
||||
if (effectDelegate != null) {
|
||||
if (effectDelegate.isSupported()) {
|
||||
Stroke stroke = effectDelegate.getStroke(paint);
|
||||
assert stroke != null;
|
||||
if (stroke != null) {
|
||||
g.setStroke(stroke);
|
||||
customStroke = true;
|
||||
}
|
||||
} else {
|
||||
Bridge.getLog().fidelityWarning(null,
|
||||
effectDelegate.getSupportMessage(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no custom stroke as been set, set the default one.
|
||||
if (customStroke == false) {
|
||||
g.setStroke(new BasicStroke(
|
||||
paint.getStrokeWidth(),
|
||||
paint.getJavaCap(),
|
||||
paint.getJavaJoin(),
|
||||
paint.getJavaStrokeMiter()));
|
||||
}
|
||||
|
||||
// the alpha for the composite. Always opaque if the normal paint color is used since
|
||||
// it contains the alpha
|
||||
int alpha = customShader ? paint.getAlpha() : 0xFF;
|
||||
|
||||
boolean customXfermode = false;
|
||||
int xfermode = paint.getXfermode();
|
||||
if (xfermode > 0) {
|
||||
Xfermode_Delegate xfermodeDelegate = Xfermode_Delegate.getDelegate(paint.getXfermode());
|
||||
assert xfermodeDelegate != null;
|
||||
if (xfermodeDelegate != null) {
|
||||
if (xfermodeDelegate.isSupported()) {
|
||||
Composite composite = xfermodeDelegate.getComposite(alpha);
|
||||
assert composite != null;
|
||||
if (composite != null) {
|
||||
g.setComposite(composite);
|
||||
customXfermode = true;
|
||||
}
|
||||
} else {
|
||||
Bridge.getLog().fidelityWarning(null,
|
||||
xfermodeDelegate.getSupportMessage(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there was no custom xfermode, but we have alpha (due to a shader and a non
|
||||
// opaque alpha channel in the paint color), then we create an AlphaComposite anyway
|
||||
// that will handle the alpha.
|
||||
if (customXfermode == false && alpha != 0xFF) {
|
||||
g.setComposite(PorterDuffXfermode_Delegate.getComposite(
|
||||
PorterDuff.Mode.SRC_OVER, alpha));
|
||||
}
|
||||
|
||||
return g;
|
||||
mSnapshot.setImage(mBufferedImage);
|
||||
}
|
||||
|
||||
private static void drawBitmap(
|
||||
int nativeCanvas,
|
||||
BufferedImage image,
|
||||
Bitmap.Config mBitmapConfig,
|
||||
final BufferedImage image,
|
||||
final Bitmap.Config mBitmapConfig,
|
||||
int nativePaintOrZero,
|
||||
int sleft, int stop, int sright, int sbottom,
|
||||
int dleft, int dtop, int dright, int dbottom) {
|
||||
final int sleft, final int stop, final int sright, final int sbottom,
|
||||
final int dleft, final int dtop, final int dright, final int dbottom) {
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
@@ -1253,47 +1108,35 @@ public final class Canvas_Delegate {
|
||||
}
|
||||
}
|
||||
|
||||
drawBitmap(canvasDelegate, image, mBitmapConfig, paintDelegate,
|
||||
sleft, stop, sright, sbottom,
|
||||
dleft, dtop, dright, dbottom);
|
||||
}
|
||||
// if the bitmap config is alpha_8, then we erase all color value from it
|
||||
// before drawing it.
|
||||
if (mBitmapConfig == Bitmap.Config.ALPHA_8) {
|
||||
int w = image.getWidth();
|
||||
int h = image.getHeight();
|
||||
int[] argb = new int[w*h];
|
||||
image.getRGB(0, 0, image.getWidth(), image.getHeight(),
|
||||
argb, 0, image.getWidth());
|
||||
|
||||
private static void drawBitmap(
|
||||
Canvas_Delegate canvasDelegate,
|
||||
BufferedImage image,
|
||||
Bitmap.Config mBitmapConfig,
|
||||
Paint_Delegate paintDelegate,
|
||||
int sleft, int stop, int sright, int sbottom,
|
||||
int dleft, int dtop, int dright, int dbottom) {
|
||||
//FIXME add support for canvas, screen and bitmap densities.
|
||||
|
||||
Graphics2D g = canvasDelegate.getGcSnapshot().create();
|
||||
try {
|
||||
if (paintDelegate != null && paintDelegate.isFilterBitmap()) {
|
||||
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
final int length = argb.length;
|
||||
for (int i = 0 ; i < length; i++) {
|
||||
argb[i] &= 0xFF000000;
|
||||
}
|
||||
|
||||
// if the bitmap config is alpha_8, then we erase all color value from it
|
||||
// before drawing it.
|
||||
if (mBitmapConfig == Bitmap.Config.ALPHA_8) {
|
||||
int w = image.getWidth();
|
||||
int h = image.getHeight();
|
||||
int[] argb = new int[w*h];
|
||||
image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
|
||||
|
||||
final int length = argb.length;
|
||||
for (int i = 0 ; i < length; i++) {
|
||||
argb[i] &= 0xFF000000;
|
||||
}
|
||||
image.setRGB(0, 0, w, h, argb, 0, w);
|
||||
}
|
||||
|
||||
g.drawImage(image, dleft, dtop, dright, dbottom,
|
||||
sleft, stop, sright, sbottom, null);
|
||||
} finally {
|
||||
g.dispose();
|
||||
image.setRGB(0, 0, w, h, argb, 0, w);
|
||||
}
|
||||
|
||||
draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/,
|
||||
new GcSnapshot.Drawable() {
|
||||
public void draw(Graphics2D graphics, Paint_Delegate paint) {
|
||||
if (paint != null && paint.isFilterBitmap()) {
|
||||
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
}
|
||||
|
||||
//FIXME add support for canvas, screen and bitmap densities.
|
||||
graphics.drawImage(image, dleft, dtop, dright, dbottom,
|
||||
sleft, stop, sright, sbottom, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public class ComposePathEffect_Delegate extends PathEffect_Delegate {
|
||||
|
||||
@Override
|
||||
public String getSupportMessage() {
|
||||
return "Composte Path Effects are not supported in Layout Preview mode.";
|
||||
return "Compose Path Effects are not supported in Layout Preview mode.";
|
||||
}
|
||||
|
||||
// ---- native methods ----
|
||||
|
||||
@@ -55,7 +55,7 @@ public class ComposeShader_Delegate extends Shader_Delegate {
|
||||
|
||||
@Override
|
||||
public String getSupportMessage() {
|
||||
return "Compose Shader are not supported in Layout Preview mode.";
|
||||
return "Compose Shaders are not supported in Layout Preview mode.";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -106,6 +106,45 @@ public final class Matrix_Delegate {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Matrix_Delegate make(AffineTransform matrix) {
|
||||
float[] values = new float[MATRIX_SIZE];
|
||||
values[0] = (float) matrix.getScaleX();
|
||||
values[1] = (float) matrix.getShearX();
|
||||
values[2] = (float) matrix.getTranslateX();
|
||||
values[3] = (float) matrix.getShearY();
|
||||
values[4] = (float) matrix.getScaleY();
|
||||
values[5] = (float) matrix.getTranslateY();
|
||||
values[6] = 0.f;
|
||||
values[7] = 0.f;
|
||||
values[8] = 1.f;
|
||||
|
||||
return new Matrix_Delegate(values);
|
||||
}
|
||||
|
||||
public boolean mapRect(RectF dst, RectF src) {
|
||||
// array with 4 corners
|
||||
float[] corners = new float[] {
|
||||
src.left, src.top,
|
||||
src.right, src.top,
|
||||
src.right, src.bottom,
|
||||
src.left, src.bottom,
|
||||
};
|
||||
|
||||
// apply the transform to them.
|
||||
mapPoints(corners);
|
||||
|
||||
// now put the result in the rect. We take the min/max of Xs and min/max of Ys
|
||||
dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6]));
|
||||
dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6]));
|
||||
|
||||
dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7]));
|
||||
dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7]));
|
||||
|
||||
|
||||
return (computeTypeMask() & kRectStaysRect_Mask) != 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an {@link AffineTransform} matching the matrix.
|
||||
*/
|
||||
@@ -655,26 +694,7 @@ public final class Matrix_Delegate {
|
||||
return false;
|
||||
}
|
||||
|
||||
// array with 4 corners
|
||||
float[] corners = new float[] {
|
||||
src.left, src.top,
|
||||
src.right, src.top,
|
||||
src.right, src.bottom,
|
||||
src.left, src.bottom,
|
||||
};
|
||||
|
||||
// apply the transform to them.
|
||||
d.mapPoints(corners);
|
||||
|
||||
// now put the result in the rect. We take the min/max of Xs and min/max of Ys
|
||||
dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6]));
|
||||
dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6]));
|
||||
|
||||
dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7]));
|
||||
dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7]));
|
||||
|
||||
|
||||
return (d.computeTypeMask() & kRectStaysRect_Mask) != 0;
|
||||
return d.mapRect(dst, src);
|
||||
}
|
||||
|
||||
/*package*/ static float native_mapRadius(int native_object, float radius) {
|
||||
@@ -740,7 +760,6 @@ public final class Matrix_Delegate {
|
||||
matrix[4], matrix[2], matrix[5]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reset a matrix to the identity
|
||||
*/
|
||||
@@ -830,6 +849,10 @@ public final class Matrix_Delegate {
|
||||
reset();
|
||||
}
|
||||
|
||||
private Matrix_Delegate(float[] values) {
|
||||
System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given transformation to the current Matrix
|
||||
* <p/>This in effect does this = this*matrix
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.graphics;
|
||||
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
import com.android.layoutlib.bridge.impl.DelegateManager;
|
||||
import com.android.layoutlib.bridge.impl.GcSnapshot;
|
||||
import com.android.ninepatch.NinePatchChunk;
|
||||
|
||||
import android.graphics.drawable.NinePatchDrawable;
|
||||
@@ -123,11 +124,11 @@ public final class NinePatch_Delegate {
|
||||
}
|
||||
|
||||
private static void draw(int canvas_instance,
|
||||
int left, int top, int right, int bottom,
|
||||
final int left, final int top, final int right, final int bottom,
|
||||
int bitmap_instance, byte[] c, int paint_instance_or_null,
|
||||
int destDensity, int srcDensity) {
|
||||
final int destDensity, final int srcDensity) {
|
||||
// get the delegate from the native int.
|
||||
Bitmap_Delegate bitmap_delegate = Bitmap_Delegate.getDelegate(bitmap_instance);
|
||||
final Bitmap_Delegate bitmap_delegate = Bitmap_Delegate.getDelegate(bitmap_instance);
|
||||
if (bitmap_delegate == null) {
|
||||
assert false;
|
||||
return;
|
||||
@@ -143,7 +144,7 @@ public final class NinePatch_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
NinePatchChunk chunkObject = getChunk(c);
|
||||
final NinePatchChunk chunkObject = getChunk(c);
|
||||
assert chunkObject != null;
|
||||
if (chunkObject == null) {
|
||||
return;
|
||||
@@ -158,19 +159,13 @@ public final class NinePatch_Delegate {
|
||||
// this one can be null
|
||||
Paint_Delegate paint_delegate = Paint_Delegate.getDelegate(paint_instance_or_null);
|
||||
|
||||
Graphics2D graphics;
|
||||
if (paint_delegate != null) {
|
||||
graphics = canvas_delegate.createCustomGraphics(paint_delegate);
|
||||
} else {
|
||||
graphics = canvas_delegate.getGcSnapshot().create();
|
||||
}
|
||||
canvas_delegate.getSnapshot().draw(new GcSnapshot.Drawable() {
|
||||
public void draw(Graphics2D graphics, Paint_Delegate paint) {
|
||||
chunkObject.draw(bitmap_delegate.getImage(), graphics,
|
||||
left, top, right - left, bottom - top, destDensity, srcDensity);
|
||||
}
|
||||
}, paint_delegate, true /*compositeOnly*/);
|
||||
|
||||
try {
|
||||
chunkObject.draw(bitmap_delegate.getImage(), graphics,
|
||||
left, top, right - left, bottom - top, destDensity, srcDensity);
|
||||
} finally {
|
||||
graphics.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ static int nativeGetTransparentRegion(int bitmap, byte[] chunk, Rect location) {
|
||||
|
||||
@@ -118,6 +118,10 @@ public class Paint_Delegate {
|
||||
return mColor >>> 24;
|
||||
}
|
||||
|
||||
public void setAlpha(int alpha) {
|
||||
mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
|
||||
}
|
||||
|
||||
public int getTextAlign() {
|
||||
return mTextAlign;
|
||||
}
|
||||
@@ -130,7 +134,11 @@ public class Paint_Delegate {
|
||||
* returns the value of stroke miter needed by the java api.
|
||||
*/
|
||||
public float getJavaStrokeMiter() {
|
||||
return mStrokeMiter * mStrokeWidth;
|
||||
float miter = mStrokeMiter * mStrokeWidth;
|
||||
if (miter < 1.f) {
|
||||
miter = 1.f;
|
||||
}
|
||||
return miter;
|
||||
}
|
||||
|
||||
public int getJavaCap() {
|
||||
@@ -274,7 +282,7 @@ public class Paint_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
delegate.mColor = (a << 24) | (delegate.mColor & 0x00FFFFFF);
|
||||
delegate.setAlpha(a);
|
||||
}
|
||||
|
||||
/*package*/ static float getStrokeWidth(Paint thisPaint) {
|
||||
@@ -835,7 +843,7 @@ public class Paint_Delegate {
|
||||
|
||||
// ---- Private delegate/helper methods ----
|
||||
|
||||
private Paint_Delegate() {
|
||||
/*package*/ Paint_Delegate() {
|
||||
reset();
|
||||
}
|
||||
|
||||
@@ -866,14 +874,14 @@ public class Paint_Delegate {
|
||||
|
||||
private void reset() {
|
||||
mFlags = Paint.DEFAULT_PAINT_FLAGS;
|
||||
mColor = 0;
|
||||
mColor = 0xFF000000;
|
||||
mStyle = Paint.Style.FILL.nativeInt;
|
||||
mCap = Paint.Cap.BUTT.nativeInt;
|
||||
mJoin = Paint.Join.MITER.nativeInt;
|
||||
mTextAlign = 0;
|
||||
mTypeface = Typeface.sDefaults[0].native_instance;
|
||||
mStrokeWidth = 1.f;
|
||||
mStrokeMiter = 2.f;
|
||||
mStrokeMiter = 4.f;
|
||||
mTextSize = 20.f;
|
||||
mTextScaleX = 1.f;
|
||||
mTextSkewX = 0.f;
|
||||
|
||||
@@ -107,7 +107,8 @@ public class BridgeRenderSession extends RenderSession {
|
||||
Bridge.prepareThread();
|
||||
mLastResult = mSession.acquire(Params.DEFAULT_TIMEOUT);
|
||||
if (mLastResult.isSuccess()) {
|
||||
mLastResult = mSession.insertChild((ViewGroup) parentView, childXml, index, listener);
|
||||
mLastResult = mSession.insertChild((ViewGroup) parentView, childXml, index,
|
||||
listener);
|
||||
}
|
||||
} finally {
|
||||
mSession.release();
|
||||
|
||||
@@ -16,20 +16,42 @@
|
||||
|
||||
package com.android.layoutlib.bridge.impl;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Region;
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Paint_Delegate;
|
||||
import android.graphics.PathEffect_Delegate;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode_Delegate;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.graphics.Shader_Delegate;
|
||||
import android.graphics.Xfermode_Delegate;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Class representing a graphics context snapshot, as well as a context stack as a linked list.
|
||||
* <p>
|
||||
* This is based on top of {@link Graphics2D} but can operate independently if none are available
|
||||
* yet when setting transforms and clip information.
|
||||
* <p>
|
||||
* This allows for drawing through {@link #draw(Drawable, Paint_Delegate)} and
|
||||
* {@link #draw(Drawable, Paint_Delegate)}
|
||||
*
|
||||
*/
|
||||
public class GcSnapshot {
|
||||
@@ -37,38 +59,209 @@ public class GcSnapshot {
|
||||
private final GcSnapshot mPrevious;
|
||||
private final int mFlags;
|
||||
|
||||
private Graphics2D mGraphics2D = null;
|
||||
/** list of layers. */
|
||||
private final ArrayList<Layer> mLayers = new ArrayList<Layer>();
|
||||
|
||||
/** temp transform in case transformation are set before a Graphics2D exists */
|
||||
private AffineTransform mTransform = null;
|
||||
/** temp clip in case clipping is set before a Graphics2D exists */
|
||||
private Area mClip = null;
|
||||
|
||||
// local layer data
|
||||
private final Layer mLocalLayer;
|
||||
private final Paint_Delegate mLocalLayerPaint;
|
||||
private Rect mLocalLayerRegion;
|
||||
|
||||
public interface Drawable {
|
||||
void draw(Graphics2D graphics, Paint_Delegate paint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link GcSnapshot} on top of another one.
|
||||
* <p/>
|
||||
* This is basically the equivalent of {@link Canvas#save(int)}
|
||||
* @param previous the previous snapshot head.
|
||||
* @param flags the flags regarding what should be saved.
|
||||
* class containing information about a layer.
|
||||
*/
|
||||
public GcSnapshot(GcSnapshot previous, int flags) {
|
||||
assert previous != null;
|
||||
mPrevious = previous;
|
||||
mFlags = flags;
|
||||
mGraphics2D = (Graphics2D) previous.mGraphics2D.create();
|
||||
private static class Layer {
|
||||
private final Graphics2D mGraphics;
|
||||
private final BufferedImage mImage;
|
||||
private BufferedImage mOriginalCopy;
|
||||
|
||||
Layer(Graphics2D graphics, BufferedImage image) {
|
||||
mGraphics = graphics;
|
||||
mImage = image;
|
||||
}
|
||||
|
||||
/** The Graphics2D, guaranteed to be non null */
|
||||
Graphics2D getGraphics() {
|
||||
return mGraphics;
|
||||
}
|
||||
|
||||
/** The BufferedImage, guaranteed to be non null */
|
||||
BufferedImage getImage() {
|
||||
return mImage;
|
||||
}
|
||||
|
||||
Layer makeCopy() {
|
||||
return new Layer((Graphics2D) mGraphics.create(), mImage);
|
||||
}
|
||||
|
||||
/** sets an optional copy of the original content to be used during restore */
|
||||
void setOriginalCopy(BufferedImage image) {
|
||||
mOriginalCopy = image;
|
||||
}
|
||||
|
||||
BufferedImage getOriginalCopy() {
|
||||
return mOriginalCopy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the root snapshot associating it with a given image.
|
||||
* <p>
|
||||
* If <var>image</var> is null, then {@link GcSnapshot#setImage(BufferedImage)} must be
|
||||
* called before the snapshot can be used to draw. Transform and clip operations are permitted
|
||||
* before.
|
||||
*
|
||||
* @param image the image to associate to the snapshot or null.
|
||||
* @return the root snapshot
|
||||
*/
|
||||
public static GcSnapshot createDefaultSnapshot(BufferedImage image) {
|
||||
GcSnapshot snapshot = new GcSnapshot();
|
||||
if (image != null) {
|
||||
snapshot.setImage(image);
|
||||
}
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the current state according to the given flags and returns the new current snapshot.
|
||||
* <p/>
|
||||
* This is the equivalent of {@link Canvas#save(int)}
|
||||
*
|
||||
* @param flags the save flags.
|
||||
* @return the new snapshot
|
||||
*
|
||||
* @see Canvas#save(int)
|
||||
*/
|
||||
public GcSnapshot save(int flags) {
|
||||
return new GcSnapshot(this, null /*layerbounds*/, null /*paint*/, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the current state and creates a new layer, and returns the new current snapshot.
|
||||
* <p/>
|
||||
* This is the equivalent of {@link Canvas#saveLayer(RectF, Paint, int)}
|
||||
*
|
||||
* @param layerBounds the layer bounds
|
||||
* @param paint the Paint information used to blit the layer back into the layers underneath
|
||||
* upon restore
|
||||
* @param flags the save flags.
|
||||
* @return the new snapshot
|
||||
*
|
||||
* @see Canvas#saveLayer(RectF, Paint, int)
|
||||
*/
|
||||
public GcSnapshot saveLayer(RectF layerBounds, Paint_Delegate paint, int flags) {
|
||||
return new GcSnapshot(this, layerBounds, paint, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the root snapshot.
|
||||
* {@link #setGraphics2D(Graphics2D)} will have to be called on it when possible.
|
||||
*/
|
||||
public GcSnapshot() {
|
||||
private GcSnapshot() {
|
||||
mPrevious = null;
|
||||
mFlags = 0;
|
||||
mLocalLayer = null;
|
||||
mLocalLayerPaint = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link GcSnapshot} on top of another one, with a layer data to be restored
|
||||
* into the main graphics when {@link #restore()} is called.
|
||||
*
|
||||
* @param previous the previous snapshot head.
|
||||
* @param layerBounds the region of the layer. Optional, if null, this is a normal save()
|
||||
* @param paint the Paint information used to blit the layer back into the layers underneath
|
||||
* upon restore
|
||||
* @param flags the flags regarding what should be saved.
|
||||
*/
|
||||
private GcSnapshot(GcSnapshot previous, RectF layerBounds, Paint_Delegate paint, int flags) {
|
||||
assert previous != null;
|
||||
mPrevious = previous;
|
||||
mFlags = flags;
|
||||
|
||||
// make a copy of the current layers before adding the new one.
|
||||
// This keeps the same BufferedImage reference but creates new Graphics2D for this
|
||||
// snapshot.
|
||||
// It does not copy whatever original copy the layers have, as they will be done
|
||||
// only if the new layer doesn't clip drawing to itself.
|
||||
for (Layer layer : mPrevious.mLayers) {
|
||||
mLayers.add(layer.makeCopy());
|
||||
}
|
||||
|
||||
if (layerBounds != null) {
|
||||
// get the current transform
|
||||
AffineTransform matrix = mLayers.get(0).getGraphics().getTransform();
|
||||
|
||||
// transform the layerBounds and puts it into a int rect
|
||||
RectF rect2 = new RectF();
|
||||
mapRect(matrix, rect2, layerBounds);
|
||||
mLocalLayerRegion = new Rect();
|
||||
rect2.round(mLocalLayerRegion);
|
||||
|
||||
// get the base layer (always at index 0)
|
||||
Layer baseLayer = mLayers.get(0);
|
||||
|
||||
// create the image for the layer
|
||||
BufferedImage layerImage = new BufferedImage(
|
||||
baseLayer.getImage().getWidth(),
|
||||
baseLayer.getImage().getHeight(),
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
// create a graphics for it so that drawing can be done.
|
||||
Graphics2D layerGraphics = layerImage.createGraphics();
|
||||
|
||||
// because this layer inherits the current context for transform and clip,
|
||||
// set them to one from the base layer.
|
||||
AffineTransform currentMtx = baseLayer.getGraphics().getTransform();
|
||||
layerGraphics.setTransform(currentMtx);
|
||||
|
||||
Shape currentClip = baseLayer.getGraphics().getClip();
|
||||
layerGraphics.setClip(currentClip);
|
||||
|
||||
// create a new layer for this new layer and add it to the list at the end.
|
||||
mLayers.add(mLocalLayer = new Layer(layerGraphics, layerImage));
|
||||
|
||||
// if the drawing is not clipped to the local layer only, we save the current content
|
||||
// of all other layers. We are only interested in the part that will actually
|
||||
// be drawn, so we create as small bitmaps as we can.
|
||||
// This is so that we can erase the drawing that goes in the layers below that will
|
||||
// be coming from the layer itself.
|
||||
if ((mFlags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) == 0) {
|
||||
int w = mLocalLayerRegion.width();
|
||||
int h = mLocalLayerRegion.height();
|
||||
for (int i = 0 ; i < mLayers.size() - 1 ; i++) {
|
||||
Layer layer = mLayers.get(i);
|
||||
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D graphics = image.createGraphics();
|
||||
graphics.drawImage(layer.getImage(),
|
||||
0, 0, w, h,
|
||||
mLocalLayerRegion.left, mLocalLayerRegion.top,
|
||||
mLocalLayerRegion.right, mLocalLayerRegion.bottom,
|
||||
null);
|
||||
graphics.dispose();
|
||||
layer.setOriginalCopy(image);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mLocalLayer = null;
|
||||
}
|
||||
|
||||
mLocalLayerPaint = paint;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (mGraphics2D != null) {
|
||||
mGraphics2D.dispose();
|
||||
for (Layer layer : mLayers) {
|
||||
layer.getGraphics().dispose();
|
||||
}
|
||||
|
||||
if (mPrevious != null) {
|
||||
@@ -102,35 +295,35 @@ public class GcSnapshot {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Graphics2D object for this snapshot if it was created through {@link #GcSnapshot()}.
|
||||
* Link the snapshot to a BufferedImage.
|
||||
* <p/>
|
||||
* This is only for the case where the snapshot was created with a null image when calling
|
||||
* {@link #createDefaultSnapshot(BufferedImage)}, and is therefore not yet linked to
|
||||
* a previous snapshot.
|
||||
* <p/>
|
||||
* If any transform or clip information was set before, they are put into the Graphics object.
|
||||
* @param graphics2D the graphics object to set.
|
||||
* @param image the buffered image to link to.
|
||||
*/
|
||||
public void setGraphics2D(Graphics2D graphics2D) {
|
||||
mGraphics2D = graphics2D;
|
||||
public void setImage(BufferedImage image) {
|
||||
assert mLayers.size() == 0;
|
||||
Graphics2D graphics2D = image.createGraphics();
|
||||
mLayers.add(new Layer(graphics2D, image));
|
||||
if (mTransform != null) {
|
||||
mGraphics2D.setTransform(mTransform);
|
||||
graphics2D.setTransform(mTransform);
|
||||
mTransform = null;
|
||||
}
|
||||
|
||||
if (mClip != null) {
|
||||
mGraphics2D.setClip(mClip);
|
||||
graphics2D.setClip(mClip);
|
||||
mClip = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and return a copy of the current {@link Graphics2D}.
|
||||
* @return a new {@link Graphics2D}.
|
||||
*/
|
||||
public Graphics2D create() {
|
||||
assert mGraphics2D != null;
|
||||
return (Graphics2D) mGraphics2D.create();
|
||||
}
|
||||
|
||||
public void translate(float dx, float dy) {
|
||||
if (mGraphics2D != null) {
|
||||
mGraphics2D.translate(dx, dy);
|
||||
if (mLayers.size() > 0) {
|
||||
for (Layer layer : mLayers) {
|
||||
layer.getGraphics().translate(dx, dy);
|
||||
}
|
||||
} else {
|
||||
if (mTransform == null) {
|
||||
mTransform = new AffineTransform();
|
||||
@@ -140,8 +333,10 @@ public class GcSnapshot {
|
||||
}
|
||||
|
||||
public void rotate(double radians) {
|
||||
if (mGraphics2D != null) {
|
||||
mGraphics2D.rotate(radians);
|
||||
if (mLayers.size() > 0) {
|
||||
for (Layer layer : mLayers) {
|
||||
layer.getGraphics().rotate(radians);
|
||||
}
|
||||
} else {
|
||||
if (mTransform == null) {
|
||||
mTransform = new AffineTransform();
|
||||
@@ -151,8 +346,10 @@ public class GcSnapshot {
|
||||
}
|
||||
|
||||
public void scale(float sx, float sy) {
|
||||
if (mGraphics2D != null) {
|
||||
mGraphics2D.scale(sx, sy);
|
||||
if (mLayers.size() > 0) {
|
||||
for (Layer layer : mLayers) {
|
||||
layer.getGraphics().scale(sx, sy);
|
||||
}
|
||||
} else {
|
||||
if (mTransform == null) {
|
||||
mTransform = new AffineTransform();
|
||||
@@ -162,8 +359,9 @@ public class GcSnapshot {
|
||||
}
|
||||
|
||||
public AffineTransform getTransform() {
|
||||
if (mGraphics2D != null) {
|
||||
return mGraphics2D.getTransform();
|
||||
if (mLayers.size() > 0) {
|
||||
// all graphics2D in the list have the same transform
|
||||
return mLayers.get(0).getGraphics().getTransform();
|
||||
} else {
|
||||
if (mTransform == null) {
|
||||
mTransform = new AffineTransform();
|
||||
@@ -173,8 +371,10 @@ public class GcSnapshot {
|
||||
}
|
||||
|
||||
public void setTransform(AffineTransform transform) {
|
||||
if (mGraphics2D != null) {
|
||||
mGraphics2D.setTransform(transform);
|
||||
if (mLayers.size() > 0) {
|
||||
for (Layer layer : mLayers) {
|
||||
layer.getGraphics().setTransform(transform);
|
||||
}
|
||||
} else {
|
||||
if (mTransform == null) {
|
||||
mTransform = new AffineTransform();
|
||||
@@ -184,40 +384,52 @@ public class GcSnapshot {
|
||||
}
|
||||
|
||||
public boolean clipRect(float left, float top, float right, float bottom, int regionOp) {
|
||||
if (mGraphics2D != null) {
|
||||
if (mLayers.size() > 0) {
|
||||
Shape clip = null;
|
||||
if (regionOp == Region.Op.DIFFERENCE.nativeInt) {
|
||||
Area newClip = new Area(mGraphics2D.getClip());
|
||||
Area newClip = new Area(getClip());
|
||||
newClip.subtract(new Area(
|
||||
new Rectangle2D.Float(left, top, right - left, bottom - top)));
|
||||
mGraphics2D.setClip(newClip);
|
||||
clip = newClip;
|
||||
|
||||
} else if (regionOp == Region.Op.INTERSECT.nativeInt) {
|
||||
mGraphics2D.clipRect((int) left, (int) top,
|
||||
(int) (right - left), (int) (bottom - top));
|
||||
for (Layer layer : mLayers) {
|
||||
layer.getGraphics().clipRect(
|
||||
(int) left, (int) top, (int) (right - left), (int) (bottom - top));
|
||||
}
|
||||
|
||||
} else if (regionOp == Region.Op.UNION.nativeInt) {
|
||||
Area newClip = new Area(mGraphics2D.getClip());
|
||||
Area newClip = new Area(getClip());
|
||||
newClip.add(new Area(
|
||||
new Rectangle2D.Float(left, top, right - left, bottom - top)));
|
||||
mGraphics2D.setClip(newClip);
|
||||
clip = newClip;
|
||||
|
||||
} else if (regionOp == Region.Op.XOR.nativeInt) {
|
||||
Area newClip = new Area(mGraphics2D.getClip());
|
||||
Area newClip = new Area(getClip());
|
||||
newClip.exclusiveOr(new Area(
|
||||
new Rectangle2D.Float(left, top, right - left, bottom - top)));
|
||||
mGraphics2D.setClip(newClip);
|
||||
clip = newClip;
|
||||
|
||||
} else if (regionOp == Region.Op.REVERSE_DIFFERENCE.nativeInt) {
|
||||
Area newClip = new Area(
|
||||
new Rectangle2D.Float(left, top, right - left, bottom - top));
|
||||
newClip.subtract(new Area(mGraphics2D.getClip()));
|
||||
mGraphics2D.setClip(newClip);
|
||||
newClip.subtract(new Area(getClip()));
|
||||
clip = newClip;
|
||||
|
||||
} else if (regionOp == Region.Op.REPLACE.nativeInt) {
|
||||
mGraphics2D.setClip((int) left, (int) top,
|
||||
(int) (right - left), (int) (bottom - top));
|
||||
for (Layer layer : mLayers) {
|
||||
layer.getGraphics().setClip(
|
||||
(int) left, (int) top, (int) (right - left), (int) (bottom - top));
|
||||
}
|
||||
}
|
||||
|
||||
return mGraphics2D.getClip().getBounds().isEmpty() == false;
|
||||
if (clip != null) {
|
||||
for (Layer layer : mLayers) {
|
||||
layer.getGraphics().setClip(clip);
|
||||
}
|
||||
}
|
||||
|
||||
return getClip().getBounds().isEmpty() == false;
|
||||
} else {
|
||||
if (mClip == null) {
|
||||
mClip = new Area();
|
||||
@@ -238,8 +450,9 @@ public class GcSnapshot {
|
||||
}
|
||||
|
||||
public Shape getClip() {
|
||||
if (mGraphics2D != null) {
|
||||
return mGraphics2D.getClip();
|
||||
if (mLayers.size() > 0) {
|
||||
// they all have the same clip
|
||||
return mLayers.get(0).getGraphics().getClip();
|
||||
} else {
|
||||
if (mClip == null) {
|
||||
mClip = new Area();
|
||||
@@ -263,26 +476,261 @@ public class GcSnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the Drawable's draw method, with a null paint delegate.
|
||||
* <p/>
|
||||
* Note that the method can be called several times if there are more than one active layer.
|
||||
* @param drawable
|
||||
*/
|
||||
public void draw(Drawable drawable) {
|
||||
draw(drawable, null, false /*compositeOnly*/);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the Drawable's draw method.
|
||||
* <p/>
|
||||
* Note that the method can be called several times if there are more than one active layer.
|
||||
* @param drawable
|
||||
* @param paint
|
||||
* @param compositeOnly whether the paint is used for composite only. This is typically
|
||||
* the case for bitmaps.
|
||||
*/
|
||||
public void draw(Drawable drawable, Paint_Delegate paint, boolean compositeOnly) {
|
||||
// if we clip to the layer, then we only draw in the layer
|
||||
if (mLocalLayer != null && (mFlags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) != 0) {
|
||||
drawInLayer(mLocalLayer, drawable, paint, compositeOnly);
|
||||
} else {
|
||||
// draw in all the layers
|
||||
for (Layer layer : mLayers) {
|
||||
drawInLayer(layer, drawable, paint, compositeOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void drawInLayer(Layer layer, Drawable drawable, Paint_Delegate paint,
|
||||
boolean compositeOnly) {
|
||||
Graphics2D originalGraphics = layer.getGraphics();
|
||||
// get a Graphics2D object configured with the drawing parameters.
|
||||
Graphics2D configuredGraphics2D =
|
||||
paint != null ?
|
||||
createCustomGraphics(originalGraphics, paint, compositeOnly) :
|
||||
(Graphics2D) originalGraphics.create();
|
||||
|
||||
try {
|
||||
drawable.draw(configuredGraphics2D, paint);
|
||||
} finally {
|
||||
// dispose Graphics2D object
|
||||
configuredGraphics2D.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private GcSnapshot doRestore() {
|
||||
// if this snapshot does not save everything, then set the previous snapshot
|
||||
// to this snapshot content
|
||||
if (mPrevious != null) {
|
||||
boolean forceAllSave = false;
|
||||
if (mLocalLayer != null) {
|
||||
forceAllSave = true; // layers always save both clip and transform
|
||||
|
||||
// prepare to draw the current layer in the previous layers, ie all layers but
|
||||
// the last one, since the last one is the local layer
|
||||
for (int i = 0 ; i < mLayers.size() - 1 ; i++) {
|
||||
Layer layer = mLayers.get(i);
|
||||
|
||||
Graphics2D baseGfx = layer.getImage().createGraphics();
|
||||
|
||||
// if the layer contains an original copy this means the flags
|
||||
// didn't restrict drawing to the local layer and we need to make sure the
|
||||
// layer bounds in the layer beneath didn't receive any drawing.
|
||||
// so we use the originalCopy to erase the new drawings in there.
|
||||
BufferedImage originalCopy = layer.getOriginalCopy();
|
||||
if (originalCopy != null) {
|
||||
Graphics2D g = (Graphics2D) baseGfx.create();
|
||||
g.setComposite(AlphaComposite.Src);
|
||||
|
||||
g.drawImage(originalCopy,
|
||||
mLocalLayerRegion.left, mLocalLayerRegion.top,
|
||||
mLocalLayerRegion.right, mLocalLayerRegion.bottom,
|
||||
0, 0, mLocalLayerRegion.width(), mLocalLayerRegion.height(),
|
||||
null);
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
// now draw put the content of the local layer onto the layer, using the paint
|
||||
// information
|
||||
Graphics2D g = createCustomGraphics(baseGfx, mLocalLayerPaint,
|
||||
true /*alphaOnly*/);
|
||||
|
||||
g.drawImage(mLocalLayer.getImage(),
|
||||
mLocalLayerRegion.left, mLocalLayerRegion.top,
|
||||
mLocalLayerRegion.right, mLocalLayerRegion.bottom,
|
||||
mLocalLayerRegion.left, mLocalLayerRegion.top,
|
||||
mLocalLayerRegion.right, mLocalLayerRegion.bottom,
|
||||
null);
|
||||
g.dispose();
|
||||
|
||||
baseGfx.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// if this snapshot does not save everything, then set the previous snapshot
|
||||
// to this snapshot content
|
||||
|
||||
// didn't save the matrix? set the current matrix on the previous snapshot
|
||||
if ((mFlags & Canvas.MATRIX_SAVE_FLAG) == 0) {
|
||||
mPrevious.mGraphics2D.setTransform(getTransform());
|
||||
if (forceAllSave == false && (mFlags & Canvas.MATRIX_SAVE_FLAG) == 0) {
|
||||
AffineTransform mtx = getTransform();
|
||||
for (Layer layer : mPrevious.mLayers) {
|
||||
layer.getGraphics().setTransform(mtx);
|
||||
}
|
||||
}
|
||||
|
||||
// didn't save the clip? set the current clip on the previous snapshot
|
||||
if ((mFlags & Canvas.CLIP_SAVE_FLAG) == 0) {
|
||||
mPrevious.mGraphics2D.setClip(mGraphics2D.getClip());
|
||||
if (forceAllSave == false && (mFlags & Canvas.CLIP_SAVE_FLAG) == 0) {
|
||||
Shape clip = getClip();
|
||||
for (Layer layer : mPrevious.mLayers) {
|
||||
layer.getGraphics().setClip(clip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mGraphics2D != null) {
|
||||
mGraphics2D.dispose();
|
||||
for (Layer layer : mLayers) {
|
||||
layer.getGraphics().dispose();
|
||||
}
|
||||
|
||||
return mPrevious;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Graphics2D} based on the {@link Paint} parameters.
|
||||
* <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
|
||||
*/
|
||||
private Graphics2D createCustomGraphics(Graphics2D original, Paint_Delegate paint,
|
||||
boolean compositeOnly) {
|
||||
// make new one graphics
|
||||
Graphics2D g = (Graphics2D) original.create();
|
||||
|
||||
// configure it
|
||||
|
||||
if (paint.isAntiAliased()) {
|
||||
g.setRenderingHint(
|
||||
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setRenderingHint(
|
||||
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
}
|
||||
|
||||
boolean customShader = false;
|
||||
|
||||
// get the shader first, as it'll replace the color if it can be used it.
|
||||
if (compositeOnly == false) {
|
||||
int nativeShader = paint.getShader();
|
||||
if (nativeShader > 0) {
|
||||
Shader_Delegate shaderDelegate = Shader_Delegate.getDelegate(nativeShader);
|
||||
assert shaderDelegate != null;
|
||||
if (shaderDelegate != null) {
|
||||
if (shaderDelegate.isSupported()) {
|
||||
java.awt.Paint shaderPaint = shaderDelegate.getJavaPaint();
|
||||
assert shaderPaint != null;
|
||||
if (shaderPaint != null) {
|
||||
g.setPaint(shaderPaint);
|
||||
customShader = true;
|
||||
}
|
||||
} else {
|
||||
Bridge.getLog().fidelityWarning(null,
|
||||
shaderDelegate.getSupportMessage(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no shader, use the paint color
|
||||
if (customShader == false) {
|
||||
g.setColor(new Color(paint.getColor(), true /*hasAlpha*/));
|
||||
}
|
||||
|
||||
boolean customStroke = false;
|
||||
int pathEffect = paint.getPathEffect();
|
||||
if (pathEffect > 0) {
|
||||
PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(pathEffect);
|
||||
assert effectDelegate != null;
|
||||
if (effectDelegate != null) {
|
||||
if (effectDelegate.isSupported()) {
|
||||
Stroke stroke = effectDelegate.getStroke(paint);
|
||||
assert stroke != null;
|
||||
if (stroke != null) {
|
||||
g.setStroke(stroke);
|
||||
customStroke = true;
|
||||
}
|
||||
} else {
|
||||
Bridge.getLog().fidelityWarning(null,
|
||||
effectDelegate.getSupportMessage(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no custom stroke as been set, set the default one.
|
||||
if (customStroke == false) {
|
||||
g.setStroke(new BasicStroke(
|
||||
paint.getStrokeWidth(),
|
||||
paint.getJavaCap(),
|
||||
paint.getJavaJoin(),
|
||||
paint.getJavaStrokeMiter()));
|
||||
}
|
||||
}
|
||||
|
||||
// the alpha for the composite. Always opaque if the normal paint color is used since
|
||||
// it contains the alpha
|
||||
int alpha = (compositeOnly || customShader) ? paint.getAlpha() : 0xFF;
|
||||
|
||||
boolean customXfermode = false;
|
||||
int xfermode = paint.getXfermode();
|
||||
if (xfermode > 0) {
|
||||
Xfermode_Delegate xfermodeDelegate = Xfermode_Delegate.getDelegate(paint.getXfermode());
|
||||
assert xfermodeDelegate != null;
|
||||
if (xfermodeDelegate != null) {
|
||||
if (xfermodeDelegate.isSupported()) {
|
||||
Composite composite = xfermodeDelegate.getComposite(alpha);
|
||||
assert composite != null;
|
||||
if (composite != null) {
|
||||
g.setComposite(composite);
|
||||
customXfermode = true;
|
||||
}
|
||||
} else {
|
||||
Bridge.getLog().fidelityWarning(null,
|
||||
xfermodeDelegate.getSupportMessage(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there was no custom xfermode, but we have alpha (due to a shader and a non
|
||||
// opaque alpha channel in the paint color), then we create an AlphaComposite anyway
|
||||
// that will handle the alpha.
|
||||
if (customXfermode == false && alpha != 0xFF) {
|
||||
g.setComposite(PorterDuffXfermode_Delegate.getComposite(
|
||||
PorterDuff.Mode.SRC_OVER, alpha));
|
||||
}
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
|
||||
private void mapRect(AffineTransform matrix, RectF dst, RectF src) {
|
||||
// array with 4 corners
|
||||
float[] corners = new float[] {
|
||||
src.left, src.top,
|
||||
src.right, src.top,
|
||||
src.right, src.bottom,
|
||||
src.left, src.bottom,
|
||||
};
|
||||
|
||||
// apply the transform to them.
|
||||
matrix.transform(corners, 0, corners, 0, 4);
|
||||
|
||||
// now put the result in the rect. We take the min/max of Xs and min/max of Ys
|
||||
dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6]));
|
||||
dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6]));
|
||||
|
||||
dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7]));
|
||||
dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user