Skip to content

Commit

Permalink
Auto merge of #9586 - notriddle:details_ui, r=SimonSapin
Browse files Browse the repository at this point in the history
Details ui

Requires a patch to rust-selectors, and doesn't currently recalculate the styles correctly (which is needed to make actual toggling work correctly).

Still trying to figure out what it takes to get style recalc to do what this needs.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.svg" height="40" alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/9586)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Mar 20, 2016
2 parents 6dbffb6 + 9d9c539 commit 090da52
Show file tree
Hide file tree
Showing 13 changed files with 295 additions and 28 deletions.
6 changes: 5 additions & 1 deletion components/layout/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
HTMLElementTypeId::HTMLInputElement))) ||
node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
HTMLElementTypeId::HTMLTextAreaElement)));
if node.get_pseudo_element_type() != PseudoElementType::Normal ||
if node.get_pseudo_element_type().is_before_or_after() ||
node_is_input_or_text_area {
// A TextArea's text contents are displayed through the input text
// box, so don't construct them.
Expand Down Expand Up @@ -1461,6 +1461,8 @@ impl<'a, ConcreteThreadSafeLayoutNode> PostorderNodeMutTraversal<ConcreteThreadS
PseudoElementType::Normal => display::T::inline,
PseudoElementType::Before(display) => display,
PseudoElementType::After(display) => display,
PseudoElementType::DetailsContent(display) => display,
PseudoElementType::DetailsSummary(display) => display,
};
(display, style.get_box().float, style.get_box().position)
}
Expand Down Expand Up @@ -1646,6 +1648,8 @@ impl<ConcreteThreadSafeLayoutNode> NodeUtils for ConcreteThreadSafeLayoutNode
match self.get_pseudo_element_type() {
PseudoElementType::Before(_) => &mut data.before_flow_construction_result,
PseudoElementType::After (_) => &mut data.after_flow_construction_result,
PseudoElementType::DetailsSummary(_) => &mut data.details_summary_flow_construction_result,
PseudoElementType::DetailsContent(_) => &mut data.details_content_flow_construction_result,
PseudoElementType::Normal => &mut data.flow_construction_result,
}
}
Expand Down
6 changes: 6 additions & 0 deletions components/layout/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ pub struct PrivateLayoutData {

pub after_flow_construction_result: ConstructionResult,

pub details_summary_flow_construction_result: ConstructionResult,

pub details_content_flow_construction_result: ConstructionResult,

/// Various flags.
pub flags: LayoutDataFlags,
}
Expand All @@ -38,6 +42,8 @@ impl PrivateLayoutData {
flow_construction_result: ConstructionResult::None,
before_flow_construction_result: ConstructionResult::None,
after_flow_construction_result: ConstructionResult::None,
details_summary_flow_construction_result: ConstructionResult::None,
details_content_flow_construction_result: ConstructionResult::None,
flags: LayoutDataFlags::empty(),
}
}
Expand Down
8 changes: 6 additions & 2 deletions components/layout/fragment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2445,15 +2445,19 @@ impl Fragment {
match self.pseudo {
PseudoElementType::Normal => FragmentType::FragmentBody,
PseudoElementType::Before(_) => FragmentType::BeforePseudoContent,
PseudoElementType::After(_) => FragmentType::AfterPseudoContent
PseudoElementType::After(_) => FragmentType::AfterPseudoContent,
PseudoElementType::DetailsSummary(_) => FragmentType::FragmentBody,
PseudoElementType::DetailsContent(_) => FragmentType::FragmentBody,
}
}

pub fn layer_id(&self) -> LayerId {
let layer_type = match self.pseudo {
PseudoElementType::Normal => LayerType::FragmentBody,
PseudoElementType::Before(_) => LayerType::BeforePseudoContent,
PseudoElementType::After(_) => LayerType::AfterPseudoContent
PseudoElementType::After(_) => LayerType::AfterPseudoContent,
PseudoElementType::DetailsSummary(_) => LayerType::FragmentBody,
PseudoElementType::DetailsContent(_) => LayerType::FragmentBody,
};
LayerId::new_of_type(layer_type, self.node.id() as usize)
}
Expand Down
2 changes: 2 additions & 0 deletions components/layout/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,8 @@ pub fn process_resolved_style_request<N: LayoutNode>(
let layout_node = match pseudo {
&Some(PseudoElement::Before) => layout_node.get_before_pseudo(),
&Some(PseudoElement::After) => layout_node.get_after_pseudo(),
&Some(PseudoElement::DetailsSummary) => layout_node.get_details_summary_pseudo(),
&Some(PseudoElement::DetailsContent) => layout_node.get_details_content_pseudo(),
_ => Some(layout_node)
};

Expand Down
173 changes: 150 additions & 23 deletions components/layout/wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,8 @@ pub enum PseudoElementType<T> {
Normal,
Before(T),
After(T),
DetailsSummary(T),
DetailsContent(T),
}

impl<T> PseudoElementType<T> {
Expand All @@ -625,19 +627,28 @@ impl<T> PseudoElementType<T> {
}
}

pub fn is_before_or_after(&self) -> bool {
match *self {
PseudoElementType::Before(_) | PseudoElementType::After(_) => true,
_ => false,
}
}

pub fn strip(&self) -> PseudoElementType<()> {
match *self {
PseudoElementType::Normal => PseudoElementType::Normal,
PseudoElementType::Before(_) => PseudoElementType::Before(()),
PseudoElementType::After(_) => PseudoElementType::After(()),
PseudoElementType::DetailsSummary(_) => PseudoElementType::DetailsSummary(()),
PseudoElementType::DetailsContent(_) => PseudoElementType::DetailsContent(()),
}
}
}

