de36b2aaba
Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
279 lines
6.9 KiB
JavaScript
279 lines
6.9 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
function xmlEncode(s) {
|
|
var i = 0,
|
|
ch;
|
|
s = String(s);
|
|
while (
|
|
i < s.length &&
|
|
(ch = s[i]) !== "&" &&
|
|
ch !== "<" &&
|
|
ch !== '"' &&
|
|
ch !== "\n" &&
|
|
ch !== "\r" &&
|
|
ch !== "\t"
|
|
) {
|
|
i++;
|
|
}
|
|
if (i >= s.length) {
|
|
return s;
|
|
}
|
|
var buf = s.substring(0, i);
|
|
while (i < s.length) {
|
|
ch = s[i++];
|
|
switch (ch) {
|
|
case "&":
|
|
buf += "&";
|
|
break;
|
|
case "<":
|
|
buf += "<";
|
|
break;
|
|
case '"':
|
|
buf += """;
|
|
break;
|
|
case "\n":
|
|
buf += "
";
|
|
break;
|
|
case "\r":
|
|
buf += "
";
|
|
break;
|
|
case "\t":
|
|
buf += "	";
|
|
break;
|
|
default:
|
|
buf += ch;
|
|
break;
|
|
}
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
function DOMElement(name) {
|
|
this.nodeName = name;
|
|
this.childNodes = [];
|
|
this.attributes = {};
|
|
this.textContent = "";
|
|
|
|
if (name === "style") {
|
|
this.sheet = {
|
|
cssRules: [],
|
|
insertRule: function(rule) {
|
|
this.cssRules.push(rule);
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
DOMElement.prototype = {
|
|
getAttribute: function DOMElement_getAttribute(name) {
|
|
if (name in this.attributes) {
|
|
return this.attributes[name];
|
|
}
|
|
return null;
|
|
},
|
|
|
|
getAttributeNS: function DOMElement_getAttributeNS(NS, name) {
|
|
// Fast path
|
|
if (name in this.attributes) {
|
|
return this.attributes[name];
|
|
}
|
|
// Slow path - used by test/unit/display_svg_spec.js
|
|
// Assuming that there is only one matching attribute for a given name,
|
|
// across all namespaces.
|
|
if (NS) {
|
|
var suffix = ":" + name;
|
|
for (var fullName in this.attributes) {
|
|
if (fullName.slice(-suffix.length) === suffix) {
|
|
return this.attributes[fullName];
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
|
|
setAttribute: function DOMElement_setAttribute(name, value) {
|
|
value = value || "";
|
|
value = xmlEncode(value);
|
|
this.attributes[name] = value;
|
|
},
|
|
|
|
setAttributeNS: function DOMElement_setAttributeNS(NS, name, value) {
|
|
this.setAttribute(name, value);
|
|
},
|
|
|
|
appendChild: function DOMElement_appendChild(element) {
|
|
var childNodes = this.childNodes;
|
|
if (!childNodes.includes(element)) {
|
|
childNodes.push(element);
|
|
}
|
|
},
|
|
|
|
hasChildNodes: function DOMElement_hasChildNodes() {
|
|
return this.childNodes.length !== 0;
|
|
},
|
|
|
|
cloneNode: function DOMElement_cloneNode() {
|
|
var newNode = new DOMElement(this.nodeName);
|
|
newNode.childNodes = this.childNodes;
|
|
newNode.attributes = this.attributes;
|
|
newNode.textContent = this.textContent;
|
|
return newNode;
|
|
},
|
|
|
|
// This method is offered for convenience. It is recommended to directly use
|
|
// getSerializer because that allows you to process the chunks as they come
|
|
// instead of requiring the whole image to fit in memory.
|
|
toString: function DOMElement_toString() {
|
|
var buf = [];
|
|
var serializer = this.getSerializer();
|
|
var chunk;
|
|
while ((chunk = serializer.getNext()) !== null) {
|
|
buf.push(chunk);
|
|
}
|
|
return buf.join("");
|
|
},
|
|
|
|
getSerializer: function DOMElement_getSerializer() {
|
|
return new DOMElementSerializer(this);
|
|
},
|
|
};
|
|
|
|
function DOMElementSerializer(node) {
|
|
this._node = node;
|
|
this._state = 0;
|
|
this._loopIndex = 0;
|
|
this._attributeKeys = null;
|
|
this._childSerializer = null;
|
|
}
|
|
DOMElementSerializer.prototype = {
|
|
/**
|
|
* Yields the next chunk in the serialization of the element.
|
|
*
|
|
* @returns {string|null} null if the element has fully been serialized.
|
|
*/
|
|
getNext: function DOMElementSerializer_getNext() {
|
|
var node = this._node;
|
|
switch (this._state) {
|
|
case 0: // Start opening tag.
|
|
++this._state;
|
|
return "<" + node.nodeName;
|
|
case 1: // Add SVG namespace if this is the root element.
|
|
++this._state;
|
|
if (node.nodeName === "svg:svg") {
|
|
return (
|
|
' xmlns:xlink="http://www.w3.org/1999/xlink"' +
|
|
' xmlns:svg="http://www.w3.org/2000/svg"'
|
|
);
|
|
}
|
|
/* falls through */
|
|
case 2: // Initialize variables for looping over attributes.
|
|
++this._state;
|
|
this._loopIndex = 0;
|
|
this._attributeKeys = Object.keys(node.attributes);
|
|
/* falls through */
|
|
case 3: // Serialize any attributes and end opening tag.
|
|
if (this._loopIndex < this._attributeKeys.length) {
|
|
var name = this._attributeKeys[this._loopIndex++];
|
|
return " " + name + '="' + xmlEncode(node.attributes[name]) + '"';
|
|
}
|
|
++this._state;
|
|
return ">";
|
|
case 4: // Serialize textContent for tspan/style elements.
|
|
if (node.nodeName === "svg:tspan" || node.nodeName === "svg:style") {
|
|
this._state = 6;
|
|
return xmlEncode(node.textContent);
|
|
}
|
|
++this._state;
|
|
this._loopIndex = 0;
|
|
/* falls through */
|
|
case 5: // Serialize child nodes (only for non-tspan/style elements).
|
|
var value;
|
|
while (true) {
|
|
value = this._childSerializer && this._childSerializer.getNext();
|
|
if (value !== null) {
|
|
return value;
|
|
}
|
|
var nextChild = node.childNodes[this._loopIndex++];
|
|
if (nextChild) {
|
|
this._childSerializer = new DOMElementSerializer(nextChild);
|
|
} else {
|
|
this._childSerializer = null;
|
|
++this._state;
|
|
break;
|
|
}
|
|
}
|
|
/* falls through */
|
|
case 6: // Ending tag.
|
|
++this._state;
|
|
return "</" + node.nodeName + ">";
|
|
case 7: // Done.
|
|
return null;
|
|
default:
|
|
throw new Error("Unexpected serialization state: " + this._state);
|
|
}
|
|
},
|
|
};
|
|
|
|
const document = {
|
|
childNodes: [],
|
|
|
|
get currentScript() {
|
|
return { src: "" };
|
|
},
|
|
|
|
get documentElement() {
|
|
return this;
|
|
},
|
|
|
|
createElementNS: function(NS, element) {
|
|
var elObject = new DOMElement(element);
|
|
return elObject;
|
|
},
|
|
|
|
createElement: function(element) {
|
|
return this.createElementNS("", element);
|
|
},
|
|
|
|
getElementsByTagName: function(element) {
|
|
if (element === "head") {
|
|
return [this.head || (this.head = new DOMElement("head"))];
|
|
}
|
|
return [];
|
|
},
|
|
};
|
|
|
|
function Image() {
|
|
this._src = null;
|
|
this.onload = null;
|
|
}
|
|
Image.prototype = {
|
|
get src() {
|
|
return this._src;
|
|
},
|
|
set src(value) {
|
|
this._src = value;
|
|
if (this.onload) {
|
|
this.onload();
|
|
}
|
|
},
|
|
};
|
|
|
|
exports.document = document;
|
|
exports.Image = Image;
|
|
|
|
var exported_symbols = Object.keys(exports);
|
|
|
|
exports.setStubs = function(namespace) {
|
|
exported_symbols.forEach(function(key) {
|
|
console.assert(!(key in namespace), "property should not be set: " + key);
|
|
namespace[key] = exports[key];
|
|
});
|
|
};
|
|
exports.unsetStubs = function(namespace) {
|
|
exported_symbols.forEach(function(key) {
|
|
console.assert(key in namespace, "property should be set: " + key);
|
|
delete namespace[key];
|
|
});
|
|
};
|