| "use strict"; |
| const conversions = require("webidl-conversions"); |
| const { serializeURL } = require("whatwg-url"); |
| const HTMLElementImpl = require("./HTMLElement-impl").implementation; |
| const { Canvas } = require("../../utils"); |
| const { parseURLToResultingURLRecord } = require("../helpers/document-base-url"); |
| |
| class HTMLImageElementImpl extends HTMLElementImpl { |
| constructor(...args) { |
| super(...args); |
| this._currentRequestState = "unavailable"; |
| } |
| |
| _attrModified(name, value, oldVal) { |
| // TODO: handle crossorigin |
| if (name === "src" || ((name === "srcset" || name === "width" || name === "sizes") && value !== oldVal)) { |
| this._updateTheImageData(); |
| } |
| |
| super._attrModified(name, value, oldVal); |
| } |
| |
| get _accept() { |
| return "image/png,image/*;q=0.8,*/*;q=0.5"; |
| } |
| |
| get height() { |
| // Just like on browsers, if no width / height is defined, we fall back on the |
| // dimensions of the internal image data. |
| return this.hasAttributeNS(null, "height") ? |
| conversions["unsigned long"](this.getAttributeNS(null, "height")) : |
| this.naturalHeight; |
| } |
| |
| set height(V) { |
| this.setAttributeNS(null, "height", String(V)); |
| } |
| |
| get width() { |
| return this.hasAttributeNS(null, "width") ? |
| conversions["unsigned long"](this.getAttributeNS(null, "width")) : |
| this.naturalWidth; |
| } |
| |
| set width(V) { |
| this.setAttributeNS(null, "width", String(V)); |
| } |
| |
| get naturalHeight() { |
| return this._image ? this._image.naturalHeight : 0; |
| } |
| |
| get naturalWidth() { |
| return this._image ? this._image.naturalWidth : 0; |
| } |
| |
| get complete() { |
| const srcAttributeValue = this.getAttributeNS(null, "src"); |
| return srcAttributeValue === null || |
| srcAttributeValue === "" || |
| this._currentRequestState === "broken" || |
| this._currentRequestState === "completely available"; |
| } |
| |
| get currentSrc() { |
| return this._currentSrc || ""; |
| } |
| |
| // https://html.spec.whatwg.org/multipage/images.html#updating-the-image-data |
| _updateTheImageData() { |
| const document = this._ownerDocument; |
| |
| if (!document._defaultView) { |
| return; |
| } |
| |
| if (!Canvas) { |
| return; |
| } |
| |
| if (!this._image) { |
| this._image = new Canvas.Image(); |
| } |
| this._currentSrc = null; |
| this._currentRequestState = "unavailable"; |
| const srcAttributeValue = this.getAttributeNS(null, "src"); |
| let urlString = null; |
| if (srcAttributeValue !== null && srcAttributeValue !== "") { |
| const urlRecord = parseURLToResultingURLRecord(srcAttributeValue, this._ownerDocument); |
| if (urlRecord === null) { |
| return; |
| } |
| urlString = serializeURL(urlRecord); |
| } |
| if (urlString !== null) { |
| const resourceLoader = document._resourceLoader; |
| let request; |
| |
| const onLoadImage = data => { |
| const { response } = request; |
| |
| if (response && response.statusCode !== undefined && response.statusCode !== 200) { |
| throw new Error("Status code: " + response.statusCode); |
| } |
| let error = null; |
| this._image.onerror = function (err) { |
| error = err; |
| }; |
| this._image.src = data; |
| if (error) { |
| throw new Error(error); |
| } |
| this._currentSrc = srcAttributeValue; |
| this._currentRequestState = "completely available"; |
| }; |
| |
| request = resourceLoader.fetch(urlString, { |
| element: this, |
| onLoad: onLoadImage, |
| onError: () => { |
| this._currentRequestState = "broken"; |
| } |
| }); |
| } else { |
| this._image.src = ""; |
| } |
| } |
| } |
| |
| module.exports = { |
| implementation: HTMLImageElementImpl |
| }; |