mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
auto merge of #862 : kmcallister/servo/embed-layout-data, r=jdm
This commit is contained in:
commit
1cdd513c04
8 changed files with 165 additions and 171 deletions
|
@ -2,10 +2,10 @@
|
|||
* 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 layout::aux::LayoutAuxMethods;
|
||||
use layout::incremental::RestyleDamage;
|
||||
|
||||
use std::cast::transmute;
|
||||
use std::cast;
|
||||
use std::cell::Cell;
|
||||
use newcss::complete::CompleteSelectResults;
|
||||
use script::dom::node::{AbstractNode, LayoutView};
|
||||
|
||||
|
@ -27,28 +27,23 @@ impl<'self> NodeUtil<'self> for AbstractNode<LayoutView> {
|
|||
* stored in a box that can be overwritten
|
||||
*/
|
||||
fn get_css_select_results(self) -> &'self CompleteSelectResults {
|
||||
if !self.has_layout_data() {
|
||||
fail!(~"style() called on a node without aux data!");
|
||||
}
|
||||
|
||||
match self.layout_data().style {
|
||||
None => fail!(~"style() called on node without a style!"),
|
||||
Some(ref style) => unsafe { transmute(style) }
|
||||
do self.read_layout_data |layout_data| {
|
||||
match layout_data.style {
|
||||
None => fail!(~"style() called on node without a style!"),
|
||||
Some(ref style) => unsafe { cast::transmute_region(style) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Does this node have a computed style yet?
|
||||
fn have_css_select_results(self) -> bool {
|
||||
self.has_layout_data() && self.layout_data().style.is_some()
|
||||
self.read_layout_data(|data| data.style.is_some())
|
||||
}
|
||||
|
||||
/// Update the computed style of an HTML element with a style specified by CSS.
|
||||
fn set_css_select_results(self, decl: CompleteSelectResults) {
|
||||
if !self.has_layout_data() {
|
||||
fail!(~"set_css_select_results() called on a node without aux data!");
|
||||
}
|
||||
|
||||
self.layout_data().style = Some(decl);
|
||||
let cell = Cell::new(decl);
|
||||
self.write_layout_data(|data| data.style = Some(cell.take()));
|
||||
}
|
||||
|
||||
/// Get the description of how to account for recent style changes.
|
||||
|
@ -62,18 +57,15 @@ impl<'self> NodeUtil<'self> for AbstractNode<LayoutView> {
|
|||
RestyleDamage::none()
|
||||
};
|
||||
|
||||
if !self.has_layout_data() {
|
||||
return default;
|
||||
do self.read_layout_data |layout_data| {
|
||||
layout_data.restyle_damage
|
||||
.map(|&x| RestyleDamage::from_int(x))
|
||||
.unwrap_or_default(default)
|
||||
}
|
||||
self.layout_data().restyle_damage.unwrap_or_default(default)
|
||||
}
|
||||
|
||||
/// Set the restyle damage field.
|
||||
fn set_restyle_damage(self, damage: RestyleDamage) {
|
||||
if !self.has_layout_data() {
|
||||
fail!(~"set_restyle_damage() called on a node without aux data!");
|
||||
}
|
||||
|
||||
self.layout_data().restyle_damage = Some(damage);
|
||||
self.write_layout_data(|data| data.restyle_damage = Some(damage.to_int()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,94 +4,28 @@
|
|||
|
||||
//! Code for managing the layout data in the DOM.
|
||||
|
||||
use layout::incremental::RestyleDamage;
|
||||
use gfx::display_list::DisplayList;
|
||||
use servo_util::range::Range;
|
||||
|
||||
use extra::arc::Arc;
|
||||
use newcss::complete::CompleteSelectResults;
|
||||
use script::dom::node::{AbstractNode, LayoutView};
|
||||
use servo_util::tree::TreeNodeRef;
|
||||
|
||||
pub struct DisplayBoxes {
|
||||
display_list: Option<Arc<DisplayList<AbstractNode<()>>>>,
|
||||
range: Option<Range>,
|
||||
}
|
||||
|
||||
/// Data that layout associates with a node.
|
||||
pub struct LayoutData {
|
||||
/// The results of CSS styling for this node.
|
||||
style: Option<CompleteSelectResults>,
|
||||
|
||||
/// Description of how to account for recent style changes.
|
||||
restyle_damage: Option<RestyleDamage>,
|
||||
|
||||
/// The boxes assosiated with this flow.
|
||||
/// Used for getBoundingClientRect and friends.
|
||||
boxes: DisplayBoxes,
|
||||
}
|
||||
|
||||
impl LayoutData {
|
||||
/// Creates new layout data.
|
||||
pub fn new() -> LayoutData {
|
||||
LayoutData {
|
||||
style: None,
|
||||
restyle_damage: None,
|
||||
boxes: DisplayBoxes { display_list: None, range: None },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Functionality useful for querying the layout-specific data on DOM nodes.
|
||||
pub trait LayoutAuxMethods {
|
||||
fn layout_data(self) -> @mut LayoutData;
|
||||
fn has_layout_data(self) -> bool;
|
||||
fn set_layout_data(self, data: @mut LayoutData);
|
||||
|
||||
fn initialize_layout_data(self) -> Option<@mut LayoutData>;
|
||||
fn initialize_style_for_subtree(self, refs: &mut ~[@mut LayoutData]);
|
||||
fn initialize_layout_data(self);
|
||||
fn initialize_style_for_subtree(self);
|
||||
}
|
||||
|
||||
impl LayoutAuxMethods for AbstractNode<LayoutView> {
|
||||
fn layout_data(self) -> @mut LayoutData {
|
||||
unsafe {
|
||||
self.unsafe_layout_data()
|
||||
}
|
||||
}
|
||||
fn has_layout_data(self) -> bool {
|
||||
unsafe {
|
||||
self.unsafe_has_layout_data()
|
||||
}
|
||||
}
|
||||
fn set_layout_data(self, data: @mut LayoutData) {
|
||||
unsafe {
|
||||
self.unsafe_set_layout_data(data)
|
||||
/// Resets layout data and styles for the node.
|
||||
fn initialize_layout_data(self) {
|
||||
do self.write_layout_data |data| {
|
||||
data.boxes.display_list = None;
|
||||
data.boxes.range = None;
|
||||
}
|
||||
}
|
||||
|
||||
/// If none exists, creates empty layout data for the node (the reader-auxiliary
|
||||
/// box in the COW model) and populates it with an empty style object.
|
||||
fn initialize_layout_data(self) -> Option<@mut LayoutData> {
|
||||
if self.has_layout_data() {
|
||||
self.layout_data().boxes.display_list = None;
|
||||
self.layout_data().boxes.range = None;
|
||||
None
|
||||
} else {
|
||||
let data = @mut LayoutData::new();
|
||||
self.set_layout_data(data);
|
||||
Some(data)
|
||||
/// Resets layout data and styles for a Node tree.
|
||||
fn initialize_style_for_subtree(self) {
|
||||
for n in self.traverse_preorder() {
|
||||
n.initialize_layout_data();
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes layout data and styles for a Node tree, if any nodes do not have
|
||||
/// this data already. Append created layout data to the task's GC roots.
|
||||
fn initialize_style_for_subtree(self, refs: &mut ~[@mut LayoutData]) {
|
||||
let _ = for n in self.traverse_preorder() {
|
||||
match n.initialize_layout_data() {
|
||||
Some(r) => refs.push(r),
|
||||
None => {}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,17 @@ impl RestyleDamage {
|
|||
RestyleDamage::all()
|
||||
}
|
||||
|
||||
/// Create a RestyleDamage from the underlying bit field.
|
||||
/// We would rather not allow this, but some types in script
|
||||
/// need to store RestyleDamage without depending on this crate.
|
||||
pub fn from_int(n: int) -> RestyleDamage {
|
||||
RestyleDamage { bits: n }
|
||||
}
|
||||
|
||||
pub fn to_int(self) -> int {
|
||||
self.bits
|
||||
}
|
||||
|
||||
pub fn is_empty(self) -> bool {
|
||||
self.bits == 0
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
use css::matching::MatchMethods;
|
||||
use css::select::new_css_select_ctx;
|
||||
use layout::aux::{LayoutData, LayoutAuxMethods};
|
||||
use layout::aux::LayoutAuxMethods;
|
||||
use layout::box_builder::LayoutTreeBuilder;
|
||||
use layout::context::LayoutContext;
|
||||
use layout::display_list_builder::{DisplayListBuilder};
|
||||
|
@ -59,9 +59,6 @@ struct LayoutTask {
|
|||
doc_url: Option<Url>,
|
||||
screen_size: Option<Size2D<Au>>,
|
||||
|
||||
/// This is used to root reader data.
|
||||
layout_refs: ~[@mut LayoutData],
|
||||
|
||||
display_list: Option<Arc<DisplayList<AbstractNode<()>>>>,
|
||||
|
||||
css_select_ctx: @mut SelectCtx,
|
||||
|
@ -123,7 +120,6 @@ impl LayoutTask {
|
|||
|
||||
display_list: None,
|
||||
|
||||
layout_refs: ~[],
|
||||
css_select_ctx: @mut new_css_select_ctx(),
|
||||
profiler_chan: profiler_chan,
|
||||
}
|
||||
|
@ -210,7 +206,7 @@ impl LayoutTask {
|
|||
//
|
||||
// FIXME: This is inefficient. We don't need an entire traversal to do this!
|
||||
do profile(time::LayoutAuxInitCategory, self.profiler_chan.clone()) {
|
||||
node.initialize_style_for_subtree(&mut self.layout_refs);
|
||||
node.initialize_style_for_subtree();
|
||||
}
|
||||
|
||||
// Perform CSS selector matching if necessary.
|
||||
|
@ -326,15 +322,14 @@ impl LayoutTask {
|
|||
let node: AbstractNode<LayoutView> = unsafe {
|
||||
transmute(display_list.get().list[i].base().extra)
|
||||
};
|
||||
assert!(node.has_layout_data(), "Node has display item but no layout data");
|
||||
|
||||
let layout_data = node.layout_data();
|
||||
layout_data.boxes.display_list = Some(display_list.clone());
|
||||
do node.write_layout_data |layout_data| {
|
||||
layout_data.boxes.display_list = Some(display_list.clone());
|
||||
|
||||
if layout_data.boxes.range.is_none() {
|
||||
debug!("Creating initial range for node");
|
||||
layout_data.boxes.range = Some(Range::new(i,1));
|
||||
} else {
|
||||
if layout_data.boxes.range.is_none() {
|
||||
debug!("Creating initial range for node");
|
||||
layout_data.boxes.range = Some(Range::new(i,1));
|
||||
} else {
|
||||
debug!("Appending item to range");
|
||||
unsafe {
|
||||
let old_node: AbstractNode<()> = transmute(node);
|
||||
|
@ -343,6 +338,7 @@ impl LayoutTask {
|
|||
}
|
||||
|
||||
layout_data.boxes.range.unwrap().extend_by(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -376,28 +372,30 @@ impl LayoutTask {
|
|||
transmute(node)
|
||||
};
|
||||
|
||||
let response = match (node.layout_data().boxes.display_list.clone(), node.layout_data().boxes.range) {
|
||||
(Some(display_list), Some(range)) => {
|
||||
let mut rect: Option<Rect<Au>> = None;
|
||||
for i in range.eachi() {
|
||||
rect = match rect {
|
||||
Some(acc) => Some(acc.union(&display_list.get().list[i].bounds())),
|
||||
None => Some(display_list.get().list[i].bounds())
|
||||
let response = do node.read_layout_data |layout_data| {
|
||||
match (layout_data.boxes.display_list.clone(), layout_data.boxes.range) {
|
||||
(Some(display_list), Some(range)) => {
|
||||
let mut rect: Option<Rect<Au>> = None;
|
||||
for i in range.eachi() {
|
||||
rect = match rect {
|
||||
Some(acc) => Some(acc.union(&display_list.get().list[i].bounds())),
|
||||
None => Some(display_list.get().list[i].bounds())
|
||||
}
|
||||
}
|
||||
|
||||
match rect {
|
||||
None => {
|
||||
error!("no boxes for node");
|
||||
Err(())
|
||||
}
|
||||
Some(rect) => Ok(ContentBoxResponse(rect))
|
||||
}
|
||||
}
|
||||
|
||||
match rect {
|
||||
None => {
|
||||
error!("no boxes for node");
|
||||
Err(())
|
||||
}
|
||||
Some(rect) => Ok(ContentBoxResponse(rect))
|
||||
_ => {
|
||||
error!("no display list present");
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
error!("no display list present");
|
||||
Err(())
|
||||
}
|
||||
};
|
||||
|
||||
reply_chan.send(response)
|
||||
|
@ -408,16 +406,18 @@ impl LayoutTask {
|
|||
transmute(node)
|
||||
};
|
||||
|
||||
let response = match (node.layout_data().boxes.display_list.clone(), node.layout_data().boxes.range) {
|
||||
(Some(display_list), Some(range)) => {
|
||||
let mut boxes = ~[];
|
||||
for i in range.eachi() {
|
||||
boxes.push(display_list.get().list[i].bounds());
|
||||
}
|
||||
let response = do node.read_layout_data |layout_data| {
|
||||
match (layout_data.boxes.display_list.clone(), layout_data.boxes.range) {
|
||||
(Some(display_list), Some(range)) => {
|
||||
let mut boxes = ~[];
|
||||
for i in range.eachi() {
|
||||
boxes.push(display_list.get().list[i].bounds());
|
||||
}
|
||||
|
||||
Ok(ContentBoxesResponse(boxes))
|
||||
Ok(ContentBoxesResponse(boxes))
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
_ => Err(()),
|
||||
};
|
||||
|
||||
reply_chan.send(response)
|
||||
|
|
|
@ -10,7 +10,6 @@ use script_task::page_from_context;
|
|||
|
||||
use std::libc::c_uint;
|
||||
use std::cast;
|
||||
use std::cell::Cell;
|
||||
use std::hashmap::HashMap;
|
||||
use std::libc;
|
||||
use std::ptr;
|
||||
|
@ -30,8 +29,7 @@ use js::jsapi::{JS_NewStringCopyN, JS_DefineFunctions, JS_DefineProperty};
|
|||
use js::jsapi::{JS_ValueToString, JS_GetReservedSlot, JS_SetReservedSlot};
|
||||
use js::jsapi::{JSContext, JSObject, JSBool, jsid, JSClass, JSNative};
|
||||
use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor};
|
||||
use js::jsapi::{JSFreeOp, JSTracer};
|
||||
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp, JSEnumerateOp, JSResolveOp, JSConvertOp};
|
||||
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp};
|
||||
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
|
||||
use js::rust::Compartment;
|
||||
use js::{JSPROP_ENUMERATE, JSVAL_NULL};
|
||||
|
|
|
@ -18,10 +18,14 @@ use dom::text::Text;
|
|||
use std::cast;
|
||||
use std::cast::transmute;
|
||||
use std::libc::c_void;
|
||||
use extra::arc::Arc;
|
||||
use js::jsapi::{JSObject, JSContext};
|
||||
use js::rust::Compartment;
|
||||
use netsurfcss::util::VoidPtrLike;
|
||||
use newcss::complete::CompleteSelectResults;
|
||||
use servo_util::tree::{TreeNode, TreeNodeRef};
|
||||
use servo_util::range::Range;
|
||||
use gfx::display_list::DisplayList;
|
||||
|
||||
//
|
||||
// The basic Node structure
|
||||
|
@ -56,7 +60,7 @@ pub struct AbstractNodeChildrenIterator<View> {
|
|||
///
|
||||
/// `View` describes extra data associated with this node that this task has access to. For
|
||||
/// the script task, this is the unit type `()`. For the layout task, this is
|
||||
/// `layout::aux::LayoutData`.
|
||||
/// `LayoutData`.
|
||||
pub struct Node<View> {
|
||||
/// The JavaScript wrapper for this node.
|
||||
wrapper: WrapperCache,
|
||||
|
@ -85,7 +89,7 @@ pub struct Node<View> {
|
|||
owner_doc: Option<AbstractDocument>,
|
||||
|
||||
/// Layout information. Only the layout task may touch this data.
|
||||
priv layout_data: Option<@mut ()>
|
||||
priv layout_data: LayoutData,
|
||||
}
|
||||
|
||||
/// The different types of nodes.
|
||||
|
@ -172,31 +176,6 @@ impl<'self, View> AbstractNode<View> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the layout data, unsafely cast to whatever type layout wishes. Only layout is
|
||||
/// allowed to call this. This is wildly unsafe and is therefore marked as such.
|
||||
pub unsafe fn unsafe_layout_data<T>(self) -> @mut T {
|
||||
do self.with_base |base| {
|
||||
transmute(base.layout_data.unwrap())
|
||||
}
|
||||
}
|
||||
/// Returns true if this node has layout data and false otherwise.
|
||||
pub unsafe fn unsafe_has_layout_data(self) -> bool {
|
||||
do self.with_base |base| {
|
||||
base.layout_data.is_some()
|
||||
}
|
||||
}
|
||||
/// Sets the layout data, unsafely casting the type as layout wishes. Only layout is allowed
|
||||
/// to call this. This is wildly unsafe and is therefore marked as such.
|
||||
pub unsafe fn unsafe_set_layout_data<T>(self, data: @mut T) {
|
||||
// Don't decrement the refcount on data, since we're giving it to the
|
||||
// base structure.
|
||||
cast::forget(data);
|
||||
|
||||
do self.with_mut_base |base| {
|
||||
base.layout_data = Some(transmute(data))
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience accessors
|
||||
|
||||
/// Returns the type ID of this node. Fails if this node is borrowed mutably.
|
||||
|
@ -435,7 +414,7 @@ impl Node<ScriptView> {
|
|||
|
||||
owner_doc: None,
|
||||
|
||||
layout_data: None,
|
||||
layout_data: LayoutData::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -631,3 +610,52 @@ impl BindingObject for Node<ScriptView> {
|
|||
}
|
||||
}
|
||||
|
||||
// This stuff is notionally private to layout, but we put it here because it needs
|
||||
// to be stored in a Node, and we can't have cross-crate cyclic dependencies.
|
||||
|
||||
pub struct DisplayBoxes {
|
||||
display_list: Option<Arc<DisplayList<AbstractNode<()>>>>,
|
||||
range: Option<Range>,
|
||||
}
|
||||
|
||||
/// Data that layout associates with a node.
|
||||
pub struct LayoutData {
|
||||
/// The results of CSS styling for this node.
|
||||
style: Option<CompleteSelectResults>,
|
||||
|
||||
/// Description of how to account for recent style changes.
|
||||
restyle_damage: Option<int>,
|
||||
|
||||
/// The boxes assosiated with this flow.
|
||||
/// Used for getBoundingClientRect and friends.
|
||||
boxes: DisplayBoxes,
|
||||
}
|
||||
|
||||
impl LayoutData {
|
||||
/// Creates new layout data.
|
||||
pub fn new() -> LayoutData {
|
||||
LayoutData {
|
||||
style: None,
|
||||
restyle_damage: None,
|
||||
boxes: DisplayBoxes { display_list: None, range: None },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractNode<LayoutView> {
|
||||
// These accessors take a continuation rather than returning a reference, because
|
||||
// an AbstractNode doesn't have a lifetime parameter relating to the underlying
|
||||
// Node. Also this makes it easier to switch to RWArc if we decide that is
|
||||
// necessary.
|
||||
pub fn read_layout_data<R>(self, blk: &fn(data: &LayoutData) -> R) -> R {
|
||||
do self.with_base |b| {
|
||||
blk(&b.layout_data)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_layout_data<R>(self, blk: &fn(data: &mut LayoutData) -> R) -> R {
|
||||
do self.with_mut_base |b| {
|
||||
blk(&mut b.layout_data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
31
src/components/util/debug.rs
Normal file
31
src/components/util/debug.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* 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 std::io;
|
||||
use std::vec::raw::buf_as_slice;
|
||||
use std::cast::transmute;
|
||||
use std::sys::size_of;
|
||||
|
||||
fn hexdump_slice(buf: &[u8]) {
|
||||
let stderr = io::stderr();
|
||||
stderr.write_str(" ");
|
||||
for (i, &v) in buf.iter().enumerate() {
|
||||
stderr.write_str(fmt!("%02X ", v as uint));
|
||||
match i % 16 {
|
||||
15 => stderr.write_str("\n "),
|
||||
7 => stderr.write_str(" "),
|
||||
_ => ()
|
||||
}
|
||||
stderr.flush();
|
||||
}
|
||||
stderr.write_char('\n');
|
||||
}
|
||||
|
||||
pub fn hexdump<T>(obj: &T) {
|
||||
unsafe {
|
||||
let buf: *u8 = transmute(obj);
|
||||
debug!("dumping at %p", buf);
|
||||
buf_as_slice(buf, size_of::<T>(), hexdump_slice);
|
||||
}
|
||||
}
|
|
@ -16,4 +16,4 @@ pub mod time;
|
|||
pub mod tree;
|
||||
pub mod url;
|
||||
pub mod vec;
|
||||
|
||||
pub mod debug;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue