Skip to content
Draft
52 changes: 52 additions & 0 deletions src/vs/platform/browserView/common/browserFaviconLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Disposable } from '../../../base/common/lifecycle.js';
import { ILogService } from '../../log/common/log.js';

export class BrowserFaviconLoader extends Disposable {
private _requestId = 0;

constructor(
private readonly fetchFavicon: (url: string) => Promise<string>,
private readonly applyFavicon: (favicon: string | undefined) => void,
@ILogService private readonly logService: ILogService,
) {
super();
}

invalidate(): void {
this._requestId++;
}

async load(urls: readonly string[]): Promise<void> {
if (this._store.isDisposed) {
return;
}
const requestId = ++this._requestId;
for (const url of urls) {
let favicon: string | undefined;
try {
favicon = await this.fetchFavicon(url);
} catch (error) {
this.logService.trace('[BrowserFaviconLoader] Failed to fetch favicon, trying the next candidate.', error);
}
if (!this.isCurrent(requestId)) {
return;
}
if (favicon !== undefined) {
this.applyFavicon(favicon);
return;
}
}
if (this.isCurrent(requestId)) {
this.applyFavicon(undefined);
}
}

private isCurrent(requestId: number): boolean {
return requestId === this._requestId && !this._store.isDisposed;
}
}
26 changes: 18 additions & 8 deletions src/vs/platform/browserView/common/browserView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,19 +323,25 @@ export interface IBrowserViewStorageKeys {
readonly permissions?: string;
}

export interface IBrowserViewState {
/** Lightweight state used to reconcile navigation without transferring screenshots or session data. */
export interface IBrowserViewNavigationState {
/** Monotonic version shared by navigation, title, loading, and favicon updates. */
navigationStateVersion: number;
url: string;
title: string;
canGoBack: boolean;
canGoForward: boolean;
loading: boolean;
lastFavicon: string | undefined;
lastError: IBrowserViewLoadError | undefined;
certificateError: IBrowserViewCertificateError | undefined;
}

export interface IBrowserViewState extends IBrowserViewNavigationState {
focused: boolean;
visible: boolean;
isDevToolsOpen: boolean;
lastScreenshot: VSBuffer | undefined;
lastFavicon: string | undefined;
lastError: IBrowserViewLoadError | undefined;
certificateError: IBrowserViewCertificateError | undefined;
storageScope: BrowserViewStorageScope;
storageKeys: IBrowserViewStorageKeys;
permissions: ISerializedBrowserPermissionsSnapshot;
Expand All @@ -348,6 +354,7 @@ export interface IBrowserViewState {
}

export interface IBrowserViewNavigationEvent {
navigationStateVersion: number;
url: string;
title: string;
canGoBack: boolean;
Expand All @@ -356,6 +363,7 @@ export interface IBrowserViewNavigationEvent {
}

export interface IBrowserViewLoadingEvent {
navigationStateVersion: number;
loading: boolean;
error?: IBrowserViewLoadError;
}
Expand Down Expand Up @@ -403,10 +411,12 @@ export interface IBrowserViewKeyDownEvent {
}

export interface IBrowserViewTitleChangeEvent {
navigationStateVersion: number;
title: string;
}

export interface IBrowserViewFaviconChangeEvent {
navigationStateVersion: number;
favicon: string | undefined;
}

Expand Down Expand Up @@ -560,13 +570,13 @@ export interface IBrowserViewService {
setOwner(id: string, owner: IBrowserViewOwner): Promise<void>;

/**
* Get the state of an existing browser view by ID, or throw if it doesn't exist
* @param id The browser view identifier
* @return The state of the browser view for the given ID
* @throws If no browser view exists for the given ID
* Get the current state, or throw if the view doesn't exist.
*/
getState(id: string): Promise<IBrowserViewState>;

/** Subscribe before reading this snapshot and use its version to reconcile navigation-related events. */
getNavigationState(id: string): Promise<IBrowserViewNavigationState>;

/**
* Adds an audience or, when disabled, removes every audience matching it.
*/
Expand Down
Loading