/// 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 {
pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
type ConcreteThreadSafeLayoutElement: ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self>;
type ChildrenIterator: Iterator<Item = Self> + Sized;

Expand All @@ -659,6 +670,9 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized {
/// Returns an iterator over this node's children.
fn children(&self) -> Self::ChildrenIterator;

#[inline]
fn is_element(&self) -> bool { if let Some(NodeTypeId::Element(_)) = self.type_id() { true } else { false } }

/// If this is an element, accesses the element data. Fails if this is not an element node.
#[inline]
fn as_element(&self) -> Self::ConcreteThreadSafeLayoutElement;
Expand Down Expand Up @@ -686,6 +700,38 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized {
})
}

#[inline]
fn get_details_summary_pseudo(&self) -> Option<Self> {
if self.is_element() &&
self.as_element().get_local_name() == &atom!("details") &&
self.as_element().get_namespace() == &ns!(html) {
self.borrow_layout_data().unwrap()
.style_data.per_pseudo
.get(&PseudoElement::DetailsSummary)
.map(|style| {
self.with_pseudo(PseudoElementType::DetailsSummary(style.get_box().display))
})
} else {
None
}
}

#[inline]
fn get_details_content_pseudo(&self) -> Option<Self> {
if self.is_element() &&
self.as_element().get_local_name() == &atom!("details") &&
self.as_element().get_namespace() == &ns!(html) {
self.borrow_layout_data().unwrap()
.style_data.per_pseudo
.get(&PseudoElement::DetailsContent)
.map(|style| {
self.with_pseudo(PseudoElementType::DetailsContent(style.get_box().display))
})
} else {
None
}
}

