Merge pull request #15713 from Snuffleupagus/annotation-no-appearance-cleanup

Reduce duplication when creating a fallback appearance for `MarkupAnnotation`s
This commit is contained in:
Jonas Jenwald 2022-11-20 17:12:41 +01:00 committed by GitHub
commit 748be3f702
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -362,6 +362,10 @@ function getRgbColor(color, defaultColor = new Uint8ClampedArray(3)) {
} }
} }
function getPdfColorArray(color) {
return Array.from(color, c => c / 255);
}
function getQuadPoints(dict, rect) { function getQuadPoints(dict, rect) {
if (!dict.has("QuadPoints")) { if (!dict.has("QuadPoints")) {
return null; return null;
@ -459,7 +463,7 @@ function getTransformMatrix(rect, bbox, matrix) {
class Annotation { class Annotation {
constructor(params) { constructor(params) {
const dict = params.dict; const { dict, xref } = params;
this.setTitle(dict.get("T")); this.setTitle(dict.get("T"));
this.setContents(dict.get("Contents")); this.setContents(dict.get("Contents"));
@ -514,11 +518,7 @@ class Annotation {
} }
} }
this.data.actions = collectActions( this.data.actions = collectActions(xref, dict, AnnotationActionEventType);
params.xref,
dict,
AnnotationActionEventType
);
this.data.fieldName = this._constructFieldName(dict); this.data.fieldName = this._constructFieldName(dict);
this.data.pageIndex = params.pageIndex; this.data.pageIndex = params.pageIndex;
} }
@ -1304,10 +1304,10 @@ class AnnotationBorderStyle {
} }
class MarkupAnnotation extends Annotation { class MarkupAnnotation extends Annotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
const dict = parameters.dict; const { dict } = params;
if (dict.has("IRT")) { if (dict.has("IRT")) {
const rawIRT = dict.getRaw("IRT"); const rawIRT = dict.getRaw("IRT");
@ -1515,7 +1515,7 @@ class WidgetAnnotation extends Annotation {
constructor(params) { constructor(params) {
super(params); super(params);
const dict = params.dict; const { dict, xref } = params;
const data = this.data; const data = this.data;
this.ref = params.ref; this.ref = params.ref;
this._needAppearances = params.needAppearances; this._needAppearances = params.needAppearances;
@ -1525,11 +1525,7 @@ class WidgetAnnotation extends Annotation {
data.fieldName = this._constructFieldName(dict); data.fieldName = this._constructFieldName(dict);
} }
if (data.actions === undefined) { if (data.actions === undefined) {
data.actions = collectActions( data.actions = collectActions(xref, dict, AnnotationActionEventType);
params.xref,
dict,
AnnotationActionEventType
);
} }
let fieldValue = getInheritableProperty({ let fieldValue = getInheritableProperty({
@ -1584,7 +1580,7 @@ class WidgetAnnotation extends Annotation {
acroFormResources, acroFormResources,
appearanceResources, appearanceResources,
mergedResources: Dict.merge({ mergedResources: Dict.merge({
xref: params.xref, xref,
dictArray: [localResources, appearanceResources, acroFormResources], dictArray: [localResources, appearanceResources, acroFormResources],
mergeSubDicts: true, mergeSubDicts: true,
}), }),
@ -1793,16 +1789,10 @@ class WidgetAnnotation extends Annotation {
mk.set("R", rotation); mk.set("R", rotation);
} }
if (this.borderColor) { if (this.borderColor) {
mk.set( mk.set("BC", getPdfColorArray(this.borderColor));
"BC",
Array.from(this.borderColor, c => c / 255)
);
} }
if (this.backgroundColor) { if (this.backgroundColor) {
mk.set( mk.set("BG", getPdfColorArray(this.backgroundColor));
"BG",
Array.from(this.backgroundColor, c => c / 255)
);
} }
return mk.size > 0 ? mk : null; return mk.size > 0 ? mk : null;
} }
@ -3147,6 +3137,7 @@ class ChoiceWidgetAnnotation extends WidgetAnnotation {
constructor(params) { constructor(params) {
super(params); super(params);
const { dict, xref } = params;
// Determine the options. The options array may consist of strings or // Determine the options. The options array may consist of strings or
// arrays. If the array consists of arrays, then the first element of // arrays. If the array consists of arrays, then the first element of
// each array is the export value and the second element of each array is // each array is the export value and the second element of each array is
@ -3158,9 +3149,8 @@ class ChoiceWidgetAnnotation extends WidgetAnnotation {
// inherit the options from a parent annotation (issue 8094). // inherit the options from a parent annotation (issue 8094).
this.data.options = []; this.data.options = [];
const options = getInheritableProperty({ dict: params.dict, key: "Opt" }); const options = getInheritableProperty({ dict, key: "Opt" });
if (Array.isArray(options)) { if (Array.isArray(options)) {
const xref = params.xref;
for (let i = 0, ii = options.length; i < ii; i++) { for (let i = 0, ii = options.length; i < ii; i++) {
const option = xref.fetchIfRef(options[i]); const option = xref.fetchIfRef(options[i]);
const isOptionArray = Array.isArray(option); const isOptionArray = Array.isArray(option);
@ -3389,12 +3379,12 @@ class SignatureWidgetAnnotation extends WidgetAnnotation {
} }
class TextAnnotation extends MarkupAnnotation { class TextAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
const DEFAULT_ICON_SIZE = 22; // px const DEFAULT_ICON_SIZE = 22; // px
super(parameters); super(params);
const dict = parameters.dict; const { dict } = params;
this.data.annotationType = AnnotationType.TEXT; this.data.annotationType = AnnotationType.TEXT;
if (this.data.hasAppearance) { if (this.data.hasAppearance) {
@ -3439,12 +3429,13 @@ class LinkAnnotation extends Annotation {
} }
class PopupAnnotation extends Annotation { class PopupAnnotation extends Annotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
const { dict } = params;
this.data.annotationType = AnnotationType.POPUP; this.data.annotationType = AnnotationType.POPUP;
let parentItem = parameters.dict.get("Parent"); let parentItem = dict.get("Parent");
if (!parentItem) { if (!parentItem) {
warn("Popup annotation has a missing or invalid parent annotation."); warn("Popup annotation has a missing or invalid parent annotation.");
return; return;
@ -3453,7 +3444,7 @@ class PopupAnnotation extends Annotation {
const parentSubtype = parentItem.get("Subtype"); const parentSubtype = parentItem.get("Subtype");
this.data.parentType = this.data.parentType =
parentSubtype instanceof Name ? parentSubtype.name : null; parentSubtype instanceof Name ? parentSubtype.name : null;
const rawParent = parameters.dict.getRaw("Parent"); const rawParent = dict.getRaw("Parent");
this.data.parentId = rawParent instanceof Ref ? rawParent.toString() : null; this.data.parentId = rawParent instanceof Ref ? rawParent.toString() : null;
const parentRect = parentItem.getArray("Rect"); const parentRect = parentItem.getArray("Rect");
@ -3508,16 +3499,15 @@ class PopupAnnotation extends Annotation {
} }
class FreeTextAnnotation extends MarkupAnnotation { class FreeTextAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
const { xref } = params;
this.data.annotationType = AnnotationType.FREETEXT; this.data.annotationType = AnnotationType.FREETEXT;
this.setDefaultAppearance(parameters); this.setDefaultAppearance(params);
if (!this.appearance && this._isOffscreenCanvasSupported) { if (!this.appearance && this._isOffscreenCanvasSupported) {
const fakeUnicodeFont = new FakeUnicodeFont( const fakeUnicodeFont = new FakeUnicodeFont(xref, "sans-serif");
parameters.xref,
"sans-serif"
);
const fontData = this.data.defaultAppearanceData; const fontData = this.data.defaultAppearanceData;
this.appearance = fakeUnicodeFont.createAppearance( this.appearance = fakeUnicodeFont.createAppearance(
this._contents.str, this._contents.str,
@ -3687,10 +3677,10 @@ class FreeTextAnnotation extends MarkupAnnotation {
} }
class LineAnnotation extends MarkupAnnotation { class LineAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
const { dict } = parameters; const { dict, xref } = params;
this.data.annotationType = AnnotationType.LINE; this.data.annotationType = AnnotationType.LINE;
const lineCoordinates = dict.getArray("L"); const lineCoordinates = dict.getArray("L");
@ -3701,21 +3691,13 @@ class LineAnnotation extends MarkupAnnotation {
if (!this.appearance) { if (!this.appearance) {
// The default stroke color is black. // The default stroke color is black.
const strokeColor = this.color const strokeColor = this.color ? getPdfColorArray(this.color) : [0, 0, 0];
? Array.from(this.color, c => c / 255)
: [0, 0, 0];
const strokeAlpha = dict.get("CA"); const strokeAlpha = dict.get("CA");
const interiorColor = getRgbColor(dict.getArray("IC"), null);
// The default fill color is transparent. Setting the fill colour is // The default fill color is transparent. Setting the fill colour is
// necessary if/when we want to add support for non-default line endings. // necessary if/when we want to add support for non-default line endings.
let fillColor = null, const fillColor = interiorColor ? getPdfColorArray(interiorColor) : null;
interiorColor = dict.getArray("IC");
if (interiorColor) {
interiorColor = getRgbColor(interiorColor, null);
fillColor = interiorColor
? Array.from(interiorColor, c => c / 255)
: null;
}
const fillAlpha = fillColor ? strokeAlpha : null; const fillAlpha = fillColor ? strokeAlpha : null;
const borderWidth = this.borderStyle.width || 1, const borderWidth = this.borderStyle.width || 1,
@ -3734,7 +3716,7 @@ class LineAnnotation extends MarkupAnnotation {
} }
this._setDefaultAppearance({ this._setDefaultAppearance({
xref: parameters.xref, xref,
extra: `${borderWidth} w`, extra: `${borderWidth} w`,
strokeColor, strokeColor,
fillColor, fillColor,
@ -3759,27 +3741,20 @@ class LineAnnotation extends MarkupAnnotation {
} }
class SquareAnnotation extends MarkupAnnotation { class SquareAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
const { dict, xref } = params;
this.data.annotationType = AnnotationType.SQUARE; this.data.annotationType = AnnotationType.SQUARE;
if (!this.appearance) { if (!this.appearance) {
// The default stroke color is black. // The default stroke color is black.
const strokeColor = this.color const strokeColor = this.color ? getPdfColorArray(this.color) : [0, 0, 0];
? Array.from(this.color, c => c / 255) const strokeAlpha = dict.get("CA");
: [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA");
const interiorColor = getRgbColor(dict.getArray("IC"), null);
// The default fill color is transparent. // The default fill color is transparent.
let fillColor = null, const fillColor = interiorColor ? getPdfColorArray(interiorColor) : null;
interiorColor = parameters.dict.getArray("IC");
if (interiorColor) {
interiorColor = getRgbColor(interiorColor, null);
fillColor = interiorColor
? Array.from(interiorColor, c => c / 255)
: null;
}
const fillAlpha = fillColor ? strokeAlpha : null; const fillAlpha = fillColor ? strokeAlpha : null;
if (this.borderStyle.width === 0 && !fillColor) { if (this.borderStyle.width === 0 && !fillColor) {
@ -3788,7 +3763,7 @@ class SquareAnnotation extends MarkupAnnotation {
} }
this._setDefaultAppearance({ this._setDefaultAppearance({
xref: parameters.xref, xref,
extra: `${this.borderStyle.width} w`, extra: `${this.borderStyle.width} w`,
strokeColor, strokeColor,
fillColor, fillColor,
@ -3813,27 +3788,20 @@ class SquareAnnotation extends MarkupAnnotation {
} }
class CircleAnnotation extends MarkupAnnotation { class CircleAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
const { dict, xref } = params;
this.data.annotationType = AnnotationType.CIRCLE; this.data.annotationType = AnnotationType.CIRCLE;
if (!this.appearance) { if (!this.appearance) {
// The default stroke color is black. // The default stroke color is black.
const strokeColor = this.color const strokeColor = this.color ? getPdfColorArray(this.color) : [0, 0, 0];
? Array.from(this.color, c => c / 255) const strokeAlpha = dict.get("CA");
: [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA");
const interiorColor = getRgbColor(dict.getArray("IC"), null);
// The default fill color is transparent. // The default fill color is transparent.
let fillColor = null; const fillColor = interiorColor ? getPdfColorArray(interiorColor) : null;
let interiorColor = parameters.dict.getArray("IC");
if (interiorColor) {
interiorColor = getRgbColor(interiorColor, null);
fillColor = interiorColor
? Array.from(interiorColor, c => c / 255)
: null;
}
const fillAlpha = fillColor ? strokeAlpha : null; const fillAlpha = fillColor ? strokeAlpha : null;
if (this.borderStyle.width === 0 && !fillColor) { if (this.borderStyle.width === 0 && !fillColor) {
@ -3847,7 +3815,7 @@ class CircleAnnotation extends MarkupAnnotation {
const controlPointsDistance = (4 / 3) * Math.tan(Math.PI / (2 * 4)); const controlPointsDistance = (4 / 3) * Math.tan(Math.PI / (2 * 4));
this._setDefaultAppearance({ this._setDefaultAppearance({
xref: parameters.xref, xref,
extra: `${this.borderStyle.width} w`, extra: `${this.borderStyle.width} w`,
strokeColor, strokeColor,
fillColor, fillColor,
@ -3884,10 +3852,10 @@ class CircleAnnotation extends MarkupAnnotation {
} }
class PolylineAnnotation extends MarkupAnnotation { class PolylineAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
const { dict } = parameters; const { dict, xref } = params;
this.data.annotationType = AnnotationType.POLYLINE; this.data.annotationType = AnnotationType.POLYLINE;
this.data.vertices = []; this.data.vertices = [];
@ -3913,9 +3881,7 @@ class PolylineAnnotation extends MarkupAnnotation {
if (!this.appearance) { if (!this.appearance) {
// The default stroke color is black. // The default stroke color is black.
const strokeColor = this.color const strokeColor = this.color ? getPdfColorArray(this.color) : [0, 0, 0];
? Array.from(this.color, c => c / 255)
: [0, 0, 0];
const strokeAlpha = dict.get("CA"); const strokeAlpha = dict.get("CA");
const borderWidth = this.borderStyle.width || 1, const borderWidth = this.borderStyle.width || 1,
@ -3935,7 +3901,7 @@ class PolylineAnnotation extends MarkupAnnotation {
} }
this._setDefaultAppearance({ this._setDefaultAppearance({
xref: parameters.xref, xref,
extra: `${borderWidth} w`, extra: `${borderWidth} w`,
strokeColor, strokeColor,
strokeAlpha, strokeAlpha,
@ -3955,34 +3921,34 @@ class PolylineAnnotation extends MarkupAnnotation {
} }
class PolygonAnnotation extends PolylineAnnotation { class PolygonAnnotation extends PolylineAnnotation {
constructor(parameters) { constructor(params) {
// Polygons are specific forms of polylines, so reuse their logic. // Polygons are specific forms of polylines, so reuse their logic.
super(parameters); super(params);
this.data.annotationType = AnnotationType.POLYGON; this.data.annotationType = AnnotationType.POLYGON;
} }
} }
class CaretAnnotation extends MarkupAnnotation { class CaretAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
this.data.annotationType = AnnotationType.CARET; this.data.annotationType = AnnotationType.CARET;
} }
} }
class InkAnnotation extends MarkupAnnotation { class InkAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
const { dict, xref } = params;
this.data.annotationType = AnnotationType.INK; this.data.annotationType = AnnotationType.INK;
this.data.inkLists = []; this.data.inkLists = [];
const rawInkLists = parameters.dict.getArray("InkList"); const rawInkLists = dict.getArray("InkList");
if (!Array.isArray(rawInkLists)) { if (!Array.isArray(rawInkLists)) {
return; return;
} }
const xref = parameters.xref;
for (let i = 0, ii = rawInkLists.length; i < ii; ++i) { for (let i = 0, ii = rawInkLists.length; i < ii; ++i) {
// The raw ink lists array contains arrays of numbers representing // The raw ink lists array contains arrays of numbers representing
// the alternating horizontal and vertical coordinates, respectively, // the alternating horizontal and vertical coordinates, respectively,
@ -3999,10 +3965,8 @@ class InkAnnotation extends MarkupAnnotation {
if (!this.appearance) { if (!this.appearance) {
// The default stroke color is black. // The default stroke color is black.
const strokeColor = this.color const strokeColor = this.color ? getPdfColorArray(this.color) : [0, 0, 0];
? Array.from(this.color, c => c / 255) const strokeAlpha = dict.get("CA");
: [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA");
const borderWidth = this.borderStyle.width || 1, const borderWidth = this.borderStyle.width || 1,
borderAdjust = 2 * borderWidth; borderAdjust = 2 * borderWidth;
@ -4023,7 +3987,7 @@ class InkAnnotation extends MarkupAnnotation {
} }
this._setDefaultAppearance({ this._setDefaultAppearance({
xref: parameters.xref, xref,
extra: `${borderWidth} w`, extra: `${borderWidth} w`,
strokeColor, strokeColor,
strokeAlpha, strokeAlpha,
@ -4141,14 +4105,13 @@ class InkAnnotation extends MarkupAnnotation {
} }
class HighlightAnnotation extends MarkupAnnotation { class HighlightAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
const { dict, xref } = params;
this.data.annotationType = AnnotationType.HIGHLIGHT; this.data.annotationType = AnnotationType.HIGHLIGHT;
const quadPoints = (this.data.quadPoints = getQuadPoints(
parameters.dict, const quadPoints = (this.data.quadPoints = getQuadPoints(dict, null));
null
));
if (quadPoints) { if (quadPoints) {
const resources = const resources =
this.appearance && this.appearance.dict.get("Resources"); this.appearance && this.appearance.dict.get("Resources");
@ -4162,13 +4125,11 @@ class HighlightAnnotation extends MarkupAnnotation {
warn("HighlightAnnotation - ignoring built-in appearance stream."); warn("HighlightAnnotation - ignoring built-in appearance stream.");
} }
// Default color is yellow in Acrobat Reader // Default color is yellow in Acrobat Reader
const fillColor = this.color const fillColor = this.color ? getPdfColorArray(this.color) : [1, 1, 0];
? Array.from(this.color, c => c / 255) const fillAlpha = dict.get("CA");
: [1, 1, 0];
const fillAlpha = parameters.dict.get("CA");
this._setDefaultAppearance({ this._setDefaultAppearance({
xref: parameters.xref, xref,
fillColor, fillColor,
blendMode: "Multiply", blendMode: "Multiply",
fillAlpha, fillAlpha,
@ -4191,24 +4152,23 @@ class HighlightAnnotation extends MarkupAnnotation {
} }
class UnderlineAnnotation extends MarkupAnnotation { class UnderlineAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
const { dict, xref } = params;
this.data.annotationType = AnnotationType.UNDERLINE; this.data.annotationType = AnnotationType.UNDERLINE;
const quadPoints = (this.data.quadPoints = getQuadPoints(
parameters.dict, const quadPoints = (this.data.quadPoints = getQuadPoints(dict, null));
null
));
if (quadPoints) { if (quadPoints) {
if (!this.appearance) { if (!this.appearance) {
// Default color is black // Default color is black
const strokeColor = this.color const strokeColor = this.color
? Array.from(this.color, c => c / 255) ? getPdfColorArray(this.color)
: [0, 0, 0]; : [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA"); const strokeAlpha = dict.get("CA");
this._setDefaultAppearance({ this._setDefaultAppearance({
xref: parameters.xref, xref,
extra: "[] 0 d 1 w", extra: "[] 0 d 1 w",
strokeColor, strokeColor,
strokeAlpha, strokeAlpha,
@ -4229,25 +4189,23 @@ class UnderlineAnnotation extends MarkupAnnotation {
} }
class SquigglyAnnotation extends MarkupAnnotation { class SquigglyAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
const { dict, xref } = params;
this.data.annotationType = AnnotationType.SQUIGGLY; this.data.annotationType = AnnotationType.SQUIGGLY;
const quadPoints = (this.data.quadPoints = getQuadPoints( const quadPoints = (this.data.quadPoints = getQuadPoints(dict, null));
parameters.dict,
null
));
if (quadPoints) { if (quadPoints) {
if (!this.appearance) { if (!this.appearance) {
// Default color is black // Default color is black
const strokeColor = this.color const strokeColor = this.color
? Array.from(this.color, c => c / 255) ? getPdfColorArray(this.color)
: [0, 0, 0]; : [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA"); const strokeAlpha = dict.get("CA");
this._setDefaultAppearance({ this._setDefaultAppearance({
xref: parameters.xref, xref,
extra: "[] 0 d 1 w", extra: "[] 0 d 1 w",
strokeColor, strokeColor,
strokeAlpha, strokeAlpha,
@ -4275,25 +4233,23 @@ class SquigglyAnnotation extends MarkupAnnotation {
} }
class StrikeOutAnnotation extends MarkupAnnotation { class StrikeOutAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
const { dict, xref } = params;
this.data.annotationType = AnnotationType.STRIKEOUT; this.data.annotationType = AnnotationType.STRIKEOUT;
const quadPoints = (this.data.quadPoints = getQuadPoints( const quadPoints = (this.data.quadPoints = getQuadPoints(dict, null));
parameters.dict,
null
));
if (quadPoints) { if (quadPoints) {
if (!this.appearance) { if (!this.appearance) {
// Default color is black // Default color is black
const strokeColor = this.color const strokeColor = this.color
? Array.from(this.color, c => c / 255) ? getPdfColorArray(this.color)
: [0, 0, 0]; : [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA"); const strokeAlpha = dict.get("CA");
this._setDefaultAppearance({ this._setDefaultAppearance({
xref: parameters.xref, xref,
extra: "[] 0 d 1 w", extra: "[] 0 d 1 w",
strokeColor, strokeColor,
strokeAlpha, strokeAlpha,
@ -4316,18 +4272,18 @@ class StrikeOutAnnotation extends MarkupAnnotation {
} }
class StampAnnotation extends MarkupAnnotation { class StampAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
this.data.annotationType = AnnotationType.STAMP; this.data.annotationType = AnnotationType.STAMP;
} }
} }
class FileAttachmentAnnotation extends MarkupAnnotation { class FileAttachmentAnnotation extends MarkupAnnotation {
constructor(parameters) { constructor(params) {
super(parameters); super(params);
const file = new FileSpec(parameters.dict.get("FS"), parameters.xref); const file = new FileSpec(params.dict.get("FS"), params.xref);
this.data.annotationType = AnnotationType.FILEATTACHMENT; this.data.annotationType = AnnotationType.FILEATTACHMENT;
this.data.file = file.serializable; this.data.file = file.serializable;