| /* |
| * 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()); |
| } |
| |
| // This test currently fails on IE9 and is disabled. |
| public void disabled_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", aPixel, 0); |
| int bPixel = clampArrayGet.get(-9999); |
| assertEquals("CanvasPixelArray should return 0 for values off its end", bPixel, 0); |
| } |
| |
| 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()); |
| } |
| } |