Local Font Access API מספק מנגנון לגישה לנתוני הגופנים שמותקנים באופן מקומי אצל המשתמש, כולל פרטים ברמה גבוהה יותר כמו שמות, סגנונות ומשפחות, וגם הבייטים הגולמיים של קובצי הגופנים הבסיסיים. איך אפליקציית העריכה של קובצי SVG, Boxy SVG, משתמשת ב-API הזה.
מבוא
(המאמר הזה זמין גם כסרטון).
Boxy SVG הוא עורך גרפיקת וקטורים. התרחיש העיקרי לשימוש בו הוא עריכת ציורים בפורמט קובץ SVG, ליצירת איורים, סמלי לוגו, סמלים ורכיבים אחרים של עיצוב גרפי. הכלי הזה פותח על ידי המפתח הפולני Jarosław Foksa, והוא שוחרר לראשונה ב-15 במרץ 2013. Jarosław מנהל את בלוג Boxy SVG שבו הוא מכריז על תכונות חדשות שהוא מוסיף לאפליקציה. המפתח תומך מאוד בפרויקט Fugu של Chromium, ואפילו יש לו תג Fugu במעקב הרעיונות של האפליקציה.
Local Font Access API ב-Boxy SVG
אחת מהתכונות שנוספו, שג'ארוסלב כתב עליה בבלוג, היא Local Font Access API. Local Font Access API מאפשר למשתמשים לגשת לגופנים שהותקנו באופן מקומי, כולל פרטים ברמה גבוהה יותר כמו שמות, סגנונות ומשפחות, וגם הבייטים הגולמיים של קובצי הגופנים הבסיסיים. בצילום המסך הבא אפשר לראות איך העניקתי לאפליקציה גישה לגופנים שהותקנו באופן מקומי ב-MacBook ובחרתי את הגופן Marker Felt לטקסט שלי.
הקוד הבסיסי פשוט למדי. כשהמשתמש פותח את הבורר של משפחת הגופנים בפעם הראשונה, האפליקציה בודקת קודם אם דפדפן האינטרנט תומך ב-Local Font Access API.
הוא גם בודק אם יש גרסה ניסיונית ישנה של ה-API, ומשתמש בה אם היא קיימת. החל משנת 2023, אפשר להתעלם בבטחה מה-API הישן כי הוא היה זמין רק לזמן קצר באמצעות דגלים ניסיוניים של Chrome, אבל יכול להיות שחלק מהנגזרות של Chromium עדיין ישתמשו בו.
let isLocalFontsApiEnabled = (
// Local Font Access API, Chrome >= 102
window.queryLocalFonts !== undefined ||
// Experimental Local Font Access API, Chrome < 102
navigator.fonts?.query !== undefined
);
אם Local Font Access API לא זמין, הבורר של משפחות הגופנים יהפוך לאפור. טקסט placeholder יוצג למשתמש במקום רשימת הגופנים:
if (isLocalFontsApiEnabled === false) {
showPlaceholder("no-local-fonts-api");
return;
}
אחרת, המערכת משתמשת ב-Local Font Access API כדי לאחזר את רשימת כל הגופנים ממערכת ההפעלה. שימו לב לבלוק try…catch
שנחוץ כדי לטפל בשגיאות הרשאה בצורה תקינה.
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);
}
}
אחרי אחזור רשימת הגופנים המקומיים, נוצר ממנה fontsIndex
פשוט ומנורמלי:
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();
}
לאחר מכן, מדד הגופנים המנורמלים נשמר במסד הנתונים של IndexedDB, כך שאפשר להריץ עליו שאילתות בקלות, לשתף אותו בין מכונות של אפליקציות ולשמור אותו בין סשנים. ב-Boxy SVG נעשה שימוש ב-Dexie.js לניהול מסד הנתונים:
let database = new Dexie("LocalFontsManager");
database.version(1).stores({cache: "family"}).
await database.cache.clear();
await database.cache.bulkPut(fontsIndex);
אחרי שנתוני מסד הנתונים יאוכלסו, הווידג'ט לבחירת גופנים יוכל להריץ בו שאילתה ולהציג את התוצאות במסך:
חשוב לציין ש-Boxy SVG מעבד את הרשימה ברכיב מותאם אישית בשם <bx-fontfamilypicker>
, ומגדיר סגנון לכל פריט ברשימה של הגופנים כך שיוצג במשפחת הגופנים הספציפית. כדי לבודד את Boxy SVG משאר הדף, הרכיב הזה ורכיבים מותאמים אישית אחרים משתמשים ב-Shadow DOM.
מסקנות
התכונה 'גופנים מקומיים' הייתה פופולרית מאוד, והמשתמשים נהנו מגישה לגופנים המקומיים שלהם לצורך עיצובים ויצירות. כשצורת ה-API השתנתה והתכונה התקלקלה לזמן קצר, המשתמשים הבחינו בכך מיד. Jarosław שינה במהירות את הקוד לדפוס ההגנה שמוצג בקטע הקוד שלמעלה, שפועל עם Chrome המעודכן וגם עם נגזרות אחרות של Chromium שאולי לא עברו לגרסה האחרונה. כדאי לנסות את Boxy SVG ולבדוק את הגופנים שמותקנים במחשב. יכול להיות שתגלו גופנים קלאסיים שנשכחו מזמן, כמו Zapf Dingbats או Webdings.