View Javadoc
1   /*
2    * Copyright (c) 2002-2026 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    * https://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 org.htmlunit.javascript.host.html;
16  
17  import static org.htmlunit.BrowserVersionFeatures.JS_CANVAS_DATA_URL_CHROME_PNG;
18  
19  import org.htmlunit.html.HtmlCanvas;
20  import org.htmlunit.javascript.HtmlUnitScriptable;
21  import org.htmlunit.javascript.JavaScriptEngine;
22  import org.htmlunit.javascript.configuration.JsxClass;
23  import org.htmlunit.javascript.configuration.JsxConstructor;
24  import org.htmlunit.javascript.configuration.JsxFunction;
25  import org.htmlunit.javascript.configuration.JsxGetter;
26  import org.htmlunit.javascript.configuration.JsxSetter;
27  import org.htmlunit.javascript.host.canvas.CanvasRenderingContext2D;
28  
29  /**
30   * The JavaScript object {@code HTMLCanvasElement}.
31   *
32   * @author Ahmed Ashour
33   * @author Ronald Brill
34   * @author Frank Danek
35   *
36   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement">MDN Documentation</a>
37   */
38  @JsxClass(domClass = HtmlCanvas.class)
39  public class HTMLCanvasElement extends HTMLElement {
40  
41      private CanvasRenderingContext2D context2d_;
42  
43      /**
44       * JavaScript constructor.
45       */
46      @Override
47      @JsxConstructor
48      public void jsConstructor() {
49          super.jsConstructor();
50      }
51  
52      /**
53       * Returns the {@code width} property.
54       * @return the {@code width} property
55       */
56      @JsxGetter
57      public int getWidth() {
58          final String value = getDomNodeOrDie().getAttributeDirect("width");
59          final Integer intValue = getValue(value);
60          if (intValue != null) {
61              return intValue;
62          }
63          return 300;
64      }
65  
66      static Integer getValue(final String value) {
67          int index = -1;
68          while (index + 1 < value.length() && Character.isDigit(value.charAt(index + 1))) {
69              index++;
70          }
71          if (index != -1) {
72              return Integer.parseInt(value.substring(0, index + 1));
73          }
74          return null;
75      }
76  
77      /**
78       * Sets the {@code width} property.
79       * @param width the {@code width} property value
80       */
81      @JsxSetter
82      public void setWidth(final int width) {
83          getDomNodeOrDie().setAttribute("width", Integer.toString(width));
84      }
85  
86      /**
87       * Returns the {@code height} property.
88       * @return the {@code height} property
89       */
90      @JsxGetter
91      public int getHeight() {
92          final String value = getDomNodeOrDie().getAttributeDirect("height");
93          final Integer intValue = getValue(value);
94          if (intValue != null) {
95              return intValue;
96          }
97          return 150;
98      }
99  
100     /**
101      * Sets the {@code height} property.
102      * @param height the {@code height} property value
103      */
104     @JsxSetter
105     public void setHeight(final int height) {
106         getDomNodeOrDie().setAttribute("height", Integer.toString(height));
107     }
108 
109     /**
110      * Gets the context.
111      * @param contextId the context id
112      * @return an object that exposes an API for drawing on the canvas,
113      *         or null if the given context ID is not supported
114      */
115     @JsxFunction
116     public HtmlUnitScriptable getContext(final String contextId) {
117         if ("2d".equals(contextId)) {
118             if (context2d_ == null) {
119                 final CanvasRenderingContext2D context = new CanvasRenderingContext2D(this);
120                 context.setParentScope(getParentScope());
121                 context.setPrototype(getPrototype(context.getClass()));
122                 context2d_ = context;
123             }
124             return context2d_;
125         }
126         return null;
127     }
128 
129     /**
130      * Gets the data: URL representation of the canvas element.
131      * Here we return an empty image.
132      * @param type the type (optional)
133      * @return the data URL
134      */
135     @JsxFunction
136     public String toDataURL(final Object type) {
137         if (context2d_ != null) {
138             final String typeInUse;
139             if (JavaScriptEngine.isUndefined(type)) {
140                 typeInUse = null;
141             }
142             else {
143                 typeInUse = JavaScriptEngine.toString(type);
144             }
145             return context2d_.toDataURL(typeInUse);
146         }
147 
148         if (getBrowserVersion().hasFeature(JS_CANVAS_DATA_URL_CHROME_PNG)) {
149             return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAEYklEQVR4Xu3UAQkAAAwCwdm/"
150                 + "9HI83BLIOdw5AgQIRAQWySkmAQIEzmB5AgIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYO"
151                 + "VqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1"
152                 + "OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamK"
153                 + "kEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWC"
154                 + "EiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCV"
155                 + "AwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgI"
156                 + "DB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg"
157                 + "+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbL"
158                 + "DxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8"
159                 + "gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QI"
160                 + "BARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAg"
161                 + "YyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZ"
162                 + "AYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgI"
163                 + "GK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDF"
164                 + "amKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlACBB1YxAJfjJb2jA"
165                 + "AAAAElFTkSuQmCC";
166         }
167 
168         return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAAxUlEQVR4nO3BMQEAAADCoPVPbQhf"
169             + "oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
170             + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
171             + "AAAAAAAAAAAAAAAAAAAAAAAAAAAOA1v9QAATX68/0AAAAASUVORK5CYII=";
172     }
173 }