-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add font-fallback on OpenHarmony and fix several compilation issues #32141
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
4fe12ac
Add OpenHarmony support for allocator / profile
jschwe fd5fb51
gfx: Build harfbuzz from source on OHOS
jschwe 648e3be
gfx: Don't depend on fontconfig on OpenHarmony
jschwe 6347c3b
gfx: Add ohos font fallback
jschwe 381e834
libservo: OHOS useragent, and explicitly opt out of sandboxing
jschwe ba2bd9a
libservo: Disable get_native_media_display_and_gl_context on ohos
jschwe File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
/* 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::fs::File; | ||
use std::io::Read; | ||
use std::path::{Path, PathBuf}; | ||
|
||
use log::warn; | ||
use serde::{Deserialize, Serialize}; | ||
use style::values::computed::{ | ||
FontStretch as StyleFontStretch, FontStyle as StyleFontStyle, FontWeight as StyleFontWeight, | ||
}; | ||
use style::Atom; | ||
use ucd::{Codepoint, UnicodeBlock}; | ||
use webrender_api::NativeFontHandle; | ||
|
||
use crate::font_template::{FontTemplate, FontTemplateDescriptor}; | ||
use crate::text::util::is_cjk; | ||
|
||
lazy_static::lazy_static! { | ||
static ref FONT_LIST: FontList = FontList::new(); | ||
} | ||
|
||
/// An identifier for a local font on OpenHarmony systems. | ||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] | ||
pub struct LocalFontIdentifier { | ||
/// The path to the font. | ||
pub path: Atom, | ||
} | ||
|
||
impl LocalFontIdentifier { | ||
pub(crate) fn index(&self) -> u32 { | ||
0 | ||
} | ||
|
||
pub(crate) fn read_data_from_file(&self) -> Vec<u8> { | ||
let mut bytes = Vec::new(); | ||
File::open(Path::new(&*self.path)) | ||
.expect("Couldn't open font file!") | ||
.read_to_end(&mut bytes) | ||
.unwrap(); | ||
bytes | ||
} | ||
} | ||
|
||
struct Font { | ||
filename: String, | ||
weight: Option<i32>, | ||
style: Option<String>, | ||
} | ||
|
||
struct FontFamily { | ||
name: String, | ||
fonts: Vec<Font>, | ||
} | ||
|
||
struct FontAlias { | ||
from: String, | ||
to: String, | ||
weight: Option<i32>, | ||
} | ||
|
||
struct FontList { | ||
families: Vec<FontFamily>, | ||
aliases: Vec<FontAlias>, | ||
} | ||
|
||
impl FontList { | ||
fn new() -> FontList { | ||
// We don't support parsing `/system/etc/fontconfig.json` yet. | ||
FontList { | ||
families: Self::fallback_font_families(), | ||
aliases: Vec::new(), | ||
} | ||
} | ||
|
||
// Fonts expected to exist in OpenHarmony devices. | ||
// Used until parsing of the fontconfig.json file is implemented. | ||
fn fallback_font_families() -> Vec<FontFamily> { | ||
let alternatives = [ | ||
("HarmonyOS Sans", "HarmonyOS_Sans_SC_Regular.ttf"), | ||
("sans-serif", "HarmonyOS_Sans_SC_Regular.ttf"), | ||
]; | ||
|
||
alternatives | ||
.iter() | ||
.filter(|item| Path::new(&Self::font_absolute_path(item.1)).exists()) | ||
.map(|item| FontFamily { | ||
name: item.0.into(), | ||
fonts: vec![Font { | ||
filename: item.1.into(), | ||
weight: None, | ||
style: None, | ||
}], | ||
}) | ||
.collect() | ||
} | ||
|
||
// OHOS fonts are located in /system/fonts | ||
fn font_absolute_path(filename: &str) -> String { | ||
if filename.starts_with("/") { | ||
String::from(filename) | ||
} else { | ||
format!("/system/fonts/{}", filename) | ||
} | ||
} | ||
|
||
fn find_family(&self, name: &str) -> Option<&FontFamily> { | ||
self.families.iter().find(|f| f.name == name) | ||
} | ||
|
||
fn find_alias(&self, name: &str) -> Option<&FontAlias> { | ||
self.aliases.iter().find(|f| f.from == name) | ||
} | ||
} | ||
|
||
// Functions used by FontCacheThread | ||
pub fn for_each_available_family<F>(mut callback: F) | ||
where | ||
F: FnMut(String), | ||
{ | ||
for family in &FONT_LIST.families { | ||
callback(family.name.clone()); | ||
} | ||
for alias in &FONT_LIST.aliases { | ||
callback(alias.from.clone()); | ||
} | ||
} | ||
|
||
pub fn for_each_variation<F>(family_name: &str, mut callback: F) | ||
where | ||
F: FnMut(FontTemplate), | ||
{ | ||
let mut produce_font = |font: &Font| { | ||
let local_font_identifier = LocalFontIdentifier { | ||
path: Atom::from(FontList::font_absolute_path(&font.filename)), | ||
}; | ||
let stretch = StyleFontStretch::NORMAL; | ||
let weight = font | ||
.weight | ||
.map(|w| StyleFontWeight::from_float(w as f32)) | ||
.unwrap_or(StyleFontWeight::NORMAL); | ||
let style = match font.style.as_deref() { | ||
Some("italic") => StyleFontStyle::ITALIC, | ||
Some("normal") => StyleFontStyle::NORMAL, | ||
Some(value) => { | ||
warn!( | ||
"unknown value \"{value}\" for \"style\" attribute in the font {}", | ||
font.filename | ||
); | ||
StyleFontStyle::NORMAL | ||
}, | ||
None => StyleFontStyle::NORMAL, | ||
}; | ||
let descriptor = FontTemplateDescriptor { | ||
weight, | ||
stretch, | ||
style, | ||
}; | ||
callback(FontTemplate::new_local(local_font_identifier, descriptor)); | ||
}; | ||
|
||
if let Some(family) = FONT_LIST.find_family(family_name) { | ||
for font in &family.fonts { | ||
produce_font(font); | ||
} | ||
return; | ||
} | ||
|
||
if let Some(alias) = FONT_LIST.find_alias(family_name) { | ||
if let Some(family) = FONT_LIST.find_family(&alias.to) { | ||
for font in &family.fonts { | ||
match (alias.weight, font.weight) { | ||
(None, _) => produce_font(font), | ||
(Some(w1), Some(w2)) if w1 == w2 => produce_font(font), | ||
_ => {}, | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
pub fn system_default_family(generic_name: &str) -> Option<String> { | ||
if let Some(family) = FONT_LIST.find_family(&generic_name) { | ||
Some(family.name.clone()) | ||
} else if let Some(alias) = FONT_LIST.find_alias(&generic_name) { | ||
Some(alias.from.clone()) | ||
} else { | ||
FONT_LIST.families.get(0).map(|family| family.name.clone()) | ||
} | ||
} | ||
|
||
// Based on fonts present in OpenHarmony. | ||
pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> { | ||
let mut families = vec![]; | ||
|
||
if let Some(block) = codepoint.and_then(|c| c.block()) { | ||
match block { | ||
UnicodeBlock::Hebrew => { | ||
families.push("Noto Sans Hebrew"); | ||
}, | ||
|
||
UnicodeBlock::Arabic => { | ||
families.push("HarmonyOS Sans Naskh Arabic"); | ||
}, | ||
|
||
UnicodeBlock::Devanagari => { | ||
families.push("Noto Sans Devanagari"); | ||
}, | ||
|
||
UnicodeBlock::Tamil => { | ||
families.push("Noto Sans Tamil"); | ||
}, | ||
|
||
UnicodeBlock::Thai => { | ||
families.push("Noto Sans Thai"); | ||
}, | ||
|
||
UnicodeBlock::Georgian | UnicodeBlock::GeorgianSupplement => { | ||
families.push("Noto Sans Georgian"); | ||
}, | ||
|
||
UnicodeBlock::Ethiopic | UnicodeBlock::EthiopicSupplement => { | ||
families.push("Noto Sans Ethiopic"); | ||
}, | ||
|
||
_ => { | ||
if is_cjk(codepoint.unwrap()) { | ||
families.push("Noto Sans JP"); | ||
families.push("Noto Sans KR"); | ||
} | ||
}, | ||
} | ||
} | ||
|
||
families.push("HarmonyOS Sans"); | ||
families | ||
} | ||
|
||
pub static SANS_SERIF_FONT_FAMILY: &'static str = "HarmonyOS Sans"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps pay special attention to this file. It's based on an earlier version of
android/font_list.rs
, which received some updates in the recent days.My current approach was to just hardcode one version of the
HarmonyOS Sans
font family available on ohos devices and update the list of fallback families for codepoints.There are quite a few
HarmonyOS_Sans_*.ttf
files available on ohos devices. I chose one with the largest filesize, and that seemed to work well in practice.There is also a fontconfig.json available, which could be parsed (for an example see https://github.com/jschwe/ohos-fontconfig/blob/main/src/lib.rs)