diff options
-rw-r--r-- | components/allocator/Cargo.toml | 4 | ||||
-rw-r--r-- | components/allocator/lib.rs | 13 | ||||
-rw-r--r-- | components/gfx/Cargo.toml | 8 | ||||
-rw-r--r-- | components/gfx/platform/freetype/ohos/font_list.rs | 241 | ||||
-rw-r--r-- | components/gfx/platform/mod.rs | 8 | ||||
-rw-r--r-- | components/profile/Cargo.toml | 1 | ||||
-rw-r--r-- | components/profile/mem.rs | 14 | ||||
-rw-r--r-- | components/servo/lib.rs | 45 |
8 files changed, 307 insertions, 27 deletions
diff --git a/components/allocator/Cargo.toml b/components/allocator/Cargo.toml index e6467da3737..3978241094d 100644 --- a/components/allocator/Cargo.toml +++ b/components/allocator/Cargo.toml @@ -12,7 +12,7 @@ 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 } @@ -20,5 +20,5 @@ 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 } diff --git a/components/allocator/lib.rs b/components/allocator/lib.rs index 20ac30e8022..a28916375df 100644 --- a/components/allocator/lib.rs +++ b/components/allocator/lib.rs @@ -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; @@ -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; diff --git a/components/gfx/Cargo.toml b/components/gfx/Cargo.toml index 06982af6aee..5174f593572 100644 --- a/components/gfx/Cargo.toml +++ b/components/gfx/Cargo.toml @@ -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 } @@ -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" diff --git a/components/gfx/platform/freetype/ohos/font_list.rs b/components/gfx/platform/freetype/ohos/font_list.rs new file mode 100644 index 00000000000..95d7209c6ad --- /dev/null +++ b/components/gfx/platform/freetype/ohos/font_list.rs @@ -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"; diff --git a/components/gfx/platform/mod.rs b/components/gfx/platform/mod.rs index 5509c214531..7b2efa41671 100644 --- a/components/gfx/platform/mod.rs +++ b/components/gfx/platform/mod.rs @@ -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 { @@ -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; } diff --git a/components/profile/Cargo.toml b/components/profile/Cargo.toml index da55faa6a00..36aca49b6df 100644 --- a/components/profile/Cargo.toml +++ b/components/profile/Cargo.toml @@ -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 } diff --git a/components/profile/mem.rs b/components/profile/mem.rs index 0fdeb76715c..56bcdeb5a0d 100644 --- a/components/profile/mem.rs +++ b/components/profile/mem.rs @@ -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; @@ -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 @@ -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 } diff --git a/components/servo/lib.rs b/components/servo/lib.rs index a638c2942ab..28ae62f1fec 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -42,7 +42,8 @@ use compositing_traits::{ not(target_os = "ios"), not(target_os = "android"), not(target_arch = "arm"), - not(target_arch = "aarch64") + not(target_arch = "aarch64"), + not(target_env = "ohos"), ))] use constellation::content_process_sandbox_profile; use constellation::{ @@ -58,7 +59,8 @@ use euclid::Scale; not(target_os = "ios"), not(target_os = "android"), not(target_arch = "arm"), - not(target_arch = "aarch64") + not(target_arch = "aarch64"), + not(target_env = "ohos"), ))] use gaol::sandbox::{ChildSandbox, ChildSandboxMethods}; use gfx::font_cache_thread::FontCacheThread; @@ -81,12 +83,12 @@ use script_traits::{ScriptToConstellationChan, WindowSizeData}; use servo_config::{opts, pref, prefs}; use servo_media::player::context::GlContext; use servo_media::ServoMedia; -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] use surfman::platform::generic::multi::connection::NativeConnection as LinuxNativeConnection; -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] use surfman::platform::generic::multi::context::NativeContext as LinuxNativeContext; use surfman::{GLApi, GLVersion}; -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] use surfman::{NativeConnection, NativeContext}; use webrender::{RenderApiSender, ShaderPrecacheFlags}; use webrender_api::{ @@ -253,6 +255,9 @@ where Some(ref ua) if ua == "desktop" => { default_user_agent_string_for(UserAgent::Desktop).into() }, + Some(ref ua) if ua == "ohos" => { + default_user_agent_string_for(UserAgent::OpenHarmony).into() + }, Some(ua) => ua.into(), None => embedder .get_user_agent_string() @@ -492,7 +497,7 @@ where } } - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] fn get_native_media_display_and_gl_context( rendering_context: &RenderingContext, ) -> Option<(NativeDisplay, GlContext)> { @@ -529,7 +534,10 @@ where Some((native_display, gl_context)) } - #[cfg(not(any(target_os = "windows", target_os = "linux")))] + #[cfg(not(any( + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + )))] fn get_native_media_display_and_gl_context( _rendering_context: &RenderingContext, ) -> Option<(NativeDisplay, GlContext)> { @@ -1196,7 +1204,8 @@ pub fn run_content_process(token: String) { not(target_os = "ios"), not(target_os = "android"), not(target_arch = "arm"), - not(target_arch = "aarch64") + not(target_arch = "aarch64"), + not(target_env = "ohos"), ))] fn create_sandbox() { ChildSandbox::new(content_process_sandbox_profile()) @@ -1209,7 +1218,8 @@ fn create_sandbox() { target_os = "ios", target_os = "android", target_arch = "arm", - target_arch = "aarch64" + target_arch = "aarch64", + target_env = "ohos", ))] fn create_sandbox() { panic!("Sandboxing is not supported on Windows, iOS, ARM targets and android."); @@ -1218,15 +1228,20 @@ fn create_sandbox() { enum UserAgent { Desktop, Android, + OpenHarmony, #[allow(non_camel_case_types)] iOS, } fn default_user_agent_string_for(agent: UserAgent) -> &'static str { - #[cfg(all(target_os = "linux", target_arch = "x86_64"))] + #[cfg(all(target_os = "linux", target_arch = "x86_64", not(target_env = "ohos")))] const DESKTOP_UA_STRING: &'static str = "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Servo/1.0 Firefox/111.0"; - #[cfg(all(target_os = "linux", not(target_arch = "x86_64")))] + #[cfg(all( + target_os = "linux", + not(target_arch = "x86_64"), + not(target_env = "ohos") + ))] const DESKTOP_UA_STRING: &'static str = "Mozilla/5.0 (X11; Linux i686; rv:109.0) Servo/1.0 Firefox/111.0"; @@ -1241,12 +1256,13 @@ fn default_user_agent_string_for(agent: UserAgent) -> &'static str { const DESKTOP_UA_STRING: &'static str = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Servo/1.0 Firefox/111.0"; - #[cfg(target_os = "android")] + #[cfg(any(target_os = "android", target_env = "ohos"))] const DESKTOP_UA_STRING: &'static str = ""; match agent { UserAgent::Desktop => DESKTOP_UA_STRING, UserAgent::Android => "Mozilla/5.0 (Android; Mobile; rv:109.0) Servo/1.0 Firefox/111.0", + UserAgent::OpenHarmony => "Mozilla/5.0 (OpenHarmony; Mobile; rv:109.0) Servo/1.0 Firefox/111.0", UserAgent::iOS => { "Mozilla/5.0 (iPhone; CPU iPhone OS 16_4 like Mac OS X; rv:109.0) Servo/1.0 Firefox/111.0" }, @@ -1256,8 +1272,11 @@ fn default_user_agent_string_for(agent: UserAgent) -> &'static str { #[cfg(target_os = "android")] const DEFAULT_USER_AGENT: UserAgent = UserAgent::Android; +#[cfg(target_env = "ohos")] +const DEFAULT_USER_AGENT: UserAgent = UserAgent::OpenHarmony; + #[cfg(target_os = "ios")] const DEFAULT_USER_AGENT: UserAgent = UserAgent::iOS; -#[cfg(not(any(target_os = "android", target_os = "ios")))] +#[cfg(not(any(target_os = "android", target_os = "ios", target_env = "ohos")))] const DEFAULT_USER_AGENT: UserAgent = UserAgent::Desktop; |