diff --git a/extensions/chromium/preferences_schema.json b/extensions/chromium/preferences_schema.json index 3b101c956..34d72e258 100644 --- a/extensions/chromium/preferences_schema.json +++ b/extensions/chromium/preferences_schema.json @@ -104,7 +104,7 @@ }, "highlightEditorColors": { "type": "string", - "default": "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F" + "default": "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F,yellow_HCM=#FFFFCC,green_HCM=#53FFBC,blue_HCM=#80EBFF,pink_HCM=#F6B8FF,red_HCM=#C50043" }, "disableRange": { "title": "Disable range requests", diff --git a/src/display/editor/highlight.js b/src/display/editor/highlight.js index 29a7f2d45..b8e7edb58 100644 --- a/src/display/editor/highlight.js +++ b/src/display/editor/highlight.js @@ -137,7 +137,7 @@ class HighlightEditor extends AnnotationEditor { return { action: "added", type: this.#isFreeHighlight ? "free_highlight" : "highlight", - color: this._uiManager.highlightColorNames.get(this.color), + color: this._uiManager.getNonHCMColorName(this.color), thickness: this.#thickness, methodOfCreation: this.#methodOfCreation, }; @@ -147,7 +147,7 @@ class HighlightEditor extends AnnotationEditor { get telemetryFinalData() { return { type: "highlight", - color: this._uiManager.highlightColorNames.get(this.color), + color: this._uiManager.getNonHCMColorName(this.color), }; } @@ -374,7 +374,7 @@ class HighlightEditor extends AnnotationEditor { this._reportTelemetry( { action: "color_changed", - color: this._uiManager.highlightColorNames.get(color), + color: this._uiManager.getNonHCMColorName(color), }, /* mustWait = */ true ); @@ -1024,7 +1024,9 @@ class HighlightEditor extends AnnotationEditor { } const rect = this.getRect(0, 0); - const color = AnnotationEditor._colorManager.convert(this.color); + const color = AnnotationEditor._colorManager.convert( + this._uiManager.getNonHCMColor(this.color) + ); const serialized = { annotationType: AnnotationEditorType.HIGHLIGHT, diff --git a/src/display/editor/tools.js b/src/display/editor/tools.js index 9e50053a8..200498f7a 100644 --- a/src/display/editor/tools.js +++ b/src/display/editor/tools.js @@ -960,10 +960,10 @@ class AnnotationEditorUIManager { ); } - get highlightColors() { + get _highlightColors() { return shadow( this, - "highlightColors", + "_highlightColors", this.#highlightColors ? new Map( this.#highlightColors.split(",").map(pair => { @@ -976,6 +976,26 @@ class AnnotationEditorUIManager { ); } + get highlightColors() { + const { _highlightColors } = this; + if (!_highlightColors) { + return shadow(this, "highlightColors", null); + } + const map = new Map(); + const hasHCM = !!this.#pageColors; + for (const [name, color] of _highlightColors) { + const isNameForHCM = name.endsWith("_HCM"); + if (hasHCM && isNameForHCM) { + map.set(name.replace("_HCM", ""), color); + continue; + } + if (!hasHCM && !isNameForHCM) { + map.set(name, color); + } + } + return shadow(this, "highlightColors", map); + } + get highlightColorNames() { return shadow( this, @@ -986,6 +1006,18 @@ class AnnotationEditorUIManager { ); } + getNonHCMColor(color) { + if (!this._highlightColors) { + return color; + } + const colorName = this.highlightColorNames.get(color); + return this._highlightColors.get(colorName) || color; + } + + getNonHCMColorName(color) { + return this.highlightColorNames.get(color) || color; + } + /** * Set the current drawing session. * @param {AnnotationEditorLayer} layer diff --git a/test/integration/highlight_editor_spec.mjs b/test/integration/highlight_editor_spec.mjs index 52ff76dc0..426b65a4b 100644 --- a/test/integration/highlight_editor_spec.mjs +++ b/test/integration/highlight_editor_spec.mjs @@ -2750,4 +2750,55 @@ describe("Highlight Editor", () => { ); }); }); + + describe("Highlight color in HCM", () => { + let pages; + + beforeEach(async () => { + pages = await loadAndWait( + "tracemonkey.pdf", + ".annotationEditorLayer", + null, + null, + { + highlightEditorColors: "red=#AB0000,red_HCM=#00AB00", + forcePageColors: true, + pageColorsForeground: "#74ffd0", + pageColorsBackground: "#392a4f", + } + ); + }); + + afterEach(async () => { + await closePages(pages); + }); + + it("must highlight with red color", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToHighlight(page); + + const rect = await getSpanRectFromText(page, 1, "Abstract"); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + + const editorSelector = getEditorSelector(0); + await page.waitForSelector(editorSelector); + await page.waitForSelector( + `.page[data-page-number = "1"] svg.highlightOutline.selected` + ); + + await page.waitForSelector( + `.page[data-page-number = "1"] .canvasWrapper > svg.highlight[fill = "#00AB00"]` + ); + await waitForSerialized(page, 1); + const serialized = await getSerialized(page); + expect(serialized[0].color) + .withContext(`In ${browserName}`) + .toEqual([0xab, 0x00, 0x00]); + }) + ); + }); + }); }); diff --git a/web/app.js b/web/app.js index 787473df7..8dd61389b 100644 --- a/web/app.js +++ b/web/app.js @@ -375,6 +375,9 @@ const PDFViewerApplication = { spreadModeOnLoad: x => parseInt(x), supportsCaretBrowsingMode: x => x === "true", viewerCssTheme: x => parseInt(x), + forcePageColors: x => x === "true", + pageColorsBackground: x => x, + pageColorsForeground: x => x, }); } diff --git a/web/app_options.js b/web/app_options.js index e5bfbbada..aa52b978f 100644 --- a/web/app_options.js +++ b/web/app_options.js @@ -286,7 +286,9 @@ const defaultOptions = { }, highlightEditorColors: { /** @type {string} */ - value: "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F", + value: + "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F," + + "yellow_HCM=#FFFFCC,green_HCM=#53FFBC,blue_HCM=#80EBFF,pink_HCM=#F6B8FF,red_HCM=#C50043", kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, historyUpdateUrl: {