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
@@ -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![]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user