Introduce DOMSVGFactory
This patch provides a new unit tested factory for creating SVG containers and elements. This code is duplicated twice in the codebase, but with upcoming changes this would need to be duplicated even more. Moreover, consolidating this code in one factory allows us to replace it easily for e.g., supporting Node.js. Therefore, move this to a central place and update/ES6-ify the related code. Finally, we replace `setAttributeNS` with `setAttribute` because no namespace is provided.
This commit is contained in:
parent
1c9af00bee
commit
f7fd1db52f
@ -14,8 +14,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
addLinkAttributes, CustomStyle, getDefaultSetting, getFilenameFromUrl,
|
addLinkAttributes, CustomStyle, DOMSVGFactory, getDefaultSetting,
|
||||||
LinkTarget
|
getFilenameFromUrl, LinkTarget
|
||||||
} from './dom_utils';
|
} from './dom_utils';
|
||||||
import {
|
import {
|
||||||
AnnotationBorderStyleType, AnnotationType, stringToPDFString, Util, warn
|
AnnotationBorderStyleType, AnnotationType, stringToPDFString, Util, warn
|
||||||
@ -31,6 +31,7 @@ import {
|
|||||||
* @property {DownloadManager} downloadManager
|
* @property {DownloadManager} downloadManager
|
||||||
* @property {string} imageResourcesPath
|
* @property {string} imageResourcesPath
|
||||||
* @property {boolean} renderInteractiveForms
|
* @property {boolean} renderInteractiveForms
|
||||||
|
* @property {Object} svgFactory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class AnnotationElementFactory {
|
class AnnotationElementFactory {
|
||||||
@ -105,6 +106,7 @@ class AnnotationElement {
|
|||||||
this.downloadManager = parameters.downloadManager;
|
this.downloadManager = parameters.downloadManager;
|
||||||
this.imageResourcesPath = parameters.imageResourcesPath;
|
this.imageResourcesPath = parameters.imageResourcesPath;
|
||||||
this.renderInteractiveForms = parameters.renderInteractiveForms;
|
this.renderInteractiveForms = parameters.renderInteractiveForms;
|
||||||
|
this.svgFactory = parameters.svgFactory;
|
||||||
|
|
||||||
if (isRenderable) {
|
if (isRenderable) {
|
||||||
this.container = this._createContainer(ignoreBorder);
|
this.container = this._createContainer(ignoreBorder);
|
||||||
@ -769,8 +771,6 @@ class LineAnnotationElement extends AnnotationElement {
|
|||||||
* @returns {HTMLSectionElement}
|
* @returns {HTMLSectionElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
||||||
|
|
||||||
this.container.className = 'lineAnnotation';
|
this.container.className = 'lineAnnotation';
|
||||||
|
|
||||||
// Create an invisible line with the same starting and ending coordinates
|
// Create an invisible line with the same starting and ending coordinates
|
||||||
@ -779,30 +779,24 @@ class LineAnnotationElement extends AnnotationElement {
|
|||||||
let data = this.data;
|
let data = this.data;
|
||||||
let width = data.rect[2] - data.rect[0];
|
let width = data.rect[2] - data.rect[0];
|
||||||
let height = data.rect[3] - data.rect[1];
|
let height = data.rect[3] - data.rect[1];
|
||||||
|
let svg = this.svgFactory.create(width, height);
|
||||||
let svg = document.createElementNS(SVG_NS, 'svg:svg');
|
|
||||||
svg.setAttributeNS(null, 'version', '1.1');
|
|
||||||
svg.setAttributeNS(null, 'width', width + 'px');
|
|
||||||
svg.setAttributeNS(null, 'height', height + 'px');
|
|
||||||
svg.setAttributeNS(null, 'preserveAspectRatio', 'none');
|
|
||||||
svg.setAttributeNS(null, 'viewBox', '0 0 ' + width + ' ' + height);
|
|
||||||
|
|
||||||
// PDF coordinates are calculated from a bottom left origin, so transform
|
// PDF coordinates are calculated from a bottom left origin, so transform
|
||||||
// the line coordinates to a top left origin for the SVG element.
|
// the line coordinates to a top left origin for the SVG element.
|
||||||
let line = document.createElementNS(SVG_NS, 'svg:line');
|
let line = this.svgFactory.createElement('svg:line');
|
||||||
line.setAttributeNS(null, 'x1', data.rect[2] - data.lineCoordinates[0]);
|
line.setAttribute('x1', data.rect[2] - data.lineCoordinates[0]);
|
||||||
line.setAttributeNS(null, 'y1', data.rect[3] - data.lineCoordinates[1]);
|
line.setAttribute('y1', data.rect[3] - data.lineCoordinates[1]);
|
||||||
line.setAttributeNS(null, 'x2', data.rect[2] - data.lineCoordinates[2]);
|
line.setAttribute('x2', data.rect[2] - data.lineCoordinates[2]);
|
||||||
line.setAttributeNS(null, 'y2', data.rect[3] - data.lineCoordinates[3]);
|
line.setAttribute('y2', data.rect[3] - data.lineCoordinates[3]);
|
||||||
line.setAttributeNS(null, 'stroke-width', data.borderStyle.width);
|
line.setAttribute('stroke-width', data.borderStyle.width);
|
||||||
line.setAttributeNS(null, 'stroke', 'transparent');
|
line.setAttribute('stroke', 'transparent');
|
||||||
|
|
||||||
svg.appendChild(line);
|
svg.appendChild(line);
|
||||||
this.container.append(svg);
|
this.container.append(svg);
|
||||||
|
|
||||||
// Create the popup ourselves so that we can bind it to the line instead
|
// Create the popup ourselves so that we can bind it to the line instead
|
||||||
// of to the entire container (which is the default).
|
// of to the entire container (which is the default).
|
||||||
this._createPopup(this.container, line, this.data);
|
this._createPopup(this.container, line, data);
|
||||||
|
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
@ -993,6 +987,7 @@ class AnnotationLayer {
|
|||||||
imageResourcesPath: parameters.imageResourcesPath ||
|
imageResourcesPath: parameters.imageResourcesPath ||
|
||||||
getDefaultSetting('imageResourcesPath'),
|
getDefaultSetting('imageResourcesPath'),
|
||||||
renderInteractiveForms: parameters.renderInteractiveForms || false,
|
renderInteractiveForms: parameters.renderInteractiveForms || false,
|
||||||
|
svgFactory: new DOMSVGFactory(),
|
||||||
});
|
});
|
||||||
if (element.isRenderable) {
|
if (element.isRenderable) {
|
||||||
parameters.div.appendChild(element.render());
|
parameters.div.appendChild(element.render());
|
||||||
|
@ -14,12 +14,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CMapCompressionType, createValidAbsoluteUrl, deprecated,
|
assert, CMapCompressionType, createValidAbsoluteUrl, deprecated,
|
||||||
removeNullCharacters, stringToBytes, warn
|
removeNullCharacters, stringToBytes, warn
|
||||||
} from '../shared/util';
|
} from '../shared/util';
|
||||||
import globalScope from '../shared/global_scope';
|
import globalScope from '../shared/global_scope';
|
||||||
|
|
||||||
var DEFAULT_LINK_REL = 'noopener noreferrer nofollow';
|
const DEFAULT_LINK_REL = 'noopener noreferrer nofollow';
|
||||||
|
const SVG_NS = 'http://www.w3.org/2000/svg';
|
||||||
|
|
||||||
class DOMCanvasFactory {
|
class DOMCanvasFactory {
|
||||||
create(width, height) {
|
create(width, height) {
|
||||||
@ -109,6 +110,27 @@ class DOMCMapReaderFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DOMSVGFactory {
|
||||||
|
create(width, height) {
|
||||||
|
assert(width > 0 && height > 0, 'Invalid SVG dimensions');
|
||||||
|
|
||||||
|
let svg = document.createElementNS(SVG_NS, 'svg:svg');
|
||||||
|
svg.setAttribute('version', '1.1');
|
||||||
|
svg.setAttribute('width', width + 'px');
|
||||||
|
svg.setAttribute('height', height + 'px');
|
||||||
|
svg.setAttribute('preserveAspectRatio', 'none');
|
||||||
|
svg.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
|
||||||
|
|
||||||
|
return svg;
|
||||||
|
}
|
||||||
|
|
||||||
|
createElement(type) {
|
||||||
|
assert(typeof type === 'string', 'Invalid SVG element type');
|
||||||
|
|
||||||
|
return document.createElementNS(SVG_NS, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optimised CSS custom property getter/setter.
|
* Optimised CSS custom property getter/setter.
|
||||||
* @class
|
* @class
|
||||||
@ -330,4 +352,5 @@ export {
|
|||||||
DEFAULT_LINK_REL,
|
DEFAULT_LINK_REL,
|
||||||
DOMCanvasFactory,
|
DOMCanvasFactory,
|
||||||
DOMCMapReaderFactory,
|
DOMCMapReaderFactory,
|
||||||
|
DOMSVGFactory,
|
||||||
};
|
};
|
||||||
|
@ -18,6 +18,7 @@ import {
|
|||||||
createObjectURL, FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageKind, isNodeJS,
|
createObjectURL, FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageKind, isNodeJS,
|
||||||
isNum, OPS, Util, warn
|
isNum, OPS, Util, warn
|
||||||
} from '../shared/util';
|
} from '../shared/util';
|
||||||
|
import { DOMSVGFactory } from './dom_utils';
|
||||||
|
|
||||||
var SVGGraphics = function() {
|
var SVGGraphics = function() {
|
||||||
throw new Error('Not implemented: SVGGraphics');
|
throw new Error('Not implemented: SVGGraphics');
|
||||||
@ -403,6 +404,8 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function SVGGraphics(commonObjs, objs, forceDataSchema) {
|
function SVGGraphics(commonObjs, objs, forceDataSchema) {
|
||||||
|
this.svgFactory = new DOMSVGFactory();
|
||||||
|
|
||||||
this.current = new SVGExtraState();
|
this.current = new SVGExtraState();
|
||||||
this.transformMatrix = IDENTITY_MATRIX; // Graphics state matrix
|
this.transformMatrix = IDENTITY_MATRIX; // Graphics state matrix
|
||||||
this.transformStack = [];
|
this.transformStack = [];
|
||||||
@ -418,7 +421,6 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
this.forceDataSchema = !!forceDataSchema;
|
this.forceDataSchema = !!forceDataSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
var NS = 'http://www.w3.org/2000/svg';
|
|
||||||
var XML_NS = 'http://www.w3.org/XML/1998/namespace';
|
var XML_NS = 'http://www.w3.org/XML/1998/namespace';
|
||||||
var XLINK_NS = 'http://www.w3.org/1999/xlink';
|
var XLINK_NS = 'http://www.w3.org/1999/xlink';
|
||||||
var LINE_CAP_STYLES = ['butt', 'round', 'square'];
|
var LINE_CAP_STYLES = ['butt', 'round', 'square'];
|
||||||
@ -683,13 +685,13 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
this.current.y = this.current.lineY = 0;
|
this.current.y = this.current.lineY = 0;
|
||||||
|
|
||||||
current.xcoords = [];
|
current.xcoords = [];
|
||||||
current.tspan = document.createElementNS(NS, 'svg:tspan');
|
current.tspan = this.svgFactory.createElement('svg:tspan');
|
||||||
current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
|
current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
|
||||||
current.tspan.setAttributeNS(null, 'font-size',
|
current.tspan.setAttributeNS(null, 'font-size',
|
||||||
pf(current.fontSize) + 'px');
|
pf(current.fontSize) + 'px');
|
||||||
current.tspan.setAttributeNS(null, 'y', pf(-current.y));
|
current.tspan.setAttributeNS(null, 'y', pf(-current.y));
|
||||||
|
|
||||||
current.txtElement = document.createElementNS(NS, 'svg:text');
|
current.txtElement = this.svgFactory.createElement('svg:text');
|
||||||
current.txtElement.appendChild(current.tspan);
|
current.txtElement.appendChild(current.tspan);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -698,9 +700,9 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
this.current.y = this.current.lineY = 0;
|
this.current.y = this.current.lineY = 0;
|
||||||
this.current.textMatrix = IDENTITY_MATRIX;
|
this.current.textMatrix = IDENTITY_MATRIX;
|
||||||
this.current.lineMatrix = IDENTITY_MATRIX;
|
this.current.lineMatrix = IDENTITY_MATRIX;
|
||||||
this.current.tspan = document.createElementNS(NS, 'svg:tspan');
|
this.current.tspan = this.svgFactory.createElement('svg:tspan');
|
||||||
this.current.txtElement = document.createElementNS(NS, 'svg:text');
|
this.current.txtElement = this.svgFactory.createElement('svg:text');
|
||||||
this.current.txtgrp = document.createElementNS(NS, 'svg:g');
|
this.current.txtgrp = this.svgFactory.createElement('svg:g');
|
||||||
this.current.xcoords = [];
|
this.current.xcoords = [];
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -710,7 +712,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
this.current.y = this.current.lineY += y;
|
this.current.y = this.current.lineY += y;
|
||||||
|
|
||||||
current.xcoords = [];
|
current.xcoords = [];
|
||||||
current.tspan = document.createElementNS(NS, 'svg:tspan');
|
current.tspan = this.svgFactory.createElement('svg:tspan');
|
||||||
current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
|
current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
|
||||||
current.tspan.setAttributeNS(null, 'font-size',
|
current.tspan.setAttributeNS(null, 'font-size',
|
||||||
pf(current.fontSize) + 'px');
|
pf(current.fontSize) + 'px');
|
||||||
@ -810,7 +812,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
|
|
||||||
addFontStyle: function SVGGraphics_addFontStyle(fontObj) {
|
addFontStyle: function SVGGraphics_addFontStyle(fontObj) {
|
||||||
if (!this.cssStyle) {
|
if (!this.cssStyle) {
|
||||||
this.cssStyle = document.createElementNS(NS, 'svg:style');
|
this.cssStyle = this.svgFactory.createElement('svg:style');
|
||||||
this.cssStyle.setAttributeNS(null, 'type', 'text/css');
|
this.cssStyle.setAttributeNS(null, 'type', 'text/css');
|
||||||
this.defs.appendChild(this.cssStyle);
|
this.defs.appendChild(this.cssStyle);
|
||||||
}
|
}
|
||||||
@ -852,7 +854,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
current.fontWeight = bold;
|
current.fontWeight = bold;
|
||||||
current.fontStyle = italic;
|
current.fontStyle = italic;
|
||||||
|
|
||||||
current.tspan = document.createElementNS(NS, 'svg:tspan');
|
current.tspan = this.svgFactory.createElement('svg:tspan');
|
||||||
current.tspan.setAttributeNS(null, 'y', pf(-current.y));
|
current.tspan.setAttributeNS(null, 'y', pf(-current.y));
|
||||||
current.xcoords = [];
|
current.xcoords = [];
|
||||||
},
|
},
|
||||||
@ -885,7 +887,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
setFillRGBColor: function SVGGraphics_setFillRGBColor(r, g, b) {
|
setFillRGBColor: function SVGGraphics_setFillRGBColor(r, g, b) {
|
||||||
var color = Util.makeCssRgb(r, g, b);
|
var color = Util.makeCssRgb(r, g, b);
|
||||||
this.current.fillColor = color;
|
this.current.fillColor = color;
|
||||||
this.current.tspan = document.createElementNS(NS, 'svg:tspan');
|
this.current.tspan = this.svgFactory.createElement('svg:tspan');
|
||||||
this.current.xcoords = [];
|
this.current.xcoords = [];
|
||||||
},
|
},
|
||||||
setDash: function SVGGraphics_setDash(dashArray, dashPhase) {
|
setDash: function SVGGraphics_setDash(dashArray, dashPhase) {
|
||||||
@ -896,7 +898,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
constructPath: function SVGGraphics_constructPath(ops, args) {
|
constructPath: function SVGGraphics_constructPath(ops, args) {
|
||||||
var current = this.current;
|
var current = this.current;
|
||||||
var x = current.x, y = current.y;
|
var x = current.x, y = current.y;
|
||||||
current.path = document.createElementNS(NS, 'svg:path');
|
current.path = this.svgFactory.createElement('svg:path');
|
||||||
var d = [];
|
var d = [];
|
||||||
var opLength = ops.length;
|
var opLength = ops.length;
|
||||||
|
|
||||||
@ -967,7 +969,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
// Add current path to clipping path
|
// Add current path to clipping path
|
||||||
var clipId = 'clippath' + clipCount;
|
var clipId = 'clippath' + clipCount;
|
||||||
clipCount++;
|
clipCount++;
|
||||||
var clipPath = document.createElementNS(NS, 'svg:clipPath');
|
var clipPath = this.svgFactory.createElement('svg:clipPath');
|
||||||
clipPath.setAttributeNS(null, 'id', clipId);
|
clipPath.setAttributeNS(null, 'id', clipId);
|
||||||
clipPath.setAttributeNS(null, 'transform', pm(this.transformMatrix));
|
clipPath.setAttributeNS(null, 'transform', pm(this.transformMatrix));
|
||||||
var clipElement = current.element.cloneNode();
|
var clipElement = current.element.cloneNode();
|
||||||
@ -1110,7 +1112,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
paintSolidColorImageMask:
|
paintSolidColorImageMask:
|
||||||
function SVGGraphics_paintSolidColorImageMask() {
|
function SVGGraphics_paintSolidColorImageMask() {
|
||||||
var current = this.current;
|
var current = this.current;
|
||||||
var rect = document.createElementNS(NS, 'svg:rect');
|
var rect = this.svgFactory.createElement('svg:rect');
|
||||||
rect.setAttributeNS(null, 'x', '0');
|
rect.setAttributeNS(null, 'x', '0');
|
||||||
rect.setAttributeNS(null, 'y', '0');
|
rect.setAttributeNS(null, 'y', '0');
|
||||||
rect.setAttributeNS(null, 'width', '1px');
|
rect.setAttributeNS(null, 'width', '1px');
|
||||||
@ -1122,7 +1124,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
|
|
||||||
paintJpegXObject: function SVGGraphics_paintJpegXObject(objId, w, h) {
|
paintJpegXObject: function SVGGraphics_paintJpegXObject(objId, w, h) {
|
||||||
var imgObj = this.objs.get(objId);
|
var imgObj = this.objs.get(objId);
|
||||||
var imgEl = document.createElementNS(NS, 'svg:image');
|
var imgEl = this.svgFactory.createElement('svg:image');
|
||||||
imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgObj.src);
|
imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgObj.src);
|
||||||
imgEl.setAttributeNS(null, 'width', pf(w));
|
imgEl.setAttributeNS(null, 'width', pf(w));
|
||||||
imgEl.setAttributeNS(null, 'height', pf(h));
|
imgEl.setAttributeNS(null, 'height', pf(h));
|
||||||
@ -1149,14 +1151,14 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
var height = imgData.height;
|
var height = imgData.height;
|
||||||
|
|
||||||
var imgSrc = convertImgDataToPng(imgData, this.forceDataSchema);
|
var imgSrc = convertImgDataToPng(imgData, this.forceDataSchema);
|
||||||
var cliprect = document.createElementNS(NS, 'svg:rect');
|
var cliprect = this.svgFactory.createElement('svg:rect');
|
||||||
cliprect.setAttributeNS(null, 'x', '0');
|
cliprect.setAttributeNS(null, 'x', '0');
|
||||||
cliprect.setAttributeNS(null, 'y', '0');
|
cliprect.setAttributeNS(null, 'y', '0');
|
||||||
cliprect.setAttributeNS(null, 'width', pf(width));
|
cliprect.setAttributeNS(null, 'width', pf(width));
|
||||||
cliprect.setAttributeNS(null, 'height', pf(height));
|
cliprect.setAttributeNS(null, 'height', pf(height));
|
||||||
this.current.element = cliprect;
|
this.current.element = cliprect;
|
||||||
this.clip('nonzero');
|
this.clip('nonzero');
|
||||||
var imgEl = document.createElementNS(NS, 'svg:image');
|
var imgEl = this.svgFactory.createElement('svg:image');
|
||||||
imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgSrc);
|
imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgSrc);
|
||||||
imgEl.setAttributeNS(null, 'x', '0');
|
imgEl.setAttributeNS(null, 'x', '0');
|
||||||
imgEl.setAttributeNS(null, 'y', pf(-height));
|
imgEl.setAttributeNS(null, 'y', pf(-height));
|
||||||
@ -1180,10 +1182,10 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
var fillColor = current.fillColor;
|
var fillColor = current.fillColor;
|
||||||
|
|
||||||
current.maskId = 'mask' + maskCount++;
|
current.maskId = 'mask' + maskCount++;
|
||||||
var mask = document.createElementNS(NS, 'svg:mask');
|
var mask = this.svgFactory.createElement('svg:mask');
|
||||||
mask.setAttributeNS(null, 'id', current.maskId);
|
mask.setAttributeNS(null, 'id', current.maskId);
|
||||||
|
|
||||||
var rect = document.createElementNS(NS, 'svg:rect');
|
var rect = this.svgFactory.createElement('svg:rect');
|
||||||
rect.setAttributeNS(null, 'x', '0');
|
rect.setAttributeNS(null, 'x', '0');
|
||||||
rect.setAttributeNS(null, 'y', '0');
|
rect.setAttributeNS(null, 'y', '0');
|
||||||
rect.setAttributeNS(null, 'width', pf(width));
|
rect.setAttributeNS(null, 'width', pf(width));
|
||||||
@ -1208,7 +1210,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
var width = bbox[2] - bbox[0];
|
var width = bbox[2] - bbox[0];
|
||||||
var height = bbox[3] - bbox[1];
|
var height = bbox[3] - bbox[1];
|
||||||
|
|
||||||
var cliprect = document.createElementNS(NS, 'svg:rect');
|
var cliprect = this.svgFactory.createElement('svg:rect');
|
||||||
cliprect.setAttributeNS(null, 'x', bbox[0]);
|
cliprect.setAttributeNS(null, 'x', bbox[0]);
|
||||||
cliprect.setAttributeNS(null, 'y', bbox[1]);
|
cliprect.setAttributeNS(null, 'y', bbox[1]);
|
||||||
cliprect.setAttributeNS(null, 'width', pf(width));
|
cliprect.setAttributeNS(null, 'width', pf(width));
|
||||||
@ -1225,24 +1227,17 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_initialize: function SVGGraphics_initialize(viewport) {
|
_initialize(viewport) {
|
||||||
// Create the SVG element.
|
let svg = this.svgFactory.create(viewport.width, viewport.height);
|
||||||
var svg = document.createElementNS(NS, 'svg:svg');
|
|
||||||
svg.setAttributeNS(null, 'version', '1.1');
|
|
||||||
svg.setAttributeNS(null, 'width', viewport.width + 'px');
|
|
||||||
svg.setAttributeNS(null, 'height', viewport.height + 'px');
|
|
||||||
svg.setAttributeNS(null, 'preserveAspectRatio', 'none');
|
|
||||||
svg.setAttributeNS(null, 'viewBox', '0 0 ' + viewport.width +
|
|
||||||
' ' + viewport.height);
|
|
||||||
|
|
||||||
// Create the definitions element.
|
// Create the definitions element.
|
||||||
var definitions = document.createElementNS(NS, 'svg:defs');
|
let definitions = this.svgFactory.createElement('svg:defs');
|
||||||
svg.appendChild(definitions);
|
svg.appendChild(definitions);
|
||||||
this.defs = definitions;
|
this.defs = definitions;
|
||||||
|
|
||||||
// Create the root group element, which acts a container for all other
|
// Create the root group element, which acts a container for all other
|
||||||
// groups and applies the viewport transform.
|
// groups and applies the viewport transform.
|
||||||
var rootGroup = document.createElementNS(NS, 'svg:g');
|
let rootGroup = this.svgFactory.createElement('svg:g');
|
||||||
rootGroup.setAttributeNS(null, 'transform', pm(viewport.transform));
|
rootGroup.setAttributeNS(null, 'transform', pm(viewport.transform));
|
||||||
svg.appendChild(rootGroup);
|
svg.appendChild(rootGroup);
|
||||||
|
|
||||||
@ -1259,7 +1254,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
*/
|
*/
|
||||||
_ensureClipGroup: function SVGGraphics_ensureClipGroup() {
|
_ensureClipGroup: function SVGGraphics_ensureClipGroup() {
|
||||||
if (!this.current.clipGroup) {
|
if (!this.current.clipGroup) {
|
||||||
var clipGroup = document.createElementNS(NS, 'svg:g');
|
var clipGroup = this.svgFactory.createElement('svg:g');
|
||||||
clipGroup.setAttributeNS(null, 'clip-path',
|
clipGroup.setAttributeNS(null, 'clip-path',
|
||||||
this.current.activeClipUrl);
|
this.current.activeClipUrl);
|
||||||
this.svg.appendChild(clipGroup);
|
this.svg.appendChild(clipGroup);
|
||||||
@ -1273,7 +1268,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
|||||||
*/
|
*/
|
||||||
_ensureTransformGroup: function SVGGraphics_ensureTransformGroup() {
|
_ensureTransformGroup: function SVGGraphics_ensureTransformGroup() {
|
||||||
if (!this.tgrp) {
|
if (!this.tgrp) {
|
||||||
this.tgrp = document.createElementNS(NS, 'svg:g');
|
this.tgrp = this.svgFactory.createElement('svg:g');
|
||||||
this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
|
this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
|
||||||
if (this.current.activeClipUrl) {
|
if (this.current.activeClipUrl) {
|
||||||
this._ensureClipGroup().appendChild(this.tgrp);
|
this._ensureClipGroup().appendChild(this.tgrp);
|
||||||
|
@ -14,11 +14,72 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getFilenameFromUrl, isExternalLinkTargetSet, LinkTarget
|
DOMSVGFactory, getFilenameFromUrl, isExternalLinkTargetSet, LinkTarget
|
||||||
} from '../../src/display/dom_utils';
|
} from '../../src/display/dom_utils';
|
||||||
|
import { isNodeJS } from '../../src/shared/util';
|
||||||
import { PDFJS } from '../../src/display/global';
|
import { PDFJS } from '../../src/display/global';
|
||||||
|
|
||||||
describe('dom_utils', function() {
|
describe('dom_utils', function() {
|
||||||
|
describe('DOMSVGFactory', function() {
|
||||||
|
let svgFactory;
|
||||||
|
|
||||||
|
beforeAll(function (done) {
|
||||||
|
svgFactory = new DOMSVGFactory();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(function () {
|
||||||
|
svgFactory = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('`create` should throw an error if the dimensions are invalid',
|
||||||
|
function() {
|
||||||
|
// Invalid width.
|
||||||
|
expect(function() {
|
||||||
|
return svgFactory.create(-1, 0);
|
||||||
|
}).toThrow(new Error('Invalid SVG dimensions'));
|
||||||
|
|
||||||
|
// Invalid height.
|
||||||
|
expect(function() {
|
||||||
|
return svgFactory.create(0, -1);
|
||||||
|
}).toThrow(new Error('Invalid SVG dimensions'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('`create` should return an SVG element if the dimensions are valid',
|
||||||
|
function() {
|
||||||
|
if (isNodeJS()) {
|
||||||
|
pending('Document is not supported in Node.js.');
|
||||||
|
}
|
||||||
|
|
||||||
|
let svg = svgFactory.create(20, 40);
|
||||||
|
|
||||||
|
expect(svg instanceof SVGSVGElement).toBe(true);
|
||||||
|
expect(svg.getAttribute('version')).toBe('1.1');
|
||||||
|
expect(svg.getAttribute('width')).toBe('20px');
|
||||||
|
expect(svg.getAttribute('height')).toBe('40px');
|
||||||
|
expect(svg.getAttribute('preserveAspectRatio')).toBe('none');
|
||||||
|
expect(svg.getAttribute('viewBox')).toBe('0 0 20 40');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('`createElement` should throw an error if the type is not a string',
|
||||||
|
function() {
|
||||||
|
expect(function() {
|
||||||
|
return svgFactory.createElement(true);
|
||||||
|
}).toThrow(new Error('Invalid SVG element type'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('`createElement` should return an SVG element if the type is valid',
|
||||||
|
function() {
|
||||||
|
if (isNodeJS()) {
|
||||||
|
pending('Document is not supported in Node.js.');
|
||||||
|
}
|
||||||
|
|
||||||
|
let svg = svgFactory.createElement('svg:rect');
|
||||||
|
|
||||||
|
expect(svg instanceof SVGRectElement).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getFilenameFromUrl', function() {
|
describe('getFilenameFromUrl', function() {
|
||||||
it('should get the filename from an absolute URL', function() {
|
it('should get the filename from an absolute URL', function() {
|
||||||
var url = 'http://server.org/filename.pdf';
|
var url = 'http://server.org/filename.pdf';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user