style: layout: Allow a lazy pseudo-element implementation in Servo.

This commit is contained in:
Emilio Cobos Álvarez 2016-05-03 18:50:25 +02:00
parent 18c1fee3c7
commit 028f9b6cd2
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
6 changed files with 172 additions and 57 deletions

View file

@ -66,7 +66,7 @@ use std::sync::Arc;
use string_cache::{Atom, Namespace};
use style::computed_values::content::ContentItem;
use style::computed_values::{content, display};
use style::dom::{TDocument, TElement, TNode, UnsafeNode};
use style::dom::{PresentationalHintsSynthetizer, TDocument, TElement, TNode, UnsafeNode};
use style::element_state::*;
use style::properties::{ComputedValues, ServoComputedValues};
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
@ -81,7 +81,7 @@ 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 : TNode {
pub trait LayoutNode: TNode {
type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode;
fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode;
@ -401,6 +401,16 @@ pub struct ServoLayoutElement<'le> {
chain: PhantomData<&'le ()>,
}
impl<'le> PresentationalHintsSynthetizer 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);
}
}
}
impl<'le> TElement for ServoLayoutElement<'le> {
type ConcreteNode = ServoLayoutNode<'le>;
type ConcreteDocument = ServoLayoutDocument<'le>;
@ -419,14 +429,6 @@ impl<'le> TElement for ServoLayoutElement<'le> {
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(&self, namespace: &Namespace, name: &Atom) -> Option<&str> {
unsafe {
@ -665,8 +667,10 @@ impl<T> PseudoElementType<T> {
/// A thread-safe version of `LayoutNode`, used during flow construction. This type of layout
/// node does not allow any parents or siblings of nodes to be accessed, to avoid races.
pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
type ConcreteThreadSafeLayoutElement: ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self>;
pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq {
type ConcreteThreadSafeLayoutElement:
ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self>
+ ::selectors::Element<Impl=ServoSelectorImpl>;
type ChildrenIterator: Iterator<Item = Self> + Sized;
/// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode`
@ -680,6 +684,18 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
/// Returns `None` if this is a pseudo-element; otherwise, returns `Some`.
fn type_id(&self) -> Option<NodeTypeId>;
/// Returns the type ID of this node, without discarding pseudo-elements as
/// `type_id` does.
fn type_id_without_excluding_pseudo_elements(&self) -> NodeTypeId;
#[inline]
fn is_element_or_elements_pseudo(&self) -> bool {
match self.type_id_without_excluding_pseudo_elements() {
NodeTypeId::Element(..) => true,
_ => false,
}
}
fn debug_id(self) -> usize;
fn flow_debug_id(self) -> usize;
@ -791,23 +807,20 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
}
}
PseudoElementCascadeType::Lazy => {
panic!("Lazy pseudo-elements can't be used in Servo \
since accessing the DOM tree during layout \
could be unsafe.")
// debug_assert!(self.is_element());
// if !self.borrow_layout_data()
// .unwrap().style_data
// .per_pseudo.contains_key(&style_pseudo) {
// let mut data = self.mutate_layout_data().unwrap();
// let new_style =
// context.stylist
// .lazily_compute_pseudo_element_style(
// &self.as_element(),
// &style_pseudo,
// data.style_data.style.as_ref().unwrap());
// data.style_data.per_pseudo
// .insert(style_pseudo.clone(), new_style.unwrap())
// }
debug_assert!(self.is_element_or_elements_pseudo());
if !self.borrow_layout_data()
.unwrap().style_data
.per_pseudo.contains_key(&style_pseudo) {
let mut data = self.mutate_layout_data().unwrap();
let new_style =
context.stylist
.lazily_compute_pseudo_element_style(
&self.as_element(),
&style_pseudo,
data.style_data.style.as_ref().unwrap());
data.style_data.per_pseudo
.insert(style_pseudo.clone(), new_style.unwrap());
}
}
}
@ -932,12 +945,14 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
// This trait is only public so that it can be implemented by the gecko wrapper.
// It can be used to violate thread-safety, so don't use it elsewhere in layout!
pub trait DangerousThreadSafeLayoutNode : ThreadSafeLayoutNode {
pub trait DangerousThreadSafeLayoutNode: ThreadSafeLayoutNode {
unsafe fn dangerous_first_child(&self) -> Option<Self>;
unsafe fn dangerous_next_sibling(&self) -> Option<Self>;
}
pub trait ThreadSafeLayoutElement: Clone + Copy + Sized {
pub trait ThreadSafeLayoutElement: Clone + Copy + Sized +
::selectors::Element<Impl=ServoSelectorImpl> +
PresentationalHintsSynthetizer {
type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<ConcreteThreadSafeLayoutElement = Self>;
#[inline]
@ -1027,6 +1042,11 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
Some(self.node.type_id())
}
#[inline]
fn type_id_without_excluding_pseudo_elements(&self) -> NodeTypeId {
self.node.type_id()
}
fn debug_id(self) -> usize {
self.node.debug_id()
}
@ -1320,3 +1340,101 @@ impl TextContent {
}
}
}
impl <'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
type Impl = ServoSelectorImpl;
fn parent_element(&self) -> Option<Self> {
warn!("ServoThreadSafeLayoutElement::parent_element called");
None
}
fn first_child_element(&self) -> Option<Self> {
warn!("ServoThreadSafeLayoutElement::first_child_element called");
None
}
// Skips non-element nodes
fn last_child_element(&self) -> Option<Self> {
warn!("ServoThreadSafeLayoutElement::last_child_element called");
None
}
// Skips non-element nodes
fn prev_sibling_element(&self) -> Option<Self> {
warn!("ServoThreadSafeLayoutElement::prev_sibling_element called");
None
}
// Skips non-element nodes
fn next_sibling_element(&self) -> Option<Self> {
warn!("ServoThreadSafeLayoutElement::next_sibling_element called");
None
}
fn is_html_element_in_html_document(&self) -> bool {
warn!("ServoThreadSafeLayoutElement::is_html_element_in_html_document called");
true
}
#[inline]
fn get_local_name(&self) -> &Atom {
ThreadSafeLayoutElement::get_local_name(self)
}
#[inline]
fn get_namespace(&self) -> &Namespace {
ThreadSafeLayoutElement::get_namespace(self)
}
fn match_non_ts_pseudo_class(&self, _: NonTSPseudoClass) -> bool {
// NB: This could maybe be implemented
warn!("ServoThreadSafeLayoutElement::match_non_ts_pseudo_class called");
false
}
fn get_id(&self) -> Option<Atom> {
warn!("ServoThreadSafeLayoutElement::get_id called");
None
}
fn has_class(&self, _name: &Atom) -> bool {
warn!("ServoThreadSafeLayoutElement::has_class called");
false
}
fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool
where F: Fn(&str) -> bool {
match attr.namespace {
NamespaceConstraint::Specific(ref ns) => {
self.get_attr(ns, &attr.name).map_or(false, |attr| test(attr))
},
NamespaceConstraint::Any => {
unsafe {
self.element.get_attr_vals_for_layout(&attr.name).iter()
.any(|attr| test(*attr))
}
}
}
}
fn is_empty(&self) -> bool {
warn!("ServoThreadSafeLayoutElement::is_empty called");
false
}
fn is_root(&self) -> bool {
warn!("ServoThreadSafeLayoutElement::is_root called");
false
}
fn each_class<F>(&self, _callback: F)
where F: FnMut(&Atom) {
warn!("ServoThreadSafeLayoutElement::each_class called");
}
}
impl<'le> PresentationalHintsSynthetizer for ServoThreadSafeLayoutElement<'le> {
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, _hints: &mut V)
where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>> {}
}