mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Auto merge of #6443 - Ms2ger:cleanup-layout, r=pcwalton
Various layout cleanup. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6443) <!-- Reviewable:end -->
This commit is contained in:
commit
469b9550f6
9 changed files with 207 additions and 287 deletions
|
@ -16,7 +16,7 @@
|
|||
use block::BlockFlow;
|
||||
use context::LayoutContext;
|
||||
use css::node_style::StyledNode;
|
||||
use data::{HAS_NEWLY_CONSTRUCTED_FLOW, LayoutDataAccess, LayoutDataWrapper};
|
||||
use data::{HAS_NEWLY_CONSTRUCTED_FLOW, LayoutDataWrapper};
|
||||
use floats::FloatKind;
|
||||
use flow::{Descendants, AbsDescendants};
|
||||
use flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
|
||||
|
@ -41,7 +41,7 @@ use table_row::TableRowFlow;
|
|||
use table_rowgroup::TableRowGroupFlow;
|
||||
use table_wrapper::TableWrapperFlow;
|
||||
use text::TextRunScanner;
|
||||
use wrapper::{PostorderNodeMutTraversal, PseudoElementType, TLayoutNode, ThreadSafeLayoutNode};
|
||||
use wrapper::{PostorderNodeMutTraversal, PseudoElementType, ThreadSafeLayoutNode};
|
||||
|
||||
use gfx::display_list::OpaqueNode;
|
||||
use script::dom::characterdata::CharacterDataTypeId;
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
use animation;
|
||||
use context::SharedLayoutContext;
|
||||
use css::node_style::StyledNode;
|
||||
use data::{LayoutDataAccess, LayoutDataWrapper};
|
||||
use data::LayoutDataWrapper;
|
||||
use incremental::{self, RestyleDamage};
|
||||
use opaque_node::OpaqueNodeMethods;
|
||||
use smallvec::SmallVec16;
|
||||
use wrapper::{LayoutElement, LayoutNode, TLayoutNode};
|
||||
use wrapper::{LayoutElement, LayoutNode};
|
||||
|
||||
use script::dom::characterdata::CharacterDataTypeId;
|
||||
use script::dom::node::NodeTypeId;
|
||||
|
@ -677,7 +677,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
|
|||
&mut None => panic!("no layout data"),
|
||||
&mut Some(ref mut layout_data) => {
|
||||
match self.type_id() {
|
||||
Some(NodeTypeId::CharacterData(CharacterDataTypeId::Text)) => {
|
||||
NodeTypeId::CharacterData(CharacterDataTypeId::Text) => {
|
||||
// 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
|
||||
|
|
|
@ -2,19 +2,14 @@
|
|||
* 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 construct::{ConstructionItem, ConstructionResult};
|
||||
use incremental::RestyleDamage;
|
||||
use msg::constellation_msg::ConstellationChan;
|
||||
use parallel::DomParallelInfo;
|
||||
use script::dom::node::SharedLayoutData;
|
||||
use script::layout_interface::LayoutChan;
|
||||
use std::cell::{Ref, RefMut};
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
use style::properties::ComputedValues;
|
||||
use wrapper::{LayoutNode, TLayoutNode};
|
||||
|
||||
/// Data that layout associates with a node.
|
||||
pub struct PrivateLayoutData {
|
||||
|
@ -95,41 +90,10 @@ impl LayoutDataWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[allow(dead_code, unsafe_code)]
|
||||
fn static_assertion(x: Option<LayoutDataWrapper>) {
|
||||
unsafe {
|
||||
let _: Option<::script::dom::node::LayoutData> =
|
||||
::std::intrinsics::transmute(x);
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait that allows access to the layout data of a DOM node.
|
||||
pub trait LayoutDataAccess {
|
||||
/// Borrows the layout data without checks.
|
||||
unsafe fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper>;
|
||||
/// Borrows the layout data immutably. Fails on a conflicting borrow.
|
||||
fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>>;
|
||||
/// Borrows the layout data mutably. Fails on a conflicting borrow.
|
||||
fn mutate_layout_data<'a>(&'a self) -> RefMut<'a,Option<LayoutDataWrapper>>;
|
||||
}
|
||||
|
||||
impl<'ln> LayoutDataAccess for LayoutNode<'ln> {
|
||||
#[inline(always)]
|
||||
unsafe fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper> {
|
||||
mem::transmute(self.get().layout_data_unchecked())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>> {
|
||||
unsafe {
|
||||
mem::transmute(self.get().layout_data())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn mutate_layout_data<'a>(&'a self) -> RefMut<'a,Option<LayoutDataWrapper>> {
|
||||
unsafe {
|
||||
mem::transmute(self.get().layout_data_mut())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ use layout_debug;
|
|||
use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, specified};
|
||||
use text;
|
||||
use opaque_node::OpaqueNodeMethods;
|
||||
use wrapper::{TLayoutNode, ThreadSafeLayoutNode};
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use euclid::{Point2D, Rect, Size2D};
|
||||
use gfx::display_list::{BLUR_INFLATION_FACTOR, OpaqueNode};
|
||||
|
|
|
@ -11,7 +11,7 @@ use animation;
|
|||
use construct::ConstructionResult;
|
||||
use context::{SharedLayoutContext, SharedLayoutContextWrapper, heap_size_of_local_context};
|
||||
use css::node_style::StyledNode;
|
||||
use data::{LayoutDataAccess, LayoutDataWrapper};
|
||||
use data::LayoutDataWrapper;
|
||||
use display_list_builder::ToGfxColor;
|
||||
use flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
|
||||
use flow_ref::FlowRef;
|
||||
|
@ -21,7 +21,7 @@ use layout_debug;
|
|||
use opaque_node::OpaqueNodeMethods;
|
||||
use parallel::{self, UnsafeFlow};
|
||||
use sequential;
|
||||
use wrapper::{LayoutNode, TLayoutNode};
|
||||
use wrapper::LayoutNode;
|
||||
|
||||
use azure::azure::AzColor;
|
||||
use canvas_traits::CanvasMsg;
|
||||
|
|
|
@ -10,7 +10,7 @@ use script::dom::bindings::js::LayoutJS;
|
|||
use script::dom::node::Node;
|
||||
use script::layout_interface::{TrustedNodeAddress};
|
||||
use script_traits::UntrustedNodeAddress;
|
||||
use wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode};
|
||||
use wrapper::{LayoutNode, ThreadSafeLayoutNode};
|
||||
|
||||
pub trait OpaqueNodeMethods {
|
||||
/// Converts a DOM node (layout view) to an `OpaqueNode`.
|
||||
|
|
|
@ -12,7 +12,7 @@ use context::{LayoutContext, SharedLayoutContextWrapper, SharedLayoutContext};
|
|||
use flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal};
|
||||
use flow;
|
||||
use flow_ref::FlowRef;
|
||||
use data::{LayoutDataAccess, LayoutDataWrapper};
|
||||
use data::LayoutDataWrapper;
|
||||
use traversal::{BubbleISizes, AssignISizes, AssignBSizesAndStoreOverflow};
|
||||
use traversal::{ComputeAbsolutePositions, BuildDisplayList};
|
||||
use traversal::{RecalcStyleForNode, ConstructFlows};
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
//!
|
||||
//! Rules of the road for this file:
|
||||
//!
|
||||
//! * You must not use `.get()`; instead, use `.unsafe_get()`.
|
||||
//!
|
||||
//! * Do not call any methods on DOM nodes without checking to see whether they use borrow flags.
|
||||
//!
|
||||
//! o Instead of `get_attr()`, use `.get_attr_val_for_layout()`.
|
||||
|
@ -36,7 +34,7 @@ use canvas_traits::CanvasMsg;
|
|||
use context::SharedLayoutContext;
|
||||
use css::node_style::StyledNode;
|
||||
use incremental::RestyleDamage;
|
||||
use data::{LayoutDataAccess, LayoutDataFlags, LayoutDataWrapper, PrivateLayoutData};
|
||||
use data::{LayoutDataFlags, LayoutDataWrapper, PrivateLayoutData};
|
||||
use opaque_node::OpaqueNodeMethods;
|
||||
|
||||
use gfx::display_list::OpaqueNode;
|
||||
|
@ -50,11 +48,10 @@ use script::dom::characterdata::{CharacterDataTypeId, LayoutCharacterDataHelpers
|
|||
use script::dom::element::{Element, ElementTypeId};
|
||||
use script::dom::element::{LayoutElementHelpers, RawLayoutElementHelpers};
|
||||
use script::dom::htmlelement::HTMLElementTypeId;
|
||||
use script::dom::htmlcanvaselement::{HTMLCanvasElement, LayoutHTMLCanvasElementHelpers};
|
||||
use script::dom::htmliframeelement::HTMLIFrameElement;
|
||||
use script::dom::htmlcanvaselement::LayoutHTMLCanvasElementHelpers;
|
||||
use script::dom::htmlimageelement::LayoutHTMLImageElementHelpers;
|
||||
use script::dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
|
||||
use script::dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
|
||||
use script::dom::htmltextareaelement::LayoutHTMLTextAreaElementHelpers;
|
||||
use script::dom::node::{Node, NodeTypeId};
|
||||
use script::dom::node::{LayoutNodeHelpers, RawLayoutNodeHelpers, SharedLayoutData};
|
||||
use script::dom::node::{HAS_CHANGED, IS_DIRTY, HAS_DIRTY_SIBLINGS, HAS_DIRTY_DESCENDANTS};
|
||||
|
@ -78,99 +75,6 @@ use style::node::{TElement, TElementAttributes, TNode};
|
|||
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use url::Url;
|
||||
|
||||
/// Allows some convenience methods on generic layout nodes.
|
||||
pub trait TLayoutNode {
|
||||
/// Creates a new layout node with the same lifetime as this layout node.
|
||||
unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> Self;
|
||||
|
||||
/// Returns the type ID of this node. Fails if this node is borrowed mutably. Returns `None`
|
||||
/// if this is a pseudo-element; otherwise, returns `Some`.
|
||||
fn type_id(&self) -> Option<NodeTypeId>;
|
||||
|
||||
/// Returns the interior of this node as a `LayoutJS`. This is highly unsafe for layout to
|
||||
/// call and as such is marked `unsafe`.
|
||||
unsafe fn get_jsmanaged<'a>(&'a self) -> &'a LayoutJS<Node>;
|
||||
|
||||
/// Returns the interior of this node as a `Node`. This is highly unsafe for layout to call
|
||||
/// and as such is marked `unsafe`.
|
||||
unsafe fn get<'a>(&'a self) -> &'a Node {
|
||||
&*self.get_jsmanaged().unsafe_get()
|
||||
}
|
||||
|
||||
fn node_is_element(&self) -> bool {
|
||||
match self.type_id() {
|
||||
Some(NodeTypeId::Element(..)) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn node_is_document(&self) -> bool {
|
||||
match self.type_id() {
|
||||
Some(NodeTypeId::Document(..)) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
/// If this is an image element, returns its URL. If this is not an image element, fails.
|
||||
///
|
||||
/// FIXME(pcwalton): Don't copy URLs.
|
||||
fn image_url(&self) -> Option<Url> {
|
||||
unsafe {
|
||||
match HTMLImageElementCast::to_layout_js(self.get_jsmanaged()) {
|
||||
Some(elem) => elem.image_url().as_ref().map(|url| (*url).clone()),
|
||||
None => panic!("not an image!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn renderer(&self) -> Option<Sender<CanvasMsg>> {
|
||||
unsafe {
|
||||
let canvas_element: Option<LayoutJS<HTMLCanvasElement>> =
|
||||
HTMLCanvasElementCast::to_layout_js(self.get_jsmanaged());
|
||||
canvas_element.and_then(|elem| elem.get_renderer())
|
||||
}
|
||||
}
|
||||
|
||||
fn canvas_width(&self) -> u32 {
|
||||
unsafe {
|
||||
let canvas_element: Option<LayoutJS<HTMLCanvasElement>> =
|
||||
HTMLCanvasElementCast::to_layout_js(self.get_jsmanaged());
|
||||
canvas_element.unwrap().get_canvas_width()
|
||||
}
|
||||
}
|
||||
|
||||
fn canvas_height(&self) -> u32 {
|
||||
unsafe {
|
||||
let canvas_element: Option<LayoutJS<HTMLCanvasElement>> =
|
||||
HTMLCanvasElementCast::to_layout_js(self.get_jsmanaged());
|
||||
canvas_element.unwrap().get_canvas_height()
|
||||
}
|
||||
}
|
||||
|
||||
/// If this node is an iframe element, returns its pipeline and subpage IDs. If this node is
|
||||
/// not an iframe element, fails.
|
||||
fn iframe_pipeline_and_subpage_ids(&self) -> (PipelineId, SubpageId) {
|
||||
unsafe {
|
||||
let iframe_element: LayoutJS<HTMLIFrameElement> =
|
||||
match HTMLIFrameElementCast::to_layout_js(self.get_jsmanaged()) {
|
||||
Some(elem) => elem,
|
||||
None => panic!("not an iframe element!")
|
||||
};
|
||||
((*iframe_element.unsafe_get()).containing_page_pipeline_id().unwrap(),
|
||||
(*iframe_element.unsafe_get()).subpage_id().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
/// If this is a text node or generated content, copies out its content. If this is not a text
|
||||
/// node, fails.
|
||||
///
|
||||
/// FIXME(pcwalton): This might have too much copying and/or allocation. Profile this.
|
||||
fn text_content(&self) -> Vec<ContentItem>;
|
||||
|
||||
/// Returns the first child of this node.
|
||||
fn first_child(&self) -> Option<Self>;
|
||||
}
|
||||
|
||||
/// 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`.
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -189,56 +93,22 @@ impl<'a> PartialEq for LayoutNode<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ln> TLayoutNode for LayoutNode<'ln> {
|
||||
unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> LayoutNode<'ln> {
|
||||
impl<'ln> LayoutNode<'ln> {
|
||||
/// Creates a new layout node with the same lifetime as this layout node.
|
||||
pub unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> LayoutNode<'ln> {
|
||||
LayoutNode {
|
||||
node: *node,
|
||||
chain: self.chain,
|
||||
}
|
||||
}
|
||||
|
||||
fn type_id(&self) -> Option<NodeTypeId> {
|
||||
/// Returns the type ID of this node.
|
||||
pub fn type_id(&self) -> NodeTypeId {
|
||||
unsafe {
|
||||
Some(self.node.type_id_for_layout())
|
||||
self.node.type_id_for_layout()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn get_jsmanaged<'a>(&'a self) -> &'a LayoutJS<Node> {
|
||||
&self.node
|
||||
}
|
||||
|
||||
fn first_child(&self) -> Option<LayoutNode<'ln>> {
|
||||
unsafe {
|
||||
self.get_jsmanaged().first_child_ref().map(|node| self.new_with_this_lifetime(&node))
|
||||
}
|
||||
}
|
||||
|
||||
fn text_content(&self) -> Vec<ContentItem> {
|
||||
unsafe {
|
||||
let text: Option<LayoutJS<Text>> = TextCast::to_layout_js(self.get_jsmanaged());
|
||||
if let Some(text) = text {
|
||||
return vec![
|
||||
ContentItem::String(
|
||||
CharacterDataCast::from_layout_js(&text).data_for_layout().to_owned())
|
||||
];
|
||||
}
|
||||
let input: Option<LayoutJS<HTMLInputElement>> =
|
||||
HTMLInputElementCast::to_layout_js(self.get_jsmanaged());
|
||||
if let Some(input) = input {
|
||||
return vec![ContentItem::String(input.get_value_for_layout())];
|
||||
}
|
||||
let area: Option<LayoutJS<HTMLTextAreaElement>> =
|
||||
HTMLTextAreaElementCast::to_layout_js(self.get_jsmanaged());
|
||||
if let Some(area) = area {
|
||||
return vec![ContentItem::String(area.get_value_for_layout())];
|
||||
}
|
||||
|
||||
panic!("not text!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ln> LayoutNode<'ln> {
|
||||
pub fn dump(self) {
|
||||
self.dump_indent(0);
|
||||
}
|
||||
|
@ -282,14 +152,8 @@ impl<'ln> LayoutNode<'ln> {
|
|||
|
||||
/// Returns an iterator over this node's children.
|
||||
pub fn children(self) -> LayoutNodeChildrenIterator<'ln> {
|
||||
// FIXME(zwarich): Remove this when UFCS lands and there is a better way
|
||||
// of disambiguating methods.
|
||||
fn first_child<T: TLayoutNode>(this: T) -> Option<T> {
|
||||
this.first_child()
|
||||
}
|
||||
|
||||
LayoutNodeChildrenIterator {
|
||||
current: first_child(self),
|
||||
current: self.first_child(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -300,6 +164,8 @@ impl<'ln> LayoutNode<'ln> {
|
|||
|
||||
}
|
||||
|
||||
/// Returns the interior of this node as a `LayoutJS`. This is highly unsafe for layout to
|
||||
/// call and as such is marked `unsafe`.
|
||||
pub unsafe fn get_jsmanaged<'a>(&'a self) -> &'a LayoutJS<Node> {
|
||||
&self.node
|
||||
}
|
||||
|
@ -322,7 +188,7 @@ impl<'ln> LayoutNode<'ln> {
|
|||
}
|
||||
|
||||
pub fn has_children(self) -> bool {
|
||||
TLayoutNode::first_child(&self).is_some()
|
||||
self.first_child().is_some()
|
||||
}
|
||||
|
||||
/// While doing a reflow, the node at the root has no parent, as far as we're
|
||||
|
@ -396,11 +262,17 @@ impl<'ln> TNode for LayoutNode<'ln> {
|
|||
}
|
||||
|
||||
fn is_element(&self) -> bool {
|
||||
self.node_is_element()
|
||||
match self.type_id() {
|
||||
NodeTypeId::Element(..) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_document(&self) -> bool {
|
||||
self.node_is_document()
|
||||
match self.type_id() {
|
||||
NodeTypeId::Document(..) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool where F: Fn(&str) -> bool {
|
||||
|
@ -460,6 +332,28 @@ impl<'ln> LayoutNode<'ln> {
|
|||
pub unsafe fn set_dirty_descendants(&self, value: bool) {
|
||||
self.node.set_flag(HAS_DIRTY_DESCENDANTS, value)
|
||||
}
|
||||
|
||||
/// Borrows the layout data without checks.
|
||||
#[inline(always)]
|
||||
pub unsafe fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper> {
|
||||
mem::transmute(self.get_jsmanaged().layout_data_unchecked())
|
||||
}
|
||||
|
||||
/// Borrows the layout data immutably. Fails on a conflicting borrow.
|
||||
#[inline(always)]
|
||||
pub fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>> {
|
||||
unsafe {
|
||||
mem::transmute(self.get_jsmanaged().layout_data())
|
||||
}
|
||||
}
|
||||
|
||||
/// Borrows the layout data mutably. Fails on a conflicting borrow.
|
||||
#[inline(always)]
|
||||
pub fn mutate_layout_data<'a>(&'a self) -> RefMut<'a,Option<LayoutDataWrapper>> {
|
||||
unsafe {
|
||||
mem::transmute(self.get_jsmanaged().layout_data_mut())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LayoutNodeChildrenIterator<'a> {
|
||||
|
@ -718,76 +612,15 @@ pub struct ThreadSafeLayoutNode<'ln> {
|
|||
pseudo: PseudoElementType,
|
||||
}
|
||||
|
||||
impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> {
|
||||
impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||
/// Creates a new layout node with the same lifetime as this layout node.
|
||||
unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> ThreadSafeLayoutNode<'ln> {
|
||||
pub unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> ThreadSafeLayoutNode<'ln> {
|
||||
ThreadSafeLayoutNode {
|
||||
node: self.node.new_with_this_lifetime(node),
|
||||
pseudo: PseudoElementType::Normal,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `None` if this is a pseudo-element.
|
||||
fn type_id(&self) -> Option<NodeTypeId> {
|
||||
if self.pseudo != PseudoElementType::Normal {
|
||||
return None
|
||||
}
|
||||
|
||||
self.node.type_id()
|
||||
}
|
||||
|
||||
unsafe fn get_jsmanaged<'a>(&'a self) -> &'a LayoutJS<Node> {
|
||||
self.node.get_jsmanaged()
|
||||
}
|
||||
|
||||
unsafe fn get<'a>(&'a self) -> &'a Node { // this change.
|
||||
&*self.get_jsmanaged().unsafe_get()
|
||||
}
|
||||
|
||||
fn first_child(&self) -> Option<ThreadSafeLayoutNode<'ln>> {
|
||||
if self.pseudo != PseudoElementType::Normal {
|
||||
return None
|
||||
}
|
||||
|
||||
if self.has_before_pseudo() {
|
||||
// FIXME(pcwalton): This logic looks weird. Is it right?
|
||||
match self.pseudo {
|
||||
PseudoElementType::Normal => {
|
||||
let pseudo_before_node = self.with_pseudo(PseudoElementType::Before(self.get_before_display()));
|
||||
return Some(pseudo_before_node)
|
||||
}
|
||||
PseudoElementType::Before(display::T::inline) => {}
|
||||
PseudoElementType::Before(_) => {
|
||||
let pseudo_before_node = self.with_pseudo(PseudoElementType::Before(display::T::inline));
|
||||
return Some(pseudo_before_node)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
self.get_jsmanaged().first_child_ref().map(|node| self.new_with_this_lifetime(&node))
|
||||
}
|
||||
}
|
||||
|
||||
fn text_content(&self) -> Vec<ContentItem> {
|
||||
if self.pseudo != PseudoElementType::Normal {
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
|
||||
|
||||
if self.pseudo.is_before() {
|
||||
let before_style = node_layout_data_wrapper.data.before_style.as_ref().unwrap();
|
||||
return get_content(&before_style.get_box().content)
|
||||
} else {
|
||||
let after_style = node_layout_data_wrapper.data.after_style.as_ref().unwrap();
|
||||
return get_content(&after_style.get_box().content)
|
||||
}
|
||||
}
|
||||
self.node.text_content()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||
/// Creates a new `ThreadSafeLayoutNode` from the given `LayoutNode`.
|
||||
pub fn new<'a>(node: &LayoutNode<'a>) -> ThreadSafeLayoutNode<'a> {
|
||||
ThreadSafeLayoutNode {
|
||||
|
@ -805,6 +638,22 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the interior of this node as a `LayoutJS`. This is highly unsafe for layout to
|
||||
/// call and as such is marked `unsafe`.
|
||||
pub unsafe fn get_jsmanaged<'a>(&'a self) -> &'a LayoutJS<Node> {
|
||||
self.node.get_jsmanaged()
|
||||
}
|
||||
|
||||
/// Returns the type ID of this node.
|
||||
/// Returns `None` if this is a pseudo-element; otherwise, returns `Some`.
|
||||
pub fn type_id(&self) -> Option<NodeTypeId> {
|
||||
if self.pseudo != PseudoElementType::Normal {
|
||||
return None
|
||||
}
|
||||
|
||||
Some(self.node.type_id())
|
||||
}
|
||||
|
||||
pub fn debug_id(self) -> usize {
|
||||
self.node.debug_id()
|
||||
}
|
||||
|
@ -813,6 +662,20 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
|||
self.node.flow_debug_id()
|
||||
}
|
||||
|
||||
fn first_child(&self) -> Option<ThreadSafeLayoutNode<'ln>> {
|
||||
if self.pseudo != PseudoElementType::Normal {
|
||||
return None
|
||||
}
|
||||
|
||||
if self.has_before_pseudo() {
|
||||
return Some(self.with_pseudo(PseudoElementType::Before(self.get_before_display())));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
self.get_jsmanaged().first_child_ref().map(|node| self.new_with_this_lifetime(&node))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the next sibling of this node. Unsafe and private because this can lead to races.
|
||||
unsafe fn next_sibling(&self) -> Option<ThreadSafeLayoutNode<'ln>> {
|
||||
if self.pseudo.is_before() {
|
||||
|
@ -889,11 +752,11 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
|||
layout_data_wrapper_ref.data.after_style.is_some()
|
||||
}
|
||||
|
||||
/// Borrows the layout data without checking. Fails on a conflicting borrow.
|
||||
/// Borrows the layout data without checking.
|
||||
#[inline(always)]
|
||||
fn borrow_layout_data_unchecked<'a>(&'a self) -> *const Option<LayoutDataWrapper> {
|
||||
unsafe {
|
||||
mem::transmute(self.get().layout_data_unchecked())
|
||||
self.node.borrow_layout_data_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -902,9 +765,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
|||
/// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases.
|
||||
#[inline(always)]
|
||||
pub fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>> {
|
||||
unsafe {
|
||||
mem::transmute(self.get().layout_data())
|
||||
}
|
||||
self.node.borrow_layout_data()
|
||||
}
|
||||
|
||||
/// Borrows the layout data mutably. Fails on a conflicting borrow.
|
||||
|
@ -912,9 +773,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
|||
/// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases.
|
||||
#[inline(always)]
|
||||
pub fn mutate_layout_data<'a>(&'a self) -> RefMut<'a,Option<LayoutDataWrapper>> {
|
||||
unsafe {
|
||||
mem::transmute(self.get().layout_data_mut())
|
||||
}
|
||||
self.node.mutate_layout_data()
|
||||
}
|
||||
|
||||
/// Traverses the tree in postorder.
|
||||
|
@ -1052,6 +911,89 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
|||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
/// If this is a text node, generated content, or a form element, copies out
|
||||
/// its content. Otherwise, panics.
|
||||
///
|
||||
/// FIXME(pcwalton): This might have too much copying and/or allocation. Profile this.
|
||||
pub fn text_content(&self) -> Vec<ContentItem> {
|
||||
if self.pseudo != PseudoElementType::Normal {
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
|
||||
|
||||
if self.pseudo.is_before() {
|
||||
let before_style = node_layout_data_wrapper.data.before_style.as_ref().unwrap();
|
||||
return get_content(&before_style.get_box().content)
|
||||
} else {
|
||||
let after_style = node_layout_data_wrapper.data.after_style.as_ref().unwrap();
|
||||
return get_content(&after_style.get_box().content)
|
||||
}
|
||||
}
|
||||
|
||||
let this = unsafe { self.get_jsmanaged() };
|
||||
let text = TextCast::to_layout_js(this);
|
||||
if let Some(text) = text {
|
||||
let data = unsafe {
|
||||
CharacterDataCast::from_layout_js(&text).data_for_layout().to_owned()
|
||||
};
|
||||
return vec![ContentItem::String(data)];
|
||||
}
|
||||
let input = HTMLInputElementCast::to_layout_js(this);
|
||||
if let Some(input) = input {
|
||||
let data = unsafe { input.get_value_for_layout() };
|
||||
return vec![ContentItem::String(data)];
|
||||
}
|
||||
let area = HTMLTextAreaElementCast::to_layout_js(this);
|
||||
if let Some(area) = area {
|
||||
let data = unsafe { area.get_value_for_layout() };
|
||||
return vec![ContentItem::String(data)];
|
||||
}
|
||||
|
||||
panic!("not text!")
|
||||
}
|
||||
|
||||
/// If this is an image element, returns its URL. If this is not an image element, fails.
|
||||
///
|
||||
/// FIXME(pcwalton): Don't copy URLs.
|
||||
pub fn image_url(&self) -> Option<Url> {
|
||||
unsafe {
|
||||
HTMLImageElementCast::to_layout_js(self.get_jsmanaged())
|
||||
.expect("not an image!")
|
||||
.image_url()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn renderer(&self) -> Option<Sender<CanvasMsg>> {
|
||||
unsafe {
|
||||
let canvas_element = HTMLCanvasElementCast::to_layout_js(self.get_jsmanaged());
|
||||
canvas_element.and_then(|elem| elem.get_renderer())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn canvas_width(&self) -> u32 {
|
||||
unsafe {
|
||||
let canvas_element = HTMLCanvasElementCast::to_layout_js(self.get_jsmanaged());
|
||||
canvas_element.unwrap().get_canvas_width()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn canvas_height(&self) -> u32 {
|
||||
unsafe {
|
||||
let canvas_element = HTMLCanvasElementCast::to_layout_js(self.get_jsmanaged());
|
||||
canvas_element.unwrap().get_canvas_height()
|
||||
}
|
||||
}
|
||||
|
||||
/// If this node is an iframe element, returns its pipeline and subpage IDs. If this node is
|
||||
/// not an iframe element, fails.
|
||||
pub fn iframe_pipeline_and_subpage_ids(&self) -> (PipelineId, SubpageId) {
|
||||
unsafe {
|
||||
let iframe_element = HTMLIFrameElementCast::to_layout_js(self.get_jsmanaged())
|
||||
.expect("not an iframe element!");
|
||||
((*iframe_element.unsafe_get()).containing_page_pipeline_id().unwrap(),
|
||||
(*iframe_element.unsafe_get()).subpage_id().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ThreadSafeLayoutNodeChildrenIterator<'a> {
|
||||
|
@ -1137,7 +1079,7 @@ pub trait PostorderNodeMutTraversal {
|
|||
}
|
||||
|
||||
/// Opaque type stored in type-unsafe work queues for parallel layout.
|
||||
/// Must be transmutable to and from LayoutNode/ThreadSafeLayoutNode.
|
||||
/// Must be transmutable to and from LayoutNode.
|
||||
pub type UnsafeLayoutNode = (usize, usize);
|
||||
|
||||
pub fn layout_node_to_unsafe_layout_node(node: &LayoutNode) -> UnsafeLayoutNode {
|
||||
|
|
|
@ -53,6 +53,7 @@ use script_traits::UntrustedNodeAddress;
|
|||
use util::geometry::Au;
|
||||
use util::namespace;
|
||||
use util::str::DOMString;
|
||||
use util::task_state;
|
||||
use selectors::parser::{Selector, AttrSelector, NamespaceConstraint};
|
||||
use selectors::parser::parse_author_origin_selector_list_from_str;
|
||||
use selectors::matching::matches;
|
||||
|
@ -222,7 +223,7 @@ pub struct LayoutData {
|
|||
unsafe impl Send for LayoutData {}
|
||||
|
||||
pub struct LayoutDataRef {
|
||||
pub data_cell: RefCell<Option<LayoutData>>,
|
||||
data_cell: RefCell<Option<LayoutData>>,
|
||||
}
|
||||
|
||||
no_jsmanaged_fields!(LayoutDataRef);
|
||||
|
@ -236,7 +237,8 @@ impl LayoutDataRef {
|
|||
|
||||
/// Sends layout data, if any, back to the layout task to be destroyed.
|
||||
pub fn dispose(&self) {
|
||||
if let Some(mut layout_data) = mem::replace(&mut *self.borrow_mut(), None) {
|
||||
debug_assert!(task_state::get().is_script());
|
||||
if let Some(mut layout_data) = mem::replace(&mut *self.data_cell.borrow_mut(), None) {
|
||||
let layout_chan = layout_data.chan.take();
|
||||
match layout_chan {
|
||||
None => {}
|
||||
|
@ -248,18 +250,20 @@ impl LayoutDataRef {
|
|||
}
|
||||
}
|
||||
|
||||
/// Borrows the layout data immutably, *asserting that there are no mutators*. Bad things will
|
||||
/// 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<'a>(&'a self) -> Ref<'a,Option<LayoutData>> {
|
||||
debug_assert!(task_state::get().is_layout());
|
||||
self.data_cell.borrow()
|
||||
}
|
||||
|
||||
|
@ -270,6 +274,7 @@ impl LayoutDataRef {
|
|||
/// on it. This has already resulted in one bug!
|
||||
#[inline]
|
||||
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a,Option<LayoutData>> {
|
||||
debug_assert!(task_state::get().is_layout());
|
||||
self.data_cell.borrow_mut()
|
||||
}
|
||||
}
|
||||
|
@ -1086,6 +1091,13 @@ pub trait LayoutNodeHelpers {
|
|||
unsafe fn get_flag(&self, flag: NodeFlags) -> bool;
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn set_flag(&self, flag: NodeFlags, value: bool);
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn layout_data(&self) -> Ref<Option<LayoutData>>;
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn layout_data_mut(&self) -> RefMut<Option<LayoutData>>;
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn layout_data_unchecked(&self) -> *const Option<LayoutData>;
|
||||
}
|
||||
|
||||
impl LayoutNodeHelpers for LayoutJS<Node> {
|
||||
|
@ -1157,6 +1169,24 @@ impl LayoutNodeHelpers for LayoutJS<Node> {
|
|||
|
||||
(*this).flags.set(flags);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn layout_data(&self) -> Ref<Option<LayoutData>> {
|
||||
(*self.unsafe_get()).layout_data.borrow()
|
||||
}
|
||||
|
||||
#[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()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RawLayoutNodeHelpers {
|
||||
|
@ -1456,22 +1486,6 @@ impl Node {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn layout_data(&self) -> Ref<Option<LayoutData>> {
|
||||
self.layout_data.borrow()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn layout_data_mut(&self) -> RefMut<Option<LayoutData>> {
|
||||
self.layout_data.borrow_mut()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(unsafe_code)]
|
||||
pub unsafe fn layout_data_unchecked(&self) -> *const Option<LayoutData> {
|
||||
self.layout_data.borrow_unchecked()
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#concept-node-adopt
|
||||
pub fn adopt(node: &Node, document: &Document) {
|
||||
// Step 1.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue