servo: Merge #9051 - Split layout wrappers into style+layout and layout-only functionality (from bholley:split_style_and_layout_wrappers); r=SimonSapin

This is a step towards removing the dependency of stylo on layout/.

This PR depends on #9004.

Source-Repo: https://github.com/servo/servo
Source-Revision: 0f5c614609fd8867a9e7c27b8a398ea7d877c714
This commit is contained in:
Bobby Holley 2015-12-30 09:35:14 +05:01
Родитель 70ca13cc30
Коммит a5868c1c28
20 изменённых файлов: 657 добавлений и 706 удалений

Просмотреть файл

@ -22,7 +22,6 @@ use euclid::approxeq::ApproxEq;
use euclid::num::Zero;
use euclid::{Matrix2D, Matrix4, Point2D, Rect, SideOffsets2D, Size2D};
use gfx_traits::{color, LayerId, LayerKind, ScrollPolicy};
use libc::uintptr_t;
use msg::constellation_msg::PipelineId;
use net_traits::image::base::Image;
use paint_context::PaintContext;
@ -49,6 +48,8 @@ use util::opts;
use util::print_tree::PrintTree;
use util::range::Range;
pub use style::dom::OpaqueNode;
// It seems cleaner to have layout code not mention Azure directly, so let's just reexport this for
// layout to use.
pub use azure::azure_hl::GradientStop;
@ -59,24 +60,6 @@ pub mod optimizer;
/// items that involve a blur. This ensures that the display item boundaries include all the ink.
pub static BLUR_INFLATION_FACTOR: i32 = 3;
/// An opaque handle to a node. The only safe operation that can be performed on this node is to
/// compare it to another opaque handle or to another node.
///
/// Because the script task's GC does not trace layout, node data cannot be safely stored in layout
/// data structures. Also, layout code tends to be faster when the DOM is not being accessed, for
/// locality reasons. Using `OpaqueNode` enforces this invariant.
#[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf, Hash, Eq, Deserialize, Serialize)]
pub struct OpaqueNode(pub uintptr_t);
impl OpaqueNode {
/// Returns the address of this node, for debugging purposes.
#[inline]
pub fn id(&self) -> uintptr_t {
let OpaqueNode(pointer) = *self;
pointer
}
}
/// LayerInfo is used to store PaintLayer metadata during DisplayList construction.
/// It is also used for tracking LayerIds when creating layers to preserve ordering when
/// layered DisplayItems should render underneath unlayered DisplayItems.

Просмотреть файл

