Merge pull request #6780 from timvandermeij/annotation-regression-tests
Implement annotation layer regression testing
This commit is contained in:
commit
9f23e115e0
73
test/annotation_layer_test.css
Normal file
73
test/annotation_layer_test.css
Normal file
@ -0,0 +1,73 @@
|
||||
/* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Used for annotation layer tests */
|
||||
|
||||
.annotationLayer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.annotationLayer > section {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.annotationLayer .annotLink > a {
|
||||
position: absolute;
|
||||
font-size: 1em;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.2;
|
||||
background: #ff0;
|
||||
box-shadow: 0px 2px 10px #ff0;
|
||||
}
|
||||
|
||||
.annotationLayer .annotText > img {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.annotationLayer .annotTextContentWrapper {
|
||||
position: absolute;
|
||||
width: 20em;
|
||||
}
|
||||
|
||||
.annotationLayer .annotTextContent {
|
||||
z-index: 200;
|
||||
float: left;
|
||||
max-width: 20em;
|
||||
background-color: #FFFF99;
|
||||
box-shadow: 0px 2px 5px #333;
|
||||
border-radius: 2px;
|
||||
padding: 0.6em;
|
||||
display: block !important;
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
.annotationLayer .annotTextContent > h1 {
|
||||
font-size: 1em;
|
||||
border-bottom: 1px solid #000000;
|
||||
margin: 0;
|
||||
padding: 0 0 0.2em 0;
|
||||
}
|
||||
|
||||
.annotationLayer .annotTextContent > p {
|
||||
margin: 0;
|
||||
padding: 0.2em 0 0 0;
|
||||
}
|
169
test/driver.js
169
test/driver.js
@ -19,6 +19,29 @@
|
||||
var WAITING_TIME = 100; // ms
|
||||
var PDF_TO_CSS_UNITS = 96.0 / 72.0;
|
||||
|
||||
/**
|
||||
* @class
|
||||
*/
|
||||
var LinkServiceMock = (function LinkServiceMockClosure() {
|
||||
function LinkServiceMock() {}
|
||||
|
||||
LinkServiceMock.prototype = {
|
||||
navigateTo: function (dest) {},
|
||||
|
||||
getDestinationHash: function (dest) {
|
||||
return '#';
|
||||
},
|
||||
|
||||
getAnchorUrl: function (hash) {
|
||||
return '#';
|
||||
},
|
||||
|
||||
executeNamedAction: function (action) {}
|
||||
};
|
||||
|
||||
return LinkServiceMock;
|
||||
})();
|
||||
|
||||
/**
|
||||
* @class
|
||||
*/
|
||||
@ -89,6 +112,115 @@ var rasterizeTextLayer = (function rasterizeTextLayerClosure() {
|
||||
return rasterizeTextLayer;
|
||||
})();
|
||||
|
||||
/**
|
||||
* @class
|
||||
*/
|
||||
var rasterizeAnnotationLayer = (function rasterizeAnnotationLayerClosure() {
|
||||
var SVG_NS = 'http://www.w3.org/2000/svg';
|
||||
|
||||
var annotationLayerStylePromise = null;
|
||||
function getAnnotationLayerStyle() {
|
||||
if (annotationLayerStylePromise) {
|
||||
return annotationLayerStylePromise;
|
||||
}
|
||||
annotationLayerStylePromise = new Promise(function (resolve) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', './annotation_layer_test.css');
|
||||
xhr.onload = function () {
|
||||
resolve(xhr.responseText);
|
||||
};
|
||||
xhr.send(null);
|
||||
});
|
||||
return annotationLayerStylePromise;
|
||||
}
|
||||
|
||||
function inlineAnnotationImages(images) {
|
||||
var imagePromises = [];
|
||||
for (var i = 0, ii = images.length; i < ii; i++) {
|
||||
var imagePromise = new Promise(function(resolve) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.responseType = 'blob';
|
||||
xhr.onload = function() {
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function() {
|
||||
resolve(reader.result);
|
||||
};
|
||||
reader.readAsDataURL(xhr.response);
|
||||
};
|
||||
xhr.onerror = function() {
|
||||
resolve('');
|
||||
};
|
||||
xhr.open('GET', images[i].src);
|
||||
xhr.send();
|
||||
});
|
||||
imagePromises.push(imagePromise);
|
||||
}
|
||||
return imagePromises;
|
||||
}
|
||||
|
||||
function rasterizeAnnotationLayer(ctx, viewport, annotations, page) {
|
||||
return new Promise(function (resolve) {
|
||||
// Building SVG with size of the viewport.
|
||||
var svg = document.createElementNS(SVG_NS, 'svg:svg');
|
||||
svg.setAttribute('width', viewport.width + 'px');
|
||||
svg.setAttribute('height', viewport.height + 'px');
|
||||
|
||||
// Adding element to host our HTML (style + annotation layer div).
|
||||
var foreignObject = document.createElementNS(SVG_NS, 'svg:foreignObject');
|
||||
foreignObject.setAttribute('x', '0');
|
||||
foreignObject.setAttribute('y', '0');
|
||||
foreignObject.setAttribute('width', viewport.width + 'px');
|
||||
foreignObject.setAttribute('height', viewport.height + 'px');
|
||||
var style = document.createElement('style');
|
||||
var stylePromise = getAnnotationLayerStyle();
|
||||
foreignObject.appendChild(style);
|
||||
var div = document.createElement('div');
|
||||
div.className = 'annotationLayer';
|
||||
|
||||
// Rendering annotation layer as HTML.
|
||||
stylePromise.then(function (styles) {
|
||||
style.textContent = styles;
|
||||
|
||||
var annotation_viewport = viewport.clone({ dontFlip: true });
|
||||
var parameters = {
|
||||
viewport: annotation_viewport,
|
||||
div: div,
|
||||
annotations: annotations,
|
||||
page: page,
|
||||
linkService: new LinkServiceMock()
|
||||
};
|
||||
PDFJS.AnnotationLayer.render(parameters);
|
||||
|
||||
// Inline SVG images from text annotations.
|
||||
var images = div.getElementsByTagName('img');
|
||||
var imagePromises = inlineAnnotationImages(images);
|
||||
var converted = Promise.all(imagePromises).then(function(data) {
|
||||
for (var i = 0, ii = data.length; i < ii; i++) {
|
||||
images[i].src = data[i];
|
||||
}
|
||||
});
|
||||
|
||||
foreignObject.appendChild(div);
|
||||
svg.appendChild(foreignObject);
|
||||
|
||||
// We need to have UTF-8 encoded XML.
|
||||
converted.then(function() {
|
||||
var svg_xml = unescape(encodeURIComponent(
|
||||
(new XMLSerializer()).serializeToString(svg)));
|
||||
var img = new Image();
|
||||
img.src = 'data:image/svg+xml;base64,' + btoa(svg_xml);
|
||||
img.onload = function () {
|
||||
ctx.drawImage(img, 0, 0);
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return rasterizeAnnotationLayer;
|
||||
})();
|
||||
|
||||
/**
|
||||
* @typedef {Object} DriverOptions
|
||||
* @property {HTMLSpanElement} inflight - Field displaying the number of
|
||||
@ -113,6 +245,7 @@ var Driver = (function DriverClosure() {
|
||||
PDFJS.cMapPacked = true;
|
||||
PDFJS.cMapUrl = '../external/bcmaps/';
|
||||
PDFJS.enableStats = true;
|
||||
PDFJS.imageResourcesPath = '/web/images/';
|
||||
|
||||
// Set the passed options
|
||||
this.inflight = options.inflight;
|
||||
@ -320,7 +453,7 @@ var Driver = (function DriverClosure() {
|
||||
self.canvas.height = viewport.height;
|
||||
self._clearCanvas();
|
||||
|
||||
var textLayerCanvas;
|
||||
var textLayerCanvas, annotationLayerCanvas;
|
||||
var initPromise;
|
||||
if (task.type === 'text') {
|
||||
// Using a dummy canvas for PDF context drawing operations
|
||||
@ -343,8 +476,36 @@ var Driver = (function DriverClosure() {
|
||||
});
|
||||
} else {
|
||||
textLayerCanvas = null;
|
||||
initPromise = Promise.resolve();
|
||||
|
||||
// Render the annotation layer if necessary.
|
||||
if (task.annotations) {
|
||||
// Create a dummy canvas for the drawing operations.
|
||||
annotationLayerCanvas = self.annotationLayerCanvas;
|
||||
if (!annotationLayerCanvas) {
|
||||
annotationLayerCanvas = document.createElement('canvas');
|
||||
self.annotationLayerCanvas = annotationLayerCanvas;
|
||||
}
|
||||
annotationLayerCanvas.width = viewport.width;
|
||||
annotationLayerCanvas.height = viewport.height;
|
||||
var annotationLayerContext =
|
||||
annotationLayerCanvas.getContext('2d');
|
||||
annotationLayerContext.clearRect(0, 0,
|
||||
annotationLayerCanvas.width, annotationLayerCanvas.height);
|
||||
|
||||
// The annotation builder will draw its content on the canvas.
|
||||
initPromise =
|
||||
page.getAnnotations({ intent: 'display' }).then(
|
||||
function(annotations) {
|
||||
return rasterizeAnnotationLayer(annotationLayerContext,
|
||||
viewport, annotations,
|
||||
page);
|
||||
});
|
||||
} else {
|
||||
annotationLayerCanvas = null;
|
||||
initPromise = Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
var renderContext = {
|
||||
canvasContext: ctx,
|
||||
viewport: viewport
|
||||
@ -359,6 +520,10 @@ var Driver = (function DriverClosure() {
|
||||
ctx.restore();
|
||||
ctx.drawImage(textLayerCanvas, 0, 0);
|
||||
}
|
||||
// If we have annotation layer, compose it on top of the page.
|
||||
if (annotationLayerCanvas) {
|
||||
ctx.drawImage(annotationLayerCanvas, 0, 0);
|
||||
}
|
||||
page.cleanup();
|
||||
task.stats = page.stats;
|
||||
page.stats = new pdfjsSharedUtil.StatTimer();
|
||||
|
@ -1600,7 +1600,8 @@
|
||||
"rounds": 1,
|
||||
"lastPage": 1,
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
"type": "eq",
|
||||
"annotations": true
|
||||
},
|
||||
{ "id": "issue1002",
|
||||
"file": "pdfs/issue1002.pdf",
|
||||
@ -2052,6 +2053,7 @@
|
||||
"md5": "56321ea830be9c4f8437ca17ac535b2d",
|
||||
"rounds": 1,
|
||||
"type": "eq",
|
||||
"annotations": true,
|
||||
"about": "Text widget annotation witout appearance streams."
|
||||
},
|
||||
{ "id": "gesamt",
|
||||
@ -2585,7 +2587,8 @@
|
||||
"file": "pdfs/annotation-border-styles.pdf",
|
||||
"md5": "22930fc09c7386e1131b14d936e554af",
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
"type": "eq",
|
||||
"annotations": true
|
||||
},
|
||||
{ "id": "issue5481.pdf",
|
||||
"file": "pdfs/issue5481.pdf",
|
||||
|
Loading…
x
Reference in New Issue
Block a user