blob: c9dddf70bffc18b20d0b318282c54874bef0b679 [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* 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.google.gwt.canvas.dom.client;
import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.Context2d.Composite;
import com.google.gwt.canvas.dom.client.Context2d.LineCap;
import com.google.gwt.canvas.dom.client.Context2d.LineJoin;
import com.google.gwt.canvas.dom.client.Context2d.TextAlign;
import com.google.gwt.canvas.dom.client.Context2d.TextBaseline;
import com.google.gwt.junit.DoNotRunWith;
import com.google.gwt.junit.Platform;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.ui.RootPanel;
import java.util.Locale;
/**
* Tests {@link Context2d}.
*
* Because HtmlUnit does not support HTML5, you will need to run these tests manually in order to
* have them run. To do that, go to "run configurations" or "debug configurations", select the test
* you would like to run, and put this line in the VM args under the arguments tab:
* -Dgwt.args="-runStyle Manual:1"
*/
@DoNotRunWith(Platform.HtmlUnitUnknown)
public class Context2dTest extends GWTTestCase {
protected Canvas canvas1;
protected Canvas canvas2;
native boolean isGecko190OrBefore() /*-{
return @com.google.gwt.dom.client.DOMImplMozilla::isGecko190OrBefore()();
}-*/;
native boolean isWebkit525OrBefore() /*-{
return @com.google.gwt.dom.client.DOMImplWebkit::isWebkit525OrBefore()();
}-*/;
@Override
public String getModuleName() {
return "com.google.gwt.canvas.Canvas";
}
@Override
protected void gwtSetUp() throws Exception {
canvas1 = Canvas.createIfSupported();
canvas2 = Canvas.createIfSupported();
if (canvas1 == null) {
return; // don't continue if not supported
}
RootPanel.get().add(canvas1);
RootPanel.get().add(canvas2);
}
@Override
protected void gwtTearDown() throws Exception {
RootPanel.get().remove(canvas1);
RootPanel.get().remove(canvas2);
}
public void testArc() {
if (canvas1 == null) {
return; // don't continue if not supported
}
canvas1.setHeight("40px");
canvas1.setWidth("60px");
canvas1.setCoordinateSpaceHeight(80);
canvas1.setCoordinateSpaceWidth(120);
// get a 2d context
Context2d context = canvas1.getContext2d();
// make sure there are no issues drawing an arc
try {
context.beginPath();
context.arc(50, 50, 40, 0, Math.PI);
context.closePath();
context.stroke();
} catch (Exception e) {
fail("Should not throw an exception drawing an arc: " + e.getMessage());
}
}
public void testFillRect() {
if (canvas1 == null) {
return; // don't continue if not supported
}
// Safari 3.0 does not support getImageData(), so the following tests are disabled for
// Safari 3.0 and before.
if (isWebkit525OrBefore()) {
return;
}
canvas1.setHeight("40px");
canvas1.setWidth("60px");
canvas1.setCoordinateSpaceHeight(80);
canvas1.setCoordinateSpaceWidth(120);
assertEquals(40, canvas1.getOffsetHeight());
assertEquals(60, canvas1.getOffsetWidth());
assertEquals(80, canvas1.getCoordinateSpaceHeight());
assertEquals(120, canvas1.getCoordinateSpaceWidth());
// get a 2d context
Context2d context = canvas1.getContext2d();
// draw green rectangle filling 1st half of canvas
context.setFillStyle(CssColor.make("#00fF00"));
context.fillRect(0, 0, 60, 80);
// draw red rectangle filling 2nd half of canvas
context.setFillStyle("#fF0000");
context.fillRect(60, 0, 60, 80);
// test that the first pixel is green and the last pixel is red
ImageData imageData = context.getImageData(0, 0, 120, 80);
CanvasPixelArray pixelArray = imageData.getData();
assertEquals(000, pixelArray.get(0));
assertEquals(255, pixelArray.get(1));
assertEquals(000, pixelArray.get(2));
assertEquals(255, pixelArray.get(3));
assertEquals(255, pixelArray.get((40 * 20 - 1) * 4 + 0));
assertEquals(000, pixelArray.get((40 * 20 - 1) * 4 + 1));
assertEquals(000, pixelArray.get((40 * 20 - 1) * 4 + 2));
assertEquals(255, pixelArray.get((40 * 20 - 1) * 4 + 3));
// draw a blue square in the top left
context.setFillStyle("#0000fF");
context.fillRect(0, 0, 20, 20);
imageData = context.getImageData(0, 0, 20, 20);
pixelArray = imageData.getData();
// test that the first pixel is blue
assertEquals(000, pixelArray.get(0));
assertEquals(000, pixelArray.get(1));
assertEquals(255, pixelArray.get(2));
assertEquals(255, pixelArray.get(3));
}
public void testFillStyle() {
if (canvas1 == null) {
return; // don't continue if not supported
}
// get the 2d contexts
Context2d context1 = canvas1.getContext2d();
Context2d context2 = canvas2.getContext2d();
// test that a color can be set and is correct
context1.setFillStyle(CssColor.make("#ffff00"));
FillStrokeStyle fillStyleCol = context1.getFillStyle();
assertTrue("fillStyleCol is a color", fillStyleCol.getType() == FillStrokeStyle.TYPE_CSSCOLOR);
assertFalse("fillStyleCol is a color", fillStyleCol.getType() == FillStrokeStyle.TYPE_GRADIENT);
assertFalse("fillStyleCol is a color", fillStyleCol.getType() == FillStrokeStyle.TYPE_PATTERN);
// test that a gradient can be set and is correct
CanvasGradient gradient = context1.createLinearGradient(0, 0, 10, 20);
gradient.addColorStop(0.5f, "#ffaaff");
context1.setFillStyle(gradient);
FillStrokeStyle fillStyleGrad = context1.getFillStyle();
assertFalse("fillStyleGrad is a gradient", fillStyleGrad.getType() == FillStrokeStyle.TYPE_CSSCOLOR);
assertTrue("fillStyleGrad is a gradient", fillStyleGrad.getType() == FillStrokeStyle.TYPE_GRADIENT);
assertFalse("fillStyleGrad is a gradient", fillStyleGrad.getType() == FillStrokeStyle.TYPE_PATTERN);
// test that a pattern can be set and is correct
CanvasPattern pattern = context1.createPattern(canvas1.getCanvasElement(),
Context2d.Repetition.REPEAT);
context1.setFillStyle(pattern);
FillStrokeStyle fillStylePat = context1.getFillStyle();
assertFalse("fillStylePat is a pattern", fillStylePat.getType() == FillStrokeStyle.TYPE_CSSCOLOR);
assertFalse("fillStylePat is a pattern", fillStylePat.getType() == FillStrokeStyle.TYPE_GRADIENT);
assertTrue("fillStylePat is a pattern", fillStylePat.getType() == FillStrokeStyle.TYPE_PATTERN);
// test that a StrokeStyle can be passed around w/o knowing what it is
FillStrokeStyle fillStyle = context1.getFillStyle();
context2.setFillStyle(fillStyle);
FillStrokeStyle fillStyle2 = context2.getFillStyle();
assertFalse("fillStyle2 is a pattern", fillStyle2.getType() == FillStrokeStyle.TYPE_CSSCOLOR);
assertFalse("fillStyle2 is a pattern", fillStyle2.getType() == FillStrokeStyle.TYPE_GRADIENT);
assertTrue("fillStyle2 is a pattern", fillStyle2.getType() == FillStrokeStyle.TYPE_PATTERN);
}
public void testFont() {
if (canvas1 == null) {
return; // don't continue if not supported
}
Context2d context = canvas1.getContext2d();
context.setFont("40px \"Times New Roman\"");
assertEquals("40px \"Times New Roman\"", context.getFont());
}
public void testGlobalAlpha() {
if (canvas1 == null) {
return; // don't continue if not supported
}
Context2d context = canvas1.getContext2d();
context.setGlobalAlpha(0.5);
assertEquals(0.5, context.getGlobalAlpha());
}
public void testGlobalComposite() {
if (canvas1 == null) {
return; // don't continue if not supported
}
Context2d context = canvas1.getContext2d();
context.setGlobalCompositeOperation(Composite.SOURCE_OVER);
assertEquals(Composite.SOURCE_OVER.getValue(), context.getGlobalCompositeOperation());
context.setGlobalCompositeOperation(Composite.DESTINATION_OVER);
assertEquals(Composite.DESTINATION_OVER.getValue(), context.getGlobalCompositeOperation());
}
public void testGradient() {
if (canvas1 == null) {
return; // don't continue if not supported
}
// Safari 3.0 does not support getImageData(), so the following tests are disabled for
// Safari 3.0 and before.
if (isWebkit525OrBefore()) {
return;
}
canvas1.setHeight("40px");
canvas1.setWidth("60px");
canvas1.setCoordinateSpaceHeight(40);
canvas1.setCoordinateSpaceWidth(60);
Context2d context = canvas1.getContext2d();
// fill the canvas with black
context.setFillStyle("#000000");
context.fillRect(0, 0, 60, 40);
// create a linear gradient from the top-left to the bottom-right.
CanvasGradient linearGradient = context.createLinearGradient(0, 0, 60, 40);
linearGradient.addColorStop(0, "#ff0000");
linearGradient.addColorStop(1, "#00ffff");
context.setFillStyle(linearGradient);
context.fillRect(0, 0, 60, 40);
// test that the first pixel is ff0000, the last is 000fff, and the middle is something else
// isn't exact due to rounding, give 5px approx wiggle-room
int approx = 5;
ImageData imageData = context.getImageData(0, 0, 60, 40);
CanvasPixelArray pixelArray = imageData.getData();
assertTrue(255 - pixelArray.get(0) < approx);
assertTrue(pixelArray.get(1) - 000 < approx);
assertTrue(pixelArray.get(2) - 000 < approx);
assertTrue(255 - pixelArray.get(3) < approx);
assertFalse(000 == pixelArray.get((60 * 40 / 2) * 4 + 0));
assertFalse(255 == pixelArray.get((60 * 40 / 2) * 4 + 0));
assertTrue(pixelArray.get((60 * 40 - 1) * 4 + 0) - 000 < approx);
assertTrue(255 - pixelArray.get((60 * 40 - 1) * 4 + 1) < approx);
assertTrue(255 - pixelArray.get((60 * 40 - 1) * 4 + 2) < approx);
assertTrue(255 - pixelArray.get((60 * 40 - 1) * 4 + 3) < approx);
}
public void testImageData() {
if (canvas1 == null) {
return; // don't continue if not supported
}
// Firefox 3.0 does not support createImageData(), so the following tests are disabled
// for FF 3.0 and before.
if (isGecko190OrBefore()) {
return;
}
// Safari 3.0 does not support getImageData(), so the following tests are disabled for
// Safari 3.0 and before.
if (isWebkit525OrBefore()) {
return;
}
canvas1.setHeight("40px");
canvas1.setWidth("60px");
canvas1.setCoordinateSpaceHeight(40);
canvas1.setCoordinateSpaceWidth(60);
Context2d context = canvas1.getContext2d();
// fill the canvas with ffff00
context.setFillStyle("#ffff00");
context.fillRect(0, 0, 60, 40);
// create a 1 x 1 image
ImageData onePx = context.createImageData(1, 1); // will fail on FF3.0 (not such method)
assertEquals(1, onePx.getHeight());
assertEquals(1, onePx.getWidth());
// set the image to a single blue pixel
CanvasPixelArray onePxArray = onePx.getData();
onePxArray.set(0, 000);
onePxArray.set(1, 000);
onePxArray.set(2, 255);
onePxArray.set(3, 255);
// put the pixel at location 10, 10 on the canvas
context.putImageData(onePx, 10, 10);
ImageData verifyPx = context.getImageData(10, 10, 1, 1);
assertEquals(1, verifyPx.getWidth());
assertEquals(1, verifyPx.getHeight());
CanvasPixelArray verifyPxArray = verifyPx.getData();
assertEquals(onePxArray.get(0), verifyPxArray.get(0));
assertEquals(onePxArray.get(1), verifyPxArray.get(1));
assertEquals(onePxArray.get(2), verifyPxArray.get(2));
assertEquals(onePxArray.get(3), verifyPxArray.get(3));
// test that edge cases don't blow up: values outside the range 0...255
ImageData clampPixels = context.createImageData(3, 3); // will fail on FF3.0 (not such method)
CanvasPixelArray clampArraySet = clampPixels.getData();
try {
clampArraySet.set(2, -2);
clampArraySet.set(3, 270);
context.putImageData(clampPixels, 4, 4);
} catch (Exception e) {
fail("Should not throw exception when setting values outside the range of 0...255");
}
clampPixels = context.getImageData(4, 4, 3, 3);
CanvasPixelArray clampArrayGet = clampPixels.getData();
// test that edge cases don't blow up: fall off the CanvasPixelArray end
int aPixel = clampArrayGet.get(9999);
assertEquals("CanvasPixelArray should return 0 for values off its end", 0, aPixel);
int bPixel = clampArrayGet.get(-9999);
assertEquals("CanvasPixelArray should return 0 for values off its end", 0, bPixel);
}
public void testIsPointInPath() {
if (canvas1 == null) {
return; // don't continue if not supported
}
canvas1.setHeight("40px");
canvas1.setWidth("60px");
canvas1.setCoordinateSpaceHeight(40);
canvas1.setCoordinateSpaceWidth(60);
Context2d context = canvas1.getContext2d();
context.beginPath();
context.moveTo(10, 10);
context.lineTo(20, 20);
context.lineTo(20, 10);
context.closePath();
assertTrue("Point should be in path", context.isPointInPath(18, 12));
assertFalse("Point should not be in path", context.isPointInPath(1, 1));
}
public void testLines() {
if (canvas1 == null) {
return; // don't continue if not supported
}
canvas1.setHeight("40px");
canvas1.setWidth("60px");
canvas1.setCoordinateSpaceHeight(40);
canvas1.setCoordinateSpaceWidth(60);
Context2d context = canvas1.getContext2d();
context.setFillStyle("#ff00ff");
context.setLineCap(LineCap.BUTT);
context.setLineJoin(LineJoin.BEVEL);
context.setLineWidth(2);
context.beginPath();
context.moveTo(10, 10);
context.lineTo(20, 20);
context.lineTo(20, 10);
context.closePath();
assertEquals(LineCap.BUTT.getValue(), context.getLineCap());
assertEquals(LineJoin.BEVEL.getValue(), context.getLineJoin());
assertEquals(2.0, context.getLineWidth());
}
public void testMiter() {
if (canvas1 == null) {
return; // don't continue if not supported
}
Context2d context = canvas1.getContext2d();
context.setMiterLimit(3);
assertEquals(3.0, context.getMiterLimit());
}
public void testPixelManipulation() {
if (canvas1 == null) {
return; // don't continue if not supported
}
// Safari 3.0 does not support getImageData(), so the following tests are disabled for
// Safari 3.0 and before.
if (isWebkit525OrBefore()) {
return;
}
canvas1.setHeight("40px");
canvas1.setWidth("60px");
canvas1.setCoordinateSpaceHeight(40);
canvas1.setCoordinateSpaceWidth(60);
Context2d context = canvas1.getContext2d();
// fill the canvas with ff0000
context.setFillStyle("#ff0000");
context.fillRect(0, 0, 60, 40);
// fill the 1st and 2nd quadrants with green
context.setFillStyle("#00ff00");
context.fillRect(0, 0, 60, 20);
ImageData imageData = context.getImageData(0, 0, 60, 40);
assertEquals("Pixels in first quadrant should be green", 0, imageData.getRedAt(45, 10));
assertEquals("Pixels in first quadrant should be green", 255, imageData.getGreenAt(45, 10));
assertEquals("Pixels in third quadrant should be red", 255, imageData.getRedAt(15, 30));
assertEquals("Pixels in third quadrant should be red", 0, imageData.getGreenAt(15, 30));
}
public void testShadows() {
if (canvas1 == null) {
return; // don't continue if not supported
}
// Firefox 3.0 returns the incorrect shadowBlur value so the following tests are disabled
// for FF 3.0 and before.
if (isGecko190OrBefore()) {
return;
}
canvas1.setHeight("40px");
canvas1.setWidth("60px");
canvas1.setCoordinateSpaceHeight(40);
canvas1.setCoordinateSpaceWidth(60);
Context2d context = canvas1.getContext2d();
context.setShadowBlur(3);
context.setShadowColor("#ff00ff");
context.setShadowOffsetX(3);
context.setShadowOffsetY(4);
context.lineTo(60, 40);
assertEquals(3.0, context.getShadowBlur());
assertEquals("#ff00ff", context.getShadowColor().toLowerCase(Locale.ROOT));
assertEquals(3.0, context.getShadowOffsetX());
assertEquals(4.0, context.getShadowOffsetY());
}
public void testStrokeStyle() {
if (canvas1 == null) {
return; // don't continue if not supported
}
// get the 2d contexts
Context2d context1 = canvas1.getContext2d();
Context2d context2 = canvas2.getContext2d();
// test that a color can be set and is correct
context1.setStrokeStyle(CssColor.make("#ffff00"));
FillStrokeStyle strokeStyleCol = context1.getStrokeStyle();
assertTrue("strokeStyleCol is a color", strokeStyleCol.getType() == FillStrokeStyle.TYPE_CSSCOLOR);
assertFalse("strokeStyleCol is a color", strokeStyleCol.getType() == FillStrokeStyle.TYPE_GRADIENT);
assertFalse("strokeStyleCol is a color", strokeStyleCol.getType() == FillStrokeStyle.TYPE_PATTERN);
// test that a gradient can be set and is correct
CanvasGradient gradient = context1.createLinearGradient(0, 0, 10, 20);
gradient.addColorStop(0.5, "#ff000f");
context1.setStrokeStyle(gradient);
FillStrokeStyle strokeStyleGrad = context1.getStrokeStyle();
assertFalse("strokeStyleGrad is a gradient", strokeStyleGrad.getType() == FillStrokeStyle.TYPE_CSSCOLOR);
assertTrue("strokeStyleGrad is a gradient", strokeStyleGrad.getType() == FillStrokeStyle.TYPE_GRADIENT);
assertFalse("strokeStyleGrad is a gradient", strokeStyleGrad.getType() == FillStrokeStyle.TYPE_PATTERN);
// test that a pattern can be set and is correct
CanvasPattern pattern = context1.createPattern(canvas1.getCanvasElement(),
Context2d.Repetition.REPEAT);
context1.setStrokeStyle(pattern);
FillStrokeStyle strokeStylePat = context1.getStrokeStyle();
assertFalse("strokeStylePat is a pattern", strokeStylePat.getType() == FillStrokeStyle.TYPE_CSSCOLOR);
assertFalse("strokeStylePat is a pattern", strokeStylePat.getType() == FillStrokeStyle.TYPE_GRADIENT);
assertTrue("strokeStylePat is a pattern", strokeStylePat.getType() == FillStrokeStyle.TYPE_PATTERN);
// test that a StrokeStyle can be passed around w/o knowing what it is
FillStrokeStyle strokeStyle = context1.getStrokeStyle();
context2.setStrokeStyle(strokeStyle);
FillStrokeStyle strokeStyle2 = context2.getStrokeStyle();
assertFalse("strokeStyle2 is a pattern", strokeStyle2.getType() == FillStrokeStyle.TYPE_CSSCOLOR);
assertFalse("strokeStyle2 is a pattern", strokeStyle2.getType() == FillStrokeStyle.TYPE_GRADIENT);
assertTrue("strokeStyle2 is a pattern", strokeStyle2.getType() == FillStrokeStyle.TYPE_PATTERN);
}
public void testText() {
if (canvas1 == null) {
return; // don't continue if not supported
}
canvas1.setHeight("40px");
canvas1.setWidth("60px");
Context2d context = canvas1.getContext2d();
context.setFont("bold 40px sans-serif");
context.setTextAlign(TextAlign.CENTER);
context.setTextBaseline(TextBaseline.HANGING);
context.fillText("GWT", 50, 60);
assertEquals(TextAlign.CENTER.getValue(), context.getTextAlign());
assertEquals(TextBaseline.HANGING.getValue(), context.getTextBaseline());
}
}