Merge pull request #5585 from timvandermeij/annotation-layer-borderstyle
Annotation border styles
This commit is contained in:
commit
98339f63a8
3
make.js
3
make.js
@ -198,7 +198,8 @@ target.jsdoc = function() {
|
|||||||
var JSDOC_FILES = [
|
var JSDOC_FILES = [
|
||||||
'src/doc_helper.js',
|
'src/doc_helper.js',
|
||||||
'src/display/api.js',
|
'src/display/api.js',
|
||||||
'src/shared/util.js'
|
'src/shared/util.js',
|
||||||
|
'src/core/annotation.js'
|
||||||
];
|
];
|
||||||
|
|
||||||
if (test('-d', JSDOC_DIR)) {
|
if (test('-d', JSDOC_DIR)) {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
/* globals PDFJS, Util, isDict, isName, stringToPDFString, warn, Dict, Stream,
|
/* globals PDFJS, Util, isDict, isName, stringToPDFString, warn, Dict, Stream,
|
||||||
stringToBytes, assert, Promise, isArray, ObjectLoader, OperatorList,
|
stringToBytes, assert, Promise, isArray, ObjectLoader, OperatorList,
|
||||||
isValidUrl, OPS, createPromiseCapability, AnnotationType,
|
isValidUrl, OPS, createPromiseCapability, AnnotationType,
|
||||||
stringToUTF8String */
|
stringToUTF8String, AnnotationBorderStyleType */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -102,45 +102,8 @@ var Annotation = (function AnnotationClosure() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some types of annotations have border style dict which has more
|
this.borderStyle = data.borderStyle = new AnnotationBorderStyle();
|
||||||
// info than the border array
|
this.setBorderStyle(dict);
|
||||||
if (dict.has('BS')) {
|
|
||||||
var borderStyle = dict.get('BS');
|
|
||||||
data.borderWidth = borderStyle.has('W') ? borderStyle.get('W') : 1;
|
|
||||||
} else {
|
|
||||||
var borderArray = dict.get('Border') || [0, 0, 1];
|
|
||||||
data.borderWidth = borderArray[2] || 0;
|
|
||||||
|
|
||||||
// TODO: implement proper support for annotations with line dash patterns.
|
|
||||||
var dashArray = borderArray[3];
|
|
||||||
if (data.borderWidth > 0 && dashArray) {
|
|
||||||
if (!isArray(dashArray)) {
|
|
||||||
// Ignore the border if dashArray is not actually an array,
|
|
||||||
// this is consistent with the behaviour in Adobe Reader.
|
|
||||||
data.borderWidth = 0;
|
|
||||||
} else {
|
|
||||||
var dashArrayLength = dashArray.length;
|
|
||||||
if (dashArrayLength > 0) {
|
|
||||||
// According to the PDF specification: the elements in a dashArray
|
|
||||||
// shall be numbers that are nonnegative and not all equal to zero.
|
|
||||||
var isInvalid = false;
|
|
||||||
var numPositive = 0;
|
|
||||||
for (var i = 0; i < dashArrayLength; i++) {
|
|
||||||
var validNumber = (+dashArray[i] >= 0);
|
|
||||||
if (!validNumber) {
|
|
||||||
isInvalid = true;
|
|
||||||
break;
|
|
||||||
} else if (dashArray[i] > 0) {
|
|
||||||
numPositive++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isInvalid || numPositive === 0) {
|
|
||||||
data.borderWidth = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.appearance = getDefaultAppearance(dict);
|
this.appearance = getDefaultAppearance(dict);
|
||||||
data.hasAppearance = !!this.appearance;
|
data.hasAppearance = !!this.appearance;
|
||||||
@ -148,6 +111,41 @@ var Annotation = (function AnnotationClosure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Annotation.prototype = {
|
Annotation.prototype = {
|
||||||
|
/**
|
||||||
|
* Set the border style (as AnnotationBorderStyle object).
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof Annotation
|
||||||
|
* @param {Dict} borderStyle - The border style dictionary
|
||||||
|
*/
|
||||||
|
setBorderStyle: function Annotation_setBorderStyle(borderStyle) {
|
||||||
|
if (!isDict(borderStyle)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (borderStyle.has('BS')) {
|
||||||
|
var dict = borderStyle.get('BS');
|
||||||
|
var dictType;
|
||||||
|
|
||||||
|
if (!dict.has('Type') || (isName(dictType = dict.get('Type')) &&
|
||||||
|
dictType.name === 'Border')) {
|
||||||
|
this.borderStyle.setWidth(dict.get('W'));
|
||||||
|
this.borderStyle.setStyle(dict.get('S'));
|
||||||
|
this.borderStyle.setDashArray(dict.get('D'));
|
||||||
|
}
|
||||||
|
} else if (borderStyle.has('Border')) {
|
||||||
|
var array = borderStyle.get('Border');
|
||||||
|
if (isArray(array) && array.length >= 3) {
|
||||||
|
this.borderStyle.setHorizontalCornerRadius(array[0]);
|
||||||
|
this.borderStyle.setVerticalCornerRadius(array[1]);
|
||||||
|
this.borderStyle.setWidth(array[2]);
|
||||||
|
this.borderStyle.setStyle('S');
|
||||||
|
|
||||||
|
if (array.length === 4) { // Dash array available
|
||||||
|
this.borderStyle.setDashArray(array[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
getData: function Annotation_getData() {
|
getData: function Annotation_getData() {
|
||||||
return this.data;
|
return this.data;
|
||||||
@ -334,6 +332,144 @@ var Annotation = (function AnnotationClosure() {
|
|||||||
return Annotation;
|
return Annotation;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains all data regarding an annotation's border style.
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
var AnnotationBorderStyle = (function AnnotationBorderStyleClosure() {
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function AnnotationBorderStyle() {
|
||||||
|
this.width = 1;
|
||||||
|
this.style = AnnotationBorderStyleType.SOLID;
|
||||||
|
this.dashArray = [3];
|
||||||
|
this.horizontalCornerRadius = 0;
|
||||||
|
this.verticalCornerRadius = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnnotationBorderStyle.prototype = {
|
||||||
|
/**
|
||||||
|
* Set the width.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof AnnotationBorderStyle
|
||||||
|
* @param {integer} width - The width
|
||||||
|
*/
|
||||||
|
setWidth: function AnnotationBorderStyle_setWidth(width) {
|
||||||
|
if (width === (width | 0)) {
|
||||||
|
this.width = width;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the style.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof AnnotationBorderStyle
|
||||||
|
* @param {Object} style - The style object
|
||||||
|
* @see {@link shared/util.js}
|
||||||
|
*/
|
||||||
|
setStyle: function AnnotationBorderStyle_setStyle(style) {
|
||||||
|
if (!style) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (style.name) {
|
||||||
|
case 'S':
|
||||||
|
this.style = AnnotationBorderStyleType.SOLID;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'D':
|
||||||
|
this.style = AnnotationBorderStyleType.DASHED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'B':
|
||||||
|
this.style = AnnotationBorderStyleType.BEVELED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'I':
|
||||||
|
this.style = AnnotationBorderStyleType.INSET;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'U':
|
||||||
|
this.style = AnnotationBorderStyleType.UNDERLINE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the dash array.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof AnnotationBorderStyle
|
||||||
|
* @param {Array} dashArray - The dash array with at least one element
|
||||||
|
*/
|
||||||
|
setDashArray: function AnnotationBorderStyle_setDashArray(dashArray) {
|
||||||
|
// We validate the dash array, but we do not use it because CSS does not
|
||||||
|
// allow us to change spacing of dashes. For more information, visit
|
||||||
|
// http://www.w3.org/TR/css3-background/#the-border-style.
|
||||||
|
if (isArray(dashArray) && dashArray.length > 0) {
|
||||||
|
// According to the PDF specification: the elements in a dashArray
|
||||||
|
// shall be numbers that are nonnegative and not all equal to zero.
|
||||||
|
var isValid = true;
|
||||||
|
var allZeros = true;
|
||||||
|
for (var i = 0, len = dashArray.length; i < len; i++) {
|
||||||
|
var element = dashArray[i];
|
||||||
|
var validNumber = (+element >= 0);
|
||||||
|
if (!validNumber) {
|
||||||
|
isValid = false;
|
||||||
|
break;
|
||||||
|
} else if (element > 0) {
|
||||||
|
allZeros = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isValid && !allZeros) {
|
||||||
|
this.dashArray = dashArray;
|
||||||
|
} else {
|
||||||
|
this.width = 0; // Adobe behavior when the array is invalid.
|
||||||
|
}
|
||||||
|
} else if (dashArray) {
|
||||||
|
this.width = 0; // Adobe behavior when the array is invalid.
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the horizontal corner radius (from a Border dictionary).
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof AnnotationBorderStyle
|
||||||
|
* @param {integer} radius - The horizontal corner radius
|
||||||
|
*/
|
||||||
|
setHorizontalCornerRadius:
|
||||||
|
function AnnotationBorderStyle_setHorizontalCornerRadius(radius) {
|
||||||
|
if (radius === (radius | 0)) {
|
||||||
|
this.horizontalCornerRadius = radius;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the vertical corner radius (from a Border dictionary).
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof AnnotationBorderStyle
|
||||||
|
* @param {integer} radius - The vertical corner radius
|
||||||
|
*/
|
||||||
|
setVerticalCornerRadius:
|
||||||
|
function AnnotationBorderStyle_setVerticalCornerRadius(radius) {
|
||||||
|
if (radius === (radius | 0)) {
|
||||||
|
this.verticalCornerRadius = radius;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return AnnotationBorderStyle;
|
||||||
|
})();
|
||||||
|
|
||||||
var WidgetAnnotation = (function WidgetAnnotationClosure() {
|
var WidgetAnnotation = (function WidgetAnnotationClosure() {
|
||||||
|
|
||||||
function WidgetAnnotation(params) {
|
function WidgetAnnotation(params) {
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
/* globals PDFJS, Util, AnnotationType */
|
/* globals PDFJS, Util, AnnotationType, AnnotationBorderStyleType, warn,
|
||||||
|
CustomStyle */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -50,19 +51,64 @@ var AnnotationUtils = (function AnnotationUtilsClosure() {
|
|||||||
var width = item.rect[2] - item.rect[0];
|
var width = item.rect[2] - item.rect[0];
|
||||||
var height = item.rect[3] - item.rect[1];
|
var height = item.rect[3] - item.rect[1];
|
||||||
|
|
||||||
var bWidth = item.borderWidth || 0;
|
// Border
|
||||||
if (bWidth) {
|
if (item.borderStyle.width > 0) {
|
||||||
width = width - 2 * bWidth;
|
// Border width
|
||||||
height = height - 2 * bWidth;
|
container.style.borderWidth = item.borderStyle.width + 'px';
|
||||||
cstyle.borderWidth = bWidth + 'px';
|
if (item.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) {
|
||||||
var color = item.color;
|
// Underline styles only have a bottom border, so we do not need
|
||||||
if (drawBorder && color) {
|
// to adjust for all borders. This yields a similar result as
|
||||||
cstyle.borderStyle = 'solid';
|
// Adobe Acrobat/Reader.
|
||||||
cstyle.borderColor = Util.makeCssRgb(Math.round(color[0] * 255),
|
width = width - 2 * item.borderStyle.width;
|
||||||
Math.round(color[1] * 255),
|
height = height - 2 * item.borderStyle.width;
|
||||||
Math.round(color[2] * 255));
|
}
|
||||||
|
|
||||||
|
// Horizontal and vertical border radius
|
||||||
|
var horizontalRadius = item.borderStyle.horizontalCornerRadius;
|
||||||
|
var verticalRadius = item.borderStyle.verticalCornerRadius;
|
||||||
|
if (horizontalRadius > 0 || verticalRadius > 0) {
|
||||||
|
var radius = horizontalRadius + 'px / ' + verticalRadius + 'px';
|
||||||
|
CustomStyle.setProp('borderRadius', container, radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Border style
|
||||||
|
switch (item.borderStyle.style) {
|
||||||
|
case AnnotationBorderStyleType.SOLID:
|
||||||
|
container.style.borderStyle = 'solid';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AnnotationBorderStyleType.DASHED:
|
||||||
|
container.style.borderStyle = 'dashed';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AnnotationBorderStyleType.BEVELED:
|
||||||
|
warn('Unimplemented border style: beveled');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AnnotationBorderStyleType.INSET:
|
||||||
|
warn('Unimplemented border style: inset');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AnnotationBorderStyleType.UNDERLINE:
|
||||||
|
container.style.borderBottomStyle = 'solid';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Border color
|
||||||
|
if (item.color) {
|
||||||
|
container.style.borderColor =
|
||||||
|
Util.makeCssRgb(Math.round(item.color[0] * 255),
|
||||||
|
Math.round(item.color[1] * 255),
|
||||||
|
Math.round(item.color[2] * 255));
|
||||||
|
} else {
|
||||||
|
// Default color is black, but that's not obvious from the spec.
|
||||||
|
container.style.borderColor = 'rgb(0,0,0)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cstyle.width = width + 'px';
|
cstyle.width = width + 'px';
|
||||||
cstyle.height = height + 'px';
|
cstyle.height = height + 'px';
|
||||||
return container;
|
return container;
|
||||||
|
@ -50,6 +50,14 @@ var AnnotationType = {
|
|||||||
LINK: 3
|
LINK: 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var AnnotationBorderStyleType = {
|
||||||
|
SOLID: 1,
|
||||||
|
DASHED: 2,
|
||||||
|
BEVELED: 3,
|
||||||
|
INSET: 4,
|
||||||
|
UNDERLINE: 5
|
||||||
|
};
|
||||||
|
|
||||||
var StreamType = {
|
var StreamType = {
|
||||||
UNKNOWN: 0,
|
UNKNOWN: 0,
|
||||||
FLATE: 1,
|
FLATE: 1,
|
||||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -131,6 +131,7 @@
|
|||||||
!issue5334.pdf
|
!issue5334.pdf
|
||||||
!issue5549.pdf
|
!issue5549.pdf
|
||||||
!issue5475.pdf
|
!issue5475.pdf
|
||||||
|
!annotation-border-styles.pdf
|
||||||
!issue5481.pdf
|
!issue5481.pdf
|
||||||
!issue5567.pdf
|
!issue5567.pdf
|
||||||
!issue5701.pdf
|
!issue5701.pdf
|
||||||
|
BIN
test/pdfs/annotation-border-styles.pdf
Normal file
BIN
test/pdfs/annotation-border-styles.pdf
Normal file
Binary file not shown.
@ -2226,6 +2226,12 @@
|
|||||||
"type": "eq",
|
"type": "eq",
|
||||||
"about": "Free image obtained from www.unsplash.com"
|
"about": "Free image obtained from www.unsplash.com"
|
||||||
},
|
},
|
||||||
|
{ "id": "annotation-border-styles.pdf",
|
||||||
|
"file": "pdfs/annotation-border-styles.pdf",
|
||||||
|
"md5": "22930fc09c7386e1131b14d936e554af",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq"
|
||||||
|
},
|
||||||
{ "id": "issue5481.pdf",
|
{ "id": "issue5481.pdf",
|
||||||
"file": "pdfs/issue5481.pdf",
|
"file": "pdfs/issue5481.pdf",
|
||||||
"md5": "cf00bd25b15b7e23542b48a626585c36",
|
"md5": "cf00bd25b15b7e23542b48a626585c36",
|
||||||
|
84
test/unit/annotation_layer_spec.js
Normal file
84
test/unit/annotation_layer_spec.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||||
|
/* globals expect, it, describe, Dict, AnnotationBorderStyle,
|
||||||
|
AnnotationBorderStyleType */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
describe('Annotation layer', function() {
|
||||||
|
describe('AnnotationBorderStyle', function() {
|
||||||
|
it('should set and get a valid width', function() {
|
||||||
|
var borderStyle = new AnnotationBorderStyle();
|
||||||
|
borderStyle.setWidth(3);
|
||||||
|
|
||||||
|
expect(borderStyle.width).toEqual(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set and get an invalid width', function() {
|
||||||
|
var borderStyle = new AnnotationBorderStyle();
|
||||||
|
borderStyle.setWidth('three');
|
||||||
|
|
||||||
|
expect(borderStyle.width).toEqual(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set and get a valid style', function() {
|
||||||
|
var borderStyle = new AnnotationBorderStyle();
|
||||||
|
var dict = new Dict();
|
||||||
|
dict.name = 'D';
|
||||||
|
borderStyle.setStyle(dict);
|
||||||
|
|
||||||
|
expect(borderStyle.style).toEqual(AnnotationBorderStyleType.DASHED);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set and get an invalid style', function() {
|
||||||
|
var borderStyle = new AnnotationBorderStyle();
|
||||||
|
borderStyle.setStyle('Dashed');
|
||||||
|
|
||||||
|
expect(borderStyle.style).toEqual(AnnotationBorderStyleType.SOLID);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set and get a valid dash array', function() {
|
||||||
|
var borderStyle = new AnnotationBorderStyle();
|
||||||
|
borderStyle.setDashArray([1, 2, 3]);
|
||||||
|
|
||||||
|
expect(borderStyle.dashArray).toEqual([1, 2, 3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set and get an invalid dash array', function() {
|
||||||
|
var borderStyle = new AnnotationBorderStyle();
|
||||||
|
borderStyle.setDashArray([0, 0]);
|
||||||
|
|
||||||
|
expect(borderStyle.dashArray).toEqual([3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set and get a valid horizontal corner radius', function() {
|
||||||
|
var borderStyle = new AnnotationBorderStyle();
|
||||||
|
borderStyle.setHorizontalCornerRadius(3);
|
||||||
|
|
||||||
|
expect(borderStyle.horizontalCornerRadius).toEqual(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set and get an invalid horizontal corner radius',
|
||||||
|
function() {
|
||||||
|
var borderStyle = new AnnotationBorderStyle();
|
||||||
|
borderStyle.setHorizontalCornerRadius('three');
|
||||||
|
|
||||||
|
expect(borderStyle.horizontalCornerRadius).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set and get a valid vertical corner radius', function() {
|
||||||
|
var borderStyle = new AnnotationBorderStyle();
|
||||||
|
borderStyle.setVerticalCornerRadius(3);
|
||||||
|
|
||||||
|
expect(borderStyle.verticalCornerRadius).toEqual(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set and get an invalid horizontal corner radius',
|
||||||
|
function() {
|
||||||
|
var borderStyle = new AnnotationBorderStyle();
|
||||||
|
borderStyle.setVerticalCornerRadius('three');
|
||||||
|
|
||||||
|
expect(borderStyle.verticalCornerRadius).toEqual(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -56,6 +56,7 @@
|
|||||||
<script src="ui_utils_spec.js"></script>
|
<script src="ui_utils_spec.js"></script>
|
||||||
<script src="util_spec.js"></script>
|
<script src="util_spec.js"></script>
|
||||||
<script src="cmap_spec.js"></script>
|
<script src="cmap_spec.js"></script>
|
||||||
|
<script src="annotation_layer_spec.js"></script>
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user