1355 lines
40 KiB
Java
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);
|
|
}
|
|
}
|