From 55876baa4b6eabb0dc80053f8699bb9fec9320e1 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Sun, 20 Sep 2026 11:33:47 +0200 Subject: [PATCH 1/2] fix(html): the pdf's selection keeps its background The `::selection` rules that keep the hidden text layer hidden stated a colour and no background. An author `::selection` rule drops the UA's own background, so a selection in a pdf view painted nothing at all: no glyphs, which was the point, but no highlight either, and a reader selecting text saw no selection to aim a mark at. The rules now state the background with the colour, as `Highlight`, which follows the platform rather than fixing a colour of its own. Checked in chromium against five variants of the rule: the colour alone takes the background with it, `-webkit-text-fill-color` does not hide the layer at all, and stating both does what is wanted. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01FJJdfqpnVCKBNHXjAVxSou --- CHANGELOG.md | 5 +++++ src/odr/internal/html/pdf_file.cpp | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82b2c8675..6d401b815 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,11 @@ The release run heads these entries with the version and opens a fresh ## Unreleased +- **Fix**: selecting text in a pdf view showed no selection at all. The + `::selection` rules that keep the hidden layer hidden stated a colour and no + background, and an author `::selection` drops the UA's own background, so the + highlight went with the glyphs. They now state both. + - **Fix**: selecting text in a pdf view showed the invisible layer that carries it, as a second set of glyphs over the drawn ones. That layer now stays transparent under `::selection`. diff --git a/src/odr/internal/html/pdf_file.cpp b/src/odr/internal/html/pdf_file.cpp index ba3330e15..7d74e36de 100644 --- a/src/odr/internal/html/pdf_file.cpp +++ b/src/odr/internal/html/pdf_file.cpp @@ -1819,7 +1819,11 @@ class HtmlServiceImpl final : public HtmlService { out.out() << ".i{color:transparent;font-family:sf,sans-serif}"; // A selection paints text in the highlight's own colour, which beats // `transparent` and shows this layer over the glyph layer it stands for. - out.out() << ".i::selection,.i *::selection{color:transparent}"; + // The background goes with it: an author `::selection` drops the UA's + // own, and a rule stating the colour alone leaves a selection that shows + // nothing at all. + out.out() << ".i::selection,.i *::selection" + "{color:transparent;background:Highlight}"; // Selection-layer run span. `overflow:hidden` clips a wider system font; // `.t`'s inherited `pre` blocks wrapping while preserving a run's own // leading/trailing space, which is real PDF content. @@ -2294,7 +2298,8 @@ class HtmlServiceImpl final : public HtmlService { // `transparent`. `*` reaches a run's own span and a search `mark`. out.out() << ".i::selection,.i *::selection," ".ov::selection,.ov *::selection," - ".sp::selection,.sp *::selection{color:transparent}"; + ".sp::selection,.sp *::selection" + "{color:transparent;background:Highlight}"; // A hit in the overlay is clipped away with it, so the glyphs it belongs // to carry the highlight instead - the whole run of them, which is as // narrow as the overlay can say. @@ -2870,7 +2875,7 @@ class HtmlServiceImpl final : public HtmlService { // The same guard for a line the embedded font makes invisible; the dual // layer's `fnN` rides a `user-select:none` run and needs none. font_styles += ".fn" + n + "::selection,.fn" + n + - " *::selection{color:transparent}"; + " *::selection{color:transparent;background:Highlight}"; } } From 9aaa5b9af2787d44a8a10fd6b5b05bf6907cb2bb Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Sun, 20 Sep 2026 11:44:40 +0200 Subject: [PATCH 2/2] fix(html): state the highlight through `background-color`, and cut the comments A highlight pseudo takes `background-color`; the `background` shorthand also carries longhands the pseudo does not, which a strict engine may drop whole. The two entries in `Unreleased` describe one change nothing has released, so they read as one. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_0149gFxhkvKTBQidz6brU8Vt --- CHANGELOG.md | 8 ++------ src/odr/internal/html/pdf_file.cpp | 17 ++++++++--------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d401b815..98f259e2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,14 +16,10 @@ The release run heads these entries with the version and opens a fresh ## Unreleased -- **Fix**: selecting text in a pdf view showed no selection at all. The - `::selection` rules that keep the hidden layer hidden stated a colour and no - background, and an author `::selection` drops the UA's own background, so the - highlight went with the glyphs. They now state both. - - **Fix**: selecting text in a pdf view showed the invisible layer that carries it, as a second set of glyphs over the drawn ones. That layer now stays - transparent under `::selection`. + transparent under `::selection`, and states the highlight background, which + an author `::selection` otherwise drops. - A tap opens a sheet cell's editor where the pointer is coarse, so a phone needs one tap rather than a double tap. A mouse keeps the double click. diff --git a/src/odr/internal/html/pdf_file.cpp b/src/odr/internal/html/pdf_file.cpp index 7d74e36de..13d358f95 100644 --- a/src/odr/internal/html/pdf_file.cpp +++ b/src/odr/internal/html/pdf_file.cpp @@ -1818,12 +1818,10 @@ class HtmlServiceImpl final : public HtmlService { // Transparent text for the selection layer line blocks. out.out() << ".i{color:transparent;font-family:sf,sans-serif}"; // A selection paints text in the highlight's own colour, which beats - // `transparent` and shows this layer over the glyph layer it stands for. - // The background goes with it: an author `::selection` drops the UA's - // own, and a rule stating the colour alone leaves a selection that shows - // nothing at all. + // `transparent` and shows this layer over the glyphs it stands for. An + // author `::selection` drops the UA background, so state that too. out.out() << ".i::selection,.i *::selection" - "{color:transparent;background:Highlight}"; + "{color:transparent;background-color:Highlight}"; // Selection-layer run span. `overflow:hidden` clips a wider system font; // `.t`'s inherited `pre` blocks wrapping while preserving a run's own // leading/trailing space, which is real PDF content. @@ -2294,12 +2292,12 @@ class HtmlServiceImpl final : public HtmlService { // height, while clipping nothing (the space is transparent). out.out() << ".sp{display:inline-block;" "color:transparent;vertical-align:baseline}"; - // A selection paints text in the highlight's own colour, which beats - // `transparent`. `*` reaches a run's own span and a search `mark`. + // As `.i` in the dual layer above, with `*` reaching a run's own span + // and a search `mark`. out.out() << ".i::selection,.i *::selection," ".ov::selection,.ov *::selection," ".sp::selection,.sp *::selection" - "{color:transparent;background:Highlight}"; + "{color:transparent;background-color:Highlight}"; // A hit in the overlay is clipped away with it, so the glyphs it belongs // to carry the highlight instead - the whole run of them, which is as // narrow as the overlay can say. @@ -2875,7 +2873,8 @@ class HtmlServiceImpl final : public HtmlService { // The same guard for a line the embedded font makes invisible; the dual // layer's `fnN` rides a `user-select:none` run and needs none. font_styles += ".fn" + n + "::selection,.fn" + n + - " *::selection{color:transparent;background:Highlight}"; + " *::selection" + "{color:transparent;background-color:Highlight}"; } }