ports/cef: Use the CEF translator tool to generate the full set of CEF

bindings.

This replaces hand-implemented CEF bindings with proper Rust wrappers
automatically generated from the C++ headers. This means that, whenever
CEF's C++ headers change, we can easily generate both the appropriate C
API and the appropriate Rust API. It eliminates much of the hand-written
unsafe code within the CEF port, because the CEF translator tool now
knows how to generate Rust smart pointer wrappers for each class that
corrently perform reference counting.

Additionally, this commit adds utility macros (located in `macros.rs`)
that make it easier to correctly expose Rust objects as CEF objects.
They handle the marshaling of objects between Rust and CEF properly.
The net result of this is that you can write mostly-natural-looking Rust
in the CEF port and interact with it with a natural-looking C++ API on
the embedding side.

This setup relies on the branch of CEF located here:

    https://github.com/pcwalton/chromium-embedded-framework

To regenerate, follow the instructions in `ports/cef/README.md`. For
convenience, and because I don't anticipate the API to change much, I
have vendored in all of the appropriate interfaces.
This commit is contained in:
Patrick Walton 2014-11-24 17:23:30 -08:00
parent 431644bfc8
commit 3bf779cd21
82 changed files with 30917 additions and 1664 deletions

View file

@ -2,10 +2,23 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use libc::c_int;
use types::cef_base_t;
use libc::{mod, c_int, c_void, size_t};
use std::mem;
use std::slice;
use std::str;
/// Allows you to downcast a CEF interface to a CEF class instance.
///
/// FIXME(pcwalton): This is currently unsafe. I think the right way to make this safe is to (a)
/// forbid more than one Rust implementation of a given interface (easy to do by manufacturing an
/// impl that will conflict if there is more than one) and then (b) add a dynamic check to make
/// sure the `release` for the object is equal to `servo_release`.
pub trait Downcast<Class> {
fn downcast(&self) -> &Class;
}
pub fn slice_to_str(s: *const u8, l: uint, f: |&str| -> c_int) -> c_int {
unsafe {
slice::raw::buf_as_slice(s, l, |result| {
@ -13,3 +26,57 @@ pub fn slice_to_str(s: *const u8, l: uint, f: |&str| -> c_int) -> c_int {
})
}
}
/// Creates a new raw CEF object of the given type and sets up its reference counting machinery.
/// All fields are initialized to zero. It is the caller's responsibility to ensure that the given
/// type is a CEF type with `cef_base_t` as its first member.
pub unsafe fn create_cef_object<Base,Extra>() -> *mut Base {
let size = (mem::size_of::<Base>() as size_t) + (mem::size_of::<Extra>() as size_t) - 1;
println!("allocating CEF object with size {}", size);
let object = libc::calloc(1, size) as *mut cef_base_t;
(*object).size = size - mem::size_of::<uint>() as u64; // Subtract out the refcount.
(*object).add_ref = Some(servo_add_ref);
(*object).release = Some(servo_release);
*ref_count(object) = 1;
object as *mut Base
}
/// Returns a pointer to the Servo-specific reference count for the given object. This only works
/// on objects that Servo created!
unsafe fn ref_count(object: *mut cef_base_t) -> *mut uint {
// The reference count should be the first field of the extra data.
(object as *mut u8).offset((*object).size as int) as *mut uint
}
/// Increments the reference count on a CEF object. This only works on objects that Servo created!
extern "C" fn servo_add_ref(object: *mut cef_base_t) -> c_int {
unsafe {
let count = ref_count(object);
*count += 1;
*count as c_int
}
}
/// Decrements the reference count on a CEF object. If zero, frees it. This only works on objects
/// that Servo created!
extern "C" fn servo_release(object: *mut cef_base_t) -> c_int {
unsafe {
let count = ref_count(object);
*count -= 1;
let new_count = *count;
if new_count == 0 {
servo_free(object);
}
(new_count == 0) as c_int
}
}
unsafe fn servo_free(object: *mut cef_base_t) {
println!("freeing Servo-created CEF object!");
libc::free(object as *mut c_void);
}
pub unsafe fn add_ref(c_object: *mut cef_base_t) {
((*c_object).add_ref.unwrap())(c_object);
}