mirror of
https://github.com/servo/servo
synced 2026-04-26 17:45:19 +02:00
Instead of using a simple `Atom` to identify a local font, use a data
structure. This allows us to carry more information necessary to
identify a local font (such as a path on MacOS). We need this for the
new version of WebRender, as fonts on MacOS now require a path.
This has a lot of benefits:
1. We can avoid loading fonts without paths on MacOS, which should
avoid a lot of problems with flakiness and ensure we always load the
same font for a given identifier.
2. This clarifies the difference between web fonts and local fonts,
though there is more work to do here.
3. This avoid a *lot* of font shenanigans, such as trying to work
backwards from the name of the font to the path of the font we
actually matched. In general, we can remove a lot of code trying to
accomplish these shenanigans.
4. Getting the font bytes always returns an `Arc` now avoiding an extra
full font copy in the case of Canvas.
336 lines
14 KiB
Rust
336 lines
14 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
use std::collections::HashMap;
|
|
use std::hash::Hash;
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use dwrote::{FontCollection, FontDescriptor};
|
|
use lazy_static::lazy_static;
|
|
use serde::{Deserialize, Serialize};
|
|
use servo_atoms::Atom;
|
|
use ucd::{Codepoint, UnicodeBlock};
|
|
|
|
use crate::text::util::unicode_plane;
|
|
|
|
pub static SANS_SERIF_FONT_FAMILY: &str = "Arial";
|
|
|
|
pub fn system_default_family(_: &str) -> Option<String> {
|
|
Some("Verdana".to_owned())
|
|
}
|
|
|
|
pub fn for_each_available_family<F>(mut callback: F)
|
|
where
|
|
F: FnMut(String),
|
|
{
|
|
let system_fc = FontCollection::system();
|
|
for family in system_fc.families_iter() {
|
|
callback(family.name());
|
|
}
|
|
}
|
|
|
|
/// An identifier for a local font on a Windows system.
|
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
|
pub struct LocalFontIdentifier {
|
|
/// The FontDescriptor of this font.
|
|
pub font_descriptor: Arc<FontDescriptor>,
|
|
}
|
|
|
|
impl Eq for LocalFontIdentifier {}
|
|
|
|
impl Hash for LocalFontIdentifier {
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
self.font_descriptor.family_name.hash(state);
|
|
self.font_descriptor.weight.to_u32().hash(state);
|
|
self.font_descriptor.stretch.to_u32().hash(state);
|
|
self.font_descriptor.style.to_u32().hash(state);
|
|
}
|
|
}
|
|
|
|
// for_each_variation is supposed to return a string that can be
|
|
// atomized and then uniquely used to return back to this font.
|
|
// Some platforms use the full postscript name (MacOS X), or
|
|
// a font filename.
|
|
//
|
|
// For windows we're going to use just a basic integer value that
|
|
// we'll stringify, and then put them all in a HashMap with
|
|
// the actual FontDescriptor there.
|
|
|
|
pub fn for_each_variation<F>(family_name: &str, mut callback: F)
|
|
where
|
|
F: FnMut(LocalFontIdentifier),
|
|
{
|
|
let system_fc = FontCollection::system();
|
|
if let Some(family) = system_fc.get_font_family_by_name(family_name) {
|
|
let count = family.get_font_count();
|
|
for i in 0..count {
|
|
let font = family.get_font(i);
|
|
callback(LocalFontIdentifier {
|
|
font_descriptor: Arc::new(font.to_descriptor()),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// Based on gfxWindowsPlatform::GetCommonFallbackFonts() in Gecko
|
|
pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
|
let mut families = vec!["Arial"];
|
|
|
|
if let Some(codepoint) = codepoint {
|
|
match unicode_plane(codepoint) {
|
|
// https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane
|
|
0 => {
|
|
if let Some(block) = codepoint.block() {
|
|
match block {
|
|
UnicodeBlock::CyrillicSupplement |
|
|
UnicodeBlock::Armenian |
|
|
UnicodeBlock::Hebrew => {
|
|
families.push("Estrangelo Edessa");
|
|
families.push("Cambria");
|
|
},
|
|
|
|
UnicodeBlock::Arabic | UnicodeBlock::ArabicSupplement => {
|
|
families.push("Microsoft Uighur");
|
|
},
|
|
|
|
UnicodeBlock::Syriac => {
|
|
families.push("Estrangelo Edessa");
|
|
},
|
|
|
|
UnicodeBlock::Thaana => {
|
|
families.push("MV Boli");
|
|
},
|
|
|
|
UnicodeBlock::NKo => {
|
|
families.push("Ebrima");
|
|
},
|
|
|
|
UnicodeBlock::Devanagari | UnicodeBlock::Bengali => {
|
|
families.push("Nirmala UI");
|
|
families.push("Utsaah");
|
|
families.push("Aparajita");
|
|
},
|
|
|
|
UnicodeBlock::Gurmukhi |
|
|
UnicodeBlock::Gujarati |
|
|
UnicodeBlock::Oriya |
|
|
UnicodeBlock::Tamil |
|
|
UnicodeBlock::Telugu |
|
|
UnicodeBlock::Kannada |
|
|
UnicodeBlock::Malayalam |
|
|
UnicodeBlock::Sinhala |
|
|
UnicodeBlock::Lepcha |
|
|
UnicodeBlock::OlChiki |
|
|
UnicodeBlock::CyrillicExtendedC |
|
|
UnicodeBlock::SundaneseSupplement |
|
|
UnicodeBlock::VedicExtensions => {
|
|
families.push("Nirmala UI");
|
|
},
|
|
|
|
UnicodeBlock::Thai => {
|
|
families.push("Leelawadee UI");
|
|
},
|
|
|
|
UnicodeBlock::Lao => {
|
|
families.push("Lao UI");
|
|
},
|
|
|
|
UnicodeBlock::Myanmar |
|
|
UnicodeBlock::MyanmarExtendedA |
|
|
UnicodeBlock::MyanmarExtendedB => {
|
|
families.push("Myanmar Text");
|
|
},
|
|
|
|
UnicodeBlock::HangulJamo |
|
|
UnicodeBlock::HangulJamoExtendedA |
|
|
UnicodeBlock::HangulSyllables |
|
|
UnicodeBlock::HangulJamoExtendedB |
|
|
UnicodeBlock::HangulCompatibilityJamo => {
|
|
families.push("Malgun Gothic");
|
|
},
|
|
|
|
UnicodeBlock::Ethiopic |
|
|
UnicodeBlock::EthiopicSupplement |
|
|
UnicodeBlock::EthiopicExtended |
|
|
UnicodeBlock::EthiopicExtendedA => {
|
|
families.push("Nyala");
|
|
},
|
|
|
|
UnicodeBlock::Cherokee => {
|
|
families.push("Plantagenet Cherokee");
|
|
},
|
|
|
|
UnicodeBlock::UnifiedCanadianAboriginalSyllabics |
|
|
UnicodeBlock::UnifiedCanadianAboriginalSyllabicsExtended => {
|
|
families.push("Euphemia");
|
|
families.push("Segoe UI");
|
|
},
|
|
|
|
UnicodeBlock::Khmer | UnicodeBlock::KhmerSymbols => {
|
|
families.push("Khmer UI");
|
|
families.push("Leelawadee UI");
|
|
},
|
|
|
|
UnicodeBlock::Mongolian => {
|
|
families.push("Mongolian Baiti");
|
|
},
|
|
|
|
UnicodeBlock::TaiLe => {
|
|
families.push("Microsoft Tai Le");
|
|
},
|
|
|
|
UnicodeBlock::NewTaiLue => {
|
|
families.push("Microsoft New Tai Lue");
|
|
},
|
|
|
|
UnicodeBlock::Buginese |
|
|
UnicodeBlock::TaiTham |
|
|
UnicodeBlock::CombiningDiacriticalMarksExtended => {
|
|
families.push("Leelawadee UI");
|
|
},
|
|
|
|
UnicodeBlock::GeneralPunctuation |
|
|
UnicodeBlock::SuperscriptsandSubscripts |
|
|
UnicodeBlock::CurrencySymbols |
|
|
UnicodeBlock::CombiningDiacriticalMarksforSymbols |
|
|
UnicodeBlock::LetterlikeSymbols |
|
|
UnicodeBlock::NumberForms |
|
|
UnicodeBlock::Arrows |
|
|
UnicodeBlock::MathematicalOperators |
|
|
UnicodeBlock::MiscellaneousTechnical |
|
|
UnicodeBlock::ControlPictures |
|
|
UnicodeBlock::OpticalCharacterRecognition |
|
|
UnicodeBlock::EnclosedAlphanumerics |
|
|
UnicodeBlock::BoxDrawing |
|
|
UnicodeBlock::BlockElements |
|
|
UnicodeBlock::GeometricShapes |
|
|
UnicodeBlock::MiscellaneousSymbols |
|
|
UnicodeBlock::Dingbats |
|
|
UnicodeBlock::MiscellaneousMathematicalSymbolsA |
|
|
UnicodeBlock::SupplementalArrowsA |
|
|
UnicodeBlock::SupplementalArrowsB |
|
|
UnicodeBlock::MiscellaneousMathematicalSymbolsB |
|
|
UnicodeBlock::SupplementalMathematicalOperators |
|
|
UnicodeBlock::MiscellaneousSymbolsandArrows |
|
|
UnicodeBlock::Glagolitic |
|
|
UnicodeBlock::LatinExtendedC |
|
|
UnicodeBlock::Coptic => {
|
|
families.push("Segoe UI");
|
|
families.push("Segoe UI Symbol");
|
|
families.push("Cambria");
|
|
families.push("Meiryo");
|
|
families.push("Lucida Sans Unicode");
|
|
families.push("Ebrima");
|
|
},
|
|
|
|
UnicodeBlock::GeorgianSupplement |
|
|
UnicodeBlock::Tifinagh |
|
|
UnicodeBlock::CyrillicExtendedA |
|
|
UnicodeBlock::SupplementalPunctuation |
|
|
UnicodeBlock::CJKRadicalsSupplement |
|
|
UnicodeBlock::KangxiRadicals |
|
|
UnicodeBlock::IdeographicDescriptionCharacters => {
|
|
families.push("Segoe UI");
|
|
families.push("Segoe UI Symbol");
|
|
families.push("Meiryo");
|
|
},
|
|
|
|
UnicodeBlock::BraillePatterns => {
|
|
families.push("Segoe UI Symbol");
|
|
},
|
|
|
|
UnicodeBlock::CJKSymbolsandPunctuation |
|
|
UnicodeBlock::Hiragana |
|
|
UnicodeBlock::Katakana |
|
|
UnicodeBlock::Bopomofo |
|
|
UnicodeBlock::Kanbun |
|
|
UnicodeBlock::BopomofoExtended |
|
|
UnicodeBlock::CJKStrokes |
|
|
UnicodeBlock::KatakanaPhoneticExtensions |
|
|
UnicodeBlock::CJKUnifiedIdeographs => {
|
|
families.push("Microsoft YaHei");
|
|
families.push("Yu Gothic");
|
|
},
|
|
|
|
UnicodeBlock::EnclosedCJKLettersandMonths => {
|
|
families.push("Malgun Gothic");
|
|
},
|
|
|
|
UnicodeBlock::YijingHexagramSymbols => {
|
|
families.push("Segoe UI Symbol");
|
|
},
|
|
|
|
UnicodeBlock::YiSyllables | UnicodeBlock::YiRadicals => {
|
|
families.push("Microsoft Yi Baiti");
|
|
families.push("Segoe UI");
|
|
},
|
|
|
|
UnicodeBlock::Vai |
|
|
UnicodeBlock::CyrillicExtendedB |
|
|
UnicodeBlock::Bamum |
|
|
UnicodeBlock::ModifierToneLetters |
|
|
UnicodeBlock::LatinExtendedD => {
|
|
families.push("Ebrima");
|
|
families.push("Segoe UI");
|
|
families.push("Cambria Math");
|
|
},
|
|
|
|
UnicodeBlock::SylotiNagri |
|
|
UnicodeBlock::CommonIndicNumberForms |
|
|
UnicodeBlock::Phagspa |
|
|
UnicodeBlock::Saurashtra |
|
|
UnicodeBlock::DevanagariExtended => {
|
|
families.push("Microsoft PhagsPa");
|
|
families.push("Nirmala UI");
|
|
},
|
|
|
|
UnicodeBlock::KayahLi | UnicodeBlock::Rejang | UnicodeBlock::Javanese => {
|
|
families.push("Malgun Gothic");
|
|
families.push("Javanese Text");
|
|
families.push("Leelawadee UI");
|
|
},
|
|
|
|
UnicodeBlock::AlphabeticPresentationForms => {
|
|
families.push("Microsoft Uighur");
|
|
families.push("Gabriola");
|
|
families.push("Sylfaen");
|
|
},
|
|
|
|
UnicodeBlock::ArabicPresentationFormsA |
|
|
UnicodeBlock::ArabicPresentationFormsB => {
|
|
families.push("Traditional Arabic");
|
|
families.push("Arabic Typesetting");
|
|
},
|
|
|
|
UnicodeBlock::VariationSelectors |
|
|
UnicodeBlock::VerticalForms |
|
|
UnicodeBlock::CombiningHalfMarks |
|
|
UnicodeBlock::CJKCompatibilityForms |
|
|
UnicodeBlock::SmallFormVariants |
|
|
UnicodeBlock::HalfwidthandFullwidthForms |
|
|
UnicodeBlock::Specials => {
|
|
families.push("Microsoft JhengHei");
|
|
},
|
|
|
|
_ => {},
|
|
}
|
|
}
|
|
},
|
|
|
|
// https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Multilingual_Plane
|
|
1 => {
|
|
families.push("Segoe UI Symbol");
|
|
families.push("Ebrima");
|
|
families.push("Nirmala UI");
|
|
families.push("Cambria Math");
|
|
},
|
|
|
|
_ => {},
|
|
}
|
|
}
|
|
|
|
families.push("Arial Unicode MS");
|
|
families
|
|
}
|