/** * Copyright 2011 The ForPlay Authors * * 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 forplay.android; import java.util.LinkedList; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.RectF; import forplay.core.Asserts; import forplay.core.Gradient; import forplay.core.Image; import forplay.core.Path; import forplay.core.Pattern; class AndroidCanvas implements forplay.core.Canvas { private static Matrix m = new Matrix(); private static Rect rect = new Rect(); private static RectF rectf = new RectF(); private final Canvas canvas; private LinkedList<AndroidSurfaceState> paintStack = new LinkedList<AndroidSurfaceState>(); AndroidCanvas(Canvas canvas) { this.canvas = canvas; paintStack.addFirst(new AndroidSurfaceState()); } @Override public void clear() { canvas.drawColor(0, PorterDuff.Mode.SRC); } @Override public void clip(Path clipPath) { Asserts.checkArgument(clipPath instanceof AndroidPath); canvas.clipPath(((AndroidPath) clipPath).path); } @Override public void drawImage(Image img, float x, float y) { Asserts.checkArgument(img instanceof AndroidImage); AndroidImage aimg = (AndroidImage) img; if (aimg.getBitmap() != null) { canvas.drawBitmap(aimg.getBitmap(), x, y, currentState().prepareImage()); } } @Override public void drawImage(Image img, float x, float y, float w, float h) { Asserts.checkArgument(img instanceof AndroidImage); AndroidImage aimg = (AndroidImage) img; if (aimg.getBitmap() != null) { rectf.set(x, y, x + w, y + h); canvas.drawBitmap(aimg.getBitmap(), null, rectf, currentState().prepareImage()); } } @Override public void drawImage(Image img, float dx, float dy, float dw, float dh, float sx, float sy, float sw, float sh) { Asserts.checkArgument(img instanceof AndroidImage); AndroidImage aimg = (AndroidImage) img; if (aimg.getBitmap() != null) { rect.set((int) sx, (int) sy, (int) (sx + sw), (int) (sy + sh)); rectf.set(dx, dy, dx + dw, dy + dh); canvas.drawBitmap(aimg.getBitmap(), rect, rectf, currentState().prepareImage()); } } @Override public void drawImageCentered(Image image, float dx, float dy) { drawImage(image, dx - image.width() / 2, dy - image.height() / 2); } @Override public void drawLine(float x0, float y0, float x1, float y1) { canvas.drawLine(x0, y0, x1, y1, currentState().prepareStroke()); } @Override public void drawPoint(float x, float y) { canvas.drawPoint(x, y, currentState().prepareStroke()); } @Override public void drawText(String text, float x, float y) { canvas.drawText(text, x, y, currentState().prepareFill()); } @Override public void fillCircle(float x, float y, float radius) { canvas.drawCircle(x, y, radius, currentState().prepareFill()); } @Override public void fillPath(Path path) { Asserts.checkArgument(path instanceof AndroidPath); canvas.drawPath(((AndroidPath) path).path, currentState().prepareFill()); } @Override public void fillRect(float x, float y, float width, float height) { float left = x; float top = y; float right = left + width; float bottom = top + height; canvas.drawRect(left, top, right, bottom, currentState().prepareFill()); } @Override public int height() { return canvas.getHeight(); } @Override public void restore() { canvas.restore(); paintStack.removeFirst(); Asserts.check(paintStack.size() > 0, "Unbalanced save/restore"); } @Override public void rotate(float angle) { canvas.rotate(rad2deg(angle)); } @Override public void save() { canvas.save(); paintStack.addFirst(new AndroidSurfaceState(currentState())); } @Override public void scale(float x, float y) { canvas.scale(x, y); } public void setAlpha(float alpha) { currentState().setAlpha(alpha); } public float alpha() { return currentState().alpha; } @Override public void setCompositeOperation(Composite composite) { currentState().setCompositeOperation(composite); } @Override public void setFillColor(int color) { currentState().setFillColor(color); } @Override public void setFillGradient(Gradient gradient) { Asserts.checkArgument(gradient instanceof AndroidGradient); currentState().setFillGradient((AndroidGradient) gradient); } @Override public void setFillPattern(Pattern pattern) { Asserts.checkArgument(pattern instanceof AndroidPattern); currentState().setFillPattern((AndroidPattern) pattern); } @Override public void setLineCap(LineCap cap) { currentState().setLineCap(cap); } @Override public void setLineJoin(LineJoin join) { currentState().setLineJoin(join); } @Override public void setMiterLimit(float miter) { currentState().setMiterLimit(miter); } @Override public void setStrokeColor(int color) { currentState().setStrokeColor(color); } @Override public void setStrokeWidth(float strokeWidth) { currentState().setStrokeWidth(strokeWidth); } @Override public void setTransform(float m11, float m12, float m21, float m22, float dx, float dy) { Matrix m = new Matrix(); // TODO(jgw): Is this the right order? m.setValues(new float[] {m11, m12, 0, m21, 0, m22, dx, dy, 1}); canvas.setMatrix(m); } @Override public void strokeCircle(float x, float y, float radius) { canvas.drawCircle(x, y, radius, currentState().prepareStroke()); } @Override public void strokePath(Path path) { Asserts.checkArgument(path instanceof AndroidPath); canvas.drawPath(((AndroidPath) path).path, currentState().prepareStroke()); } @Override public void strokeRect(float x, float y, float width, float height) { float left = x; float top = y; float right = left + width; float bottom = top + height; canvas.drawRect(left, top, right, bottom, currentState().prepareStroke()); } @Override public void transform(float m11, float m12, float m21, float m22, float dx, float dy) { m.setValues(new float[] {m11, m21, dx, m12, m22, dy, 0, 0, 1}); canvas.concat(m); } @Override public void translate(float x, float y) { canvas.translate(x, y); } @Override public int width() { return canvas.getWidth(); } private AndroidSurfaceState currentState() { return paintStack.peek(); } private float rad2deg(double deg) { return (float) (deg * 360 / (2 * Math.PI)); } }