replicant-frameworks_native/awt/com/android/internal/awt/AndroidGraphics2D.java
2009-03-03 19:31:44 -08:00

1355 lines
40 KiB
Java

/*
* Copyright 2007, 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.internal.awt;
import com.android.internal.awt.AndroidGraphicsConfiguration;
import com.android.internal.graphics.NativeUtils;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.PathIterator;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.DataBuffer;
import java.awt.image.DirectColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.RenderableImage;
import java.text.AttributedCharacterIterator;
import java.util.Map;
import org.apache.harmony.awt.gl.ImageSurface;
import org.apache.harmony.awt.gl.MultiRectArea;
import org.apache.harmony.awt.gl.Surface;
import org.apache.harmony.awt.gl.font.AndroidGlyphVector;
import org.apache.harmony.awt.gl.font.FontMetricsImpl;
import org.apache.harmony.awt.gl.image.OffscreenImage;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Typeface;
import android.graphics.PixelXorXfermode;
import android.view.Display;
import android.view.WindowManager;
import android.content.Context;
public class AndroidGraphics2D extends Graphics2D {
private int displayWidth, displayHeight;
protected Surface dstSurf = null;
protected MultiRectArea clip = null;
protected Composite composite = AlphaComposite.SrcOver;
protected AffineTransform transform = new AffineTransform();
private static AndroidGraphics2D mAg;
private static Canvas mC;
// Android Paint
public static Paint mP;
private static java.awt.Font mFnt;
// Cached Matrix
public static Matrix mM;
private static FontMetrics mFm;
private static RenderingHints mRh;
private static Color mBc;
private Area mCurrClip;
public final static double RAD_360 = Math.PI / 180 * 360;
// Image drawing
private AndroidJavaBlitter blitter;
private DirectColorModel cm;
private SinglePixelPackedSampleModel sm;
private WritableRaster wr;
public static AndroidGraphics2D getInstance() {
if (mAg == null) {
throw new RuntimeException("AndroidGraphics2D not instantiated!");
}
return mAg;
}
public static AndroidGraphics2D getInstance(Context ctx, Canvas c, Paint p) {
if (c == null || ctx == null) {
throw new RuntimeException(
"Illegal argument, Canvas cannot be null!");
}
mAg = new AndroidGraphics2D(ctx, c, p);
return mAg;
}
private AndroidGraphics2D(Context ctx, Canvas c, Paint p) {
super();
mC = c;
mP = p;
mM = new Matrix();
mM.reset();
mM = mC.getMatrix();
Rect r = mC.getClipBounds();
int cl[] = {-1, r.top, r.left, -2, r.top, r.right, -2, r.bottom, r.right, -2, r.bottom, r.left};
mCurrClip = new Area(createShape(cl));
if(ctx != null) {
WindowManager wm = (WindowManager)ctx.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
displayWidth = d.getWidth();
displayHeight = d.getHeight();
}
blitter = new AndroidJavaBlitter(c);
cm = new DirectColorModel(32, 0xff0000, 0xff00, 0xff, 0xff000000);
sm = new SinglePixelPackedSampleModel(
DataBuffer.TYPE_INT, displayWidth, displayHeight, cm.getMasks());
wr = Raster.createWritableRaster(sm, null);
dstSurf = new ImageSurface(cm, wr);
}
@Override
public void addRenderingHints(Map<?, ?> hints) {
if (mRh == null) {
mRh = (RenderingHints) hints;
}
mRh.add((RenderingHints) hints);
}
public float[] getMatrix() {
float[] f = new float[9];
mC.getMatrix().getValues(f);
return f;
}
/**
*
* @return a Matrix in Android format
*/
public float[] getInverseMatrix() {
AffineTransform af = new AffineTransform(createAWTMatrix(getMatrix()));
try {
af = af.createInverse();
} catch (NoninvertibleTransformException e) {
}
return createMatrix(af);
}
private Path getPath(Shape s) {
Path path = new Path();
PathIterator pi = s.getPathIterator(null);
while (pi.isDone() == false) {
getCurrentSegment(pi, path);
pi.next();
}
return path;
}
private void getCurrentSegment(PathIterator pi, Path path) {
float[] coordinates = new float[6];
int type = pi.currentSegment(coordinates);
switch (type) {
case PathIterator.SEG_MOVETO:
path.moveTo(coordinates[0], coordinates[1]);
break;
case PathIterator.SEG_LINETO:
path.lineTo(coordinates[0], coordinates[1]);
break;
case PathIterator.SEG_QUADTO:
path.quadTo(coordinates[0], coordinates[1], coordinates[2],
coordinates[3]);
break;
case PathIterator.SEG_CUBICTO:
path.cubicTo(coordinates[0], coordinates[1], coordinates[2],
coordinates[3], coordinates[4], coordinates[5]);
break;
case PathIterator.SEG_CLOSE:
path.close();
break;
default:
break;
}
}
private Shape createShape(int[] arr) {
Shape s = new GeneralPath();
for(int i = 0; i < arr.length; i++) {
int type = arr[i];
switch (type) {
case -1:
//MOVETO
((GeneralPath)s).moveTo(arr[++i], arr[++i]);
break;
case -2:
//LINETO
((GeneralPath)s).lineTo(arr[++i], arr[++i]);
break;
case -3:
//QUADTO
((GeneralPath)s).quadTo(arr[++i], arr[++i], arr[++i],
arr[++i]);
break;
case -4:
//CUBICTO
((GeneralPath)s).curveTo(arr[++i], arr[++i], arr[++i],
arr[++i], arr[++i], arr[++i]);
break;
case -5:
//CLOSE
return s;
default:
break;
}
}
return s;
}
/*
public int[] getPixels() {
return mC.getPixels();
}*/
public static float getRadian(float degree) {
return (float) ((Math.PI / 180) * degree);
}
private Shape getShape() {
return null;
}
public static float getDegree(float radian) {
return (float) ((180 / Math.PI) * radian);
}
/*
* Degree in radian
*/
public static float getEllipsisX(float degree, float princAxis) {
return (float) Math.cos(degree) * princAxis;
}
public static float getEllipsisY(float degree, float conAxis) {
return (float) Math.sin(degree) * conAxis;
}
@Override
public void clip(Shape s) {
mC.clipPath(getPath(s));
}
public void setCanvas(Canvas c) {
mC = c;
}
@Override
public void draw(Shape s) {
if (mP == null) {
mP = new Paint();
}
Paint.Style tmp = mP.getStyle();
mP.setStyle(Paint.Style.STROKE);
mC.drawPath(getPath(s), mP);
mP.setStyle(tmp);
}
/*
private ArrayList getSegments(Shape s) {
ArrayList arr = new ArrayList();
PathIterator pi = s.getPathIterator(null);
while (pi.isDone() == false) {
getCurrentSegment(pi, arr);
pi.next();
}
return arr;
}
private void getCurrentSegment(PathIterator pi, ArrayList arr) {
float[] coordinates = new float[6];
int type = pi.currentSegment(coordinates);
switch (type) {
case PathIterator.SEG_MOVETO:
arr.add(new Integer(-1));
break;
case PathIterator.SEG_LINETO:
arr.add(new Integer(-2));
break;
case PathIterator.SEG_QUADTO:
arr.add(new Integer(-3));
break;
case PathIterator.SEG_CUBICTO:
arr.add(new Integer(-4));
break;
case PathIterator.SEG_CLOSE:
arr.add(new Integer(-5));
break;
default:
break;
}
}
*/
/*
* Convenience method, not standard AWT
*/
public void draw(Path s) {
if (mP == null) {
mP = new Paint();
}
Paint.Style tmp = mP.getStyle();
mP.setStyle(Paint.Style.STROKE);
s.transform(mM);
mC.drawPath(s, mP);
mP.setStyle(tmp);
}
@Override
public void drawGlyphVector(GlyphVector g, float x, float y) {
// TODO draw at x, y
// draw(g.getOutline());
/*
Matrix matrix = new Matrix();
matrix.setTranslate(x, y);
Path pth = getPath(g.getOutline());
pth.transform(matrix);
draw(pth);
*/
Path path = new Path();
char[] c = ((AndroidGlyphVector)g).getGlyphs();
mP.getTextPath(c, 0, c.length, x, y, path);
mC.drawPath(path, mP);
}
@Override
public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
throw new RuntimeException("Not implemented!");
}
@Override
public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
throw new RuntimeException("Not implemented!");
}
@Override
public void drawString(AttributedCharacterIterator iterator, float x,
float y) {
throw new RuntimeException("AttributedCharacterIterator not supported!");
}
@Override
public void drawString(AttributedCharacterIterator iterator, int x, int y) {
throw new RuntimeException("AttributedCharacterIterator not supported!");
}
@Override
public void drawString(String s, float x, float y) {
if (mP == null) {
mP = new Paint();
}
Paint.Style tmp = mP.getStyle();
mP.setStyle(Paint.Style.FILL);
Path pth = new Path();
mP.getTextPath(s, 0, s.length(), x, y, pth);
mC.drawPath(pth, mP);
mP.setStyle(tmp);
}
@Override
public void drawString(String str, int x, int y) {
if (mP == null) {
mP = new Paint();
}
Paint.Style tmp = mP.getStyle();
mP.setStrokeWidth(0);
mC.drawText(str.toCharArray(), 0, str.toCharArray().length, x, y,
mP);
mP.setStyle(tmp);
}
@Override
public void fill(Shape s) {
if (mP == null) {
mP = new Paint();
}
Paint.Style tmp = mP.getStyle();
mP.setStyle(Paint.Style.FILL);
mC.drawPath(getPath(s), mP);
mP.setStyle(tmp);
}
@Override
public Color getBackground() {
return mBc;
}
@Override
public Composite getComposite() {
throw new RuntimeException("Composite not implemented!");
}
@Override
public GraphicsConfiguration getDeviceConfiguration() {
return new AndroidGraphicsConfiguration();
}
@Override
public FontRenderContext getFontRenderContext() {
return new FontRenderContext(getTransform(), mP.isAntiAlias(), true);
}
@Override
public java.awt.Paint getPaint() {
throw new RuntimeException("AWT Paint not implemented in Android!");
}
public static Canvas getAndroidCanvas() {
return mC;
}
public static Paint getAndroidPaint() {
return mP;
}
@Override
public RenderingHints getRenderingHints() {
return mRh;
}
@Override
public Stroke getStroke() {
if (mP != null) {
return new BasicStroke(mP.getStrokeWidth(), mP.getStrokeCap()
.ordinal(), mP.getStrokeJoin().ordinal());
}
return null;
}
@Override
public AffineTransform getTransform() {
return new AffineTransform(createAWTMatrix(getMatrix()));
}
@Override
public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
// ???AWT TODO check if on stroke
return s.intersects(rect.getX(), rect.getY(), rect.getWidth(), rect
.getHeight());
}
@Override
public void rotate(double theta) {
mM.preRotate((float) AndroidGraphics2D
.getDegree((float) (RAD_360 - theta)));
mC.concat(mM);
}
@Override
public void rotate(double theta, double x, double y) {
mM.preRotate((float) AndroidGraphics2D.getDegree((float) theta),
(float) x, (float) y);
mC.concat(mM);
}
@Override
public void scale(double sx, double sy) {
mM.setScale((float) sx, (float) sy);
mC.concat(mM);
}
@Override
public void setBackground(Color color) {
mBc = color;
mC.clipRect(new Rect(0, 0, mC.getWidth(), mC.getHeight()));
// TODO don't limit to current clip
mC.drawARGB(color.getAlpha(), color.getRed(), color.getGreen(), color
.getBlue());
}
@Override
public void setComposite(Composite comp) {
throw new RuntimeException("Composite not implemented!");
}
public void setSpaint(Paint paint) {
mP = paint;
}
@Override
public void setPaint(java.awt.Paint paint) {
setColor((Color)paint);
}
@Override
public Object getRenderingHint(RenderingHints.Key key) {
if (mRh == null) {
return null;
}
return mRh.get(key);
}
@Override
public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) {
if (mRh == null) {
mRh = new RenderingHints(hintKey, hintValue);
} else {
mRh.put(hintKey, hintValue);
}
applyHints();
}
@Override
public void setRenderingHints(Map<?, ?> hints) {
mRh = (RenderingHints) hints;
applyHints();
}
private void applyHints() {
Object o;
// TODO do something like this:
/*
* Set s = mRh.keySet(); Iterator it = s.iterator(); while(it.hasNext()) {
* o = it.next(); }
*/
// /////////////////////////////////////////////////////////////////////
// not supported in skia
/*
* o = mRh.get(RenderingHints.KEY_ALPHA_INTERPOLATION); if
* (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) { } else
* if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)) { }
* else if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED)) { }
*
* o = mRh.get(RenderingHints.KEY_COLOR_RENDERING); if
* (o.equals(RenderingHints.VALUE_COLOR_RENDER_DEFAULT)) { } else if
* (o.equals(RenderingHints.VALUE_COLOR_RENDER_QUALITY)) { } else if
* (o.equals(RenderingHints.VALUE_COLOR_RENDER_SPEED)) { }
*
* o = mRh.get(RenderingHints.KEY_DITHERING); if
* (o.equals(RenderingHints.VALUE_DITHER_DEFAULT)) { } else if
* (o.equals(RenderingHints.VALUE_DITHER_DISABLE)) { } else if
* (o.equals(RenderingHints.VALUE_DITHER_ENABLE)) { }
*
* o = mRh.get(RenderingHints.KEY_FRACTIONALMETRICS); if
* (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT)) { } else
* if (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_OFF)) { } else if
* (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_ON)) { }
*
* o = mRh.get(RenderingHints.KEY_INTERPOLATION); if
* (o.equals(RenderingHints.VALUE_INTERPOLATION_BICUBIC)) { } else if
* (o.equals(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) { } else if
* (o .equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) { }
*
* o = mRh.get(RenderingHints.KEY_RENDERING); if
* (o.equals(RenderingHints.VALUE_RENDER_DEFAULT)) { } else if
* (o.equals(RenderingHints.VALUE_RENDER_QUALITY)) { } else if
* (o.equals(RenderingHints.VALUE_RENDER_SPEED)) { }
*
* o = mRh.get(RenderingHints.KEY_STROKE_CONTROL); if
* (o.equals(RenderingHints.VALUE_STROKE_DEFAULT)) { } else if
* (o.equals(RenderingHints.VALUE_STROKE_NORMALIZE)) { } else if
* (o.equals(RenderingHints.VALUE_STROKE_PURE)) { }
*/
o = mRh.get(RenderingHints.KEY_ANTIALIASING);
if (o != null) {
if (o.equals(RenderingHints.VALUE_ANTIALIAS_DEFAULT)) {
mP.setAntiAlias(false);
} else if (o.equals(RenderingHints.VALUE_ANTIALIAS_OFF)) {
mP.setAntiAlias(false);
} else if (o.equals(RenderingHints.VALUE_ANTIALIAS_ON)) {
mP.setAntiAlias(true);
}
}
o = mRh.get(RenderingHints.KEY_TEXT_ANTIALIASING);
if (o != null) {
if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT)) {
mP.setAntiAlias(false);
} else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)) {
mP.setAntiAlias(false);
} else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_ON)) {
mP.setAntiAlias(true);
}
}
}
@Override
public void setStroke(Stroke s) {
if (mP == null) {
mP = new Paint();
}
BasicStroke bs = (BasicStroke) s;
mP.setStyle(Paint.Style.STROKE);
mP.setStrokeWidth(bs.getLineWidth());
int cap = bs.getEndCap();
if (cap == 0) {
mP.setStrokeCap(Paint.Cap.BUTT);
} else if (cap == 1) {
mP.setStrokeCap(Paint.Cap.ROUND);
} else if (cap == 2) {
mP.setStrokeCap(Paint.Cap.SQUARE);
}
int join = bs.getLineJoin();
if (join == 0) {
mP.setStrokeJoin(Paint.Join.MITER);
} else if (join == 1) {
mP.setStrokeJoin(Paint.Join.ROUND);
} else if (join == 2) {
mP.setStrokeJoin(Paint.Join.BEVEL);
}
}
public static float[] createMatrix(AffineTransform Tx) {
double[] at = new double[9];
Tx.getMatrix(at);
float[] f = new float[at.length];
f[0] = (float) at[0];
f[1] = (float) at[2];
f[2] = (float) at[4];
f[3] = (float) at[1];
f[4] = (float) at[3];
f[5] = (float) at[5];
f[6] = 0;
f[7] = 0;
f[8] = 1;
return f;
}
private float[] createAWTMatrix(float[] matrix) {
float[] at = new float[9];
at[0] = matrix[0];
at[1] = matrix[3];
at[2] = matrix[1];
at[3] = matrix[4];
at[4] = matrix[2];
at[5] = matrix[5];
at[6] = 0;
at[7] = 0;
at[8] = 1;
return at;
}
public static Matrix createMatrixObj(AffineTransform Tx) {
Matrix m = new Matrix();
m.reset();
m.setValues(createMatrix(Tx));
return m;
}
@Override
public void setTransform(AffineTransform Tx) {
mM.reset();
/*
* if(Tx.isIdentity()) { mM = new Matrix(); }
*/
mM.setValues(createMatrix(Tx));
Matrix m = new Matrix();
m.setValues(getInverseMatrix());
mC.concat(m);
mC.concat(mM);
}
@Override
public void shear(double shx, double shy) {
mM.setSkew((float) shx, (float) shy);
mC.concat(mM);
}
@Override
public void transform(AffineTransform Tx) {
Matrix m = new Matrix();
m.setValues(createMatrix(Tx));
mC.concat(m);
}
@Override
public void translate(double tx, double ty) {
mM.setTranslate((float) tx, (float) ty);
mC.concat(mM);
}
@Override
public void translate(int x, int y) {
mM.setTranslate((float) x, (float) y);
mC.concat(mM);
}
@Override
public void clearRect(int x, int y, int width, int height) {
mC.clipRect(x, y, x + width, y + height);
if (mBc != null) {
mC.drawARGB(mBc.getAlpha(), mBc.getBlue(), mBc.getGreen(), mBc
.getRed());
} else {
mC.drawARGB(0xff, 0xff, 0xff, 0xff);
}
}
@Override
public void clipRect(int x, int y, int width, int height) {
int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y};
Shape shp = createShape(cl);
mCurrClip.intersect(new Area(shp));
mC.clipRect(new Rect(x, y, x + width, y + height), Region.Op.INTERSECT);
}
@Override
public void copyArea(int sx, int sy, int width, int height, int dx, int dy) {
copyArea(mC, sx, sy, width + dx, height + dy, dx, dy);
}
@Override
public Graphics create() {
return this;
}
@Override
public void dispose() {
mC = null;
mP = null;
}
@Override
public void drawArc(int x, int y, int width, int height, int sa, int ea) {
if (mP == null) {
mP = new Paint();
}
mP.setStrokeWidth(0);
mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (ea + sa),
ea, true, mP);
}
// ???AWT: only used for debuging, delete in final version
public void drawBitmap(Bitmap bm, float x, float y, Paint p) {
mC.drawBitmap(bm, x, y, null);
}
@Override
public boolean drawImage(Image image, int x, int y, Color bgcolor,
ImageObserver imageObserver) {
if(image == null) {
return true;
}
boolean done = false;
boolean somebits = false;
Surface srcSurf = null;
if(image instanceof OffscreenImage){
OffscreenImage oi = (OffscreenImage) image;
if((oi.getState() & ImageObserver.ERROR) != 0) {
return false;
}
done = oi.prepareImage(imageObserver);
somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
srcSurf = oi.getImageSurface();
}else{
done = true;
srcSurf = Surface.getImageSurface(image);
}
if(done || somebits) {
int w = srcSurf.getWidth();
int h = srcSurf.getHeight();
blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, (AffineTransform) transform.clone(),
composite, bgcolor, clip);
}
return done;
}
@Override
public boolean drawImage(Image image, int x, int y, ImageObserver imageObserver) {
return drawImage(image, x, y, null, imageObserver);
}
@Override
public boolean drawImage(Image image, int x, int y, int width, int height,
Color bgcolor, ImageObserver imageObserver) {
if(image == null) {
return true;
}
if(width == 0 || height == 0) {
return true;
}
boolean done = false;
boolean somebits = false;
Surface srcSurf = null;
if(image instanceof OffscreenImage){
OffscreenImage oi = (OffscreenImage) image;
if((oi.getState() & ImageObserver.ERROR) != 0) {
return false;
}
done = oi.prepareImage(imageObserver);
somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
srcSurf = oi.getImageSurface();
}else{
done = true;
srcSurf = Surface.getImageSurface(image);
}
if(done || somebits) {
int w = srcSurf.getWidth();
int h = srcSurf.getHeight();
if(w == width && h == height){
blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
(AffineTransform) transform.clone(),
composite, bgcolor, clip);
}else{
AffineTransform xform = new AffineTransform();
xform.setToScale((float)width / w, (float)height / h);
blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
(AffineTransform) transform.clone(),
xform, composite, bgcolor, clip);
}
}
return done;
}
@Override
public boolean drawImage(Image image, int x, int y, int width, int height,
ImageObserver imageObserver) {
return drawImage(image, x, y, width, height, null, imageObserver);
}
@Override
public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2, Color bgcolor,
ImageObserver imageObserver) {
if(image == null) {
return true;
}
if(dx1 == dx2 || dy1 == dy2 || sx1 == sx2 || sy1 == sy2) {
return true;
}
boolean done = false;
boolean somebits = false;
Surface srcSurf = null;
if(image instanceof OffscreenImage){
OffscreenImage oi = (OffscreenImage) image;
if((oi.getState() & ImageObserver.ERROR) != 0) {
return false;
}
done = oi.prepareImage(imageObserver);
somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
srcSurf = oi.getImageSurface();
}else{
done = true;
srcSurf = Surface.getImageSurface(image);
}
if(done || somebits) {
int dstX = dx1;
int dstY = dy1;
int srcX = sx1;
int srcY = sy1;
int dstW = dx2 - dx1;
int dstH = dy2 - dy1;
int srcW = sx2 - sx1;
int srcH = sy2 - sy1;
if(srcW == dstW && srcH == dstH){
blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
(AffineTransform) transform.clone(),
composite, bgcolor, clip);
}else{
AffineTransform xform = new AffineTransform();
xform.setToScale((float)dstW / srcW, (float)dstH / srcH);
blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
(AffineTransform) transform.clone(),
xform, composite, bgcolor, clip);
}
}
return done;
}
@Override
public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2, ImageObserver imageObserver) {
return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null,
imageObserver);
}
@Override
public void drawImage(BufferedImage bufImage, BufferedImageOp op,
int x, int y) {
if(bufImage == null) {
return;
}
if(op == null) {
drawImage(bufImage, x, y, null);
} else if(op instanceof AffineTransformOp){
AffineTransformOp atop = (AffineTransformOp) op;
AffineTransform xform = atop.getTransform();
Surface srcSurf = Surface.getImageSurface(bufImage);
int w = srcSurf.getWidth();
int h = srcSurf.getHeight();
blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
(AffineTransform) transform.clone(), xform,
composite, null, clip);
} else {
bufImage = op.filter(bufImage, null);
Surface srcSurf = Surface.getImageSurface(bufImage);
int w = srcSurf.getWidth();
int h = srcSurf.getHeight();
blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
(AffineTransform) transform.clone(),
composite, null, clip);
}
}
@Override
public boolean drawImage(Image image, AffineTransform trans,
ImageObserver imageObserver) {
if(image == null) {
return true;
}
if(trans == null || trans.isIdentity()) {
return drawImage(image, 0, 0, imageObserver);
}
boolean done = false;
boolean somebits = false;
Surface srcSurf = null;
if(image instanceof OffscreenImage){
OffscreenImage oi = (OffscreenImage) image;
if((oi.getState() & ImageObserver.ERROR) != 0) {
return false;
}
done = oi.prepareImage(imageObserver);
somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
srcSurf = oi.getImageSurface();
}else{
done = true;
srcSurf = Surface.getImageSurface(image);
}
if(done || somebits) {
int w = srcSurf.getWidth();
int h = srcSurf.getHeight();
AffineTransform xform = (AffineTransform) transform.clone();
xform.concatenate(trans);
blitter.blit(0, 0, srcSurf, 0, 0, dstSurf, w, h, xform, composite,
null, clip);
}
return done;
}
@Override
public void drawLine(int x1, int y1, int x2, int y2) {
if (mP == null) {
mP = new Paint();
}
mC.drawLine(x1, y1, x2, y2, mP);
}
@Override
public void drawOval(int x, int y, int width, int height) {
if (mP == null) {
mP = new Paint();
}
mP.setStyle(Paint.Style.STROKE);
mC.drawOval(new RectF(x, y, x + width, y + height), mP);
}
@Override
public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) {
if (mP == null) {
mP = new Paint();
}
mC.drawLine(xpoints[npoints - 1], ypoints[npoints - 1], xpoints[0],
ypoints[0], mP);
for (int i = 0; i < npoints - 1; i++) {
mC.drawLine(xpoints[i], ypoints[i], xpoints[i + 1],
ypoints[i + 1], mP);
}
}
@Override
public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) {
for (int i = 0; i < npoints - 1; i++) {
drawLine(xpoints[i], ypoints[i], xpoints[i + 1], ypoints[i + 1]);
}
}
@Override
public void drawRoundRect(int x, int y, int width, int height,
int arcWidth, int arcHeight) {
if (mP == null) {
mP = new Paint();
}
mC.drawRoundRect(new RectF(x, y, width, height), arcWidth,
arcHeight, mP);
}
@Override
public void fillArc(int x, int y, int width, int height, int sa, int ea) {
if (mP == null) {
mP = new Paint();
}
Paint.Style tmp = mP.getStyle();
mP.setStyle(Paint.Style.FILL_AND_STROKE);
mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (sa + ea),
ea, true, mP);
mP.setStyle(tmp);
}
@Override
public void fillOval(int x, int y, int width, int height) {
if (mP == null) {
mP = new Paint();
}
Paint.Style tmp = mP.getStyle();
mP.setStyle(Paint.Style.FILL);
mC.drawOval(new RectF(x, y, x + width, y + height), mP);
mP.setStyle(tmp);
}
@Override
public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) {
if (mP == null) {
mP = new Paint();
}
Paint.Style tmp = mP.getStyle();
mC.save(Canvas.CLIP_SAVE_FLAG);
mP.setStyle(Paint.Style.FILL);
GeneralPath filledPolygon = new GeneralPath(
GeneralPath.WIND_EVEN_ODD, npoints);
filledPolygon.moveTo(xpoints[0], ypoints[0]);
for (int index = 1; index < xpoints.length; index++) {
filledPolygon.lineTo(xpoints[index], ypoints[index]);
}
filledPolygon.closePath();
Path path = getPath(filledPolygon);
mC.clipPath(path);
mC.drawPath(path, mP);
mP.setStyle(tmp);
mC.restore();
}
@Override
public void fillRect(int x, int y, int width, int height) {
if (mP == null) {
mP = new Paint();
}
Paint.Style tmp = mP.getStyle();
mP.setStyle(Paint.Style.FILL);
mC.drawRect(new Rect(x, y, x + width, y + height), mP);
mP.setStyle(tmp);
}
@Override
public void drawRect(int x, int y, int width, int height) {
int[] xpoints = { x, x, x + width, x + width };
int[] ypoints = { y, y + height, y + height, y };
drawPolygon(xpoints, ypoints, 4);
}
@Override
public void fillRoundRect(int x, int y, int width, int height,
int arcWidth, int arcHeight) {
if (mP == null) {
mP = new Paint();
}
mP.setStyle(Paint.Style.FILL);
mC.drawRoundRect(new RectF(x, y, x + width, y + height), arcWidth,
arcHeight, mP);
}
@Override
public Shape getClip() {
return mCurrClip;
}
@Override
public Rectangle getClipBounds() {
Rect r = mC.getClipBounds();
return new Rectangle(r.left, r.top, r.width(), r.height());
}
@Override
public Color getColor() {
if (mP != null) {
return new Color(mP.getColor());
}
return null;
}
@Override
public Font getFont() {
return mFnt;
}
@Override
public FontMetrics getFontMetrics(Font font) {
mFm = new FontMetricsImpl(font);
return mFm;
}
@Override
public void setClip(int x, int y, int width, int height) {
int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y};
mCurrClip = new Area(createShape(cl));
mC.clipRect(x, y, x + width, y + height, Region.Op.REPLACE);
}
@Override
public void setClip(Shape clip) {
mCurrClip = new Area(clip);
mC.clipPath(getPath(clip), Region.Op.REPLACE);
}
@Override
public void setColor(Color c) {
if (mP == null) {
mP = new Paint();
}
mP.setColor(c.getRGB());
}
/**
* Font mapping:
*
* Family:
*
* Android AWT
* -------------------------------------
* serif Serif / TimesRoman
* sans-serif SansSerif / Helvetica
* monospace Monospaced / Courier
*
* Style:
*
* Android AWT
* -------------------------------------
* normal Plain
* bold bold
* italic italic
*
*/
@Override
public void setFont(Font font) {
if (font == null) {
return;
}
if (mP == null) {
mP = new Paint();
}
mFnt = font;
Typeface tf = null;
int sty = font.getStyle();
String nam = font.getName();
String aF = "";
if (nam != null) {
if (nam.equalsIgnoreCase("Serif")
|| nam.equalsIgnoreCase("TimesRoman")) {
aF = "serif";
} else if (nam.equalsIgnoreCase("SansSerif")
|| nam.equalsIgnoreCase("Helvetica")) {
aF = "sans-serif";
} else if (nam.equalsIgnoreCase("Monospaced")
|| nam.equalsIgnoreCase("Courier")) {
aF = "monospace";
}
}
switch (sty) {
case Font.PLAIN:
tf = Typeface.create(aF, Typeface.NORMAL);
break;
case Font.BOLD:
tf = Typeface.create(aF, Typeface.BOLD);
break;
case Font.ITALIC:
tf = Typeface.create(aF, Typeface.ITALIC);
break;
case Font.BOLD | Font.ITALIC:
tf = Typeface.create(aF, Typeface.BOLD_ITALIC);
break;
default:
tf = Typeface.DEFAULT;
}
mP.setTextSize(font.getSize());
mP.setTypeface(tf);
}
@Override
public void drawBytes(byte[] data, int offset, int length, int x, int y) {
drawString(new String(data, offset, length), x, y);
}
@Override
public void drawPolygon(Polygon p) {
drawPolygon(p.xpoints, p.ypoints, p.npoints);
}
@Override
public void fillPolygon(Polygon p) {
fillPolygon(p.xpoints, p.ypoints, p.npoints);
}
@Override
public Rectangle getClipBounds(Rectangle r) {
Shape clip = getClip();
if (clip != null) {
Rectangle b = clip.getBounds();
r.x = b.x;
r.y = b.y;
r.width = b.width;
r.height = b.height;
}
return r;
}
@Override
public boolean hitClip(int x, int y, int width, int height) {
return getClipBounds().intersects(new Rectangle(x, y, width, height));
}
@Override
public void drawChars(char[] data, int offset, int length, int x, int y) {
mC.drawText(data, offset, length, x, y, mP);
}
@Override
public void setPaintMode() {
if (mP == null) {
mP = new Paint();
}
mP.setXfermode(null);
}
@Override
public void setXORMode(Color color) {
if (mP == null) {
mP = new Paint();
}
mP.setXfermode(new PixelXorXfermode(color.getRGB()));
}
@Override
public void fill3DRect(int x, int y, int width, int height, boolean raised) {
Color color = getColor();
Color colorUp, colorDown;
if (raised) {
colorUp = color.brighter();
colorDown = color.darker();
setColor(color);
} else {
colorUp = color.darker();
colorDown = color.brighter();
setColor(colorUp);
}
width--;
height--;
fillRect(x+1, y+1, width-1, height-1);
setColor(colorUp);
fillRect(x, y, width, 1);
fillRect(x, y+1, 1, height);
setColor(colorDown);
fillRect(x+width, y, 1, height);
fillRect(x+1, y+height, width, 1);
}
@Override
public void draw3DRect(int x, int y, int width, int height, boolean raised) {
Color color = getColor();
Color colorUp, colorDown;
if (raised) {
colorUp = color.brighter();
colorDown = color.darker();
} else {
colorUp = color.darker();
colorDown = color.brighter();
}
setColor(colorUp);
fillRect(x, y, width, 1);
fillRect(x, y+1, 1, height);
setColor(colorDown);
fillRect(x+width, y, 1, height);
fillRect(x+1, y+height, width, 1);
}
public void copyArea(Canvas canvas, int sx, int sy, int width, int height, int dx, int dy) {
sx += getTransform().getTranslateX();
sy += getTransform().getTranslateY();
NativeUtils.nativeScrollRect(canvas,
new Rect(sx, sy, sx + width, sy + height),
dx, dy);
}
}