/// Borrows the layout data immutably. Fails on a conflicting borrow.
///
/// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases.
Expand All @@ -708,6 +754,8 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized {
let style = match self.get_pseudo_element_type() {
PseudoElementType::Before(_) => data.style_data.per_pseudo.get(&PseudoElement::Before),
PseudoElementType::After(_) => data.style_data.per_pseudo.get(&PseudoElement::After),
PseudoElementType::DetailsSummary(_) => data.style_data.per_pseudo.get(&PseudoElement::DetailsSummary),
PseudoElementType::DetailsContent(_) => data.style_data.per_pseudo.get(&PseudoElement::DetailsContent),
PseudoElementType::Normal => data.style_data.style.as_ref(),
};
style.unwrap()
Expand All @@ -727,6 +775,13 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized {
PseudoElementType::After(_) => {
data.style_data.per_pseudo.remove(&PseudoElement::After);
}
PseudoElementType::DetailsSummary(_) => {
data.style_data.per_pseudo.remove(&PseudoElement::DetailsSummary);
}
PseudoElementType::DetailsContent(_) => {
data.style_data.per_pseudo.remove(&PseudoElement::DetailsContent);
}

PseudoElementType::Normal => {
data.style_data.style = None;
}
Expand Down Expand Up @@ -798,6 +853,12 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized {

#[inline]
fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str>;

#[inline]
fn get_local_name(&self) -> &Atom;

#[inline]
fn get_namespace(&self) -> &Namespace;
}

#[derive(Copy, Clone)]
Expand All @@ -808,7 +869,15 @@ pub struct ServoThreadSafeLayoutNode<'ln> {
pseudo: PseudoElementType<display::T>,
}

impl<'a> PartialEq for ServoThreadSafeLayoutNode<'a> {
#[inline]
fn eq(&self, other: &ServoThreadSafeLayoutNode<'a>) -> bool {
self.node == other.node
}
}

impl<'ln> DangerousThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {

unsafe fn dangerous_first_child(&self) -> Option<Self> {
self.get_jsmanaged().first_child_ref()
.map(|node| self.new_with_this_lifetime(&node))
Expand Down Expand Up @@ -1041,10 +1110,13 @@ impl<ConcreteNode> ThreadSafeLayoutNodeChildrenIterator<ConcreteNode>
pub fn new(parent: ConcreteNode) -> Self {
let first_child: Option<ConcreteNode> = match parent.get_pseudo_element_type() {
PseudoElementType::Normal => {
parent.get_before_pseudo().or_else(|| {
parent.get_before_pseudo().or_else(|| parent.get_details_summary_pseudo()).or_else(|| {
unsafe { parent.dangerous_first_child() }
})
},
PseudoElementType::DetailsContent(_) | PseudoElementType::DetailsSummary(_) => {
unsafe { parent.dangerous_first_child() }
},
_ => None,
};
ThreadSafeLayoutNodeChildrenIterator {
Expand All @@ -1058,29 +1130,74 @@ impl<ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<ConcreteNod
where ConcreteNode: DangerousThreadSafeLayoutNode {
type Item = ConcreteNode;
fn next(&mut self) -> Option<ConcreteNode> {
let node = self.current_node.clone();

if let Some(ref node) = node {
self.current_node = match node.get_pseudo_element_type() {
PseudoElementType::Before(_) => {
match unsafe { self.parent_node.dangerous_first_child() } {
Some(first) => Some(first),
None => self.parent_node.get_after_pseudo(),
}
},
PseudoElementType::Normal => {
match unsafe { node.dangerous_next_sibling() } {
Some(next) => Some(next),
None => self.parent_node.get_after_pseudo(),
match self.parent_node.get_pseudo_element_type() {

PseudoElementType::Before(_) | PseudoElementType::After(_) => None,

PseudoElementType::DetailsSummary(_) => {
let mut current_node = self.current_node.clone();
loop {
let next_node = if let Some(ref node) = current_node {
if node.is_element() &&
node.as_element().get_local_name() == &atom!("summary") &&
node.as_element().get_namespace() == &ns!(html) {
self.current_node = None;
return Some(node.clone());
}
unsafe { node.dangerous_next_sibling() }
} else {
self.current_node = None;
return None
};
current_node = next_node;
}
}

PseudoElementType::DetailsContent(_) => {
let node = self.current_node.clone();
let node = node.and_then(|node| {
if node.is_element() &&
node.as_element().get_local_name() == &atom!("summary") &&
node.as_element().get_namespace() == &ns!(html) {
unsafe { node.dangerous_next_sibling() }
} else {
Some(node)
}
},
PseudoElementType::After(_) => {
None
},
};
}
});
self.current_node = node.and_then(|node| unsafe { node.dangerous_next_sibling() });
node
}

PseudoElementType::Normal => {
let node = self.current_node.clone();
if let Some(ref node) = node {
self.current_node = match node.get_pseudo_element_type() {
PseudoElementType::Before(_) => {
let first = self.parent_node.get_details_summary_pseudo().or_else(|| unsafe {
self.parent_node.dangerous_first_child()
});
match first {
Some(first) => Some(first),
None => self.parent_node.get_after_pseudo(),
}
},
PseudoElementType::Normal => {
match unsafe { node.dangerous_next_sibling() } {
Some(next) => Some(next),
None => self.parent_node.get_after_pseudo(),
}
},
PseudoElementType::DetailsSummary(_) => self.parent_node.get_details_content_pseudo(),
PseudoElementType::DetailsContent(_) => self.parent_node.get_after_pseudo(),
PseudoElementType::After(_) => {
None
},
};
}
node
}

node
}
}
}

Expand All @@ -1099,6 +1216,16 @@ impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> {
self.element.get_attr_val_for_layout(namespace, name)
}
}

#[inline]
fn get_local_name(&self) -> &Atom {
self.element.local_name()
}

#[inline]
fn get_namespace(&self) -> &Namespace {
self.element.namespace()
}
}

pub enum TextContent {
Expand Down
16 changes: 15 additions & 1 deletion components/style/selector_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ pub trait SelectorImplExt : SelectorImpl + Sized {
pub enum PseudoElement {
Before,
After,
DetailsSummary,
DetailsContent,
}

#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)]
Expand Down Expand Up @@ -97,12 +99,22 @@ impl SelectorImpl for ServoSelectorImpl {
Ok(pseudo_class)
}

fn parse_pseudo_element(_context: &ParserContext,
fn parse_pseudo_element(context: &ParserContext,
name: &str) -> Result<PseudoElement, ()> {
use self::PseudoElement::*;
let pseudo_element = match_ignore_ascii_case! { name,
"before" => Before,
"after" => After,
"-servo-details-summary" => if context.in_user_agent_stylesheet {
DetailsSummary
} else {
return Err(())
},
"-servo-details-content" => if context.in_user_agent_stylesheet {
DetailsContent
} else {
return Err(())
},
_ => return Err(())
};

Expand All @@ -122,6 +134,8 @@ impl SelectorImplExt for ServoSelectorImpl {
where F: FnMut(PseudoElement) {
fun(PseudoElement::Before);
fun(PseudoElement::After);
fun(PseudoElement::DetailsContent);
fun(PseudoElement::DetailsSummary);
}

#[inline]
Expand Down
1 change: 0 additions & 1 deletion components/style/selector_matching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
if !stylesheet.is_effective_for_device(device) {
return;
}

let mut rules_source_order = self.rules_source_order;

// Take apart the StyleRule into individual Rules and insert
Expand Down
Loading

0 comments on commit 090da52

Please sign in to comment.