Skip to content

Commit 9723c5d

Browse files
committed
[Editor] Handle correctly colors when saving a document in HCM
- for example in Dusk theme (Windows 11), black appears to be white, so the user will draw something in white. But if they want to print or save the used color must be black. - fix a bug with the color input which only accepts hex string colors; - adjust outline color of the selected/hovered editors in HCM.
1 parent a520fc9 commit 9723c5d

File tree

6 files changed

+120
-17
lines changed

6 files changed

+120
-17
lines changed

src/display/display_utils.js

+13
Original file line numberDiff line numberDiff line change
@@ -589,12 +589,25 @@ function getRGB(color) {
589589
return [0, 0, 0];
590590
}
591591

592+
function getColorValues(colors) {
593+
const span = document.createElement("span");
594+
span.style.visibility = "hidden";
595+
document.body.append(span);
596+
for (const name of colors.keys()) {
597+
span.style.color = name;
598+
const computedColor = window.getComputedStyle(span).color;
599+
colors.set(name, getRGB(computedColor));
600+
}
601+
span.remove();
602+
}
603+
592604
export {
593605
deprecated,
594606
DOMCanvasFactory,
595607
DOMCMapReaderFactory,
596608
DOMStandardFontDataFactory,
597609
DOMSVGFactory,
610+
getColorValues,
598611
getFilenameFromUrl,
599612
getPdfFilenameFromUrl,
600613
getRGB,

src/display/editor/editor.js

+12-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
// eslint-disable-next-line max-len
1717
/** @typedef {import("./annotation_editor_layer.js").AnnotationEditorLayer} AnnotationEditorLayer */
1818

19-
import { bindEvents } from "./tools.js";
20-
import { unreachable } from "../../shared/util.js";
19+
import { bindEvents, ColorManager } from "./tools.js";
20+
import { shadow, unreachable } from "../../shared/util.js";
2121

2222
/**
2323
* @typedef {Object} AnnotationEditorParameters
@@ -33,6 +33,8 @@ import { unreachable } from "../../shared/util.js";
3333
class AnnotationEditor {
3434
#isInEditMode = false;
3535

36+
static _colorManager = new ColorManager();
37+
3638
/**
3739
* @param {AnnotationEditorParameters} parameters
3840
*/
@@ -56,6 +58,14 @@ class AnnotationEditor {
5658
this.isAttachedToDOM = false;
5759
}
5860

61+
static get _defaultLineColor() {
62+
return shadow(
63+
this,
64+
"_defaultLineColor",
65+
this._colorManager.getHexCode("CanvasText")
66+
);
67+
}
68+
5969
/**
6070
* This editor will be behind the others.
6171
*/

src/display/editor/freetext.js

+13-7
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import {
2121
} from "../../shared/util.js";
2222
import { AnnotationEditor } from "./editor.js";
2323
import { bindEvents } from "./tools.js";
24-
import { getRGB } from "../display_utils.js";
2524

2625
/**
2726
* Basic text editor in order to create a FreeTex annotation.
@@ -43,13 +42,16 @@ class FreeTextEditor extends AnnotationEditor {
4342

4443
static _internalPadding = 0;
4544

46-
static _defaultFontSize = 10;
45+
static _defaultColor = null;
4746

48-
static _defaultColor = "CanvasText";
47+
static _defaultFontSize = 10;
4948

5049
constructor(params) {
5150
super({ ...params, name: "freeTextEditor" });
52-
this.#color = params.color || FreeTextEditor._defaultColor;
51+
this.#color =
52+
params.color ||
53+
FreeTextEditor._defaultColor ||
54+
AnnotationEditor._defaultLineColor;
5355
this.#fontSize = params.fontSize || FreeTextEditor._defaultFontSize;
5456
}
5557

@@ -124,7 +126,10 @@ class FreeTextEditor extends AnnotationEditor {
124126
AnnotationEditorParamsType.FREETEXT_SIZE,
125127
FreeTextEditor._defaultFontSize,
126128
],
127-
[AnnotationEditorParamsType.FREETEXT_COLOR, FreeTextEditor._defaultColor],
129+
[
130+
AnnotationEditorParamsType.FREETEXT_COLOR,
131+
FreeTextEditor._defaultColor || AnnotationEditor._defaultLineColor,
132+
],
128133
];
129134
}
130135

@@ -362,8 +367,9 @@ class FreeTextEditor extends AnnotationEditor {
362367
const padding = FreeTextEditor._internalPadding * this.parent.scaleFactor;
363368
const rect = this.getRect(padding, padding);
364369

365-
// We don't use this.#color directly because it can be CanvasText.
366-
const color = getRGB(getComputedStyle(this.editorDiv).color);
370+
const color = AnnotationEditor._colorManager.convert(
371+
getComputedStyle(this.editorDiv).color
372+
);
367373

368374
return {
369375
annotationType: AnnotationEditorType.FREETEXT,

src/display/editor/ink.js

+11-7
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import {
2020
} from "../../shared/util.js";
2121
import { AnnotationEditor } from "./editor.js";
2222
import { fitCurve } from "./fit_curve/fit_curve.js";
23-
import { getRGB } from "../display_utils.js";
2423

2524
/**
2625
* Basic draw editor in order to generate an Ink annotation.
@@ -48,13 +47,16 @@ class InkEditor extends AnnotationEditor {
4847

4948
#realHeight = 0;
5049

51-
static _defaultThickness = 1;
50+
static _defaultColor = null;
5251

53-
static _defaultColor = "CanvasText";
52+
static _defaultThickness = 1;
5453

5554
constructor(params) {
5655
super({ ...params, name: "inkEditor" });
57-
this.color = params.color || InkEditor._defaultColor;
56+
this.color =
57+
params.color ||
58+
InkEditor._defaultColor ||
59+
AnnotationEditor._defaultLineColor;
5860
this.thickness = params.thickness || InkEditor._defaultThickness;
5961
this.paths = [];
6062
this.bezierPath2D = [];
@@ -124,7 +126,10 @@ class InkEditor extends AnnotationEditor {
124126
static get defaultPropertiesToUpdate() {
125127
return [
126128
[AnnotationEditorParamsType.INK_THICKNESS, InkEditor._defaultThickness],
127-
[AnnotationEditorParamsType.INK_COLOR, InkEditor._defaultColor],
129+
[
130+
AnnotationEditorParamsType.INK_COLOR,
131+
InkEditor._defaultColor || AnnotationEditor._defaultLineColor,
132+
],
128133
];
129134
}
130135

@@ -846,8 +851,7 @@ class InkEditor extends AnnotationEditor {
846851
const height =
847852
this.rotation % 180 === 0 ? rect[3] - rect[1] : rect[2] - rect[0];
848853

849-
// We don't use this.color directly because it can be CanvasText.
850-
const color = getRGB(this.ctx.strokeStyle);
854+
const color = AnnotationEditor._colorManager.convert(this.ctx.strokeStyle);
851855

852856
return {
853857
annotationType: AnnotationEditorType.INK,

src/display/editor/tools.js

+64-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ import {
2121
AnnotationEditorPrefix,
2222
AnnotationEditorType,
2323
shadow,
24+
Util,
2425
} from "../../shared/util.js";
26+
import { getColorValues, getRGB } from "../display_utils.js";
2527

2628
function bindEvents(obj, element, names) {
2729
for (const name of names) {
@@ -279,6 +281,67 @@ class ClipboardManager {
279281
}
280282
}
281283

284+
class ColorManager {
285+
static _colorsMapping = new Map([
286+
["CanvasText", [0, 0, 0]],
287+
["Canvas", [255, 255, 255]],
288+
]);
289+
290+
get _colors() {
291+
if (
292+
typeof PDFJSDev !== "undefined" &&
293+
PDFJSDev.test("LIB") &&
294+
typeof document === "undefined"
295+
) {
296+
return shadow(this, "_colors", ColorManager._colorsMapping);
297+
}
298+
299+
const colors = new Map([
300+
["CanvasText", null],
301+
["Canvas", null],
302+
]);
303+
getColorValues(colors);
304+
return shadow(this, "_colors", colors);
305+
}
306+
307+
/**
308+
* In High Contrast Mode, the color on the screen is not always the
309+
* real color used in the pdf.
310+
* For example in some cases white can appear to be black but when saving
311+
* we want to have white.
312+
* @param {string} color
313+
* @returns {Array<number>}
314+
*/
315+
convert(color) {
316+
const rgb = getRGB(color);
317+
if (!window.matchMedia("(forced-colors: active)").matches) {
318+
return rgb;
319+
}
320+
321+
for (const [name, RGB] of this._colors) {
322+
if (RGB.every((x, i) => x === rgb[i])) {
323+
return ColorManager._colorsMapping.get(name);
324+
}
325+
}
326+
return rgb;
327+
}
328+
329+
/**
330+
* An input element must have its color value as a hex string
331+
* and not as color name.
332+
* So this function converts a name into an hex string.
333+
* @param {string} name
334+
* @returns {string}
335+
*/
336+
getHexCode(name) {
337+
const rgb = this._colors.get(name);
338+
if (!rgb) {
339+
return name;
340+
}
341+
return Util.makeHexColor(...rgb);
342+
}
343+
}
344+
282345
/**
283346
* A pdf has several pages and each of them when it will rendered
284347
* will have an AnnotationEditorLayer which will contain the some
@@ -683,4 +746,4 @@ class AnnotationEditorUIManager {
683746
}
684747
}
685748

686-
export { AnnotationEditorUIManager, bindEvents, KeyboardManager };
749+
export { AnnotationEditorUIManager, bindEvents, ColorManager, KeyboardManager };

web/annotation_editor_layer_builder.css

+7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@
2020
--freetext-padding: 2px;
2121
}
2222

23+
@media (forced-colors: active) {
24+
:root {
25+
--focus-outline: solid 3px ButtonText;
26+
--hover-outline: dashed 3px ButtonText;
27+
}
28+
}
29+
2330
[data-editor-rotation="90"] {
2431
transform: rotate(90deg);
2532
}

0 commit comments

Comments
 (0)