From 0b1ad403471c0c097d08af59717a34691d8bf5b7 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 20 Aug 2022 11:20:23 -0400 Subject: [PATCH] CSS zoom handling (#2178) * Refactor * Handle CSS zoom when scanning --- ext/js/dom/document-util.js | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/ext/js/dom/document-util.js b/ext/js/dom/document-util.js index f5cf194b..b974387e 100644 --- a/ext/js/dom/document-util.js +++ b/ext/js/dom/document-util.js @@ -24,6 +24,7 @@ class DocumentUtil { constructor() { this._transparentColorPattern = /rgba\s*\([^)]*,\s*0(?:\.0+)?\s*\)/; + this._cssZoomSupported = (typeof document.createElement('div').style.zoom === 'string'); } getRangeFromPoint(x, y, deepContentScan) { @@ -436,15 +437,21 @@ class DocumentUtil { _isPointInRange(x, y, range) { // Require a text node to start - if (range.startContainer.nodeType !== Node.TEXT_NODE) { + const {startContainer} = range; + if (startContainer.nodeType !== Node.TEXT_NODE) { return false; } + // Convert CSS zoom coordinates + if (this._cssZoomSupported) { + ({x, y} = this._convertCssZoomCoordinates(x, y, startContainer)); + } + // Scan forward const nodePre = range.endContainer; const offsetPre = range.endOffset; try { - const {node, offset, content} = new DOMTextScanner(range.endContainer, range.endOffset, true, false).seek(1); + const {node, offset, content} = new DOMTextScanner(nodePre, offsetPre, true, false).seek(1); range.setEnd(node, offset); if (!this._isWhitespace(content) && DocumentUtil.isPointInAnyRect(x, y, range.getClientRects())) { @@ -455,7 +462,7 @@ class DocumentUtil { } // Scan backward - const {node, offset, content} = new DOMTextScanner(range.startContainer, range.startOffset, true, false).seek(-1); + const {node, offset, content} = new DOMTextScanner(startContainer, range.startOffset, true, false).seek(-1); range.setStart(node, offset); if (!this._isWhitespace(content) && DocumentUtil.isPointInAnyRect(x, y, range.getClientRects())) { @@ -661,4 +668,18 @@ class DocumentUtil { _isElementUserSelectAll(element) { return getComputedStyle(element).userSelect === 'all'; } + + _convertCssZoomCoordinates(x, y, node) { + const ELEMENT_NODE = Node.ELEMENT_NODE; + for (; node !== null; node = node.parentNode) { + if (node.nodeType !== ELEMENT_NODE) { continue; } + let {zoom} = getComputedStyle(node); + if (typeof zoom !== 'string') { continue; } + zoom = Number.parseFloat(zoom); + if (!Number.isFinite(zoom) || zoom === 0) { continue; } + x /= zoom; + y /= zoom; + } + return {x, y}; + } }