@ -15,7 +15,7 @@
use block::BlockFlow;
use context::LayoutContext;
use data::{HAS_NEWLY_CONSTRUCTED_FLOW, LayoutDataWrapper};
use data::{HAS_NEWLY_CONSTRUCTED_FLOW, PrivateLayoutData};
use flex::FlexFlow;
use floats::FloatKind;
use flow::{MutableFlowUtils, MutableOwnedFlowUtils};
@ -58,7 +58,7 @@ use traversal::PostorderNodeMutTraversal;
use url::Url;
use util::linked_list;
use util::opts;
use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
use wrapper::{LayoutNode, PseudoElementType, TextContent, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
/// The results of flow construction for a DOM node.
#[derive(Clone)]
@ -1326,10 +1326,9 @@ impl<'a, 'ln, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln>>
let mut style = node.style().clone();
let mut layout_data_ref = node.mutate_layout_data();
let layout_data = layout_data_ref.as_mut().expect("no layout data");
let damage = layout_data.data.restyle_damage;
match *node.construction_result_mut(layout_data) {
let mut data = node.mutate_layout_data().unwrap();
let damage = data.restyle_damage;
match *node.construction_result_mut(&mut *data) {
ConstructionResult::None => true,
ConstructionResult::Flow(ref mut flow, _) => {
// The node's flow is of the same type and has the same set of children and can
@ -1580,7 +1579,7 @@ trait NodeUtils {
/// Returns true if this node doesn't render its kids and false otherwise.
fn is_replaced_content(&self) -> bool;
fn construction_result_mut(self, layout_data: &mut LayoutDataWrapper) -> &mut ConstructionResult;
fn construction_result_mut(self, layout_data: &mut PrivateLayoutData) -> &mut ConstructionResult;
/// Sets the construction result of a flow.
fn set_flow_construction_result(self, result: ConstructionResult);
@ -1611,30 +1610,26 @@ impl<'ln, ConcreteThreadSafeLayoutNode> NodeUtils for ConcreteThreadSafeLayoutNo
}
}
fn construction_result_mut(self, layout_data: &mut LayoutDataWrapper) -> &mut ConstructionResult {
fn construction_result_mut(self, data: &mut PrivateLayoutData) -> &mut ConstructionResult {
match self.get_pseudo_element_type() {
PseudoElementType::Before(_) => &mut layout_data.data.before_flow_construction_result,
PseudoElementType::After (_) => &mut layout_data.data.after_flow_construction_result,
PseudoElementType::Normal => &mut layout_data.data.flow_construction_result,
PseudoElementType::Before(_) => &mut data.before_flow_construction_result,
PseudoElementType::After (_) => &mut data.after_flow_construction_result,
PseudoElementType::Normal => &mut data.flow_construction_result,
}
}
#[inline(always)]
fn set_flow_construction_result(self, result: ConstructionResult) {
let mut layout_data_ref = self.mutate_layout_data();
let layout_data = layout_data_ref.as_mut().expect("no layout data");
let dst = self.construction_result_mut(layout_data);
let mut layout_data = self.mutate_layout_data().unwrap();
let dst = self.construction_result_mut(&mut *layout_data);
*dst = result;
}
#[inline(always)]
fn swap_out_construction_result(self) -> ConstructionResult {
let mut layout_data_ref = self.mutate_layout_data();
let layout_data = layout_data_ref.as_mut().expect("no layout data");
self.construction_result_mut(layout_data).swap_out()
let mut layout_data = self.mutate_layout_data().unwrap();
self.construction_result_mut(&mut *layout_data).swap_out()
}
}

Просмотреть файл

@ -8,7 +8,7 @@
use animation;
use context::SharedLayoutContext;
use data::LayoutDataWrapper;
use data::PrivateLayoutData;
use incremental::{self, RestyleDamage};
use msg::ParseErrorReporter;
use script::layout_interface::Animation;
@ -20,18 +20,19 @@ use selectors::{Element};
use smallvec::SmallVec;
use std::borrow::ToOwned;
use std::hash::{Hash, Hasher};
use std::mem::transmute;
use std::slice::Iter;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
use string_cache::{Atom, Namespace};
use style::node::TElementAttributes;
use style::data::PrivateStyleData;
use style::dom::{TElement, TNode};
use style::properties::{ComputedValues, PropertyDeclaration, cascade};
use style::selector_matching::{DeclarationBlock, Stylist};
use util::arc_ptr_eq;
use util::cache::{LRUCache, SimpleHashCache};
use util::opts;
use util::vec::ForgetfulSink;
use wrapper::{LayoutElement, LayoutNode};
pub struct ApplicableDeclarations {
pub normal: SmallVec<[DeclarationBlock; 16]>,
@ -160,7 +161,7 @@ pub struct StyleSharingCandidateCache {
cache: LRUCache<StyleSharingCandidate, ()>,
}
fn create_common_style_affecting_attributes_from_element<'le, E: LayoutElement<'le>>(element: &E)
fn create_common_style_affecting_attributes_from_element<'le, E: TElement<'le>>(element: &E)
-> CommonStyleAffectingAttributes {
let mut flags = CommonStyleAffectingAttributes::empty();
for attribute_info in &common_style_affecting_attributes() {
@ -211,17 +212,17 @@ impl StyleSharingCandidate {
/// Attempts to create a style sharing candidate from this node. Returns
/// the style sharing candidate or `None` if this node is ineligible for
/// style sharing.
fn new<'le, E: LayoutElement<'le>>(element: &E) -> Option<StyleSharingCandidate> {
fn new<'le, E: TElement<'le>>(element: &E) -> Option<StyleSharingCandidate> {
let parent_element = match element.parent_element() {
None => return None,
Some(parent_element) => parent_element,
};
let style = unsafe {
match *element.as_node().borrow_layout_data_unchecked() {
match element.as_node().borrow_data_unchecked() {
None => return None,
Some(ref layout_data_ref) => {
match layout_data_ref.shared_data.style {
Some(data_ref) => {
match (*data_ref).style {
None => return None,
Some(ref data) => (*data).clone(),
}
@ -229,10 +230,10 @@ impl StyleSharingCandidate {
}
};
let parent_style = unsafe {
match *parent_element.as_node().borrow_layout_data_unchecked() {
match parent_element.as_node().borrow_data_unchecked() {
None => return None,
Some(ref parent_layout_data_ref) => {
match parent_layout_data_ref.shared_data.style {
Some(parent_data_ref) => {
match (*parent_data_ref).style {
None => return None,
Some(ref data) => (*data).clone(),
}
@ -257,7 +258,7 @@ impl StyleSharingCandidate {
})
}
fn can_share_style_with<'a, E: LayoutElement<'a>>(&self, element: &E) -> bool {
fn can_share_style_with<'a, E: TElement<'a>>(&self, element: &E) -> bool {
if *element.get_local_name() != self.local_name {
return false
}
@ -342,7 +343,7 @@ impl StyleSharingCandidateCache {
self.cache.iter()
}
pub fn insert_if_possible<'le, E: LayoutElement<'le>>(&mut self, element: &E) {
pub fn insert_if_possible<'le, E: TElement<'le>>(&mut self, element: &E) {
match StyleSharingCandidate::new(element) {
None => {}
Some(candidate) => self.cache.insert(candidate, ())
@ -363,7 +364,7 @@ pub enum StyleSharingResult {
StyleWasShared(usize, RestyleDamage),
}
pub trait ElementMatchMethods<'le, ConcreteLayoutElement: LayoutElement<'le>> {
pub trait ElementMatchMethods<'le, ConcreteElement: TElement<'le>> {
fn match_element(&self,
stylist: &Stylist,
parent_bf: Option<&BloomFilter>,
@ -376,11 +377,11 @@ pub trait ElementMatchMethods<'le, ConcreteLayoutElement: LayoutElement<'le>> {
unsafe fn share_style_if_possible(&self,
style_sharing_candidate_cache:
&mut StyleSharingCandidateCache,
parent: Option<ConcreteLayoutElement::ConcreteLayoutNode>)
parent: Option<ConcreteElement::ConcreteNode>)
-> StyleSharingResult;
}
pub trait MatchMethods<'ln, ConcreteLayoutNode: LayoutNode<'ln>> {
pub trait MatchMethods<'ln, ConcreteNode: TNode<'ln>> {
/// Inserts and removes the matching `Descendant` selectors from a bloom
/// filter. This is used to speed up CSS selector matching to remove
/// unnecessary tree climbs for `Descendant` queries.
@ -396,7 +397,7 @@ pub trait MatchMethods<'ln, ConcreteLayoutNode: LayoutNode<'ln>> {
unsafe fn cascade_node(&self,
layout_context: &SharedLayoutContext,
parent: Option<ConcreteLayoutNode>,
parent: Option<ConcreteNode>,
applicable_declarations: &ApplicableDeclarations,
applicable_declarations_cache: &mut ApplicableDeclarationsCache,
new_animations_sender: &Mutex<Sender<Animation>>);
@ -420,15 +421,15 @@ trait PrivateMatchMethods {
-> bool;
}
trait PrivateElementMatchMethods<'le, ConcreteLayoutElement: LayoutElement<'le>> {
trait PrivateElementMatchMethods<'le, ConcreteElement: TElement<'le>> {
fn share_style_with_candidate_if_possible(&self,
parent_node: Option<ConcreteLayoutElement::ConcreteLayoutNode>,
parent_node: Option<ConcreteElement::ConcreteNode>,
candidate: &StyleSharingCandidate)
-> Option<Arc<ComputedValues>>;
}
impl<'ln, ConcreteLayoutNode> PrivateMatchMethods for ConcreteLayoutNode
where ConcreteLayoutNode: LayoutNode<'ln> {
impl<'ln, ConcreteNode> PrivateMatchMethods for ConcreteNode
where ConcreteNode: TNode<'ln> {
fn cascade_node_pseudo_element(&self,
layout_context: &SharedLayoutContext,
parent_style: Option<&Arc<ComputedValues>>,
@ -547,11 +548,11 @@ impl<'ln, ConcreteLayoutNode> PrivateMatchMethods for ConcreteLayoutNode
}
}
impl<'le, ConcreteLayoutElement> PrivateElementMatchMethods<'le, ConcreteLayoutElement>
for ConcreteLayoutElement
where ConcreteLayoutElement: LayoutElement<'le> {
impl<'le, ConcreteElement> PrivateElementMatchMethods<'le, ConcreteElement>
for ConcreteElement
where ConcreteElement: TElement<'le> {
fn share_style_with_candidate_if_possible(&self,
parent_node: Option<ConcreteLayoutElement::ConcreteLayoutNode>,
parent_node: Option<ConcreteElement::ConcreteNode>,
candidate: &StyleSharingCandidate)
-> Option<Arc<ComputedValues>> {
let parent_node = match parent_node {
@ -559,13 +560,13 @@ impl<'le, ConcreteLayoutElement> PrivateElementMatchMethods<'le, ConcreteLayoutE
Some(_) | None => return None,
};
let parent_layout_data: &Option<LayoutDataWrapper> = unsafe {
&*parent_node.borrow_layout_data_unchecked()
let parent_data: Option<&PrivateStyleData> = unsafe {
parent_node.borrow_data_unchecked().map(|d| &*d)
};
match *parent_layout_data {
Some(ref parent_layout_data_ref) => {
match parent_data {
Some(parent_data_ref) => {
// Check parent style.
let parent_style = parent_layout_data_ref.shared_data.style.as_ref().unwrap();
let parent_style = (*parent_data_ref).style.as_ref().unwrap();
if !arc_ptr_eq(parent_style, &candidate.parent_style) {
return None
}
@ -584,9 +585,9 @@ impl<'le, ConcreteLayoutElement> PrivateElementMatchMethods<'le, ConcreteLayoutE
}
}
impl<'le, ConcreteLayoutElement> ElementMatchMethods<'le, ConcreteLayoutElement>
for ConcreteLayoutElement
where ConcreteLayoutElement: LayoutElement<'le> {
impl<'le, ConcreteElement> ElementMatchMethods<'le, ConcreteElement>
for ConcreteElement
where ConcreteElement: TElement<'le> {
fn match_element(&self,
stylist: &Stylist,
parent_bf: Option<&BloomFilter>,
@ -619,7 +620,7 @@ impl<'le, ConcreteLayoutElement> ElementMatchMethods<'le, ConcreteLayoutElement>
unsafe fn share_style_if_possible(&self,
style_sharing_candidate_cache:
&mut StyleSharingCandidateCache,
parent: Option<ConcreteLayoutElement::ConcreteLayoutNode>)
parent: Option<ConcreteElement::ConcreteNode>)
-> StyleSharingResult {
if opts::get().disable_share_style_cache {
return StyleSharingResult::CannotShare
@ -637,9 +638,7 @@ impl<'le, ConcreteLayoutElement> ElementMatchMethods<'le, ConcreteLayoutElement>
Some(shared_style) => {
// Yay, cache hit. Share the style.
let node = self.as_node();
let mut layout_data_ref = node.mutate_layout_data();
let shared_data = &mut layout_data_ref.as_mut().unwrap().shared_data;
let style = &mut shared_data.style;
let style = &mut node.mutate_data().unwrap().style;
let damage = incremental::compute_damage(style, &*shared_style);
*style = Some(shared_style);
return StyleSharingResult::StyleWasShared(i, damage)
@ -652,9 +651,9 @@ impl<'le, ConcreteLayoutElement> ElementMatchMethods<'le, ConcreteLayoutElement>
}
}
impl<'ln, ConcreteLayoutNode> MatchMethods<'ln, ConcreteLayoutNode>
for ConcreteLayoutNode
where ConcreteLayoutNode: LayoutNode<'ln> {
impl<'ln, ConcreteNode> MatchMethods<'ln, ConcreteNode>
for ConcreteNode
where ConcreteNode: TNode<'ln> {
// The below two functions are copy+paste because I can't figure out how to
// write a function which takes a generic function. I don't think it can
// be done.
@ -696,7 +695,7 @@ impl<'ln, ConcreteLayoutNode> MatchMethods<'ln, ConcreteLayoutNode>
unsafe fn cascade_node(&self,
layout_context: &SharedLayoutContext,
parent: Option<ConcreteLayoutNode>,
parent: Option<ConcreteNode>,
applicable_declarations: &ApplicableDeclarations,
applicable_declarations_cache: &mut ApplicableDeclarationsCache,
new_animations_sender: &Mutex<Sender<Animation>>) {
@ -708,63 +707,57 @@ impl<'ln, ConcreteLayoutNode> MatchMethods<'ln, ConcreteLayoutNode>
let parent_style = match parent {
None => None,
Some(parent_node) => {
let parent_layout_data_ref = parent_node.borrow_layout_data_unchecked();
let parent_layout_data = (&*parent_layout_data_ref).as_ref()
.expect("no parent data!?");
let parent_style = parent_layout_data.shared_data
.style
.as_ref()
.expect("parent hasn't been styled yet!");
let parent_style = (*parent_node.borrow_data_unchecked().unwrap()).style.as_ref().unwrap();
Some(parent_style)
}
};
let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_ref {
None => panic!("no layout data"),
Some(ref mut layout_data) => {
if self.is_text_node() {
// Text nodes get a copy of the parent style. This ensures
// that during fragment construction any non-inherited
// CSS properties (such as vertical-align) are correctly
// set on the fragment(s).
let cloned_parent_style = parent_style.unwrap().clone();
layout_data.shared_data.style = Some(cloned_parent_style);
} else {
let mut damage = self.cascade_node_pseudo_element(
layout_context,
parent_style,
&applicable_declarations.normal,
&mut layout_data.shared_data.style,
applicable_declarations_cache,
new_animations_sender,
applicable_declarations.normal_shareable,
true);
if !applicable_declarations.before.is_empty() {
damage = damage | self.cascade_node_pseudo_element(
layout_context,
Some(layout_data.shared_data.style.as_ref().unwrap()),
&*applicable_declarations.before,
&mut layout_data.data.before_style,
applicable_declarations_cache,
new_animations_sender,
false,
false);
}
if !applicable_declarations.after.is_empty() {
damage = damage | self.cascade_node_pseudo_element(
layout_context,
Some(layout_data.shared_data.style.as_ref().unwrap()),
&*applicable_declarations.after,
&mut layout_data.data.after_style,
applicable_declarations_cache,
new_animations_sender,
false,
false);
}
layout_data.data.restyle_damage = damage;
}
let mut data_ref = self.mutate_data().unwrap();
let mut data = &mut *data_ref;
if self.is_text_node() {
// Text nodes get a copy of the parent style. This ensures
// that during fragment construction any non-inherited
// CSS properties (such as vertical-align) are correctly
// set on the fragment(s).
let cloned_parent_style = parent_style.unwrap().clone();
data.style = Some(cloned_parent_style);
} else {
let mut damage = self.cascade_node_pseudo_element(
layout_context,
parent_style,
&applicable_declarations.normal,
&mut data.style,
applicable_declarations_cache,
new_animations_sender,
applicable_declarations.normal_shareable,
true);
if !applicable_declarations.before.is_empty() {
damage = damage | self.cascade_node_pseudo_element(
layout_context,
Some(data.style.as_ref().unwrap()),
&*applicable_declarations.before,
&mut data.before_style,
applicable_declarations_cache,
new_animations_sender,
false,
false);
}
if !applicable_declarations.after.is_empty() {
damage = damage | self.cascade_node_pseudo_element(
layout_context,
Some(data.style.as_ref().unwrap()),
&*applicable_declarations.after,
&mut data.after_style,
applicable_declarations_cache,
new_animations_sender,
false,
false);
}
// FIXME(bholley): This is the only dependency in this file on non-style
// stuff.
let layout_data: &mut PrivateLayoutData = transmute(data);
layout_data.restyle_damage = damage;
}
}
}

Просмотреть файл

@ -4,18 +4,15 @@
use construct::ConstructionResult;
use incremental::RestyleDamage;
use parallel::DomParallelInfo;
use script::dom::node::SharedLayoutData;
use std::sync::Arc;
use style::properties::ComputedValues;
use style::data::PrivateStyleData;
/// Data that layout associates with a node.
pub struct PrivateLayoutData {
/// The results of CSS styling for this node's `before` pseudo-element, if any.
pub before_style: Option<Arc<ComputedValues>>,
/// The results of CSS styling for this node's `after` pseudo-element, if any.
pub after_style: Option<Arc<ComputedValues>>,
/// Data that the style system associates with a node. When the
/// style system is being used standalone, this is all that hangs
/// off the node. This must be first to permit the various
/// transmuations between PrivateStyleData PrivateLayoutData.
pub style_data: PrivateStyleData,
/// Description of how to account for recent style changes.
pub restyle_damage: RestyleDamage,
@ -28,9 +25,6 @@ pub struct PrivateLayoutData {
pub after_flow_construction_result: ConstructionResult,
/// Information needed during parallel traversals.
pub parallel: DomParallelInfo,
/// Various flags.
pub flags: LayoutDataFlags,
}
@ -39,13 +33,11 @@ impl PrivateLayoutData {
/// Creates new layout data.
pub fn new() -> PrivateLayoutData {
PrivateLayoutData {
before_style: None,
after_style: None,
style_data: PrivateStyleData::new(),
restyle_damage: RestyleDamage::empty(),
flow_construction_result: ConstructionResult::None,
before_flow_construction_result: ConstructionResult::None,
after_flow_construction_result: ConstructionResult::None,
parallel: DomParallelInfo::new(),
flags: LayoutDataFlags::empty(),
}
}
@ -57,16 +49,3 @@ bitflags! {
const HAS_NEWLY_CONSTRUCTED_FLOW = 0x01
}
}
pub struct LayoutDataWrapper {
pub shared_data: SharedLayoutData,
pub data: Box<PrivateLayoutData>,
}
#[allow(dead_code, unsafe_code)]
fn static_assertion(x: Option<LayoutDataWrapper>) {
unsafe {
let _: Option<::script::dom::node::LayoutData> =
::std::intrinsics::transmute(x);
}
}

Просмотреть файл

@ -47,6 +47,7 @@ bitflags! {
}
}
impl RestyleDamage {
/// Supposing a flow has the given `position` property and this damage, returns the damage that
/// we should add to the *parent* of this flow.

Просмотреть файл

@ -13,7 +13,6 @@ use azure::azure::AzColor;
use canvas_traits::CanvasMsg;
use construct::ConstructionResult;
use context::{SharedLayoutContext, StylistWrapper, heap_size_of_local_context};
use data::LayoutDataWrapper;
use display_list_builder::ToGfxColor;
use euclid::Matrix4;
use euclid::point::Point2D;
@ -45,7 +44,7 @@ use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
use profile_traits::time::{self, TimerMetadata, profile};
use query::{LayoutRPCImpl, process_content_box_request, process_content_boxes_request};
use query::{process_node_geometry_request, process_offset_parent_query, process_resolved_style_request};
use script::dom::node::LayoutData;
use script::dom::node::OpaqueStyleAndLayoutData;
use script::layout_interface::Animation;
use script::layout_interface::{LayoutRPC, OffsetParentResponse};
use script::layout_interface::{Msg, NewLayoutTaskInfo, Reflow, ReflowGoal, ReflowQueryType};
@ -65,6 +64,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::sync::{Arc, Mutex, MutexGuard, RwLock};
use style::computed_values::{filter, mix_blend_mode};
use style::dom::{TDocument, TElement, TNode};
use style::media_queries::{Device, MediaType};
use style::selector_matching::{Stylist, USER_OR_USER_AGENT_STYLESHEETS};
use style::stylesheets::{CSSRuleIteratorExt, Stylesheet};
@ -77,8 +77,7 @@ use util::opts;
use util::task;
use util::task_state;
use util::workqueue::WorkQueue;
use wrapper::{LayoutDocument, LayoutElement, LayoutNode};
use wrapper::{ServoLayoutNode, ThreadSafeLayoutNode};
use wrapper::{LayoutNode, NonOpaqueStyleAndLayoutData, ServoLayoutNode, ThreadSafeLayoutNode};
/// The number of screens of data we're allowed to generate display lists for in each direction.
pub const DISPLAY_PORT_SIZE_FACTOR: i32 = 8;
@ -607,9 +606,9 @@ impl LayoutTask {
Msg::SetVisibleRects(new_visible_rects) => {
self.set_visible_rects(new_visible_rects, possibly_locked_rw_data);
}
Msg::ReapLayoutData(dead_layout_data) => {
Msg::ReapStyleAndLayoutData(dead_data) => {
unsafe {
self.handle_reap_layout_data(dead_layout_data)
self.handle_reap_style_and_layout_data(dead_data)
}
}
Msg::CollectReports(reports_chan) => {
@ -707,9 +706,9 @@ impl LayoutTask {
response_chan.send(()).unwrap();
loop {
match self.port.recv().unwrap() {
Msg::ReapLayoutData(dead_layout_data) => {
Msg::ReapStyleAndLayoutData(dead_data) => {
unsafe {
self.handle_reap_layout_data(dead_layout_data)
self.handle_reap_style_and_layout_data(dead_data)
}
}
Msg::ExitNow => {
@ -765,14 +764,11 @@ impl LayoutTask {
}
fn try_get_layout_root<'ln, N: LayoutNode<'ln>>(&self, node: N) -> Option<FlowRef> {
let mut layout_data_ref = node.mutate_layout_data();
let layout_data =
match layout_data_ref.as_mut() {
None => return None,
Some(layout_data) => layout_data,
};
let result = layout_data.data.flow_construction_result.swap_out();
let mut data = match node.mutate_layout_data() {
Some(x) => x,
None => return None,
};
let result = data.flow_construction_result.swap_out();
let mut flow = match result {
ConstructionResult::Flow(mut flow, abs_descendants) => {
@ -1312,8 +1308,9 @@ impl LayoutTask {
/// Handles a message to destroy layout data. Layout data must be destroyed on *this* task
/// because the struct type is transmuted to a different type on the script side.
unsafe fn handle_reap_layout_data(&self, layout_data: LayoutData) {
let _: LayoutDataWrapper = transmute(layout_data);
unsafe fn handle_reap_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) {
let non_opaque: NonOpaqueStyleAndLayoutData = transmute(data.ptr);
let _ = Box::from_raw(non_opaque);
}
/// Returns profiling information which is passed to the time profiler.

Просмотреть файл

@ -2,11 +2,13 @@
* 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/. */
#![feature(as_unsafe_cell)]
#![feature(box_syntax)]
#![feature(cell_extras)]
#![feature(custom_derive)]
#![feature(hashmap_hasher)]
#![feature(mpsc_select)]
#![feature(nonzero)]
#![feature(plugin)]
#![feature(raw)]
#![feature(step_by)]
@ -22,6 +24,7 @@ extern crate azure;
#[macro_use]
extern crate bitflags;
extern crate canvas_traits;
extern crate core;
extern crate cssparser;
extern crate encoding;
extern crate euclid;

Просмотреть файл

@ -15,6 +15,7 @@ use gfx::display_list::OpaqueNode;
use profile_traits::time::{self, TimerMetadata, profile};
use std::mem;
use std::sync::atomic::{AtomicIsize, Ordering};
use style::dom::UnsafeNode;
use traversal::PostorderNodeMutTraversal;
use traversal::{AssignBSizesAndStoreOverflow, AssignISizes, BubbleISizes};
use traversal::{BuildDisplayList, ComputeAbsolutePositions};
@ -22,17 +23,17 @@ use traversal::{ConstructFlows, RecalcStyleForNode};
use traversal::{PostorderDomTraversal, PreorderDomTraversal};
use util::opts;
use util::workqueue::{WorkQueue, WorkUnit, WorkerProxy};
use wrapper::{LayoutNode, UnsafeLayoutNode};
use wrapper::LayoutNode;
const CHUNK_SIZE: usize = 64;
pub struct WorkQueueData(usize, usize);
#[allow(dead_code)]
fn static_assertion(node: UnsafeLayoutNode) {
fn static_assertion(node: UnsafeNode) {
unsafe {
let _: UnsafeFlow = ::std::intrinsics::transmute(node);
let _: UnsafeLayoutNodeList = ::std::intrinsics::transmute(node);
let _: UnsafeNodeList = ::std::intrinsics::transmute(node);
}
}
@ -55,31 +56,17 @@ pub fn borrowed_flow_to_unsafe_flow(flow: &Flow) -> UnsafeFlow {
}
}
/// Information that we need stored in each DOM node.
pub struct DomParallelInfo {
/// The number of children that still need work done.
pub children_count: AtomicIsize,
}
pub type UnsafeNodeList = (Box<Vec<UnsafeNode>>, OpaqueNode);
impl DomParallelInfo {
pub fn new() -> DomParallelInfo {
DomParallelInfo {
children_count: AtomicIsize::new(0),
}
}
}
pub type UnsafeLayoutNodeList = (Box<Vec<UnsafeLayoutNode>>, OpaqueNode);
pub type UnsafeFlowList = (Box<Vec<UnsafeLayoutNode>>, usize);
pub type UnsafeFlowList = (Box<Vec<UnsafeNode>>, usize);
pub type ChunkedDomTraversalFunction =
extern "Rust" fn(UnsafeLayoutNodeList,
&mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>);
extern "Rust" fn(UnsafeNodeList,
&mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>);
pub type DomTraversalFunction =
extern "Rust" fn(OpaqueNode, UnsafeLayoutNode,
&mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>);
extern "Rust" fn(OpaqueNode, UnsafeNode,
&mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>);
pub type ChunkedFlowTraversalFunction =
extern "Rust" fn(UnsafeFlowList, &mut WorkerProxy<SharedLayoutContext, UnsafeFlowList>);
@ -91,14 +78,14 @@ pub trait ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>
: PreorderDomTraversal<'ln, ConcreteLayoutNode>
where ConcreteLayoutNode: LayoutNode<'ln> {
fn run_parallel(&self,
nodes: UnsafeLayoutNodeList,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>);
nodes: UnsafeNodeList,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>);
#[inline(always)]
fn run_parallel_helper(
&self,
unsafe_nodes: UnsafeLayoutNodeList,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>,
unsafe_nodes: UnsafeNodeList,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>,
top_down_func: ChunkedDomTraversalFunction,
bottom_up_func: DomTraversalFunction) {
let mut discovered_child_nodes = Vec::new();
@ -113,10 +100,9 @@ pub trait ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>
// Reset the count of children.
{
let mut layout_data_ref = node.mutate_layout_data();
let layout_data = layout_data_ref.as_mut().expect("no layout data");
layout_data.data.parallel.children_count.store(child_count as isize,
Ordering::Relaxed);
let data = node.mutate_data().unwrap();
data.parallel.children_count.store(child_count as isize,
Ordering::Relaxed);
}
// Possibly enqueue the children.
@ -156,7 +142,7 @@ trait ParallelPostorderDomTraversal<'ln, ConcreteLayoutNode>
///
/// The only communication between siblings is that they both
/// fetch-and-subtract the parent's children count.
fn run_parallel(&self, unsafe_node: UnsafeLayoutNode) {
fn run_parallel(&self, unsafe_node: UnsafeNode) {
// Get a real layout node.
let mut node = unsafe { ConcreteLayoutNode::from_unsafe(&unsafe_node) };
loop {
@ -168,13 +154,11 @@ trait ParallelPostorderDomTraversal<'ln, ConcreteLayoutNode>
Some(parent) => parent,
};
let parent_layout_data = unsafe {
&*parent.borrow_layout_data_unchecked()
let parent_data = unsafe {
&*parent.borrow_data_unchecked().unwrap()
};
let parent_layout_data = parent_layout_data.as_ref().expect("no layout data");
if parent_layout_data
.data
if parent_data
.parallel
.children_count
.fetch_sub(1, Ordering::Relaxed) != 1 {
@ -360,8 +344,8 @@ impl<'a, 'ln, ConcreteLayoutNode> ParallelPreorderDomTraversal<'ln, ConcreteLayo
for RecalcStyleForNode<'a>
where ConcreteLayoutNode: LayoutNode<'ln> {
fn run_parallel(&self,
unsafe_nodes: UnsafeLayoutNodeList,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) {
unsafe_nodes: UnsafeNodeList,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>) {
// Not exactly sure why we need UFCS here, but we seem to.
<RecalcStyleForNode<'a> as ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>>
::run_parallel_helper(self, unsafe_nodes, proxy,
@ -370,8 +354,8 @@ impl<'a, 'ln, ConcreteLayoutNode> ParallelPreorderDomTraversal<'ln, ConcreteLayo
}
}
fn recalc_style<'ln, ConcreteLayoutNode>(unsafe_nodes: UnsafeLayoutNodeList,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>)
fn recalc_style<'ln, ConcreteLayoutNode>(unsafe_nodes: UnsafeNodeList,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>)
where ConcreteLayoutNode: LayoutNode<'ln> {
let shared_layout_context = proxy.user_data();
let layout_context = LayoutContext::new(shared_layout_context);
@ -388,8 +372,8 @@ fn recalc_style<'ln, ConcreteLayoutNode>(unsafe_nodes: UnsafeLayoutNodeList,
fn construct_flows<'ln, ConcreteLayoutNode: LayoutNode<'ln>>(
root: OpaqueNode,
unsafe_node: UnsafeLayoutNode,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) {
unsafe_node: UnsafeNode,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>) {
let shared_layout_context = proxy.user_data();
let layout_context = LayoutContext::new(shared_layout_context);
let construct_flows_traversal = ConstructFlows {

Просмотреть файл

@ -479,9 +479,9 @@ pub fn process_resolved_style_request<'ln, N: LayoutNode<'ln>>(
layout_root: &mut FlowRef,
requested_node: N,
property: &Atom) -> Option<String> {
let layout_data = layout_node.borrow_layout_data();
let position = layout_data.as_ref().map(|layout_data| {
match layout_data.data.flow_construction_result {
let maybe_data = layout_node.borrow_layout_data();
let position = maybe_data.map(|data| {
match (*data).flow_construction_result {
ConstructionResult::Flow(ref flow_ref, _) =>
flow::base(flow_ref.deref()).stacking_relative_position,
// TODO(dzbarsky) search parents until we find node with a flow ref.

Просмотреть файл

@ -15,10 +15,10 @@ use script::layout_interface::ReflowGoal;
use selectors::bloom::BloomFilter;
use std::cell::RefCell;
use std::mem;
use style::dom::UnsafeNode;
use util::opts;
use util::tid::tid;
use wrapper::{LayoutNode, UnsafeLayoutNode};
use wrapper::{ThreadSafeLayoutNode};
use wrapper::{LayoutNode, ThreadSafeLayoutNode};
/// Every time we do another layout, the old bloom filters are invalid. This is
/// detected by ticking a generation number every layout.
@ -45,7 +45,7 @@ type Generation = u32;
/// will no longer be the for the parent of the node we're currently on. When
/// this happens, the task local bloom filter will be thrown away and rebuilt.
thread_local!(
static STYLE_BLOOM: RefCell<Option<(Box<BloomFilter>, UnsafeLayoutNode, Generation)>> = RefCell::new(None));
static STYLE_BLOOM: RefCell<Option<(Box<BloomFilter>, UnsafeNode, Generation)>> = RefCell::new(None));
/// Returns the task local bloom filter.
///
@ -88,7 +88,7 @@ fn take_task_local_bloom_filter<'ln, N>(parent_node: Option<N>,
}
fn put_task_local_bloom_filter(bf: Box<BloomFilter>,
unsafe_node: &UnsafeLayoutNode,
unsafe_node: &UnsafeNode,
layout_context: &LayoutContext) {
STYLE_BLOOM.with(move |style_bloom| {
assert!(style_bloom.borrow().is_none(),
@ -153,7 +153,7 @@ impl<'a, 'ln, ConcreteLayoutNode> PreorderDomTraversal<'ln, ConcreteLayoutNode>
//
// FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML
// parser.
node.initialize_layout_data();
node.initialize_data();
// Get the parent node.
let parent_opt = node.layout_parent_node(self.root);

Просмотреть файл

@ -30,7 +30,8 @@
#![allow(unsafe_code)]
use data::{LayoutDataFlags, LayoutDataWrapper, PrivateLayoutData};
use core::nonzero::NonZero;
use data::{LayoutDataFlags, PrivateLayoutData};
use gfx::display_list::OpaqueNode;
use gfx::text::glyph::CharIndex;
use incremental::RestyleDamage;
@ -49,7 +50,7 @@ use script::dom::htmlimageelement::LayoutHTMLImageElementHelpers;
use script::dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
use script::dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
use script::dom::node::{HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY};
use script::dom::node::{LayoutNodeHelpers, Node, SharedLayoutData};
use script::dom::node::{LayoutNodeHelpers, Node, OpaqueStyleAndLayoutData};
use script::dom::text::Text;
use script::layout_interface::TrustedNodeAddress;
use selectors::matching::DeclarationBlock;
@ -57,204 +58,38 @@ use selectors::parser::{AttrSelector, NamespaceConstraint};
use selectors::states::*;
use smallvec::VecLike;
use std::borrow::ToOwned;
use std::cell::{Ref, RefMut};
use std::cell::{Ref, RefCell, RefMut};
use std::marker::PhantomData;
use std::mem;
use std::mem::{transmute, transmute_copy};
use std::sync::Arc;
use string_cache::{Atom, Namespace};
use style::computed_values::content::ContentItem;
use style::computed_values::{content, display};
use style::node::TElementAttributes;
use style::data::PrivateStyleData;
use style::dom::{TDocument, TElement, TNode, UnsafeNode};
use style::properties::ComputedValues;
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
use style::restyle_hints::{ElementSnapshot, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
use style::restyle_hints::ElementSnapshot;
use url::Url;
use util::str::{is_whitespace, search_index};
/// Opaque type stored in type-unsafe work queues for parallel layout.
/// Must be transmutable to and from LayoutNode.
pub type UnsafeLayoutNode = (usize, usize);
pub type NonOpaqueStyleAndLayoutData = *mut RefCell<PrivateLayoutData>;
/// A wrapper so that layout can access only the methods that it should have access to. Layout must
/// only ever see these and must never see instances of `LayoutJS`.
pub trait LayoutNode<'ln> : Sized + Copy + Clone {
pub trait LayoutNode<'ln> : TNode<'ln> {
type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln>;
type ConcreteLayoutElement: LayoutElement<'ln, ConcreteLayoutNode = Self,
ConcreteLayoutDocument = Self::ConcreteLayoutDocument>;
type ConcreteLayoutDocument: LayoutDocument<'ln, ConcreteLayoutNode = Self,
ConcreteLayoutElement = Self::ConcreteLayoutElement>;
fn to_unsafe(&self) -> UnsafeLayoutNode;
unsafe fn from_unsafe(&UnsafeLayoutNode) -> Self;
fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode;
/// Returns the type ID of this node.
fn type_id(&self) -> NodeTypeId;
/// Returns whether this is a text node. It turns out that this is all the style system cares
/// about, and thus obviates the need to compute the full type id, which would be expensive in
/// Gecko.
fn is_text_node(&self) -> bool;
fn is_element(&self) -> bool;
fn dump(self);
fn traverse_preorder(self) -> LayoutTreeIterator<'ln, Self> {
LayoutTreeIterator::new(self)
}
/// Returns an iterator over this node's children.
fn children(self) -> LayoutNodeChildrenIterator<'ln, Self> {
LayoutNodeChildrenIterator {
current: self.first_child(),
phantom: PhantomData,
}
}
fn rev_children(self) -> LayoutNodeReverseChildrenIterator<'ln, Self> {
LayoutNodeReverseChildrenIterator {
current: self.last_child(),
phantom: PhantomData,
}
}
/// Converts self into an `OpaqueNode`.
fn opaque(&self) -> OpaqueNode;
/// Resets layout data and styles for the node.
///
/// FIXME(pcwalton): Do this as part of fragment building instead of in a traversal.
fn initialize_layout_data(self);
/// While doing a reflow, the node at the root has no parent, as far as we're
/// concerned. This method returns `None` at the reflow root.
fn layout_parent_node(self, reflow_root: OpaqueNode) -> Option<Self>;
fn debug_id(self) -> usize;
fn as_element(&self) -> Option<Self::ConcreteLayoutElement>;
fn as_document(&self) -> Option<Self::ConcreteLayoutDocument>;
fn children_count(&self) -> u32;
fn has_changed(&self) -> bool;
unsafe fn set_changed(&self, value: bool);
fn is_dirty(&self) -> bool;
unsafe fn set_dirty(&self, value: bool);
fn has_dirty_descendants(&self) -> bool;
unsafe fn set_dirty_descendants(&self, value: bool);
fn dirty_self(&self) {
unsafe {
self.set_dirty(true);
self.set_dirty_descendants(true);
}
}
fn dirty_descendants(&self) {
for ref child in self.children() {
child.dirty_self();
child.dirty_descendants();
}
}
/// Borrows the layout data without checks.
#[inline(always)]
unsafe fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper>;
/// Borrows the layout data immutably. Fails on a conflicting borrow.
#[inline(always)]
fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>>;
/// Borrows the layout data mutably. Fails on a conflicting borrow.
#[inline(always)]
fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>>;
fn parent_node(&self) -> Option<Self>;
fn first_child(&self) -> Option<Self>;
fn last_child(&self) -> Option<Self>;
fn prev_sibling(&self) -> Option<Self>;
fn next_sibling(&self) -> Option<Self>;
}
pub trait LayoutDocument<'ld> : Sized + Copy + Clone {
type ConcreteLayoutNode: LayoutNode<'ld, ConcreteLayoutElement = Self::ConcreteLayoutElement,
ConcreteLayoutDocument = Self>;
type ConcreteLayoutElement: LayoutElement<'ld, ConcreteLayoutNode = Self::ConcreteLayoutNode,
ConcreteLayoutDocument = Self>;
fn as_node(&self) -> Self::ConcreteLayoutNode;
fn root_node(&self) -> Option<Self::ConcreteLayoutNode>;
fn drain_modified_elements(&self) -> Vec<(Self::ConcreteLayoutElement, ElementSnapshot)>;
}
pub trait LayoutElement<'le> : Sized + Copy + Clone + ::selectors::Element + TElementAttributes {
type ConcreteLayoutNode: LayoutNode<'le, ConcreteLayoutElement = Self,
ConcreteLayoutDocument = Self::ConcreteLayoutDocument>;
type ConcreteLayoutDocument: LayoutDocument<'le, ConcreteLayoutNode = Self::ConcreteLayoutNode,
ConcreteLayoutElement = Self>;
fn as_node(&self) -> Self::ConcreteLayoutNode;
fn style_attribute(&self) -> &'le Option<PropertyDeclarationBlock>;
fn get_state(&self) -> ElementState;
/// Properly marks nodes as dirty in response to restyle hints.
fn note_restyle_hint(&self, mut hint: RestyleHint) {
// Bail early if there's no restyling to do.
if hint.is_empty() {
return;
}
// If the restyle hint is non-empty, we need to restyle either this element
// or one of its siblings. Mark our ancestor chain as having dirty descendants.
let node = self.as_node();
let mut curr = node;
while let Some(parent) = curr.parent_node() {
if parent.has_dirty_descendants() { break }
unsafe { parent.set_dirty_descendants(true); }
curr = parent;
}
// Process hints.
if hint.contains(RESTYLE_SELF) {
node.dirty_self();
// FIXME(bholley, #8438): We currently need to RESTYLE_DESCENDANTS in the
// RESTYLE_SELF case in order to make sure "inherit" style structs propagate
// properly. See the explanation in the github issue.
hint.insert(RESTYLE_DESCENDANTS);
}
if hint.contains(RESTYLE_DESCENDANTS) {
unsafe { node.set_dirty_descendants(true); }
node.dirty_descendants();
}
if hint.contains(RESTYLE_LATER_SIBLINGS) {
let mut next = ::selectors::Element::next_sibling_element(self);
while let Some(sib) = next {
let sib_node = sib.as_node();
sib_node.dirty_self();
sib_node.dirty_descendants();
next = ::selectors::Element::next_sibling_element(&sib);
}
}
}
/// Similar to borrow_data*, but returns the full PrivateLayoutData rather
/// than only the PrivateStyleData.
unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData>;
fn borrow_layout_data(&self) -> Option<Ref<PrivateLayoutData>>;
fn mutate_layout_data(&self) -> Option<RefMut<PrivateLayoutData>>;
}
#[derive(Copy, Clone)]
@ -294,31 +129,20 @@ impl<'ln> ServoLayoutNode<'ln> {
}
}
impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'ln>;
type ConcreteLayoutElement = ServoLayoutElement<'ln>;
type ConcreteLayoutDocument = ServoLayoutDocument<'ln>;
impl<'ln> TNode<'ln> for ServoLayoutNode<'ln> {
type ConcreteElement = ServoLayoutElement<'ln>;
type ConcreteDocument = ServoLayoutDocument<'ln>;
fn to_unsafe(&self) -> UnsafeLayoutNode {
fn to_unsafe(&self) -> UnsafeNode {
unsafe {
let ptr: usize = mem::transmute_copy(self);
let ptr: usize = transmute_copy(self);
(ptr, 0)
}
}
unsafe fn from_unsafe(n: &UnsafeLayoutNode) -> Self {
unsafe fn from_unsafe(n: &UnsafeNode) -> Self {
let (node, _) = *n;
mem::transmute(node)
}
fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode {
ServoThreadSafeLayoutNode::new(self)
}
fn type_id(&self) -> NodeTypeId {
unsafe {
self.node.type_id_for_layout()
}
transmute(node)
}
fn is_text_node(&self) -> bool {
@ -339,16 +163,17 @@ impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
OpaqueNodeMethods::from_jsmanaged(unsafe { self.get_jsmanaged() })
}
fn initialize_layout_data(self) {
let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_ref {
None => {
*layout_data_ref = Some(LayoutDataWrapper {
shared_data: SharedLayoutData { style: None },
data: box PrivateLayoutData::new(),
});
fn initialize_data(self) {
let has_data = unsafe { self.borrow_data_unchecked().is_some() };
if !has_data {
let ptr: NonOpaqueStyleAndLayoutData =
Box::into_raw(box RefCell::new(PrivateLayoutData::new()));
let opaque = OpaqueStyleAndLayoutData {
ptr: unsafe { NonZero::new(ptr as *mut ()) }
};
unsafe {
self.node.init_style_and_layout_data(opaque);
}
Some(_) => {}
}
}
@ -400,20 +225,16 @@ impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
self.node.set_flag(HAS_DIRTY_DESCENDANTS, value)
}
unsafe fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper> {
mem::transmute(self.get_jsmanaged().layout_data_unchecked())
unsafe fn borrow_data_unchecked(&self) -> Option<*const PrivateStyleData> {
self.borrow_layout_data_unchecked().map(|d| &(*d).style_data as *const PrivateStyleData)
}
fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>> {
unsafe {
mem::transmute(self.get_jsmanaged().layout_data())
}
fn borrow_data(&self) -> Option<Ref<PrivateStyleData>> {
unsafe { self.borrow_layout_data().map(|d| transmute(d)) }
}
fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>> {
unsafe {
mem::transmute(self.get_jsmanaged().layout_data_mut())
}
fn mutate_data(&self) -> Option<RefMut<PrivateStyleData>> {
unsafe { self.mutate_layout_data().map(|d| transmute(d)) }
}
fn parent_node(&self) -> Option<ServoLayoutNode<'ln>> {
@ -447,6 +268,46 @@ impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
}
}
impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'ln>;
fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode {
ServoThreadSafeLayoutNode::new(self)
}
fn type_id(&self) -> NodeTypeId {
unsafe {
self.node.type_id_for_layout()
}
}
unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData> {
self.get_jsmanaged().get_style_and_layout_data().map(|opaque| {
let container: NonOpaqueStyleAndLayoutData = transmute(opaque.ptr);
&(*(*container).as_unsafe_cell().get()) as *const PrivateLayoutData
})
}
fn borrow_layout_data(&self) -> Option<Ref<PrivateLayoutData>> {
unsafe {
self.get_jsmanaged().get_style_and_layout_data().map(|opaque| {
let container: NonOpaqueStyleAndLayoutData = transmute(opaque.ptr);
(*container).borrow()
})
}
}
fn mutate_layout_data(&self) -> Option<RefMut<PrivateLayoutData>> {
unsafe {
self.get_jsmanaged().get_style_and_layout_data().map(|opaque| {
let container: NonOpaqueStyleAndLayoutData = transmute(opaque.ptr);
(*container).borrow_mut()
})
}
}
}
impl<'ln> ServoLayoutNode<'ln> {
fn dump_indent(self, indent: u32) {
let mut s = String::new();
@ -468,11 +329,7 @@ impl<'ln> ServoLayoutNode<'ln> {
}
pub fn flow_debug_id(self) -> usize {
let layout_data_ref = self.borrow_layout_data();
match *layout_data_ref {
None => 0,
Some(ref layout_data) => layout_data.data.flow_construction_result.debug_id()
}
self.borrow_layout_data().map_or(0, |d| d.flow_construction_result.debug_id())
}
/// Returns the interior of this node as a `LayoutJS`. This is highly unsafe for layout to
@ -482,65 +339,6 @@ impl<'ln> ServoLayoutNode<'ln> {
}
}
pub struct LayoutNodeChildrenIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> {
current: Option<ConcreteLayoutNode>,
// Satisfy the compiler about the unused lifetime.
phantom: PhantomData<&'a ()>,
}
impl<'a, ConcreteLayoutNode> Iterator for LayoutNodeChildrenIterator<'a, ConcreteLayoutNode>
where ConcreteLayoutNode: LayoutNode<'a> {
type Item = ConcreteLayoutNode;
fn next(&mut self) -> Option<ConcreteLayoutNode> {
let node = self.current;
self.current = node.and_then(|node| node.next_sibling());
node
}
}
pub struct LayoutNodeReverseChildrenIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> {
current: Option<ConcreteLayoutNode>,
// Satisfy the compiler about the unused lifetime.
phantom: PhantomData<&'a ()>,
}
impl<'a, ConcreteLayoutNode> Iterator for LayoutNodeReverseChildrenIterator<'a, ConcreteLayoutNode>
where ConcreteLayoutNode: LayoutNode<'a> {
type Item = ConcreteLayoutNode;
fn next(&mut self) -> Option<ConcreteLayoutNode> {
let node = self.current;
self.current = node.and_then(|node| node.prev_sibling());
node
}
}
pub struct LayoutTreeIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> {
stack: Vec<ConcreteLayoutNode>,
// Satisfy the compiler about the unused lifetime.
phantom: PhantomData<&'a ()>,
}
impl<'a, ConcreteLayoutNode> LayoutTreeIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> {
fn new(root: ConcreteLayoutNode) -> LayoutTreeIterator<'a, ConcreteLayoutNode> {
let mut stack = vec!();
stack.push(root);
LayoutTreeIterator {
stack: stack,
phantom: PhantomData,
}
}
}
impl<'a, ConcreteLayoutNode> Iterator for LayoutTreeIterator<'a, ConcreteLayoutNode>
where ConcreteLayoutNode: LayoutNode<'a> {
type Item = ConcreteLayoutNode;
fn next(&mut self) -> Option<ConcreteLayoutNode> {
let ret = self.stack.pop();
ret.map(|node| self.stack.extend(node.rev_children()));
ret
}
}
// A wrapper around documents that ensures ayout can only ever access safe properties.
#[derive(Copy, Clone)]
pub struct ServoLayoutDocument<'ld> {
@ -548,9 +346,9 @@ pub struct ServoLayoutDocument<'ld> {
chain: PhantomData<&'ld ()>,
}
impl<'ld> LayoutDocument<'ld> for ServoLayoutDocument<'ld> {
type ConcreteLayoutNode = ServoLayoutNode<'ld>;
type ConcreteLayoutElement = ServoLayoutElement<'ld>;
impl<'ld> TDocument<'ld> for ServoLayoutDocument<'ld> {
type ConcreteNode = ServoLayoutNode<'ld>;
type ConcreteElement = ServoLayoutElement<'ld>;
fn as_node(&self) -> ServoLayoutNode<'ld> {
ServoLayoutNode::from_layout_js(self.document.upcast())
@ -582,9 +380,9 @@ pub struct ServoLayoutElement<'le> {
chain: PhantomData<&'le ()>,
}
impl<'le> LayoutElement<'le> for ServoLayoutElement<'le> {
type ConcreteLayoutNode = ServoLayoutNode<'le>;
type ConcreteLayoutDocument = ServoLayoutDocument<'le>;
impl<'le> TElement<'le> for ServoLayoutElement<'le> {
type ConcreteNode = ServoLayoutNode<'le>;
type ConcreteDocument = ServoLayoutDocument<'le>;
fn as_node(&self) -> ServoLayoutNode<'le> {
ServoLayoutNode::from_layout_js(self.element.upcast())
@ -599,6 +397,28 @@ impl<'le> LayoutElement<'le> for ServoLayoutElement<'le> {
fn get_state(&self) -> ElementState {
self.element.get_state_for_layout()
}
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>
{
unsafe {
self.element.synthesize_presentational_hints_for_legacy_attributes(hints);
}
}
#[inline]
fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str> {
unsafe {
(*self.element.unsafe_get()).get_attr_val_for_layout(namespace, name)
}
}
#[inline]
fn get_attrs<'a>(&'a self, name: &Atom) -> Vec<&'a str> {
unsafe {
(*self.element.unsafe_get()).get_attr_vals_for_layout(name)
}
}
}
@ -783,30 +603,6 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
}
}
impl<'le> TElementAttributes for ServoLayoutElement<'le> {
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>
{
unsafe {
self.element.synthesize_presentational_hints_for_legacy_attributes(hints);
}
}
#[inline]
fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str> {
unsafe {
(*self.element.unsafe_get()).get_attr_val_for_layout(namespace, name)
}
}
#[inline]
fn get_attrs<'a>(&'a self, name: &Atom) -> Vec<&'a str> {
unsafe {
(*self.element.unsafe_get()).get_attr_vals_for_layout(name)
}
}
}
#[derive(Copy, PartialEq, Clone)]
pub enum PseudoElementType<T> {
Normal,
@ -865,18 +661,14 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
#[inline]
fn get_before_pseudo(&self) -> Option<Self> {
let layout_data_ref = self.borrow_layout_data();
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
node_layout_data_wrapper.data.before_style.as_ref().map(|style| {
self.borrow_layout_data().unwrap().style_data.before_style.as_ref().map(|style| {
self.with_pseudo(PseudoElementType::Before(style.get_box().display))
})
}
#[inline]
fn get_after_pseudo(&self) -> Option<Self> {
let layout_data_ref = self.borrow_layout_data();
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
node_layout_data_wrapper.data.after_style.as_ref().map(|style| {
self.borrow_layout_data().unwrap().style_data.after_style.as_ref().map(|style| {
self.with_pseudo(PseudoElementType::After(style.get_box().display))
})
}
@ -885,24 +677,23 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
///
/// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases.
#[inline(always)]
fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>>;
fn borrow_layout_data(&self) -> Option<Ref<PrivateLayoutData>>;
/// Borrows the layout data mutably. Fails on a conflicting borrow.
///
/// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases.
#[inline(always)]
fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>>;
fn mutate_layout_data(&self) -> Option<RefMut<PrivateLayoutData>>;
/// Returns the style results for the given node. If CSS selector matching
/// has not yet been performed, fails.
#[inline]
fn style(&self) -> Ref<Arc<ComputedValues>> {
Ref::map(self.borrow_layout_data(), |layout_data_ref| {
let layout_data = layout_data_ref.as_ref().expect("no layout data");
Ref::map(self.borrow_layout_data().unwrap(), |data| {
let style = match self.get_pseudo_element_type() {
PseudoElementType::Before(_) => &layout_data.data.before_style,
PseudoElementType::After(_) => &layout_data.data.after_style,
PseudoElementType::Normal => &layout_data.shared_data.style,
PseudoElementType::Before(_) => &data.style_data.before_style,
PseudoElementType::After(_) => &data.style_data.after_style,
PseudoElementType::Normal => &data.style_data.style,
};
style.as_ref().unwrap()
})
@ -910,14 +701,12 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
/// Removes the style from this node.
fn unstyle(self) {
let mut layout_data_ref = self.mutate_layout_data();
let layout_data = layout_data_ref.as_mut().expect("no layout data");
let mut data = self.mutate_layout_data().unwrap();
let style =
match self.get_pseudo_element_type() {
PseudoElementType::Before(_) => &mut layout_data.data.before_style,
PseudoElementType::After (_) => &mut layout_data.data.after_style,
PseudoElementType::Normal => &mut layout_data.shared_data.style,
PseudoElementType::Before(_) => &mut data.style_data.before_style,
PseudoElementType::After (_) => &mut data.style_data.after_style,
PseudoElementType::Normal => &mut data.style_data.style,
};
*style = None;
@ -928,17 +717,12 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
/// Get the description of how to account for recent style changes.
/// This is a simple bitfield and fine to copy by value.
fn restyle_damage(self) -> RestyleDamage {
let layout_data_ref = self.borrow_layout_data();
layout_data_ref.as_ref().unwrap().data.restyle_damage
self.borrow_layout_data().unwrap().restyle_damage
}
/// Set the restyle damage field.
fn set_restyle_damage(self, damage: RestyleDamage) {
let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_ref {
Some(ref mut layout_data) => layout_data.data.restyle_damage = damage,
_ => panic!("no layout data for this node"),
}
self.mutate_layout_data().unwrap().restyle_damage = damage;
}
/// Returns the layout data flags for this node.
@ -946,20 +730,12 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
/// Adds the given flags to this node.
fn insert_flags(self, new_flags: LayoutDataFlags) {
let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_ref {
Some(ref mut layout_data) => layout_data.data.flags.insert(new_flags),
_ => panic!("no layout data for this node"),
}
self.mutate_layout_data().unwrap().flags.insert(new_flags);
}
/// Removes the given flags from this node.
fn remove_flags(self, flags: LayoutDataFlags) {
let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_ref {
Some(ref mut layout_data) => layout_data.data.flags.remove(flags),
_ => panic!("no layout data for this node"),
}
self.mutate_layout_data().unwrap().flags.remove(flags);
}
/// Returns true if this node contributes content. This is used in the implementation of
@ -1049,14 +825,6 @@ impl<'ln> ServoThreadSafeLayoutNode<'ln> {
unsafe fn get_jsmanaged(&self) -> &LayoutJS<Node> {
self.node.get_jsmanaged()
}
/// Borrows the layout data without checking.
#[inline(always)]
fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper> {
unsafe {
self.node.borrow_layout_data_unchecked()
}
}
}
impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> {
@ -1112,11 +880,11 @@ impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> {
self.pseudo
}
fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>> {
fn borrow_layout_data(&self) -> Option<Ref<PrivateLayoutData>> {
self.node.borrow_layout_data()
}
fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>> {
fn mutate_layout_data(&self) -> Option<RefMut<PrivateLayoutData>> {
self.node.mutate_layout_data()
}
@ -1143,17 +911,13 @@ impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> {
fn flags(self) -> LayoutDataFlags {
unsafe {
match *self.borrow_layout_data_unchecked() {
None => panic!(),
Some(ref layout_data) => layout_data.data.flags,
}
(*self.node.borrow_layout_data_unchecked().unwrap()).flags
}
}
fn text_content(&self) -> TextContent {
if self.pseudo != PseudoElementType::Normal {
let layout_data_ref = self.borrow_layout_data();
let data = &layout_data_ref.as_ref().unwrap().data;
let data = &self.borrow_layout_data().unwrap().style_data;
let style = if self.pseudo.is_before() {
&data.before_style

Просмотреть файл

@ -57,14 +57,12 @@ use selectors::matching::matches;
use selectors::parser::Selector;
use selectors::parser::parse_author_origin_selector_list_from_str;
use std::borrow::ToOwned;
use std::cell::{Cell, Ref, RefCell, RefMut};
use std::cell::Cell;
use std::cmp::max;
use std::default::Default;
use std::iter::{self, FilterMap, Peekable};
use std::mem;
use std::sync::Arc;
use string_cache::{Atom, Namespace, QualName};
use style::properties::ComputedValues;
use util::str::DOMString;
use util::task_state;
use uuid::Uuid;
@ -115,11 +113,11 @@ pub struct Node {
/// are this node.
ranges: WeakRangeVec,
/// Layout information. Only the layout task may touch this data.
/// Style+Layout information. Only the layout task may touch this data.
///
/// Must be sent back to the layout task to be destroyed when this
/// node is finalized.
layout_data: LayoutDataRef,
style_and_layout_data: Cell<Option<OpaqueStyleAndLayoutData>>,
unique_id: DOMRefCell<Option<Box<Uuid>>>,
}
@ -164,7 +162,7 @@ impl NodeFlags {
impl Drop for Node {
#[allow(unsafe_code)]
fn drop(&mut self) {
self.layout_data.dispose(self);
self.style_and_layout_data.get().map(|d| d.dispose(self));
}
}
@ -177,74 +175,27 @@ enum SuppressObserver {
Unsuppressed
}
/// Layout data that is shared between the script and layout tasks.
#[derive(HeapSizeOf)]
pub struct SharedLayoutData {
/// The results of CSS styling for this node.
pub style: Option<Arc<ComputedValues>>,
}
/// Encapsulates the abstract layout data.
#[derive(HeapSizeOf)]
pub struct LayoutData {
_shared_data: SharedLayoutData,
#[ignore_heap_size_of = "TODO(#6910) Box value that should be counted but the type lives in layout"]
_data: NonZero<*const ()>,
#[derive(Copy, Clone, HeapSizeOf)]
pub struct OpaqueStyleAndLayoutData {
#[ignore_heap_size_of = "TODO(#6910) Box value that should be counted but \
the type lives in layout"]
pub ptr: NonZero<*mut ()>
}
#[allow(unsafe_code)]
unsafe impl Send for LayoutData {}
unsafe impl Send for OpaqueStyleAndLayoutData {}
#[derive(HeapSizeOf)]
pub struct LayoutDataRef {
data_cell: RefCell<Option<LayoutData>>,
}
no_jsmanaged_fields!(OpaqueStyleAndLayoutData);
no_jsmanaged_fields!(LayoutDataRef);
impl LayoutDataRef {
pub fn new() -> LayoutDataRef {
LayoutDataRef {
data_cell: RefCell::new(None),
}
}
/// Sends layout data, if any, back to the layout task to be destroyed.
pub fn dispose(&self, node: &Node) {
impl OpaqueStyleAndLayoutData {
/// Sends the style and layout data, if any, back to the layout task to be destroyed.
pub fn dispose(self, node: &Node) {
debug_assert!(task_state::get().is_script());
if let Some(layout_data) = mem::replace(&mut *self.data_cell.borrow_mut(), None) {
let win = window_from_node(node);
let LayoutChan(chan) = win.layout_chan();
chan.send(Msg::ReapLayoutData(layout_data)).unwrap()
}
}
/// Borrows the layout data immutably, *assuming that there are no mutators*. Bad things will
/// happen if you try to mutate the layout data while this is held. This is the only thread-
/// safe layout data accessor.
#[inline]
#[allow(unsafe_code)]
pub unsafe fn borrow_unchecked(&self) -> *const Option<LayoutData> {
debug_assert!(task_state::get().is_layout());
self.data_cell.as_unsafe_cell().get() as *const _
}
/// Borrows the layout data immutably. This function is *not* thread-safe.
#[inline]
pub fn borrow(&self) -> Ref<Option<LayoutData>> {
debug_assert!(task_state::get().is_layout());
self.data_cell.borrow()
}
/// Borrows the layout data mutably. This function is *not* thread-safe.
///
/// FIXME(pcwalton): We should really put this behind a `MutLayoutView` phantom type, to
/// prevent CSS selector matching from mutably accessing nodes it's not supposed to and racing
/// on it. This has already resulted in one bug!
#[inline]
pub fn borrow_mut(&self) -> RefMut<Option<LayoutData>> {
debug_assert!(task_state::get().is_layout());
self.data_cell.borrow_mut()
let win = window_from_node(node);
let LayoutChan(chan) = win.layout_chan();
node.style_and_layout_data.set(None);
chan.send(Msg::ReapStyleAndLayoutData(self)).unwrap();
}
}
@ -334,7 +285,7 @@ impl Node {
for node in child.traverse_preorder() {
node.set_flag(IS_IN_DOC, false);
vtable_for(&&*node).unbind_from_tree(&context);
node.layout_data.dispose(&node);
node.style_and_layout_data.get().map(|d| d.dispose(&node));
}
self.owner_doc().content_and_heritage_changed(self, NodeDamage::OtherNodeDamage);
@ -378,7 +329,7 @@ impl<'a> Iterator for QuerySelectorIterator {
impl Node {
pub fn teardown(&self) {
self.layout_data.dispose(self);
self.style_and_layout_data.get().map(|d| d.dispose(self));
for kid in self.children() {
kid.teardown();
}
@ -966,9 +917,8 @@ pub trait LayoutNodeHelpers {
unsafe fn children_count(&self) -> u32;
unsafe fn layout_data(&self) -> Ref<Option<LayoutData>>;
unsafe fn layout_data_mut(&self) -> RefMut<Option<LayoutData>>;
unsafe fn layout_data_unchecked(&self) -> *const Option<LayoutData>;
unsafe fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>;
unsafe fn init_style_and_layout_data(&self, OpaqueStyleAndLayoutData);
}
impl LayoutNodeHelpers for LayoutJS<Node> {
@ -1049,20 +999,15 @@ impl LayoutNodeHelpers for LayoutJS<Node> {
#[inline]
#[allow(unsafe_code)]
unsafe fn layout_data(&self) -> Ref<Option<LayoutData>> {
(*self.unsafe_get()).layout_data.borrow()
unsafe fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
(*self.unsafe_get()).style_and_layout_data.get()
}
#[inline]
#[allow(unsafe_code)]
unsafe fn layout_data_mut(&self) -> RefMut<Option<LayoutData>> {
(*self.unsafe_get()).layout_data.borrow_mut()
}
#[inline]
#[allow(unsafe_code)]
unsafe fn layout_data_unchecked(&self) -> *const Option<LayoutData> {
(*self.unsafe_get()).layout_data.borrow_unchecked()
unsafe fn init_style_and_layout_data(&self, val: OpaqueStyleAndLayoutData) {
debug_assert!((*self.unsafe_get()).style_and_layout_data.get().is_none());
(*self.unsafe_get()).style_and_layout_data.set(Some(val));
}
}
@ -1322,7 +1267,7 @@ impl Node {
inclusive_descendants_version: Cell::new(0),
ranges: WeakRangeVec::new(),
layout_data: LayoutDataRef::new(),
style_and_layout_data: Cell::new(None),
unique_id: DOMRefCell::new(None),
}

Просмотреть файл

@ -7,7 +7,7 @@
//! the DOM to be placed in a separate crate from layout.
use app_units::Au;
use dom::node::LayoutData;
use dom::node::OpaqueStyleAndLayoutData;
use euclid::point::Point2D;
use euclid::rect::Rect;
use gfx_traits::LayerId;
@ -59,7 +59,7 @@ pub enum Msg {
/// Destroys layout data associated with a DOM node.
///
/// TODO(pcwalton): Maybe think about batching to avoid message traffic.
ReapLayoutData(LayoutData),
ReapStyleAndLayoutData(OpaqueStyleAndLayoutData),
/// Requests that the layout task measure its memory usage. The resulting reports are sent back
/// via the supplied channel.

Просмотреть файл

@ -0,0 +1,48 @@
/* 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 properties::ComputedValues;
use std::sync::Arc;
use std::sync::atomic::AtomicIsize;
pub struct PrivateStyleData {
/// The results of CSS styling for this node.
pub style: Option<Arc<ComputedValues>>,
/// The results of CSS styling for this node's `before` pseudo-element, if any.
pub before_style: Option<Arc<ComputedValues>>,
/// The results of CSS styling for this node's `after` pseudo-element, if any.
pub after_style: Option<Arc<ComputedValues>>,
/// Information needed during parallel traversals.
pub parallel: DomParallelInfo,
}
impl PrivateStyleData {
pub fn new() -> PrivateStyleData {
PrivateStyleData {
style: None,
before_style: None,
after_style: None,
parallel: DomParallelInfo::new(),
}
}
}
/// Information that we need stored in each DOM node.
#[derive(HeapSizeOf)]
pub struct DomParallelInfo {
/// The number of children that still need work done.
pub children_count: AtomicIsize,
}
impl DomParallelInfo {
pub fn new() -> DomParallelInfo {
DomParallelInfo {
children_count: AtomicIsize::new(0),
}
}
}

Просмотреть файл

@ -0,0 +1,274 @@
/* 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/. */
#![allow(unsafe_code)]
use data::PrivateStyleData;
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
use restyle_hints::{ElementSnapshot, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
use selectors::matching::DeclarationBlock;
use selectors::states::ElementState;
use smallvec::VecLike;
use std::cell::{Ref, RefMut};
use std::marker::PhantomData;
use string_cache::{Atom, Namespace};
/// Opaque type stored in type-unsafe work queues for parallel layout.
/// Must be transmutable to and from TNode.
pub type UnsafeNode = (usize, usize);
/// An opaque handle to a node, which, unlike UnsafeNode, cannot be transformed
/// back into a non-opaque representation. The only safe operation that can be
/// performed on this node is to compare it to another opaque handle or to another
/// OpaqueNode.
///
/// Layout and Graphics use this to safely represent nodes for comparison purposes.
/// Because the script task's GC does not trace layout, node data cannot be safely stored in layout
/// data structures. Also, layout code tends to be faster when the DOM is not being accessed, for
/// locality reasons. Using `OpaqueNode` enforces this invariant.
#[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf, Hash, Eq, Deserialize, Serialize)]
pub struct OpaqueNode(pub usize);
impl OpaqueNode {
/// Returns the address of this node, for debugging purposes.
#[inline]
pub fn id(&self) -> usize {
let OpaqueNode(pointer) = *self;
pointer
}
}
pub trait TNode<'ln> : Sized + Copy + Clone {
type ConcreteElement: TElement<'ln, ConcreteNode = Self, ConcreteDocument = Self::ConcreteDocument>;
type ConcreteDocument: TDocument<'ln, ConcreteNode = Self, ConcreteElement = Self::ConcreteElement>;
fn to_unsafe(&self) -> UnsafeNode;
unsafe fn from_unsafe(n: &UnsafeNode) -> Self;
/// Returns whether this is a text node. It turns out that this is all the style system cares
/// about, and thus obviates the need to compute the full type id, which would be expensive in
/// Gecko.
fn is_text_node(&self) -> bool;
fn is_element(&self) -> bool;
fn dump(self);
fn traverse_preorder(self) -> TreeIterator<'ln, Self> {
TreeIterator::new(self)
}
/// Returns an iterator over this node's children.
fn children(self) -> ChildrenIterator<'ln, Self> {
ChildrenIterator {
current: self.first_child(),
phantom: PhantomData,
}
}
fn rev_children(self) -> ReverseChildrenIterator<'ln, Self> {
ReverseChildrenIterator {
current: self.last_child(),
phantom: PhantomData,
}
}
/// Converts self into an `OpaqueNode`.
fn opaque(&self) -> OpaqueNode;
/// Initializes style and layout data for the node. No-op if the data is already
/// initialized.
///
/// FIXME(pcwalton): Do this as part of fragment building instead of in a traversal.
fn initialize_data(self);
/// While doing a reflow, the node at the root has no parent, as far as we're
/// concerned. This method returns `None` at the reflow root.
fn layout_parent_node(self, reflow_root: OpaqueNode) -> Option<Self>;
fn debug_id(self) -> usize;
fn as_element(&self) -> Option<Self::ConcreteElement>;
fn as_document(&self) -> Option<Self::ConcreteDocument>;
fn children_count(&self) -> u32;
fn has_changed(&self) -> bool;
unsafe fn set_changed(&self, value: bool);
fn is_dirty(&self) -> bool;
unsafe fn set_dirty(&self, value: bool);
fn has_dirty_descendants(&self) -> bool;
unsafe fn set_dirty_descendants(&self, value: bool);
fn dirty_self(&self) {
unsafe {
self.set_dirty(true);
self.set_dirty_descendants(true);
}
}
fn dirty_descendants(&self) {
for ref child in self.children() {
child.dirty_self();
child.dirty_descendants();
}
}
/// Borrows the PrivateStyleData without checks.
#[inline(always)]
unsafe fn borrow_data_unchecked(&self) -> Option<*const PrivateStyleData>;
/// Borrows the PrivateStyleData immutably. Fails on a conflicting borrow.
#[inline(always)]
fn borrow_data(&self) -> Option<Ref<PrivateStyleData>>;
/// Borrows the PrivateStyleData mutably. Fails on a conflicting borrow.
#[inline(always)]
fn mutate_data(&self) -> Option<RefMut<PrivateStyleData>>;
fn parent_node(&self) -> Option<Self>;
fn first_child(&self) -> Option<Self>;
fn last_child(&self) -> Option<Self>;
fn prev_sibling(&self) -> Option<Self>;
fn next_sibling(&self) -> Option<Self>;
}
pub trait TDocument<'ld> : Sized + Copy + Clone {
type ConcreteNode: TNode<'ld, ConcreteElement = Self::ConcreteElement, ConcreteDocument = Self>;
type ConcreteElement: TElement<'ld, ConcreteNode = Self::ConcreteNode, ConcreteDocument = Self>;
fn as_node(&self) -> Self::ConcreteNode;
fn root_node(&self) -> Option<Self::ConcreteNode>;
fn drain_modified_elements(&self) -> Vec<(Self::ConcreteElement, ElementSnapshot)>;
}
pub trait TElement<'le> : Sized + Copy + Clone + ::selectors::Element {
type ConcreteNode: TNode<'le, ConcreteElement = Self, ConcreteDocument = Self::ConcreteDocument>;
type ConcreteDocument: TDocument<'le, ConcreteNode = Self::ConcreteNode, ConcreteElement = Self>;
fn as_node(&self) -> Self::ConcreteNode;
fn style_attribute(&self) -> &'le Option<PropertyDeclarationBlock>;
fn get_state(&self) -> ElementState;
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, &mut V)
where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>;
fn get_attr<'a>(&'a self, namespace: &Namespace, attr: &Atom) -> Option<&'a str>;
fn get_attrs<'a>(&'a self, attr: &Atom) -> Vec<&'a str>;
/// Properly marks nodes as dirty in response to restyle hints.
fn note_restyle_hint(&self, mut hint: RestyleHint) {
// Bail early if there's no restyling to do.
if hint.is_empty() {
return;
}
// If the restyle hint is non-empty, we need to restyle either this element
// or one of its siblings. Mark our ancestor chain as having dirty descendants.
let node = self.as_node();
let mut curr = node;
while let Some(parent) = curr.parent_node() {
if parent.has_dirty_descendants() { break }
unsafe { parent.set_dirty_descendants(true); }
curr = parent;
}
// Process hints.
if hint.contains(RESTYLE_SELF) {
node.dirty_self();
// FIXME(bholley, #8438): We currently need to RESTYLE_DESCENDANTS in the
// RESTYLE_SELF case in order to make sure "inherit" style structs propagate
// properly. See the explanation in the github issue.
hint.insert(RESTYLE_DESCENDANTS);
}
if hint.contains(RESTYLE_DESCENDANTS) {
unsafe { node.set_dirty_descendants(true); }
node.dirty_descendants();
}
if hint.contains(RESTYLE_LATER_SIBLINGS) {
let mut next = ::selectors::Element::next_sibling_element(self);
while let Some(sib) = next {
let sib_node = sib.as_node();
sib_node.dirty_self();
sib_node.dirty_descendants();
next = ::selectors::Element::next_sibling_element(&sib);
}
}
}
}
pub struct TreeIterator<'a, ConcreteNode> where ConcreteNode: TNode<'a> {
stack: Vec<ConcreteNode>,
// Satisfy the compiler about the unused lifetime.
phantom: PhantomData<&'a ()>,
}
impl<'a, ConcreteNode> TreeIterator<'a, ConcreteNode> where ConcreteNode: TNode<'a> {
fn new(root: ConcreteNode) -> TreeIterator<'a, ConcreteNode> {
let mut stack = vec!();
stack.push(root);
TreeIterator {
stack: stack,
phantom: PhantomData,
}
}
}
impl<'a, ConcreteNode> Iterator for TreeIterator<'a, ConcreteNode>
where ConcreteNode: TNode<'a> {
type Item = ConcreteNode;
fn next(&mut self) -> Option<ConcreteNode> {
let ret = self.stack.pop();
ret.map(|node| self.stack.extend(node.rev_children()));
ret
}
}
pub struct ChildrenIterator<'a, ConcreteNode> where ConcreteNode: TNode<'a> {
current: Option<ConcreteNode>,
// Satisfy the compiler about the unused lifetime.
phantom: PhantomData<&'a ()>,
}
impl<'a, ConcreteNode> Iterator for ChildrenIterator<'a, ConcreteNode>
where ConcreteNode: TNode<'a> {
type Item = ConcreteNode;
fn next(&mut self) -> Option<ConcreteNode> {
let node = self.current;
self.current = node.and_then(|node| node.next_sibling());
node
}
}
pub struct ReverseChildrenIterator<'a, ConcreteNode> where ConcreteNode: TNode<'a> {
current: Option<ConcreteNode>,
// Satisfy the compiler about the unused lifetime.
phantom: PhantomData<&'a ()>,
}
impl<'a, ConcreteNode> Iterator for ReverseChildrenIterator<'a, ConcreteNode>
where ConcreteNode: TNode<'a> {
type Item = ConcreteNode;
fn next(&mut self) -> Option<ConcreteNode> {
let node = self.current;
self.current = node.and_then(|node| node.prev_sibling());
node
}
}

Просмотреть файл

@ -17,6 +17,7 @@
extern crate app_units;
#[macro_use]
extern crate bitflags;
extern crate core;
#[macro_use]
extern crate cssparser;
extern crate encoding;
@ -43,9 +44,10 @@ extern crate util;
pub mod animation;
pub mod attr;
mod custom_properties;
pub mod data;
pub mod dom;
pub mod font_face;
pub mod media_queries;
pub mod node;
pub mod parser;
pub mod restyle_hints;
pub mod selector_matching;

Просмотреть файл

@ -1,19 +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 http://mozilla.org/MPL/2.0/. */
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and
//! style.
use properties::PropertyDeclaration;
use selectors::matching::DeclarationBlock;
use smallvec::VecLike;
use string_cache::{Atom, Namespace};
pub trait TElementAttributes {
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, &mut V)
where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>;
fn get_attr<'a>(&'a self, namespace: &Namespace, attr: &Atom) -> Option<&'a str>;
fn get_attrs<'a>(&'a self, attr: &Atom) -> Vec<&'a str>;
}

Просмотреть файл

@ -3,11 +3,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use cssparser::{Parser, SourcePosition};
use dom::TElement;
use log;
use media_queries::{Device, MediaType};
use msg::ParseErrorReporter;
use msg::constellation_msg::PipelineId;
use node::TElementAttributes;
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
use restyle_hints::{ElementSnapshot, RestyleHint, DependencySet};
use selectors::Element;
@ -270,7 +270,7 @@ impl Stylist {
/// The returned boolean indicates whether the style is *shareable*; that is, whether the
/// matched selectors are simple enough to allow the matching logic to be reduced to the logic
/// in `css::matching::PrivateMatchMethods::candidate_element_allows_for_style_sharing`.
pub fn push_applicable_declarations<E, V>(
pub fn push_applicable_declarations<'le, E, V>(
&self,
element: &E,
parent_bf: Option<&BloomFilter>,
@ -278,7 +278,7 @@ impl Stylist {
pseudo_element: Option<PseudoElement>,
applicable_declarations: &mut V)
-> bool
where E: Element + TElementAttributes,
where E: Element + TElement<'le>,
V: VecLike<DeclarationBlock> {
assert!(!self.is_device_dirty);
assert!(style_attribute.is_none() || pseudo_element.is_none(),

Просмотреть файл

@ -35,6 +35,7 @@ use std::mem::{size_of, transmute};
use std::rc::Rc;
use std::result::Result;
use std::sync::Arc;
use std::sync::atomic::{AtomicIsize, AtomicUsize};
use str::{DOMString, LengthOrPercentageOrAuto};
use string_cache::atom::Atom;
use string_cache::namespace::{QualName, Namespace};
@ -418,6 +419,7 @@ impl HeapSizeOf for Value {
known_heap_size!(0, u8, u16, u32, u64, usize);
known_heap_size!(0, i8, i16, i32, i64, isize);
known_heap_size!(0, bool, f32, f64);
known_heap_size!(0, AtomicIsize, AtomicUsize);
known_heap_size!(0, Rect<T>, Point2D<T>, Size2D<T>, Matrix2D<T>, SideOffsets2D<T>, Range<T>);
known_heap_size!(0, Length<T, U>, ScaleFactor<T, U, V>);

Просмотреть файл

@ -38,10 +38,10 @@ macro_rules! sizeof_checker (
// Update the sizes here
sizeof_checker!(size_event_target, EventTarget, 40);
sizeof_checker!(size_node, Node, 184);
sizeof_checker!(size_element, Element, 328);
sizeof_checker!(size_htmlelement, HTMLElement, 344);
sizeof_checker!(size_div, HTMLDivElement, 344);
sizeof_checker!(size_span, HTMLSpanElement, 344);
sizeof_checker!(size_text, Text, 216);
sizeof_checker!(size_characterdata, CharacterData, 216);
sizeof_checker!(size_node, Node, 168);
sizeof_checker!(size_element, Element, 312);
sizeof_checker!(size_htmlelement, HTMLElement, 328);
sizeof_checker!(size_div, HTMLDivElement, 328);
sizeof_checker!(size_span, HTMLSpanElement, 328);
sizeof_checker!(size_text, Text, 200);
sizeof_checker!(size_characterdata, CharacterData, 200);