mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Remove the libsimpleservo C API (#31172)
This is unused and unmaintained. It also added a bit of complication to the build.
This commit is contained in:
parent
b10875956a
commit
bbba839278
20 changed files with 159 additions and 1758 deletions
121
Cargo.lock
generated
121
Cargo.lock
generated
|
@ -267,17 +267,6 @@ version = "0.1.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c"
|
checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "atty"
|
|
||||||
version = "0.2.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi 0.1.19",
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -679,25 +668,6 @@ dependencies = [
|
||||||
"webxr-api",
|
"webxr-api",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cbindgen"
|
|
||||||
version = "0.26.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49"
|
|
||||||
dependencies = [
|
|
||||||
"clap",
|
|
||||||
"heck",
|
|
||||||
"indexmap 1.9.3",
|
|
||||||
"log",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"syn 1.0.103",
|
|
||||||
"tempfile",
|
|
||||||
"toml 0.5.9",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.83"
|
version = "1.0.83"
|
||||||
|
@ -779,30 +749,6 @@ dependencies = [
|
||||||
"libloading 0.8.0",
|
"libloading 0.8.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap"
|
|
||||||
version = "3.2.25"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
|
|
||||||
dependencies = [
|
|
||||||
"atty",
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"clap_lex",
|
|
||||||
"indexmap 1.9.3",
|
|
||||||
"strsim",
|
|
||||||
"termcolor",
|
|
||||||
"textwrap",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap_lex"
|
|
||||||
version = "0.2.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
|
||||||
dependencies = [
|
|
||||||
"os_str_bytes",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clipboard-win"
|
name = "clipboard-win"
|
||||||
version = "4.5.0"
|
version = "4.5.0"
|
||||||
|
@ -2664,15 +2610,6 @@ version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.1.19"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -2948,7 +2885,7 @@ version = "0.4.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
|
checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.3.2",
|
"hermit-abi",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
@ -4041,7 +3978,7 @@ version = "1.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.3.2",
|
"hermit-abi",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -4179,12 +4116,6 @@ version = "0.3.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
|
checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "os_str_bytes"
|
|
||||||
version = "6.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "owned_ttf_parser"
|
name = "owned_ttf_parser"
|
||||||
version = "0.20.0"
|
version = "0.20.0"
|
||||||
|
@ -5562,13 +5493,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "simpleservo"
|
name = "simpleservo_jniapi"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation",
|
"android_logger",
|
||||||
|
"cc",
|
||||||
"getopts",
|
"getopts",
|
||||||
"gl_generator",
|
"gl_generator",
|
||||||
"ipc-channel",
|
"ipc-channel",
|
||||||
|
"jni",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading 0.8.0",
|
"libloading 0.8.0",
|
||||||
"libservo",
|
"libservo",
|
||||||
|
@ -5578,36 +5511,6 @@ dependencies = [
|
||||||
"surfman",
|
"surfman",
|
||||||
"vergen",
|
"vergen",
|
||||||
"webxr",
|
"webxr",
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "simpleservo_capi"
|
|
||||||
version = "0.0.1"
|
|
||||||
dependencies = [
|
|
||||||
"backtrace",
|
|
||||||
"cbindgen",
|
|
||||||
"env_logger 0.10.2",
|
|
||||||
"keyboard-types",
|
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"simpleservo",
|
|
||||||
"surfman",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "simpleservo_jniapi"
|
|
||||||
version = "0.0.1"
|
|
||||||
dependencies = [
|
|
||||||
"android_logger",
|
|
||||||
"cc",
|
|
||||||
"jni",
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"serde_json",
|
|
||||||
"simpleservo",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -5779,12 +5682,6 @@ dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strsim"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "style"
|
name = "style"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -6083,12 +5980,6 @@ dependencies = [
|
||||||
"term",
|
"term",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "textwrap"
|
|
||||||
version = "0.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thin-vec"
|
name = "thin-vec"
|
||||||
version = "0.2.13"
|
version = "0.2.13"
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
"ports/servoshell",
|
"ports/servoshell",
|
||||||
"ports/libsimpleservo/capi/",
|
"ports/jniapi/",
|
||||||
"ports/libsimpleservo/jniapi/",
|
|
||||||
"tests/unit/*",
|
"tests/unit/*",
|
||||||
"support/crown",
|
"support/crown",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,40 +1,43 @@
|
||||||
[package]
|
[package]
|
||||||
name = "simpleservo"
|
name = "simpleservo_jniapi"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
authors = ["The Servo Project Developers"]
|
authors = ["The Servo Project Developers"]
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
publish = false
|
publish = false
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "simpleservo"
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
test = false
|
||||||
|
bench = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
android_logger = "0.13"
|
||||||
getopts = { workspace = true }
|
getopts = { workspace = true }
|
||||||
ipc-channel = { workspace = true }
|
ipc-channel = { workspace = true }
|
||||||
libservo = { path = "../../../components/servo" }
|
jni = "0.18.0"
|
||||||
|
libc = { workspace = true }
|
||||||
|
libloading = "0.8"
|
||||||
|
libservo = { path = "../../components/servo" }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
|
serde_json = { workspace = true }
|
||||||
servo-media = { git = "https://github.com/servo/media" }
|
servo-media = { git = "https://github.com/servo/media" }
|
||||||
surfman = { workspace = true, features = ["sm-angle-default"] }
|
surfman = { workspace = true, features = ["sm-angle-default"] }
|
||||||
webxr = { git = "https://github.com/servo/webxr" }
|
webxr = { git = "https://github.com/servo/webxr" }
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
|
||||||
libc = { workspace = true }
|
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
|
||||||
core-foundation = "0.9"
|
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
|
||||||
winapi = { workspace = true }
|
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))'.dependencies]
|
|
||||||
libloading = "0.8"
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
cc = "1.0"
|
||||||
gl_generator = "0.14"
|
gl_generator = "0.14"
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
vergen = { version = "8.0.0", features = ["git", "gitcl"] }
|
vergen = { version = "8.0.0", features = ["git", "gitcl"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debugmozjs = ["libservo/debugmozjs"]
|
debugmozjs = ["libservo/debugmozjs"]
|
||||||
default = ["max_log_level", "native-bluetooth", "webdriver"]
|
# TODO: Once the native-bluetooth feature works for
|
||||||
|
# Android, re-add it here.
|
||||||
|
default = ["max_log_level", "webdriver"]
|
||||||
googlevr = ["libservo/googlevr"]
|
googlevr = ["libservo/googlevr"]
|
||||||
jitspew = ["libservo/jitspew"]
|
jitspew = ["libservo/jitspew"]
|
||||||
js_backtrace = ["libservo/js_backtrace"]
|
js_backtrace = ["libservo/js_backtrace"]
|
43
ports/jniapi/build.rs
Normal file
43
ports/jniapi/build.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/* 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::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use gl_generator::{Api, Fallbacks, Profile, Registry};
|
||||||
|
use serde_json::{self, Value};
|
||||||
|
use vergen::EmitBuilder;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let target = env::var("TARGET").unwrap();
|
||||||
|
let dest = PathBuf::from(&env::var("OUT_DIR").unwrap());
|
||||||
|
|
||||||
|
if let Err(error) = EmitBuilder::builder()
|
||||||
|
.fail_on_error()
|
||||||
|
.git_sha(true /* short */)
|
||||||
|
.emit()
|
||||||
|
{
|
||||||
|
println!(
|
||||||
|
"cargo:warning=Could not generate git version information: {:?}",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
println!("cargo:rustc-env=VERGEN_GIT_SHA=nogit");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate GL bindings. For now, we only support EGL.
|
||||||
|
if target.contains("android") {
|
||||||
|
let mut file = File::create(&dest.join("egl_bindings.rs")).unwrap();
|
||||||
|
Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
|
||||||
|
.write_bindings(gl_generator::StaticStructGenerator, &mut file)
|
||||||
|
.unwrap();
|
||||||
|
println!("cargo:rustc-link-lib=EGL");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut default_prefs = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
default_prefs.push("../../resources/prefs.json");
|
||||||
|
let prefs: Value = serde_json::from_reader(File::open(&default_prefs).unwrap()).unwrap();
|
||||||
|
let file = File::create(&dest.join("prefs.json")).unwrap();
|
||||||
|
serde_json::to_writer(file, &prefs).unwrap();
|
||||||
|
}
|
58
ports/jniapi/src/gl_glue.rs
Normal file
58
ports/jniapi/src/gl_glue.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#![allow(bare_trait_objects)] // Until https://github.com/brendanzab/gl-rs/pull/493
|
||||||
|
//
|
||||||
|
pub type ServoGl = std::rc::Rc<dyn servo::gl::Gl>;
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "android", target_os = "windows"))]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub mod egl {
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
|
use log::info;
|
||||||
|
use servo::gl::GlesFns;
|
||||||
|
|
||||||
|
pub type EGLNativeWindowType = *const libc::c_void;
|
||||||
|
pub type khronos_utime_nanoseconds_t = khronos_uint64_t;
|
||||||
|
pub type khronos_uint64_t = u64;
|
||||||
|
pub type khronos_ssize_t = libc::c_long;
|
||||||
|
pub type EGLint = i32;
|
||||||
|
pub type EGLContext = *const libc::c_void;
|
||||||
|
pub type EGLNativeDisplayType = *const libc::c_void;
|
||||||
|
pub type EGLNativePixmapType = *const libc::c_void;
|
||||||
|
pub type NativeDisplayType = EGLNativeDisplayType;
|
||||||
|
pub type NativePixmapType = EGLNativePixmapType;
|
||||||
|
pub type NativeWindowType = EGLNativeWindowType;
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs"));
|
||||||
|
|
||||||
|
pub struct EGLInitResult {
|
||||||
|
pub gl_wrapper: crate::gl_glue::ServoGl,
|
||||||
|
pub gl_context: EGLContext,
|
||||||
|
pub display: EGLNativeDisplayType,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() -> Result<EGLInitResult, &'static str> {
|
||||||
|
info!("Loading EGL...");
|
||||||
|
unsafe {
|
||||||
|
let egl = Egl;
|
||||||
|
let display = egl.GetCurrentDisplay();
|
||||||
|
egl.SwapInterval(display, 1);
|
||||||
|
let egl = GlesFns::load_with(|addr| {
|
||||||
|
let addr = CString::new(addr.as_bytes()).unwrap();
|
||||||
|
let addr = addr.as_ptr();
|
||||||
|
let egl = Egl;
|
||||||
|
egl.GetProcAddress(addr) as *const c_void
|
||||||
|
});
|
||||||
|
info!("EGL loaded");
|
||||||
|
Ok(EGLInitResult {
|
||||||
|
gl_wrapper: egl,
|
||||||
|
gl_context: Egl.GetCurrentContext(),
|
||||||
|
display,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
mod gl_glue;
|
||||||
|
mod simpleservo;
|
||||||
|
|
||||||
use std::os::raw::{c_char, c_int, c_void};
|
use std::os::raw::{c_char, c_int, c_void};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
@ -15,8 +18,8 @@ use jni::{JNIEnv, JavaVM};
|
||||||
use libc::{dup2, pipe, read};
|
use libc::{dup2, pipe, read};
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
use simpleservo::{
|
use simpleservo::{
|
||||||
self, gl_glue, Coordinates, DeviceIntRect, EventLoopWaker, HostTrait, InitOptions,
|
Coordinates, DeviceIntRect, EventLoopWaker, HostTrait, InitOptions, InputMethodType,
|
||||||
InputMethodType, MediaSessionPlaybackState, PromptResult, ServoGlue, SERVO,
|
MediaSessionPlaybackState, PromptResult, ServoGlue, SERVO,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HostCallbacks {
|
struct HostCallbacks {
|
|
@ -2,8 +2,6 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
pub mod gl_glue;
|
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -941,28 +939,28 @@ impl ResourceReaderMethods for ResourceReaderInstance {
|
||||||
Vec::from(match res {
|
Vec::from(match res {
|
||||||
Resource::Preferences => &include_bytes!(concat!(env!("OUT_DIR"), "/prefs.json"))[..],
|
Resource::Preferences => &include_bytes!(concat!(env!("OUT_DIR"), "/prefs.json"))[..],
|
||||||
Resource::HstsPreloadList => {
|
Resource::HstsPreloadList => {
|
||||||
&include_bytes!("../../../../resources/hsts_preload.json")[..]
|
&include_bytes!("../../../resources/hsts_preload.json")[..]
|
||||||
},
|
},
|
||||||
Resource::BadCertHTML => &include_bytes!("../../../../resources/badcert.html")[..],
|
Resource::BadCertHTML => &include_bytes!("../../../resources/badcert.html")[..],
|
||||||
Resource::NetErrorHTML => &include_bytes!("../../../../resources/neterror.html")[..],
|
Resource::NetErrorHTML => &include_bytes!("../../../resources/neterror.html")[..],
|
||||||
Resource::UserAgentCSS => &include_bytes!("../../../../resources/user-agent.css")[..],
|
Resource::UserAgentCSS => &include_bytes!("../../../resources/user-agent.css")[..],
|
||||||
Resource::ServoCSS => &include_bytes!("../../../../resources/servo.css")[..],
|
Resource::ServoCSS => &include_bytes!("../../../resources/servo.css")[..],
|
||||||
Resource::PresentationalHintsCSS => {
|
Resource::PresentationalHintsCSS => {
|
||||||
&include_bytes!("../../../../resources/presentational-hints.css")[..]
|
&include_bytes!("../../../resources/presentational-hints.css")[..]
|
||||||
},
|
},
|
||||||
Resource::QuirksModeCSS => &include_bytes!("../../../../resources/quirks-mode.css")[..],
|
Resource::QuirksModeCSS => &include_bytes!("../../../resources/quirks-mode.css")[..],
|
||||||
Resource::RippyPNG => &include_bytes!("../../../../resources/rippy.png")[..],
|
Resource::RippyPNG => &include_bytes!("../../../resources/rippy.png")[..],
|
||||||
Resource::DomainList => &include_bytes!("../../../../resources/public_domains.txt")[..],
|
Resource::DomainList => &include_bytes!("../../../resources/public_domains.txt")[..],
|
||||||
Resource::BluetoothBlocklist => {
|
Resource::BluetoothBlocklist => {
|
||||||
&include_bytes!("../../../../resources/gatt_blocklist.txt")[..]
|
&include_bytes!("../../../resources/gatt_blocklist.txt")[..]
|
||||||
},
|
},
|
||||||
Resource::MediaControlsCSS => {
|
Resource::MediaControlsCSS => {
|
||||||
&include_bytes!("../../../../resources/media-controls.css")[..]
|
&include_bytes!("../../../resources/media-controls.css")[..]
|
||||||
},
|
},
|
||||||
Resource::MediaControlsJS => {
|
Resource::MediaControlsJS => {
|
||||||
&include_bytes!("../../../../resources/media-controls.js")[..]
|
&include_bytes!("../../../resources/media-controls.js")[..]
|
||||||
},
|
},
|
||||||
Resource::CrashHTML => &include_bytes!("../../../../resources/crash.html")[..],
|
Resource::CrashHTML => &include_bytes!("../../../resources/crash.html")[..],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
# libsimpleservo
|
|
||||||
This is a basic wrapper around Servo. While libservo itself (/components/servo/) offers a lot of flexibility,
|
|
||||||
libsimpleservo (/ports/libsimpleservo/) tries to make it easier to embed Servo, without much configuration needed.
|
|
||||||
It is limited to only one view (no tabs, no multiple rendering area).
|
|
||||||
|
|
||||||
## Building
|
|
||||||
Run the following command to generate `libsimpleservo`
|
|
||||||
```
|
|
||||||
./mach build --release --libsimpleservo
|
|
||||||
```
|
|
||||||
this will generate a shared library (`libsimpleservo.so` on linux) as well as a header file in `target/release` that you can then link to your application.
|
|
|
@ -1,70 +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::env;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use gl_generator::{Api, Fallbacks, Profile, Registry};
|
|
||||||
use serde_json::{self, Value};
|
|
||||||
use vergen::EmitBuilder;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let target = env::var("TARGET").unwrap();
|
|
||||||
let dest = PathBuf::from(&env::var("OUT_DIR").unwrap());
|
|
||||||
|
|
||||||
if let Err(error) = EmitBuilder::builder()
|
|
||||||
.fail_on_error()
|
|
||||||
.git_sha(true /* short */)
|
|
||||||
.emit()
|
|
||||||
{
|
|
||||||
println!(
|
|
||||||
"cargo:warning=Could not generate git version information: {:?}",
|
|
||||||
error
|
|
||||||
);
|
|
||||||
println!("cargo:rustc-env=VERGEN_GIT_SHA=nogit");
|
|
||||||
}
|
|
||||||
|
|
||||||
// On MacOS, all dylib dependencies are shipped along with the binary
|
|
||||||
// in the "/lib" directory. Setting the rpath here, allows the dynamic
|
|
||||||
// linker to locate them. See `man dyld` for more info.
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path/lib/");
|
|
||||||
|
|
||||||
// Generate GL bindings
|
|
||||||
// For now, we only support EGL, and only on Windows and Android.
|
|
||||||
if target.contains("android") || target.contains("windows") {
|
|
||||||
let mut file = File::create(&dest.join("egl_bindings.rs")).unwrap();
|
|
||||||
Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
|
|
||||||
.write_bindings(gl_generator::StaticStructGenerator, &mut file)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Historically, Android builds have succeeded with rustc-link-lib=EGL.
|
|
||||||
// On Windows when relying on %LIBS% to contain libEGL.lib, however,
|
|
||||||
// we must explicitly use rustc-link-lib=libEGL or rustc will attempt
|
|
||||||
// to link EGL.lib instead.
|
|
||||||
if target.contains("windows") {
|
|
||||||
println!("cargo:rustc-link-lib=libEGL");
|
|
||||||
} else {
|
|
||||||
println!("cargo:rustc-link-lib=EGL");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if target.contains("linux") ||
|
|
||||||
target.contains("dragonfly") ||
|
|
||||||
target.contains("freebsd") ||
|
|
||||||
target.contains("openbsd")
|
|
||||||
{
|
|
||||||
let mut file = File::create(&dest.join("glx_bindings.rs")).unwrap();
|
|
||||||
Registry::new(Api::Glx, (1, 4), Profile::Core, Fallbacks::All, [])
|
|
||||||
.write_bindings(gl_generator::StructGenerator, &mut file)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut default_prefs = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
||||||
default_prefs.push("../../../resources/prefs.json");
|
|
||||||
let prefs: Value = serde_json::from_reader(File::open(&default_prefs).unwrap()).unwrap();
|
|
||||||
let file = File::create(&dest.join("prefs.json")).unwrap();
|
|
||||||
serde_json::to_writer(file, &prefs).unwrap();
|
|
||||||
}
|
|
|
@ -1,141 +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/. */
|
|
||||||
|
|
||||||
#![allow(bare_trait_objects)] // Until https://github.com/brendanzab/gl-rs/pull/493
|
|
||||||
//
|
|
||||||
pub type ServoGl = std::rc::Rc<dyn servo::gl::Gl>;
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "android", target_os = "windows"))]
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
pub mod egl {
|
|
||||||
use std::ffi::CString;
|
|
||||||
use std::os::raw::c_void;
|
|
||||||
|
|
||||||
use log::info;
|
|
||||||
use servo::gl::GlesFns;
|
|
||||||
|
|
||||||
pub type EGLNativeWindowType = *const libc::c_void;
|
|
||||||
pub type khronos_utime_nanoseconds_t = khronos_uint64_t;
|
|
||||||
pub type khronos_uint64_t = u64;
|
|
||||||
pub type khronos_ssize_t = libc::c_long;
|
|
||||||
pub type EGLint = i32;
|
|
||||||
pub type EGLContext = *const libc::c_void;
|
|
||||||
pub type EGLNativeDisplayType = *const libc::c_void;
|
|
||||||
pub type EGLNativePixmapType = *const libc::c_void;
|
|
||||||
pub type NativeDisplayType = EGLNativeDisplayType;
|
|
||||||
pub type NativePixmapType = EGLNativePixmapType;
|
|
||||||
pub type NativeWindowType = EGLNativeWindowType;
|
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs"));
|
|
||||||
|
|
||||||
pub struct EGLInitResult {
|
|
||||||
pub gl_wrapper: crate::gl_glue::ServoGl,
|
|
||||||
pub gl_context: EGLContext,
|
|
||||||
pub display: EGLNativeDisplayType,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init() -> Result<EGLInitResult, &'static str> {
|
|
||||||
info!("Loading EGL...");
|
|
||||||
unsafe {
|
|
||||||
let egl = Egl;
|
|
||||||
let display = egl.GetCurrentDisplay();
|
|
||||||
egl.SwapInterval(display, 1);
|
|
||||||
let egl = GlesFns::load_with(|addr| {
|
|
||||||
let addr = CString::new(addr.as_bytes()).unwrap();
|
|
||||||
let addr = addr.as_ptr();
|
|
||||||
let egl = Egl;
|
|
||||||
egl.GetProcAddress(addr) as *const c_void
|
|
||||||
});
|
|
||||||
info!("EGL loaded");
|
|
||||||
Ok(EGLInitResult {
|
|
||||||
gl_wrapper: egl,
|
|
||||||
gl_context: Egl.GetCurrentContext(),
|
|
||||||
display,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub mod gl {
|
|
||||||
pub fn init() -> Result<crate::gl_glue::ServoGl, &'static str> {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub mod gl {
|
|
||||||
use std::os::raw::c_void;
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
use core_foundation::base::TCFType;
|
|
||||||
use core_foundation::bundle::{
|
|
||||||
CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName,
|
|
||||||
};
|
|
||||||
use core_foundation::string::CFString;
|
|
||||||
use log::info;
|
|
||||||
use servo::gl::GlFns;
|
|
||||||
|
|
||||||
pub fn init() -> Result<crate::gl_glue::ServoGl, &'static str> {
|
|
||||||
info!("Loading OpenGL...");
|
|
||||||
let gl = unsafe {
|
|
||||||
GlFns::load_with(|addr| {
|
|
||||||
let symbol_name: CFString = str::FromStr::from_str(addr).unwrap();
|
|
||||||
let framework_name: CFString = str::FromStr::from_str("com.apple.opengl").unwrap();
|
|
||||||
let framework =
|
|
||||||
CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef());
|
|
||||||
let symbol =
|
|
||||||
CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef());
|
|
||||||
symbol as *const c_void
|
|
||||||
})
|
|
||||||
};
|
|
||||||
info!("OpenGL loaded");
|
|
||||||
Ok(gl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(
|
|
||||||
target_os = "linux",
|
|
||||||
target_os = "dragonfly",
|
|
||||||
target_os = "freebsd",
|
|
||||||
target_os = "openbsd"
|
|
||||||
))]
|
|
||||||
pub mod gl {
|
|
||||||
use std::ffi::CString;
|
|
||||||
use std::os::raw::c_void;
|
|
||||||
|
|
||||||
use libloading::{Library, Symbol};
|
|
||||||
use log::info;
|
|
||||||
use servo::gl::GlFns;
|
|
||||||
|
|
||||||
pub fn init() -> Result<crate::gl_glue::ServoGl, &'static str> {
|
|
||||||
info!("Loading OpenGL");
|
|
||||||
|
|
||||||
pub mod glx {
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/glx_bindings.rs"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let lib = match unsafe { Library::new("libGL.so.1").or_else(|_| Library::new("libGL.so")) }
|
|
||||||
{
|
|
||||||
Ok(lib) => lib,
|
|
||||||
Err(_) => return Err("Can't find libGL.so, OpenGL isn't configured/installed"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let glx = glx::Glx::load_with(|sym| unsafe {
|
|
||||||
let symbol: Symbol<*const c_void> = lib.get(sym.as_bytes()).unwrap();
|
|
||||||
*symbol.into_raw()
|
|
||||||
});
|
|
||||||
|
|
||||||
let gl = unsafe {
|
|
||||||
GlFns::load_with(|addr| {
|
|
||||||
let addr = CString::new(addr.as_bytes()).unwrap();
|
|
||||||
glx.GetProcAddress(addr.as_ptr() as *const _) as *const _
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
info!("OpenGL is loaded");
|
|
||||||
|
|
||||||
Ok(gl)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "simpleservo_capi"
|
|
||||||
version = "0.0.1"
|
|
||||||
authors = ["The Servo Project Developers"]
|
|
||||||
license = "MPL-2.0"
|
|
||||||
edition = "2018"
|
|
||||||
publish = false
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
name = "simpleservo"
|
|
||||||
crate-type = ["cdylib"]
|
|
||||||
test = false
|
|
||||||
bench = false
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
backtrace = { workspace = true }
|
|
||||||
env_logger = { workspace = true }
|
|
||||||
lazy_static = { workspace = true }
|
|
||||||
log = { workspace = true }
|
|
||||||
simpleservo = { path = "../api" }
|
|
||||||
surfman = { workspace = true }
|
|
||||||
keyboard-types = { workspace = true }
|
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
|
||||||
libc = { workspace = true }
|
|
||||||
winapi = { workspace = true, features = ["wingdi", "winuser", "winnt", "winbase", "processenv", "namedpipeapi", "ntdef", "minwindef", "handleapi", "debugapi"] }
|
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
cbindgen = "0.26"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
debugmozjs = ["simpleservo/debugmozjs"]
|
|
||||||
default = ["webdriver", "max_log_level"]
|
|
||||||
googlevr = ["simpleservo/googlevr"]
|
|
||||||
jitspew = ["simpleservo/jitspew"]
|
|
||||||
js_backtrace = ["simpleservo/js_backtrace"]
|
|
||||||
max_log_level = ["simpleservo/max_log_level"]
|
|
||||||
media-gstreamer = ["simpleservo/media-gstreamer"]
|
|
||||||
native-bluetooth = ["simpleservo/native-bluetooth"]
|
|
||||||
no-wgl = ["simpleservo/no-wgl"]
|
|
||||||
profilemozjs = ["simpleservo/profilemozjs"]
|
|
||||||
refcell_backtrace = ["simpleservo/refcell_backtrace"]
|
|
||||||
webdriver = ["simpleservo/webdriver"]
|
|
||||||
webgl_backtrace = ["simpleservo/webgl_backtrace"]
|
|
||||||
xr-profile = ["simpleservo/xr-profile"]
|
|
|
@ -1,23 +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::env;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
|
||||||
let target_dir = env::var("CARGO_TARGET_DIR").unwrap();
|
|
||||||
let mut path: PathBuf = [crate_dir.clone(), target_dir].iter().collect();
|
|
||||||
let target = env::var("TARGET").unwrap();
|
|
||||||
let host = env::var("HOST").unwrap();
|
|
||||||
if target != host {
|
|
||||||
path.push(target);
|
|
||||||
}
|
|
||||||
let profile_dir = env::var("PROFILE").unwrap();
|
|
||||||
path.push(profile_dir);
|
|
||||||
path.push("simpleservo.h");
|
|
||||||
cbindgen::generate(crate_dir)
|
|
||||||
.expect("Unable to generate C bindings")
|
|
||||||
.write_to_file(path);
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
language = "C"
|
|
||||||
include_guard = "simpleservo_h"
|
|
||||||
cpp_compat = true
|
|
||||||
tab_width = 4
|
|
||||||
documentation_style = "c99"
|
|
||||||
|
|
||||||
[export]
|
|
||||||
exclude = ["OutputDebugStringA"]
|
|
|
@ -1,953 +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/. */
|
|
||||||
|
|
||||||
mod prefs;
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
mod vslogger;
|
|
||||||
|
|
||||||
use std::ffi::{CStr, CString};
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
use std::mem;
|
|
||||||
use std::os::raw::{c_char, c_uint, c_void};
|
|
||||||
use std::slice;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use std::sync::{Mutex, RwLock};
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
use env_logger;
|
|
||||||
use keyboard_types::Key;
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use log::{debug, error, info, warn, LevelFilter};
|
|
||||||
use simpleservo::{
|
|
||||||
self, gl_glue, ContextMenuResult, Coordinates, DeviceIntRect, EventLoopWaker, HostTrait,
|
|
||||||
InitOptions, InputMethodType, MediaSessionActionType, MediaSessionPlaybackState, MouseButton,
|
|
||||||
PromptResult, ServoGlue, SurfmanIntegration, SERVO,
|
|
||||||
};
|
|
||||||
|
|
||||||
extern "C" fn default_panic_handler(msg: *const c_char) {
|
|
||||||
let c_str: &CStr = unsafe { CStr::from_ptr(msg) };
|
|
||||||
error!("{}", c_str.to_str().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
type LogHandlerFn = extern "C" fn(buffer: *const c_char, len: u32);
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref ON_PANIC: RwLock<extern "C" fn(*const c_char)> = RwLock::new(default_panic_handler);
|
|
||||||
static ref SERVO_VERSION: CString =
|
|
||||||
CString::new(simpleservo::servo_version()).expect("Can't create string");
|
|
||||||
pub(crate) static ref OUTPUT_LOG_HANDLER: Mutex<Option<LogHandlerFn>> = Mutex::new(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn register_panic_handler(on_panic: extern "C" fn(*const c_char)) {
|
|
||||||
*ON_PANIC.write().unwrap() = on_panic;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Report panic to embedder.
|
|
||||||
fn report_panic(reason: &str, backtrace: Option<String>) {
|
|
||||||
let message = match backtrace {
|
|
||||||
Some(bt) => format!("Servo panic ({})\n{}", reason, bt),
|
|
||||||
None => format!("Servo panic ({})", reason),
|
|
||||||
};
|
|
||||||
let error = CString::new(message).expect("Can't create string");
|
|
||||||
(ON_PANIC.read().unwrap())(error.as_ptr());
|
|
||||||
// At this point, embedder should probably have thrown, so we never reach
|
|
||||||
// this point. But if it didn't, don't recursively panic.
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
fn redirect_stdout_stderr(_handler: LogHandlerFn) -> Result<(), String> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn redirect_stdout_stderr(handler: LogHandlerFn) -> Result<(), String> {
|
|
||||||
do_redirect_stdout_stderr(handler).map_err(|()| {
|
|
||||||
format!("GetLastError() = {}", unsafe {
|
|
||||||
winapi::um::errhandlingapi::GetLastError()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
// Function to redirect STDOUT (1) and STDERR(2) to Windows API
|
|
||||||
// OutputDebugString().
|
|
||||||
// Return Value: Result<(), String>
|
|
||||||
// Ok() - stdout and stderr redirects.
|
|
||||||
// Err(str) - The Err value can contain the string value of GetLastError.
|
|
||||||
fn do_redirect_stdout_stderr(handler: LogHandlerFn) -> Result<(), ()> {
|
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
use winapi::shared;
|
|
||||||
use winapi::um::{handleapi, minwinbase, namedpipeapi, processenv, winbase, winnt};
|
|
||||||
|
|
||||||
let mut h_read_pipe: winnt::HANDLE = handleapi::INVALID_HANDLE_VALUE;
|
|
||||||
let mut h_write_pipe: winnt::HANDLE = handleapi::INVALID_HANDLE_VALUE;
|
|
||||||
let mut secattr: minwinbase::SECURITY_ATTRIBUTES = unsafe { mem::zeroed() };
|
|
||||||
const BUF_LENGTH: usize = 1024;
|
|
||||||
|
|
||||||
secattr.nLength = mem::size_of::<minwinbase::SECURITY_ATTRIBUTES>() as u32;
|
|
||||||
secattr.bInheritHandle = shared::minwindef::TRUE;
|
|
||||||
secattr.lpSecurityDescriptor = shared::ntdef::NULL;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
if namedpipeapi::CreatePipe(
|
|
||||||
&mut h_read_pipe,
|
|
||||||
&mut h_write_pipe,
|
|
||||||
&mut secattr,
|
|
||||||
BUF_LENGTH as u32,
|
|
||||||
) == 0
|
|
||||||
{
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
if processenv::SetStdHandle(winbase::STD_OUTPUT_HANDLE, h_write_pipe) == 0 ||
|
|
||||||
processenv::SetStdHandle(winbase::STD_ERROR_HANDLE, h_write_pipe) == 0
|
|
||||||
{
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
if handleapi::SetHandleInformation(
|
|
||||||
h_read_pipe,
|
|
||||||
winbase::HANDLE_FLAG_INHERIT,
|
|
||||||
winbase::HANDLE_FLAG_INHERIT,
|
|
||||||
) == 0 ||
|
|
||||||
handleapi::SetHandleInformation(
|
|
||||||
h_write_pipe,
|
|
||||||
winbase::HANDLE_FLAG_INHERIT,
|
|
||||||
winbase::HANDLE_FLAG_INHERIT,
|
|
||||||
) == 0
|
|
||||||
{
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let h_read_pipe_fd = libc::open_osfhandle(h_read_pipe as libc::intptr_t, libc::O_RDONLY);
|
|
||||||
let h_write_pipe_fd = libc::open_osfhandle(h_write_pipe as libc::intptr_t, libc::O_WRONLY);
|
|
||||||
|
|
||||||
if h_read_pipe_fd == -1 || h_write_pipe_fd == -1 {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0 indicates success.
|
|
||||||
if libc::dup2(h_write_pipe_fd, 1) != 0 || libc::dup2(h_write_pipe_fd, 2) != 0 {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If SetStdHandle(winbase::STD_OUTPUT_HANDLE, hWritePipe) is not called prior,
|
|
||||||
// this will fail. GetStdHandle() is used to make certain "servo" has the stdout
|
|
||||||
// file descriptor associated.
|
|
||||||
let h_stdout = processenv::GetStdHandle(winbase::STD_OUTPUT_HANDLE);
|
|
||||||
if h_stdout == handleapi::INVALID_HANDLE_VALUE || h_stdout == shared::ntdef::NULL {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If SetStdHandle(winbase::STD_ERROR_HANDLE, hWritePipe) is not called prior,
|
|
||||||
// this will fail. GetStdHandle() is used to make certain "servo" has the stderr
|
|
||||||
// file descriptor associated.
|
|
||||||
let h_stderr = processenv::GetStdHandle(winbase::STD_ERROR_HANDLE);
|
|
||||||
if h_stderr == handleapi::INVALID_HANDLE_VALUE || h_stderr == shared::ntdef::NULL {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spawn a thread. The thread will redirect all STDOUT and STDERR messages
|
|
||||||
// to the provided handler function.
|
|
||||||
let _handler = thread::spawn(move || loop {
|
|
||||||
let mut read_buf: [i8; BUF_LENGTH] = [0; BUF_LENGTH];
|
|
||||||
|
|
||||||
let result = libc::read(
|
|
||||||
h_read_pipe_fd,
|
|
||||||
read_buf.as_mut_ptr() as *mut _,
|
|
||||||
read_buf.len() as u32 - 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
if result == -1 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
handler(read_buf.as_ptr(), result as u32);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call<T, F>(f: F) -> T
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut ServoGlue) -> Result<T, &'static str>,
|
|
||||||
{
|
|
||||||
match SERVO.with(|s| match s.borrow_mut().as_mut() {
|
|
||||||
Some(ref mut s) => (f)(s),
|
|
||||||
None => Err("Servo not available in this thread"),
|
|
||||||
}) {
|
|
||||||
Err(e) => panic!("{}", e),
|
|
||||||
Ok(r) => r,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Callback used by Servo internals
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct CHostCallbacks {
|
|
||||||
pub on_load_started: extern "C" fn(),
|
|
||||||
pub on_load_ended: extern "C" fn(),
|
|
||||||
pub on_title_changed: extern "C" fn(title: *const c_char),
|
|
||||||
pub on_allow_navigation: extern "C" fn(url: *const c_char) -> bool,
|
|
||||||
pub on_url_changed: extern "C" fn(url: *const c_char),
|
|
||||||
pub on_history_changed: extern "C" fn(can_go_back: bool, can_go_forward: bool),
|
|
||||||
pub on_animating_changed: extern "C" fn(animating: bool),
|
|
||||||
pub on_shutdown_complete: extern "C" fn(),
|
|
||||||
pub on_ime_show: extern "C" fn(
|
|
||||||
text: *const c_char,
|
|
||||||
text_index: i32,
|
|
||||||
multiline: bool,
|
|
||||||
x: i32,
|
|
||||||
y: i32,
|
|
||||||
width: i32,
|
|
||||||
height: i32,
|
|
||||||
),
|
|
||||||
pub on_ime_hide: extern "C" fn(),
|
|
||||||
pub get_clipboard_contents: extern "C" fn() -> *const c_char,
|
|
||||||
pub set_clipboard_contents: extern "C" fn(contents: *const c_char),
|
|
||||||
pub on_media_session_metadata:
|
|
||||||
extern "C" fn(title: *const c_char, album: *const c_char, artist: *const c_char),
|
|
||||||
pub on_media_session_playback_state_change: extern "C" fn(state: CMediaSessionPlaybackState),
|
|
||||||
pub on_media_session_set_position_state:
|
|
||||||
extern "C" fn(duration: f64, position: f64, playback_rate: f64),
|
|
||||||
pub prompt_alert: extern "C" fn(message: *const c_char, trusted: bool),
|
|
||||||
pub prompt_ok_cancel: extern "C" fn(message: *const c_char, trusted: bool) -> CPromptResult,
|
|
||||||
pub prompt_yes_no: extern "C" fn(message: *const c_char, trusted: bool) -> CPromptResult,
|
|
||||||
pub prompt_input:
|
|
||||||
extern "C" fn(message: *const c_char, def: *const c_char, trusted: bool) -> *const c_char,
|
|
||||||
pub on_devtools_started:
|
|
||||||
extern "C" fn(result: CDevtoolsServerState, port: c_uint, token: *const c_char),
|
|
||||||
pub show_context_menu:
|
|
||||||
extern "C" fn(title: *const c_char, items_list: *const *const c_char, items_size: u32),
|
|
||||||
pub on_log_output: extern "C" fn(buffer: *const c_char, buffer_length: u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Servo options
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct CInitOptions {
|
|
||||||
pub args: *const c_char,
|
|
||||||
pub width: i32,
|
|
||||||
pub height: i32,
|
|
||||||
pub density: f32,
|
|
||||||
pub vslogger_mod_list: *const *const c_char,
|
|
||||||
pub vslogger_mod_size: u32,
|
|
||||||
pub native_widget: *mut c_void,
|
|
||||||
pub prefs: *const prefs::CPrefList,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub enum CMouseButton {
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Middle,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CMouseButton {
|
|
||||||
pub fn convert(&self) -> MouseButton {
|
|
||||||
match self {
|
|
||||||
CMouseButton::Left => MouseButton::Left,
|
|
||||||
CMouseButton::Right => MouseButton::Right,
|
|
||||||
CMouseButton::Middle => MouseButton::Middle,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub enum CPromptResult {
|
|
||||||
Dismissed,
|
|
||||||
Primary,
|
|
||||||
Secondary,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CPromptResult {
|
|
||||||
pub fn convert(&self) -> PromptResult {
|
|
||||||
match self {
|
|
||||||
CPromptResult::Primary => PromptResult::Primary,
|
|
||||||
CPromptResult::Secondary => PromptResult::Secondary,
|
|
||||||
CPromptResult::Dismissed => PromptResult::Dismissed,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub enum CMediaSessionPlaybackState {
|
|
||||||
None = 1,
|
|
||||||
Playing,
|
|
||||||
Paused,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub enum CDevtoolsServerState {
|
|
||||||
Started,
|
|
||||||
Error,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<MediaSessionPlaybackState> for CMediaSessionPlaybackState {
|
|
||||||
fn from(state: MediaSessionPlaybackState) -> Self {
|
|
||||||
match state {
|
|
||||||
MediaSessionPlaybackState::None_ => CMediaSessionPlaybackState::None,
|
|
||||||
MediaSessionPlaybackState::Playing => CMediaSessionPlaybackState::Playing,
|
|
||||||
MediaSessionPlaybackState::Paused => CMediaSessionPlaybackState::Paused,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub enum CMediaSessionActionType {
|
|
||||||
Play = 1,
|
|
||||||
Pause,
|
|
||||||
SeekBackward,
|
|
||||||
SeekForward,
|
|
||||||
PreviousTrack,
|
|
||||||
NextTrack,
|
|
||||||
SkipAd,
|
|
||||||
Stop,
|
|
||||||
SeekTo,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CMediaSessionActionType {
|
|
||||||
pub fn convert(&self) -> MediaSessionActionType {
|
|
||||||
match self {
|
|
||||||
CMediaSessionActionType::Play => MediaSessionActionType::Play,
|
|
||||||
CMediaSessionActionType::Pause => MediaSessionActionType::Pause,
|
|
||||||
CMediaSessionActionType::SeekBackward => MediaSessionActionType::SeekBackward,
|
|
||||||
CMediaSessionActionType::SeekForward => MediaSessionActionType::SeekForward,
|
|
||||||
CMediaSessionActionType::PreviousTrack => MediaSessionActionType::PreviousTrack,
|
|
||||||
CMediaSessionActionType::NextTrack => MediaSessionActionType::NextTrack,
|
|
||||||
CMediaSessionActionType::SkipAd => MediaSessionActionType::SkipAd,
|
|
||||||
CMediaSessionActionType::Stop => MediaSessionActionType::Stop,
|
|
||||||
CMediaSessionActionType::SeekTo => MediaSessionActionType::SeekTo,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub enum CContextMenuResult {
|
|
||||||
Ignored,
|
|
||||||
Selected,
|
|
||||||
// Can't use Dismissed. Already used by PromptResult. See:
|
|
||||||
// https://github.com/servo/servo/issues/25986
|
|
||||||
Dismissed_,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CContextMenuResult {
|
|
||||||
pub fn convert(&self, idx: u32) -> ContextMenuResult {
|
|
||||||
match self {
|
|
||||||
CContextMenuResult::Ignored => ContextMenuResult::Ignored,
|
|
||||||
CContextMenuResult::Dismissed_ => ContextMenuResult::Dismissed,
|
|
||||||
CContextMenuResult::Selected => ContextMenuResult::Selected(idx as usize),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The returned string is not freed. This will leak.
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn servo_version() -> *const c_char {
|
|
||||||
SERVO_VERSION.as_ptr()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn init_logger(modules: &[*const c_char], level: LevelFilter) {
|
|
||||||
use std::sync::Once;
|
|
||||||
|
|
||||||
use vslogger::VSLogger;
|
|
||||||
|
|
||||||
use crate::vslogger::LOG_MODULE_FILTERS;
|
|
||||||
|
|
||||||
static LOGGER: VSLogger = VSLogger;
|
|
||||||
static LOGGER_INIT: Once = Once::new();
|
|
||||||
|
|
||||||
if !modules.is_empty() {
|
|
||||||
*LOG_MODULE_FILTERS.lock().unwrap() = modules
|
|
||||||
.iter()
|
|
||||||
.map(|modules| unsafe { CStr::from_ptr(*modules).to_string_lossy().into_owned() })
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER_INIT.call_once(|| {
|
|
||||||
log::set_logger(&LOGGER)
|
|
||||||
.map(|_| log::set_max_level(level))
|
|
||||||
.unwrap();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
fn init_logger(_modules: &[*const c_char], _level: LevelFilter) {
|
|
||||||
crate::env_logger::init();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn init(
|
|
||||||
opts: CInitOptions,
|
|
||||||
gl: gl_glue::ServoGl,
|
|
||||||
gl_context: Option<*const c_void>,
|
|
||||||
display: Option<*const c_void>,
|
|
||||||
wakeup: extern "C" fn(),
|
|
||||||
callbacks: CHostCallbacks,
|
|
||||||
) {
|
|
||||||
// Catch any panics.
|
|
||||||
std::panic::set_hook(Box::new(|info| {
|
|
||||||
let msg = match info.payload().downcast_ref::<&'static str>() {
|
|
||||||
Some(s) => *s,
|
|
||||||
None => match info.payload().downcast_ref::<String>() {
|
|
||||||
Some(s) => &**s,
|
|
||||||
None => "Box<Any>",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let current_thread = std::thread::current();
|
|
||||||
let name = current_thread.name().unwrap_or("<unnamed>");
|
|
||||||
let details = if let Some(location) = info.location() {
|
|
||||||
format!(
|
|
||||||
"{} (thread {}, at {}:{})",
|
|
||||||
msg,
|
|
||||||
name,
|
|
||||||
location.file(),
|
|
||||||
location.line()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
format!("{} (thread {})", msg, name)
|
|
||||||
};
|
|
||||||
report_panic("General panic handler", Some(details));
|
|
||||||
}));
|
|
||||||
|
|
||||||
let args = if !opts.args.is_null() {
|
|
||||||
let args = CStr::from_ptr(opts.args);
|
|
||||||
args.to_str()
|
|
||||||
.unwrap_or("")
|
|
||||||
.split(' ')
|
|
||||||
.map(|s| s.to_owned())
|
|
||||||
.collect()
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
};
|
|
||||||
|
|
||||||
let logger_level = if let Some(level_index) = args.iter().position(|s| s == "--vslogger-level")
|
|
||||||
{
|
|
||||||
if args.len() >= level_index + 1 {
|
|
||||||
LevelFilter::from_str(&args[level_index + 1]).unwrap_or(LevelFilter::Warn)
|
|
||||||
} else {
|
|
||||||
LevelFilter::Warn
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LevelFilter::Warn
|
|
||||||
};
|
|
||||||
|
|
||||||
let logger_modules = if opts.vslogger_mod_list.is_null() {
|
|
||||||
&[]
|
|
||||||
} else {
|
|
||||||
slice::from_raw_parts(opts.vslogger_mod_list, opts.vslogger_mod_size as usize)
|
|
||||||
};
|
|
||||||
|
|
||||||
*OUTPUT_LOG_HANDLER.lock().unwrap() = Some(callbacks.on_log_output);
|
|
||||||
init_logger(logger_modules, logger_level);
|
|
||||||
|
|
||||||
if let Err(reason) = redirect_stdout_stderr(callbacks.on_log_output) {
|
|
||||||
warn!("Error redirecting stdout/stderr: {}", reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
let coordinates = Coordinates::new(0, 0, opts.width, opts.height, opts.width, opts.height);
|
|
||||||
|
|
||||||
let prefs = if opts.prefs.is_null() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some((*opts.prefs).convert())
|
|
||||||
};
|
|
||||||
|
|
||||||
let opts = InitOptions {
|
|
||||||
args,
|
|
||||||
coordinates,
|
|
||||||
prefs,
|
|
||||||
density: opts.density,
|
|
||||||
xr_discovery: None,
|
|
||||||
gl_context_pointer: gl_context,
|
|
||||||
native_display_pointer: display,
|
|
||||||
surfman_integration: SurfmanIntegration::Widget(opts.native_widget),
|
|
||||||
};
|
|
||||||
|
|
||||||
let wakeup = Box::new(WakeupCallback::new(wakeup));
|
|
||||||
let callbacks = Box::new(HostCallbacks::new(callbacks));
|
|
||||||
|
|
||||||
simpleservo::init(opts, gl, wakeup, callbacks).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn init_with_egl(
|
|
||||||
opts: CInitOptions,
|
|
||||||
wakeup: extern "C" fn(),
|
|
||||||
callbacks: CHostCallbacks,
|
|
||||||
) {
|
|
||||||
let gl = gl_glue::egl::init().unwrap();
|
|
||||||
unsafe {
|
|
||||||
init(
|
|
||||||
opts,
|
|
||||||
gl.gl_wrapper,
|
|
||||||
Some(gl.gl_context),
|
|
||||||
Some(gl.display),
|
|
||||||
wakeup,
|
|
||||||
callbacks,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(
|
|
||||||
target_os = "linux",
|
|
||||||
all(target_os = "windows", not(feature = "no-wgl")),
|
|
||||||
target_os = "macos"
|
|
||||||
))]
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn init_with_gl(
|
|
||||||
opts: CInitOptions,
|
|
||||||
wakeup: extern "C" fn(),
|
|
||||||
callbacks: CHostCallbacks,
|
|
||||||
) {
|
|
||||||
let gl = gl_glue::gl::init().unwrap();
|
|
||||||
unsafe { init(opts, gl, None, None, wakeup, callbacks) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn deinit() {
|
|
||||||
debug!("deinit");
|
|
||||||
simpleservo::deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn request_shutdown() {
|
|
||||||
debug!("request_shutdown");
|
|
||||||
call(|s| s.request_shutdown());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn set_batch_mode(batch: bool) {
|
|
||||||
debug!("set_batch_mode");
|
|
||||||
call(|s| s.set_batch_mode(batch));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn on_context_menu_closed(result: CContextMenuResult, item: u32) {
|
|
||||||
debug!("on_context_menu_closed");
|
|
||||||
call(|s| s.on_context_menu_closed(result.convert(item)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn resize(width: i32, height: i32) {
|
|
||||||
debug!("resize {}/{}", width, height);
|
|
||||||
call(|s| {
|
|
||||||
let coordinates = Coordinates::new(0, 0, width, height, width, height);
|
|
||||||
s.resize(coordinates)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn perform_updates() {
|
|
||||||
debug!("perform_updates");
|
|
||||||
// We might have allocated some memory to respond to a potential
|
|
||||||
// request, from the embedder, for a copy of Servo's preferences.
|
|
||||||
prefs::free_prefs();
|
|
||||||
call(|s| s.perform_updates());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn is_uri_valid(url: *const c_char) -> bool {
|
|
||||||
debug!("is_uri_valid");
|
|
||||||
let url = unsafe { CStr::from_ptr(url) };
|
|
||||||
let url = url.to_str().expect("Can't read string");
|
|
||||||
simpleservo::is_uri_valid(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn load_uri(url: *const c_char) -> bool {
|
|
||||||
debug!("load_url");
|
|
||||||
let url = unsafe { CStr::from_ptr(url) };
|
|
||||||
let url = url.to_str().expect("Can't read string");
|
|
||||||
call(|s| Ok(s.load_uri(url).is_ok()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn clear_cache() {
|
|
||||||
debug!("clear_cache");
|
|
||||||
call(|s| s.clear_cache())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn reload() {
|
|
||||||
debug!("reload");
|
|
||||||
call(|s| s.reload());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn stop() {
|
|
||||||
debug!("stop");
|
|
||||||
call(|s| s.stop());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn refresh() {
|
|
||||||
debug!("refresh");
|
|
||||||
call(|s| s.refresh());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn go_back() {
|
|
||||||
debug!("go_back");
|
|
||||||
call(|s| s.go_back());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn go_forward() {
|
|
||||||
debug!("go_forward");
|
|
||||||
call(|s| s.go_forward());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn scroll_start(dx: i32, dy: i32, x: i32, y: i32) {
|
|
||||||
debug!("scroll_start");
|
|
||||||
call(|s| s.scroll_start(dx as f32, dy as f32, x, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn scroll_end(dx: i32, dy: i32, x: i32, y: i32) {
|
|
||||||
debug!("scroll_end");
|
|
||||||
call(|s| s.scroll_end(dx as f32, dy as f32, x, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn scroll(dx: i32, dy: i32, x: i32, y: i32) {
|
|
||||||
debug!("scroll");
|
|
||||||
call(|s| s.scroll(dx as f32, dy as f32, x, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn touch_down(x: f32, y: f32, pointer_id: i32) {
|
|
||||||
debug!("touch down");
|
|
||||||
call(|s| s.touch_down(x, y, pointer_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn touch_up(x: f32, y: f32, pointer_id: i32) {
|
|
||||||
debug!("touch up");
|
|
||||||
call(|s| s.touch_up(x, y, pointer_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn touch_move(x: f32, y: f32, pointer_id: i32) {
|
|
||||||
debug!("touch move");
|
|
||||||
call(|s| s.touch_move(x, y, pointer_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn touch_cancel(x: f32, y: f32, pointer_id: i32) {
|
|
||||||
debug!("touch cancel");
|
|
||||||
call(|s| s.touch_cancel(x, y, pointer_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn pinchzoom_start(factor: f32, x: i32, y: i32) {
|
|
||||||
debug!("pinchzoom_start");
|
|
||||||
call(|s| s.pinchzoom_start(factor, x as u32, y as u32));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn pinchzoom(factor: f32, x: i32, y: i32) {
|
|
||||||
debug!("pinchzoom");
|
|
||||||
call(|s| s.pinchzoom(factor, x as u32, y as u32));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn pinchzoom_end(factor: f32, x: i32, y: i32) {
|
|
||||||
debug!("pinchzoom_end");
|
|
||||||
call(|s| s.pinchzoom_end(factor, x as u32, y as u32));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn mouse_move(x: f32, y: f32) {
|
|
||||||
debug!("mouse_move");
|
|
||||||
call(|s| s.mouse_move(x, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn mouse_down(x: f32, y: f32, button: CMouseButton) {
|
|
||||||
debug!("mouse_down");
|
|
||||||
call(|s| s.mouse_down(x, y, button.convert()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn mouse_up(x: f32, y: f32, button: CMouseButton) {
|
|
||||||
debug!("mouse_up");
|
|
||||||
call(|s| s.mouse_up(x, y, button.convert()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn click(x: f32, y: f32) {
|
|
||||||
debug!("click");
|
|
||||||
call(|s| s.click(x, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn key_down(name: *const c_char) {
|
|
||||||
debug!("key_up");
|
|
||||||
key_event(name, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn key_up(name: *const c_char) {
|
|
||||||
debug!("key_up");
|
|
||||||
key_event(name, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn key_event(name: *const c_char, up: bool) {
|
|
||||||
let name = unsafe { CStr::from_ptr(name) };
|
|
||||||
let name = match name.to_str() {
|
|
||||||
Ok(name) => name,
|
|
||||||
Err(..) => {
|
|
||||||
warn!("Couldn't not read str");
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let key = Key::from_str(&name);
|
|
||||||
if let Ok(key) = key {
|
|
||||||
call(|s| if up { s.key_up(key) } else { s.key_down(key) });
|
|
||||||
} else {
|
|
||||||
warn!("Received unknown keys");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn media_session_action(action: CMediaSessionActionType) {
|
|
||||||
debug!("media_session_action");
|
|
||||||
call(|s| s.media_session_action(action.convert()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn change_visibility(visible: bool) {
|
|
||||||
debug!("change_visibility");
|
|
||||||
call(|s| s.change_visibility(visible));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn ime_dismissed() {
|
|
||||||
debug!("ime_dismissed");
|
|
||||||
call(|s| s.ime_dismissed());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WakeupCallback(extern "C" fn());
|
|
||||||
|
|
||||||
impl WakeupCallback {
|
|
||||||
fn new(callback: extern "C" fn()) -> WakeupCallback {
|
|
||||||
WakeupCallback(callback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EventLoopWaker for WakeupCallback {
|
|
||||||
fn clone_box(&self) -> Box<dyn EventLoopWaker> {
|
|
||||||
Box::new(WakeupCallback(self.0))
|
|
||||||
}
|
|
||||||
fn wake(&self) {
|
|
||||||
(self.0)();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct HostCallbacks(CHostCallbacks);
|
|
||||||
|
|
||||||
impl HostCallbacks {
|
|
||||||
fn new(callback: CHostCallbacks) -> HostCallbacks {
|
|
||||||
HostCallbacks(callback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HostTrait for HostCallbacks {
|
|
||||||
fn on_load_started(&self) {
|
|
||||||
debug!("on_load_started");
|
|
||||||
(self.0.on_load_started)();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_load_ended(&self) {
|
|
||||||
debug!("on_load_ended");
|
|
||||||
(self.0.on_load_ended)();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_title_changed(&self, title: Option<String>) {
|
|
||||||
debug!("on_title_changed");
|
|
||||||
match title {
|
|
||||||
None => (self.0.on_title_changed)(std::ptr::null()),
|
|
||||||
Some(title) => {
|
|
||||||
let title = CString::new(title).expect("Can't create string");
|
|
||||||
(self.0.on_title_changed)(title.as_ptr());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_allow_navigation(&self, url: String) -> bool {
|
|
||||||
debug!("on_allow_navigation");
|
|
||||||
let url = CString::new(url).expect("Can't create string");
|
|
||||||
(self.0.on_allow_navigation)(url.as_ptr())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_url_changed(&self, url: String) {
|
|
||||||
debug!("on_url_changed");
|
|
||||||
let url = CString::new(url).expect("Can't create string");
|
|
||||||
(self.0.on_url_changed)(url.as_ptr());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_history_changed(&self, can_go_back: bool, can_go_forward: bool) {
|
|
||||||
debug!("on_history_changed");
|
|
||||||
(self.0.on_history_changed)(can_go_back, can_go_forward);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_animating_changed(&self, animating: bool) {
|
|
||||||
debug!("on_animating_changed");
|
|
||||||
(self.0.on_animating_changed)(animating);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_shutdown_complete(&self) {
|
|
||||||
debug!("on_shutdown_complete");
|
|
||||||
(self.0.on_shutdown_complete)();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_ime_show(
|
|
||||||
&self,
|
|
||||||
_input_type: InputMethodType,
|
|
||||||
text: Option<(String, i32)>,
|
|
||||||
multiline: bool,
|
|
||||||
bounds: DeviceIntRect,
|
|
||||||
) {
|
|
||||||
debug!("on_ime_show");
|
|
||||||
let text_index = text.as_ref().map_or(0, |(_, i)| *i);
|
|
||||||
let text = text.and_then(|(s, _)| CString::new(s).ok());
|
|
||||||
let text_ptr = text
|
|
||||||
.as_ref()
|
|
||||||
.map(|cstr| cstr.as_ptr())
|
|
||||||
.unwrap_or(std::ptr::null());
|
|
||||||
(self.0.on_ime_show)(
|
|
||||||
text_ptr,
|
|
||||||
text_index,
|
|
||||||
multiline,
|
|
||||||
bounds.origin.x,
|
|
||||||
bounds.origin.y,
|
|
||||||
bounds.size.width,
|
|
||||||
bounds.size.height,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_ime_hide(&self) {
|
|
||||||
debug!("on_ime_hide");
|
|
||||||
(self.0.on_ime_hide)();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_clipboard_contents(&self) -> Option<String> {
|
|
||||||
debug!("get_clipboard_contents");
|
|
||||||
let raw_contents = (self.0.get_clipboard_contents)();
|
|
||||||
if raw_contents.is_null() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let c_str = unsafe { CStr::from_ptr(raw_contents) };
|
|
||||||
let contents_str = c_str.to_str().expect("Can't create str");
|
|
||||||
Some(contents_str.to_owned())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_clipboard_contents(&self, contents: String) {
|
|
||||||
debug!("set_clipboard_contents");
|
|
||||||
let contents = CString::new(contents).expect("Can't create string");
|
|
||||||
(self.0.set_clipboard_contents)(contents.as_ptr());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_media_session_metadata(&self, title: String, artist: String, album: String) {
|
|
||||||
debug!(
|
|
||||||
"on_media_session_metadata ({:?} {:?} {:?})",
|
|
||||||
title, artist, album
|
|
||||||
);
|
|
||||||
let title = CString::new(title).expect("Can't create string");
|
|
||||||
let artist = CString::new(artist).expect("Can't create string");
|
|
||||||
let album = CString::new(album).expect("Can't create string");
|
|
||||||
(self.0.on_media_session_metadata)(title.as_ptr(), artist.as_ptr(), album.as_ptr());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_media_session_playback_state_change(&self, state: MediaSessionPlaybackState) {
|
|
||||||
debug!("on_media_session_playback_state_change {:?}", state);
|
|
||||||
(self.0.on_media_session_playback_state_change)(state.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_media_session_set_position_state(
|
|
||||||
&self,
|
|
||||||
duration: f64,
|
|
||||||
position: f64,
|
|
||||||
playback_rate: f64,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"on_media_session_set_position_state ({:?} {:?} {:?})",
|
|
||||||
duration, position, playback_rate
|
|
||||||
);
|
|
||||||
(self.0.on_media_session_set_position_state)(duration, position, playback_rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prompt_alert(&self, message: String, trusted: bool) {
|
|
||||||
debug!("prompt_alert");
|
|
||||||
let message = CString::new(message).expect("Can't create string");
|
|
||||||
(self.0.prompt_alert)(message.as_ptr(), trusted);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prompt_ok_cancel(&self, message: String, trusted: bool) -> PromptResult {
|
|
||||||
debug!("prompt_ok_cancel");
|
|
||||||
let message = CString::new(message).expect("Can't create string");
|
|
||||||
(self.0.prompt_ok_cancel)(message.as_ptr(), trusted).convert()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prompt_yes_no(&self, message: String, trusted: bool) -> PromptResult {
|
|
||||||
debug!("prompt_yes_no");
|
|
||||||
let message = CString::new(message).expect("Can't create string");
|
|
||||||
(self.0.prompt_yes_no)(message.as_ptr(), trusted).convert()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prompt_input(&self, message: String, default: String, trusted: bool) -> Option<String> {
|
|
||||||
debug!("prompt_input");
|
|
||||||
let message = CString::new(message).expect("Can't create string");
|
|
||||||
let default = CString::new(default).expect("Can't create string");
|
|
||||||
let raw_contents = (self.0.prompt_input)(message.as_ptr(), default.as_ptr(), trusted);
|
|
||||||
if raw_contents.is_null() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let c_str = unsafe { CStr::from_ptr(raw_contents) };
|
|
||||||
let contents_str = c_str.to_str().expect("Can't create str");
|
|
||||||
Some(contents_str.to_owned())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_panic(&self, reason: String, details: Option<String>) {
|
|
||||||
report_panic(&reason, details);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_devtools_started(&self, port: Result<u16, ()>, token: String) {
|
|
||||||
let token = CString::new(token).expect("Can't create string");
|
|
||||||
match port {
|
|
||||||
Ok(p) => {
|
|
||||||
info!("Devtools Server running on port {}", p);
|
|
||||||
(self.0.on_devtools_started)(
|
|
||||||
CDevtoolsServerState::Started,
|
|
||||||
p.into(),
|
|
||||||
token.as_ptr(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
Err(()) => {
|
|
||||||
error!("Error running devtools server");
|
|
||||||
(self.0.on_devtools_started)(CDevtoolsServerState::Error, 0, token.as_ptr());
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show_context_menu(&self, title: Option<String>, items: Vec<String>) {
|
|
||||||
debug!("show_context_menu");
|
|
||||||
let items_size = items.len() as u32;
|
|
||||||
let cstrs: Vec<CString> = items
|
|
||||||
.into_iter()
|
|
||||||
.map(|i| CString::new(i).expect("Can't create string"))
|
|
||||||
.collect();
|
|
||||||
let items: Vec<*const c_char> = cstrs.iter().map(|cstr| cstr.as_ptr()).collect();
|
|
||||||
let title = title.map(|s| CString::new(s).expect("Can't create string"));
|
|
||||||
let title_ptr = title
|
|
||||||
.as_ref()
|
|
||||||
.map(|cstr| cstr.as_ptr())
|
|
||||||
.unwrap_or(std::ptr::null());
|
|
||||||
(self.0.show_context_menu)(title_ptr, items.as_ptr(), items_size);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,233 +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/. */
|
|
||||||
|
|
||||||
//! Servo's internal preferences are not C-compatible. To expose the preference to the embedder,
|
|
||||||
//! we keep a C-compatible copy of the preferences alive (LOCALCPREFS). The embedder can
|
|
||||||
//! retrieve an array (CPREFS) of struct of pointers (CPrefs) to the C-compatible preferences
|
|
||||||
//! (LocalCPref).
|
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::{BTreeMap, HashMap};
|
|
||||||
use std::ffi::{CStr, CString};
|
|
||||||
use std::os::raw::{c_char, c_void};
|
|
||||||
|
|
||||||
use log::debug;
|
|
||||||
|
|
||||||
use crate::simpleservo::{self, PrefValue};
|
|
||||||
|
|
||||||
thread_local! {
|
|
||||||
// CPREFS keeps alive a set of CPref that are sent over to the embedder.
|
|
||||||
// The CPREFS are structs holding pointers to values held alive by LOCALCPREFS.
|
|
||||||
// This is emptied in free_prefs the next time perform_updates is called.
|
|
||||||
static CPREFS: RefCell<Vec<CPref>> = RefCell::new(Vec::new());
|
|
||||||
static LOCALCPREFS: RefCell<BTreeMap<String, Box<LocalCPref>>> = RefCell::new(BTreeMap::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LocalCPref {
|
|
||||||
key: CString,
|
|
||||||
value: LocalCPrefValue,
|
|
||||||
is_default: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum LocalCPrefValue {
|
|
||||||
Float(f64),
|
|
||||||
Int(i64),
|
|
||||||
Str(CString),
|
|
||||||
Bool(bool),
|
|
||||||
Missing,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LocalCPrefValue {
|
|
||||||
pub fn new(v: &PrefValue) -> LocalCPrefValue {
|
|
||||||
match v {
|
|
||||||
PrefValue::Float(v) => LocalCPrefValue::Float(*v),
|
|
||||||
PrefValue::Int(v) => LocalCPrefValue::Int(*v),
|
|
||||||
PrefValue::Str(v) => LocalCPrefValue::Str(CString::new(v.as_bytes()).unwrap()),
|
|
||||||
PrefValue::Bool(v) => LocalCPrefValue::Bool(*v),
|
|
||||||
PrefValue::Missing => LocalCPrefValue::Missing,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct CPrefList {
|
|
||||||
pub len: usize,
|
|
||||||
pub list: *const CPref,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CPrefList {
|
|
||||||
pub fn convert(&self) -> HashMap<String, PrefValue> {
|
|
||||||
let slice = unsafe { std::slice::from_raw_parts(self.list, self.len) };
|
|
||||||
slice.iter().map(|cpref| cpref.convert()).collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct CPref {
|
|
||||||
pub pref_type: CPrefType,
|
|
||||||
pub key: *const c_char,
|
|
||||||
pub value: *const c_void,
|
|
||||||
pub is_default: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CPref {
|
|
||||||
fn new(local: &Box<LocalCPref>) -> CPref {
|
|
||||||
let (pref_type, value) = match &local.value {
|
|
||||||
LocalCPrefValue::Float(v) => (CPrefType::Float, v as *const f64 as *const c_void),
|
|
||||||
LocalCPrefValue::Int(v) => (CPrefType::Int, v as *const i64 as *const c_void),
|
|
||||||
LocalCPrefValue::Bool(v) => (CPrefType::Bool, v as *const bool as *const c_void),
|
|
||||||
LocalCPrefValue::Str(v) => (CPrefType::Str, v.as_ptr() as *const c_void),
|
|
||||||
LocalCPrefValue::Missing => (CPrefType::Missing, std::ptr::null()),
|
|
||||||
};
|
|
||||||
CPref {
|
|
||||||
key: local.key.as_ptr(),
|
|
||||||
is_default: local.is_default,
|
|
||||||
pref_type,
|
|
||||||
value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn convert(&self) -> (String, PrefValue) {
|
|
||||||
let key = unsafe { CStr::from_ptr(self.key) };
|
|
||||||
let key = key.to_str().expect("Can't read string").to_string();
|
|
||||||
let value = unsafe {
|
|
||||||
match self.pref_type {
|
|
||||||
CPrefType::Float => PrefValue::Float(*(self.value as *const f64)),
|
|
||||||
CPrefType::Int => PrefValue::Int(*(self.value as *const i64)),
|
|
||||||
CPrefType::Bool => PrefValue::Bool(*(self.value as *const bool)),
|
|
||||||
CPrefType::Str => PrefValue::Str({
|
|
||||||
let value = CStr::from_ptr(self.value as *const c_char);
|
|
||||||
value.to_str().expect("Can't read string").to_string()
|
|
||||||
}),
|
|
||||||
CPrefType::Missing => PrefValue::Missing,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub enum CPrefType {
|
|
||||||
Float,
|
|
||||||
Int,
|
|
||||||
Str,
|
|
||||||
Bool,
|
|
||||||
Missing,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn get_pref_as_float(ptr: *const c_void) -> *const f64 {
|
|
||||||
ptr as *const f64
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn get_pref_as_int(ptr: *const c_void) -> *const i64 {
|
|
||||||
ptr as *const i64
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn get_pref_as_str(ptr: *const c_void) -> *const c_char {
|
|
||||||
ptr as *const c_char
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn get_pref_as_bool(ptr: *const c_void) -> *const bool {
|
|
||||||
ptr as *const bool
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn reset_all_prefs() {
|
|
||||||
debug!("reset_all_prefs");
|
|
||||||
simpleservo::reset_all_prefs()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn reset_pref(key: *const c_char) -> bool {
|
|
||||||
debug!("reset_pref");
|
|
||||||
let key = unsafe { CStr::from_ptr(key) };
|
|
||||||
let key = key.to_str().expect("Can't read string");
|
|
||||||
simpleservo::reset_pref(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn get_pref(key: *const c_char) -> CPref {
|
|
||||||
debug!("get_pref");
|
|
||||||
LOCALCPREFS.with(|localmap| {
|
|
||||||
let key = unsafe { CStr::from_ptr(key) };
|
|
||||||
let key = key.to_str().expect("Can't read string");
|
|
||||||
let (value, is_default) = simpleservo::get_pref(key);
|
|
||||||
let local = Box::new(LocalCPref {
|
|
||||||
key: CString::new(key).unwrap(),
|
|
||||||
value: LocalCPrefValue::new(&value),
|
|
||||||
is_default: is_default,
|
|
||||||
});
|
|
||||||
let cpref = CPref::new(&local);
|
|
||||||
localmap.borrow_mut().insert(key.to_string(), local);
|
|
||||||
cpref
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_pref(key: *const c_char, value: PrefValue) -> bool {
|
|
||||||
debug!("set_pref");
|
|
||||||
let key = unsafe { CStr::from_ptr(key) };
|
|
||||||
let key = key.to_str().expect("Can't read string");
|
|
||||||
simpleservo::set_pref(key, value).is_ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn set_float_pref(key: *const c_char, value: f64) -> bool {
|
|
||||||
set_pref(key, PrefValue::Float(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn set_int_pref(key: *const c_char, value: i64) -> bool {
|
|
||||||
set_pref(key, PrefValue::Int(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn set_bool_pref(key: *const c_char, value: bool) -> bool {
|
|
||||||
set_pref(key, PrefValue::Bool(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn set_str_pref(key: *const c_char, value: *const c_char) -> bool {
|
|
||||||
let value = unsafe { CStr::from_ptr(value) };
|
|
||||||
let value = value.to_str().expect("Can't read string").to_string();
|
|
||||||
set_pref(key, PrefValue::Str(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn get_prefs() -> CPrefList {
|
|
||||||
// Called from any thread
|
|
||||||
debug!("get_prefs");
|
|
||||||
let map = simpleservo::get_prefs();
|
|
||||||
let local: BTreeMap<String, Box<LocalCPref>> = map
|
|
||||||
.into_iter()
|
|
||||||
.map(|(key, (value, is_default))| {
|
|
||||||
let l = Box::new(LocalCPref {
|
|
||||||
key: CString::new(key.as_bytes()).unwrap(),
|
|
||||||
value: LocalCPrefValue::new(&value),
|
|
||||||
is_default: is_default,
|
|
||||||
});
|
|
||||||
(key, l)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let ptrs: Vec<CPref> = local.iter().map(|(_, local)| CPref::new(&local)).collect();
|
|
||||||
|
|
||||||
let list = CPrefList {
|
|
||||||
len: ptrs.len(),
|
|
||||||
list: ptrs.as_ptr(),
|
|
||||||
};
|
|
||||||
|
|
||||||
LOCALCPREFS.with(|p| *p.borrow_mut() = local);
|
|
||||||
CPREFS.with(|p| *p.borrow_mut() = ptrs);
|
|
||||||
|
|
||||||
list
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn free_prefs() {
|
|
||||||
LOCALCPREFS.with(|p| p.borrow_mut().clear());
|
|
||||||
CPREFS.with(|p| p.borrow_mut().clear());
|
|
||||||
}
|
|
|
@ -1,42 +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::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
use log::{self, Metadata, Record};
|
|
||||||
|
|
||||||
use crate::OUTPUT_LOG_HANDLER;
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
pub static ref LOG_MODULE_FILTERS: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VSLogger;
|
|
||||||
|
|
||||||
impl log::Log for VSLogger {
|
|
||||||
fn enabled(&self, metadata: &Metadata) -> bool {
|
|
||||||
let modules = LOG_MODULE_FILTERS.lock().unwrap();
|
|
||||||
modules.is_empty() ||
|
|
||||||
modules.iter().any(|module| {
|
|
||||||
metadata.target() == module ||
|
|
||||||
metadata.target().starts_with(&format!("{}::", module))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn log(&self, record: &Record) {
|
|
||||||
if self.enabled(record.metadata()) {
|
|
||||||
let log = format!(
|
|
||||||
"RUST: {} - {} - {}\r\n\0",
|
|
||||||
record.level(),
|
|
||||||
record.target(),
|
|
||||||
record.args()
|
|
||||||
);
|
|
||||||
if let Some(handler) = OUTPUT_LOG_HANDLER.lock().unwrap().as_ref() {
|
|
||||||
(handler)(log.as_ptr() as _, log.len() as u32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&self) {}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "simpleservo_jniapi"
|
|
||||||
version = "0.0.1"
|
|
||||||
authors = ["The Servo Project Developers"]
|
|
||||||
license = "MPL-2.0"
|
|
||||||
edition = "2018"
|
|
||||||
publish = false
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
name = "simpleservo"
|
|
||||||
crate-type = ["cdylib"]
|
|
||||||
test = false
|
|
||||||
bench = false
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
android_logger = "0.13"
|
|
||||||
jni = "0.18.0"
|
|
||||||
libc = { workspace = true }
|
|
||||||
log = { workspace = true }
|
|
||||||
serde_json = { workspace = true }
|
|
||||||
# TODO: Once the native-bluetooth feature works for
|
|
||||||
# Android, remove the explicit feature list here.
|
|
||||||
simpleservo = { path = "../api", default-features = false, features = ["max_log_level", "webdriver"] }
|
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
cc = "1.0"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
debugmozjs = ["simpleservo/debugmozjs"]
|
|
||||||
default = ["max_log_level", "webdriver", "no_static_freetype"]
|
|
||||||
googlevr = ["simpleservo/googlevr"]
|
|
||||||
js_backtrace = ["simpleservo/js_backtrace"]
|
|
||||||
max_log_level = ["simpleservo/max_log_level"]
|
|
||||||
media-gstreamer = ["simpleservo/media-gstreamer"]
|
|
||||||
native-bluetooth = ["simpleservo/native-bluetooth"]
|
|
||||||
webdriver = ["simpleservo/webdriver"]
|
|
||||||
webgl_backtrace = ["simpleservo/webgl_backtrace"]
|
|
||||||
no_static_freetype = ["simpleservo/no_static_freetype"]
|
|
|
@ -57,7 +57,7 @@ class MachCommands(CommandBase):
|
||||||
help="Command-line arguments to be passed through to Cargo")
|
help="Command-line arguments to be passed through to Cargo")
|
||||||
@CommandBase.common_command_arguments(build_configuration=True, build_type=True)
|
@CommandBase.common_command_arguments(build_configuration=True, build_type=True)
|
||||||
def build(self, build_type: BuildType, jobs=None, params=None, no_package=False,
|
def build(self, build_type: BuildType, jobs=None, params=None, no_package=False,
|
||||||
verbose=False, very_verbose=False, libsimpleservo=False, **kwargs):
|
verbose=False, very_verbose=False, **kwargs):
|
||||||
opts = params or []
|
opts = params or []
|
||||||
|
|
||||||
if build_type.is_release():
|
if build_type.is_release():
|
||||||
|
@ -99,19 +99,15 @@ class MachCommands(CommandBase):
|
||||||
print((key, env[key]))
|
print((key, env[key]))
|
||||||
|
|
||||||
status = self.run_cargo_build_like_command(
|
status = self.run_cargo_build_like_command(
|
||||||
"build", opts, env=env, verbose=verbose,
|
"build", opts, env=env, verbose=verbose, **kwargs)
|
||||||
libsimpleservo=libsimpleservo, **kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
# Do some additional things if the build succeeded
|
|
||||||
built_binary = self.get_binary_path(
|
|
||||||
build_type,
|
|
||||||
target=self.cross_compile_target,
|
|
||||||
android=self.is_android_build,
|
|
||||||
simpleservo=libsimpleservo
|
|
||||||
)
|
|
||||||
|
|
||||||
if status == 0:
|
if status == 0:
|
||||||
|
built_binary = self.get_binary_path(
|
||||||
|
build_type,
|
||||||
|
target=self.cross_compile_target,
|
||||||
|
android=self.is_android_build,
|
||||||
|
)
|
||||||
|
|
||||||
if self.is_android_build and not no_package:
|
if self.is_android_build and not no_package:
|
||||||
flavor = None
|
flavor = None
|
||||||
if "googlevr" in self.features:
|
if "googlevr" in self.features:
|
||||||
|
@ -128,14 +124,12 @@ class MachCommands(CommandBase):
|
||||||
status = 1
|
status = 1
|
||||||
|
|
||||||
elif sys.platform == "darwin":
|
elif sys.platform == "darwin":
|
||||||
servo_path = self.get_binary_path(
|
servo_bin_dir = os.path.dirname(built_binary)
|
||||||
build_type, target=self.cross_compile_target, simpleservo=libsimpleservo)
|
|
||||||
servo_bin_dir = os.path.dirname(servo_path)
|
|
||||||
assert os.path.exists(servo_bin_dir)
|
assert os.path.exists(servo_bin_dir)
|
||||||
|
|
||||||
if self.enable_media:
|
if self.enable_media:
|
||||||
print("Packaging gstreamer dylibs")
|
print("Packaging gstreamer dylibs")
|
||||||
if not package_gstreamer_dylibs(self.cross_compile_target, servo_path):
|
if not package_gstreamer_dylibs(self.cross_compile_target, built_binary):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# On the Mac, set a lovely icon. This makes it easier to pick out the Servo binary in tools
|
# On the Mac, set a lovely icon. This makes it easier to pick out the Servo binary in tools
|
||||||
|
@ -146,7 +140,7 @@ class MachCommands(CommandBase):
|
||||||
icon = Cocoa.NSImage.alloc().initWithContentsOfFile_(icon_path)
|
icon = Cocoa.NSImage.alloc().initWithContentsOfFile_(icon_path)
|
||||||
if icon is not None:
|
if icon is not None:
|
||||||
Cocoa.NSWorkspace.sharedWorkspace().setIcon_forFile_options_(icon,
|
Cocoa.NSWorkspace.sharedWorkspace().setIcon_forFile_options_(icon,
|
||||||
servo_path,
|
built_binary,
|
||||||
0)
|
0)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -331,23 +331,15 @@ class CommandBase(object):
|
||||||
apk_name = "servoapp.apk"
|
apk_name = "servoapp.apk"
|
||||||
return path.join(base_path, build_type.directory_name(), apk_name)
|
return path.join(base_path, build_type.directory_name(), apk_name)
|
||||||
|
|
||||||
def get_binary_path(self, build_type: BuildType, target=None, android=False, simpleservo=False):
|
def get_binary_path(self, build_type: BuildType, target=None, android=False):
|
||||||
base_path = util.get_target_dir()
|
base_path = util.get_target_dir()
|
||||||
if android:
|
if android:
|
||||||
base_path = path.join(base_path, self.config["android"]["target"])
|
base_path = path.join(base_path, self.config["android"]["target"])
|
||||||
simpleservo = True
|
return path.join(base_path, build_type.directory_name(), "libsimpleservo.so")
|
||||||
elif target:
|
elif target:
|
||||||
base_path = path.join(base_path, target)
|
base_path = path.join(base_path, target)
|
||||||
|
|
||||||
binary_name = f"servo{servo.platform.get().executable_suffix()}"
|
binary_name = f"servo{servo.platform.get().executable_suffix()}"
|
||||||
if simpleservo:
|
|
||||||
if sys.platform == "win32":
|
|
||||||
binary_name = "simpleservo.dll"
|
|
||||||
elif sys.platform == "darwin":
|
|
||||||
binary_name = "libsimpleservo.dylib"
|
|
||||||
else:
|
|
||||||
binary_name = "libsimpleservo.so"
|
|
||||||
|
|
||||||
binary_path = path.join(base_path, build_type.directory_name(), binary_name)
|
binary_path = path.join(base_path, build_type.directory_name(), binary_name)
|
||||||
|
|
||||||
if not path.exists(binary_path):
|
if not path.exists(binary_path):
|
||||||
|
@ -688,13 +680,6 @@ class CommandBase(object):
|
||||||
'--media-stack', default=None, group="Feature Selection",
|
'--media-stack', default=None, group="Feature Selection",
|
||||||
choices=["gstreamer", "dummy"], help='Which media stack to use',
|
choices=["gstreamer", "dummy"], help='Which media stack to use',
|
||||||
),
|
),
|
||||||
CommandArgument(
|
|
||||||
'--libsimpleservo',
|
|
||||||
default=None,
|
|
||||||
group="Feature Selection",
|
|
||||||
action='store_true',
|
|
||||||
help='Build the libsimpleservo library instead of the servo executable',
|
|
||||||
),
|
|
||||||
CommandArgument(
|
CommandArgument(
|
||||||
'--debug-mozjs',
|
'--debug-mozjs',
|
||||||
default=False,
|
default=False,
|
||||||
|
@ -828,7 +813,6 @@ class CommandBase(object):
|
||||||
def run_cargo_build_like_command(
|
def run_cargo_build_like_command(
|
||||||
self, command: str, cargo_args: List[str],
|
self, command: str, cargo_args: List[str],
|
||||||
env=None, verbose=False,
|
env=None, verbose=False,
|
||||||
libsimpleservo=False,
|
|
||||||
debug_mozjs=False, with_debug_assertions=False,
|
debug_mozjs=False, with_debug_assertions=False,
|
||||||
with_frame_pointer=False, without_wgl=False,
|
with_frame_pointer=False, without_wgl=False,
|
||||||
**_kwargs
|
**_kwargs
|
||||||
|
@ -848,12 +832,8 @@ class CommandBase(object):
|
||||||
|
|
||||||
args = []
|
args = []
|
||||||
if "--manifest-path" not in cargo_args:
|
if "--manifest-path" not in cargo_args:
|
||||||
if libsimpleservo or self.is_android_build:
|
if self.is_android_build:
|
||||||
if self.is_android_build:
|
port = "jniapi"
|
||||||
api = "jniapi"
|
|
||||||
else:
|
|
||||||
api = "capi"
|
|
||||||
port = path.join("libsimpleservo", api)
|
|
||||||
else:
|
else:
|
||||||
port = "servoshell"
|
port = "servoshell"
|
||||||
args += [
|
args += [
|
||||||
|
|
|
@ -37,10 +37,6 @@ packages = [
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"toml",
|
"toml",
|
||||||
|
|
||||||
# This dependency is for "hermit os" which Servo doesn't support.
|
|
||||||
# Theoretically, it's never fetched.
|
|
||||||
"hermit-abi",
|
|
||||||
|
|
||||||
# Duplicated by winit.
|
# Duplicated by winit.
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
"windows-targets",
|
"windows-targets",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue