本系列目錄 《來做個網路瀏覽器吧!》文章列表

今天來介紹 font-family

當我們對 CSS 定義「字形」的時候,會使用 font-family

p {
    font-family: "Times New Roman", Georgia, Serif;
}

font-family 由一串字型名稱組成,預設是瀏覽器會選取第一個字型來呈現,以上面例子來說,假設你的電腦有 Times New Roman 這個字型,就會用它來呈現文字;若是沒有的話,則檢查下一個,也就是 Georgia 是否有。如果 font-family 定義的字型都沒有,就會採用瀏覽器預設的字型。

想了解更多的話可以看 MDN 或是 W3C 的文件。

而今天要特別講的是預設字型的「回調」
以下這串字:

のコ Hello 你好嗎 안녕하세요 Cześć Olá Здравствуйте ♫

並不是單一字型就能處理的,即使是預設字型,也要好幾種才能把這串字呈現出來。

所以概念就是一串字,我們先試試看 font-family 的順序看能不能把字元呈現,不行的話就使用瀏覽器預設的字型,瀏覽器預設的一樣有順序,就照順序直到可以顯示出來為止。


本系列本來都是用 Servo 介紹,不過目前的寫法並沒有實踐 font-family,不管如何都直接採用預設的字型。相關的程式碼在這邊。但也因為還沒實踐,所以就不拿來舉例,若是大家有興趣可以一起來貢獻把它完成。

不過 Firefox 的 Gecko 理所當然有把它實踐囉!
這邊來看 Gecko 針對 Windows 平台的程式碼,因為不同平台的處理方式還是有差異,所以處理字型的部分有特別切開。

Gecko 使用 GetCommonFallbackFonts 這個函式來處理字型。

gfxWindowsPlatform::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
                                           Script aRunScript,
                                           nsTArray<const char*>& aFontList)
{
    EmojiPresentation emoji = GetEmojiPresentation(aCh);
    if (emoji != EmojiPresentation::TextOnly) {
        if (aNextCh == kVariationSelector16 ||
           (aNextCh != kVariationSelector15 &&
            emoji == EmojiPresentation::EmojiDefault)) {
            // if char is followed by VS16, try for a color emoji glyph
            aFontList.AppendElement(kFontSegoeUIEmoji);
            aFontList.AppendElement(kFontEmojiOneMozilla);
        }
    }

    // Arial is used as the default fallback for system fallback
    aFontList.AppendElement(kFontArial);

    if (!IS_IN_BMP(aCh)) {
        uint32_t p = aCh >> 16;
        if (p == 1) { // SMP plane
            aFontList.AppendElement(kFontSegoeUISymbol);
            aFontList.AppendElement(kFontEbrima);
            aFontList.AppendElement(kFontNirmalaUI);
            aFontList.AppendElement(kFontCambriaMath);
        }
    } else {
        uint32_t b = (aCh >> 8) & 0xff;

        switch (b) {
        case 0x05:
            aFontList.AppendElement(kFontEstrangeloEdessa);
            aFontList.AppendElement(kFontCambria);
            break;
        case 0x06:
            aFontList.AppendElement(kFontMicrosoftUighur);
            break;
        case 0x07:
            aFontList.AppendElement(kFontEstrangeloEdessa);
            aFontList.AppendElement(kFontMVBoli);
            aFontList.AppendElement(kFontEbrima);
            break;
        case 0x09:
            aFontList.AppendElement(kFontNirmalaUI);
            aFontList.AppendElement(kFontUtsaah);
            aFontList.AppendElement(kFontAparajita);
            break;
        case 0x0a:
        case 0x0b:
        case 0x0c:
        case 0x0d:
            aFontList.AppendElement(kFontNirmalaUI);
            break;
        case 0x0e:
        // ...
        // ...
        // 中間省略
        // ...
        // ...
       case 0xff:
            aFontList.AppendElement(kFontMicrosoftJhengHei);
            break;
        default:
            break;
        }
    }

    // Arial Unicode MS has lots of glyphs for obscure characters,
    // use it as a last resort
    aFontList.AppendElement(kFontArialUnicodeMS);
}

可以看到光瀏覽器預設字型就超過四十種,這也是因為各種奇形怪狀的符號實在太多,不同國家的文字使用的字型也不一樣,為了讓各種字元都能顯示,才不會出現顯示不出來變成框框的情形。


希望對大家有幫助,我們明天見!