optimize source frame finding

This commit is contained in:
siikamiika 2020-04-18 16:48:49 +03:00
parent c992e7f920
commit bb3ad78e37

View File

@ -22,6 +22,7 @@
class FrameOffsetForwarder { class FrameOffsetForwarder {
constructor() { constructor() {
this._started = false; this._started = false;
this._frameCache = new Set();
this._forwardFrameOffset = ( this._forwardFrameOffset = (
window !== window.parent ? window !== window.parent ?
@ -73,21 +74,12 @@ class FrameOffsetForwarder {
} }
_onGetFrameOffset(offset, uniqueId, e) { _onGetFrameOffset(offset, uniqueId, e) {
let sourceFrame = null; const sourceFrame = this._findFrameWithContentWindow(e.source);
for (const frame of document.querySelectorAll('frame, iframe:not(.yomichan-float)')) {
if (frame.contentWindow !== e.source) { continue; }
sourceFrame = frame;
break;
}
if (sourceFrame === null) { if (sourceFrame === null) {
sourceFrame = this._getOpenShadowRootSourceFrame(e.source);
if (!sourceFrame) {
// closed shadow root etc. // closed shadow root etc.
this._forwardFrameOffsetOrigin(null, uniqueId); this._forwardFrameOffsetOrigin(null, uniqueId);
return; return;
} }
}
const [forwardedX, forwardedY] = offset; const [forwardedX, forwardedY] = offset;
const {x, y} = sourceFrame.getBoundingClientRect(); const {x, y} = sourceFrame.getBoundingClientRect();
@ -96,22 +88,38 @@ class FrameOffsetForwarder {
this._forwardFrameOffset(offset, uniqueId); this._forwardFrameOffset(offset, uniqueId);
} }
_getOpenShadowRootSourceFrame(sourceWindow) { _findFrameWithContentWindow(contentWindow) {
const getShadowRootElements = (documentOrElement) => { const elements = [
const elements = Array.from(documentOrElement.querySelectorAll('*')) ...this._frameCache,
.filter((el) => !!el.shadowRoot); // will contain duplicates, but frame elements are cheap to handle
const childElements = elements ...document.querySelectorAll('frame, iframe:not(.yomichan-float)'),
.map((el) => el.shadowRoot) document.documentElement
.map(getShadowRootElements); ];
elements.push(childElements.flat()); const ELEMENT_NODE = Node.ELEMENT_NODE;
while (elements.length > 0) {
const element = elements.shift();
if (element.contentWindow === contentWindow) {
this._frameCache.add(element);
return element;
}
return elements.flat(); const shadowRoot = element.shadowRoot;
}; if (shadowRoot) {
for (const child of shadowRoot.children) {
if (child.nodeType === ELEMENT_NODE) {
elements.push(child);
}
}
}
return getShadowRootElements(document) for (const child of element.children) {
.map((el) => Array.from(el.shadowRoot.querySelectorAll('frame, iframe:not(.yomichan-float)'))) if (child.nodeType === ELEMENT_NODE) {
.flat() elements.push(child);
.find((el) => el.contentWindow === sourceWindow); }
}
}
return null;
} }
_forwardFrameOffsetParent(offset, uniqueId) { _forwardFrameOffsetParent(offset, uniqueId) {