From 3413450d564d99636c935966b09274a6c23ebc19 Mon Sep 17 00:00:00 2001 From: Cesar Gonzalez Date: Thu, 13 Jun 2024 10:44:32 -0500 Subject: [PATCH] [PM-5189] Implementing a methodology for triggering subframe updates from layout-shift --- .../abstractions/overlay.background.ts | 3 ++- .../autofill/background/overlay.background.ts | 18 ++++++++++++------ .../autofill-overlay-content.service.ts | 13 ++++++++++--- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/apps/browser/src/autofill/background/abstractions/overlay.background.ts b/apps/browser/src/autofill/background/abstractions/overlay.background.ts index ff98499f445..94e13bab2ca 100644 --- a/apps/browser/src/autofill/background/abstractions/overlay.background.ts +++ b/apps/browser/src/autofill/background/abstractions/overlay.background.ts @@ -65,6 +65,7 @@ export type OverlayBackgroundExtensionMessage = { subFrameData?: SubFrameOffsetData; focusedFieldData?: FocusedFieldData; styles?: Partial; + triggerInlineMenuPositionUpdate?: boolean; data?: LockedVaultPendingNotificationsData; } & OverlayAddNewItemMessage & CloseInlineMenuMessage; @@ -120,7 +121,7 @@ export type OverlayBackgroundExtensionMessageHandlers = { checkShouldRepositionInlineMenu: ({ sender }: BackgroundSenderParam) => boolean; getCurrentTabFrameId: ({ sender }: BackgroundSenderParam) => number; updateSubFrameData: ({ message, sender }: BackgroundOnMessageHandlerParams) => void; - rebuildSubFrameOffsets: ({ sender }: BackgroundSenderParam) => void; + rebuildSubFrameOffsets: ({ message, sender }: BackgroundOnMessageHandlerParams) => void; destroyAutofillInlineMenuListeners: ({ message, sender, diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index fee2d21f740..b25b4c800cc 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -95,7 +95,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { checkShouldRepositionInlineMenu: ({ sender }) => this.checkShouldRepositionInlineMenu(sender), getCurrentTabFrameId: ({ sender }) => this.getSenderFrameId(sender), updateSubFrameData: ({ message, sender }) => this.updateSubFrameData(message, sender), - rebuildSubFrameOffsets: ({ sender }) => this.rebuildSubFrameOffsets(sender), + rebuildSubFrameOffsets: ({ message, sender }) => this.rebuildSubFrameOffsets(message, sender), destroyAutofillInlineMenuListeners: ({ message, sender }) => this.triggerDestroyInlineMenuListeners(sender.tab, message.subFrameData.frameId), collectPageDetailsResponse: ({ message, sender }) => this.storePageDetails(message, sender), @@ -382,9 +382,13 @@ export class OverlayBackground implements OverlayBackgroundInterface { * the field currently focused. We trigger a re-calculation of the field's position * and as a result, the sub frame offsets of that frame will be updated. * + * @param message - The message received from the `rebuildSubFrameOffsets` command * @param sender - The sender of the message */ - private async rebuildSubFrameOffsets(sender: chrome.runtime.MessageSender) { + private async rebuildSubFrameOffsets( + message: OverlayBackgroundExtensionMessage, + sender: chrome.runtime.MessageSender, + ) { if (sender.frameId === this.focusedFieldData?.frameId) { return; } @@ -406,10 +410,12 @@ export class OverlayBackground implements OverlayBackgroundInterface { } } - this.updateInlineMenuPositionTimeout = globalThis.setTimeout( - () => this.updateInlineMenuPositionAfterSubFrameRebuild(sender), - 650, - ); + if (message.triggerInlineMenuPositionUpdate) { + this.updateInlineMenuPositionTimeout = globalThis.setTimeout( + () => this.updateInlineMenuPositionAfterSubFrameRebuild(sender), + 650, + ); + } } /** diff --git a/apps/browser/src/autofill/services/autofill-overlay-content.service.ts b/apps/browser/src/autofill/services/autofill-overlay-content.service.ts index 978ef4a1804..771509e951b 100644 --- a/apps/browser/src/autofill/services/autofill-overlay-content.service.ts +++ b/apps/browser/src/autofill/services/autofill-overlay-content.service.ts @@ -43,6 +43,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ private focusedFieldData: FocusedFieldData; private userInteractionEventTimeout: number | NodeJS.Timeout; private recalculateSubFrameOffsetsTimeout: number | NodeJS.Timeout; + private performanceObserver: PerformanceObserver; private autofillFieldKeywordsMap: WeakMap = new WeakMap(); private eventHandlersMemo: { [key: string]: EventListener } = {}; private readonly extensionMessageHandlers: AutofillOverlayContentExtensionMessageHandlers = { @@ -786,6 +787,8 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ capture: true, }); globalThis.addEventListener(EVENTS.RESIZE, this.handleOverlayRepositionEvent); + this.performanceObserver = new PerformanceObserver(() => this.rebuildSubFrameOffsets(0, false)); + this.performanceObserver.observe({ type: "layout-shift", buffered: true }); } /** @@ -820,11 +823,14 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ /** * Triggers a rebuild of a sub frame's offsets within the tab. */ - private rebuildSubFrameOffsets() { + private rebuildSubFrameOffsets(delay: number = 150, triggerInlineMenuPositionUpdate = true) { this.clearRecalculateSubFrameOffsetsTimeout(); this.recalculateSubFrameOffsetsTimeout = globalThis.setTimeout( - () => void this.sendExtensionMessage("rebuildSubFrameOffsets"), - 150, + () => + void this.sendExtensionMessage("rebuildSubFrameOffsets", { + triggerInlineMenuPositionUpdate, + }), + delay, ); } @@ -1161,6 +1167,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ this.handleVisibilityChangeEvent, ); globalThis.removeEventListener(EVENTS.FOCUSOUT, this.handleFormFieldBlurEvent); + this.performanceObserver?.disconnect(); this.removeOverlayRepositionEventListeners(); } }