diff --git a/ext/fg/js/frame-offset-forwarder.js b/ext/fg/js/frame-offset-forwarder.js index 38fc0b03..c32c2ec1 100644 --- a/ext/fg/js/frame-offset-forwarder.js +++ b/ext/fg/js/frame-offset-forwarder.js @@ -41,7 +41,7 @@ class FrameOffsetForwarder { this._started = true; } - async applyOffset(x, y) { + async getOffset() { const uniqueId = yomichan.generateId(16); const frameOffsetPromise = yomichan.getTemporaryListenerResult( @@ -58,7 +58,7 @@ class FrameOffsetForwarder { action: 'getFrameOffset', params: { uniqueId, - offset: [x, y] + offset: [0, 0] } }, '*'); diff --git a/ext/fg/js/frontend-initialize.js b/ext/fg/js/frontend-initialize.js index 97e315b5..2f86f5c8 100644 --- a/ext/fg/js/frontend-initialize.js +++ b/ext/fg/js/frontend-initialize.js @@ -45,9 +45,9 @@ async function main() { const frameOffsetForwarder = new FrameOffsetForwarder(); frameOffsetForwarder.start(); - const applyFrameOffset = frameOffsetForwarder.applyOffset.bind(frameOffsetForwarder); + const getFrameOffset = frameOffsetForwarder.getOffset.bind(frameOffsetForwarder); - popup = new PopupProxy(popupId, 0, null, frameId, url, applyFrameOffset); + popup = new PopupProxy(popupId, 0, null, frameId, url, getFrameOffset); await popup.prepare(); } else if (proxy) { popup = new PopupProxy(null, depth + 1, id, parentFrameId, url); diff --git a/ext/fg/js/popup-proxy.js b/ext/fg/js/popup-proxy.js index a25f9183..0cd5bbad 100644 --- a/ext/fg/js/popup-proxy.js +++ b/ext/fg/js/popup-proxy.js @@ -21,14 +21,18 @@ */ class PopupProxy { - constructor(id, depth, parentId, parentFrameId, url, applyFrameOffset=null) { + constructor(id, depth, parentId, parentFrameId, url, getFrameOffset=null) { this._parentId = parentId; this._parentFrameId = parentFrameId; this._id = id; this._depth = depth; this._url = url; this._apiSender = new FrontendApiSender(); - this._applyFrameOffset = applyFrameOffset; + this._getFrameOffset = getFrameOffset; + + this._frameOffset = null; + this._frameOffsetPromise = null; + this._frameOffsetUpdatedAt = null; } // Public properties @@ -81,16 +85,18 @@ class PopupProxy { } async containsPoint(x, y) { - if (this._applyFrameOffset !== null) { - [x, y] = await this._applyFrameOffset(x, y); + if (this._getFrameOffset !== null) { + await this._updateFrameOffset(); + [x, y] = this._applyFrameOffset(x, y); } return await this._invokeHostApi('containsPoint', {id: this._id, x, y}); } async showContent(elementRect, writingMode, type=null, details=null) { let {x, y, width, height} = elementRect; - if (this._applyFrameOffset !== null) { - [x, y] = await this._applyFrameOffset(x, y); + if (this._getFrameOffset !== null) { + await this._updateFrameOffset(); + [x, y] = this._applyFrameOffset(x, y); } elementRect = {x, y, width, height}; return await this._invokeHostApi('showContent', {id: this._id, elementRect, writingMode, type, details}); @@ -116,4 +122,32 @@ class PopupProxy { } return this._apiSender.invoke(action, params, `popup-proxy-host#${this._parentFrameId}`); } + + async _updateFrameOffset() { + const firstRun = this._frameOffsetUpdatedAt === null; + const expired = firstRun || this._frameOffsetUpdatedAt < Date.now() - 1000; + if (this._frameOffsetPromise === null && !expired) { return; } + + if (this._frameOffsetPromise !== null) { + await this._frameOffsetPromise; + return; + } + + if (firstRun) { + this._frameOffsetPromise = this._getFrameOffset(); + this._frameOffset = await this._frameOffsetPromise; + this._frameOffsetPromise = null; + this._frameOffsetUpdatedAt = Date.now(); + } else { + this._getFrameOffset().then((offset) => { + this._frameOffset = offset; + this._frameOffsetUpdatedAt = Date.now(); + }); + } + } + + _applyFrameOffset(x, y) { + const [offsetX, offsetY] = this._frameOffset; + return [x + offsetX, y + offsetY]; + } }