Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pseudo element build flow and box #1496

Closed
@@ -14,6 +14,8 @@ use style::ComputedValues;
/// Node mixin providing `style` method that returns a `NodeStyle`
pub trait StyledNode {
fn style<'a>(&'a self) -> &'a Arc<ComputedValues>;
fn before_style<'a>(&'a self) -> &'a Arc<ComputedValues>;
fn after_style<'a>(&'a self) -> &'a Arc<ComputedValues>;
fn restyle_damage(&self) -> RestyleDamage;
}

@@ -23,6 +25,16 @@ impl<'ln> StyledNode for ThreadSafeLayoutNode<'ln> {
self.get_css_select_results()
}

#[inline]
fn before_style<'a>(&'a self) -> &'a Arc<ComputedValues> {
self.get_before_css_select_results()
}

#[inline]
fn after_style<'a>(&'a self) -> &'a Arc<ComputedValues> {
self.get_before_css_select_results()
}

fn restyle_damage(&self) -> RestyleDamage {
self.get_restyle_damage()
}
@@ -12,6 +12,8 @@ use style::ComputedValues;

pub trait NodeUtil {
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues>;
fn get_before_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues>;
fn get_after_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues>;
fn have_css_select_results(self) -> bool;

fn get_restyle_damage(self) -> RestyleDamage;
@@ -35,6 +37,22 @@ impl<'ln> NodeUtil for ThreadSafeLayoutNode<'ln> {
}
}

#[inline]
fn get_before_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues> {
unsafe {
let layout_data_ref = self.borrow_layout_data();
cast::transmute_region(layout_data_ref.get().as_ref().unwrap().data.before_style.as_ref().unwrap())
}
}

#[inline]
fn get_after_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues> {
unsafe {
let layout_data_ref = self.borrow_layout_data();
cast::transmute_region(layout_data_ref.get().as_ref().unwrap().data.after_style.as_ref().unwrap())
}
}

/// Does this node have a computed style yet?
fn have_css_select_results(self) -> bool {
let layout_data_ref = self.borrow_layout_data();
@@ -31,14 +31,23 @@ use layout::flow::{Flow, FlowLeafSet, ImmutableFlowUtils, MutableOwnedFlowUtils}
use layout::inline::InlineFlow;
use layout::text::TextRunScanner;
use layout::util::{LayoutDataAccess, OpaqueNode};
use layout::util::{PrivateLayoutData, PseudoNode};
use layout::wrapper::{PostorderNodeMutTraversal, TLayoutNode, ThreadSafeLayoutNode};
use layout::wrapper::LayoutPseudoNode;
use layout::extra::LayoutAuxMethods;

use gfx::font_context::FontContext;
use script::dom::element::{HTMLIframeElementTypeId, HTMLImageElementTypeId};
use script::dom::element::Element;
use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId};
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstructionNodeTypeId};
use script::dom::node::{TextNodeTypeId};
use script::dom::node::AbstractNode;
use script::dom::text::Text;
use style::computed_values::{display, position, float, white_space};
use style::computed_values::content;
use style::TNode;
use style::{PseudoElement, Before, After};
use style::ComputedValues;

use extra::arc::Arc;
@@ -371,8 +380,6 @@ impl<'fc> FlowConstructor<'fc> {
}
}
}

