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