diff --git a/ports/geckolib/bindings.rs b/ports/geckolib/bindings.rs index 102d6779d99..34d7b26e540 100644 --- a/ports/geckolib/bindings.rs +++ b/ports/geckolib/bindings.rs @@ -54,6 +54,8 @@ pub enum Struct_ServoNodeData { } pub type ServoNodeData = Struct_ServoNodeData; pub enum Struct_ServoArcStyleSheet { } pub type ServoArcStyleSheet = Struct_ServoArcStyleSheet; +pub enum Struct_ServoStyleSetData { } +pub type ServoStyleSetData = Struct_ServoStyleSetData; extern "C" { pub fn Gecko_ElementState(element: *mut RawGeckoElement) -> uint8_t; pub fn Gecko_GetAttrAsUTF8(element: *mut RawGeckoElement, @@ -84,10 +86,21 @@ extern "C" { pub fn Gecko_NodeIsElement(node: *mut RawGeckoNode) -> ::libc::c_int; pub fn Gecko_SetNodeData(node: *mut RawGeckoNode, data: *mut ServoNodeData); - pub fn Servo_RestyleDocument(aDoc: *mut RawGeckoDocument); + pub fn Servo_RestyleDocument(doc: *mut RawGeckoDocument, + data: *mut ServoStyleSetData); pub fn Servo_DropNodeData(data: *mut ServoNodeData); pub fn Servo_StylesheetFromUTF8Bytes(bytes: *const uint8_t, length: uint32_t) -> *mut ServoArcStyleSheet; + pub fn Servo_AppendStyleSheet(sheet: *mut ServoArcStyleSheet, + data: *mut ServoStyleSetData); + pub fn Servo_PrependStyleSheet(sheet: *mut ServoArcStyleSheet, + data: *mut ServoStyleSetData); + pub fn Servo_RemoveStyleSheet(sheet: *mut ServoArcStyleSheet, + data: *mut ServoStyleSetData); + pub fn Servo_StyleSheetHasRules(sheet: *mut ServoArcStyleSheet) + -> ::libc::c_int; pub fn Servo_DropStylesheet(sheet: *mut ServoArcStyleSheet); + pub fn Servo_InitStyleSetData() -> *mut ServoStyleSetData; + pub fn Servo_DropStyleSetData(data: *mut ServoStyleSetData); } diff --git a/ports/geckolib/data.rs b/ports/geckolib/data.rs new file mode 100644 index 00000000000..3e78c6c87ae --- /dev/null +++ b/ports/geckolib/data.rs @@ -0,0 +1,75 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use bindings::ServoStyleSetData; +use euclid::Size2D; +use euclid::size::TypedSize2D; +use num_cpus; +use std::cmp; +use std::collections::HashMap; +use std::sync::mpsc::{channel, Receiver, Sender}; +use std::sync::{Arc, RwLock}; +use style::animation::Animation; +use style::context::SharedStyleContext; +use style::dom::OpaqueNode; +use style::media_queries::{Device, MediaType}; +use style::parallel::WorkQueueData; +use style::selector_matching::Stylist; +use style::stylesheets::Stylesheet; +use util::geometry::ViewportPx; +use util::thread_state; +use util::workqueue::WorkQueue; + +pub struct PerDocumentStyleData { + + /// Rule processor. + pub stylist: Stylist, + + /// List of stylesheets, mirrored from Gecko. + pub stylesheets: Vec>, + + /// Whether the stylesheets list above has changed since the last restyle. + pub stylesheets_changed: bool, + + // FIXME(bholley): Hook these up to something. + pub new_animations_sender: Sender, + pub new_animations_receiver: Receiver, + pub running_animations: Arc>>>, + pub expired_animations: Arc>>>, + + // FIXME(bholley): This shouldn't be per-document. + pub work_queue: WorkQueue, +} + +impl PerDocumentStyleData { + pub fn new() -> PerDocumentStyleData { + // FIXME(bholley): Real window size. + let window_size: TypedSize2D = Size2D::typed(800.0, 600.0); + let device = Device::new(MediaType::Screen, window_size); + + let (new_anims_sender, new_anims_receiver) = channel(); + let num_threads = cmp::max(num_cpus::get() * 3 / 4, 1); + + PerDocumentStyleData { + stylist: Stylist::new(device), + stylesheets: Vec::new(), + stylesheets_changed: true, + new_animations_sender: new_anims_sender, + new_animations_receiver: new_anims_receiver, + running_animations: Arc::new(RwLock::new(HashMap::new())), + expired_animations: Arc::new(RwLock::new(HashMap::new())), + work_queue: WorkQueue::new("StyleWorker", thread_state::LAYOUT, num_threads), + } + } + + pub fn borrow_mut_from_raw<'a>(data: *mut ServoStyleSetData) -> &'a mut Self { + unsafe { &mut *(data as *mut PerDocumentStyleData) } + } +} + +impl Drop for PerDocumentStyleData { + fn drop(&mut self) { + self.work_queue.shutdown(); + } +} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 5bfa980ef7d..9ad4c99577a 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -6,31 +6,22 @@ use app_units::Au; use bindings::RawGeckoDocument; -use bindings::{ServoNodeData, ServoArcStyleSheet, uint8_t, uint32_t}; +use bindings::{ServoArcStyleSheet, ServoNodeData, ServoStyleSetData, uint8_t, uint32_t}; +use data::PerDocumentStyleData; use euclid::Size2D; -use euclid::size::TypedSize2D; -use num_cpus; -use std::cmp; -use std::collections::HashMap; -use std::mem::transmute; +use std::mem::{forget, transmute}; use std::slice; use std::str::from_utf8_unchecked; -use std::sync::mpsc::{channel, Sender}; -use std::sync::{Arc, Mutex, RwLock}; -use style::animation::Animation; +use std::sync::{Arc, Mutex}; use style::context::{ReflowGoal, SharedStyleContext, StylistWrapper}; use style::dom::{TDocument, TNode}; use style::error_reporting::StdoutErrorReporter; -use style::media_queries::{Device, MediaType}; -use style::parallel::{self, WorkQueueData}; -use style::selector_matching::Stylist; +use style::parallel; use style::stylesheets::{Origin, Stylesheet}; use traversal::RecalcStyleOnly; use url::Url; -use util::geometry::ViewportPx; +use util::arc_ptr_eq; use util::resource_files::set_resources_path; -use util::thread_state; -use util::workqueue::WorkQueue; use wrapper::{GeckoDocument, GeckoNode, NonOpaqueStyleData}; /* @@ -42,50 +33,36 @@ use wrapper::{GeckoDocument, GeckoNode, NonOpaqueStyleData}; */ #[no_mangle] -pub extern "C" fn Servo_RestyleDocument(doc: *mut RawGeckoDocument) -> () { +pub extern "C" fn Servo_RestyleDocument(doc: *mut RawGeckoDocument, raw_data: *mut ServoStyleSetData) -> () { let document = unsafe { GeckoDocument::from_raw(doc) }; let node = match document.root_node() { Some(x) => x, None => return, }; + let data = unsafe { &mut *(raw_data as *mut PerDocumentStyleData) }; // FIXME(bholley): Don't hardcode resources path. We may want to use Gecko's UA stylesheets // anyway. set_resources_path(Some("/files/mozilla/stylo/servo/resources/".to_owned())); - // FIXME(bholley): Real window size. - let window_size: TypedSize2D = Size2D::typed(800.0, 600.0); - let device = Device::new(MediaType::Screen, window_size); - - // FIXME(bholley): Real stylist and stylesheets. - let stylesheets: Vec> = Vec::new(); - let mut stylist = Box::new(Stylist::new(device)); - let _needs_dirtying = stylist.update(&stylesheets, false); - - // FIXME(bholley): Hook this up to something. - let new_animations_sender: Sender = channel().0; + let _needs_dirtying = data.stylist.update(&data.stylesheets, data.stylesheets_changed); + data.stylesheets_changed = false; let shared_style_context = SharedStyleContext { viewport_size: Size2D::new(Au(0), Au(0)), screen_size_changed: false, generation: 0, goal: ReflowGoal::ForScriptQuery, - stylist: StylistWrapper(&*stylist), - new_animations_sender: Mutex::new(new_animations_sender), - running_animations: Arc::new(RwLock::new(HashMap::new())), - expired_animations: Arc::new(RwLock::new(HashMap::new())), + stylist: StylistWrapper(&data.stylist), + new_animations_sender: Mutex::new(data.new_animations_sender.clone()), + running_animations: data.running_animations.clone(), + expired_animations: data.expired_animations.clone(), error_reporter: Box::new(StdoutErrorReporter), }; - let num_threads = cmp::max(num_cpus::get() * 3 / 4, 1); - let mut parallel_traversal: WorkQueue = - WorkQueue::new("StyleWorker", thread_state::LAYOUT, num_threads); - if node.is_dirty() || node.has_dirty_descendants() { - parallel::traverse_dom::(node, &shared_style_context, &mut parallel_traversal); + parallel::traverse_dom::(node, &shared_style_context, &mut data.work_queue); } - - parallel_traversal.shutdown(); } #[no_mangle] @@ -109,9 +86,73 @@ pub extern "C" fn Servo_StylesheetFromUTF8Bytes(bytes: *const uint8_t, } } +fn with_arc_stylesheet(raw: *mut ServoArcStyleSheet, cb: F) -> Output + where F: FnOnce(&Arc) -> Output { + let owned = unsafe { consume_arc_stylesheet(raw) }; + let result = cb(&owned); + forget(owned); + result +} + +unsafe fn consume_arc_stylesheet(raw: *mut ServoArcStyleSheet) -> Arc { + transmute(raw) +} + +#[no_mangle] +pub extern "C" fn Servo_AppendStyleSheet(raw_sheet: *mut ServoArcStyleSheet, + raw_data: *mut ServoStyleSetData) { + let data = PerDocumentStyleData::borrow_mut_from_raw(raw_data); + with_arc_stylesheet(raw_sheet, |sheet| { + data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); + data.stylesheets.push(sheet.clone()); + data.stylesheets_changed = true; + }); +} + +#[no_mangle] +pub extern "C" fn Servo_PrependStyleSheet(raw_sheet: *mut ServoArcStyleSheet, + raw_data: *mut ServoStyleSetData) { + let data = PerDocumentStyleData::borrow_mut_from_raw(raw_data); + with_arc_stylesheet(raw_sheet, |sheet| { + data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); + data.stylesheets.insert(0, sheet.clone()); + data.stylesheets_changed = true; + }) +} + +#[no_mangle] +pub extern "C" fn Servo_RemoveStyleSheet(raw_sheet: *mut ServoArcStyleSheet, + raw_data: *mut ServoStyleSetData) { + let data = PerDocumentStyleData::borrow_mut_from_raw(raw_data); + with_arc_stylesheet(raw_sheet, |sheet| { + data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); + data.stylesheets_changed = true; + }); +} + +#[no_mangle] +pub extern "C" fn Servo_StyleSheetHasRules(raw_sheet: *mut ServoArcStyleSheet) -> ::libc::c_int { + with_arc_stylesheet(raw_sheet, |sheet| if sheet.rules.is_empty() { 0 } else { 1 }) +} + + #[no_mangle] pub extern "C" fn Servo_DropStylesheet(sheet: *mut ServoArcStyleSheet) -> () { unsafe { - let _ : Arc = transmute(sheet); + let _ = consume_arc_stylesheet(sheet); + } +} + +#[no_mangle] +pub extern "C" fn Servo_InitStyleSetData() -> *mut ServoStyleSetData { + let data = Box::new(PerDocumentStyleData::new()); + Box::into_raw(data) as *mut ServoStyleSetData +} + + +#[no_mangle] +pub extern "C" fn Servo_DropStyleSetData(data: *mut ServoStyleSetData) -> () { + unsafe { + let _ = Box::::from_raw(data as *mut PerDocumentStyleData); } } diff --git a/ports/geckolib/lib.rs b/ports/geckolib/lib.rs index e224864dc6c..e47d757b127 100644 --- a/ports/geckolib/lib.rs +++ b/ports/geckolib/lib.rs @@ -23,6 +23,7 @@ extern crate util; #[allow(dead_code, non_camel_case_types)] mod bindings; +mod data; #[allow(non_snake_case)] pub mod glue; mod traversal;