View Javadoc
1   /*
2    * Copyright (c) 2002-2017 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package com.gargoylesoftware.htmlunit.javascript.host.canvas;
16  
17  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_CANVAS_DRAW_THROWS_FOR_MISSING_IMG;
18  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
19  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
20  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF;
21  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF52;
22  
23  import java.io.IOException;
24  
25  import javax.imageio.ImageReader;
26  
27  import com.gargoylesoftware.htmlunit.gae.GAEUtils;
28  import com.gargoylesoftware.htmlunit.html.HtmlImage;
29  import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable;
30  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxClass;
31  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxConstructor;
32  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxFunction;
33  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxGetter;
34  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxSetter;
35  import com.gargoylesoftware.htmlunit.javascript.host.canvas.rendering.AwtRenderingBackend;
36  import com.gargoylesoftware.htmlunit.javascript.host.canvas.rendering.GaeRenderingBackend;
37  import com.gargoylesoftware.htmlunit.javascript.host.canvas.rendering.RenderingBackend;
38  import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLCanvasElement;
39  import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLImageElement;
40  
41  import net.sourceforge.htmlunit.corejs.javascript.Context;
42  import net.sourceforge.htmlunit.corejs.javascript.Undefined;
43  
44  /**
45   * A JavaScript object for {@code CanvasRenderingContext2D}.
46   *
47   * @author Ahmed Ashour
48   * @author Marc Guillemot
49   * @author Frank Danek
50   * @author Ronald Brill
51   */
52  @JsxClass
53  public class CanvasRenderingContext2D extends SimpleScriptable {
54      /** The number of (horizontal) pixels to assume that each character occupies. */
55      private static final int PIXELS_PER_CHAR = 10;
56  
57      private final HTMLCanvasElement canvas_;
58      private RenderingBackend renderingBackend_;
59  
60      /**
61       * Default constructor.
62       */
63      @JsxConstructor({CHROME, FF, EDGE})
64      public CanvasRenderingContext2D() {
65          canvas_ = null;
66          renderingBackend_ = null;
67      }
68  
69      /**
70       * Constructs in association with {@link HTMLCanvasElement}.
71       * @param canvas the {@link HTMLCanvasElement}
72       */
73      public CanvasRenderingContext2D(final HTMLCanvasElement canvas) {
74          canvas_ = canvas;
75          renderingBackend_ = null;
76      }
77  
78      private RenderingBackend getRenderingBackend() {
79          if (renderingBackend_ == null) {
80              final int imageWidth = Math.max(1, canvas_.getWidth());
81              final int imageHeight = Math.max(1, canvas_.getHeight());
82              if (GAEUtils.isGaeMode()) {
83                  renderingBackend_ = new GaeRenderingBackend(imageWidth, imageHeight);
84              }
85              else {
86                  renderingBackend_ = new AwtRenderingBackend(imageWidth, imageHeight);
87              }
88          }
89          return renderingBackend_;
90      }
91  
92      /**
93       * Returns the {@code fillStyle} property.
94       * @return the {@code fillStyle} property
95       */
96      @JsxGetter
97      public Object getFillStyle() {
98          return null;
99      }
100 
101     /**
102      * Sets the {@code fillStyle} property.
103      * @param fillStyle the {@code fillStyle} property
104      */
105     @JsxSetter
106     public void setFillStyle(final String fillStyle) {
107         getRenderingBackend().setFillStyle(fillStyle);
108     }
109 
110     /**
111      * Returns the {@code strokeStyle} property.
112      * @return the {@code strokeStyle} property
113      */
114     @JsxGetter
115     public Object getStrokeStyle() {
116         return null;
117     }
118 
119     /**
120      * Sets the {@code strokeStyle} property.
121      * @param strokeStyle the {@code strokeStyle} property
122      */
123     @JsxSetter
124     public void setStrokeStyle(final Object strokeStyle) {
125         //empty
126     }
127 
128     /**
129      * Returns the {@code lineWidth} property.
130      * @return the {@code lineWidth} property
131      */
132     @JsxGetter
133     public double getLineWidth() {
134         return 0;
135     }
136 
137     /**
138      * Sets the {@code lineWidth} property.
139      * @param lineWidth the {@code lineWidth} property
140      */
141     @JsxSetter
142     public void setLineWidth(final Object lineWidth) {
143         //empty
144     }
145 
146     /**
147      * Returns the {@code globalAlpha} property.
148      * @return the {@code globalAlpha} property
149      */
150     @JsxGetter
151     public double getGlobalAlpha() {
152         return 0;
153     }
154 
155     /**
156      * Sets the {@code globalAlpha} property.
157      * @param globalAlpha the {@code globalAlpha} property
158      */
159     @JsxSetter
160     public void setGlobalAlpha(final Object globalAlpha) {
161         //empty
162     }
163 
164     /**
165      * Draws an arc.
166      * @param x the x
167      * @param y the y
168      * @param radius the radius
169      * @param startAngle the start angle
170      * @param endAngle the end angle
171      * @param anticlockwise is anti-clockwise
172      */
173     @JsxFunction
174     public void arc(final double x, final double y, final double radius, final double startAngle,
175                 final double endAngle, final boolean anticlockwise) {
176         //empty
177     }
178 
179     /**
180      * Draws an arc.
181      * @param x1 the x1
182      * @param y1 the y1
183      * @param x2 the x2
184      * @param y2 the y2
185      * @param radius the radius
186      */
187     @JsxFunction
188     public void arcTo(final double x1, final double y1, final double x2, final double y2,
189                 final double radius) {
190         //empty
191     }
192 
193     /**
194      * Begins the subpaths.
195      */
196     @JsxFunction
197     public void beginPath() {
198         //empty
199     }
200 
201     /**
202      * Draws a cubic Bézier curve.
203      * @param cp1x the cp1x
204      * @param cp1y the cp1y
205      * @param cp2x the cp2x
206      * @param cp2y the cp2y
207      * @param x the x
208      * @param y the y
209      */
210     @JsxFunction
211     public void bezierCurveTo(final double cp1x, final double cp1y, final double cp2x, final double cp2y,
212             final double x, final double y) {
213         //empty
214     }
215 
216     /**
217      * Clears the specified rectangular area.
218      * @param x the x
219      * @param y the y
220      * @param w the width
221      * @param h the height
222      */
223     @JsxFunction
224     public void clearRect(final int x, final int y, final int w, final int h) {
225         getRenderingBackend().clearRect(x, y, w, h);
226     }
227 
228     /**
229      * Creates a new clipping region.
230      */
231     @JsxFunction
232     public void clip() {
233         //empty
234     }
235 
236     /**
237      * Closes the subpaths.
238      */
239     @JsxFunction
240     public void closePath() {
241         //empty
242     }
243 
244     /**
245      * Creates a new, blank ImageData object with the specified dimensions.
246      */
247     @JsxFunction
248     public void createImageData() {
249         //empty
250     }
251 
252     /**
253      * Creates linear gradient.
254      * @param x0 the x0
255      * @param y0 the y0
256      * @param r0 the r0
257      * @param x1 the x1
258      * @param y1 the y1
259      * @param r1 the r1
260      */
261     @JsxFunction
262     public void createLinearGradient(final double x0, final double y0, final double r0, final double x1,
263             final Object y1, final Object r1) {
264         //empty
265     }
266 
267     /**
268      * Creates a pattern.
269      */
270     @JsxFunction
271     public void createPattern() {
272         //empty
273     }
274 
275     /**
276      * Creates a gradient.
277      */
278     @JsxFunction
279     public void createRadialGradient() {
280         //empty
281     }
282 
283     /**
284      * Draws images onto the canvas.
285      *
286      * @param image an element to draw into the context
287      * @param sx the X coordinate of the top left corner of the sub-rectangle of the source image
288      *        to draw into the destination context
289      * @param sy the Y coordinate of the top left corner of the sub-rectangle of the source image
290      *        to draw into the destination context
291      * @param sWidth the width of the sub-rectangle of the source image to draw into the destination context
292      * @param sHeight the height of the sub-rectangle of the source image to draw into the destination context
293      * @param dx the X coordinate in the destination canvas at which to place the top-left corner of the source image
294      * @param dy the Y coordinate in the destination canvas at which to place the top-left corner of the source image
295      * @param dWidth the width to draw the image in the destination canvas. This allows scaling of the drawn image
296      * @param dHeight the height to draw the image in the destination canvas. This allows scaling of the drawn image
297      */
298     @JsxFunction
299     @SuppressWarnings("unused")
300     public void drawImage(final Object image, final int sx, final int sy, final Object sWidth, final Object sHeight,
301             final Object dx, final Object dy, final Object dWidth, final Object dHeight) {
302         final Integer dxI;
303         final Integer dyI;
304         Integer dWidthI = null;
305         Integer dHeightI = null;
306         Integer sWidthI = null;
307         Integer sHeightI = null;
308         if (dx != Undefined.instance) {
309             dxI = ((Number) dx).intValue();
310             dyI = ((Number) dy).intValue();
311             dWidthI = ((Number) dWidth).intValue();
312             dHeightI = ((Number) dHeight).intValue();
313         }
314         else {
315             dxI = sx;
316             dyI = sy;
317         }
318         if (sWidth != Undefined.instance) {
319             sWidthI = ((Number) sWidth).intValue();
320             sHeightI = ((Number) sHeight).intValue();
321         }
322 
323         try {
324             if (image instanceof HTMLImageElement) {
325                 final ImageReader imageReader =
326                         ((HtmlImage) ((HTMLImageElement) image).getDomNodeOrDie()).getImageReader();
327                 getRenderingBackend().drawImage(imageReader, dxI, dyI);
328             }
329         }
330         catch (final IOException ioe) {
331             if (getBrowserVersion().hasFeature(JS_CANVAS_DRAW_THROWS_FOR_MISSING_IMG)) {
332                 throw Context.throwAsScriptRuntimeEx(ioe);
333             }
334         }
335     }
336 
337     /**
338      * Returns the Data URL.
339      *
340      * @param type an optional type
341      * @return the dataURL
342      */
343     public String toDataURL(String type) {
344         try {
345             if (type == null) {
346                 type = "image/png";
347             }
348             return "data:" + type + ";base64," + getRenderingBackend().encodeToString(type);
349         }
350         catch (final IOException ioe) {
351             throw Context.throwAsScriptRuntimeEx(ioe);
352         }
353     }
354 
355     /**
356      * Paints the specified ellipse.
357      * @param x the x
358      * @param y the y
359      * @param radiusX the radiusX
360      * @param radiusY the radiusY
361      * @param rotation the rotation
362      * @param startAngle the startAngle
363      * @param endAngle the endAngle
364      * @param anticlockwise the anticlockwise
365      */
366     @JsxFunction({CHROME, FF52})
367     public void ellipse(final double x, final double y,
368                     final double radiusX, final double radiusY,
369                     final double rotation, final double startAngle, final double endAngle,
370                     final boolean anticlockwise) {
371         //empty
372     }
373 
374     /**
375      * Fills the shape.
376      */
377     @JsxFunction
378     public void fill() {
379         //empty
380     }
381 
382     /**
383      * Paints the specified rectangular area.
384      * @param x the x
385      * @param y the y
386      * @param w the width
387      * @param h the height
388      */
389     @JsxFunction
390     public void fillRect(final int x, final int y, final int w, final int h) {
391         getRenderingBackend().fillRect(x, y, w, h);
392     }
393 
394     /**
395      * Fills a given text at the given (x, y) position.
396      * @param text the text
397      * @param x the x
398      * @param y the y
399      */
400     @JsxFunction
401     public void fillText(final String text, final int x, final int y) {
402         getRenderingBackend().fillText(text, x, y);
403     }
404 
405     /**
406      * Returns the {@code ImageData} object.
407      * @param sx x
408      * @param sy y
409      * @param sw width
410      * @param sh height
411      * @return the {@code ImageData} object
412      */
413     @JsxFunction
414     public ImageData getImageData(final int sx, final int sy, final int sw, final int sh) {
415         final ImageData imageData = new ImageData(getRenderingBackend(), sx, sy, sw, sh);
416         imageData.setParentScope(getParentScope());
417         imageData.setPrototype(getPrototype(imageData.getClass()));
418         return imageData;
419     }
420 
421     /**
422      * Dummy placeholder.
423      */
424     @JsxFunction
425     public void getLineDash() {
426         //empty
427     }
428 
429     /**
430      * Dummy placeholder.
431      */
432     @JsxFunction
433     public void getLineData() {
434         //empty
435     }
436 
437     /**
438      * Dummy placeholder.
439      */
440     @JsxFunction
441     public void isPointInPath() {
442         //empty
443     }
444 
445     /**
446      * Connect the last point to the given point.
447      * @param x the x
448      * @param y the y
449      */
450     @JsxFunction
451     public void lineTo(final double x, final double y) {
452         //empty
453     }
454 
455     /**
456      * Calculate TextMetrics for the given text.
457      * @param text the text to measure
458      * @return the text metrics
459      */
460     @JsxFunction
461     public TextMetrics measureText(final Object text) {
462         if (text == null || Undefined.instance == text) {
463             throw Context.throwAsScriptRuntimeEx(
464                     new RuntimeException("Missing argument for CanvasRenderingContext2D.measureText()."));
465         }
466 
467         final String textValue = Context.toString(text);
468 
469         // TODO take font into account
470         final int width = textValue.length() * PIXELS_PER_CHAR;
471 
472         final TextMetrics metrics = new TextMetrics(width);
473         metrics.setParentScope(getParentScope());
474         metrics.setPrototype(getPrototype(metrics.getClass()));
475         return metrics;
476     }
477 
478     /**
479      * Creates a new subpath.
480      * @param x the x
481      * @param y the y
482      */
483     @JsxFunction
484     public void moveTo(final double x, final double y) {
485         //empty
486     }
487 
488     /**
489      * Dummy placeholder.
490      */
491     @JsxFunction
492     public void putImageData() {
493         //empty
494     }
495 
496     /**
497      * Draws a quadratic Bézier curve.
498      * @param controlPointX the x-coordinate of the control point
499      * @param controlPointY the y-coordinate of the control point
500      * @param endPointX the x-coordinate of the end point
501      * @param endPointY the y-coordinate of the end point
502      */
503     @JsxFunction
504     public void quadraticCurveTo(final double controlPointX, final double controlPointY,
505             final double endPointX, final double endPointY) {
506         //empty
507     }
508 
509     /**
510      * Renders a rectangle.
511      * @param x the x
512      * @param y the y
513      * @param w the width
514      * @param h the height
515      */
516     @JsxFunction
517     public void rect(final double x, final double y, final double w, final double h) {
518         //empty
519     }
520 
521     /**
522      * Pops state stack and restore state.
523      */
524     @JsxFunction
525     public void restore() {
526         //empty
527     }
528 
529     /**
530      * Dummy placeholder.
531      */
532     @JsxFunction
533     public void rotate() {
534         //empty
535     }
536 
537     /**
538      * Pushes state on state stack.
539      */
540     @JsxFunction
541     public void save() {
542         //empty
543     }
544 
545     /**
546      * Changes the transformation matrix to apply a scaling transformation with the given characteristics.
547      * @param x the scale factor in the horizontal direction
548      * @param y the scale factor in the vertical direction
549      */
550     @JsxFunction
551     public void scale(final Object x, final Object y) {
552       //empty
553     }
554 
555     /**
556      * Dummy placeholder.
557      */
558     @JsxFunction
559     public void setLineDash() {
560         //empty
561     }
562 
563     /**
564      * Dummy placeholder.
565      */
566     @JsxFunction
567     public void setTransform() {
568         //empty
569     }
570 
571     /**
572      * Calculates the strokes of all the subpaths of the current path.
573      */
574     @JsxFunction
575     public void stroke() {
576         //empty
577     }
578 
579     /**
580      * Strokes the specified rectangular area.
581      * @param x the x
582      * @param y the y
583      * @param w the width
584      * @param h the height
585      */
586     @JsxFunction
587     public void strokeRect(final int x, final int y, final int w, final int h) {
588         getRenderingBackend().strokeRect(x, y, w, h);
589     }
590 
591     /**
592      * Dummy placeholder.
593      */
594     @JsxFunction
595     public void strokeText() {
596         //empty
597     }
598 
599     /**
600      * Dummy placeholder.
601      */
602     @JsxFunction
603     public void transform() {
604         //empty
605     }
606 
607     /**
608      * Changes the transformation matrix to apply a translation transformation with the given characteristics.
609      * @param x the translation distance in the horizontal direction
610      * @param y the translation distance in the vertical direction
611      */
612     @JsxFunction
613     public void translate(final Object x, final Object y) {
614       // empty
615     }
616 
617     /**
618      * Returns the associated {@link HTMLCanvasElement}.
619      * @return the associated {@link HTMLCanvasElement}
620      */
621     @JsxGetter
622     public HTMLCanvasElement getCanvas() {
623         return canvas_;
624     }
625 }