Local Font Access API מספק מנגנון לגישה לנתוני הגופנים שהותקנו באופן מקומי אצל המשתמש, כולל פרטים ברמה גבוהה יותר כמו שמות, סגנונות ומשפחות, וגם הבייטים הגולמיים של קובצי הגופנים הבסיסיים. איך אפליקציית העריכה של קובצי SVG, Boxy SVG, משתמשת ב-API הזה.
מבוא
(המאמר הזה זמין גם כסרטון).
Boxy SVG הוא עורך גרפיקת וקטורים. תרחישים לדוגמה שבהם כדאי להשתמש ב-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 ובחרתי בגופן Markup 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.