Skip to content

Commit 85e6f3c

Browse files
Merge pull request #19785 from nicolo-ribaudo/chrome-selection-fix
[chrome] Fix text selection with `.markedContent`
2 parents 115ea6a + da5b681 commit 85e6f3c

File tree

4 files changed

+107
-0
lines changed

4 files changed

+107
-0
lines changed

test/integration/text_layer_spec.mjs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,104 @@ describe("Text layer", () => {
217217
});
218218
});
219219

220+
describe("doesn't jump when hovering on an empty area, with .markedContent", () => {
221+
let pages;
222+
223+
beforeAll(async () => {
224+
pages = await loadAndWait(
225+
"chrome-text-selection-markedContent.pdf",
226+
`.page[data-page-number = "1"] .endOfContent`
227+
);
228+
});
229+
afterAll(async () => {
230+
await closePages(pages);
231+
});
232+
233+
it("in per-character selection mode", async () => {
234+
await Promise.all(
235+
pages.map(async ([browserName, page]) => {
236+
const [positionStart, positionEnd] = await Promise.all([
237+
getSpanRectFromText(
238+
page,
239+
1,
240+
"strengthen in the coming quarters as the railway projects under"
241+
).then(middlePosition),
242+
getSpanRectFromText(
243+
page,
244+
1,
245+
"development enter the construction phase (estimated at around"
246+
).then(belowEndPosition),
247+
]);
248+
249+
await page.mouse.move(positionStart.x, positionStart.y);
250+
await page.mouse.down();
251+
await moveInSteps(page, positionStart, positionEnd, 20);
252+
await page.mouse.up();
253+
254+
await expectAsync(page)
255+
.withContext(`In ${browserName}`)
256+
.toHaveRoughlySelected(
257+
"rs as the railway projects under\n" +
258+
"development enter the construction phase (estimated at "
259+
);
260+
})
261+
);
262+
});
263+
264+
it("in per-word selection mode", async () => {
265+
await Promise.all(
266+
pages.map(async ([browserName, page]) => {
267+
const [positionStart, positionEnd] = await Promise.all([
268+
getSpanRectFromText(
269+
page,
270+
1,
271+
"strengthen in the coming quarters as the railway projects under"
272+
).then(middlePosition),
273+
getSpanRectFromText(
274+
page,
275+
1,
276+
"development enter the construction phase (estimated at around"
277+
).then(belowEndPosition),
278+
]);
279+
280+
if (browserName !== "firefox") {
281+
await page.mouse.move(positionStart.x, positionStart.y);
282+
await page.mouse.down({ clickCount: 1 });
283+
await page.mouse.up({ clickCount: 1 });
284+
await page.mouse.down({ clickCount: 2 });
285+
} else {
286+
// When running tests with Firefox we use WebDriver BiDi, for
287+
// which puppeteer doesn't support emulating "double click and
288+
// hold". We need to manually dispatch an action through the
289+
// protocol.
290+
// See https://github.com/puppeteer/puppeteer/issues/13745.
291+
await page.mainFrame().browsingContext.performActions([
292+
{
293+
type: "pointer",
294+
id: "__puppeteer_mouse",
295+
actions: [
296+
{ type: "pointerMove", ...positionStart },
297+
{ type: "pointerDown", button: 0 },
298+
{ type: "pointerUp", button: 0 },
299+
{ type: "pointerDown", button: 0 },
300+
],
301+
},
302+
]);
303+
}
304+
await moveInSteps(page, positionStart, positionEnd, 20);
305+
await page.mouse.up();
306+
307+
await expectAsync(page)
308+
.withContext(`In ${browserName}`)
309+
.toHaveRoughlySelected(
310+
"quarters as the railway projects under\n" +
311+
"development enter the construction phase (estimated at around"
312+
);
313+
})
314+
);
315+
});
316+
});
317+
220318
describe("when selecting over a link", () => {
221319
let pages;
222320

test/pdfs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,3 +718,4 @@
718718
!issue19424.pdf
719719
!issue18529.pdf
720720
!issue16742.pdf
721+
!chrome-text-selection-markedContent.pdf
134 KB
Binary file not shown.

web/text_layer_builder.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,14 @@ class TextLayerBuilder {
307307
if (anchor.nodeType === Node.TEXT_NODE) {
308308
anchor = anchor.parentNode;
309309
}
310+
if (!modifyStart && range.endOffset === 0) {
311+
do {
312+
while (!anchor.previousSibling) {
313+
anchor = anchor.parentNode;
314+
}
315+
anchor = anchor.previousSibling;
316+
} while (!anchor.childNodes.length);
317+
}
310318

311319
const parentTextLayer = anchor.parentElement?.closest(".textLayer");
312320
const endDiv = this.#textLayers.get(parentTextLayer);

0 commit comments

Comments
 (0)