mirror of
https://github.com/servo/servo
synced 2026-04-25 17:15:48 +02:00
Embed default resources in Servo applications using a servo-default-resources crate (#43182)
This PR considers the following constraints: - Resources must be available when building servo via a published crates.io package (i.e. no `../../../resources/<file>` file references). - Minimal setup when writing tests (`nextest` spawns each test in its own process, so we don't want to explicitly initialize the resource handler for every `#[test]` fn) - Use local resources when developing locally - Support loading the resources from a proper resource directory if the embedder wishes so, including via a custom mechanism, not necessarily as files (File) Resources that are only accessed from servoshell are out of scope of this PR, since it mainly focusses on unblocking publishing `libservo` to crates.io. Baking the resources into the binary by default simplifies the setup a lot. We already supported that before, but only for testing purposes and explicitly not for production builds. Using [`inventory`](https://crates.io/crates/inventory) adds a simple way for the embedder to replace the default baked in resources, while also keeping the test usage of baked in resources simple. rippy.png is also referenced from image_cache - We simply duplicate it, since the image is small, to avoid adding unnecessarily complex solutions like adding a dedicated crate. Testing: Covered by existing tests. [mach try full](https://github.com/jschwe/servo/actions/runs/23811669469) Fixes: Part of #43145 --------- Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This commit is contained in:
committed by
GitHub
parent
05946163f2
commit
f4877c190e
21
Cargo.lock
generated
21
Cargo.lock
generated
@@ -4438,6 +4438,15 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inventory"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipc-channel"
|
||||
version = "0.21.0"
|
||||
@@ -7436,6 +7445,7 @@ dependencies = [
|
||||
"servo-config",
|
||||
"servo-constellation",
|
||||
"servo-constellation-traits",
|
||||
"servo-default-resources",
|
||||
"servo-devtools",
|
||||
"servo-devtools-traits",
|
||||
"servo-embedder-traits",
|
||||
@@ -7712,6 +7722,13 @@ dependencies = [
|
||||
"wgpu-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servo-default-resources"
|
||||
version = "0.0.6"
|
||||
dependencies = [
|
||||
"servo-embedder-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servo-deny-public-fields"
|
||||
version = "0.0.6"
|
||||
@@ -7784,6 +7801,7 @@ dependencies = [
|
||||
"euclid",
|
||||
"http 1.4.0",
|
||||
"image",
|
||||
"inventory",
|
||||
"keyboard-types",
|
||||
"log",
|
||||
"malloc_size_of_derive",
|
||||
@@ -8304,6 +8322,7 @@ dependencies = [
|
||||
"serde",
|
||||
"servo-base",
|
||||
"servo-config",
|
||||
"servo-default-resources",
|
||||
"servo-devtools-traits",
|
||||
"servo-embedder-traits",
|
||||
"servo-hyper-serde",
|
||||
@@ -8353,6 +8372,7 @@ dependencies = [
|
||||
"serde",
|
||||
"servo-base",
|
||||
"servo-config",
|
||||
"servo-default-resources",
|
||||
"servo-embedder-traits",
|
||||
"servo-hyper-serde",
|
||||
"servo-malloc-size-of",
|
||||
@@ -8720,6 +8740,7 @@ dependencies = [
|
||||
"serde",
|
||||
"servo-base",
|
||||
"servo-config",
|
||||
"servo-default-resources",
|
||||
"servo-malloc-size-of",
|
||||
"servo-net-traits",
|
||||
"servo-profile",
|
||||
|
||||
@@ -106,6 +106,7 @@ icu_segmenter = "1.5.0"
|
||||
image = { version = "0.25", default-features = false, features = ["avif", "rayon", "bmp", "gif", "ico", "jpeg", "png", "webp"] }
|
||||
imsz = "0.4"
|
||||
indexmap = { version = "2.11.4", features = ["std"] }
|
||||
inventory = { version = "0.3.24" }
|
||||
ipc-channel = "0.21"
|
||||
itertools = "0.14"
|
||||
js = { package = "mozjs", version = "=0.15.7", default-features = false, features = ["libz-sys", "intl"] }
|
||||
@@ -265,6 +266,7 @@ servo-config = { version = "0.0.6", path = "components/config" }
|
||||
servo-config-macro = { version = "0.0.6", path = "components/config/macro" }
|
||||
servo-constellation = { version = "0.0.6", path = "components/constellation" }
|
||||
servo-constellation-traits = { version = "0.0.6", path = "components/shared/constellation" }
|
||||
servo-default-resources = { version = "0.0.6", path = "components/default-resources" }
|
||||
servo-geometry = { version = "0.0.6", path = "components/geometry" }
|
||||
servo-media = { version = "0.0.6", path = "components/media/servo-media" }
|
||||
servo-media-audio = { version = "0.0.6", path = "components/media/audio" }
|
||||
|
||||
16
components/default-resources/Cargo.toml
Normal file
16
components/default-resources/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "servo-default-resources"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
description.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
embedder_traits = { workspace = true }
|
||||
38
components/default-resources/lib.rs
Normal file
38
components/default-resources/lib.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
/* 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::path::PathBuf;
|
||||
|
||||
use embedder_traits::resources::{Resource, ResourceReaderMethods};
|
||||
|
||||
/// A default resource reader that provides baked in resources.
|
||||
pub struct DefaultResourceReader;
|
||||
|
||||
impl ResourceReaderMethods for DefaultResourceReader {
|
||||
fn sandbox_access_files(&self) -> Vec<PathBuf> {
|
||||
vec![]
|
||||
}
|
||||
fn sandbox_access_files_dirs(&self) -> Vec<PathBuf> {
|
||||
vec![]
|
||||
}
|
||||
fn read(&self, file: Resource) -> Vec<u8> {
|
||||
match file {
|
||||
Resource::BluetoothBlocklist => &include_bytes!("resources/gatt_blocklist.txt")[..],
|
||||
Resource::DomainList => &include_bytes!("resources/public_domains.txt")[..],
|
||||
Resource::HstsPreloadList => &include_bytes!("resources/hsts_preload.fstmap")[..],
|
||||
Resource::BadCertHTML => &include_bytes!("resources/badcert.html")[..],
|
||||
Resource::NetErrorHTML => &include_bytes!("resources/neterror.html")[..],
|
||||
Resource::BrokenImageIcon => &include_bytes!("resources/rippy.png")[..],
|
||||
Resource::CrashHTML => &include_bytes!("resources/crash.html")[..],
|
||||
Resource::DirectoryListingHTML => {
|
||||
&include_bytes!("resources/directory-listing.html")[..]
|
||||
},
|
||||
Resource::AboutMemoryHTML => &include_bytes!("resources/about-memory.html")[..],
|
||||
Resource::DebuggerJS => &include_bytes!("resources/debugger.js")[..],
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
embedder_traits::submit_resource_reader!(&DefaultResourceReader);
|
||||
|
Before Width: | Height: | Size: 144 B After Width: | Height: | Size: 144 B |
@@ -17,7 +17,7 @@ test = false
|
||||
doctest = false
|
||||
|
||||
[features]
|
||||
test-util = ["hyper-util/server-graceful"]
|
||||
test-util = ["hyper-util/server-graceful", "dep:servo-default-resources"]
|
||||
|
||||
[dependencies]
|
||||
async-compression = { version = "0.4.12", default-features = false, features = ["brotli", "gzip", "tokio", "zlib", "zstd"] }
|
||||
@@ -69,6 +69,7 @@ serde = { workspace = true }
|
||||
servo_arc = { workspace = true }
|
||||
servo-base = { workspace = true }
|
||||
servo-config = { workspace = true }
|
||||
servo-default-resources = { workspace = true, optional = true }
|
||||
servo-url = { workspace = true }
|
||||
sha2 = { workspace = true }
|
||||
time = { workspace = true }
|
||||
@@ -84,7 +85,7 @@ webpki-roots = { workspace = true }
|
||||
webrender_api = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
embedder_traits = { workspace = true, features = ["baked-default-resources"] }
|
||||
servo-default-resources = { workspace = true }
|
||||
flate2 = { workspace = true }
|
||||
fst = "0.4"
|
||||
hyper = { workspace = true, features = ["full"] }
|
||||
|
||||
@@ -39,7 +39,7 @@ use webrender_api::units::DeviceIntSize;
|
||||
// We bake in rippy.png as a fallback, in case the embedder does not provide a broken
|
||||
// image icon resource. This version is 229 bytes, so don't exchange it against
|
||||
// something of higher resolution.
|
||||
const FALLBACK_RIPPY: &[u8] = include_bytes!("../../resources/rippy.png");
|
||||
const FALLBACK_RIPPY: &[u8] = include_bytes!("resources/rippy.png");
|
||||
|
||||
/// The current SVG stack relies on `resvg` to provide the natural dimensions of
|
||||
/// the SVG, which it automatically infers from the width/height/viewBox properties
|
||||
|
||||
BIN
components/net/resources/rippy.png
Normal file
BIN
components/net/resources/rippy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 144 B |
@@ -22,6 +22,7 @@ use hyper_util::rt::tokio::TokioIo;
|
||||
use net_traits::AsyncRuntime;
|
||||
use rustls_pki_types::pem::PemObject;
|
||||
use rustls_pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer};
|
||||
use servo_default_resources as _;
|
||||
use servo_url::ServoUrl;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio_rustls::{self, TlsAcceptor};
|
||||
|
||||
@@ -18,8 +18,11 @@ crate-type = ["rlib"]
|
||||
[features]
|
||||
# Note: Servoshell does not use the default features of servo, so you also
|
||||
# need to add features that should be default to ports/servoshell/Cargo.toml
|
||||
default = ["clipboard", "js_jit"]
|
||||
default = ["baked-in-resources", "clipboard", "js_jit"]
|
||||
background_hang_monitor = ["servo-background-hang-monitor/sampler"]
|
||||
# This is slightly magical, but this will also work on ohos, where `servo-default-resource` is not added,
|
||||
# which makes `baked-in-resources a no-op (as intended) on ohos (and perhaps other platforms in the future).
|
||||
baked-in-resources = ["dep:servo-default-resources"]
|
||||
bluetooth = [
|
||||
"servo-bluetooth-traits",
|
||||
"dep:servo-bluetooth",
|
||||
@@ -135,6 +138,12 @@ webrender = { workspace = true }
|
||||
webrender_api = { workspace = true }
|
||||
webxr-api = { workspace = true, optional = true }
|
||||
|
||||
# On most platforms we bake in the resources for simplicity. On ohos we load resources via the filesystem.
|
||||
# In the future we might want to use this approach also for the other platforms.
|
||||
# If the feature is turned off, a resource reader must be injected into the build via `inventory::submit!()`.
|
||||
[target.'cfg(not(target_env = "ohos"))'.dependencies]
|
||||
servo-default-resources = { workspace = true, optional = true }
|
||||
|
||||
[target.'cfg(any(target_os = "android", target_env = "ohos"))'.dependencies]
|
||||
webxr = { workspace = true, optional = true }
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ mod webview_delegate;
|
||||
// should be exported at the root. See <https://github.com/servo/servo/issues/18475>.
|
||||
pub use accesskit;
|
||||
pub use embedder_traits::user_contents::UserScript;
|
||||
pub use embedder_traits::*;
|
||||
pub use embedder_traits::{submit_resource_reader, *};
|
||||
pub use image::RgbaImage;
|
||||
pub use keyboard_types::{
|
||||
Code, CompositionEvent, CompositionState, Key, KeyState, Location, Modifiers, NamedKey,
|
||||
@@ -106,3 +106,7 @@ pub mod protocol_handler {
|
||||
|
||||
pub use crate::webview_delegate::ProtocolHandlerRegistration;
|
||||
}
|
||||
|
||||
// We need to reference this crate, in order for the linker not to remove it.
|
||||
#[cfg(all(feature = "baked-in-resources", not(target_env = "ohos")))]
|
||||
use servo_default_resources as _;
|
||||
|
||||
@@ -14,9 +14,6 @@ name = "embedder_traits"
|
||||
path = "lib.rs"
|
||||
|
||||
[features]
|
||||
# bakes default resources into the library.
|
||||
# This feature is mainly intended for testing purposes.
|
||||
baked-default-resources = []
|
||||
gamepad = []
|
||||
|
||||
[dependencies]
|
||||
@@ -29,6 +26,7 @@ http = { workspace = true }
|
||||
hyper_serde = { workspace = true }
|
||||
image = { workspace = true }
|
||||
keyboard-types = { workspace = true }
|
||||
inventory = { workspace = true }
|
||||
log = { workspace = true }
|
||||
malloc_size_of = { workspace = true }
|
||||
malloc_size_of_derive = { workspace = true }
|
||||
|
||||
@@ -3,47 +3,82 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::sync::RwLock;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
static RES: RwLock<Option<Box<dyn ResourceReaderMethods + Sync + Send>>> = RwLock::new(None);
|
||||
#[doc(hidden)]
|
||||
pub use inventory as _inventory;
|
||||
|
||||
#[cfg(feature = "baked-default-resources")]
|
||||
static INIT_TEST_RESOURCES: std::sync::Once = std::sync::Once::new();
|
||||
/// A static reference to a ResourceReader
|
||||
///
|
||||
/// If you need to initialize the resource reader at runtime, use interior mutability.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// pub(crate) struct ResourceReaderImpl {
|
||||
/// resource_dir: OnceLock<PathBuf>,
|
||||
/// }
|
||||
/// static RESOURCE_READER: ResourceReaderImpl = ResourceReaderImpl {
|
||||
/// resource_dir: OnceLock::new(),
|
||||
/// };
|
||||
///
|
||||
/// servo::submit_resource_reader!(&RESOURCE_READER);
|
||||
///
|
||||
/// /// This can be called during initialization, e.g. after parsing commandline flags.
|
||||
/// pub(crate) fn set_resource_dir(resource_dir: PathBuf) {
|
||||
/// RESOURCE_READER.resource_dir.set(resource_dir).expect("Already initialized.")
|
||||
/// }
|
||||
/// impl ResourceReaderMethods for ResourceReaderImpl {
|
||||
/// //
|
||||
/// }
|
||||
/// ```
|
||||
pub type ResourceReader = &'static (dyn ResourceReaderMethods + Sync + Send);
|
||||
|
||||
#[cfg(all(feature = "baked-default-resources", servo_production))]
|
||||
const _: () = assert!(
|
||||
false,
|
||||
"baked-default-resources should not be used in production"
|
||||
);
|
||||
|
||||
/// The Embedder should initialize the ResourceReader early.
|
||||
pub fn set(reader: Box<dyn ResourceReaderMethods + Sync + Send>) {
|
||||
*RES.write().unwrap() = Some(reader);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "baked-default-resources"))]
|
||||
pub fn read_bytes(res: Resource) -> Vec<u8> {
|
||||
if let Some(reader) = RES.read().unwrap().as_ref() {
|
||||
reader.read(res)
|
||||
} else {
|
||||
log::error!("Resource reader not set.");
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "baked-default-resources")]
|
||||
pub fn read_bytes(res: Resource) -> Vec<u8> {
|
||||
INIT_TEST_RESOURCES.call_once(|| {
|
||||
let mut reader = RES.write().unwrap();
|
||||
if reader.is_none() {
|
||||
*reader = Some(resources_for_tests())
|
||||
/// Register the [`ResourceReader`] implementation.
|
||||
///
|
||||
/// This should be added at most once in the whole project.
|
||||
/// In particular this means you should make sure to disable the (default)
|
||||
/// `baked-in-resources` feature of servo if you want to override the default reader.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Put `submit_resource_reader` invocations **outside** any function body:
|
||||
/// ```
|
||||
/// servo_embedder_traits::submit_resource_reader!(my_resource_reader);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! submit_resource_reader {
|
||||
($resource_reader:expr) => {
|
||||
$crate::resources::_inventory::submit! {
|
||||
$resource_reader as $crate::resources::ResourceReader
|
||||
}
|
||||
});
|
||||
RES.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.expect("Resource reader not set.")
|
||||
.read(res)
|
||||
};
|
||||
}
|
||||
|
||||
// The embedder may register a resource reader via `submit_resource_reader!()`
|
||||
// Note: A weak symbol would perhaps be preferable, but that isn't available in stable rust yet.
|
||||
inventory::collect!(ResourceReader);
|
||||
|
||||
static RESOURCE_READER: LazyLock<ResourceReader> = {
|
||||
LazyLock::new(|| {
|
||||
let mut resource_reader_iterator = inventory::iter::<ResourceReader>.into_iter();
|
||||
let Some(resource_reader) = resource_reader_iterator.next() else {
|
||||
panic!("No resource reader registered");
|
||||
};
|
||||
if resource_reader_iterator.next().is_some() {
|
||||
log::error!(
|
||||
"Multiple resource readers registered. Taking the first implementation \
|
||||
(random, non deterministic order). This is a bug! Check usages of \
|
||||
`submit_resource_reader!()`. Perhaps you meant to disable the default resource reader \
|
||||
(selected by depending on the `servo-default-resources` crate) ?"
|
||||
);
|
||||
}
|
||||
*resource_reader
|
||||
})
|
||||
};
|
||||
|
||||
pub fn read_bytes(res: Resource) -> Vec<u8> {
|
||||
RESOURCE_READER.read(res)
|
||||
}
|
||||
|
||||
pub fn read_string(res: Resource) -> String {
|
||||
@@ -51,19 +86,11 @@ pub fn read_string(res: Resource) -> String {
|
||||
}
|
||||
|
||||
pub fn sandbox_access_files() -> Vec<PathBuf> {
|
||||
RES.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.map(|reader| reader.sandbox_access_files())
|
||||
.unwrap_or_default()
|
||||
RESOURCE_READER.sandbox_access_files()
|
||||
}
|
||||
|
||||
pub fn sandbox_access_files_dirs() -> Vec<PathBuf> {
|
||||
RES.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.map(|reader| reader.sandbox_access_files_dirs())
|
||||
.unwrap_or_default()
|
||||
RESOURCE_READER.sandbox_access_files_dirs()
|
||||
}
|
||||
|
||||
pub enum Resource {
|
||||
@@ -146,45 +173,3 @@ pub trait ResourceReaderMethods {
|
||||
/// here to ensure the content process can access the files.
|
||||
fn sandbox_access_files_dirs(&self) -> Vec<PathBuf>;
|
||||
}
|
||||
|
||||
/// Provides baked in resources for tests.
|
||||
///
|
||||
/// Embedder builds (e.g. servoshell) should use [`set`] and ship the resources themselves.
|
||||
#[cfg(feature = "baked-default-resources")]
|
||||
fn resources_for_tests() -> Box<dyn ResourceReaderMethods + Sync + Send> {
|
||||
struct ResourceReader;
|
||||
impl ResourceReaderMethods for ResourceReader {
|
||||
fn sandbox_access_files(&self) -> Vec<PathBuf> {
|
||||
vec![]
|
||||
}
|
||||
fn sandbox_access_files_dirs(&self) -> Vec<PathBuf> {
|
||||
vec![]
|
||||
}
|
||||
fn read(&self, file: Resource) -> Vec<u8> {
|
||||
match file {
|
||||
Resource::BluetoothBlocklist => {
|
||||
&include_bytes!("../../../resources/gatt_blocklist.txt")[..]
|
||||
},
|
||||
Resource::DomainList => {
|
||||
&include_bytes!("../../../resources/public_domains.txt")[..]
|
||||
},
|
||||
Resource::HstsPreloadList => {
|
||||
&include_bytes!("../../../resources/hsts_preload.fstmap")[..]
|
||||
},
|
||||
Resource::BadCertHTML => &include_bytes!("../../../resources/badcert.html")[..],
|
||||
Resource::NetErrorHTML => &include_bytes!("../../../resources/neterror.html")[..],
|
||||
Resource::BrokenImageIcon => &include_bytes!("../../../resources/rippy.png")[..],
|
||||
Resource::CrashHTML => &include_bytes!("../../../resources/crash.html")[..],
|
||||
Resource::DirectoryListingHTML => {
|
||||
&include_bytes!("../../../resources/directory-listing.html")[..]
|
||||
},
|
||||
Resource::AboutMemoryHTML => {
|
||||
&include_bytes!("../../../resources/about-memory.html")[..]
|
||||
},
|
||||
Resource::DebuggerJS => &include_bytes!("../../../resources/debugger.js")[..],
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
}
|
||||
Box::new(ResourceReader)
|
||||
}
|
||||
|
||||
@@ -51,4 +51,4 @@ uuid = { workspace = true }
|
||||
webrender_api = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
embedder_traits = { workspace = true, features = ["baked-default-resources"] }
|
||||
servo-default-resources = { workspace = true }
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use net_traits::pub_domains::{is_pub_domain, is_reg_domain, pub_suffix, reg_suffix};
|
||||
use servo_default_resources as _;
|
||||
|
||||
// These tests may need to be updated if the PSL changes.
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ uuid = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
profile = { workspace = true }
|
||||
servo-default-resources = { workspace = true }
|
||||
url = { workspace = true }
|
||||
|
||||
[[test]]
|
||||
|
||||
@@ -6,6 +6,7 @@ use profile::mem as profile_mem;
|
||||
use servo_base::generic_channel as base_channel;
|
||||
use servo_base::generic_channel::GenericSend;
|
||||
use servo_base::id::TEST_WEBVIEW_ID;
|
||||
use servo_default_resources as _;
|
||||
use servo_url::ServoUrl;
|
||||
use storage_traits::StorageThreads;
|
||||
use storage_traits::webstorage_thread::{WebStorageThreadMsg, WebStorageType};
|
||||
|
||||
@@ -41,7 +41,8 @@ OriginalFilename = "servoshell.exe"
|
||||
ProductName = "ServoShell"
|
||||
|
||||
[features]
|
||||
default = ["gamepad", "servo/clipboard", "js_jit", "max_log_level", "webgpu", "webxr"]
|
||||
default = ["baked-in-resources", "gamepad", "servo/clipboard", "js_jit", "max_log_level", "webgpu", "webxr"]
|
||||
baked-in-resources = ["servo/baked-in-resources"]
|
||||
crown = ["servo/crown"]
|
||||
debugmozjs = ["servo/debugmozjs"]
|
||||
gamepad = ["servo/gamepad"]
|
||||
|
||||
@@ -12,7 +12,6 @@ use crate::prefs::{ArgumentParsingResult, parse_command_line_arguments};
|
||||
pub fn main() {
|
||||
crate::crash_handler::install();
|
||||
crate::init_crypto();
|
||||
crate::resources::init();
|
||||
|
||||
// TODO: once log-panics is released, can this be replaced by
|
||||
// log_panics::init()?
|
||||
|
||||
@@ -43,9 +43,7 @@ impl ResourceProtocolHandler {
|
||||
)));
|
||||
};
|
||||
|
||||
let file_path = crate::resources::resources_dir_path()
|
||||
.join("resource_protocol")
|
||||
.join(path);
|
||||
let file_path = crate::resources::resource_protocol_dir_path().join(path);
|
||||
|
||||
if !file_path.exists() || file_path.is_dir() {
|
||||
return Box::pin(std::future::ready(Response::network_error(
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
mod resources;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::ptr::NonNull;
|
||||
@@ -23,7 +21,6 @@ use raw_window_handle::{
|
||||
AndroidDisplayHandle, AndroidNdkWindowHandle, DisplayHandle, RawDisplayHandle, RawWindowHandle,
|
||||
WindowHandle,
|
||||
};
|
||||
use resources::ResourceReaderInstance;
|
||||
pub use servo::MediaSessionPlaybackState;
|
||||
use servo::{
|
||||
self, DevicePixel, EventLoopWaker, InputMethodControl, LoadStatus, MediaSessionActionType,
|
||||
@@ -165,7 +162,6 @@ pub extern "C" fn Java_org_servo_servoview_JNIServo_init<'local>(
|
||||
let host = Rc::new(HostCallbacks::new(callbacks_ref, &env));
|
||||
|
||||
crate::init_crypto();
|
||||
servo::resources::set(Box::new(ResourceReaderInstance::new()));
|
||||
|
||||
let (opts, mut preferences, servoshell_preferences) =
|
||||
match parse_command_line_arguments(init_opts.args.as_slice()) {
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/* 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::path::PathBuf;
|
||||
|
||||
use servo::resources::{Resource, ResourceReaderMethods};
|
||||
|
||||
pub(crate) struct ResourceReaderInstance;
|
||||
|
||||
impl ResourceReaderInstance {
|
||||
pub(crate) fn new() -> ResourceReaderInstance {
|
||||
ResourceReaderInstance
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceReaderMethods for ResourceReaderInstance {
|
||||
fn read(&self, res: Resource) -> Vec<u8> {
|
||||
Vec::from(match res {
|
||||
Resource::HstsPreloadList => {
|
||||
&include_bytes!("../../../../resources/hsts_preload.fstmap")[..]
|
||||
},
|
||||
Resource::BadCertHTML => &include_bytes!("../../../../resources/badcert.html")[..],
|
||||
Resource::NetErrorHTML => &include_bytes!("../../../../resources/neterror.html")[..],
|
||||
Resource::BrokenImageIcon => &include_bytes!("../../../../resources/rippy.png")[..],
|
||||
Resource::DomainList => &include_bytes!("../../../../resources/public_domains.txt")[..],
|
||||
Resource::BluetoothBlocklist => {
|
||||
&include_bytes!("../../../../resources/gatt_blocklist.txt")[..]
|
||||
},
|
||||
Resource::CrashHTML => &include_bytes!("../../../../resources/crash.html")[..],
|
||||
Resource::DirectoryListingHTML => {
|
||||
&include_bytes!("../../../../resources/directory-listing.html")[..]
|
||||
},
|
||||
Resource::AboutMemoryHTML => {
|
||||
&include_bytes!("../../../../resources/about-memory.html")[..]
|
||||
},
|
||||
Resource::DebuggerJS => &include_bytes!("../../../../resources/debugger.js")[..],
|
||||
})
|
||||
}
|
||||
|
||||
fn sandbox_access_files(&self) -> Vec<PathBuf> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn sandbox_access_files_dirs(&self) -> Vec<PathBuf> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
@@ -102,7 +102,6 @@ use xcomponent_sys::{
|
||||
|
||||
use super::app::{App, AppInitOptions, EmbeddedPlatformWindow, VsyncRefreshDriver};
|
||||
use super::host_trait::HostTrait;
|
||||
use crate::egl::ohos::resources::ResourceReaderInstance;
|
||||
use crate::prefs::{ArgumentParsingResult, parse_command_line_arguments};
|
||||
|
||||
/// Queue length for the thread-safe function to submit URL updates to ArkTS
|
||||
@@ -209,7 +208,7 @@ fn init_app(
|
||||
|
||||
let resource_dir = PathBuf::from(&options.resource_dir).join("servo");
|
||||
debug!("Resources are located at: {:?}", resource_dir);
|
||||
servo::resources::set(Box::new(ResourceReaderInstance::new(resource_dir.clone())));
|
||||
resources::set_resource_dir(resource_dir.clone());
|
||||
|
||||
let args = options
|
||||
.commandline_args
|
||||
|
||||
@@ -3,24 +3,37 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use servo::resources::{Resource, ResourceReaderMethods};
|
||||
|
||||
pub(crate) struct ResourceReaderInstance {
|
||||
resource_dir: PathBuf,
|
||||
pub(crate) struct ResourceReaderImpl {
|
||||
resource_dir: OnceLock<PathBuf>,
|
||||
}
|
||||
|
||||
impl ResourceReaderInstance {
|
||||
pub(crate) fn new(resource_dir: PathBuf) -> Self {
|
||||
assert!(resource_dir.is_dir());
|
||||
Self { resource_dir }
|
||||
static RESOURCE_READER: ResourceReaderImpl = ResourceReaderImpl {
|
||||
resource_dir: OnceLock::new(),
|
||||
};
|
||||
|
||||
servo::submit_resource_reader!(&RESOURCE_READER);
|
||||
|
||||
pub(crate) fn set_resource_dir(resource_dir: PathBuf) {
|
||||
if let Err(e) = RESOURCE_READER.resource_dir.set(resource_dir) {
|
||||
log::warn!("Failed to set resource dir: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceReaderMethods for ResourceReaderInstance {
|
||||
impl ResourceReaderMethods for ResourceReaderImpl {
|
||||
fn read(&self, res: Resource) -> Vec<u8> {
|
||||
let file_path = self.resource_dir.join(res.filename());
|
||||
fs::read(&file_path).expect("failed to read resource file")
|
||||
let file_path = RESOURCE_READER
|
||||
.resource_dir
|
||||
.get()
|
||||
.expect("Attempted to read resources before reader initialized")
|
||||
.join("named_resources")
|
||||
.join(res.filename());
|
||||
fs::read(&file_path).unwrap_or_else(|e| {
|
||||
panic!("Failed to read resource file: {:?}: {:?}", file_path, e);
|
||||
})
|
||||
}
|
||||
|
||||
fn sandbox_access_files(&self) -> Vec<PathBuf> {
|
||||
|
||||
@@ -19,7 +19,7 @@ mod egl;
|
||||
mod panic_hook;
|
||||
mod parser;
|
||||
mod prefs;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[cfg(not(any(target_os = "android", target_env = "ohos")))]
|
||||
mod resources;
|
||||
mod running_app_state;
|
||||
mod webdriver;
|
||||
|
||||
@@ -2,22 +2,19 @@
|
||||
* 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::env;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Mutex;
|
||||
use std::{env, fs};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use servo::resources::{self, Resource};
|
||||
|
||||
static CMD_RESOURCE_DIR: Mutex<Option<PathBuf>> = Mutex::new(None);
|
||||
|
||||
struct ResourceReader;
|
||||
|
||||
pub fn init() {
|
||||
resources::set(Box::new(ResourceReader));
|
||||
pub(crate) fn resource_protocol_dir_path() -> PathBuf {
|
||||
resource_root_dir_path().join("resource_protocol")
|
||||
}
|
||||
|
||||
pub(crate) fn resources_dir_path() -> PathBuf {
|
||||
fn resource_root_dir_path() -> PathBuf {
|
||||
// This needs to be called before the process is sandboxed
|
||||
// as we only give permission to read inside the resources directory,
|
||||
// not the permissions the "search" for the resources directory.
|
||||
@@ -27,7 +24,7 @@ pub(crate) fn resources_dir_path() -> PathBuf {
|
||||
}
|
||||
|
||||
// Try ./resources and ./Resources relative to the directory containing the
|
||||
// canonicalised executable path, then each of its ancestors.
|
||||
// canonicalized executable path, then each of its ancestors.
|
||||
let mut path = env::current_exe().unwrap().canonicalize().unwrap();
|
||||
while path.pop() {
|
||||
path.push("resources");
|
||||
@@ -51,7 +48,7 @@ pub(crate) fn resources_dir_path() -> PathBuf {
|
||||
panic!("Can't find resources directory")
|
||||
} else {
|
||||
// Static assert that this is really a non-production build, rather
|
||||
// than a failure of the build script’s production check.
|
||||
// than a failure of the build script's production check.
|
||||
const _: () = assert!(cfg!(servo_do_not_use_in_production));
|
||||
|
||||
// Try ./resources in the current directory, then each of its ancestors.
|
||||
@@ -72,17 +69,3 @@ pub(crate) fn resources_dir_path() -> PathBuf {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl resources::ResourceReaderMethods for ResourceReader {
|
||||
fn read(&self, file: Resource) -> Vec<u8> {
|
||||
let mut path = resources_dir_path();
|
||||
path.push(file.filename());
|
||||
fs::read(path).expect("Can't read file")
|
||||
}
|
||||
fn sandbox_access_files_dirs(&self) -> Vec<PathBuf> {
|
||||
vec![resources_dir_path()]
|
||||
}
|
||||
fn sandbox_access_files(&self) -> Vec<PathBuf> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ class MachCommands(CommandBase):
|
||||
@Command("update-hsts-preload", description="Download the HSTS preload list", category="bootstrap")
|
||||
def bootstrap_hsts_preload(self, force: bool = False) -> None:
|
||||
preload_filename = "hsts_preload.fstmap"
|
||||
preload_path = path.join(self.context.topdir, "resources")
|
||||
preload_path = path.join(self.context.topdir, "components", "default-resources", "resources")
|
||||
|
||||
chromium_hsts_url = (
|
||||
"https://chromium.googlesource.com/chromium/src"
|
||||
@@ -108,12 +108,18 @@ class MachCommands(CommandBase):
|
||||
|
||||
@Command(
|
||||
"update-pub-domains",
|
||||
description="Download the public domains list and update resources/public_domains.txt",
|
||||
description="Download the public domains list and update the copy in servo-default-resources",
|
||||
category="bootstrap",
|
||||
)
|
||||
def bootstrap_pub_suffix(self, force: bool = False) -> None:
|
||||
list_url = "https://publicsuffix.org/list/public_suffix_list.dat"
|
||||
dst_filename = path.join(self.context.topdir, "resources", "public_domains.txt")
|
||||
dst_filename = path.join(
|
||||
self.context.topdir,
|
||||
"components",
|
||||
"default-resources",
|
||||
"resources",
|
||||
"public_domains.txt",
|
||||
)
|
||||
not_implemented_case = re.compile(r"^[^*]+\*")
|
||||
|
||||
try:
|
||||
|
||||
@@ -69,6 +69,16 @@ def check_call_with_randomized_backoff(args: list[str], retries: int) -> int:
|
||||
return check_call_with_randomized_backoff(args, retries - 1)
|
||||
|
||||
|
||||
def copy_packaged_resources(top_dir: str, destination: str) -> None:
|
||||
os.makedirs(destination, exist_ok=True)
|
||||
shutil.copytree(path.join(top_dir, "resources"), destination, dirs_exist_ok=True)
|
||||
shutil.copytree(
|
||||
path.join(top_dir, "components", "default-resources", "resources"),
|
||||
path.join(destination, "named_resources"),
|
||||
dirs_exist_ok=True,
|
||||
)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class PackageCommands(CommandBase):
|
||||
@staticmethod
|
||||
@@ -176,7 +186,7 @@ class PackageCommands(CommandBase):
|
||||
if path.exists(dir_to_resources):
|
||||
delete(dir_to_resources)
|
||||
|
||||
shutil.copytree(path.join(dir_to_root, "resources"), dir_to_resources)
|
||||
copy_packaged_resources(dir_to_root, dir_to_resources)
|
||||
|
||||
variant = ":assemble" + flavor_name + arch_string + build_type_string
|
||||
apk_task_name = ":servoapp" + variant
|
||||
@@ -198,10 +208,8 @@ class PackageCommands(CommandBase):
|
||||
print("Cleaning up from previous packaging")
|
||||
delete(ohos_target_dir)
|
||||
shutil.copytree(ohos_app_dir, ohos_target_dir)
|
||||
resources_src_dir = path.join(self.get_top_dir(), "resources")
|
||||
resources_app_dir = path.join(ohos_target_dir, "AppScope", "resources", "resfile", "servo")
|
||||
os.makedirs(resources_app_dir, exist_ok=True)
|
||||
shutil.copytree(resources_src_dir, resources_app_dir, dirs_exist_ok=True)
|
||||
copy_packaged_resources(self.get_top_dir(), str(resources_app_dir))
|
||||
|
||||
# Map non-debug profiles to 'release' buildMode HAP.
|
||||
if build_type.is_custom():
|
||||
@@ -273,7 +281,7 @@ class PackageCommands(CommandBase):
|
||||
delete(dir_to_dmg)
|
||||
|
||||
print("Copying files")
|
||||
shutil.copytree(path.join(dir_to_root, "resources"), dir_to_resources)
|
||||
copy_packaged_resources(dir_to_root, dir_to_resources)
|
||||
shutil.copy2(
|
||||
path.join(dir_to_root, "ports/servoshell/platform/macos/Info.plist"),
|
||||
path.join(dir_to_app, "Contents", "Info.plist"),
|
||||
@@ -349,7 +357,7 @@ class PackageCommands(CommandBase):
|
||||
print("Copying files")
|
||||
dir_to_temp = path.join(dir_to_msi, "temp")
|
||||
dir_to_resources = path.join(dir_to_temp, "resources")
|
||||
shutil.copytree(path.join(dir_to_root, "resources"), dir_to_resources)
|
||||
copy_packaged_resources(dir_to_root, dir_to_resources)
|
||||
shutil.copy(binary_path, dir_to_temp)
|
||||
copy_windows_dependencies(target_dir, dir_to_temp)
|
||||
|
||||
@@ -417,7 +425,7 @@ class PackageCommands(CommandBase):
|
||||
|
||||
print("Copying files")
|
||||
dir_to_resources = path.join(dir_to_temp, "resources")
|
||||
shutil.copytree(path.join(dir_to_root, "resources"), dir_to_resources)
|
||||
copy_packaged_resources(dir_to_root, dir_to_resources)
|
||||
shutil.copy(binary_path, dir_to_temp)
|
||||
|
||||
print("Creating tarball")
|
||||
|
||||
@@ -5,7 +5,7 @@ skip-check-licenses = false
|
||||
# Files that are ignored for all tidy and lint checks.
|
||||
files = [
|
||||
"./components/shared/net/tests/parsable_mime/text",
|
||||
"./resources/hsts_preload.fstmap",
|
||||
"./components/default-resources/resources/hsts_preload.fstmap",
|
||||
"./tests/wpt/meta/MANIFEST.json",
|
||||
"./tests/wpt/mozilla/meta/MANIFEST.json",
|
||||
# Long encoded string
|
||||
|
||||
Reference in New Issue
Block a user