/** * Copyright 2010 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.html; import com.google.gwt.canvas.dom.client.Context2d; import com.google.gwt.dom.client.CanvasElement; import com.google.gwt.dom.client.Document; import forplay.core.Asserts; import forplay.core.Gradient; import forplay.core.Image; import forplay.core.Path; import forplay.core.Pattern; import forplay.core.Canvas; class HtmlCanvas implements Canvas { private final CanvasElement canvas; private final Context2d ctx; private final int width, height; private boolean dirty = true; HtmlCanvas(int width, int height) { this(Document.get().createElement("canvas").<CanvasElement>cast(), width, height); } HtmlCanvas(CanvasElement canvas, int width, int height) { this.canvas = canvas; this.width = width; this.height = height; canvas.setWidth(width); canvas.setHeight(height); ctx = canvas.getContext2d(); } @Override public void clear() { ctx.clearRect(0, 0, width, height); dirty = true; } @Override public void clip(Path path) { Asserts.checkArgument(path instanceof HtmlPath); ((HtmlPath) path).replay(ctx); ctx.clip(); } @Override public void drawImage(Image img, float x, float y) { Asserts.checkArgument(img instanceof HtmlImage); ctx.drawImage(((HtmlImage) img).img, x, y); dirty = true; } @Override public void drawImage(Image img, float x, float y, float w, float h) { Asserts.checkArgument(img instanceof HtmlImage); ctx.drawImage(((HtmlImage) img).img, x, y, w, h); dirty = true; } @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 HtmlImage); ctx.drawImage(((HtmlImage) img).img, sx, sy, sw, sh, dx, dy, dw, dh); dirty = true; } @Override public void drawImageCentered(Image img, float x, float y) { drawImage(img, x - img.width()/2, y - img.height()/2); dirty = true; } @Override public void drawLine(float x0, float y0, float x1, float y1) { ctx.beginPath(); ctx.moveTo(x0, y0); ctx.lineTo(x1, y1); ctx.stroke(); dirty = true; } @Override public void drawPoint(float x, float y) { ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(x, y); ctx.stroke(); dirty = true; } @Override public void drawText(String text, float x, float y) { ctx.fillText(text, x, y); dirty = true; } @Override public void fillCircle(float x, float y, float radius) { ctx.beginPath(); ctx.arc(x, y, radius, 0, 2 * Math.PI); ctx.fill(); dirty = true; } @Override public void fillPath(Path path) { Asserts.checkArgument(path instanceof HtmlPath); ((HtmlPath) path).replay(ctx); ctx.fill(); dirty = true; } @Override public void fillRect(float x, float y, float w, float h) { ctx.fillRect(x, y, w, h); dirty = true; } @Override public final int height() { return height; } @Override public void restore() { ctx.restore(); } @Override public void rotate(float radians) { ctx.rotate(radians); } @Override public void save() { ctx.save(); } @Override public void scale(float x, float y) { ctx.scale(x, y); } @Override public void setCompositeOperation(Canvas.Composite composite) { ctx.setGlobalCompositeOperation(convertComposite(composite)); } @Override public void setFillColor(int color) { ctx.setFillStyle(HtmlGraphics.cssColor(color)); } @Override public void setFillGradient(Gradient gradient) { Asserts.checkArgument(gradient instanceof HtmlGradient); ctx.setFillStyle(((HtmlGradient) gradient).gradient); } @Override public void setFillPattern(Pattern pattern) { Asserts.checkArgument(pattern instanceof HtmlPattern); ctx.setFillStyle(((HtmlPattern) pattern).pattern); } @Override public void setLineCap(LineCap cap) { ctx.setLineCap(convertLineCap(cap)); } @Override public void setLineJoin(LineJoin join) { ctx.setLineJoin(convertLineJoin(join)); } @Override public void setMiterLimit(float miter) { ctx.setMiterLimit(miter); } @Override public void setStrokeColor(int color) { ctx.setStrokeStyle(HtmlGraphics.cssColor(color)); } @Override public void setStrokeWidth(float w) { ctx.setLineWidth(w); } @Override public void setTransform(float m11, float m12, float m21, float m22, float dx, float dy) { ctx.setTransform(m11, m12, m21, m22, dx, dy); } @Override public void strokeCircle(float x, float y, float radius) { ctx.beginPath(); ctx.arc(x, y, radius, 0, 2 * Math.PI); ctx.stroke(); dirty = true; } @Override public void strokePath(Path path) { Asserts.checkArgument(path instanceof HtmlPath); ((HtmlPath) path).replay(ctx); ctx.stroke(); dirty = true; } @Override public void strokeRect(float x, float y, float w, float h) { ctx.strokeRect(x, y, w, h); dirty = true; } @Override public void transform(float m11, float m12, float m21, float m22, float dx, float dy) { ctx.transform(m11, m12, m21, m22, dx, dy); } @Override public void translate(float x, float y) { ctx.translate(x, y); } @Override public final int width() { return width; } CanvasElement canvas() { return canvas; } void clearDirty() { dirty = false; } boolean dirty() { return dirty; } private String convertComposite(Canvas.Composite composite) { switch (composite) { case SRC: return "copy"; case DST_ATOP: return "destination-atop"; case SRC_OVER: return "source-over"; case DST_OVER: return "destination-over"; case SRC_IN: return "source-in"; case DST_IN: return "destionation-in"; case SRC_OUT: return "source-out"; case DST_OUT: return "destination-out"; case SRC_ATOP: return "source-atop"; case XOR: return "xor"; } return "copy"; } private Context2d.LineCap convertLineCap(LineCap cap) { switch (cap) { case BUTT: return Context2d.LineCap.BUTT; case ROUND: return Context2d.LineCap.ROUND; case SQUARE: return Context2d.LineCap.SQUARE; } return Context2d.LineCap.SQUARE; } private Context2d.LineJoin convertLineJoin(LineJoin join) { switch (join) { case BEVEL: return Context2d.LineJoin.BEVEL; case MITER: return Context2d.LineJoin.MITER; case ROUND: return Context2d.LineJoin.ROUND; } return Context2d.LineJoin.ROUND; } }