mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Bug 1325734 - Remove Servo Layout's dependency on the initial-ness of the style. r=emilio
This commit is contained in:
parent
9482467add
commit
962a4a79bb
6 changed files with 59 additions and 13 deletions
|
@ -46,6 +46,8 @@ impl PersistentLayoutData {
|
|||
bitflags! {
|
||||
pub flags LayoutDataFlags: u8 {
|
||||
#[doc = "Whether a flow has been newly constructed."]
|
||||
const HAS_NEWLY_CONSTRUCTED_FLOW = 0x01
|
||||
const HAS_NEWLY_CONSTRUCTED_FLOW = 0x01,
|
||||
#[doc = "Whether this node has been traversed by layout."]
|
||||
const HAS_BEEN_TRAVERSED = 0x02,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ use style::values::{self, Either};
|
|||
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||
use text;
|
||||
use text::TextRunScanner;
|
||||
use wrapper::ThreadSafeLayoutNodeHelpers;
|
||||
|
||||
// From gfxFontConstants.h in Firefox.
|
||||
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
|
||||
|
|
|
@ -20,6 +20,7 @@ use style::servo::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, RE
|
|||
use style::traversal::{DomTraversal, recalc_style_at};
|
||||
use style::traversal::PerLevelTraversalData;
|
||||
use wrapper::{GetRawData, LayoutNodeHelpers, LayoutNodeLayoutData};
|
||||
use wrapper::ThreadSafeLayoutNodeHelpers;
|
||||
|
||||
pub struct RecalcStyleAndConstructFlows {
|
||||
shared: SharedLayoutContext,
|
||||
|
@ -134,6 +135,8 @@ fn construct_flows_at<'a, N>(context: &LayoutContext<'a>,
|
|||
tnode.flow_debug_id());
|
||||
}
|
||||
}
|
||||
|
||||
tnode.mutate_layout_data().unwrap().flags.insert(::data::HAS_BEEN_TRAVERSED);
|
||||
}
|
||||
|
||||
if let Some(el) = node.as_element() {
|
||||
|
|
|
@ -37,6 +37,8 @@ use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutD
|
|||
use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
||||
use script_layout_interface::wrapper_traits::GetLayoutData;
|
||||
use style::computed_values::content::{self, ContentItem};
|
||||
use style::dom::{NodeInfo, TNode};
|
||||
use style::selector_parser::RestyleDamage;
|
||||
|
||||
pub type NonOpaqueStyleAndLayoutData = AtomicRefCell<PersistentLayoutData>;
|
||||
|
||||
|
@ -120,6 +122,12 @@ pub trait ThreadSafeLayoutNodeHelpers {
|
|||
///
|
||||
/// FIXME(pcwalton): This might have too much copying and/or allocation. Profile this.
|
||||
fn text_content(&self) -> TextContent;
|
||||
|
||||
/// The RestyleDamage from any restyling, or RestyleDamage::rebuild_and_reflow() if this
|
||||
/// is the first time layout is visiting this node. We implement this here, rather than
|
||||
/// with the rest of the wrapper layer, because we need layout code to determine whether
|
||||
/// layout has visited the node.
|
||||
fn restyle_damage(self) -> RestyleDamage;
|
||||
}
|
||||
|
||||
impl<T: ThreadSafeLayoutNode> ThreadSafeLayoutNodeHelpers for T {
|
||||
|
@ -149,6 +157,37 @@ impl<T: ThreadSafeLayoutNode> ThreadSafeLayoutNodeHelpers for T {
|
|||
|
||||
return TextContent::Text(self.node_text_content());
|
||||
}
|
||||
|
||||
fn restyle_damage(self) -> RestyleDamage {
|
||||
// We need the underlying node to potentially access the parent in the
|
||||
// case of text nodes. This is safe as long as we don't let the parent
|
||||
// escape and never access its descendants.
|
||||
let mut node = unsafe { self.unsafe_get() };
|
||||
|
||||
// If this is a text node, use the parent element, since that's what
|
||||
// controls our style.
|
||||
if node.is_text_node() {
|
||||
node = node.parent_node().unwrap();
|
||||
debug_assert!(node.is_element());
|
||||
}
|
||||
|
||||
let data = node.borrow_layout_data().unwrap();
|
||||
if let Some(r) = data.base.style_data.as_restyle() {
|
||||
// We're reflowing a node that just got a restyle, and so the
|
||||
// damage has been computed and stored in the RestyleData.
|
||||
r.damage
|
||||
} else if !data.flags.contains(::data::HAS_BEEN_TRAVERSED) {
|
||||
// We're reflowing a node that was styled for the first time and
|
||||
// has never been visited by layout. Return rebuild_and_reflow,
|
||||
// because that's what the code expects.
|
||||
RestyleDamage::rebuild_and_reflow()
|
||||
} else {
|
||||
// We're reflowing a node whose style data didn't change, but whose
|
||||
// layout may change due to changes in ancestors or descendants.
|
||||
RestyleDamage::empty()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub enum TextContent {
|
||||
|
|
|
@ -67,7 +67,7 @@ use style::dom::{LayoutIterator, NodeInfo, OpaqueNode, PresentationalHintsSynthe
|
|||
use style::dom::UnsafeNode;
|
||||
use style::element_state::*;
|
||||
use style::properties::{ComputedValues, PropertyDeclarationBlock};
|
||||
use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl};
|
||||
use style::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl};
|
||||
use style::sink::Push;
|
||||
use style::str::is_whitespace;
|
||||
use style::stylist::ApplicableDeclarationBlock;
|
||||
|
@ -740,6 +740,7 @@ impl<'ln> NodeInfo for ServoThreadSafeLayoutNode<'ln> {
|
|||
}
|
||||
|
||||
impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
|
||||
type ConcreteNode = ServoLayoutNode<'ln>;
|
||||
type ConcreteThreadSafeLayoutElement = ServoThreadSafeLayoutElement<'ln>;
|
||||
type ChildrenIterator = ThreadSafeLayoutNodeChildrenIterator<Self>;
|
||||
|
||||
|
@ -815,15 +816,8 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
|
|||
}
|
||||
}
|
||||
|
||||
fn restyle_damage(self) -> RestyleDamage {
|
||||
let element = if self.is_text_node() {
|
||||
self.node.parent_node().unwrap().as_element().unwrap()
|
||||
} else {
|
||||
self.node.as_element().unwrap()
|
||||
};
|
||||
|
||||
let damage = element.borrow_data().unwrap().damage();
|
||||
damage
|
||||
unsafe fn unsafe_get(self) -> Self::ConcreteNode {
|
||||
self.node
|
||||
}
|
||||
|
||||
fn can_be_fragmented(&self) -> bool {
|
||||
|
|
|
@ -151,6 +151,7 @@ impl<ConcreteNode> Iterator for TreeIterator<ConcreteNode>
|
|||
/// 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 + Debug + GetLayoutData + NodeInfo + PartialEq + Sized {
|
||||
type ConcreteNode: LayoutNode<ConcreteThreadSafeLayoutNode = Self>;
|
||||
type ConcreteThreadSafeLayoutElement:
|
||||
ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self>
|
||||
+ ::selectors::Element<Impl=SelectorImpl>;
|
||||
|
@ -237,14 +238,20 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Debug + GetLayoutData + NodeInfo
|
|||
|
||||
fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool;
|
||||
|
||||
fn restyle_damage(self) -> RestyleDamage;
|
||||
|
||||
/// Returns true if this node contributes content. This is used in the implementation of
|
||||
/// `empty_cells` per CSS 2.1 § 17.6.1.1.
|
||||
fn is_content(&self) -> bool {
|
||||
self.type_id().is_some()
|
||||
}
|
||||
|
||||
/// Returns access to the underlying LayoutNode. This is breaks the abstraction
|
||||
/// barrier of ThreadSafeLayout wrapper layer, and can lead to races if not used
|
||||
/// carefully.
|
||||
///
|
||||
/// We need this because the implementation of some methods need to access the layout
|
||||
/// data flags, and we have this annoying trait separation between script and layout :-(
|
||||
unsafe fn unsafe_get(self) -> Self::ConcreteNode;
|
||||
|
||||
fn can_be_fragmented(&self) -> bool;
|
||||
|
||||
fn node_text_content(&self) -> String;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue