Merge pull request #8228 from timvandermeij/line-annotations

Implement support for line annotations
This commit is contained in:
Tim van der Meij 2017-04-13 00:18:31 +02:00 committed by GitHub
commit 32e01cda96
7 changed files with 139 additions and 24 deletions

View File

@ -115,6 +115,9 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
case 'Popup':
return new PopupAnnotation(parameters);
case 'Line':
return new LineAnnotation(parameters);
case 'Highlight':
return new HighlightAnnotation(parameters);
@ -955,6 +958,8 @@ var PopupAnnotation = (function PopupAnnotationClosure() {
return;
}
var parentSubtype = parentItem.get('Subtype');
this.data.parentType = isName(parentSubtype) ? parentSubtype.name : null;
this.data.parentId = dict.getRaw('Parent').toString();
this.data.title = stringToPDFString(parentItem.get('T') || '');
this.data.contents = stringToPDFString(parentItem.get('Contents') || '');
@ -983,15 +988,28 @@ var PopupAnnotation = (function PopupAnnotationClosure() {
return PopupAnnotation;
})();
var LineAnnotation = (function LineAnnotationClosure() {
function LineAnnotation(parameters) {
Annotation.call(this, parameters);
this.data.annotationType = AnnotationType.LINE;
var dict = parameters.dict;
this.data.lineCoordinates = Util.normalizeRect(dict.getArray('L'));
this._preparePopup(dict);
}
Util.inherit(LineAnnotation, Annotation, {});
return LineAnnotation;
})();
var HighlightAnnotation = (function HighlightAnnotationClosure() {
function HighlightAnnotation(parameters) {
Annotation.call(this, parameters);
this.data.annotationType = AnnotationType.HIGHLIGHT;
this._preparePopup(parameters.dict);
// PDF viewers completely ignore any border styles.
this.data.borderStyle.setWidth(0);
}
Util.inherit(HighlightAnnotation, Annotation, {});
@ -1005,9 +1023,6 @@ var UnderlineAnnotation = (function UnderlineAnnotationClosure() {
this.data.annotationType = AnnotationType.UNDERLINE;
this._preparePopup(parameters.dict);
// PDF viewers completely ignore any border styles.
this.data.borderStyle.setWidth(0);
}
Util.inherit(UnderlineAnnotation, Annotation, {});
@ -1021,9 +1036,6 @@ var SquigglyAnnotation = (function SquigglyAnnotationClosure() {
this.data.annotationType = AnnotationType.SQUIGGLY;
this._preparePopup(parameters.dict);
// PDF viewers completely ignore any border styles.
this.data.borderStyle.setWidth(0);
}
Util.inherit(SquigglyAnnotation, Annotation, {});
@ -1037,9 +1049,6 @@ var StrikeOutAnnotation = (function StrikeOutAnnotationClosure() {
this.data.annotationType = AnnotationType.STRIKEOUT;
this._preparePopup(parameters.dict);
// PDF viewers completely ignore any border styles.
this.data.borderStyle.setWidth(0);
}
Util.inherit(StrikeOutAnnotation, Annotation, {});

View File

@ -93,6 +93,9 @@ AnnotationElementFactory.prototype =
case AnnotationType.POPUP:
return new PopupAnnotationElement(parameters);
case AnnotationType.LINE:
return new LineAnnotationElement(parameters);
case AnnotationType.HIGHLIGHT:
return new HighlightAnnotationElement(parameters);
@ -119,7 +122,7 @@ AnnotationElementFactory.prototype =
* @alias AnnotationElement
*/
var AnnotationElement = (function AnnotationElementClosure() {
function AnnotationElement(parameters, isRenderable) {
function AnnotationElement(parameters, isRenderable, ignoreBorder) {
this.isRenderable = isRenderable || false;
this.data = parameters.data;
this.layer = parameters.layer;
@ -131,7 +134,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
this.renderInteractiveForms = parameters.renderInteractiveForms;
if (isRenderable) {
this.container = this._createContainer();
this.container = this._createContainer(ignoreBorder);
}
}
@ -140,10 +143,12 @@ var AnnotationElement = (function AnnotationElementClosure() {
* Create an empty container for the annotation's HTML element.
*
* @private
* @param {boolean} ignoreBorder
* @memberof AnnotationElement
* @returns {HTMLSectionElement}
*/
_createContainer: function AnnotationElement_createContainer() {
_createContainer:
function AnnotationElement_createContainer(ignoreBorder) {
var data = this.data, page = this.page, viewport = this.viewport;
var container = document.createElement('section');
var width = data.rect[2] - data.rect[0];
@ -165,7 +170,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
CustomStyle.setProp('transformOrigin', container,
-rect[0] + 'px ' + -rect[1] + 'px');
if (data.borderStyle.width > 0) {
if (!ignoreBorder && data.borderStyle.width > 0) {
container.style.borderWidth = data.borderStyle.width + 'px';
if (data.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) {
// Underline styles only have a bottom border, so we do not need
@ -679,6 +684,10 @@ var ChoiceWidgetAnnotationElement = (
* @alias PopupAnnotationElement
*/
var PopupAnnotationElement = (function PopupAnnotationElementClosure() {
// Do not render popup annotations for parent elements with these types as
// they create the popups themselves (because of custom trigger divs).
var IGNORE_TYPES = ['Line'];
function PopupAnnotationElement(parameters) {
var isRenderable = !!(parameters.data.title || parameters.data.contents);
AnnotationElement.call(this, parameters, isRenderable);
@ -695,6 +704,10 @@ var PopupAnnotationElement = (function PopupAnnotationElementClosure() {
render: function PopupAnnotationElement_render() {
this.container.className = 'popupAnnotation';
if (IGNORE_TYPES.indexOf(this.data.parentType) >= 0) {
return this.container;
}
var selector = '[data-annotation-id="' + this.data.parentId + '"]';
var parentElement = this.layer.querySelector(selector);
if (!parentElement) {
@ -864,6 +877,69 @@ var PopupElement = (function PopupElementClosure() {
return PopupElement;
})();
/**
* @class
* @alias LineAnnotationElement
*/
var LineAnnotationElement = (function LineAnnotationElementClosure() {
var SVG_NS = 'http://www.w3.org/2000/svg';
function LineAnnotationElement(parameters) {
var isRenderable = !!(parameters.data.hasPopup ||
parameters.data.title || parameters.data.contents);
AnnotationElement.call(this, parameters, isRenderable,
/* ignoreBorder = */ true);
}
Util.inherit(LineAnnotationElement, AnnotationElement, {
/**
* Render the line annotation's HTML element in the empty container.
*
* @public
* @memberof LineAnnotationElement
* @returns {HTMLSectionElement}
*/
render: function LineAnnotationElement_render() {
this.container.className = 'lineAnnotation';
// Create an invisible line with the same starting and ending coordinates
// that acts as the trigger for the popup. Only the line itself should
// trigger the popup, not the entire container.
var data = this.data;
var width = data.rect[2] - data.rect[0];
var height = data.rect[3] - data.rect[1];
var 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
// the line coordinates to a top left origin for the SVG element.
var line = document.createElementNS(SVG_NS, 'svg:line');
line.setAttributeNS(null, 'x1', data.rect[2] - data.lineCoordinates[0]);
line.setAttributeNS(null, 'y1', data.rect[3] - data.lineCoordinates[1]);
line.setAttributeNS(null, 'x2', data.rect[2] - data.lineCoordinates[2]);
line.setAttributeNS(null, 'y2', data.rect[3] - data.lineCoordinates[3]);
line.setAttributeNS(null, 'stroke-width', data.borderStyle.width);
line.setAttributeNS(null, 'stroke', 'transparent');
svg.appendChild(line);
this.container.append(svg);
// Create the popup ourselves so that we can bind it to the line instead
// of to the entire container (which is the default).
this._createPopup(this.container, line, this.data);
return this.container;
}
});
return LineAnnotationElement;
})();
/**
* @class
* @alias HighlightAnnotationElement
@ -873,7 +949,8 @@ var HighlightAnnotationElement = (
function HighlightAnnotationElement(parameters) {
var isRenderable = !!(parameters.data.hasPopup ||
parameters.data.title || parameters.data.contents);
AnnotationElement.call(this, parameters, isRenderable);
AnnotationElement.call(this, parameters, isRenderable,
/* ignoreBorder = */ true);
}
Util.inherit(HighlightAnnotationElement, AnnotationElement, {
@ -890,7 +967,6 @@ var HighlightAnnotationElement = (
if (!this.data.hasPopup) {
this._createPopup(this.container, null, this.data);
}
return this.container;
}
});
@ -907,7 +983,8 @@ var UnderlineAnnotationElement = (
function UnderlineAnnotationElement(parameters) {
var isRenderable = !!(parameters.data.hasPopup ||
parameters.data.title || parameters.data.contents);
AnnotationElement.call(this, parameters, isRenderable);
AnnotationElement.call(this, parameters, isRenderable,
/* ignoreBorder = */ true);
}
Util.inherit(UnderlineAnnotationElement, AnnotationElement, {
@ -924,7 +1001,6 @@ var UnderlineAnnotationElement = (
if (!this.data.hasPopup) {
this._createPopup(this.container, null, this.data);
}
return this.container;
}
});
@ -940,7 +1016,8 @@ var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {
function SquigglyAnnotationElement(parameters) {
var isRenderable = !!(parameters.data.hasPopup ||
parameters.data.title || parameters.data.contents);
AnnotationElement.call(this, parameters, isRenderable);
AnnotationElement.call(this, parameters, isRenderable,
/* ignoreBorder = */ true);
}
Util.inherit(SquigglyAnnotationElement, AnnotationElement, {
@ -957,7 +1034,6 @@ var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {
if (!this.data.hasPopup) {
this._createPopup(this.container, null, this.data);
}
return this.container;
}
});
@ -974,7 +1050,8 @@ var StrikeOutAnnotationElement = (
function StrikeOutAnnotationElement(parameters) {
var isRenderable = !!(parameters.data.hasPopup ||
parameters.data.title || parameters.data.contents);
AnnotationElement.call(this, parameters, isRenderable);
AnnotationElement.call(this, parameters, isRenderable,
/* ignoreBorder = */ true);
}
Util.inherit(StrikeOutAnnotationElement, AnnotationElement, {
@ -991,7 +1068,6 @@ var StrikeOutAnnotationElement = (
if (!this.data.hasPopup) {
this._createPopup(this.container, null, this.data);
}
return this.container;
}
});

View File

@ -269,6 +269,7 @@
!annotation-strikeout.pdf
!annotation-squiggly.pdf
!annotation-highlight.pdf
!annotation-line.pdf
!annotation-fileattachment.pdf
!annotation-text-widget.pdf
!annotation-choice-widget.pdf

BIN
test/pdfs/annotation-line.pdf Executable file

Binary file not shown.

View File

@ -3370,6 +3370,13 @@
"type": "eq",
"annotations": true
},
{ "id": "annotation-line",
"file": "pdfs/annotation-line.pdf",
"md5": "fde60608be2748f10fb6522cba425ca1",
"rounds": 1,
"type": "eq",
"annotations": true
},
{ "id": "annotation-fileattachment",
"file": "pdfs/annotation-fileattachment.pdf",
"md5": "d20ecee4b53c81b2dd44c8715a1b4a83",

View File

@ -1287,6 +1287,27 @@ describe('annotation', function() {
});
});
describe('LineAnnotation', function() {
it('should set the line coordinates', function() {
var lineDict = new Dict();
lineDict.set('Type', Name.get('Annot'));
lineDict.set('Subtype', Name.get('Line'));
lineDict.set('L', [1, 2, 3, 4]);
var lineRef = new Ref(122, 0);
var xref = new XRefMock([
{ ref: lineRef, data: lineDict, }
]);
var annotation = annotationFactory.create(xref, lineRef, pdfManagerMock,
idFactoryMock);
var data = annotation.data;
expect(data.annotationType).toEqual(AnnotationType.LINE);
expect(data.lineCoordinates).toEqual([1, 2, 3, 4]);
});
});
describe('FileAttachmentAnnotation', function() {
it('should correctly parse a file attachment', function() {
var fileStream = new StringStream(

View File

@ -143,6 +143,7 @@
.annotationLayer .underlineAnnotation,
.annotationLayer .squigglyAnnotation,
.annotationLayer .strikeoutAnnotation,
.annotationLayer .lineAnnotation svg line,
.annotationLayer .fileAttachmentAnnotation {
cursor: pointer;
}