Merge "LayoutLib: replace the stack of Graphics2D with custom snapshots."
This commit is contained in:
committed by
Android (Google) Code Review
commit
971ea63a66
@@ -18,7 +18,7 @@ package android.graphics;
|
||||
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
import com.android.layoutlib.bridge.impl.DelegateManager;
|
||||
import com.android.layoutlib.bridge.impl.Stack;
|
||||
import com.android.layoutlib.bridge.impl.GcSnapshot;
|
||||
|
||||
import android.graphics.Paint_Delegate.FontInfo;
|
||||
import android.text.TextUtils;
|
||||
@@ -26,7 +26,6 @@ import android.text.TextUtils;
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
@@ -58,7 +57,7 @@ public class Canvas_Delegate {
|
||||
|
||||
// ---- delegate data ----
|
||||
private BufferedImage mBufferedImage;
|
||||
private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>();
|
||||
private GcSnapshot mSnapshot = new GcSnapshot();
|
||||
|
||||
// ---- Public Helper methods ----
|
||||
|
||||
@@ -79,8 +78,8 @@ public class Canvas_Delegate {
|
||||
/**
|
||||
* Returns the current {@link Graphics2D} used to draw.
|
||||
*/
|
||||
public Graphics2D getGraphics2d() {
|
||||
return mGraphicsStack.peek();
|
||||
public GcSnapshot getGcSnapshot() {
|
||||
return mSnapshot;
|
||||
}
|
||||
|
||||
// ---- native methods ----
|
||||
@@ -120,7 +119,7 @@ public class Canvas_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
canvasDelegate.getGraphics2d().translate(dx, dy);
|
||||
canvasDelegate.getGcSnapshot().translate(dx, dy);
|
||||
}
|
||||
|
||||
/*package*/ static void rotate(Canvas thisCanvas, float degrees) {
|
||||
@@ -131,7 +130,7 @@ public class Canvas_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
canvasDelegate.getGraphics2d().rotate(Math.toRadians(degrees));
|
||||
canvasDelegate.getGcSnapshot().rotate(Math.toRadians(degrees));
|
||||
}
|
||||
|
||||
/*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
|
||||
@@ -142,7 +141,7 @@ public class Canvas_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
canvasDelegate.getGraphics2d().scale(sx, sy);
|
||||
canvasDelegate.getGcSnapshot().scale(sx, sy);
|
||||
}
|
||||
|
||||
/*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
|
||||
@@ -154,7 +153,7 @@ public class Canvas_Delegate {
|
||||
}
|
||||
|
||||
// get the current top graphics2D object.
|
||||
Graphics2D g = canvasDelegate.getGraphics2d();
|
||||
GcSnapshot g = canvasDelegate.getGcSnapshot();
|
||||
|
||||
// get its current matrix
|
||||
AffineTransform currentTx = g.getTransform();
|
||||
@@ -170,21 +169,16 @@ public class Canvas_Delegate {
|
||||
}
|
||||
|
||||
/*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) {
|
||||
return clipRect(thisCanvas,
|
||||
(int) rect.left, (int) rect.top, (int) rect.right, (int) rect.bottom);
|
||||
return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom);
|
||||
}
|
||||
|
||||
/*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) {
|
||||
return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom);
|
||||
return clipRect(thisCanvas, (float) rect.left, (float) rect.top,
|
||||
(float) rect.right, (float) rect.bottom);
|
||||
}
|
||||
|
||||
/*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
|
||||
float bottom) {
|
||||
return clipRect(thisCanvas, (int) left, (int) top, (int) right, (int) bottom);
|
||||
}
|
||||
|
||||
/*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right,
|
||||
int bottom) {
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
@@ -195,7 +189,17 @@ public class Canvas_Delegate {
|
||||
return canvasDelegate.clipRect(left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
|
||||
}
|
||||
|
||||
/*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right,
|
||||
int bottom) {
|
||||
|
||||
return clipRect(thisCanvas, (float) left, (float) top, (float) right, (float) bottom);
|
||||
}
|
||||
|
||||
/*package*/ static int save(Canvas thisCanvas) {
|
||||
return save(thisCanvas, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG);
|
||||
}
|
||||
|
||||
/*package*/ static int save(Canvas thisCanvas, int saveFlags) {
|
||||
// get the delegate from the native int.
|
||||
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
|
||||
if (canvasDelegate == null) {
|
||||
@@ -203,21 +207,7 @@ public class Canvas_Delegate {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get the current save count
|
||||
int count = canvasDelegate.mGraphicsStack.size();
|
||||
|
||||
// create a new graphics and add it to the stack
|
||||
Graphics2D g = (Graphics2D)canvasDelegate.getGraphics2d().create();
|
||||
canvasDelegate.mGraphicsStack.push(g);
|
||||
|
||||
// return the old save count
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
/*package*/ static int save(Canvas thisCanvas, int saveFlags) {
|
||||
// FIXME implement save(flags)
|
||||
return save(thisCanvas);
|
||||
return canvasDelegate.save(saveFlags);
|
||||
}
|
||||
|
||||
/*package*/ static void restore(Canvas thisCanvas) {
|
||||
@@ -228,7 +218,7 @@ public class Canvas_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
canvasDelegate.mGraphicsStack.pop();
|
||||
canvasDelegate.restore();
|
||||
}
|
||||
|
||||
/*package*/ static int getSaveCount(Canvas thisCanvas) {
|
||||
@@ -239,7 +229,7 @@ public class Canvas_Delegate {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return canvasDelegate.mGraphicsStack.size();
|
||||
return canvasDelegate.getGcSnapshot().size();
|
||||
}
|
||||
|
||||
/*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
|
||||
@@ -250,9 +240,7 @@ public class Canvas_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
while (canvasDelegate.mGraphicsStack.size() > saveCount) {
|
||||
canvasDelegate.mGraphicsStack.pop();
|
||||
}
|
||||
canvasDelegate.restoreTo(saveCount);
|
||||
}
|
||||
|
||||
/*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count,
|
||||
@@ -282,7 +270,7 @@ public class Canvas_Delegate {
|
||||
}
|
||||
|
||||
// get a Graphics2D object configured with the drawing parameters.
|
||||
Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate);
|
||||
Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate);
|
||||
|
||||
try {
|
||||
for (int i = 0 ; i < count ; i += 4) {
|
||||
@@ -378,10 +366,10 @@ public class Canvas_Delegate {
|
||||
}
|
||||
|
||||
// get the current top graphics2D object.
|
||||
Graphics2D g = canvasDelegate.getGraphics2d();
|
||||
GcSnapshot snapshot = canvasDelegate.getGcSnapshot();
|
||||
|
||||
// get its current matrix
|
||||
AffineTransform currentTx = g.getTransform();
|
||||
AffineTransform currentTx = snapshot.getTransform();
|
||||
// get the AffineTransform of the given matrix
|
||||
AffineTransform matrixTx = matrixDelegate.getAffineTransform();
|
||||
|
||||
@@ -389,7 +377,7 @@ public class Canvas_Delegate {
|
||||
currentTx.preConcatenate(matrixTx);
|
||||
|
||||
// give it to the graphics2D as a new matrix replacing all previous transform
|
||||
g.setTransform(currentTx);
|
||||
snapshot.setTransform(currentTx);
|
||||
}
|
||||
|
||||
/*package*/ static void native_setMatrix(int nCanvas, int nMatrix) {
|
||||
@@ -405,15 +393,16 @@ public class Canvas_Delegate {
|
||||
}
|
||||
|
||||
// get the current top graphics2D object.
|
||||
Graphics2D g = canvasDelegate.getGraphics2d();
|
||||
GcSnapshot snapshot = canvasDelegate.getGcSnapshot();
|
||||
|
||||
// get the AffineTransform of the given matrix
|
||||
AffineTransform matrixTx = matrixDelegate.getAffineTransform();
|
||||
|
||||
// give it to the graphics2D as a new matrix replacing all previous transform
|
||||
g.setTransform(matrixTx);
|
||||
snapshot.setTransform(matrixTx);
|
||||
|
||||
if (matrixDelegate.hasPerspective()) {
|
||||
assert false;
|
||||
Bridge.getLog().warning(null,
|
||||
"android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " +
|
||||
"supports affine transformations in the Layout Preview.");
|
||||
@@ -431,9 +420,7 @@ public class Canvas_Delegate {
|
||||
assert false;
|
||||
}
|
||||
|
||||
return canvasDelegate.clipRect(
|
||||
(int) left, (int) top, (int) right, (int) bottom,
|
||||
regionOp);
|
||||
return canvasDelegate.clipRect(left, top, right, bottom, regionOp);
|
||||
}
|
||||
|
||||
/*package*/ static boolean native_clipPath(int nativeCanvas,
|
||||
@@ -465,7 +452,7 @@ public class Canvas_Delegate {
|
||||
return false;
|
||||
}
|
||||
|
||||
Rectangle rect = canvasDelegate.getGraphics2d().getClipBounds();
|
||||
Rectangle rect = canvasDelegate.getGcSnapshot().getClip().getBounds();
|
||||
if (rect != null) {
|
||||
bounds.left = rect.x;
|
||||
bounds.top = rect.y;
|
||||
@@ -527,7 +514,7 @@ public class Canvas_Delegate {
|
||||
}
|
||||
|
||||
// get a new graphics context.
|
||||
Graphics2D graphics = (Graphics2D)canvasDelegate.getGraphics2d().create();
|
||||
Graphics2D graphics = (Graphics2D)canvasDelegate.getGcSnapshot().create();
|
||||
try {
|
||||
// reset its transform just in case
|
||||
graphics.setTransform(new AffineTransform());
|
||||
@@ -568,12 +555,14 @@ public class Canvas_Delegate {
|
||||
}
|
||||
|
||||
// get a Graphics2D object configured with the drawing parameters.
|
||||
Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate);
|
||||
Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate);
|
||||
|
||||
g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
|
||||
|
||||
// dispose Graphics2D object
|
||||
g.dispose();
|
||||
try {
|
||||
g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
|
||||
} finally {
|
||||
// dispose Graphics2D object
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ static void native_drawRect(int nativeCanvas, RectF rect,
|
||||
@@ -600,23 +589,25 @@ public class Canvas_Delegate {
|
||||
|
||||
if (right > left && bottom > top) {
|
||||
// get a Graphics2D object configured with the drawing parameters.
|
||||
Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate);
|
||||
Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate);
|
||||
|
||||
int style = paintDelegate.getStyle();
|
||||
try {
|
||||
int style = paintDelegate.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));
|
||||
// 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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
} finally {
|
||||
// dispose Graphics2D object
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
// dispose Graphics2D object
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -638,7 +629,7 @@ public class Canvas_Delegate {
|
||||
|
||||
if (oval.right > oval.left && oval.bottom > oval.top) {
|
||||
// get a Graphics2D object configured with the drawing parameters.
|
||||
Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate);
|
||||
Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate);
|
||||
|
||||
int style = paintDelegate.getStyle();
|
||||
|
||||
@@ -692,7 +683,7 @@ public class Canvas_Delegate {
|
||||
|
||||
if (rect.right > rect.left && rect.bottom > rect.top) {
|
||||
// get a Graphics2D object configured with the drawing parameters.
|
||||
Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate);
|
||||
Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate);
|
||||
|
||||
int style = paintDelegate.getStyle();
|
||||
|
||||
@@ -833,7 +824,7 @@ public class Canvas_Delegate {
|
||||
return;
|
||||
}
|
||||
|
||||
Graphics2D g = (Graphics2D) canvasDelegate.getCustomGraphics(paintDelegate);
|
||||
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.
|
||||
@@ -1018,34 +1009,53 @@ public class Canvas_Delegate {
|
||||
* Disposes of the {@link Graphics2D} stack.
|
||||
*/
|
||||
private void dispose() {
|
||||
while (mGraphicsStack.size() > 0) {
|
||||
mGraphicsStack.pop().dispose();
|
||||
}
|
||||
mSnapshot.dispose();
|
||||
}
|
||||
|
||||
private boolean clipRect(int left, int top, int right, int bottom, int regionOp) {
|
||||
if (regionOp == Region.Op.INTERSECT.nativeInt) {
|
||||
Graphics2D gc = getGraphics2d();
|
||||
gc.clipRect(left, top, right - left, bottom - top);
|
||||
return gc.getClip().getBounds().isEmpty() == false;
|
||||
} else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
private int save(int saveFlags) {
|
||||
// get the current save count
|
||||
int count = mSnapshot.size();
|
||||
|
||||
// create a new snapshot and add it to the stack
|
||||
mSnapshot = new GcSnapshot(mSnapshot, saveFlags);
|
||||
|
||||
// return the old save count
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the {@link GcSnapshot} to <var>saveCount</var>
|
||||
* @param saveCount the saveCount
|
||||
*/
|
||||
private void restoreTo(int saveCount) {
|
||||
mSnapshot = mSnapshot.restoreTo(saveCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the {@link GcSnapshot} to <var>saveCount</var>
|
||||
* @param saveCount the saveCount
|
||||
*/
|
||||
private void restore() {
|
||||
mSnapshot = mSnapshot.restore();
|
||||
}
|
||||
|
||||
private boolean clipRect(float left, float top, float right, float bottom, int regionOp) {
|
||||
return mSnapshot.clipRect(left, top, right, bottom, regionOp);
|
||||
}
|
||||
|
||||
private void setBitmap(BufferedImage image) {
|
||||
mBufferedImage = image;
|
||||
mGraphicsStack.push(mBufferedImage.createGraphics());
|
||||
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 getCustomGraphics(Paint_Delegate paint) {
|
||||
/*package*/ Graphics2D createCustomGraphics(Paint_Delegate paint) {
|
||||
// make new one
|
||||
Graphics2D g = getGraphics2d();
|
||||
g = (Graphics2D)g.create();
|
||||
Graphics2D g = getGcSnapshot().create();
|
||||
|
||||
// configure it
|
||||
|
||||
@@ -1062,6 +1072,7 @@ public class Canvas_Delegate {
|
||||
Shader_Delegate shaderDelegate = Shader_Delegate.getDelegate(paint.getShader());
|
||||
if (shaderDelegate != null) {
|
||||
java.awt.Paint shaderPaint = shaderDelegate.getJavaPaint();
|
||||
assert shaderPaint != null;
|
||||
if (shaderPaint != null) {
|
||||
g.setPaint(shaderPaint);
|
||||
useColorPaint = false;
|
||||
@@ -1113,6 +1124,7 @@ public class Canvas_Delegate {
|
||||
|
||||
// if xfermode wasn't null, then it's something we don't support. log it.
|
||||
if (xfermodeDelegate != null) {
|
||||
assert false;
|
||||
Bridge.getLog().warning(null,
|
||||
String.format(
|
||||
"Xfermode '%1$s' is not supported in the Layout Preview.",
|
||||
@@ -1217,30 +1229,18 @@ public class Canvas_Delegate {
|
||||
int sleft, int stop, int sright, int sbottom,
|
||||
int dleft, int dtop, int dright, int dbottom) {
|
||||
|
||||
Graphics2D g = canvasDelegate.getGraphics2d();
|
||||
|
||||
Composite c = null;
|
||||
|
||||
if (paintDelegate != null) {
|
||||
if (paintDelegate.isFilterBitmap()) {
|
||||
g = (Graphics2D)g.create();
|
||||
Graphics2D g = canvasDelegate.getGcSnapshot().create();
|
||||
try {
|
||||
if (paintDelegate != null && paintDelegate.isFilterBitmap()) {
|
||||
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
}
|
||||
}
|
||||
|
||||
g.drawImage(image, dleft, dtop, dright, dbottom,
|
||||
sleft, stop, sright, sbottom, null);
|
||||
|
||||
if (paintDelegate != null) {
|
||||
if (paintDelegate.isFilterBitmap()) {
|
||||
g.dispose();
|
||||
}
|
||||
if (c != null) {
|
||||
g.setComposite(c);
|
||||
}
|
||||
g.drawImage(image, dleft, dtop, dright, dbottom,
|
||||
sleft, stop, sright, sbottom, null);
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -195,7 +195,8 @@ public final class Matrix_Delegate {
|
||||
setTranslate(d.mValues, dx, dy);
|
||||
}
|
||||
|
||||
/*package*/ static void native_setScale(int native_object, float sx, float sy, float px, float py) {
|
||||
/*package*/ static void native_setScale(int native_object, float sx, float sy,
|
||||
float px, float py) {
|
||||
Matrix_Delegate d = sManager.getDelegate(native_object);
|
||||
if (d == null) {
|
||||
assert false;
|
||||
@@ -272,7 +273,8 @@ public final class Matrix_Delegate {
|
||||
setRotate(d.mValues, sinValue, cosValue);
|
||||
}
|
||||
|
||||
/*package*/ static void native_setSkew(int native_object, float kx, float ky, float px, float py) {
|
||||
/*package*/ static void native_setSkew(int native_object, float kx, float ky,
|
||||
float px, float py) {
|
||||
Matrix_Delegate d = sManager.getDelegate(native_object);
|
||||
if (d == null) {
|
||||
assert false;
|
||||
@@ -364,7 +366,8 @@ public final class Matrix_Delegate {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*package*/ static boolean native_preRotate(int native_object, float degrees, float px, float py) {
|
||||
/*package*/ static boolean native_preRotate(int native_object, float degrees,
|
||||
float px, float py) {
|
||||
Matrix_Delegate d = sManager.getDelegate(native_object);
|
||||
if (d == null) {
|
||||
assert false;
|
||||
@@ -464,7 +467,8 @@ public final class Matrix_Delegate {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*package*/ static boolean native_postRotate(int native_object, float degrees, float px, float py) {
|
||||
/*package*/ static boolean native_postRotate(int native_object, float degrees,
|
||||
float px, float py) {
|
||||
Matrix_Delegate d = sManager.getDelegate(native_object);
|
||||
if (d == null) {
|
||||
assert false;
|
||||
@@ -526,7 +530,8 @@ public final class Matrix_Delegate {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*package*/ static boolean native_setRectToRect(int native_object, RectF src, RectF dst, int stf) {
|
||||
/*package*/ static boolean native_setRectToRect(int native_object, RectF src,
|
||||
RectF dst, int stf) {
|
||||
Matrix_Delegate d = sManager.getDelegate(native_object);
|
||||
if (d == null) {
|
||||
assert false;
|
||||
|
||||
@@ -160,20 +160,17 @@ public class NinePatch_Delegate {
|
||||
|
||||
Graphics2D graphics;
|
||||
if (paint_delegate != null) {
|
||||
graphics = canvas_delegate.getCustomGraphics(paint_delegate);
|
||||
graphics = canvas_delegate.createCustomGraphics(paint_delegate);
|
||||
} else {
|
||||
graphics = canvas_delegate.getGraphics2d();
|
||||
graphics = canvas_delegate.getGcSnapshot().create();
|
||||
}
|
||||
|
||||
try {
|
||||
chunkObject.draw(bitmap_delegate.getImage(), graphics,
|
||||
left, top, right - left, bottom - top, destDensity, srcDensity);
|
||||
} finally {
|
||||
if (paint_delegate != null) {
|
||||
graphics.dispose();
|
||||
}
|
||||
graphics.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*package*/ static int nativeGetTransparentRegion(int bitmap, byte[] chunk, Rect location) {
|
||||
|
||||
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.layoutlib.bridge.impl;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Region;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
public class GcSnapshot {
|
||||
|
||||
private final GcSnapshot mPrevious;
|
||||
private final int mFlags;
|
||||
|
||||
private Graphics2D mGraphics2D = null;
|
||||
/** 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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public GcSnapshot(GcSnapshot previous, int flags) {
|
||||
assert previous != null;
|
||||
mPrevious = previous;
|
||||
mFlags = flags;
|
||||
mGraphics2D = (Graphics2D) previous.mGraphics2D.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the root snapshot.
|
||||
* {@link #setGraphics2D(Graphics2D)} will have to be called on it when possible.
|
||||
*/
|
||||
public GcSnapshot() {
|
||||
mPrevious = null;
|
||||
mFlags = 0;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (mGraphics2D != null) {
|
||||
mGraphics2D.dispose();
|
||||
}
|
||||
|
||||
if (mPrevious != null) {
|
||||
mPrevious.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the top {@link GcSnapshot}, and returns the next one.
|
||||
*/
|
||||
public GcSnapshot restore() {
|
||||
return doRestore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the {@link GcSnapshot} to <var>saveCount</var>.
|
||||
* @param saveCount the saveCount or -1 to only restore 1.
|
||||
*
|
||||
* @return the new head of the Gc snapshot stack.
|
||||
*/
|
||||
public GcSnapshot restoreTo(int saveCount) {
|
||||
return doRestoreTo(size(), saveCount);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
if (mPrevious != null) {
|
||||
return mPrevious.size() + 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Graphics2D object for this snapshot if it was created through {@link #GcSnapshot()}.
|
||||
* If any transform or clip information was set before, they are put into the Graphics object.
|
||||
* @param graphics2D the graphics object to set.
|
||||
*/
|
||||
public void setGraphics2D(Graphics2D graphics2D) {
|
||||
mGraphics2D = graphics2D;
|
||||
if (mTransform != null) {
|
||||
mGraphics2D.setTransform(mTransform);
|
||||
mTransform = null;
|
||||
}
|
||||
|
||||
if (mClip != null) {
|
||||
mGraphics2D.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);
|
||||
} else {
|
||||
if (mTransform == null) {
|
||||
mTransform = new AffineTransform();
|
||||
}
|
||||
mTransform.translate(dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
public void rotate(double radians) {
|
||||
if (mGraphics2D != null) {
|
||||
mGraphics2D.rotate(radians);
|
||||
} else {
|
||||
if (mTransform == null) {
|
||||
mTransform = new AffineTransform();
|
||||
}
|
||||
mTransform.rotate(radians);
|
||||
}
|
||||
}
|
||||
|
||||
public void scale(float sx, float sy) {
|
||||
if (mGraphics2D != null) {
|
||||
mGraphics2D.scale(sx, sy);
|
||||
} else {
|
||||
if (mTransform == null) {
|
||||
mTransform = new AffineTransform();
|
||||
}
|
||||
mTransform.scale(sx, sy);
|
||||
}
|
||||
}
|
||||
|
||||
public AffineTransform getTransform() {
|
||||
if (mGraphics2D != null) {
|
||||
return mGraphics2D.getTransform();
|
||||
} else {
|
||||
if (mTransform == null) {
|
||||
mTransform = new AffineTransform();
|
||||
}
|
||||
return mTransform;
|
||||
}
|
||||
}
|
||||
|
||||
public void setTransform(AffineTransform transform) {
|
||||
if (mGraphics2D != null) {
|
||||
mGraphics2D.setTransform(transform);
|
||||
} else {
|
||||
if (mTransform == null) {
|
||||
mTransform = new AffineTransform();
|
||||
}
|
||||
mTransform.setTransform(transform);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean clipRect(float left, float top, float right, float bottom, int regionOp) {
|
||||
if (mGraphics2D != null) {
|
||||
if (regionOp == Region.Op.DIFFERENCE.nativeInt) {
|
||||
Area newClip = new Area(mGraphics2D.getClip());
|
||||
newClip.subtract(new Area(
|
||||
new Rectangle2D.Float(left, top, right - left, bottom - top)));
|
||||
mGraphics2D.setClip(newClip);
|
||||
|
||||
} else if (regionOp == Region.Op.INTERSECT.nativeInt) {
|
||||
mGraphics2D.clipRect((int) left, (int) top,
|
||||
(int) (right - left), (int) (bottom - top));
|
||||
|
||||
} else if (regionOp == Region.Op.UNION.nativeInt) {
|
||||
Area newClip = new Area(mGraphics2D.getClip());
|
||||
newClip.add(new Area(
|
||||
new Rectangle2D.Float(left, top, right - left, bottom - top)));
|
||||
mGraphics2D.setClip(newClip);
|
||||
|
||||
} else if (regionOp == Region.Op.XOR.nativeInt) {
|
||||
Area newClip = new Area(mGraphics2D.getClip());
|
||||
newClip.exclusiveOr(new Area(
|
||||
new Rectangle2D.Float(left, top, right - left, bottom - top)));
|
||||
mGraphics2D.setClip(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);
|
||||
} else if (regionOp == Region.Op.REPLACE.nativeInt) {
|
||||
mGraphics2D.setClip((int) left, (int) top,
|
||||
(int) (right - left), (int) (bottom - top));
|
||||
}
|
||||
|
||||
return mGraphics2D.getClip().getBounds().isEmpty() == false;
|
||||
} else {
|
||||
if (mClip == null) {
|
||||
mClip = new Area();
|
||||
}
|
||||
|
||||
if (regionOp == Region.Op.DIFFERENCE.nativeInt) {
|
||||
//FIXME
|
||||
} else if (regionOp == Region.Op.DIFFERENCE.nativeInt) {
|
||||
} else if (regionOp == Region.Op.INTERSECT.nativeInt) {
|
||||
} else if (regionOp == Region.Op.UNION.nativeInt) {
|
||||
} else if (regionOp == Region.Op.XOR.nativeInt) {
|
||||
} else if (regionOp == Region.Op.REVERSE_DIFFERENCE.nativeInt) {
|
||||
} else if (regionOp == Region.Op.REPLACE.nativeInt) {
|
||||
}
|
||||
|
||||
return mClip.getBounds().isEmpty() == false;
|
||||
}
|
||||
}
|
||||
|
||||
public Shape getClip() {
|
||||
if (mGraphics2D != null) {
|
||||
return mGraphics2D.getClip();
|
||||
} else {
|
||||
if (mClip == null) {
|
||||
mClip = new Area();
|
||||
}
|
||||
return mClip;
|
||||
}
|
||||
}
|
||||
|
||||
private GcSnapshot doRestoreTo(int size, int saveCount) {
|
||||
if (size <= saveCount) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// restore the current one first.
|
||||
GcSnapshot previous = doRestore();
|
||||
|
||||
if (size == saveCount + 1) { // this was the only one that needed restore.
|
||||
return previous;
|
||||
} else {
|
||||
return previous.doRestoreTo(size - 1, saveCount);
|
||||
}
|
||||
}
|
||||
|
||||
private GcSnapshot doRestore() {
|
||||
// if this snapshot does not save everything, then set the previous snapshot
|
||||
// to this snapshot content
|
||||
if (mPrevious != null) {
|
||||
// didn't save the matrix? set the current matrix on the previous snapshot
|
||||
if ((mFlags & Canvas.MATRIX_SAVE_FLAG) == 0) {
|
||||
mPrevious.mGraphics2D.setTransform(getTransform());
|
||||
}
|
||||
|
||||
// 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 (mGraphics2D != null) {
|
||||
mGraphics2D.dispose();
|
||||
}
|
||||
|
||||
return mPrevious;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user