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

[Editor] Add the possibility to change the thickness of a free highlight (bug 1876096) #17568

Merged
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
2 changes: 2 additions & 0 deletions l10n/en-US/viewer.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ pdfjs-editor-ink-opacity-input = Opacity
pdfjs-editor-stamp-add-image-button =
.title = Add image
pdfjs-editor-stamp-add-image-button-label = Add image
# This refers to the thickness of the line used for free highlighting (not bound to text)
pdfjs-editor-free-highlight-thickness-input = Thickness
pdfjs-free-text =
.aria-label = Text Editor
Expand Down
8 changes: 8 additions & 0 deletions src/display/draw_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ class DrawLayer {
path.setAttribute("d", line.toSVGPath());
}

updateLine(id, line) {
const root = this.#mapping.get(id);
const defs = root.firstChild;
const path = defs.firstChild;
this.updateBox(id, line.box);
path.setAttribute("d", line.toSVGPath());
}

removeFreeHighlight(id) {
this.remove(id);
this.#toUpdate.delete(id);
Expand Down
6 changes: 5 additions & 1 deletion src/display/editor/annotation_editor_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,11 @@ class AnnotationEditorLayer {
// Do nothing on right click.
return;
}
HighlightEditor.startHighlighting(this, event);
HighlightEditor.startHighlighting(
this,
this.#uiManager.direction === "ltr",
event
);
event.preventDefault();
}
}
Expand Down
13 changes: 10 additions & 3 deletions src/display/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ class AnnotationEditor {
// the position: it'll be done when the user will release the mouse button.

let { x, y } = this;
const [bx, by] = this.#getBaseTranslation();
const [bx, by] = this.getBaseTranslation();
x += bx;
y += by;

Expand All @@ -481,7 +481,14 @@ class AnnotationEditor {
this.div.scrollIntoView({ block: "nearest" });
}

#getBaseTranslation() {
/**
* Get the translation to take into account the editor border.
* The CSS engine positions the element by taking the border into account so
* we must apply the opposite translation to have the editor in the right
* position.
* @returns {Array<number>}
*/
getBaseTranslation() {
const [parentWidth, parentHeight] = this.parentDimensions;
const { _borderLineWidth } = AnnotationEditor;
const x = _borderLineWidth / parentWidth;
Expand Down Expand Up @@ -532,7 +539,7 @@ class AnnotationEditor {
this.x = x /= pageWidth;
this.y = y /= pageHeight;

const [bx, by] = this.#getBaseTranslation();
const [bx, by] = this.getBaseTranslation();
x += bx;
y += by;

Expand Down
113 changes: 88 additions & 25 deletions src/display/editor/highlight.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,13 @@ class HighlightEditor extends AnnotationEditor {

#outlineId = null;

#thickness;

static _defaultColor = null;

static _defaultOpacity = 1;

static _defaultThickness = 10;
static _defaultThickness = 12;

static _l10nPromise;

Expand All @@ -71,6 +73,7 @@ class HighlightEditor extends AnnotationEditor {
constructor(params) {
super({ ...params, name: "highlightEditor" });
this.color = params.color || HighlightEditor._defaultColor;
this.#thickness = params.thickness || HighlightEditor._defaultThickness;
this.#opacity = params.opacity || HighlightEditor._defaultOpacity;
this.#boxes = params.boxes || null;
this._isDraggable = false;
Expand Down Expand Up @@ -112,17 +115,31 @@ class HighlightEditor extends AnnotationEditor {
];
}

#createFreeOutlines({ highlight, highlightId, clipPathId }) {
this.#highlightOutlines = highlight.getOutlines(
this._uiManager.direction === "ltr"
#createFreeOutlines({ highlightOutlines, highlightId, clipPathId }) {
this.#highlightOutlines = highlightOutlines;
const extraThickness = 1.5;
this.#focusOutlines = highlightOutlines.getNewOutline(
/* Slightly bigger than the highlight in order to have a little
space between the highlight and the outline. */
this.#thickness / 2 + extraThickness,
/* innerMargin = */ 0.0025
);
this.#id = highlightId;
this.#clipPathId = clipPathId;
const { x, y, width, height, lastPoint } = this.#highlightOutlines.box;

// We need to redraw the highlight because we change the coordinates to be
// in the box coordinate system.
this.parent.drawLayer.finalizeLine(this.#id, this.#highlightOutlines);
if (highlightId >= 0) {
this.#id = highlightId;
this.#clipPathId = clipPathId;
// We need to redraw the highlight because we change the coordinates to be
// in the box coordinate system.
this.parent.drawLayer.finalizeLine(highlightId, highlightOutlines);
this.#outlineId = this.parent.drawLayer.highlightOutline(
this.#focusOutlines
);
} else if (this.parent) {
this.parent.drawLayer.updateLine(this.#id, highlightOutlines);
this.parent.drawLayer.updateLine(this.#outlineId, this.#focusOutlines);
}
const { x, y, width, height, lastPoint } = highlightOutlines.box;
this.#lastPoint = lastPoint;
switch (this.rotation) {
case 0:
this.x = x;
Expand Down Expand Up @@ -153,30 +170,24 @@ class HighlightEditor extends AnnotationEditor {
break;
}
}

const innerMargin = 1.5;
this.#focusOutlines = highlight.getFocusOutline(
/* Slightly bigger than the highlight in order to have a little
space between the highlight and the outline. */
HighlightEditor._defaultThickness + innerMargin
);
this.#outlineId = this.parent.drawLayer.highlightOutline(
this.#focusOutlines
);
this.#lastPoint = lastPoint;
}

/** @inheritdoc */
static initialize(l10n, uiManager) {
AnnotationEditor.initialize(l10n, uiManager);
HighlightEditor._defaultColor ||=
uiManager.highlightColors?.values().next().value || "#fff066";
}

/** @inheritdoc */
static updateDefaultParams(type, value) {
switch (type) {
case AnnotationEditorParamsType.HIGHLIGHT_DEFAULT_COLOR:
HighlightEditor._defaultColor = value;
break;
case AnnotationEditorParamsType.HIGHLIGHT_THICKNESS:
HighlightEditor._defaultThickness = value;
break;
}
}

Expand All @@ -194,6 +205,9 @@ class HighlightEditor extends AnnotationEditor {
case AnnotationEditorParamsType.HIGHLIGHT_COLOR:
this.#updateColor(value);
break;
case AnnotationEditorParamsType.HIGHLIGHT_THICKNESS:
this.#updateThickness(value);
break;
}
}

Expand All @@ -203,6 +217,10 @@ class HighlightEditor extends AnnotationEditor {
AnnotationEditorParamsType.HIGHLIGHT_DEFAULT_COLOR,
HighlightEditor._defaultColor,
],
[
AnnotationEditorParamsType.HIGHLIGHT_THICKNESS,
HighlightEditor._defaultThickness,
],
];
}

