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"
|
||||
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]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
|
@ -679,25 +668,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
|
@ -779,30 +749,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "clipboard-win"
|
||||
version = "4.5.0"
|
||||
|
@ -2664,15 +2610,6 @@ version = "0.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.2"
|
||||
|
@ -2948,7 +2885,7 @@ version = "0.4.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
|
||||
dependencies = [
|
||||
"hermit-abi 0.3.2",
|
||||
"hermit-abi",
|
||||
"rustix",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
@ -4041,7 +3978,7 @@ version = "1.16.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi 0.3.2",
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
|
@ -4179,12 +4116,6 @@ version = "0.3.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
|
||||
|
||||
[[package]]
|
||||
name = "owned_ttf_parser"
|
||||
version = "0.20.0"
|
||||
|
@ -5562,13 +5493,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "simpleservo"
|
||||
name = "simpleservo_jniapi"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"core-foundation",
|
||||
"android_logger",
|
||||
"cc",
|
||||
"getopts",
|
||||
"gl_generator",
|
||||
"ipc-channel",
|
||||
"jni",
|
||||
"libc",
|
||||
"libloading 0.8.0",
|
||||
"libservo",
|
||||
|
@ -5578,36 +5511,6 @@ dependencies = [
|
|||
"surfman",
|
||||
"vergen",
|
||||
"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]]
|
||||
|
@ -5779,12 +5682,6 @@ dependencies = [
|
|||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "style"
|
||||
version = "0.0.1"
|
||||
|
@ -6083,12 +5980,6 @@ dependencies = [
|
|||
"term",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
|
||||
|
||||
[[package]]
|
||||
name = "thin-vec"
|
||||
version = "0.2.13"
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
resolver = "2"
|
||||
members = [
|
||||
"ports/servoshell",
|
||||
"ports/libsimpleservo/capi/",
|
||||
"ports/libsimpleservo/jniapi/",
|
||||
"ports/jniapi/",
|
||||
"tests/unit/*",
|
||||
"support/crown",
|
||||
]
|
||||
|
|
|
@ -1,40 +1,43 @@
|
|||
[package]
|
||||
name = "simpleservo"
|
||||
name = "simpleservo_jniapi"
|
||||
version = "0.0.1"
|
||||
authors = ["The Servo Project Developers"]
|
||||
license = "MPL-2.0"
|
||||
edition = "2018"
|
||||
publish = false
|
||||
build = "build.rs"
|
||||
|
||||
[lib]
|
||||
name = "simpleservo"
|
||||
crate-type = ["cdylib"]
|
||||
test = false
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
android_logger = "0.13"
|
||||
getopts = { 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 }
|
||||
serde_json = { workspace = true }
|
||||
servo-media = { git = "https://github.com/servo/media" }
|
||||
surfman = { workspace = true, features = ["sm-angle-default"] }
|
||||
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]
|
||||
cc = "1.0"
|
||||
gl_generator = "0.14"
|
||||
serde_json = { workspace = true }
|
||||
vergen = { version = "8.0.0", features = ["git", "gitcl"] }
|
||||
|
||||
[features]
|
||||
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"]
|
||||
jitspew = ["libservo/jitspew"]
|
||||
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)]
|
||||
|
||||
mod gl_glue;
|
||||
mod simpleservo;
|
||||
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
@ -15,8 +18,8 @@ use jni::{JNIEnv, JavaVM};
|
|||
use libc::{dup2, pipe, read};
|
||||
use log::{debug, error, info, warn};
|
||||
use simpleservo::{
|
||||
self, gl_glue, Coordinates, DeviceIntRect, EventLoopWaker, HostTrait, InitOptions,
|
||||
InputMethodType, MediaSessionPlaybackState, PromptResult, ServoGlue, SERVO,
|
||||
Coordinates, DeviceIntRect, EventLoopWaker, HostTrait, InitOptions, InputMethodType,
|
||||
MediaSessionPlaybackState, PromptResult, ServoGlue, SERVO,
|
||||
};
|
||||
|
||||
struct HostCallbacks {
|
|
@ -2,8 +2,6 @@
|
|||
* 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/. */
|
||||
|
||||
pub mod gl_glue;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::mem;
|
||||
|
@ -941,28 +939,28 @@ impl ResourceReaderMethods for ResourceReaderInstance {
|
|||
Vec::from(match res {
|
||||
Resource::Preferences => &include_bytes!(concat!(env!("OUT_DIR"), "/prefs.json"))[..],
|
||||
Resource::HstsPreloadList => {
|
||||
&include_bytes!("../../../../resources/hsts_preload.json")[..]
|
||||
&include_bytes!("../../../resources/hsts_preload.json")[..]
|
||||
},
|
||||
Resource::BadCertHTML => &include_bytes!("../../../../resources/badcert.html")[..],
|
||||
Resource::NetErrorHTML => &include_bytes!("../../../../resources/neterror.html")[..],
|
||||
Resource::UserAgentCSS => &include_bytes!("../../../../resources/user-agent.css")[..],
|
||||
Resource::ServoCSS => &include_bytes!("../../../../resources/servo.css")[..],
|
||||
Resource::BadCertHTML => &include_bytes!("../../../resources/badcert.html")[..],
|
||||
Resource::NetErrorHTML => &include_bytes!("../../../resources/neterror.html")[..],
|
||||
Resource::UserAgentCSS => &include_bytes!("../../../resources/user-agent.css")[..],
|
||||
Resource::ServoCSS => &include_bytes!("../../../resources/servo.css")[..],
|
||||
Resource::PresentationalHintsCSS => {
|
||||
&include_bytes!("../../../../resources/presentational-hints.css")[..]
|
||||
&include_bytes!("../../../resources/presentational-hints.css")[..]
|
||||
},
|
||||
Resource::QuirksModeCSS => &include_bytes!("../../../../resources/quirks-mode.css")[..],
|
||||
Resource::RippyPNG => &include_bytes!("../../../../resources/rippy.png")[..],
|
||||
Resource::DomainList => &include_bytes!("../../../../resources/public_domains.txt")[..],
|
||||
Resource::QuirksModeCSS => &include_bytes!("../../../resources/quirks-mode.css")[..],
|
||||
Resource::RippyPNG => &include_bytes!("../../../resources/rippy.png")[..],
|
||||
Resource::DomainList => &include_bytes!("../../../resources/public_domains.txt")[..],
|
||||
Resource::BluetoothBlocklist => {
|
||||
&include_bytes!("../../../../resources/gatt_blocklist.txt")[..]
|
||||
&include_bytes!("../../../resources/gatt_blocklist.txt")[..]
|
||||
},
|
||||
Resource::MediaControlsCSS => {
|
||||
&include_bytes!("../../../../resources/media-controls.css")[..]
|
||||
&include_bytes!("../../../resources/media-controls.css")[..]
|
||||
},
|
||||
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")
|
||||
@CommandBase.common_command_arguments(build_configuration=True, build_type=True)
|
||||
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 []
|
||||
|
||||
if build_type.is_release():
|
||||
|
@ -99,19 +99,15 @@ class MachCommands(CommandBase):
|
|||
print((key, env[key]))
|
||||
|
||||
status = self.run_cargo_build_like_command(
|
||||
"build", opts, env=env, verbose=verbose,
|
||||
libsimpleservo=libsimpleservo, **kwargs
|
||||
)
|
||||
"build", opts, env=env, verbose=verbose, **kwargs)
|
||||
|
||||
# Do some additional things if the build succeeded
|
||||
if status == 0:
|
||||
built_binary = self.get_binary_path(
|
||||
build_type,
|
||||
target=self.cross_compile_target,
|
||||
android=self.is_android_build,
|
||||
simpleservo=libsimpleservo
|
||||
)
|
||||
|
||||
if status == 0:
|
||||
if self.is_android_build and not no_package:
|
||||
flavor = None
|
||||
if "googlevr" in self.features:
|
||||
|
@ -128,14 +124,12 @@ class MachCommands(CommandBase):
|
|||
status = 1
|
||||
|
||||
elif sys.platform == "darwin":
|
||||
servo_path = self.get_binary_path(
|
||||
build_type, target=self.cross_compile_target, simpleservo=libsimpleservo)
|
||||
servo_bin_dir = os.path.dirname(servo_path)
|
||||
servo_bin_dir = os.path.dirname(built_binary)
|
||||
assert os.path.exists(servo_bin_dir)
|
||||
|
||||
if self.enable_media:
|
||||
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
|
||||
|
||||
# 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)
|
||||
if icon is not None:
|
||||
Cocoa.NSWorkspace.sharedWorkspace().setIcon_forFile_options_(icon,
|
||||
servo_path,
|
||||
built_binary,
|
||||
0)
|
||||
except ImportError:
|
||||
pass
|
||||
|
|
|
@ -331,23 +331,15 @@ class CommandBase(object):
|
|||
apk_name = "servoapp.apk"
|
||||
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()
|
||||
if android:
|
||||
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:
|
||||
base_path = path.join(base_path, target)
|
||||
|
||||
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)
|
||||
|
||||
if not path.exists(binary_path):
|
||||
|
@ -688,13 +680,6 @@ class CommandBase(object):
|
|||
'--media-stack', default=None, group="Feature Selection",
|
||||
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(
|
||||
'--debug-mozjs',
|
||||
default=False,
|
||||
|
@ -828,7 +813,6 @@ class CommandBase(object):
|
|||
def run_cargo_build_like_command(
|
||||
self, command: str, cargo_args: List[str],
|
||||
env=None, verbose=False,
|
||||
libsimpleservo=False,
|
||||
debug_mozjs=False, with_debug_assertions=False,
|
||||
with_frame_pointer=False, without_wgl=False,
|
||||
**_kwargs
|
||||
|
@ -848,12 +832,8 @@ class CommandBase(object):
|
|||
|
||||
args = []
|
||||
if "--manifest-path" not in cargo_args:
|
||||
if libsimpleservo or self.is_android_build:
|
||||
if self.is_android_build:
|
||||
api = "jniapi"
|
||||
else:
|
||||
api = "capi"
|
||||
port = path.join("libsimpleservo", api)
|
||||
port = "jniapi"
|
||||
else:
|
||||
port = "servoshell"
|
||||
args += [
|
||||
|
|
|
@ -37,10 +37,6 @@ packages = [
|
|||
"proc-macro-crate",
|
||||
"toml",
|
||||
|
||||
# This dependency is for "hermit os" which Servo doesn't support.
|
||||
# Theoretically, it's never fetched.
|
||||
"hermit-abi",
|
||||
|
||||
# Duplicated by winit.
|
||||
"windows-sys",
|
||||
"windows-targets",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue