Browse Source

fix: add generic font family fallbacks before Segoe UI Emoji to fix glyph rendering on windows (#9425)

Sachintha Lakmin 3 months ago
parent
commit
9e77373c81

+ 32 - 2
packages/common/src/constants.ts

@@ -147,19 +147,49 @@ export const FONT_FAMILY = {
   Assistant: 10,
 };
 
+// Segoe UI Emoji fails to properly fallback for some glyphs: ∞, ∫, ≠
+// so we need to have generic font fallback before it
+export const SANS_SERIF_GENERIC_FONT = "sans-serif";
+export const MONOSPACE_GENERIC_FONT = "monospace";
+
+export const FONT_FAMILY_GENERIC_FALLBACKS = {
+  [SANS_SERIF_GENERIC_FONT]: 998,
+  [MONOSPACE_GENERIC_FONT]: 999,
+};
+
 export const FONT_FAMILY_FALLBACKS = {
   [CJK_HAND_DRAWN_FALLBACK_FONT]: 100,
+  ...FONT_FAMILY_GENERIC_FALLBACKS,
   [WINDOWS_EMOJI_FALLBACK_FONT]: 1000,
 };
 
+export function getGenericFontFamilyFallback(
+  fontFamily: number,
+): keyof typeof FONT_FAMILY_GENERIC_FALLBACKS {
+  switch (fontFamily) {
+    case FONT_FAMILY.Cascadia:
+    case FONT_FAMILY["Comic Shanns"]:
+      return MONOSPACE_GENERIC_FONT;
+
+    default:
+      return SANS_SERIF_GENERIC_FONT;
+  }
+}
+
 export const getFontFamilyFallbacks = (
   fontFamily: number,
 ): Array<keyof typeof FONT_FAMILY_FALLBACKS> => {
+  const genericFallbackFont = getGenericFontFamilyFallback(fontFamily);
+
   switch (fontFamily) {
     case FONT_FAMILY.Excalifont:
-      return [CJK_HAND_DRAWN_FALLBACK_FONT, WINDOWS_EMOJI_FALLBACK_FONT];
+      return [
+        CJK_HAND_DRAWN_FALLBACK_FONT,
+        genericFallbackFont,
+        WINDOWS_EMOJI_FALLBACK_FONT,
+      ];
     default:
-      return [WINDOWS_EMOJI_FALLBACK_FONT];
+      return [genericFallbackFont, WINDOWS_EMOJI_FALLBACK_FONT];
   }
 };
 

+ 0 - 1
packages/common/src/utils.ts

@@ -103,7 +103,6 @@ export const getFontFamilyString = ({
 }) => {
   for (const [fontFamilyString, id] of Object.entries(FONT_FAMILY)) {
     if (id === fontFamily) {
-      // TODO: we should fallback first to generic family names first
       return `${fontFamilyString}${getFontFamilyFallbacks(id)
         .map((x) => `, ${x}`)
         .join("")}`;

+ 1 - 1
packages/element/tests/__snapshots__/linearElementEditor.test.tsx.snap

@@ -17,7 +17,7 @@ exports[`Test Linear Elements > Test bound text element > should match styles fo
   class="excalidraw-wysiwyg"
   data-type="wysiwyg"
   dir="auto"
-  style="position: absolute; display: inline-block; min-height: 1em; backface-visibility: hidden; margin: 0px; padding: 0px; border: 0px; outline: 0; resize: none; background: transparent; overflow: hidden; z-index: var(--zIndex-wysiwyg); word-break: break-word; white-space: pre-wrap; overflow-wrap: break-word; box-sizing: content-box; width: 10.5px; height: 26.25px; left: 35px; top: 7.5px; transform: translate(0px, 0px) scale(1) rotate(0deg); text-align: center; vertical-align: middle; color: rgb(30, 30, 30); opacity: 1; filter: var(--theme-filter); max-height: 992.5px; font: Emoji 20px 20px; line-height: 1.25; font-family: Excalifont, Xiaolai, Segoe UI Emoji;"
+  style="position: absolute; display: inline-block; min-height: 1em; backface-visibility: hidden; margin: 0px; padding: 0px; border: 0px; outline: 0; resize: none; background: transparent; overflow: hidden; z-index: var(--zIndex-wysiwyg); word-break: break-word; white-space: pre-wrap; overflow-wrap: break-word; box-sizing: content-box; width: 10.5px; height: 26.25px; left: 35px; top: 7.5px; transform: translate(0px, 0px) scale(1) rotate(0deg); text-align: center; vertical-align: middle; color: rgb(30, 30, 30); opacity: 1; filter: var(--theme-filter); max-height: 992.5px; font: Emoji 20px 20px; line-height: 1.25; font-family: Excalifont, Xiaolai, sans-serif, Segoe UI Emoji;"
   tabindex="0"
   wrap="off"
 />

+ 1 - 1
packages/excalidraw/tests/__snapshots__/export.test.tsx.snap

@@ -2,7 +2,7 @@
 
 exports[`export > export svg-embedded scene > svg-embdedded scene export output 1`] = `
 "<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="36" height="36"><!-- svg-source:excalidraw --><metadata><!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nHVTS27bMFx1MDAxMN33XHUwMDE0grItXHUwMDEy2UW68C7NXHUwMDA3zVwiXdRcdTAwMDW6KLpgxLE0ME1cdTAwMTLkKLZrXHUwMDE4yDG661x1MDAxNXOEXGZpVTTlRFx1MDAwMlxi8M3vzZvh7kNRlLS1UM6KXHUwMDEyNrVQKJ1Yl1x1MDAxZlx1MDAwM/5cdTAwMDTOo9Fsmsa7N52ro2dLZGdcdTAwMTdcdTAwMTfKcEBrPM0+VVV1XGJcdTAwMDJcdTAwMDUr0OTZ7Vx1MDAxN9+LYlx1MDAxN0+2oFxmoVfRLVx1MDAwMv/rXHUwMDEybCihXHUwMDFihqrhts1ua5TUMjL5PEAtYNNSjlx03SjIXHUwMDAyPTmzhGujjFx1MDAwYlx1MDAxNc8mXHUwMDEw/lT0UdTLxplOy8GHnNDeXG7HzSS/XHUwMDA1KjWnbczOerBa5ajGz57idIS/XHUwMDE3xUWbVoNcdTAwMGaCTVx1MDAwNtRYUSOF5idV6lwiMLT3Mmr7O3FyYlx1MDAwNfdBXFzdKTXAqCVsxmBssa+WXHUwMDE5PIDMXHUwMDE4pOGfYN+MrnN50d/w3CmmWFxi5SFcdFx1MDAxYlxu3qadyIp2VlxuXHUwMDFh1VWol2M/3rPlXHUwMDFiuePesKIv//4+XHUwMDFmjchomuOfQHBaZeidWKFcbppeZimuXHUwMDE0NqHPUsHiaNTcLCHv92AmY5O15nxcdTAwMDI1uFPhjcNcdTAwMDa1UD/epCc6Mt/BXHUwMDFmXGKS6+C4c/g6bPP59DJcdTAwMWH2fMZZl8LaObFebD28Kd5cdTAwMDeUo1ZcdTAwMGZcdTAwMTiBTW1G6MFIuNXiUY11LJ9cdTAwMTDWX07X/2xcdTAwMTG/nng/godOXHUwMDExznnUNfFcdTAwMWWEee5cdTAwMDK/feTHb1x1MDAwM3po/1xua2IoWiJ9<!-- payload-end --></metadata><defs><style class="style-fonts">
-      </style></defs><rect x="0" y="0" width="36" height="36" fill="#ffffff"></rect><g transform="translate(10 10) rotate(0 8 8)" data-id="A"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">😀</text></g></svg>"
+      </style></defs><rect x="0" y="0" width="36" height="36" fill="#ffffff"></rect><g transform="translate(10 10) rotate(0 8 8)" data-id="A"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, sans-serif, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">😀</text></g></svg>"
 `;
 
 exports[`export > exporting svg containing transformed images > svg export output 1`] = `

File diff suppressed because it is too large
+ 5 - 5
packages/excalidraw/tests/scene/__snapshots__/export.test.ts.snap


Some files were not shown because too many files changed in this diff