Expand All @@ -213,6 +231,10 @@ class HighlightEditor extends AnnotationEditor {
AnnotationEditorParamsType.HIGHLIGHT_COLOR,
this.color || HighlightEditor._defaultColor,
],
[
AnnotationEditorParamsType.HIGHLIGHT_THICKNESS,
this.#thickness || HighlightEditor._defaultThickness,
],
];
}

Expand All @@ -238,6 +260,27 @@ class HighlightEditor extends AnnotationEditor {
});
}

/**
* Update the thickness and make this action undoable.
* @param {number} thickness
*/
#updateThickness(thickness) {
const savedThickness = this.#thickness;
const setThickness = th => {
this.#thickness = th;
this.#changeThickness(th);
};
this.addCommands({
cmd: setThickness.bind(this, thickness),
undo: setThickness.bind(this, savedThickness),
post: this._uiManager.updateUI.bind(this._uiManager, this),
mustExec: true,
type: AnnotationEditorParamsType.INK_THICKNESS,
overwriteIfSameType: true,
keepUndo: true,
});
}

/** @inheritdoc */
async addEditToolbar() {
const toolbar = await super.addEditToolbar();
Expand Down Expand Up @@ -268,6 +311,13 @@ class HighlightEditor extends AnnotationEditor {
return super.fixAndSetPosition(this.#getRotation());
}

/** @inheritdoc */
getBaseTranslation() {
// The editor itself doesn't have any CSS border (we're drawing one
// ourselves in using SVG).
return [0, 0];
}

/** @inheritdoc */
getRect(tx, ty) {
return super.getRect(tx, ty, this.#getRotation());
Expand Down Expand Up @@ -322,6 +372,18 @@ class HighlightEditor extends AnnotationEditor {
}
}

#changeThickness(thickness) {
if (!this.#isFreeHighlight) {
return;
}
this.#createFreeOutlines({
highlightOutlines: this.#highlightOutlines.getNewOutline(thickness / 2),
});
this.fixAndSetPosition();
const [parentWidth, parentHeight] = this.parentDimensions;
this.setDims(this.width * parentWidth, this.height * parentHeight);
}

#cleanDrawLayer() {
if (this.#id === null || !this.parent) {
return;
Expand Down Expand Up @@ -480,7 +542,7 @@ class HighlightEditor extends AnnotationEditor {
return this.#highlightOutlines.serialize(rect, this.#getRotation());
}

static startHighlighting(parent, { target: textLayer, x, y }) {
static startHighlighting(parent, isLTR, { target: textLayer, x, y }) {
const {
x: layerX,
y: layerY,
Expand Down Expand Up @@ -518,7 +580,8 @@ class HighlightEditor extends AnnotationEditor {
{ x, y },
[layerX, layerY, parentWidth, parentHeight],
parent.scale,
this._defaultThickness,
this._defaultThickness / 2,
isLTR,
/* innerMargin = */ 0.001
);
({ id: this._freeHighlightId, clipPathId: this._freeHighlightClipId } =
Expand All @@ -541,7 +604,7 @@ class HighlightEditor extends AnnotationEditor {
if (!this._freeHighlight.isEmpty()) {
parent.createAndAddNewEditor(event, false, {
highlightId: this._freeHighlightId,
highlight: this._freeHighlight,
highlightOutlines: this._freeHighlight.getOutlines(),
clipPathId: this._freeHighlightClipId,
});
} else {
Expand Down Expand Up @@ -595,7 +658,7 @@ class HighlightEditor extends AnnotationEditor {
annotationType: AnnotationEditorType.HIGHLIGHT,
color,
opacity: this.#opacity,
thickness: 2 * HighlightEditor._defaultThickness,
thickness: this.#thickness,
quadPoints: this.#serializeBoxes(rect),
outlines: this.#serializeOutlines(rect),
pageIndex: this.pageIndex,
Expand Down
Loading