From 4fdc300b61ebc3d36c3f5a511df92248453f8d55 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Fri, 17 Apr 2020 23:09:55 +0300 Subject: [PATCH 01/11] disable root frame popup when iframe is fullscreen --- ext/fg/js/frontend-initialize.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/fg/js/frontend-initialize.js b/ext/fg/js/frontend-initialize.js index 2b942258..83c0e606 100644 --- a/ext/fg/js/frontend-initialize.js +++ b/ext/fg/js/frontend-initialize.js @@ -88,7 +88,7 @@ async function main() { } let popup; - if (isIframe && options.general.showIframePopupsInRootFrame) { + if (isIframe && options.general.showIframePopupsInRootFrame && !document.fullscreen) { popup = popups.iframe || await createIframePopupProxy(url, frameOffsetForwarder); popups.iframe = popup; } else if (proxy) { @@ -117,6 +117,7 @@ async function main() { }; yomichan.on('optionsUpdated', applyOptions); + window.addEventListener('fullscreenchange', applyOptions, false); await applyOptions(); } From fbaf50def1934ef6fe0967233f4419efc44f1c30 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 18 Apr 2020 00:33:49 +0300 Subject: [PATCH 02/11] support iframes inside open shadow dom --- ext/fg/js/frame-offset-forwarder.js | 23 +++++++++++++++++++++-- test/data/html/test-document2.html | 19 ++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/ext/fg/js/frame-offset-forwarder.js b/ext/fg/js/frame-offset-forwarder.js index c658c55a..ac6e617d 100644 --- a/ext/fg/js/frame-offset-forwarder.js +++ b/ext/fg/js/frame-offset-forwarder.js @@ -79,9 +79,28 @@ class FrameOffsetForwarder { sourceFrame = frame; break; } + if (sourceFrame === null) { - this._forwardFrameOffsetOrigin(null, uniqueId); - return; + const getShadowRootElements = (documentOrElement) => { + const elements = Array.from(documentOrElement.querySelectorAll('*')) + .filter((el) => !!el.shadowRoot); + const childElements = elements + .map((el) => el.shadowRoot) + .map(getShadowRootElements); + elements.push(childElements.flat()); + + return elements.flat(); + }; + + sourceFrame = getShadowRootElements(document) + .map((el) => Array.from(el.shadowRoot.querySelectorAll('frame, iframe:not(.yomichan-float)'))) + .flat() + .find((el) => el.contentWindow === e.source); + + if (!sourceFrame) { + this._forwardFrameOffsetOrigin(null, uniqueId); + return; + } } const [forwardedX, forwardedY] = offset; diff --git a/test/data/html/test-document2.html b/test/data/html/test-document2.html index 3a22a5bf..b2046dfd 100644 --- a/test/data/html/test-document2.html +++ b/test/data/html/test-document2.html @@ -77,5 +77,22 @@ document.querySelector('#fullscreen-link1').addEventListener('click', () => togg +
+
<iframe> element inside of an open shadow DOM.
+
+ + +
+ - \ No newline at end of file + From 85706c421b7496d2d73a0f3d1f7721d39d5d0b3f Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 18 Apr 2020 00:50:05 +0300 Subject: [PATCH 03/11] show popup inside iframe for closed shadow dom --- ext/fg/js/frontend-initialize.js | 15 +++++++++++---- ext/fg/js/popup-proxy.js | 7 ++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/ext/fg/js/frontend-initialize.js b/ext/fg/js/frontend-initialize.js index 83c0e606..2e63c29f 100644 --- a/ext/fg/js/frontend-initialize.js +++ b/ext/fg/js/frontend-initialize.js @@ -24,7 +24,7 @@ * apiOptionsGet */ -async function createIframePopupProxy(url, frameOffsetForwarder) { +async function createIframePopupProxy(url, frameOffsetForwarder, setDisabled) { const rootPopupInformationPromise = yomichan.getTemporaryListenerResult( chrome.runtime.onMessage, ({action, params}, {resolve}) => { @@ -38,7 +38,7 @@ async function createIframePopupProxy(url, frameOffsetForwarder) { const getFrameOffset = frameOffsetForwarder.getOffset.bind(frameOffsetForwarder); - const popup = new PopupProxy(popupId, 0, null, frameId, url, getFrameOffset); + const popup = new PopupProxy(popupId, 0, null, frameId, url, getFrameOffset, setDisabled); await popup.prepare(); return popup; @@ -78,6 +78,13 @@ async function main() { let frontendPreparePromise = null; let frameOffsetForwarder = null; + let iframePopupsInRootFrameAvailable = true; + + const disableIframePopupsInRootFrame = () => { + iframePopupsInRootFrameAvailable = false; + applyOptions(); + }; + const applyOptions = async () => { const optionsContext = {depth: isSearchPage ? 0 : depth, url}; const options = await apiOptionsGet(optionsContext); @@ -88,8 +95,8 @@ async function main() { } let popup; - if (isIframe && options.general.showIframePopupsInRootFrame && !document.fullscreen) { - popup = popups.iframe || await createIframePopupProxy(url, frameOffsetForwarder); + if (isIframe && options.general.showIframePopupsInRootFrame && !document.fullscreen && iframePopupsInRootFrameAvailable) { + popup = popups.iframe || await createIframePopupProxy(url, frameOffsetForwarder, disableIframePopupsInRootFrame); popups.iframe = popup; } else if (proxy) { popup = popups.proxy || await createPopupProxy(depth, id, parentFrameId, url); diff --git a/ext/fg/js/popup-proxy.js b/ext/fg/js/popup-proxy.js index 82ad9a8f..3af83db2 100644 --- a/ext/fg/js/popup-proxy.js +++ b/ext/fg/js/popup-proxy.js @@ -20,7 +20,7 @@ */ class PopupProxy { - constructor(id, depth, parentId, parentFrameId, url, getFrameOffset=null) { + constructor(id, depth, parentId, parentFrameId, url, getFrameOffset=null, setDisabled=null) { this._parentId = parentId; this._parentFrameId = parentFrameId; this._id = id; @@ -28,6 +28,7 @@ class PopupProxy { this._url = url; this._apiSender = new FrontendApiSender(); this._getFrameOffset = getFrameOffset; + this._setDisabled = setDisabled; this._frameOffset = null; this._frameOffsetPromise = null; @@ -142,6 +143,10 @@ class PopupProxy { try { const offset = await this._frameOffsetPromise; this._frameOffset = offset !== null ? offset : [0, 0]; + if (offset === null && this._setDisabled !== null) { + this._setDisabled(); + return; + } this._frameOffsetUpdatedAt = now; } catch (e) { logError(e); From b786e2da1912dfa7d707db628d54fb914189f7d1 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 18 Apr 2020 00:55:16 +0300 Subject: [PATCH 04/11] move open shadow root iframe finder to a function --- ext/fg/js/frame-offset-forwarder.js | 36 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/ext/fg/js/frame-offset-forwarder.js b/ext/fg/js/frame-offset-forwarder.js index ac6e617d..2b48ba26 100644 --- a/ext/fg/js/frame-offset-forwarder.js +++ b/ext/fg/js/frame-offset-forwarder.js @@ -81,23 +81,9 @@ class FrameOffsetForwarder { } if (sourceFrame === null) { - const getShadowRootElements = (documentOrElement) => { - const elements = Array.from(documentOrElement.querySelectorAll('*')) - .filter((el) => !!el.shadowRoot); - const childElements = elements - .map((el) => el.shadowRoot) - .map(getShadowRootElements); - elements.push(childElements.flat()); - - return elements.flat(); - }; - - sourceFrame = getShadowRootElements(document) - .map((el) => Array.from(el.shadowRoot.querySelectorAll('frame, iframe:not(.yomichan-float)'))) - .flat() - .find((el) => el.contentWindow === e.source); - + sourceFrame = this._getOpenShadowRootSourceFrame(e.source); if (!sourceFrame) { + // closed shadow root etc. this._forwardFrameOffsetOrigin(null, uniqueId); return; } @@ -110,6 +96,24 @@ class FrameOffsetForwarder { this._forwardFrameOffset(offset, uniqueId); } + _getOpenShadowRootSourceFrame(sourceWindow) { + const getShadowRootElements = (documentOrElement) => { + const elements = Array.from(documentOrElement.querySelectorAll('*')) + .filter((el) => !!el.shadowRoot); + const childElements = elements + .map((el) => el.shadowRoot) + .map(getShadowRootElements); + elements.push(childElements.flat()); + + return elements.flat(); + }; + + return getShadowRootElements(document) + .map((el) => Array.from(el.shadowRoot.querySelectorAll('frame, iframe:not(.yomichan-float)'))) + .flat() + .find((el) => el.contentWindow === sourceWindow); + } + _forwardFrameOffsetParent(offset, uniqueId) { window.parent.postMessage({action: 'getFrameOffset', params: {offset, uniqueId}}, '*'); } From 350a1139968ec3db4da95cd27c4ce8b5be45c56a Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 18 Apr 2020 02:05:18 +0300 Subject: [PATCH 05/11] use getFullscreenElement to check fullscreen --- ext/fg/js/frontend-initialize.js | 3 ++- ext/fg/js/popup.js | 13 ++----------- ext/mixed/js/dom.js | 10 ++++++++++ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/ext/fg/js/frontend-initialize.js b/ext/fg/js/frontend-initialize.js index 2e63c29f..2df59e20 100644 --- a/ext/fg/js/frontend-initialize.js +++ b/ext/fg/js/frontend-initialize.js @@ -16,6 +16,7 @@ */ /* global + * DOM * FrameOffsetForwarder * Frontend * PopupProxy @@ -95,7 +96,7 @@ async function main() { } let popup; - if (isIframe && options.general.showIframePopupsInRootFrame && !document.fullscreen && iframePopupsInRootFrameAvailable) { + if (isIframe && options.general.showIframePopupsInRootFrame && DOM.getFullscreenElement() === null && iframePopupsInRootFrameAvailable) { popup = popups.iframe || await createIframePopupProxy(url, frameOffsetForwarder, disableIframePopupsInRootFrame); popups.iframe = popup; } else if (proxy) { diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index 99610e17..ae158263 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -16,6 +16,7 @@ */ /* global + * DOM * apiGetMessageToken * apiInjectStylesheet */ @@ -271,7 +272,7 @@ class Popup { } _onFullscreenChanged() { - const parent = (Popup._getFullscreenElement() || document.body || null); + const parent = (DOM.getFullscreenElement() || document.body || null); if (parent !== null && this._container.parentNode !== parent) { parent.appendChild(this._container); } @@ -365,16 +366,6 @@ class Popup { contentWindow.postMessage({action, params, token}, this._targetOrigin); } - static _getFullscreenElement() { - return ( - document.fullscreenElement || - document.msFullscreenElement || - document.mozFullScreenElement || - document.webkitFullscreenElement || - null - ); - } - static _getPositionForHorizontalText(elementRect, width, height, viewport, offsetScale, optionsGeneral) { const preferBelow = (optionsGeneral.popupHorizontalTextPosition === 'below'); const horizontalOffset = optionsGeneral.popupHorizontalOffset * offsetScale; diff --git a/ext/mixed/js/dom.js b/ext/mixed/js/dom.js index 03acbb80..31ba33d6 100644 --- a/ext/mixed/js/dom.js +++ b/ext/mixed/js/dom.js @@ -62,4 +62,14 @@ class DOM { default: return false; } } + + static getFullscreenElement() { + return ( + document.fullscreenElement || + document.msFullscreenElement || + document.mozFullScreenElement || + document.webkitFullscreenElement || + null + ); + } } From c992e7f920f20c0c7cc55fddf6aba61e0f8b1641 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 18 Apr 2020 03:35:00 +0300 Subject: [PATCH 06/11] add manual performance tests --- test/data/html/test-document3-frame1.html | 44 ++++++++++++++++ test/data/html/test-document3-frame2.html | 62 +++++++++++++++++++++++ test/data/html/test-document3.html | 26 ++++++++++ 3 files changed, 132 insertions(+) create mode 100644 test/data/html/test-document3-frame1.html create mode 100644 test/data/html/test-document3-frame2.html create mode 100644 test/data/html/test-document3.html diff --git a/test/data/html/test-document3-frame1.html b/test/data/html/test-document3-frame1.html new file mode 100644 index 00000000..2ae906d2 --- /dev/null +++ b/test/data/html/test-document3-frame1.html @@ -0,0 +1,44 @@ + + + + + + Yomichan Manual Performance Tests + + +
+ +
Add elements
+ +
+ 1000 + 10000 + 100000 + 1000000 + +
+ +
+
+ +
+ diff --git a/test/data/html/test-document3-frame2.html b/test/data/html/test-document3-frame2.html new file mode 100644 index 00000000..c486e04b --- /dev/null +++ b/test/data/html/test-document3-frame2.html @@ -0,0 +1,62 @@ + + + + + + Yomichan Manual Performance Tests + + +
+ +
<iframe> element inside of an open shadow DOM.
+ +
+ + + +
Add elements
+ +
+ 1000 + 10000 + 100000 + 1000000 +
+ +
+
+ + +
+ diff --git a/test/data/html/test-document3.html b/test/data/html/test-document3.html new file mode 100644 index 00000000..3e7d5236 --- /dev/null +++ b/test/data/html/test-document3.html @@ -0,0 +1,26 @@ + + + + + + Yomichan Manual Performance Tests + + + + + +

Yomichan Manual Performance Tests

+

Testing Yomichan performance with artificially demanding cases in a real browser

+ +
+
<iframe> element.
+ +
+ +
+
<iframe> element containing an <iframe> element inside of an open shadow DOM.
+ +
+ + + From bb3ad78e373b01b64a24fc46712f24964528a24f Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 18 Apr 2020 16:48:49 +0300 Subject: [PATCH 07/11] optimize source frame finding --- ext/fg/js/frame-offset-forwarder.js | 62 ++++++++++++++++------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/ext/fg/js/frame-offset-forwarder.js b/ext/fg/js/frame-offset-forwarder.js index 2b48ba26..c2df7581 100644 --- a/ext/fg/js/frame-offset-forwarder.js +++ b/ext/fg/js/frame-offset-forwarder.js @@ -22,6 +22,7 @@ class FrameOffsetForwarder { constructor() { this._started = false; + this._frameCache = new Set(); this._forwardFrameOffset = ( window !== window.parent ? @@ -73,20 +74,11 @@ class FrameOffsetForwarder { } _onGetFrameOffset(offset, uniqueId, e) { - let sourceFrame = null; - for (const frame of document.querySelectorAll('frame, iframe:not(.yomichan-float)')) { - if (frame.contentWindow !== e.source) { continue; } - sourceFrame = frame; - break; - } - + const sourceFrame = this._findFrameWithContentWindow(e.source); if (sourceFrame === null) { - sourceFrame = this._getOpenShadowRootSourceFrame(e.source); - if (!sourceFrame) { - // closed shadow root etc. - this._forwardFrameOffsetOrigin(null, uniqueId); - return; - } + // closed shadow root etc. + this._forwardFrameOffsetOrigin(null, uniqueId); + return; } const [forwardedX, forwardedY] = offset; @@ -96,22 +88,38 @@ class FrameOffsetForwarder { this._forwardFrameOffset(offset, uniqueId); } - _getOpenShadowRootSourceFrame(sourceWindow) { - const getShadowRootElements = (documentOrElement) => { - const elements = Array.from(documentOrElement.querySelectorAll('*')) - .filter((el) => !!el.shadowRoot); - const childElements = elements - .map((el) => el.shadowRoot) - .map(getShadowRootElements); - elements.push(childElements.flat()); + _findFrameWithContentWindow(contentWindow) { + const elements = [ + ...this._frameCache, + // will contain duplicates, but frame elements are cheap to handle + ...document.querySelectorAll('frame, iframe:not(.yomichan-float)'), + document.documentElement + ]; + 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) - .map((el) => Array.from(el.shadowRoot.querySelectorAll('frame, iframe:not(.yomichan-float)'))) - .flat() - .find((el) => el.contentWindow === sourceWindow); + for (const child of element.children) { + if (child.nodeType === ELEMENT_NODE) { + elements.push(child); + } + } + } + + return null; } _forwardFrameOffsetParent(offset, uniqueId) { From 66354f1f9e866fd31f6bb0365024a39697a54079 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 18 Apr 2020 17:18:33 +0300 Subject: [PATCH 08/11] lazy load element sources --- ext/fg/js/frame-offset-forwarder.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/ext/fg/js/frame-offset-forwarder.js b/ext/fg/js/frame-offset-forwarder.js index c2df7581..4b77d5ed 100644 --- a/ext/fg/js/frame-offset-forwarder.js +++ b/ext/fg/js/frame-offset-forwarder.js @@ -89,14 +89,27 @@ class FrameOffsetForwarder { } _findFrameWithContentWindow(contentWindow) { - const elements = [ - ...this._frameCache, + const elementSources = [ + () => [...this._frameCache], // will contain duplicates, but frame elements are cheap to handle - ...document.querySelectorAll('frame, iframe:not(.yomichan-float)'), - document.documentElement + () => [...document.querySelectorAll('frame, iframe:not(.yomichan-float)')], + () => [document.documentElement] ]; + const getMoreElements = () => { + while (true) { + const source = elementSources.shift(); + if (source) { + const elements = source(); + if (elements.length === 0) { continue; } + return elements; + } + return []; + } + }; + + const elements = []; const ELEMENT_NODE = Node.ELEMENT_NODE; - while (elements.length > 0) { + while (elements.length > 0 || elements.push(...getMoreElements())) { const element = elements.shift(); if (element.contentWindow === contentWindow) { this._frameCache.add(element); From 691b7398490bbf247070cd38603e51c7a6b66121 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 18 Apr 2020 17:54:49 +0300 Subject: [PATCH 09/11] cache closed shadow dom content windows --- ext/fg/js/frame-offset-forwarder.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ext/fg/js/frame-offset-forwarder.js b/ext/fg/js/frame-offset-forwarder.js index 4b77d5ed..72731605 100644 --- a/ext/fg/js/frame-offset-forwarder.js +++ b/ext/fg/js/frame-offset-forwarder.js @@ -23,6 +23,7 @@ class FrameOffsetForwarder { constructor() { this._started = false; this._frameCache = new Set(); + this._unreachableContentWindowCache = new Set(); this._forwardFrameOffset = ( window !== window.parent ? @@ -74,9 +75,13 @@ class FrameOffsetForwarder { } _onGetFrameOffset(offset, uniqueId, e) { - const sourceFrame = this._findFrameWithContentWindow(e.source); + let sourceFrame = null; + if (!this._unreachableContentWindowCache.has(e.source)) { + sourceFrame = this._findFrameWithContentWindow(e.source); + } if (sourceFrame === null) { // closed shadow root etc. + this._unreachableContentWindowCache.add(e.source); this._forwardFrameOffsetOrigin(null, uniqueId); return; } From a81c33b60aac0752ccca06f5183632146f6c6bf0 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 18 Apr 2020 22:08:38 +0300 Subject: [PATCH 10/11] simplify element source lazy load --- ext/fg/js/frame-offset-forwarder.js | 58 ++++++++++++----------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/ext/fg/js/frame-offset-forwarder.js b/ext/fg/js/frame-offset-forwarder.js index 72731605..f40c642d 100644 --- a/ext/fg/js/frame-offset-forwarder.js +++ b/ext/fg/js/frame-offset-forwarder.js @@ -94,52 +94,42 @@ class FrameOffsetForwarder { } _findFrameWithContentWindow(contentWindow) { - const elementSources = [ - () => [...this._frameCache], - // will contain duplicates, but frame elements are cheap to handle - () => [...document.querySelectorAll('frame, iframe:not(.yomichan-float)')], - () => [document.documentElement] - ]; - const getMoreElements = () => { - while (true) { - const source = elementSources.shift(); - if (source) { - const elements = source(); - if (elements.length === 0) { continue; } - return elements; - } - return []; - } - }; - - const elements = []; const ELEMENT_NODE = Node.ELEMENT_NODE; - while (elements.length > 0 || elements.push(...getMoreElements())) { - const element = elements.shift(); - if (element.contentWindow === contentWindow) { - this._frameCache.add(element); - return element; - } + for (const elements of this._getFrameElementSources()) { + while (elements.length > 0) { + const element = elements.shift(); + if (element.contentWindow === contentWindow) { + this._frameCache.add(element); + return element; + } - const shadowRoot = element.shadowRoot; - if (shadowRoot) { - for (const child of shadowRoot.children) { + const shadowRoot = element.shadowRoot; + if (shadowRoot) { + for (const child of shadowRoot.children) { + if (child.nodeType === ELEMENT_NODE) { + elements.push(child); + } + } + } + + for (const child of element.children) { if (child.nodeType === ELEMENT_NODE) { elements.push(child); } } } - - for (const child of element.children) { - if (child.nodeType === ELEMENT_NODE) { - elements.push(child); - } - } } return null; } + *_getFrameElementSources() { + yield [...this._frameCache]; + // will contain duplicates, but frame elements are cheap to handle + yield [...document.querySelectorAll('frame, iframe:not(.yomichan-float)')]; + yield [document.documentElement]; + } + _forwardFrameOffsetParent(offset, uniqueId) { window.parent.postMessage({action: 'getFrameOffset', params: {offset, uniqueId}}, '*'); } From d66ca93ce4d6a4c9814bac4cc508c24ff87b8f69 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 18 Apr 2020 22:26:11 +0300 Subject: [PATCH 11/11] cache invalidation --- ext/fg/js/frame-offset-forwarder.js | 29 ++++++++++++++++++++++++++--- ext/manifest.json | 2 +- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/ext/fg/js/frame-offset-forwarder.js b/ext/fg/js/frame-offset-forwarder.js index f40c642d..1a2f3e1e 100644 --- a/ext/fg/js/frame-offset-forwarder.js +++ b/ext/fg/js/frame-offset-forwarder.js @@ -22,6 +22,8 @@ class FrameOffsetForwarder { constructor() { this._started = false; + + this._cacheMaxSize = 1000; this._frameCache = new Set(); this._unreachableContentWindowCache = new Set(); @@ -81,7 +83,7 @@ class FrameOffsetForwarder { } if (sourceFrame === null) { // closed shadow root etc. - this._unreachableContentWindowCache.add(e.source); + this._addToCache(this._unreachableContentWindowCache, e.source); this._forwardFrameOffsetOrigin(null, uniqueId); return; } @@ -99,7 +101,7 @@ class FrameOffsetForwarder { while (elements.length > 0) { const element = elements.shift(); if (element.contentWindow === contentWindow) { - this._frameCache.add(element); + this._addToCache(this._frameCache, element); return element; } @@ -124,12 +126,33 @@ class FrameOffsetForwarder { } *_getFrameElementSources() { - yield [...this._frameCache]; + const frameCache = []; + for (const frame of this._frameCache) { + // removed from DOM + if (!frame.isConnected) { + this._frameCache.delete(frame); + continue; + } + frameCache.push(frame); + } + yield frameCache; // will contain duplicates, but frame elements are cheap to handle yield [...document.querySelectorAll('frame, iframe:not(.yomichan-float)')]; yield [document.documentElement]; } + _addToCache(cache, value) { + let freeSlots = this._cacheMaxSize - cache.size; + if (freeSlots <= 0) { + for (const cachedValue of cache) { + cache.delete(cachedValue); + ++freeSlots; + if (freeSlots > 0) { break; } + } + } + cache.add(value); + } + _forwardFrameOffsetParent(offset, uniqueId) { window.parent.postMessage({action: 'getFrameOffset', params: {offset, uniqueId}}, '*'); } diff --git a/ext/manifest.json b/ext/manifest.json index 452b642c..d383dab0 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -71,7 +71,7 @@ "applications": { "gecko": { "id": "alex@foosoft.net", - "strict_min_version": "52.0" + "strict_min_version": "53.0" } } }