Skip to content

Commit

Permalink
Add font-fallback on OpenHarmony and fix several compilation issues (#…
Browse files Browse the repository at this point in the history
…32141)

* Add OpenHarmony support for allocator / profile

Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com>

* gfx: Build harfbuzz from source on OHOS

Updates `freetype-sys` to v0.20.1, which includes a build
fix for OpenHarmony.

Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com>

* gfx: Don't depend on fontconfig on OpenHarmony

Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com>

* gfx: Add ohos font fallback

Hardcode HarmonyOS_Sans_SC_Regular for Chinese

Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com>

* libservo: OHOS useragent, and explicitly opt out of sandboxing

Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com>

* libservo: Disable get_native_media_display_and_gl_context on ohos

Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com>

---------

Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com>
  • Loading branch information
jschwe committed May 2, 2024
1 parent 9acf218 commit ca064ea
Show file tree
Hide file tree
Showing 8 changed files with 307 additions and 27 deletions.
4 changes: 2 additions & 2 deletions components/allocator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ path = "lib.rs"
[features]
use-system-allocator = ["libc"]

[target.'cfg(not(any(windows, target_os = "android")))'.dependencies]
[target.'cfg(not(any(windows, target_os = "android", target_env = "ohos")))'.dependencies]
jemallocator = { workspace = true }
jemalloc-sys = { workspace = true }
libc = { workspace = true, optional = true }

[target.'cfg(windows)'.dependencies]
winapi = { workspace = true, features = ["heapapi"] }

[target.'cfg(target_os = "android")'.dependencies]
[target.'cfg(any(target_os = "android", target_env = "ohos"))'.dependencies]
libc = { workspace = true }
13 changes: 11 additions & 2 deletions components/allocator/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ static ALLOC: Allocator = Allocator;

pub use crate::platform::*;

#[cfg(not(any(windows, target_os = "android", feature = "use-system-allocator")))]
#[cfg(not(any(
windows,
target_os = "android",
feature = "use-system-allocator",
target_env = "ohos"
)))]
mod platform {
use std::os::raw::c_void;

Expand All @@ -32,7 +37,11 @@ mod platform {

#[cfg(all(
not(windows),
any(target_os = "android", feature = "use-system-allocator")
any(
target_os = "android",
feature = "use-system-allocator",
target_env = "ohos"
)
))]
mod platform {
pub use std::alloc::System as Allocator;
Expand Down
8 changes: 6 additions & 2 deletions components/gfx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ euclid = { workspace = true }
fnv = { workspace = true }
fontsan = { git = "https://github.com/servo/fontsan" }
gfx_traits = { workspace = true }
harfbuzz-sys = "0.6"
harfbuzz-sys = "0.6.1"
ipc-channel = { workspace = true }
lazy_static = { workspace = true }
libc = { workspace = true }
Expand Down Expand Up @@ -55,12 +55,16 @@ harfbuzz-sys = { version = "0.6", features = ["bundled"] }
freetype = "0.7"
servo_allocator = { path = "../allocator" }

[target.'cfg(target_os = "linux")'.dependencies]
[target.'cfg(all(target_os = "linux", not(target_env = "ohos")))'.dependencies]
fontconfig_sys = { package = "yeslogic-fontconfig-sys", version = "5" }

[target.'cfg(target_os = "android")'.dependencies]
xml-rs = "0.8"

[target.'cfg(target_env = "ohos")'.dependencies]
harfbuzz-sys = { version = "0.6.1", features = ["bundled"] }


[target.'cfg(target_os = "windows")'.dependencies]
harfbuzz-sys = { version = "0.6", features = ["bundled"] }
dwrote = "0.11"
Expand Down
241 changes: 241 additions & 0 deletions components/gfx/platform/freetype/ohos/font_list.rs
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";
8 changes: 7 additions & 1 deletion components/gfx/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ mod freetype {

pub mod font;

#[cfg(target_os = "linux")]
#[cfg(all(target_os = "linux", not(target_env = "ohos")))]
pub mod font_list;
#[cfg(target_os = "android")]
mod android {
Expand All @@ -35,6 +35,12 @@ mod freetype {
}
#[cfg(target_os = "android")]
pub use self::android::font_list;
#[cfg(target_env = "ohos")]
mod ohos {
pub mod font_list;
}
#[cfg(target_env = "ohos")]
pub use self::ohos::font_list;

pub mod library_handle;
}
Expand Down
1 change: 1 addition & 0 deletions components/profile/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ regex = { workspace = true }

[target.'cfg(not(any(target_os = "windows", target_os = "android")))'.dependencies]
libc = { workspace = true }
[target.'cfg(not(any(target_os = "windows", target_os = "android", target_env = "ohos")))'.dependencies]
jemalloc-sys = { workspace = true }
14 changes: 7 additions & 7 deletions components/profile/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,16 +387,16 @@ impl ReportsForest {
//---------------------------------------------------------------------------

mod system_reporter {
#[cfg(not(any(target_os = "windows", target_os = "android")))]
#[cfg(not(any(target_os = "windows", target_os = "android", target_env = "ohos")))]
use std::ffi::CString;
#[cfg(not(any(target_os = "windows", target_os = "android")))]
#[cfg(not(any(target_os = "windows", target_os = "android", target_env = "ohos")))]
use std::mem::size_of;
#[cfg(not(any(target_os = "windows", target_os = "android")))]
#[cfg(not(any(target_os = "windows", target_os = "android", target_env = "ohos")))]
use std::ptr::null_mut;

#[cfg(target_os = "linux")]
use libc::c_int;
#[cfg(not(any(target_os = "windows", target_os = "android")))]
#[cfg(not(any(target_os = "windows", target_os = "android", target_env = "ohos")))]
use libc::{c_void, size_t};
use profile_traits::mem::{Report, ReportKind, ReporterRequest};
use profile_traits::path;
Expand Down Expand Up @@ -499,10 +499,10 @@ mod system_reporter {
None
}

#[cfg(not(any(target_os = "windows", target_os = "android")))]
#[cfg(not(any(target_os = "windows", target_os = "android", target_env = "ohos")))]
use jemalloc_sys::mallctl;

#[cfg(not(any(target_os = "windows", target_os = "android")))]
#[cfg(not(any(target_os = "windows", target_os = "android", target_env = "ohos")))]
fn jemalloc_stat(value_name: &str) -> Option<usize> {
// Before we request the measurement of interest, we first send an "epoch"
// request. Without that jemalloc gives cached statistics(!) which can be
Expand Down Expand Up @@ -549,7 +549,7 @@ mod system_reporter {
Some(value as usize)
}

#[cfg(any(target_os = "windows", target_os = "android"))]
#[cfg(any(target_os = "windows", target_os = "android", target_env = "ohos"))]
fn jemalloc_stat(_value_name: &str) -> Option<usize> {
None
}
Expand Down

0 comments on commit ca064ea

Please sign in to comment.