Skip to content

Commit

Permalink
Merge pull request mozilla#8228 from timvandermeij/line-annotations
Browse files Browse the repository at this point in the history
Implement support for line annotations
  • Loading branch information
timvandermeij authored Apr 12, 2017
2 parents 7bf5471 + 02bc751 commit 8649bb2
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 24 deletions.
33 changes: 21 additions & 12 deletions src/core/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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') || '');
Expand Down Expand Up @@ -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, {});
Expand All @@ -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, {});
Expand All @@ -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, {});
Expand All @@ -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, {});
Expand Down
100 changes: 88 additions & 12 deletions src/display/annotation_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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;
Expand All @@ -131,7 +134,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
this.renderInteractiveForms = parameters.renderInteractiveForms;

if (isRenderable) {
this.container = this._createContainer();
this.container = this._createContainer(ignoreBorder);
}
}

Expand All @@ -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];
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand Down Expand Up @@ -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
Expand All @@ -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, {
Expand All @@ -890,7 +967,6 @@ var HighlightAnnotationElement = (
if (!this.data.hasPopup) {
this._createPopup(this.container, null, this.data);
}

return this.container;
}
});
Expand All @@ -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, {
Expand All @@ -924,7 +1001,6 @@ var UnderlineAnnotationElement = (
if (!this.data.hasPopup) {
this._createPopup(this.container, null, this.data);
}

return this.container;
}
});
Expand All @@ -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, {
Expand All @@ -957,7 +1034,6 @@ var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {
if (!this.data.hasPopup) {
this._createPopup(this.container, null, this.data);
}

return this.container;
}
});
Expand All @@ -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, {
Expand All @@ -991,7 +1068,6 @@ var StrikeOutAnnotationElement = (
if (!this.data.hasPopup) {
this._createPopup(this.container, null, this.data);
}

return this.container;
}
});
Expand Down
1 change: 1 addition & 0 deletions test/pdfs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Binary file added test/pdfs/annotation-line.pdf
Binary file not shown.
7 changes: 7 additions & 0 deletions test/test_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
21 changes: 21 additions & 0 deletions test/unit/annotation_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
1 change: 1 addition & 0 deletions web/annotation_layer_builder.css
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
.annotationLayer .underlineAnnotation,
.annotationLayer .squigglyAnnotation,
.annotationLayer .strikeoutAnnotation,
.annotationLayer .lineAnnotation svg line,
.annotationLayer .fileAttachmentAnnotation {
cursor: pointer;
}

0 comments on commit 8649bb2

Please sign in to comment.