pdf.js/examples/node/domstubs.js

265 lines
6.7 KiB
JavaScript
Raw Normal View History

2014-08-14 05:04:47 +09:00
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
2018-12-06 21:55:15 +09:00
function xmlEncode(s) {
2014-08-14 05:04:47 +09:00
var i = 0, ch;
2014-10-22 23:59:20 +09:00
s = String(s);
2014-08-14 05:04:47 +09:00
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 += '&amp;';
break;
case '<':
buf += '&lt;';
break;
case '\"':
buf += '&quot;';
break;
case '\n':
buf += '&#xA;';
break;
case '\r':
buf += '&#xD;';
break;
case '\t':
buf += '&#x9;';
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: [],
2018-12-06 21:55:15 +09:00
insertRule: function(rule) {
this.cssRules.push(rule);
},
};
}
2014-08-14 05:04:47 +09:00
}
DOMElement.prototype = {
getAttribute: function DOMElement_getAttribute(name) {
if (name in this.attributes) {
return this.attributes[name];
}
return null;
},
2014-08-14 05:04:47 +09:00
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) {
2014-08-14 05:04:47 +09:00
value = value || '';
value = xmlEncode(value);
this.attributes[name] = value;
},
setAttributeNS: function DOMElement_setAttributeNS(NS, name, value) {
this.setAttribute(name, value);
},
2014-08-14 05:04:47 +09:00
appendChild: function DOMElement_appendChild(element) {
var childNodes = this.childNodes;
2018-12-06 22:02:39 +09:00
if (!childNodes.includes(element)) {
2014-08-14 05:04:47 +09:00
childNodes.push(element);
}
},
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);
2018-12-06 21:55:15 +09:00
},
};
2015-02-03 00:12:52 +09:00
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"';
}
2018-12-06 22:02:39 +09:00
/* falls through */
case 2: // Initialize variables for looping over attributes.
++this._state;
this._loopIndex = 0;
this._attributeKeys = Object.keys(node.attributes);
2018-12-06 22:02:39 +09:00
/* 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;
2018-12-06 22:02:39 +09:00
/* 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;
}
}
2018-12-06 22:02:39 +09:00
/* 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 = {
2018-12-06 21:55:15 +09:00
childNodes: [],
2014-08-14 05:04:47 +09:00
get currentScript() {
2018-12-06 21:55:15 +09:00
return { src: '', };
},
get documentElement() {
return this;
2014-08-14 05:04:47 +09:00
},
2018-12-06 21:55:15 +09:00
createElementNS: function(NS, element) {
2014-08-14 05:04:47 +09:00
var elObject = new DOMElement(element);
return elObject;
},
2018-12-06 21:55:15 +09:00
createElement: function(element) {
return this.createElementNS('', element);
},
2018-12-06 21:55:15 +09:00
getElementsByTagName: function(element) {
if (element === 'head') {
return [this.head || (this.head = new DOMElement('head'))];
}
return [];
2018-12-06 21:55:15 +09:00
},
2014-08-14 05:04:47 +09:00
};
2018-12-06 21:55:15 +09:00
function Image() {
this._src = null;
this.onload = null;
}
Image.prototype = {
2018-12-06 21:55:15 +09:00
get src() {
return this._src;
},
2018-12-06 21:55:15 +09:00
set src(value) {
this._src = value;
if (this.onload) {
this.onload();
}
2018-12-06 21:55:15 +09:00
},
};
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];
});
};