package com.himamis.retex.renderer.android.graphics; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.PointF; import android.graphics.RectF; import android.view.View; import com.himamis.retex.renderer.android.font.FontA; import com.himamis.retex.renderer.android.font.FontRenderContextA; import com.himamis.retex.renderer.android.geom.Line2DA; import com.himamis.retex.renderer.android.geom.Rectangle2DA; import com.himamis.retex.renderer.android.geom.RoundRectangle2DA; import com.himamis.retex.renderer.share.ColorUtil; import com.himamis.retex.renderer.share.platform.font.Font; import com.himamis.retex.renderer.share.platform.font.FontRenderContext; import com.himamis.retex.renderer.share.platform.geom.Line2D; import com.himamis.retex.renderer.share.platform.geom.Rectangle2D; import com.himamis.retex.renderer.share.platform.geom.RoundRectangle2D; import com.himamis.retex.renderer.share.platform.graphics.Color; import com.himamis.retex.renderer.share.platform.graphics.Graphics2DInterface; import com.himamis.retex.renderer.share.platform.graphics.Image; import com.himamis.retex.renderer.share.platform.graphics.RenderingHints; import com.himamis.retex.renderer.share.platform.graphics.Stroke; import com.himamis.retex.renderer.share.platform.graphics.Transform; @SuppressLint("NewApi") public class Graphics2DA implements Graphics2DInterface { private Canvas mCanvas; private View mView; private Paint mDrawPaint; private Paint mFontPaint; // The canvas is never scaled directly because with hardwareAcceleration:on // the drawing be pixelated. Instead the scale values are saved in a stack private ScaleStack mScaleStack; private FontA mFont; private ColorA mColor; private Style mOldDrawPaintStyle; public Graphics2DA() { mDrawPaint = new Paint(); mDrawPaint.setStyle(Style.STROKE); mDrawPaint.setSubpixelText(true); mDrawPaint.setAntiAlias(true); mDrawPaint.setLinearText(true); mFontPaint = new Paint(); mFontPaint.set(mDrawPaint); mScaleStack = new ScaleStack(); mFont = new FontA("Serif", Font.PLAIN, 10); mColor = (ColorA) ColorUtil.BLACK; } public Graphics2DA(Canvas canvas) { this(); setCanvas(canvas); } public Graphics2DA(Canvas canvas, View view) { this(canvas); setView(view); } public void setCanvas(Canvas canvas) { mCanvas = canvas; } public void setView(View view) { mView = view; } private void setBasicStroke(BasicStrokeA basicStroke) { mDrawPaint.setStrokeWidth((float)basicStroke.getWidth()); mDrawPaint.setStrokeMiter((float)basicStroke.getMiterLimit()); mDrawPaint.setStrokeCap(basicStroke.getNativeCap()); mDrawPaint.setStrokeJoin(basicStroke.getNativeJoin()); } public Stroke getStroke() { return new BasicStrokeA(mDrawPaint.getStrokeWidth(), mDrawPaint.getStrokeMiter(), mDrawPaint.getStrokeCap(), mDrawPaint.getStrokeJoin()); } public void setStroke(Stroke stroke) { BasicStrokeA basicStroke = (BasicStrokeA) stroke; setBasicStroke(basicStroke); } public Color getColor() { return mColor; } public void setColor(Color color) { mColor = (ColorA) color; mDrawPaint.setColor(mColor.getColor()); } @SuppressWarnings("deprecation") public Transform getTransform() { Matrix matrix = null; if (mView != null && android.os.Build.VERSION.SDK_INT >= 11) { matrix = mView.getMatrix(); } if (matrix == null) { matrix = mCanvas.getMatrix(); } TransformA transform = new TransformA(matrix); transform.scale(mScaleStack.getScaleX(), mScaleStack.getScaleY()); return transform; } public Font getFont() { return mFont; } public void setFont(Font font) { mFont = (FontA) font; mDrawPaint.setTypeface(mFont.getTypeface()); mDrawPaint.setTextSize(mScaleStack.scaleFontSize(mFont.getSize())); } public void fillRect(int x, int y, int width, int height) { beforeFill(); RectF rectF = new RectF(x, y, x + width, y + height); RectF scaled = mScaleStack.scaleRectF(rectF); RectF amended = AmendRect.amendRectF(scaled); mCanvas.drawRect(amended, mDrawPaint); afterFill(); } public void fill(Rectangle2D rectangle) { beforeFill(); draw(rectangle); afterFill(); } public void draw(Rectangle2D rectangle) { RectF rect = ((Rectangle2DA) rectangle).getRectF(); RectF copy = new RectF(rect); RectF scaled = mScaleStack.scaleRectF(copy); RectF amended = AmendRect.amendRectF(scaled); mCanvas.drawRect(amended, mDrawPaint); } public void draw(RoundRectangle2D rectangle) { RectF rect = ((RoundRectangle2DA) rectangle).getRectF(); RectF copy = new RectF(rect); mCanvas.drawRoundRect(mScaleStack.scaleRectF(copy), mScaleStack.scaleX((float) rectangle.getArcW()), mScaleStack.scaleY((float) rectangle.getArcH()), mDrawPaint); } public void draw(Line2D line) { Line2DA impl = (Line2DA) line; PointF start = impl.getStartPoint(); PointF end = impl.getEndPoint(); mCanvas.drawLine(mScaleStack.scaleX(start.x), mScaleStack.scaleY(start.y), mScaleStack.scaleX(end.x), mScaleStack.scaleY(end.y), mDrawPaint); } public void drawChars(char[] data, int offset, int length, int x, int y) { beforeFill(); mDrawPaint.setTextSize(mScaleStack.scaleFontSize(mFont.getSize())); mCanvas.drawText(data, offset, length, mScaleStack.scaleX(x), mScaleStack.scaleY(y), mDrawPaint); afterFill(); } public void drawString(String text, int x, int y, Paint paint) { paint.setTextSize(mScaleStack.scaleFontSize(paint.getTextSize())); paint.setColor(mDrawPaint.getColor()); mCanvas.drawText(text, mScaleStack.scaleX(x), mScaleStack.scaleY(y), paint); } public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { RectF oval = new RectF(x, y, (x + width), (y + height)); mCanvas.drawArc(mScaleStack.scaleRectF(oval), startAngle, arcAngle, false, mDrawPaint); } public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { beforeFill(); drawArc(x, y, width, height, startAngle, arcAngle); afterFill(); } public void translate(double x, double y) { mCanvas.translate(mScaleStack.scaleX((float) x), mScaleStack.scaleY((float) y)); } public void scale(double x, double y) { mScaleStack.appendScale((float) x, (float) y); } public void rotate(double theta, double x, double y) { translate(x, y); rotate(theta); translate(-x, -y); } public void rotate(double theta) { // theta is in radians // change to degrees float degrees = (float) Math.toDegrees(theta); mCanvas.rotate(degrees); } public void drawImage(Image image, int x, int y) { ImageA imageA = (ImageA) image; Bitmap bitmap = imageA.getBitmap(); mCanvas.drawBitmap(mScaleStack.scaleBitmap(bitmap), mScaleStack.scaleX(x), mScaleStack.scaleY(y), mDrawPaint); } public void drawImage(Image image, Transform transform) { ImageA imageA = (ImageA) image; Bitmap bitmap = imageA.getBitmap(); mCanvas.drawBitmap(mScaleStack.scaleBitmap(bitmap), (Matrix) transform, mDrawPaint); } public FontRenderContext getFontRenderContext() { mFontPaint.set(mDrawPaint); return new FontRenderContextA(mFontPaint); } public void setRenderingHint(int key, int value) { if (key == RenderingHints.KEY_ANTIALIASING && value == RenderingHints.VALUE_ANTIALIAS_ON) { mDrawPaint.setAntiAlias(true); } else { // No other rendering hint is supported } } public int getRenderingHint(int key) { // Not supported return -1; } public void dispose() { // NO-OP } private void saveDrawPaintStyle() { mOldDrawPaintStyle = mDrawPaint.getStyle(); } private void restoreDrawPaintStyle() { mDrawPaint.setStyle(mOldDrawPaintStyle); } private void setDrawPaintFillStyle() { mDrawPaint.setStyle(Style.FILL); } private void beforeFill() { saveDrawPaintStyle(); setDrawPaintFillStyle(); } private void afterFill() { restoreDrawPaintStyle(); } public void saveTransformation() { mCanvas.save(Canvas.MATRIX_SAVE_FLAG); mScaleStack.pushScaleValues(); } public void restoreTransformation() { mCanvas.restore(); mScaleStack.popScaleValues(); } }