// Add the boxes to the list we're maintaining.
opt_boxes_for_inline_flow.push_all_move(boxes)
}
ConstructionItemConstructionResult(WhitespaceConstructionItem(..)) => {
@@ -402,6 +409,7 @@ impl<'fc> FlowConstructor<'fc> {
fn build_flow_for_block(&mut self, node: ThreadSafeLayoutNode, is_fixed: bool) -> ~Flow {
let mut flow = ~BlockFlow::from_node(self, node, is_fixed) as ~Flow;
self.build_children_of_block_flow(&mut flow, node);

flow
}

@@ -617,6 +625,113 @@ impl<'fc> FlowConstructor<'fc> {
self.build_boxes_for_replaced_inline_content(node)
}
}

fn build_flow_or_boxes_for_pseudo_element(&mut self, node: ThreadSafeLayoutNode, pseudo_element: PseudoElement) {
let p = unsafe { node.parent_node().expect("Text node should have its parent") };
let mut content = ~"";

// Create pseudo parent_node
let pseudo_parent_element = match pseudo_element {
Before => ~Element::new_layout_pseudo(~"before"),
After => ~Element::new_layout_pseudo(~"after"),
};
let pseudo_parent_abstract_node = unsafe { AbstractNode::from_layout_pseudo(pseudo_parent_element) };
let mut pseudo_parent_node = unsafe { p.new_with_this_lifetime(pseudo_parent_abstract_node.clone()) };

// Create layout data for pseudo parent node
let layout_data_ref = p.borrow_layout_data();
let pseudo_parent_ldw = layout_data_ref.get().get_ref();

ThreadSafeLayoutNode::to_pseudo_layout_node(pseudo_parent_node).initialize_layout_data_no_chan();

if pseudo_element == Before {
insert_layout_data(&pseudo_parent_node, ~PrivateLayoutData::new_with_style(pseudo_parent_ldw.data.before_style.clone()));
let before_style = pseudo_parent_ldw.data.before_style.get_ref();
content = FlowConstructor::get_content(&before_style.get().Box.content)
} else if pseudo_element == After {
insert_layout_data(&pseudo_parent_node, ~PrivateLayoutData::new_with_style(pseudo_parent_ldw.data.after_style.clone()));
let after_style = pseudo_parent_ldw.data.after_style.get_ref();
content = FlowConstructor::get_content(&after_style.get().Box.content);
}

let pseudo_parent_display = pseudo_parent_node.style().get().Box.display;

// Create pseudo node
let pseudo_text = ~Text::new_layout_pseudo(content);
let pseudo_abstract_node = unsafe { AbstractNode::from_layout_pseudo(pseudo_text) };
let mut pseudo_node = unsafe { node.new_with_this_lifetime(pseudo_abstract_node) };
let mut layout_data_ref = node.mutate_layout_data();
let pseudo_child_ldw = layout_data_ref.get().get_mut_ref();

ThreadSafeLayoutNode::to_pseudo_layout_node(pseudo_node).initialize_layout_data_no_chan();

if pseudo_element == Before {
insert_layout_data(&pseudo_node, ~PrivateLayoutData::new_with_style(pseudo_parent_ldw.data.before_style.clone()));
} else if pseudo_element == After {
insert_layout_data(&pseudo_node, ~PrivateLayoutData::new_with_style(pseudo_parent_ldw.data.after_style.clone()));
}

// Store pseudo_parent_node & pseudo_node in node
if pseudo_element == Before {
let parent = LayoutPseudoNode::from_layout_pseudo(pseudo_parent_abstract_node, pseudo_parent_display);
let element = LayoutPseudoNode::from_layout_pseudo(pseudo_abstract_node, display::none);

pseudo_child_ldw.data.before = Some(PseudoNode{parent: parent, element: element});
} else if pseudo_element == After {
let parent = LayoutPseudoNode::from_layout_pseudo(pseudo_parent_abstract_node, pseudo_parent_display);
let element = LayoutPseudoNode::from_layout_pseudo(pseudo_abstract_node, display::none);

pseudo_child_ldw.data.after = Some(PseudoNode{parent: parent, element: element});
}

// Set relation between pseudo_node and pseudo_parent_node
pseudo_parent_node.set_first_child(&mut pseudo_node);
pseudo_node.set_parent_node(&mut pseudo_parent_node);

// Set relation with dom nodes
if pseudo_parent_display == display::inline {
if pseudo_element == Before {
let construction_result = self.build_boxes_for_inline(pseudo_parent_node);
pseudo_parent_node.set_flow_construction_result(construction_result);
pseudo_node.set_next_sibling(&node);
} else if pseudo_element == After {
pseudo_parent_node.set_prev_sibling(&node);
match node.next_pseudo_sibling() {
Some(next_sibling) => {
pseudo_parent_node.set_next_sibling(&next_sibling);
}
None => {}
}
}
} else if pseudo_parent_display == display::block {
if pseudo_element == Before {
let flow = self.build_flow_for_block(pseudo_parent_node, false);
pseudo_parent_node.set_flow_construction_result(FlowConstructionResult(flow));
pseudo_parent_node.set_next_sibling(&p);
} else if pseudo_element == After {
pseudo_parent_node.set_prev_sibling(&p);
match p.next_pseudo_sibling() {
Some(next_sibling) => {
pseudo_parent_node.set_next_sibling(&next_sibling);
}
None => {}
}
}
}
}

fn get_content(content_list: &content::T) -> ~str{
match *content_list {
content::Content(ref value) => {
let iter = &mut value.clone().move_iter().peekable();
match iter.next() {
Some(content::StringContent(str)) => str,
_ => ~"",
}
}
_ => ~"",
}
}
}

impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
@@ -653,6 +768,12 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {

// Inline items contribute inline box construction results.
(display::inline, float::none, _) => {
if node.is_text() {
let pseudo_elements = node.necessary_pseudo_elements();
for pseudo_element in pseudo_elements.iter() {
self.build_flow_or_boxes_for_pseudo_element(node, *pseudo_element);
}
}
let construction_result = self.build_boxes_for_inline(node);
node.set_flow_construction_result(construction_result)
}
@@ -812,3 +933,10 @@ fn strip_ignorable_whitespace_from_end(opt_boxes: &mut Option<~[Box]>) {
}
}

fn insert_layout_data(node: &ThreadSafeLayoutNode, new_layout_data: ~PrivateLayoutData) {
let mut layout_data = node.mutate_layout_data();
match *layout_data.get() {
Some(ref mut layout_data_wrapper) => layout_data_wrapper.data = new_layout_data,
None => { fail!("Dont have layout_data."); }
}
}
@@ -10,11 +10,28 @@ use script::layout_interface::LayoutChan;

/// Functionality useful for querying the layout-specific data on DOM nodes.
pub trait LayoutAuxMethods {
fn initialize_layout_data_no_chan(self);
fn initialize_layout_data(self, chan: LayoutChan);
fn initialize_style_for_subtree(self, chan: LayoutChan);
}

impl<'ln> LayoutAuxMethods for LayoutNode<'ln> {
/// Resets layout data and styles without a channel for the node.
///
/// FIXME(pcwalton): Do this as part of box building instead of in a traversal.
fn initialize_layout_data_no_chan(self) {
let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_ref.get() {
None => {
*layout_data_ref.get() = Some(LayoutDataWrapper {
chan: None,
data: ~PrivateLayoutData::new(),
});
}
Some(_) => {}
}
}

/// Resets layout data and styles for the node.
///
/// FIXME(pcwalton): Do this as part of box building instead of in a traversal.
@@ -6,6 +6,7 @@ use layout::box_::Box;
use layout::construct::{ConstructionResult, NoConstructionResult};
use layout::parallel::DomParallelInfo;
use layout::wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode};
use layout::wrapper::LayoutPseudoNode;

use extra::arc::Arc;
use script::dom::bindings::utils::Reflectable;
@@ -19,6 +20,7 @@ use std::iter::Enumerate;
use std::libc::uintptr_t;
use std::vec::VecIterator;
use style::{ComputedValues, PropertyDeclaration};
use style::{PseudoElement, Before, After};

/// A range of nodes.
pub struct NodeRange {
@@ -128,6 +130,11 @@ impl ElementMapping {
}
}

pub struct PseudoNode {
parent: LayoutPseudoNode,
element: LayoutPseudoNode
}

/// Data that layout associates with a node.
pub struct PrivateLayoutData {
/// The results of CSS matching for this node.
@@ -144,6 +151,10 @@ pub struct PrivateLayoutData {

after_style: Option<Arc<ComputedValues>>,

before: Option<PseudoNode>,

after: Option<PseudoNode>,

/// Description of how to account for recent style changes.
restyle_damage: Option<int>,

@@ -165,6 +176,24 @@ impl PrivateLayoutData {
before_style: None,
style: None,
after_style: None,
before: None,
after: None,
restyle_damage: None,
flow_construction_result: NoConstructionResult,
parallel: DomParallelInfo::new(),
}
}

pub fn new_with_style(style: Option<Arc<ComputedValues>>) -> PrivateLayoutData {
PrivateLayoutData {
applicable_declarations: SmallVec16::new(),
before_applicable_declarations: SmallVec0::new(),
after_applicable_declarations: SmallVec0::new(),
before_style: None,
style: style,
after_style: None,
before: None,
after: None,
restyle_damage: None,
flow_construction_result: NoConstructionResult,
parallel: DomParallelInfo::new(),
@@ -178,6 +207,13 @@ impl PrivateLayoutData {
self.before_applicable_declarations = SmallVec0::new();
self.after_applicable_declarations = SmallVec0::new();
}

pub fn get_pseudo_element<'a>(&'a self, pseudo_element: PseudoElement) -> Option<&'a PseudoNode> {
match pseudo_element {
Before => self.before.as_ref(),
After => self.after.as_ref()
}
}
}

pub struct LayoutDataWrapper {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.