Merge pull request #16110 from calixteman/norotate

[Annotation] Don't rotate an annotation when it has the NoRotate flag
This commit is contained in:
calixteman 2023-03-06 19:17:44 +01:00 committed by GitHub
commit e11371c75f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 105 additions and 36 deletions

View File

@ -486,6 +486,7 @@ class Annotation {
rect: this.rectangle, rect: this.rectangle,
subtype: params.subtype, subtype: params.subtype,
hasOwnCanvas: false, hasOwnCanvas: false,
noRotate: !!(this.flags & AnnotationFlag.NOROTATE),
}; };
if (params.collectFields) { if (params.collectFields) {
@ -3415,6 +3416,7 @@ class SignatureWidgetAnnotation extends WidgetAnnotation {
// non-serializable and will thus cause errors when sending annotations // non-serializable and will thus cause errors when sending annotations
// to the main-thread (issue 10347). // to the main-thread (issue 10347).
this.data.fieldValue = null; this.data.fieldValue = null;
this.data.hasOwnCanvas = this.data.noRotate;
} }
getFieldObject() { getFieldObject() {
@ -3433,6 +3435,10 @@ class TextAnnotation extends MarkupAnnotation {
super(params); super(params);
// No rotation for Text (see 12.5.6.4).
this.data.noRotate = true;
this.data.hasOwnCanvas = this.data.noRotate;
const { dict } = params; const { dict } = params;
this.data.annotationType = AnnotationType.TEXT; this.data.annotationType = AnnotationType.TEXT;
@ -3551,6 +3557,8 @@ class FreeTextAnnotation extends MarkupAnnotation {
constructor(params) { constructor(params) {
super(params); super(params);
this.data.hasOwnCanvas = this.data.noRotate;
const { xref } = params; const { xref } = params;
this.data.annotationType = AnnotationType.FREETEXT; this.data.annotationType = AnnotationType.FREETEXT;
this.setDefaultAppearance(params); this.setDefaultAppearance(params);
@ -3731,6 +3739,7 @@ class LineAnnotation extends MarkupAnnotation {
const { dict, xref } = params; const { dict, xref } = params;
this.data.annotationType = AnnotationType.LINE; this.data.annotationType = AnnotationType.LINE;
this.data.hasOwnCanvas = this.data.noRotate;
const lineCoordinates = dict.getArray("L"); const lineCoordinates = dict.getArray("L");
this.data.lineCoordinates = Util.normalizeRect(lineCoordinates); this.data.lineCoordinates = Util.normalizeRect(lineCoordinates);
@ -3795,6 +3804,7 @@ class SquareAnnotation extends MarkupAnnotation {
const { dict, xref } = params; const { dict, xref } = params;
this.data.annotationType = AnnotationType.SQUARE; this.data.annotationType = AnnotationType.SQUARE;
this.data.hasOwnCanvas = this.data.noRotate;
if (!this.appearance) { if (!this.appearance) {
// The default stroke color is black. // The default stroke color is black.
@ -3906,6 +3916,7 @@ class PolylineAnnotation extends MarkupAnnotation {
const { dict, xref } = params; const { dict, xref } = params;
this.data.annotationType = AnnotationType.POLYLINE; this.data.annotationType = AnnotationType.POLYLINE;
this.data.hasOwnCanvas = this.data.noRotate;
this.data.vertices = []; this.data.vertices = [];
if (!(this instanceof PolygonAnnotation)) { if (!(this instanceof PolygonAnnotation)) {
@ -3990,6 +4001,8 @@ class InkAnnotation extends MarkupAnnotation {
constructor(params) { constructor(params) {
super(params); super(params);
this.data.hasOwnCanvas = this.data.noRotate;
const { dict, xref } = params; const { dict, xref } = params;
this.data.annotationType = AnnotationType.INK; this.data.annotationType = AnnotationType.INK;
this.data.inkLists = []; this.data.inkLists = [];
@ -4325,6 +4338,7 @@ class StampAnnotation extends MarkupAnnotation {
super(params); super(params);
this.data.annotationType = AnnotationType.STAMP; this.data.annotationType = AnnotationType.STAMP;
this.data.hasOwnCanvas = this.data.noRotate;
} }
} }
@ -4336,6 +4350,7 @@ class FileAttachmentAnnotation extends MarkupAnnotation {
const file = new FileSpec(dict.get("FS"), xref); const file = new FileSpec(dict.get("FS"), xref);
this.data.annotationType = AnnotationType.FILEATTACHMENT; this.data.annotationType = AnnotationType.FILEATTACHMENT;
this.data.hasOwnCanvas = this.data.noRotate;
this.data.file = file.serializable; this.data.file = file.serializable;
const name = dict.get("Name"); const name = dict.get("Name");

View File

@ -199,6 +199,10 @@ class AnnotationElement {
const container = document.createElement("section"); const container = document.createElement("section");
container.setAttribute("data-annotation-id", data.id); container.setAttribute("data-annotation-id", data.id);
if (data.noRotate) {
container.classList.add("norotate");
}
const { pageWidth, pageHeight, pageX, pageY } = viewport.rawDims; const { pageWidth, pageHeight, pageX, pageY } = viewport.rawDims;
const { width, height } = getRectDims(data.rect); const { width, height } = getRectDims(data.rect);
@ -454,7 +458,7 @@ class AnnotationElement {
// If no trigger element is specified, create it. // If no trigger element is specified, create it.
if (!trigger) { if (!trigger) {
trigger = document.createElement("div"); trigger = document.createElement("div");
trigger.className = "popupTriggerArea"; trigger.classList.add("popupTriggerArea");
container.append(trigger); container.append(trigger);
} }
@ -493,7 +497,7 @@ class AnnotationElement {
} }
for (const quadrilateral of this.quadrilaterals) { for (const quadrilateral of this.quadrilaterals) {
quadrilateral.className = className; quadrilateral.classList.add(className);
} }
return this.quadrilaterals; return this.quadrilaterals;
} }
@ -622,7 +626,7 @@ class LinkAnnotationElement extends AnnotationElement {
); );
} }
this.container.className = "linkAnnotation"; this.container.classList.add("linkAnnotation");
if (isBound) { if (isBound) {
this.container.append(link); this.container.append(link);
} }
@ -857,7 +861,7 @@ class TextAnnotationElement extends AnnotationElement {
} }
render() { render() {
this.container.className = "textAnnotation"; this.container.classList.add("textAnnotation");
const image = document.createElement("img"); const image = document.createElement("img");
image.src = image.src =
@ -1029,7 +1033,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
const storage = this.annotationStorage; const storage = this.annotationStorage;
const id = this.data.id; const id = this.data.id;
this.container.className = "textWidgetAnnotation"; this.container.classList.add("textWidgetAnnotation");
let element = null; let element = null;
if (this.renderForms) { if (this.renderForms) {
@ -1357,7 +1361,7 @@ class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
storage.setValue(id, { value }); storage.setValue(id, { value });
} }
this.container.className = "buttonWidgetAnnotation checkBox"; this.container.classList.add("buttonWidgetAnnotation", "checkBox");
const element = document.createElement("input"); const element = document.createElement("input");
GetElementsByNameSet.add(element); GetElementsByNameSet.add(element);
@ -1431,7 +1435,7 @@ class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
} }
render() { render() {
this.container.className = "buttonWidgetAnnotation radioButton"; this.container.classList.add("buttonWidgetAnnotation", "radioButton");
const storage = this.annotationStorage; const storage = this.annotationStorage;
const data = this.data; const data = this.data;
const id = data.id; const id = data.id;
@ -1525,7 +1529,7 @@ class PushButtonWidgetAnnotationElement extends LinkAnnotationElement {
// equal to that of a link annotation, but may have more functionality, such // equal to that of a link annotation, but may have more functionality, such
// as performing actions on form fields (resetting, submitting, et cetera). // as performing actions on form fields (resetting, submitting, et cetera).
const container = super.render(); const container = super.render();
container.className = "buttonWidgetAnnotation pushButton"; container.classList.add("buttonWidgetAnnotation", "pushButton");
if (this.data.alternativeText) { if (this.data.alternativeText) {
container.title = this.data.alternativeText; container.title = this.data.alternativeText;
@ -1550,7 +1554,7 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
} }
render() { render() {
this.container.className = "choiceWidgetAnnotation"; this.container.classList.add("choiceWidgetAnnotation");
const storage = this.annotationStorage; const storage = this.annotationStorage;
const id = this.data.id; const id = this.data.id;
@ -1810,7 +1814,7 @@ class PopupAnnotationElement extends AnnotationElement {
} }
render() { render() {
this.container.className = "popupAnnotation"; this.container.classList.add("popupAnnotation");
const parentElements = this.layer.querySelectorAll( const parentElements = this.layer.querySelectorAll(
`[data-annotation-id="${this.data.parentId}"]` `[data-annotation-id="${this.data.parentId}"]`
@ -1870,7 +1874,7 @@ class PopupElement {
const BACKGROUND_ENLIGHT = 0.7; const BACKGROUND_ENLIGHT = 0.7;
const wrapper = document.createElement("div"); const wrapper = document.createElement("div");
wrapper.className = "popupWrapper"; wrapper.classList.add("popupWrapper");
// For Popup annotations we hide the entire section because it contains // For Popup annotations we hide the entire section because it contains
// only the popup. However, for Text annotations without a separate Popup // only the popup. However, for Text annotations without a separate Popup
@ -1880,7 +1884,7 @@ class PopupElement {
this.hideElement.hidden = true; this.hideElement.hidden = true;
const popup = document.createElement("div"); const popup = document.createElement("div");
popup.className = "popup"; popup.classList.add("popup");
const color = this.color; const color = this.color;
if (color) { if (color) {
@ -1902,7 +1906,7 @@ class PopupElement {
const dateObject = PDFDateString.toDateObject(this.modificationDate); const dateObject = PDFDateString.toDateObject(this.modificationDate);
if (dateObject) { if (dateObject) {
const modificationDate = document.createElement("span"); const modificationDate = document.createElement("span");
modificationDate.className = "popupDate"; modificationDate.classList.add("popupDate");
modificationDate.textContent = "{{date}}, {{time}}"; modificationDate.textContent = "{{date}}, {{time}}";
modificationDate.dataset.l10nId = "annotation_date_string"; modificationDate.dataset.l10nId = "annotation_date_string";
modificationDate.dataset.l10nArgs = JSON.stringify({ modificationDate.dataset.l10nArgs = JSON.stringify({
@ -1921,7 +1925,7 @@ class PopupElement {
intent: "richText", intent: "richText",
div: popup, div: popup,
}); });
popup.lastChild.className = "richText popupContent"; popup.lastChild.classList.add("richText", "popupContent");
} else { } else {
const contents = this._formatContents(this.contentsObj); const contents = this._formatContents(this.contentsObj);
popup.append(contents); popup.append(contents);
@ -1953,7 +1957,7 @@ class PopupElement {
*/ */
_formatContents({ str, dir }) { _formatContents({ str, dir }) {
const p = document.createElement("p"); const p = document.createElement("p");
p.className = "popupContent"; p.classList.add("popupContent");
p.dir = dir; p.dir = dir;
const lines = str.split(/(?:\r\n?|\n)/); const lines = str.split(/(?:\r\n?|\n)/);
for (let i = 0, ii = lines.length; i < ii; ++i) { for (let i = 0, ii = lines.length; i < ii; ++i) {
@ -2030,11 +2034,11 @@ class FreeTextAnnotationElement extends AnnotationElement {
} }
render() { render() {
this.container.className = "freeTextAnnotation"; this.container.classList.add("freeTextAnnotation");
if (this.textContent) { if (this.textContent) {
const content = document.createElement("div"); const content = document.createElement("div");
content.className = "annotationTextContent"; content.classList.add("annotationTextContent");
content.setAttribute("role", "comment"); content.setAttribute("role", "comment");
for (const line of this.textContent) { for (const line of this.textContent) {
const lineSpan = document.createElement("span"); const lineSpan = document.createElement("span");
@ -2063,7 +2067,7 @@ class LineAnnotationElement extends AnnotationElement {
} }
render() { render() {
this.container.className = "lineAnnotation"; this.container.classList.add("lineAnnotation");
// Create an invisible line with the same starting and ending coordinates // Create an invisible line with the same starting and ending coordinates
// that acts as the trigger for the popup. Only the line itself should // that acts as the trigger for the popup. Only the line itself should
@ -2112,7 +2116,7 @@ class SquareAnnotationElement extends AnnotationElement {
} }
render() { render() {
this.container.className = "squareAnnotation"; this.container.classList.add("squareAnnotation");
// Create an invisible square with the same rectangle that acts as the // Create an invisible square with the same rectangle that acts as the
// trigger for the popup. Only the square itself should trigger the // trigger for the popup. Only the square itself should trigger the
@ -2163,7 +2167,7 @@ class CircleAnnotationElement extends AnnotationElement {
} }
render() { render() {
this.container.className = "circleAnnotation"; this.container.classList.add("circleAnnotation");
// Create an invisible circle with the same ellipse that acts as the // Create an invisible circle with the same ellipse that acts as the
// trigger for the popup. Only the circle itself should trigger the // trigger for the popup. Only the circle itself should trigger the
@ -2217,7 +2221,7 @@ class PolylineAnnotationElement extends AnnotationElement {
} }
render() { render() {
this.container.className = this.containerClassName; this.container.classList.add(this.containerClassName);
// Create an invisible polyline with the same points that acts as the // Create an invisible polyline with the same points that acts as the
// trigger for the popup. Only the polyline itself should trigger the // trigger for the popup. Only the polyline itself should trigger the
@ -2283,7 +2287,7 @@ class CaretAnnotationElement extends AnnotationElement {
} }
render() { render() {
this.container.className = "caretAnnotation"; this.container.classList.add("caretAnnotation");
if (!this.data.hasPopup) { if (!this.data.hasPopup) {
this._createPopup(null, this.data); this._createPopup(null, this.data);
@ -2310,7 +2314,7 @@ class InkAnnotationElement extends AnnotationElement {
} }
render() { render() {
this.container.className = this.containerClassName; this.container.classList.add(this.containerClassName);
// Create an invisible polyline with the same points that acts as the // Create an invisible polyline with the same points that acts as the
// trigger for the popup. // trigger for the popup.
@ -2379,7 +2383,7 @@ class HighlightAnnotationElement extends AnnotationElement {
return this._renderQuadrilaterals("highlightAnnotation"); return this._renderQuadrilaterals("highlightAnnotation");
} }
this.container.className = "highlightAnnotation"; this.container.classList.add("highlightAnnotation");
return this.container; return this.container;
} }
} }
@ -2408,7 +2412,7 @@ class UnderlineAnnotationElement extends AnnotationElement {
return this._renderQuadrilaterals("underlineAnnotation"); return this._renderQuadrilaterals("underlineAnnotation");
} }
this.container.className = "underlineAnnotation"; this.container.classList.add("underlineAnnotation");
return this.container; return this.container;
} }
} }
@ -2437,7 +2441,7 @@ class SquigglyAnnotationElement extends AnnotationElement {
return this._renderQuadrilaterals("squigglyAnnotation"); return this._renderQuadrilaterals("squigglyAnnotation");
} }
this.container.className = "squigglyAnnotation"; this.container.classList.add("squigglyAnnotation");
return this.container; return this.container;
} }
} }
@ -2466,7 +2470,7 @@ class StrikeOutAnnotationElement extends AnnotationElement {
return this._renderQuadrilaterals("strikeoutAnnotation"); return this._renderQuadrilaterals("strikeoutAnnotation");
} }
this.container.className = "strikeoutAnnotation"; this.container.classList.add("strikeoutAnnotation");
return this.container; return this.container;
} }
} }
@ -2483,7 +2487,7 @@ class StampAnnotationElement extends AnnotationElement {
} }
render() { render() {
this.container.className = "stampAnnotation"; this.container.classList.add("stampAnnotation");
if (!this.data.hasPopup) { if (!this.data.hasPopup) {
this._createPopup(null, this.data); this._createPopup(null, this.data);
@ -2508,7 +2512,7 @@ class FileAttachmentAnnotationElement extends AnnotationElement {
} }
render() { render() {
this.container.className = "fileAttachmentAnnotation"; this.container.classList.add("fileAttachmentAnnotation");
let trigger; let trigger;
if (this.data.hasAppearance) { if (this.data.hasAppearance) {
@ -2524,7 +2528,7 @@ class FileAttachmentAnnotationElement extends AnnotationElement {
/paperclip/i.test(this.data.name) ? "paperclip" : "pushpin" /paperclip/i.test(this.data.name) ? "paperclip" : "pushpin"
}.svg`; }.svg`;
} }
trigger.className = "popupTriggerArea"; trigger.classList.add("popupTriggerArea");
trigger.addEventListener("dblclick", this._download.bind(this)); trigger.addEventListener("dblclick", this._download.bind(this));
if ( if (

View File

@ -19,7 +19,7 @@
position: absolute; position: absolute;
} }
.annotationLayer .buttonWidgetAnnotation.pushButton > img { .annotationLayer .wasCanvas {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: absolute; position: absolute;

View File

@ -135,6 +135,7 @@ async function convertCanvasesToImages(annotationCanvasMap, outputScale) {
new Promise(resolve => { new Promise(resolve => {
canvas.toBlob(blob => { canvas.toBlob(blob => {
const image = document.createElement("img"); const image = document.createElement("img");
image.classList.add("wasCanvas");
image.onload = function () { image.onload = function () {
image.style.width = Math.floor(image.width / outputScale) + "px"; image.style.width = Math.floor(image.width / outputScale) + "px";
resolve(); resolve();
@ -625,6 +626,9 @@ class Driver {
let viewport = page.getViewport({ let viewport = page.getViewport({
scale: PixelsPerInch.PDF_TO_CSS_UNITS, scale: PixelsPerInch.PDF_TO_CSS_UNITS,
}); });
if (task.rotation) {
viewport = viewport.clone({ rotation: task.rotation });
}
// Restrict the test from creating a canvas that is too big. // Restrict the test from creating a canvas that is too big.
const MAX_CANVAS_PIXEL_DIMENSION = 4096; const MAX_CANVAS_PIXEL_DIMENSION = 4096;
const largestDimension = Math.max(viewport.width, viewport.height); const largestDimension = Math.max(viewport.width, viewport.height);

View File

@ -7394,5 +7394,32 @@
"rounds": 1, "rounds": 1,
"link": true, "link": true,
"type": "eq" "type": "eq"
},
{
"id": "annotation-link-text-popup-rotated-90",
"file": "pdfs/annotation-link-text-popup.pdf",
"md5": "4bbf56e81d47232de5f305124ab0ba27",
"rounds": 1,
"type": "eq",
"annotations": true,
"rotation": 90
},
{
"id": "annotation-link-text-popup-rotated-180",
"file": "pdfs/annotation-link-text-popup.pdf",
"md5": "4bbf56e81d47232de5f305124ab0ba27",
"rounds": 1,
"type": "eq",
"annotations": true,
"rotation": 180
},
{
"id": "annotation-link-text-popup-rotated-270",
"file": "pdfs/annotation-link-text-popup.pdf",
"md5": "4bbf56e81d47232de5f305124ab0ba27",
"rounds": 1,
"type": "eq",
"annotations": true,
"rotation": 270
} }
] ]

View File

@ -53,6 +53,22 @@
z-index: 3; z-index: 3;
} }
.annotationLayer[data-main-rotation="90"] .norotate {
transform: rotate(270deg) translateX(-100%);
}
.annotationLayer[data-main-rotation="180"] .norotate {
transform: rotate(180deg) translate(-100%, -100%);
}
.annotationLayer[data-main-rotation="270"] .norotate {
transform: rotate(90deg) translateY(-100%);
}
.annotationLayer canvas {
position: absolute;
width: 100%;
height: 100%;
}
.annotationLayer section { .annotationLayer section {
position: absolute; position: absolute;
text-align: initial; text-align: initial;
@ -75,11 +91,6 @@
height: 100%; height: 100%;
} }
.annotationLayer .buttonWidgetAnnotation.pushButton > canvas {
width: 100%;
height: 100%;
}
.annotationLayer .linkAnnotation > a:hover, .annotationLayer .linkAnnotation > a:hover,
.annotationLayer .buttonWidgetAnnotation.pushButton > a:hover { .annotationLayer .buttonWidgetAnnotation.pushButton > a:hover {
opacity: 0.2; opacity: 0.2;
@ -92,6 +103,8 @@
cursor: pointer; cursor: pointer;
width: 100%; width: 100%;
height: 100%; height: 100%;
top: 0;
left: 0;
} }
.annotationLayer .textWidgetAnnotation input, .annotationLayer .textWidgetAnnotation input,
@ -237,6 +250,10 @@
width: 100%; width: 100%;
} }
.annotationLayer .fileAttachmentAnnotation .popupTriggerArea {
position: absolute;
}
.annotationLayer .popupWrapper { .annotationLayer .popupWrapper {
position: absolute; position: absolute;
font-size: calc(9px * var(--scale-factor)); font-size: calc(9px * var(--scale-factor));
@ -306,6 +323,8 @@
position: absolute; position: absolute;
width: 100%; width: 100%;
height: 100%; height: 100%;
top: 0;
left: 0;
} }
.annotationLayer .annotationTextContent { .annotationLayer .annotationTextContent {