0e1b5589e7
These were removed in PR 9170, since they were unused in the browsers that we'll support in PDF.js version `2.0`. However looking at the output of Travis, where a subset of the unit-tests are run using Node.js, there's warnings about `btoa` being undefined. This doesn't appear to cause any errors, which probably explains why we didn't notice this before (despite PR 9201).
261 lines
6.6 KiB
JavaScript
261 lines
6.6 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.indexOf(element) === -1) {
|
|
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);
|
|
}
|
|
}
|
|
|
|
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"';
|
|
}
|
|
case 2: // Initialize variables for looping over attributes.
|
|
++this._state;
|
|
this._loopIndex = 0;
|
|
this._attributeKeys = Object.keys(node.attributes);
|
|
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;
|
|
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;
|
|
}
|
|
}
|
|
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];
|
|
});
|
|
};
|