Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support rotating editor layer #15088

Merged
merged 1 commit into from
Jun 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 48 additions & 24 deletions src/core/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -1509,6 +1509,19 @@ class WidgetAnnotation extends Annotation {
return !!(this.data.fieldFlags & flag);
}

static _getRotationMatrix(rotation, width, height) {
switch (rotation) {
case 90:
return [0, 1, -1, 0, width, 0];
case 180:
return [-1, 0, 0, -1, width, height];
case 270:
return [0, -1, 1, 0, 0, height];
default:
throw new Error("Invalid rotation");
}
}

getRotationMatrix(annotationStorage) {
const storageEntry = annotationStorage
? annotationStorage.get(this.data.id)
Expand All @@ -1525,16 +1538,7 @@ class WidgetAnnotation extends Annotation {
const width = this.data.rect[2] - this.data.rect[0];
const height = this.data.rect[3] - this.data.rect[1];

switch (rotation) {
case 90:
return [0, 1, -1, 0, width, 0];
case 180:
return [-1, 0, 0, -1, width, height];
case 270:
return [0, -1, 1, 0, 0, height];
default:
throw new Error("Invalid rotation");
}
return WidgetAnnotation._getRotationMatrix(rotation, width, height);
}

getBorderAndBackgroundAppearances(annotationStorage) {
Expand Down Expand Up @@ -3185,7 +3189,7 @@ class FreeTextAnnotation extends MarkupAnnotation {
}

static createNewDict(annotation, xref, { apRef, ap }) {
const { color, fontSize, rect, user, value } = annotation;
const { color, fontSize, rect, rotation, user, value } = annotation;
const freetext = new Dict(xref);
freetext.set("Type", Name.get("Annot"));
freetext.set("Subtype", Name.get("FreeText"));
Expand All @@ -3196,7 +3200,7 @@ class FreeTextAnnotation extends MarkupAnnotation {
freetext.set("Contents", value);
freetext.set("F", 4);
freetext.set("Border", [0, 0, 0]);
freetext.set("Rotate", 0);
freetext.set("Rotate", rotation);

if (user) {
freetext.set("T", stringToUTF8String(user));
Expand All @@ -3216,7 +3220,7 @@ class FreeTextAnnotation extends MarkupAnnotation {

static async createNewAppearanceStream(annotation, xref, params) {
const { baseFontRef, evaluator, task } = params;
const { color, fontSize, rect, value } = annotation;
const { color, fontSize, rect, rotation, value } = annotation;

const resources = new Dict(xref);
const font = new Dict(xref);
Expand Down Expand Up @@ -3244,8 +3248,12 @@ class FreeTextAnnotation extends MarkupAnnotation {
);

const [x1, y1, x2, y2] = rect;
const w = x2 - x1;
const h = y2 - y1;
let w = x2 - x1;
let h = y2 - y1;

if (rotation % 180 !== 0) {
[w, h] = [h, w];
}

const lines = value.split("\n");
const scale = fontSize / 1000;
Expand Down Expand Up @@ -3301,6 +3309,11 @@ class FreeTextAnnotation extends MarkupAnnotation {
appearanceStreamDict.set("Length", appearance.length);
appearanceStreamDict.set("Resources", resources);

if (rotation) {
const matrix = WidgetAnnotation._getRotationMatrix(rotation, w, h);
appearanceStreamDict.set("Matrix", matrix);
}

const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;

Expand Down Expand Up @@ -3669,18 +3682,19 @@ class InkAnnotation extends MarkupAnnotation {
}

static createNewDict(annotation, xref, { apRef, ap }) {
const { paths, rect, rotation } = annotation;
const ink = new Dict(xref);
ink.set("Type", Name.get("Annot"));
ink.set("Subtype", Name.get("Ink"));
ink.set("CreationDate", `D:${getModificationDate()}`);
ink.set("Rect", annotation.rect);
ink.set("Rect", rect);
ink.set(
"InkList",
annotation.paths.map(p => p.points)
paths.map(p => p.points)
);
ink.set("F", 4);
ink.set("Border", [0, 0, 0]);
ink.set("Rotate", 0);
ink.set("Rotate", rotation);

const n = new Dict(xref);
ink.set("AP", n);
Expand All @@ -3695,16 +3709,21 @@ class InkAnnotation extends MarkupAnnotation {
}

static async createNewAppearanceStream(annotation, xref, params) {
const [x1, y1, x2, y2] = annotation.rect;
const w = x2 - x1;
const h = y2 - y1;
const { color, rect, rotation, paths, thickness } = annotation;
const [x1, y1, x2, y2] = rect;
let w = x2 - x1;
let h = y2 - y1;

if (rotation % 180 !== 0) {
[w, h] = [h, w];
}

const appearanceBuffer = [
`${annotation.thickness} w`,
`${getPdfColor(annotation.color, /* isFill */ false)}`,
`${thickness} w`,
`${getPdfColor(color, /* isFill */ false)}`,
];
const buffer = [];
for (const { bezier } of annotation.paths) {
for (const { bezier } of paths) {
buffer.length = 0;
buffer.push(
`${numberToString(bezier[0])} ${numberToString(bezier[1])} m`
Expand All @@ -3728,6 +3747,11 @@ class InkAnnotation extends MarkupAnnotation {
appearanceStreamDict.set("BBox", [0, 0, w, h]);
appearanceStreamDict.set("Length", appearance.length);

if (rotation) {
const matrix = WidgetAnnotation._getRotationMatrix(rotation, w, h);
appearanceStreamDict.set("Matrix", matrix);
}

const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;

Expand Down
4 changes: 2 additions & 2 deletions src/display/annotation_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ class AnnotationElement {
container.style.width = `${elementWidth}%`;
container.style.height = `${elementHeight}%`;

container.setAttribute("data-annotation-rotation", (360 - angle) % 360);
container.setAttribute("data-main-rotation", (360 - angle) % 360);
}

get _commonActions() {
Expand Down Expand Up @@ -2552,7 +2552,7 @@ class AnnotationLayer {

style.width = flipOrientation ? heightStr : widthStr;
style.height = flipOrientation ? widthStr : heightStr;
div.setAttribute("data-annotation-rotation", rotation);
div.setAttribute("data-main-rotation", rotation);
}

static #setAnnotationCanvasMap(div, annotationCanvasMap) {
Expand Down
64 changes: 46 additions & 18 deletions src/display/editor/annotation_editor_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
/** @typedef {import("../annotation_storage.js").AnnotationStorage} AnnotationStorage */
/** @typedef {import("../../web/interfaces").IL10n} IL10n */

import { AnnotationEditorType, Util } from "../../shared/util.js";
import { bindEvents, KeyboardManager } from "./tools.js";
import { AnnotationEditorType } from "../../shared/util.js";
import { FreeTextEditor } from "./freetext.js";
import { InkEditor } from "./ink.js";

Expand Down Expand Up @@ -106,6 +106,7 @@ class AnnotationEditorLayer {
} else {
this.div.removeEventListener("mouseover", this.#boundMouseover);
}
this.setActiveEditor(null);
}

/**
Expand Down Expand Up @@ -273,6 +274,11 @@ class AnnotationEditorLayer {
if (editor.parent === this) {
return;
}

if (this.#uiManager.isActive(editor)) {
editor.parent.setActiveEditor(null);
}

this.attach(editor);
editor.pageIndex = this.pageIndex;
editor.parent.detach(editor);
Expand Down Expand Up @@ -419,10 +425,10 @@ class AnnotationEditorLayer {
this.#changeParent(editor);

const rect = this.div.getBoundingClientRect();
editor.setAt(
event.clientX - rect.x - editor.mouseX,
event.clientY - rect.y - editor.mouseY
);
const endX = event.clientX - rect.x;
const endY = event.clientY - rect.y;

editor.translate(endX - editor.startX, endY - editor.startY);
}

/**
Expand Down Expand Up @@ -463,29 +469,19 @@ class AnnotationEditorLayer {
*/
render(parameters) {
this.viewport = parameters.viewport;
this.inverseViewportTransform = Util.inverseTransform(
this.viewport.transform
);
bindEvents(this, this.div, ["dragover", "drop", "keydown"]);
this.div.addEventListener("click", this.#boundClick);
this.setDimensions();
}

/**
* Update the main editor.
* @param {Object} parameters
*/
update(parameters) {
const transform = Util.transform(
parameters.viewport.transform,
this.inverseViewportTransform
);
this.setActiveEditor(null);
this.viewport = parameters.viewport;
this.inverseViewportTransform = Util.inverseTransform(
this.viewport.transform
);
for (const editor of this.#editors.values()) {
editor.transform(transform);
}
this.setDimensions();
}

/**
Expand All @@ -495,6 +491,38 @@ class AnnotationEditorLayer {
get scaleFactor() {
return this.viewport.scale;
}

/**
* Get page dimensions.
* @returns {Object} dimensions.
*/
get pageDimensions() {
const [pageLLx, pageLLy, pageURx, pageURy] = this.viewport.viewBox;
const width = pageURx - pageLLx;
const height = pageURy - pageLLy;

return [width, height];
}

get viewportBaseDimensions() {
const { width, height, rotation } = this.viewport;
return rotation % 180 === 0 ? [width, height] : [height, width];
}

/**
* Set the dimensions of the main div.
*/
setDimensions() {
const { width, height, rotation } = this.viewport;

const flipOrientation = rotation % 180 !== 0,
widthStr = Math.floor(width) + "px",
heightStr = Math.floor(height) + "px";

this.div.style.width = flipOrientation ? heightStr : widthStr;
this.div.style.height = flipOrientation ? widthStr : heightStr;
this.div.setAttribute("data-main-rotation", rotation);
}
}

export { AnnotationEditorLayer };
Loading