L'API Local Font Access fournit un mécanisme permettant d'accéder aux données de police installées localement par l'utilisateur, y compris des détails de niveau supérieur tels que les noms, les styles et les familles, ainsi qu'aux octets bruts des fichiers de police sous-jacents. Découvrez comment l'application d'édition SVG Boxy utilise cette API.
Introduction
(Cet article est également disponible sous forme de vidéo.)
Le SVG Boxy est un éditeur de graphiques vectoriels. Son principal cas d'utilisation consiste à modifier des dessins au format SVG, afin de créer des illustrations, des logos, des icônes et d'autres éléments de conception graphique. Il a été développé par le développeur polonais Jarosław Foksa et est sorti le 15 mars 2013. Jarosław tient un blog Boxy SVG dans lequel il annonce les nouvelles fonctionnalités qu'il ajoute à l'application. Le développeur est un fervent défenseur du projet Fugu de Chromium et a même ajouté une balise Fugu dans l'outil de suivi des idées de l'application.
API Local Font Access dans le SVG Boxy
Jarosław a mentionné un ajout de fonctionnalité : l'API Local Font Access. L'API Local Font Access permet aux utilisateurs d'accéder aux polices installées localement, y compris aux détails de niveau supérieur tels que les noms, les styles et les familles, ainsi qu'aux octets bruts des fichiers de police sous-jacents. Dans la capture d'écran suivante, vous pouvez voir comment j'ai autorisé l'application à accéder aux polices installées localement sur mon MacBook et à choisir la police Marker Felt pour mon texte.
Le code sous-jacent est assez simple. Lorsque l'utilisateur ouvre le sélecteur de famille de polices pour la première fois, l'application vérifie d'abord si le navigateur Web prend en charge l'API Local Font Access.
Il recherche également l'ancienne version expérimentale de l'API et l'utilise, le cas échéant. Depuis 2023, vous pouvez ignorer l'ancienne API en toute sécurité, car elle n'était disponible que pendant une courte période grâce aux indicateurs Chrome expérimentaux, mais il est possible que certains dérivés de Chromium l'utilisent encore.
let isLocalFontsApiEnabled = (
// Local Font Access API, Chrome >= 102
window.queryLocalFonts !== undefined ||
// Experimental Local Font Access API, Chrome < 102
navigator.fonts?.query !== undefined
);
Si l'API Local Font Access n'est pas disponible, l'outil de sélection de famille de polices devient gris. Un espace réservé s'affichera pour l'utilisateur à la place de la liste des polices:
if (isLocalFontsApiEnabled === false) {
showPlaceholder("no-local-fonts-api");
return;
}
Sinon, l'API Local Font Access est utilisée pour récupérer la liste de toutes les polices du système d'exploitation. Notez le bloc try…catch
, qui est nécessaire pour gérer correctement les erreurs d'autorisation.
let localFonts;
if (isLocalFontsApiEnabled === true) {
try {
// Local Font Access API, Chrome >= 102
if (window.queryLocalFonts) {
localFonts = await window.queryLocalFonts();
}
// Experimental Local Font Access API, Chrome < 102
else if (navigator.fonts?.query) {
localFonts = await navigator.fonts.query({
persistentAccess: true,
});
}
} catch (error) {
showError(error.message, error.name);
}
}
Une fois la liste des polices locales récupérée, une fontsIndex
simplifiée et normalisée est créée à partir de celle-ci:
let fontsIndex = [];
for (let localFont of localFonts) {
let face = "400";
// Determine the face name
{
let subfamily = localFont.style.toLowerCase();
subfamily = subfamily.replaceAll(" ", "");
subfamily = subfamily.replaceAll("-", "");
subfamily = subfamily.replaceAll("_", "");
if (subfamily.includes("thin")) {
face = "100";
} else if (subfamily.includes("extralight")) {
face = "200";
} else if (subfamily.includes("light")) {
face = "300";
} else if (subfamily.includes("medium")) {
face = "500";
} else if (subfamily.includes("semibold")) {
face = "600";
} else if (subfamily.includes("extrabold")) {
face = "800";
} else if (subfamily.includes("ultrabold")) {
face = "900";
} else if (subfamily.includes("bold")) {
face = "700";
}
if (subfamily.includes("italic")) {
face += "i";
}
}
let descriptor = fontsIndex.find((descriptor) => {
return descriptor.family === localFont.family);
});
if (descriptor) {
if (descriptor.faces.includes(face) === false) {
descriptor.faces.push(face);
}
} else {
let descriptor = {
family: localFont.family,
faces: [face],
};
fontsIndex.push(descriptor);
}
}
for (let descriptor of fontsIndex) {
descriptor.faces.sort();
}
L'index des polices normalisées est ensuite stocké dans la base de données IndexedDB afin d'être facilement interrogé, partagé entre les instances d'application et conservé d'une session à l'autre. Le SVG Boxy utilise Dexie.js pour gérer la base de données:
let database = new Dexie("LocalFontsManager");
database.version(1).stores({cache: "family"}).
await database.cache.clear();
await database.cache.bulkPut(fontsIndex);
Une fois la base de données renseignée, le widget de sélection de police peut l'interroger et afficher les résultats à l'écran:
Notez que le SVG Boxy affiche la liste dans un élément personnalisé nommé <bx-fontfamilypicker>
et applique un style à chaque élément de la liste de polices pour qu'il s'affiche dans la famille de polices concernée. Pour isoler le contenu du reste de la page, le SVG Boxy utilise le Shadow DOM dans cet élément et dans d'autres éléments personnalisés.
Conclusions
La fonctionnalité de police locale est très populaire, et les utilisateurs apprécient d'avoir accès à leurs polices locales pour leurs conceptions et leurs créations. Lorsque la forme de l'API a changé et que la fonctionnalité a cessé de fonctionner brièvement, les utilisateurs en ont immédiatement noté l'existence. Jarosław a rapidement remplacé le code par le schéma défensif de l'extrait ci-dessus, qui fonctionne avec les toutes dernières versions de Chrome et d'autres versions dérivées de Chromium qui n'ont peut-être pas encore adopté la dernière version. Essayez le SVG Boxy et assurez-vous de vérifier les polices installées localement. Vous découvrirez peut-être des classiques oubliés depuis longtemps, comme Zapf Dingbats ou Webdings.