Implement a more realistic and persistent document restyle.

This commit is contained in:
Bobby Holley 2016-01-27 09:27:42 -08:00
parent 33c4689b15
commit 2e770b78a2
4 changed files with 170 additions and 40 deletions

View file

@ -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);
}

75
ports/geckolib/data.rs Normal file
View file

@ -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<Arc<Stylesheet>>,
/// 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<Animation>,
pub new_animations_receiver: Receiver<Animation>,
pub running_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
pub expired_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
// FIXME(bholley): This shouldn't be per-document.
pub work_queue: WorkQueue<SharedStyleContext, WorkQueueData>,
}
impl PerDocumentStyleData {
pub fn new() -> PerDocumentStyleData {
// FIXME(bholley): Real window size.
let window_size: TypedSize2D<ViewportPx, f32> = 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();
}
}

View file

@ -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<ViewportPx, f32> = Size2D::typed(800.0, 600.0);
let device = Device::new(MediaType::Screen, window_size);
// FIXME(bholley): Real stylist and stylesheets.
let stylesheets: Vec<Arc<Stylesheet>> = 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<Animation> = 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<SharedStyleContext, WorkQueueData> =
WorkQueue::new("StyleWorker", thread_state::LAYOUT, num_threads);
if node.is_dirty() || node.has_dirty_descendants() {
parallel::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context, &mut parallel_traversal);
parallel::traverse_dom::<GeckoNode, RecalcStyleOnly>(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<F, Output>(raw: *mut ServoArcStyleSheet, cb: F) -> Output
where F: FnOnce(&Arc<Stylesheet>) -> Output {
let owned = unsafe { consume_arc_stylesheet(raw) };
let result = cb(&owned);
forget(owned);
result
}
unsafe fn consume_arc_stylesheet(raw: *mut ServoArcStyleSheet) -> Arc<Stylesheet> {
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<Stylesheet> = 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::<PerDocumentStyleData>::from_raw(data as *mut PerDocumentStyleData);
}
}

View file

@ -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;