Merge pull request #8691 from timvandermeij/square-circle-annotations
Implement support for square and circle annotations
This commit is contained in:
commit
320779e6ed
@ -81,6 +81,12 @@ class AnnotationFactory {
|
|||||||
case 'Line':
|
case 'Line':
|
||||||
return new LineAnnotation(parameters);
|
return new LineAnnotation(parameters);
|
||||||
|
|
||||||
|
case 'Square':
|
||||||
|
return new SquareAnnotation(parameters);
|
||||||
|
|
||||||
|
case 'Circle':
|
||||||
|
return new CircleAnnotation(parameters);
|
||||||
|
|
||||||
case 'Highlight':
|
case 'Highlight':
|
||||||
return new HighlightAnnotation(parameters);
|
return new HighlightAnnotation(parameters);
|
||||||
|
|
||||||
@ -886,6 +892,24 @@ class LineAnnotation extends Annotation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SquareAnnotation extends Annotation {
|
||||||
|
constructor(parameters) {
|
||||||
|
super(parameters);
|
||||||
|
|
||||||
|
this.data.annotationType = AnnotationType.SQUARE;
|
||||||
|
this._preparePopup(parameters.dict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CircleAnnotation extends Annotation {
|
||||||
|
constructor(parameters) {
|
||||||
|
super(parameters);
|
||||||
|
|
||||||
|
this.data.annotationType = AnnotationType.CIRCLE;
|
||||||
|
this._preparePopup(parameters.dict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class HighlightAnnotation extends Annotation {
|
class HighlightAnnotation extends Annotation {
|
||||||
constructor(parameters) {
|
constructor(parameters) {
|
||||||
super(parameters);
|
super(parameters);
|
||||||
|
@ -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 {
|
||||||
@ -73,6 +74,12 @@ class AnnotationElementFactory {
|
|||||||
case AnnotationType.LINE:
|
case AnnotationType.LINE:
|
||||||
return new LineAnnotationElement(parameters);
|
return new LineAnnotationElement(parameters);
|
||||||
|
|
||||||
|
case AnnotationType.SQUARE:
|
||||||
|
return new SquareAnnotationElement(parameters);
|
||||||
|
|
||||||
|
case AnnotationType.CIRCLE:
|
||||||
|
return new CircleAnnotationElement(parameters);
|
||||||
|
|
||||||
case AnnotationType.HIGHLIGHT:
|
case AnnotationType.HIGHLIGHT:
|
||||||
return new HighlightAnnotationElement(parameters);
|
return new HighlightAnnotationElement(parameters);
|
||||||
|
|
||||||
@ -105,6 +112,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);
|
||||||
@ -590,7 +598,7 @@ class PopupAnnotationElement extends AnnotationElement {
|
|||||||
render() {
|
render() {
|
||||||
// Do not render popup annotations for parent elements with these types as
|
// Do not render popup annotations for parent elements with these types as
|
||||||
// they create the popups themselves (because of custom trigger divs).
|
// they create the popups themselves (because of custom trigger divs).
|
||||||
const IGNORE_TYPES = ['Line'];
|
const IGNORE_TYPES = ['Line', 'Square', 'Circle'];
|
||||||
|
|
||||||
this.container.className = 'popupAnnotation';
|
this.container.className = 'popupAnnotation';
|
||||||
|
|
||||||
@ -771,8 +779,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
|
||||||
@ -781,30 +787,122 @@ 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SquareAnnotationElement extends AnnotationElement {
|
||||||
|
constructor(parameters) {
|
||||||
|
let isRenderable = !!(parameters.data.hasPopup ||
|
||||||
|
parameters.data.title || parameters.data.contents);
|
||||||
|
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the square annotation's HTML element in the empty container.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof SquareAnnotationElement
|
||||||
|
* @returns {HTMLSectionElement}
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
this.container.className = 'squareAnnotation';
|
||||||
|
|
||||||
|
// Create an invisible square with the same rectangle that acts as the
|
||||||
|
// trigger for the popup. Only the square itself should trigger the
|
||||||
|
// popup, not the entire container.
|
||||||
|
let data = this.data;
|
||||||
|
let width = data.rect[2] - data.rect[0];
|
||||||
|
let height = data.rect[3] - data.rect[1];
|
||||||
|
let svg = this.svgFactory.create(width, height);
|
||||||
|
|
||||||
|
// The browser draws half of the borders inside the square and half of
|
||||||
|
// the borders outside the square by default. This behavior cannot be
|
||||||
|
// changed programmatically, so correct for that here.
|
||||||
|
let borderWidth = data.borderStyle.width;
|
||||||
|
let square = this.svgFactory.createElement('svg:rect');
|
||||||
|
square.setAttribute('x', borderWidth / 2);
|
||||||
|
square.setAttribute('y', borderWidth / 2);
|
||||||
|
square.setAttribute('width', width - borderWidth);
|
||||||
|
square.setAttribute('height', height - borderWidth);
|
||||||
|
square.setAttribute('stroke-width', borderWidth);
|
||||||
|
square.setAttribute('stroke', 'transparent');
|
||||||
|
square.setAttribute('fill', 'none');
|
||||||
|
|
||||||
|
svg.appendChild(square);
|
||||||
|
this.container.append(svg);
|
||||||
|
|
||||||
|
// Create the popup ourselves so that we can bind it to the square instead
|
||||||
|
// of to the entire container (which is the default).
|
||||||
|
this._createPopup(this.container, square, data);
|
||||||
|
|
||||||
|
return this.container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CircleAnnotationElement extends AnnotationElement {
|
||||||
|
constructor(parameters) {
|
||||||
|
let isRenderable = !!(parameters.data.hasPopup ||
|
||||||
|
parameters.data.title || parameters.data.contents);
|
||||||
|
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the circle annotation's HTML element in the empty container.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof CircleAnnotationElement
|
||||||
|
* @returns {HTMLSectionElement}
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
this.container.className = 'circleAnnotation';
|
||||||
|
|
||||||
|
// Create an invisible circle with the same ellipse that acts as the
|
||||||
|
// trigger for the popup. Only the circle itself should trigger the
|
||||||
|
// popup, not the entire container.
|
||||||
|
let data = this.data;
|
||||||
|
let width = data.rect[2] - data.rect[0];
|
||||||
|
let height = data.rect[3] - data.rect[1];
|
||||||
|
let svg = this.svgFactory.create(width, height);
|
||||||
|
|
||||||
|
// The browser draws half of the borders inside the circle and half of
|
||||||
|
// the borders outside the circle by default. This behavior cannot be
|
||||||
|
// changed programmatically, so correct for that here.
|
||||||
|
let borderWidth = data.borderStyle.width;
|
||||||
|
let circle = this.svgFactory.createElement('svg:ellipse');
|
||||||
|
circle.setAttribute('cx', width / 2);
|
||||||
|
circle.setAttribute('cy', height / 2);
|
||||||
|
circle.setAttribute('rx', (width / 2) - (borderWidth / 2));
|
||||||
|
circle.setAttribute('ry', (height / 2) - (borderWidth / 2));
|
||||||
|
circle.setAttribute('stroke-width', borderWidth);
|
||||||
|
circle.setAttribute('stroke', 'transparent');
|
||||||
|
circle.setAttribute('fill', 'none');
|
||||||
|
|
||||||
|
svg.appendChild(circle);
|
||||||
|
this.container.append(svg);
|
||||||
|
|
||||||
|
// Create the popup ourselves so that we can bind it to the circle instead
|
||||||
|
// of to the entire container (which is the default).
|
||||||
|
this._createPopup(this.container, circle, data);
|
||||||
|
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
@ -995,6 +1093,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);
|
||||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -284,6 +284,7 @@
|
|||||||
!annotation-squiggly.pdf
|
!annotation-squiggly.pdf
|
||||||
!annotation-highlight.pdf
|
!annotation-highlight.pdf
|
||||||
!annotation-line.pdf
|
!annotation-line.pdf
|
||||||
|
!annotation-square-circle.pdf
|
||||||
!annotation-fileattachment.pdf
|
!annotation-fileattachment.pdf
|
||||||
!annotation-text-widget.pdf
|
!annotation-text-widget.pdf
|
||||||
!annotation-choice-widget.pdf
|
!annotation-choice-widget.pdf
|
||||||
|
BIN
test/pdfs/annotation-square-circle.pdf
Executable file
BIN
test/pdfs/annotation-square-circle.pdf
Executable file
Binary file not shown.
@ -3560,6 +3560,13 @@
|
|||||||
"type": "eq",
|
"type": "eq",
|
||||||
"annotations": true
|
"annotations": true
|
||||||
},
|
},
|
||||||
|
{ "id": "annotation-square-circle",
|
||||||
|
"file": "pdfs/annotation-square-circle.pdf",
|
||||||
|
"md5": "cfd3c302f68d61e1d55ed9c7896046c3",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq",
|
||||||
|
"annotations": true
|
||||||
|
},
|
||||||
{ "id": "annotation-fileattachment",
|
{ "id": "annotation-fileattachment",
|
||||||
"file": "pdfs/annotation-fileattachment.pdf",
|
"file": "pdfs/annotation-fileattachment.pdf",
|
||||||
"md5": "d20ecee4b53c81b2dd44c8715a1b4a83",
|
"md5": "d20ecee4b53c81b2dd44c8715a1b4a83",
|
||||||
|
@ -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';
|
||||||
|
@ -181,6 +181,8 @@
|
|||||||
.annotationLayer .squigglyAnnotation,
|
.annotationLayer .squigglyAnnotation,
|
||||||
.annotationLayer .strikeoutAnnotation,
|
.annotationLayer .strikeoutAnnotation,
|
||||||
.annotationLayer .lineAnnotation svg line,
|
.annotationLayer .lineAnnotation svg line,
|
||||||
|
.annotationLayer .squareAnnotation svg rect,
|
||||||
|
.annotationLayer .circleAnnotation svg ellipse,
|
||||||
.annotationLayer .fileAttachmentAnnotation {
|
.annotationLayer .fileAttachmentAnnotation {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user