mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
Auto merge of #11754 - Ms2ger:wrapper-traits-prep2, r=nox
Move ServoLayoutNode and related structs to script. <!-- Reviewable:start --> This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/11754) <!-- Reviewable:end -->
This commit is contained in:
commit
ee8c5c5a67
51 changed files with 2215 additions and 1840 deletions
|
@ -11,6 +11,8 @@ use std::cmp::{Ordering, PartialOrd};
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use std::{fmt, mem, u16};
|
use std::{fmt, mem, u16};
|
||||||
|
|
||||||
|
pub use gfx_traits::ByteIndex;
|
||||||
|
|
||||||
/// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly.
|
/// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly.
|
||||||
///
|
///
|
||||||
/// In the common case (reasonable glyph advances, no offsets from the font em-box, and one glyph
|
/// In the common case (reasonable glyph advances, no offsets from the font em-box, and one glyph
|
||||||
|
@ -426,14 +428,6 @@ pub struct GlyphStore {
|
||||||
is_rtl: bool,
|
is_rtl: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
int_range_index! {
|
|
||||||
#[derive(Deserialize, Serialize, RustcEncodable)]
|
|
||||||
#[doc = "An index that refers to a byte offset in a text run. This could \
|
|
||||||
point to the middle of a glyph."]
|
|
||||||
#[derive(HeapSizeOf)]
|
|
||||||
struct ByteIndex(isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> GlyphStore {
|
impl<'a> GlyphStore {
|
||||||
/// Initializes the glyph store, but doesn't actually shape anything.
|
/// Initializes the glyph store, but doesn't actually shape anything.
|
||||||
///
|
///
|
||||||
|
|
|
@ -13,6 +13,8 @@ azure = {git = "https://github.com/servo/rust-azure", features = ["plugins"]}
|
||||||
layers = {git = "https://github.com/servo/rust-layers", features = ["plugins"]}
|
layers = {git = "https://github.com/servo/rust-layers", features = ["plugins"]}
|
||||||
msg = {path = "../msg"}
|
msg = {path = "../msg"}
|
||||||
plugins = {path = "../plugins"}
|
plugins = {path = "../plugins"}
|
||||||
|
range = {path = "../range"}
|
||||||
|
rustc-serialize = "0.3"
|
||||||
euclid = {version = "0.6.5", features = ["plugins"]}
|
euclid = {version = "0.6.5", features = ["plugins"]}
|
||||||
heapsize = "0.3.0"
|
heapsize = "0.3.0"
|
||||||
heapsize_plugin = "0.1.2"
|
heapsize_plugin = "0.1.2"
|
||||||
|
|
|
@ -15,6 +15,9 @@ extern crate euclid;
|
||||||
extern crate heapsize;
|
extern crate heapsize;
|
||||||
extern crate layers;
|
extern crate layers;
|
||||||
extern crate msg;
|
extern crate msg;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate range;
|
||||||
|
extern crate rustc_serialize;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
|
||||||
pub mod color;
|
pub mod color;
|
||||||
|
@ -25,6 +28,7 @@ use azure::azure_hl::Color;
|
||||||
use euclid::Matrix4D;
|
use euclid::Matrix4D;
|
||||||
use euclid::rect::Rect;
|
use euclid::rect::Rect;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
|
use range::RangeIndex;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
|
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
@ -255,3 +259,10 @@ impl FragmentType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int_range_index! {
|
||||||
|
#[derive(Deserialize, Serialize, RustcEncodable)]
|
||||||
|
#[doc = "An index that refers to a byte offset in a text run. This could \
|
||||||
|
point to the middle of a glyph."]
|
||||||
|
#[derive(HeapSizeOf)]
|
||||||
|
struct ByteIndex(isize)
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ profile_traits = {path = "../profile_traits"}
|
||||||
range = {path = "../range"}
|
range = {path = "../range"}
|
||||||
rustc-serialize = "0.3"
|
rustc-serialize = "0.3"
|
||||||
script = {path = "../script"}
|
script = {path = "../script"}
|
||||||
|
script_layout_interface = {path = "../script_layout_interface"}
|
||||||
script_traits = {path = "../script_traits"}
|
script_traits = {path = "../script_traits"}
|
||||||
selectors = {version = "0.6", features = ["heap_size"]}
|
selectors = {version = "0.6", features = ["heap_size"]}
|
||||||
serde_json = "0.7"
|
serde_json = "0.7"
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
|
|
||||||
use flow::{self, Flow};
|
use flow::{self, Flow};
|
||||||
use gfx::display_list::OpaqueNode;
|
use gfx::display_list::OpaqueNode;
|
||||||
use incremental::RestyleDamage;
|
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
|
use script_layout_interface::restyle_damage::RestyleDamage;
|
||||||
use script_traits::{AnimationState, LayoutMsg as ConstellationMsg};
|
use script_traits::{AnimationState, LayoutMsg as ConstellationMsg};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
|
|
|
@ -45,12 +45,12 @@ use fragment::SpecificFragmentInfo;
|
||||||
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, HAS_LAYER, Overflow};
|
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, HAS_LAYER, Overflow};
|
||||||
use gfx::display_list::{ClippingRegion, StackingContext};
|
use gfx::display_list::{ClippingRegion, StackingContext};
|
||||||
use gfx_traits::{LayerId, StackingContextId};
|
use gfx_traits::{LayerId, StackingContextId};
|
||||||
use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT};
|
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
use layout_thread::DISPLAY_PORT_SIZE_FACTOR;
|
use layout_thread::DISPLAY_PORT_SIZE_FACTOR;
|
||||||
use model::{CollapsibleMargins, MaybeAuto, specified, specified_or_none};
|
use model::{CollapsibleMargins, MaybeAuto, specified, specified_or_none};
|
||||||
use model::{self, IntrinsicISizes, MarginCollapseInfo};
|
use model::{self, IntrinsicISizes, MarginCollapseInfo};
|
||||||
use rustc_serialize::{Encodable, Encoder};
|
use rustc_serialize::{Encodable, Encoder};
|
||||||
|
use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT};
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
|
@ -28,15 +28,14 @@ use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo};
|
||||||
use fragment::{InlineAbsoluteHypotheticalFragmentInfo, TableColumnFragmentInfo};
|
use fragment::{InlineAbsoluteHypotheticalFragmentInfo, TableColumnFragmentInfo};
|
||||||
use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo};
|
use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo};
|
||||||
use gfx::display_list::OpaqueNode;
|
use gfx::display_list::OpaqueNode;
|
||||||
use incremental::{BUBBLE_ISIZES, RECONSTRUCT_FLOW, RestyleDamage};
|
|
||||||
use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, InlineFragmentNodeFlags};
|
use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, InlineFragmentNodeFlags};
|
||||||
use inline::{InlineFragmentNodeInfo, LAST_FRAGMENT_OF_ELEMENT};
|
use inline::{InlineFragmentNodeInfo, LAST_FRAGMENT_OF_ELEMENT};
|
||||||
use list_item::{ListItemFlow, ListStyleTypeContent};
|
use list_item::{ListItemFlow, ListStyleTypeContent};
|
||||||
use multicol::{MulticolFlow, MulticolColumnFlow};
|
use multicol::{MulticolFlow, MulticolColumnFlow};
|
||||||
use parallel;
|
use parallel;
|
||||||
use script::layout_interface::is_image_data;
|
use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, RECONSTRUCT_FLOW, RestyleDamage};
|
||||||
use script::layout_interface::{CharacterDataTypeId, ElementTypeId};
|
use script_layout_interface::wrapper_traits::{ThreadSafeLayoutNode, PseudoElementType, ThreadSafeLayoutElement};
|
||||||
use script::layout_interface::{HTMLElementTypeId, NodeTypeId};
|
use script_layout_interface::{LayoutNodeType, LayoutElementType, is_image_data};
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::collections::LinkedList;
|
use std::collections::LinkedList;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
@ -60,7 +59,7 @@ use traversal::PostorderNodeMutTraversal;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util::linked_list;
|
use util::linked_list;
|
||||||
use util::opts;
|
use util::opts;
|
||||||
use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
use wrapper::{TextContent, ThreadSafeLayoutNodeHelpers};
|
||||||
|
|
||||||
/// The results of flow construction for a DOM node.
|
/// The results of flow construction for a DOM node.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -303,44 +302,35 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
|
||||||
/// Builds the fragment for the given block or subclass thereof.
|
/// Builds the fragment for the given block or subclass thereof.
|
||||||
fn build_fragment_for_block(&mut self, node: &ConcreteThreadSafeLayoutNode) -> Fragment {
|
fn build_fragment_for_block(&mut self, node: &ConcreteThreadSafeLayoutNode) -> Fragment {
|
||||||
let specific_fragment_info = match node.type_id() {
|
let specific_fragment_info = match node.type_id() {
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
Some(LayoutNodeType::Element(LayoutElementType::HTMLIFrameElement)) => {
|
||||||
HTMLElementTypeId::HTMLIFrameElement))) => {
|
|
||||||
SpecificFragmentInfo::Iframe(IframeFragmentInfo::new(node))
|
SpecificFragmentInfo::Iframe(IframeFragmentInfo::new(node))
|
||||||
}
|
}
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
Some(LayoutNodeType::Element(LayoutElementType::HTMLImageElement)) => {
|
||||||
HTMLElementTypeId::HTMLImageElement))) => {
|
|
||||||
let image_info = box ImageFragmentInfo::new(node,
|
let image_info = box ImageFragmentInfo::new(node,
|
||||||
node.image_url(),
|
node.image_url(),
|
||||||
&self.layout_context);
|
&self.layout_context);
|
||||||
SpecificFragmentInfo::Image(image_info)
|
SpecificFragmentInfo::Image(image_info)
|
||||||
}
|
}
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
Some(LayoutNodeType::Element(LayoutElementType::HTMLObjectElement)) => {
|
||||||
HTMLElementTypeId::HTMLObjectElement))) => {
|
|
||||||
let image_info = box ImageFragmentInfo::new(node,
|
let image_info = box ImageFragmentInfo::new(node,
|
||||||
node.object_data(),
|
node.object_data(),
|
||||||
&self.layout_context);
|
&self.layout_context);
|
||||||
SpecificFragmentInfo::Image(image_info)
|
SpecificFragmentInfo::Image(image_info)
|
||||||
}
|
}
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
Some(LayoutNodeType::Element(LayoutElementType::HTMLTableElement)) => {
|
||||||
HTMLElementTypeId::HTMLTableElement))) => {
|
|
||||||
SpecificFragmentInfo::TableWrapper
|
SpecificFragmentInfo::TableWrapper
|
||||||
}
|
}
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
Some(LayoutNodeType::Element(LayoutElementType::HTMLTableColElement)) => {
|
||||||
HTMLElementTypeId::HTMLTableColElement))) => {
|
|
||||||
SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node))
|
SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node))
|
||||||
}
|
}
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
Some(LayoutNodeType::Element(LayoutElementType::HTMLTableCellElement)) => {
|
||||||
HTMLElementTypeId::HTMLTableCellElement(_)))) => {
|
|
||||||
SpecificFragmentInfo::TableCell
|
SpecificFragmentInfo::TableCell
|
||||||
}
|
}
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
Some(LayoutNodeType::Element(LayoutElementType::HTMLTableRowElement)) |
|
||||||
HTMLElementTypeId::HTMLTableRowElement))) |
|
Some(LayoutNodeType::Element(LayoutElementType::HTMLTableSectionElement)) => {
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
|
||||||
HTMLElementTypeId::HTMLTableSectionElement))) => {
|
|
||||||
SpecificFragmentInfo::TableRow
|
SpecificFragmentInfo::TableRow
|
||||||
}
|
}
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
Some(LayoutNodeType::Element(LayoutElementType::HTMLCanvasElement)) => {
|
||||||
HTMLElementTypeId::HTMLCanvasElement))) => {
|
|
||||||
let data = node.canvas_data().unwrap();
|
let data = node.canvas_data().unwrap();
|
||||||
SpecificFragmentInfo::Canvas(box CanvasFragmentInfo::new(node, data, self.layout_context))
|
SpecificFragmentInfo::Canvas(box CanvasFragmentInfo::new(node, data, self.layout_context))
|
||||||
}
|
}
|
||||||
|
@ -689,16 +679,13 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let mut initial_fragments = IntermediateInlineFragments::new();
|
let mut initial_fragments = IntermediateInlineFragments::new();
|
||||||
let node_is_input_or_text_area =
|
let node_is_input_or_text_area =
|
||||||
node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
node.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLInputElement)) ||
|
||||||
HTMLElementTypeId::HTMLInputElement))) ||
|
node.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLTextAreaElement));
|
||||||
node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
|
||||||
HTMLElementTypeId::HTMLTextAreaElement)));
|
|
||||||
if node.get_pseudo_element_type().is_replaced_content() ||
|
if node.get_pseudo_element_type().is_replaced_content() ||
|
||||||
node_is_input_or_text_area {
|
node_is_input_or_text_area {
|
||||||
// A TextArea's text contents are displayed through the input text
|
// A TextArea's text contents are displayed through the input text
|
||||||
// box, so don't construct them.
|
// box, so don't construct them.
|
||||||
if node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
if node.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLTextAreaElement)) {
|
||||||
HTMLElementTypeId::HTMLTextAreaElement))) {
|
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
self.set_flow_construction_result(&kid, ConstructionResult::None)
|
self.set_flow_construction_result(&kid, ConstructionResult::None)
|
||||||
}
|
}
|
||||||
|
@ -970,7 +957,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
|
||||||
// fragment that needs to be generated for this inline node.
|
// fragment that needs to be generated for this inline node.
|
||||||
let mut fragments = IntermediateInlineFragments::new();
|
let mut fragments = IntermediateInlineFragments::new();
|
||||||
match (node.get_pseudo_element_type(), node.type_id()) {
|
match (node.get_pseudo_element_type(), node.type_id()) {
|
||||||
(_, Some(NodeTypeId::CharacterData(CharacterDataTypeId::Text))) => {
|
(_, Some(LayoutNodeType::Text)) => {
|
||||||
self.create_fragments_for_node_text_content(&mut fragments, node, &style)
|
self.create_fragments_for_node_text_content(&mut fragments, node, &style)
|
||||||
}
|
}
|
||||||
(PseudoElementType::Normal, _) => {
|
(PseudoElementType::Normal, _) => {
|
||||||
|
@ -1524,7 +1511,7 @@ impl<'a, ConcreteThreadSafeLayoutNode> PostorderNodeMutTraversal<ConcreteThreadS
|
||||||
};
|
};
|
||||||
(display, style.get_box().float, style.get_box().position)
|
(display, style.get_box().float, style.get_box().position)
|
||||||
}
|
}
|
||||||
Some(NodeTypeId::Element(_)) => {
|
Some(LayoutNodeType::Element(_)) => {
|
||||||
let style = node.style(self.style_context());
|
let style = node.style(self.style_context());
|
||||||
let original_display = style.get_box()._servo_display_for_hypothetical_box;
|
let original_display = style.get_box()._servo_display_for_hypothetical_box;
|
||||||
let munged_display = match original_display {
|
let munged_display = match original_display {
|
||||||
|
@ -1533,13 +1520,13 @@ impl<'a, ConcreteThreadSafeLayoutNode> PostorderNodeMutTraversal<ConcreteThreadS
|
||||||
};
|
};
|
||||||
(munged_display, style.get_box().float, style.get_box().position)
|
(munged_display, style.get_box().float, style.get_box().position)
|
||||||
}
|
}
|
||||||
Some(NodeTypeId::CharacterData(CharacterDataTypeId::Text)) =>
|
Some(LayoutNodeType::Text) =>
|
||||||
(display::T::inline, float::T::none, position::T::static_),
|
(display::T::inline, float::T::none, position::T::static_),
|
||||||
Some(NodeTypeId::CharacterData(CharacterDataTypeId::Comment)) |
|
Some(LayoutNodeType::Comment) |
|
||||||
Some(NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)) |
|
Some(LayoutNodeType::ProcessingInstruction) |
|
||||||
Some(NodeTypeId::DocumentType) |
|
Some(LayoutNodeType::DocumentType) |
|
||||||
Some(NodeTypeId::DocumentFragment) |
|
Some(LayoutNodeType::DocumentFragment) |
|
||||||
Some(NodeTypeId::Document(_)) => {
|
Some(LayoutNodeType::Document) => {
|
||||||
(display::T::none, float::T::none, position::T::static_)
|
(display::T::none, float::T::none, position::T::static_)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1678,19 +1665,17 @@ impl<ConcreteThreadSafeLayoutNode> NodeUtils for ConcreteThreadSafeLayoutNode
|
||||||
where ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode {
|
where ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode {
|
||||||
fn is_replaced_content(&self) -> bool {
|
fn is_replaced_content(&self) -> bool {
|
||||||
match self.type_id() {
|
match self.type_id() {
|
||||||
Some(NodeTypeId::CharacterData(_)) |
|
Some(LayoutNodeType::Comment) |
|
||||||
Some(NodeTypeId::DocumentType) |
|
Some(LayoutNodeType::ProcessingInstruction) |
|
||||||
Some(NodeTypeId::DocumentFragment) |
|
Some(LayoutNodeType::Text) |
|
||||||
Some(NodeTypeId::Document(_)) |
|
Some(LayoutNodeType::DocumentType) |
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
Some(LayoutNodeType::DocumentFragment) |
|
||||||
HTMLElementTypeId::HTMLImageElement))) |
|
Some(LayoutNodeType::Document) |
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
Some(LayoutNodeType::Element(LayoutElementType::HTMLImageElement)) |
|
||||||
HTMLElementTypeId::HTMLIFrameElement))) |
|
Some(LayoutNodeType::Element(LayoutElementType::HTMLIFrameElement)) |
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
Some(LayoutNodeType::Element(LayoutElementType::HTMLCanvasElement)) => true,
|
||||||
HTMLElementTypeId::HTMLCanvasElement))) => true,
|
Some(LayoutNodeType::Element(LayoutElementType::HTMLObjectElement)) => self.has_object_data(),
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
Some(LayoutNodeType::Element(_)) => false,
|
||||||
HTMLElementTypeId::HTMLObjectElement))) => self.has_object_data(),
|
|
||||||
Some(NodeTypeId::Element(_)) => false,
|
|
||||||
None => self.get_pseudo_element_type().is_replaced_content(),
|
None => self.get_pseudo_element_type().is_replaced_content(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use construct::ConstructionResult;
|
use construct::ConstructionResult;
|
||||||
use incremental::RestyleDamage;
|
use script_layout_interface::restyle_damage::RestyleDamage;
|
||||||
use style::servo::PrivateStyleData;
|
use style::servo::PrivateStyleData;
|
||||||
|
|
||||||
/// Data that layout associates with a node.
|
/// Data that layout associates with a node.
|
||||||
|
|
|
@ -19,9 +19,9 @@ use flow_ref::{self, FlowRef};
|
||||||
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
||||||
use gfx::display_list::StackingContext;
|
use gfx::display_list::StackingContext;
|
||||||
use gfx_traits::StackingContextId;
|
use gfx_traits::StackingContextId;
|
||||||
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
|
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
use model::{IntrinsicISizes, MaybeAuto, MinMaxConstraint};
|
use model::{IntrinsicISizes, MaybeAuto, MinMaxConstraint};
|
||||||
|
use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use style::computed_values::flex_direction;
|
use style::computed_values::flex_direction;
|
||||||
|
|
|
@ -36,12 +36,13 @@ use flow_ref::{self, FlowRef, WeakFlowRef};
|
||||||
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
|
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
|
||||||
use gfx::display_list::{ClippingRegion, StackingContext};
|
use gfx::display_list::{ClippingRegion, StackingContext};
|
||||||
use gfx_traits::{LayerId, LayerType, StackingContextId};
|
use gfx_traits::{LayerId, LayerType, StackingContextId};
|
||||||
use incremental::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
|
|
||||||
use inline::InlineFlow;
|
use inline::InlineFlow;
|
||||||
use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
|
use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
|
||||||
use multicol::MulticolFlow;
|
use multicol::MulticolFlow;
|
||||||
use parallel::FlowParallelInfo;
|
use parallel::FlowParallelInfo;
|
||||||
use rustc_serialize::{Encodable, Encoder};
|
use rustc_serialize::{Encodable, Encoder};
|
||||||
|
use script_layout_interface::restyle_damage::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
|
||||||
|
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutNode};
|
||||||
use std::iter::Zip;
|
use std::iter::Zip;
|
||||||
use std::slice::IterMut;
|
use std::slice::IterMut;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -60,7 +61,6 @@ use table_row::TableRowFlow;
|
||||||
use table_rowgroup::TableRowGroupFlow;
|
use table_rowgroup::TableRowGroupFlow;
|
||||||
use table_wrapper::TableWrapperFlow;
|
use table_wrapper::TableWrapperFlow;
|
||||||
use util::print_tree::PrintTree;
|
use util::print_tree::PrintTree;
|
||||||
use wrapper::{PseudoElementType, ThreadSafeLayoutNode};
|
|
||||||
|
|
||||||
/// Virtual methods that make up a float context.
|
/// Virtual methods that make up a float context.
|
||||||
///
|
///
|
||||||
|
|
|
@ -18,7 +18,6 @@ use gfx::display_list::{BLUR_INFLATION_FACTOR, OpaqueNode};
|
||||||
use gfx::text::glyph::ByteIndex;
|
use gfx::text::glyph::ByteIndex;
|
||||||
use gfx::text::text_run::{TextRun, TextRunSlice};
|
use gfx::text::text_run::{TextRun, TextRunSlice};
|
||||||
use gfx_traits::{FragmentType, LayerId, LayerType, StackingContextId};
|
use gfx_traits::{FragmentType, LayerId, LayerType, StackingContextId};
|
||||||
use incremental::{RECONSTRUCT_FLOW, RestyleDamage};
|
|
||||||
use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFragmentContext, InlineFragmentNodeInfo};
|
use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFragmentContext, InlineFragmentNodeInfo};
|
||||||
use inline::{InlineMetrics, LAST_FRAGMENT_OF_ELEMENT};
|
use inline::{InlineMetrics, LAST_FRAGMENT_OF_ELEMENT};
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
|
@ -30,7 +29,9 @@ use net_traits::image::base::{Image, ImageMetadata};
|
||||||
use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
|
use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
|
||||||
use range::*;
|
use range::*;
|
||||||
use rustc_serialize::{Encodable, Encoder};
|
use rustc_serialize::{Encodable, Encoder};
|
||||||
use script::layout_interface::HTMLCanvasData;
|
use script_layout_interface::HTMLCanvasData;
|
||||||
|
use script_layout_interface::restyle_damage::{RECONSTRUCT_FLOW, RestyleDamage};
|
||||||
|
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::collections::LinkedList;
|
use std::collections::LinkedList;
|
||||||
|
@ -49,7 +50,6 @@ use text;
|
||||||
use text::TextRunScanner;
|
use text::TextRunScanner;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util;
|
use util;
|
||||||
use wrapper::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
|
||||||
|
|
||||||
/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
|
/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
|
||||||
/// themselves. In general, fragments do not have a simple correspondence with CSS fragments in the
|
/// themselves. In general, fragments do not have a simple correspondence with CSS fragments in the
|
||||||
|
|
|
@ -13,7 +13,8 @@ use flow::InorderFlowTraversal;
|
||||||
use flow::{self, AFFECTS_COUNTERS, Flow, HAS_COUNTER_AFFECTING_CHILDREN, ImmutableFlowUtils};
|
use flow::{self, AFFECTS_COUNTERS, Flow, HAS_COUNTER_AFFECTING_CHILDREN, ImmutableFlowUtils};
|
||||||
use fragment::{Fragment, GeneratedContentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo};
|
use fragment::{Fragment, GeneratedContentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo};
|
||||||
use gfx::display_list::OpaqueNode;
|
use gfx::display_list::OpaqueNode;
|
||||||
use incremental::{RESOLVE_GENERATED_CONTENT, RestyleDamage};
|
use script_layout_interface::restyle_damage::{RESOLVE_GENERATED_CONTENT, RestyleDamage};
|
||||||
|
use script_layout_interface::wrapper_traits::PseudoElementType;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::collections::{HashMap, LinkedList};
|
use std::collections::{HashMap, LinkedList};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -22,7 +23,6 @@ use style::computed_values::{display, list_style_type};
|
||||||
use style::dom::TRestyleDamage;
|
use style::dom::TRestyleDamage;
|
||||||
use style::properties::{ComputedValues, ServoComputedValues};
|
use style::properties::{ComputedValues, ServoComputedValues};
|
||||||
use text::TextRunScanner;
|
use text::TextRunScanner;
|
||||||
use wrapper::PseudoElementType;
|
|
||||||
|
|
||||||
// Decimal styles per CSS-COUNTER-STYLES § 6.1:
|
// Decimal styles per CSS-COUNTER-STYLES § 6.1:
|
||||||
static DECIMAL: [char; 10] = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ];
|
static DECIMAL: [char; 10] = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ];
|
||||||
|
|
|
@ -3,46 +3,9 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use flow::{self, AFFECTS_COUNTERS, Flow, HAS_COUNTER_AFFECTING_CHILDREN, IS_ABSOLUTELY_POSITIONED};
|
use flow::{self, AFFECTS_COUNTERS, Flow, HAS_COUNTER_AFFECTING_CHILDREN, IS_ABSOLUTELY_POSITIONED};
|
||||||
use std::fmt;
|
use script_layout_interface::restyle_damage::{RestyleDamage, REFLOW, RECONSTRUCT_FLOW};
|
||||||
use std::sync::Arc;
|
use style::computed_values::float;
|
||||||
use style::computed_values::{display, float};
|
|
||||||
use style::dom::TRestyleDamage;
|
use style::dom::TRestyleDamage;
|
||||||
use style::properties::{ComputedValues, ServoComputedValues};
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
#[doc = "Individual layout actions that may be necessary after restyling."]
|
|
||||||
pub flags RestyleDamage: u8 {
|
|
||||||
#[doc = "Repaint the node itself."]
|
|
||||||
#[doc = "Currently unused; need to decide how this propagates."]
|
|
||||||
const REPAINT = 0x01,
|
|
||||||
|
|
||||||
#[doc = "Recompute the overflow regions (bounding box of object and all descendants)."]
|
|
||||||
#[doc = "Propagates down the flow tree because the computation is bottom-up."]
|
|
||||||
const STORE_OVERFLOW = 0x02,
|
|
||||||
|
|
||||||
#[doc = "Recompute intrinsic inline_sizes (minimum and preferred)."]
|
|
||||||
#[doc = "Propagates down the flow tree because the computation is"]
|
|
||||||
#[doc = "bottom-up."]
|
|
||||||
const BUBBLE_ISIZES = 0x04,
|
|
||||||
|
|
||||||
#[doc = "Recompute actual inline-sizes and block-sizes, only taking out-of-flow children \
|
|
||||||
into account. \
|
|
||||||
Propagates up the flow tree because the computation is top-down."]
|
|
||||||
const REFLOW_OUT_OF_FLOW = 0x08,
|
|
||||||
|
|
||||||
#[doc = "Recompute actual inline_sizes and block_sizes."]
|
|
||||||
#[doc = "Propagates up the flow tree because the computation is"]
|
|
||||||
#[doc = "top-down."]
|
|
||||||
const REFLOW = 0x10,
|
|
||||||
|
|
||||||
#[doc = "Re-resolve generated content. \
|
|
||||||
Propagates up the flow tree because the computation is inorder."]
|
|
||||||
const RESOLVE_GENERATED_CONTENT = 0x20,
|
|
||||||
|
|
||||||
#[doc = "The entire flow needs to be reconstructed."]
|
|
||||||
const RECONSTRUCT_FLOW = 0x40
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub flags SpecialRestyleDamage: u8 {
|
pub flags SpecialRestyleDamage: u8 {
|
||||||
|
@ -52,221 +15,6 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TRestyleDamage for RestyleDamage {
|
|
||||||
type ConcreteComputedValues = ServoComputedValues;
|
|
||||||
fn compute(old: Option<&Arc<ServoComputedValues>>, new: &ServoComputedValues) ->
|
|
||||||
RestyleDamage { compute_damage(old, new) }
|
|
||||||
|
|
||||||
/// Returns a bitmask that represents a flow that needs to be rebuilt and reflowed.
|
|
||||||
///
|
|
||||||
/// Use this instead of `RestyleDamage::all()` because `RestyleDamage::all()` will result in
|
|
||||||
/// unnecessary sequential resolution of generated content.
|
|
||||||
fn rebuild_and_reflow() -> RestyleDamage {
|
|
||||||
REPAINT | STORE_OVERFLOW | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW | RECONSTRUCT_FLOW
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl RestyleDamage {
|
|
||||||
/// Supposing a flow has the given `position` property and this damage, returns the damage that
|
|
||||||
/// we should add to the *parent* of this flow.
|
|
||||||
pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> RestyleDamage {
|
|
||||||
if child_is_absolutely_positioned {
|
|
||||||
self & (REPAINT | STORE_OVERFLOW | REFLOW_OUT_OF_FLOW | RESOLVE_GENERATED_CONTENT)
|
|
||||||
} else {
|
|
||||||
self & (REPAINT | STORE_OVERFLOW | REFLOW | REFLOW_OUT_OF_FLOW |
|
|
||||||
RESOLVE_GENERATED_CONTENT)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Supposing the *parent* of a flow with the given `position` property has this damage,
|
|
||||||
/// returns the damage that we should add to this flow.
|
|
||||||
pub fn damage_for_child(self,
|
|
||||||
parent_is_absolutely_positioned: bool,
|
|
||||||
child_is_absolutely_positioned: bool)
|
|
||||||
-> RestyleDamage {
|
|
||||||
match (parent_is_absolutely_positioned, child_is_absolutely_positioned) {
|
|
||||||
(false, true) => {
|
|
||||||
// Absolute children are out-of-flow and therefore insulated from changes.
|
|
||||||
//
|
|
||||||
// FIXME(pcwalton): Au contraire, if the containing block dimensions change!
|
|
||||||
self & REPAINT
|
|
||||||
}
|
|
||||||
(true, false) => {
|
|
||||||
// Changing the position of an absolutely-positioned block requires us to reflow
|
|
||||||
// its kids.
|
|
||||||
if self.contains(REFLOW_OUT_OF_FLOW) {
|
|
||||||
self | REFLOW
|
|
||||||
} else {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// TODO(pcwalton): Take floatedness into account.
|
|
||||||
self & (REPAINT | REFLOW)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for RestyleDamage {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
||||||
let mut first_elem = true;
|
|
||||||
|
|
||||||
let to_iter =
|
|
||||||
[ (REPAINT, "Repaint")
|
|
||||||
, (STORE_OVERFLOW, "StoreOverflow")
|
|
||||||
, (BUBBLE_ISIZES, "BubbleISizes")
|
|
||||||
, (REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow")
|
|
||||||
, (REFLOW, "Reflow")
|
|
||||||
, (RESOLVE_GENERATED_CONTENT, "ResolveGeneratedContent")
|
|
||||||
, (RECONSTRUCT_FLOW, "ReconstructFlow")
|
|
||||||
];
|
|
||||||
|
|
||||||
for &(damage, damage_str) in &to_iter {
|
|
||||||
if self.contains(damage) {
|
|
||||||
if !first_elem { try!(write!(f, " | ")); }
|
|
||||||
try!(write!(f, "{}", damage_str));
|
|
||||||
first_elem = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if first_elem {
|
|
||||||
try!(write!(f, "NoDamage"));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NB: We need the braces inside the RHS due to Rust #8012. This particular
|
|
||||||
// version of this macro might be safe anyway, but we want to avoid silent
|
|
||||||
// breakage on modifications.
|
|
||||||
macro_rules! add_if_not_equal(
|
|
||||||
($old:ident, $new:ident, $damage:ident,
|
|
||||||
[ $($effect:ident),* ], [ $($style_struct_getter:ident.$name:ident),* ]) => ({
|
|
||||||
if $( ($old.$style_struct_getter().$name != $new.$style_struct_getter().$name) )||* {
|
|
||||||
$damage.insert($($effect)|*);
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
pub fn compute_damage(old: Option<&Arc<ServoComputedValues>>, new: &ServoComputedValues) -> RestyleDamage {
|
|
||||||
let old: &ServoComputedValues = match old {
|
|
||||||
None => return RestyleDamage::rebuild_and_reflow(),
|
|
||||||
Some(cv) => &**cv,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut damage = RestyleDamage::empty();
|
|
||||||
|
|
||||||
// This should check every CSS property, as enumerated in the fields of
|
|
||||||
// http://doc.servo.org/style/properties/struct.ServoComputedValues.html
|
|
||||||
|
|
||||||
// FIXME: Test somehow that every property is included.
|
|
||||||
|
|
||||||
add_if_not_equal!(old, new, damage,
|
|
||||||
[
|
|
||||||
REPAINT,
|
|
||||||
STORE_OVERFLOW,
|
|
||||||
BUBBLE_ISIZES,
|
|
||||||
REFLOW_OUT_OF_FLOW,
|
|
||||||
REFLOW,
|
|
||||||
RECONSTRUCT_FLOW
|
|
||||||
], [
|
|
||||||
get_box.float, get_box.display, get_box.position, get_counters.content,
|
|
||||||
get_counters.counter_reset, get_counters.counter_increment,
|
|
||||||
get_inheritedbox._servo_under_display_none,
|
|
||||||
get_list.quotes, get_list.list_style_type,
|
|
||||||
|
|
||||||
// If these text or font properties change, we need to reconstruct the flow so that
|
|
||||||
// text shaping is re-run.
|
|
||||||
get_inheritedtext.letter_spacing, get_inheritedtext.text_rendering,
|
|
||||||
get_inheritedtext.text_transform, get_inheritedtext.word_spacing,
|
|
||||||
get_inheritedtext.overflow_wrap, get_inheritedtext.text_justify,
|
|
||||||
get_inheritedtext.white_space, get_inheritedtext.word_break, get_text.text_overflow,
|
|
||||||
get_font.font_family, get_font.font_style, get_font.font_variant, get_font.font_weight,
|
|
||||||
get_font.font_size, get_font.font_stretch,
|
|
||||||
get_inheritedbox.direction, get_inheritedbox.writing_mode,
|
|
||||||
get_inheritedbox.text_orientation,
|
|
||||||
get_text.text_decoration, get_text.unicode_bidi,
|
|
||||||
get_inheritedtable.empty_cells, get_inheritedtable.caption_side,
|
|
||||||
get_column.column_width, get_column.column_count
|
|
||||||
]) || (new.get_box().display == display::T::inline &&
|
|
||||||
add_if_not_equal!(old, new, damage,
|
|
||||||
[REPAINT, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW,
|
|
||||||
RECONSTRUCT_FLOW], [
|
|
||||||
// For inline boxes only, border/padding styles are used in flow construction (to decide
|
|
||||||
// whether to create fragments for empty flows).
|
|
||||||
get_border.border_top_width, get_border.border_right_width,
|
|
||||||
get_border.border_bottom_width, get_border.border_left_width,
|
|
||||||
get_padding.padding_top, get_padding.padding_right,
|
|
||||||
get_padding.padding_bottom, get_padding.padding_left
|
|
||||||
])) || add_if_not_equal!(old, new, damage,
|
|
||||||
[ REPAINT, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW ],
|
|
||||||
[get_border.border_top_width, get_border.border_right_width,
|
|
||||||
get_border.border_bottom_width, get_border.border_left_width,
|
|
||||||
get_margin.margin_top, get_margin.margin_right,
|
|
||||||
get_margin.margin_bottom, get_margin.margin_left,
|
|
||||||
get_padding.padding_top, get_padding.padding_right,
|
|
||||||
get_padding.padding_bottom, get_padding.padding_left,
|
|
||||||
get_position.width, get_position.height,
|
|
||||||
get_inheritedtext.line_height,
|
|
||||||
get_inheritedtext.text_align, get_inheritedtext.text_indent,
|
|
||||||
get_table.table_layout,
|
|
||||||
get_inheritedtable.border_collapse,
|
|
||||||
get_inheritedtable.border_spacing,
|
|
||||||
get_column.column_gap,
|
|
||||||
get_position.flex_direction,
|
|
||||||
get_position.flex_wrap,
|
|
||||||
get_position.justify_content,
|
|
||||||
get_position.align_items,
|
|
||||||
get_position.align_content,
|
|
||||||
get_position.order,
|
|
||||||
get_position.flex_basis,
|
|
||||||
get_position.flex_grow,
|
|
||||||
get_position.flex_shrink,
|
|
||||||
get_position.align_self
|
|
||||||
]) || add_if_not_equal!(old, new, damage,
|
|
||||||
[ REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW ], [
|
|
||||||
get_position.top, get_position.left,
|
|
||||||
get_position.right, get_position.bottom
|
|
||||||
]) || add_if_not_equal!(old, new, damage,
|
|
||||||
[ REPAINT ], [
|
|
||||||
get_color.color, get_background.background_color,
|
|
||||||
get_background.background_image, get_background.background_position,
|
|
||||||
get_background.background_repeat, get_background.background_attachment,
|
|
||||||
get_background.background_clip, get_background.background_origin,
|
|
||||||
get_background.background_size,
|
|
||||||
get_border.border_top_color, get_border.border_right_color,
|
|
||||||
get_border.border_bottom_color, get_border.border_left_color,
|
|
||||||
get_border.border_top_style, get_border.border_right_style,
|
|
||||||
get_border.border_bottom_style, get_border.border_left_style,
|
|
||||||
get_border.border_top_left_radius, get_border.border_top_right_radius,
|
|
||||||
get_border.border_bottom_left_radius, get_border.border_bottom_right_radius,
|
|
||||||
get_position.z_index, get_box._servo_overflow_clip_box,
|
|
||||||
get_inheritedtext._servo_text_decorations_in_effect,
|
|
||||||
get_pointing.cursor, get_pointing.pointer_events,
|
|
||||||
get_effects.box_shadow, get_effects.clip, get_inheritedtext.text_shadow, get_effects.filter,
|
|
||||||
get_effects.transform, get_effects.backface_visibility, get_effects.transform_style,
|
|
||||||
get_effects.transform_origin, get_effects.perspective, get_effects.perspective_origin,
|
|
||||||
get_effects.mix_blend_mode, get_inheritedbox.image_rendering,
|
|
||||||
|
|
||||||
// Note: May require REFLOW et al. if `visibility: collapse` is implemented.
|
|
||||||
get_inheritedbox.visibility
|
|
||||||
]);
|
|
||||||
|
|
||||||
// If the layer requirements of this flow have changed due to the value
|
|
||||||
// of the transform, then reflow is required to rebuild the layers.
|
|
||||||
if old.transform_requires_layer() != new.transform_requires_layer() {
|
|
||||||
damage.insert(RestyleDamage::rebuild_and_reflow());
|
|
||||||
}
|
|
||||||
|
|
||||||
damage
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait LayoutDamageComputation {
|
pub trait LayoutDamageComputation {
|
||||||
fn compute_layout_damage(self) -> SpecialRestyleDamage;
|
fn compute_layout_damage(self) -> SpecialRestyleDamage;
|
||||||
fn reflow_entire_document(self);
|
fn reflow_entire_document(self);
|
||||||
|
|
|
@ -21,10 +21,12 @@ use gfx::display_list::{OpaqueNode, StackingContext};
|
||||||
use gfx::font::FontMetrics;
|
use gfx::font::FontMetrics;
|
||||||
use gfx::font_context::FontContext;
|
use gfx::font_context::FontContext;
|
||||||
use gfx_traits::StackingContextId;
|
use gfx_traits::StackingContextId;
|
||||||
use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RESOLVE_GENERATED_CONTENT};
|
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
use model::IntrinsicISizesContribution;
|
use model::IntrinsicISizesContribution;
|
||||||
use range::{Range, RangeIndex};
|
use range::{Range, RangeIndex};
|
||||||
|
use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW};
|
||||||
|
use script_layout_interface::restyle_damage::{REPAINT, RESOLVE_GENERATED_CONTENT};
|
||||||
|
use script_layout_interface::wrapper_traits::PseudoElementType;
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -38,7 +40,6 @@ use text;
|
||||||
use unicode_bidi;
|
use unicode_bidi;
|
||||||
use util;
|
use util;
|
||||||
use util::print_tree::PrintTree;
|
use util::print_tree::PrintTree;
|
||||||
use wrapper::PseudoElementType;
|
|
||||||
|
|
||||||
// From gfxFontConstants.h in Firefox
|
// From gfxFontConstants.h in Firefox
|
||||||
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
|
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
|
||||||
|
|
|
@ -29,8 +29,7 @@ use gfx::font_context;
|
||||||
use gfx::paint_thread::LayoutToPaintMsg;
|
use gfx::paint_thread::LayoutToPaintMsg;
|
||||||
use gfx_traits::{color, Epoch, FragmentType, LayerId, ScrollPolicy, StackingContextId};
|
use gfx_traits::{color, Epoch, FragmentType, LayerId, ScrollPolicy, StackingContextId};
|
||||||
use heapsize::HeapSizeOf;
|
use heapsize::HeapSizeOf;
|
||||||
use incremental::LayoutDamageComputation;
|
use incremental::{LayoutDamageComputation, REFLOW_ENTIRE_DOCUMENT};
|
||||||
use incremental::{REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW, REFLOW, REFLOW_ENTIRE_DOCUMENT};
|
|
||||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
|
@ -47,15 +46,19 @@ use query::process_offset_parent_query;
|
||||||
use query::{LayoutRPCImpl, process_content_box_request, process_content_boxes_request};
|
use query::{LayoutRPCImpl, process_content_box_request, process_content_boxes_request};
|
||||||
use query::{process_node_geometry_request, process_node_layer_id_request, process_node_scroll_area_request};
|
use query::{process_node_geometry_request, process_node_layer_id_request, process_node_scroll_area_request};
|
||||||
use query::{process_node_overflow_request, process_resolved_style_request, process_margin_style_query};
|
use query::{process_node_overflow_request, process_resolved_style_request, process_margin_style_query};
|
||||||
use script::layout_interface::OpaqueStyleAndLayoutData;
|
use script::layout_wrapper::ServoLayoutNode;
|
||||||
use script::layout_interface::{LayoutRPC, OffsetParentResponse, NodeOverflowResponse, MarginStyleResponse};
|
use script_layout_interface::message::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow};
|
||||||
use script::layout_interface::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow};
|
use script_layout_interface::reporter::CSSErrorReporter;
|
||||||
use script::reporter::CSSErrorReporter;
|
use script_layout_interface::restyle_damage::{REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW, REFLOW};
|
||||||
|
use script_layout_interface::rpc::{LayoutRPC, MarginStyleResponse, NodeOverflowResponse, OffsetParentResponse};
|
||||||
|
use script_layout_interface::wrapper_traits::LayoutNode;
|
||||||
|
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData};
|
||||||
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
|
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
|
||||||
use script_traits::{StackingContextScrollState, UntrustedNodeAddress};
|
use script_traits::{StackingContextScrollState, UntrustedNodeAddress};
|
||||||
use sequential;
|
use sequential;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
@ -84,7 +87,7 @@ use util::thread_state;
|
||||||
use util::workqueue::WorkQueue;
|
use util::workqueue::WorkQueue;
|
||||||
use webrender_helpers::{WebRenderDisplayListConverter, WebRenderFrameBuilder};
|
use webrender_helpers::{WebRenderDisplayListConverter, WebRenderFrameBuilder};
|
||||||
use webrender_traits;
|
use webrender_traits;
|
||||||
use wrapper::{LayoutNode, NonOpaqueStyleAndLayoutData, ServoLayoutNode};
|
use wrapper::{LayoutNodeLayoutData, NonOpaqueStyleAndLayoutData};
|
||||||
|
|
||||||
/// The number of screens of data we're allowed to generate display lists for in each direction.
|
/// The number of screens of data we're allowed to generate display lists for in each direction.
|
||||||
pub const DISPLAY_PORT_SIZE_FACTOR: i32 = 8;
|
pub const DISPLAY_PORT_SIZE_FACTOR: i32 = 8;
|
||||||
|
@ -1480,7 +1483,7 @@ impl LayoutThread {
|
||||||
/// Handles a message to destroy layout data. Layout data must be destroyed on *this* thread
|
/// Handles a message to destroy layout data. Layout data must be destroyed on *this* thread
|
||||||
/// because the struct type is transmuted to a different type on the script side.
|
/// because the struct type is transmuted to a different type on the script side.
|
||||||
unsafe fn handle_reap_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) {
|
unsafe fn handle_reap_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) {
|
||||||
let ptr: *mut () = *data.ptr;
|
let ptr: *mut RefCell<PartialStyleAndLayoutData> = *data.ptr;
|
||||||
let non_opaque: NonOpaqueStyleAndLayoutData = ptr as *mut _;
|
let non_opaque: NonOpaqueStyleAndLayoutData = ptr as *mut _;
|
||||||
let _ = Box::from_raw(non_opaque);
|
let _ = Box::from_raw(non_opaque);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ extern crate profile_traits;
|
||||||
extern crate range;
|
extern crate range;
|
||||||
extern crate rustc_serialize;
|
extern crate rustc_serialize;
|
||||||
extern crate script;
|
extern crate script;
|
||||||
|
extern crate script_layout_interface;
|
||||||
extern crate script_traits;
|
extern crate script_traits;
|
||||||
extern crate selectors;
|
extern crate selectors;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
@ -102,4 +103,3 @@ mod wrapper;
|
||||||
|
|
||||||
// For unit tests:
|
// For unit tests:
|
||||||
pub use fragment::Fragment;
|
pub use fragment::Fragment;
|
||||||
pub use wrapper::ServoThreadSafeLayoutNode;
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, GeneratedC
|
||||||
use generated_content;
|
use generated_content;
|
||||||
use gfx::display_list::StackingContext;
|
use gfx::display_list::StackingContext;
|
||||||
use gfx_traits::StackingContextId;
|
use gfx_traits::StackingContextId;
|
||||||
use incremental::RESOLVE_GENERATED_CONTENT;
|
|
||||||
use inline::InlineMetrics;
|
use inline::InlineMetrics;
|
||||||
|
use script_layout_interface::restyle_damage::RESOLVE_GENERATED_CONTENT;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use style::computed_values::{list_style_type, position};
|
use style::computed_values::{list_style_type, position};
|
||||||
use style::logical_geometry::LogicalSize;
|
use style::logical_geometry::LogicalSize;
|
||||||
|
|
|
@ -2,41 +2,17 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#![allow(unsafe_code)]
|
|
||||||
|
|
||||||
use gfx::display_list::OpaqueNode;
|
use gfx::display_list::OpaqueNode;
|
||||||
use libc::{c_void, uintptr_t};
|
use libc::c_void;
|
||||||
use script::layout_interface::LayoutJS;
|
|
||||||
use script::layout_interface::Node;
|
|
||||||
use script::layout_interface::TrustedNodeAddress;
|
|
||||||
use script_traits::UntrustedNodeAddress;
|
use script_traits::UntrustedNodeAddress;
|
||||||
|
|
||||||
pub trait OpaqueNodeMethods {
|
pub trait OpaqueNodeMethods {
|
||||||
/// Converts a DOM node (script view) to an `OpaqueNode`.
|
|
||||||
fn from_script_node(node: TrustedNodeAddress) -> Self;
|
|
||||||
|
|
||||||
/// Converts a DOM node to an `OpaqueNode'.
|
|
||||||
fn from_jsmanaged(node: &LayoutJS<Node>) -> Self;
|
|
||||||
|
|
||||||
/// Converts this node to an `UntrustedNodeAddress`. An `UntrustedNodeAddress` is just the type
|
/// Converts this node to an `UntrustedNodeAddress`. An `UntrustedNodeAddress` is just the type
|
||||||
/// of node that script expects to receive in a hit test.
|
/// of node that script expects to receive in a hit test.
|
||||||
fn to_untrusted_node_address(&self) -> UntrustedNodeAddress;
|
fn to_untrusted_node_address(&self) -> UntrustedNodeAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpaqueNodeMethods for OpaqueNode {
|
impl OpaqueNodeMethods for OpaqueNode {
|
||||||
fn from_script_node(node: TrustedNodeAddress) -> OpaqueNode {
|
|
||||||
unsafe {
|
|
||||||
OpaqueNodeMethods::from_jsmanaged(&LayoutJS::from_trusted_node_address(node))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_jsmanaged(node: &LayoutJS<Node>) -> OpaqueNode {
|
|
||||||
unsafe {
|
|
||||||
let ptr: uintptr_t = node.get_jsobject() as uintptr_t;
|
|
||||||
OpaqueNode(ptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_untrusted_node_address(&self) -> UntrustedNodeAddress {
|
fn to_untrusted_node_address(&self) -> UntrustedNodeAddress {
|
||||||
UntrustedNodeAddress(self.0 as *const c_void)
|
UntrustedNodeAddress(self.0 as *const c_void)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,12 @@ use gfx::display_list::OpaqueNode;
|
||||||
use gfx_traits::LayerId;
|
use gfx_traits::LayerId;
|
||||||
use layout_thread::LayoutThreadData;
|
use layout_thread::LayoutThreadData;
|
||||||
use opaque_node::OpaqueNodeMethods;
|
use opaque_node::OpaqueNodeMethods;
|
||||||
use script::layout_interface::{ContentBoxResponse, NodeOverflowResponse, ContentBoxesResponse, NodeGeometryResponse};
|
use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse};
|
||||||
use script::layout_interface::{HitTestResponse, LayoutRPC, OffsetParentResponse, NodeLayerIdResponse};
|
use script_layout_interface::rpc::{HitTestResponse, LayoutRPC};
|
||||||
use script::layout_interface::{ResolvedStyleResponse, MarginStyleResponse};
|
use script_layout_interface::rpc::{MarginStyleResponse, NodeGeometryResponse};
|
||||||
|
use script_layout_interface::rpc::{NodeLayerIdResponse, NodeOverflowResponse};
|
||||||
|
use script_layout_interface::rpc::{OffsetParentResponse, ResolvedStyleResponse};
|
||||||
|
use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
|
||||||
use script_traits::LayoutMsg as ConstellationMsg;
|
use script_traits::LayoutMsg as ConstellationMsg;
|
||||||
use script_traits::UntrustedNodeAddress;
|
use script_traits::UntrustedNodeAddress;
|
||||||
use sequential;
|
use sequential;
|
||||||
|
@ -34,7 +37,7 @@ use style::properties::style_structs;
|
||||||
use style::selector_impl::PseudoElement;
|
use style::selector_impl::PseudoElement;
|
||||||
use style::values::AuExtensionMethods;
|
use style::values::AuExtensionMethods;
|
||||||
use style_traits::cursor::Cursor;
|
use style_traits::cursor::Cursor;
|
||||||
use wrapper::{LayoutNode, ThreadSafeLayoutNode};
|
use wrapper::ThreadSafeLayoutNodeHelpers;
|
||||||
|
|
||||||
pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutThreadData>>);
|
pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutThreadData>>);
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ use flow_ref::{self, FlowRef};
|
||||||
use fragment::FragmentBorderBoxIterator;
|
use fragment::FragmentBorderBoxIterator;
|
||||||
use generated_content::ResolveGeneratedContent;
|
use generated_content::ResolveGeneratedContent;
|
||||||
use gfx::display_list::{DisplayItem, StackingContext};
|
use gfx::display_list::{DisplayItem, StackingContext};
|
||||||
use incremental::{REFLOW, STORE_OVERFLOW};
|
use script_layout_interface::restyle_damage::{REFLOW, STORE_OVERFLOW};
|
||||||
use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList, ComputeAbsolutePositions};
|
use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList, ComputeAbsolutePositions};
|
||||||
use util::opts;
|
use util::opts;
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,9 @@ use flow_list::MutFlowListIterator;
|
||||||
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
||||||
use gfx::display_list::StackingContext;
|
use gfx::display_list::StackingContext;
|
||||||
use gfx_traits::StackingContextId;
|
use gfx_traits::StackingContextId;
|
||||||
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
|
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
use model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto};
|
use model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto};
|
||||||
|
use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
|
@ -16,9 +16,10 @@ use flow::{self, Flow, FlowClass, OpaqueFlow};
|
||||||
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
||||||
use gfx::display_list::StackingContext;
|
use gfx::display_list::StackingContext;
|
||||||
use gfx_traits::StackingContextId;
|
use gfx_traits::StackingContextId;
|
||||||
use incremental::REFLOW;
|
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
use model::MaybeAuto;
|
use model::MaybeAuto;
|
||||||
|
use script_layout_interface::restyle_damage::REFLOW;
|
||||||
|
use script_layout_interface::wrapper_traits::ThreadSafeLayoutNode;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use style::computed_values::{border_collapse, border_top_style, vertical_align};
|
use style::computed_values::{border_collapse, border_top_style, vertical_align};
|
||||||
|
@ -27,7 +28,6 @@ use style::properties::{ComputedValues, ServoComputedValues};
|
||||||
use table::InternalTable;
|
use table::InternalTable;
|
||||||
use table_row::{CollapsedBorder, CollapsedBorderProvenance};
|
use table_row::{CollapsedBorder, CollapsedBorderProvenance};
|
||||||
use util::print_tree::PrintTree;
|
use util::print_tree::PrintTree;
|
||||||
use wrapper::ThreadSafeLayoutNode;
|
|
||||||
|
|
||||||
/// A table formatting context.
|
/// A table formatting context.
|
||||||
#[derive(RustcEncodable)]
|
#[derive(RustcEncodable)]
|
||||||
|
|
|
@ -10,22 +10,30 @@ use display_list_builder::DisplayListBuildState;
|
||||||
use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal};
|
use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal};
|
||||||
use flow::{PreorderFlowTraversal, self};
|
use flow::{PreorderFlowTraversal, self};
|
||||||
use gfx::display_list::OpaqueNode;
|
use gfx::display_list::OpaqueNode;
|
||||||
use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
|
use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
|
||||||
|
use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use style::context::StyleContext;
|
use style::context::StyleContext;
|
||||||
|
use style::dom::TNode;
|
||||||
use style::matching::MatchMethods;
|
use style::matching::MatchMethods;
|
||||||
|
use style::properties::ServoComputedValues;
|
||||||
|
use style::selector_impl::ServoSelectorImpl;
|
||||||
use style::traversal::{DomTraversalContext, STYLE_BLOOM};
|
use style::traversal::{DomTraversalContext, STYLE_BLOOM};
|
||||||
use style::traversal::{put_thread_local_bloom_filter, recalc_style_at};
|
use style::traversal::{put_thread_local_bloom_filter, recalc_style_at};
|
||||||
use util::opts;
|
use util::opts;
|
||||||
use util::tid::tid;
|
use util::tid::tid;
|
||||||
use wrapper::{LayoutNode, ServoLayoutNode, ThreadSafeLayoutNode};
|
use wrapper::{LayoutNodeLayoutData, ThreadSafeLayoutNodeHelpers};
|
||||||
|
|
||||||
pub struct RecalcStyleAndConstructFlows<'lc> {
|
pub struct RecalcStyleAndConstructFlows<'lc> {
|
||||||
context: LayoutContext<'lc>,
|
context: LayoutContext<'lc>,
|
||||||
root: OpaqueNode,
|
root: OpaqueNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lc, 'ln> DomTraversalContext<ServoLayoutNode<'ln>> for RecalcStyleAndConstructFlows<'lc> {
|
impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc>
|
||||||
|
where N: LayoutNode + TNode<ConcreteComputedValues=ServoComputedValues>,
|
||||||
|
N::ConcreteElement: ::selectors::Element<Impl=ServoSelectorImpl>
|
||||||
|
|
||||||
|
{
|
||||||
type SharedContext = SharedLayoutContext;
|
type SharedContext = SharedLayoutContext;
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self {
|
fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self {
|
||||||
|
@ -65,7 +73,7 @@ impl<'lc, 'ln> DomTraversalContext<ServoLayoutNode<'ln>> for RecalcStyleAndConst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_preorder(&self, node: ServoLayoutNode<'ln>) {
|
fn process_preorder(&self, node: N) {
|
||||||
// FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML
|
// FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML
|
||||||
// parser.
|
// parser.
|
||||||
node.initialize_data();
|
node.initialize_data();
|
||||||
|
@ -73,7 +81,7 @@ impl<'lc, 'ln> DomTraversalContext<ServoLayoutNode<'ln>> for RecalcStyleAndConst
|
||||||
recalc_style_at(&self.context, self.root, node);
|
recalc_style_at(&self.context, self.root, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_postorder(&self, node: ServoLayoutNode<'ln>) { construct_flows_at(&self.context, self.root, node); }
|
fn process_postorder(&self, node: N) { construct_flows_at(&self.context, self.root, node); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A bottom-up, parallelizable traversal.
|
/// A bottom-up, parallelizable traversal.
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -49,10 +49,12 @@ phf_macros = "0.7.13"
|
||||||
plugins = {path = "../plugins"}
|
plugins = {path = "../plugins"}
|
||||||
profile_traits = {path = "../profile_traits"}
|
profile_traits = {path = "../profile_traits"}
|
||||||
rand = "0.3"
|
rand = "0.3"
|
||||||
|
range = {path = "../range"}
|
||||||
ref_filter_map = "1.0"
|
ref_filter_map = "1.0"
|
||||||
ref_slice = "1.0"
|
ref_slice = "1.0"
|
||||||
regex = "0.1.43"
|
regex = "0.1.43"
|
||||||
rustc-serialize = "0.3"
|
rustc-serialize = "0.3"
|
||||||
|
script_layout_interface = {path = "../script_layout_interface"}
|
||||||
script_traits = {path = "../script_traits"}
|
script_traits = {path = "../script_traits"}
|
||||||
selectors = {version = "0.6", features = ["heap_size"]}
|
selectors = {version = "0.6", features = ["heap_size"]}
|
||||||
serde = "0.7"
|
serde = "0.7"
|
||||||
|
|
|
@ -33,7 +33,7 @@ use dom::node::Node;
|
||||||
use heapsize::HeapSizeOf;
|
use heapsize::HeapSizeOf;
|
||||||
use js::jsapi::{Heap, JSObject, JSTracer};
|
use js::jsapi::{Heap, JSObject, JSTracer};
|
||||||
use js::jsval::JSVal;
|
use js::jsval::JSVal;
|
||||||
use layout_interface::TrustedNodeAddress;
|
use script_layout_interface::TrustedNodeAddress;
|
||||||
use script_thread::STACK_ROOTS;
|
use script_thread::STACK_ROOTS;
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
|
|
@ -55,7 +55,6 @@ use js::glue::{CallObjectTracer, CallUnbarrieredObjectTracer, CallValueTracer};
|
||||||
use js::jsapi::{GCTraceKindToAscii, Heap, TraceKind, JSObject, JSTracer};
|
use js::jsapi::{GCTraceKindToAscii, Heap, TraceKind, JSObject, JSTracer};
|
||||||
use js::jsval::JSVal;
|
use js::jsval::JSVal;
|
||||||
use js::rust::Runtime;
|
use js::rust::Runtime;
|
||||||
use layout_interface::LayoutRPC;
|
|
||||||
use libc;
|
use libc;
|
||||||
use msg::constellation_msg::{FrameType, PipelineId, SubpageId, WindowSizeData, WindowSizeType, ReferrerPolicy};
|
use msg::constellation_msg::{FrameType, PipelineId, SubpageId, WindowSizeData, WindowSizeType, ReferrerPolicy};
|
||||||
use net_traits::filemanager_thread::SelectedFileId;
|
use net_traits::filemanager_thread::SelectedFileId;
|
||||||
|
@ -67,6 +66,9 @@ use net_traits::{Metadata, NetworkError, ResourceThreads};
|
||||||
use offscreen_gl_context::GLLimits;
|
use offscreen_gl_context::GLLimits;
|
||||||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||||
use profile_traits::time::ProfilerChan as TimeProfilerChan;
|
use profile_traits::time::ProfilerChan as TimeProfilerChan;
|
||||||
|
use script_layout_interface::OpaqueStyleAndLayoutData;
|
||||||
|
use script_layout_interface::reporter::CSSErrorReporter;
|
||||||
|
use script_layout_interface::rpc::LayoutRPC;
|
||||||
use script_runtime::ScriptChan;
|
use script_runtime::ScriptChan;
|
||||||
use script_traits::{TimerEventId, TimerSource, TouchpadPressurePhase, UntrustedNodeAddress};
|
use script_traits::{TimerEventId, TimerSource, TouchpadPressurePhase, UntrustedNodeAddress};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -328,6 +330,8 @@ no_jsmanaged_fields!(ReferrerPolicy);
|
||||||
no_jsmanaged_fields!(ResourceThreads);
|
no_jsmanaged_fields!(ResourceThreads);
|
||||||
no_jsmanaged_fields!(SystemTime);
|
no_jsmanaged_fields!(SystemTime);
|
||||||
no_jsmanaged_fields!(SelectedFileId);
|
no_jsmanaged_fields!(SelectedFileId);
|
||||||
|
no_jsmanaged_fields!(OpaqueStyleAndLayoutData);
|
||||||
|
no_jsmanaged_fields!(CSSErrorReporter);
|
||||||
|
|
||||||
impl JSTraceable for Box<ScriptChan + Send> {
|
impl JSTraceable for Box<ScriptChan + Send> {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -92,7 +92,6 @@ use html5ever::tree_builder::{LimitedQuirks, NoQuirks, Quirks, QuirksMode};
|
||||||
use ipc_channel::ipc::{self, IpcSender};
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
use js::jsapi::JS_GetRuntime;
|
use js::jsapi::JS_GetRuntime;
|
||||||
use js::jsapi::{JSContext, JSObject, JSRuntime};
|
use js::jsapi::{JSContext, JSObject, JSRuntime};
|
||||||
use layout_interface::{Msg, ReflowQueryType};
|
|
||||||
use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER};
|
use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER};
|
||||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
||||||
use msg::constellation_msg::{PipelineId, ReferrerPolicy, SubpageId};
|
use msg::constellation_msg::{PipelineId, ReferrerPolicy, SubpageId};
|
||||||
|
@ -103,6 +102,7 @@ use net_traits::{AsyncResponseTarget, PendingAsyncLoad, IpcSend};
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
use origin::Origin;
|
use origin::Origin;
|
||||||
use parse::{ParserRoot, ParserRef, MutNullableParserField};
|
use parse::{ParserRoot, ParserRef, MutNullableParserField};
|
||||||
|
use script_layout_interface::message::{Msg, ReflowQueryType};
|
||||||
use script_thread::{MainThreadScriptMsg, Runnable};
|
use script_thread::{MainThreadScriptMsg, Runnable};
|
||||||
use script_traits::UntrustedNodeAddress;
|
use script_traits::UntrustedNodeAddress;
|
||||||
use script_traits::{AnimationState, MouseButton, MouseEventType, MozBrowserEvent};
|
use script_traits::{AnimationState, MouseButton, MouseEventType, MozBrowserEvent};
|
||||||
|
|
|
@ -30,6 +30,7 @@ use ipc_channel::ipc::{self, IpcSender};
|
||||||
use js::jsapi::{HandleValue, JSContext};
|
use js::jsapi::{HandleValue, JSContext};
|
||||||
use offscreen_gl_context::GLContextAttributes;
|
use offscreen_gl_context::GLContextAttributes;
|
||||||
use rustc_serialize::base64::{STANDARD, ToBase64};
|
use rustc_serialize::base64::{STANDARD, ToBase64};
|
||||||
|
use script_layout_interface::HTMLCanvasData;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use style::attr::AttrValue;
|
use style::attr::AttrValue;
|
||||||
|
@ -92,12 +93,6 @@ impl HTMLCanvasElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HTMLCanvasData {
|
|
||||||
pub ipc_renderer: Option<IpcSender<CanvasMsg>>,
|
|
||||||
pub width: u32,
|
|
||||||
pub height: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait LayoutHTMLCanvasElementHelpers {
|
pub trait LayoutHTMLCanvasElementHelpers {
|
||||||
fn data(&self) -> HTMLCanvasData;
|
fn data(&self) -> HTMLCanvasData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,9 +38,9 @@ use dom::window::{ReflowReason, Window};
|
||||||
use ipc_channel::ipc;
|
use ipc_channel::ipc;
|
||||||
use js::jsapi::{JSAutoCompartment, RootedValue, JSContext, MutableHandleValue};
|
use js::jsapi::{JSAutoCompartment, RootedValue, JSContext, MutableHandleValue};
|
||||||
use js::jsval::{UndefinedValue, NullValue};
|
use js::jsval::{UndefinedValue, NullValue};
|
||||||
use layout_interface::ReflowQueryType;
|
|
||||||
use msg::constellation_msg::{FrameType, LoadData, NavigationDirection, PipelineId, SubpageId};
|
use msg::constellation_msg::{FrameType, LoadData, NavigationDirection, PipelineId, SubpageId};
|
||||||
use net_traits::response::HttpsState;
|
use net_traits::response::HttpsState;
|
||||||
|
use script_layout_interface::message::ReflowQueryType;
|
||||||
use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
|
use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
|
||||||
use script_traits::{IFrameLoadInfo, MozBrowserEvent, ScriptMsg as ConstellationMsg};
|
use script_traits::{IFrameLoadInfo, MozBrowserEvent, ScriptMsg as ConstellationMsg};
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
|
@ -25,9 +25,9 @@ use hyper::header::ContentType;
|
||||||
use hyper::mime::{Mime, TopLevel, SubLevel};
|
use hyper::mime::{Mime, TopLevel, SubLevel};
|
||||||
use ipc_channel::ipc;
|
use ipc_channel::ipc;
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
use layout_interface::Msg;
|
|
||||||
use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata, NetworkError};
|
use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata, NetworkError};
|
||||||
use network_listener::{NetworkListener, PreInvoke};
|
use network_listener::{NetworkListener, PreInvoke};
|
||||||
|
use script_layout_interface::message::Msg;
|
||||||
use script_traits::{MozBrowserEvent, ScriptMsg as ConstellationMsg};
|
use script_traits::{MozBrowserEvent, ScriptMsg as ConstellationMsg};
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
|
|
|
@ -68,11 +68,6 @@ impl<'a> ProcessDataURL for &'a HTMLObjectElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_image_data(uri: &str) -> bool {
|
|
||||||
static TYPES: &'static [&'static str] = &["data:image/png", "data:image/gif", "data:image/jpeg"];
|
|
||||||
TYPES.iter().any(|&type_| uri.starts_with(type_))
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HTMLObjectElementMethods for HTMLObjectElement {
|
impl HTMLObjectElementMethods for HTMLObjectElement {
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-cva-validity
|
// https://html.spec.whatwg.org/multipage/#dom-cva-validity
|
||||||
fn Validity(&self) -> Root<ValidityState> {
|
fn Validity(&self) -> Root<ValidityState> {
|
||||||
|
|
|
@ -14,7 +14,7 @@ use dom::element::Element;
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::node::{ChildrenMutation, Node, document_from_node, window_from_node};
|
use dom::node::{ChildrenMutation, Node, document_from_node, window_from_node};
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
use layout_interface::Msg;
|
use script_layout_interface::message::Msg;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use style::media_queries::parse_media_query_list;
|
use style::media_queries::parse_media_query_list;
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
//! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements.
|
//! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements.
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use core::nonzero::NonZero;
|
|
||||||
use devtools_traits::NodeInfo;
|
use devtools_traits::NodeInfo;
|
||||||
use document_loader::DocumentLoader;
|
use document_loader::DocumentLoader;
|
||||||
use dom::attr::Attr;
|
use dom::attr::Attr;
|
||||||
|
@ -22,8 +21,8 @@ use dom::bindings::codegen::UnionTypes::NodeOrString;
|
||||||
use dom::bindings::conversions::{self, DerivedFrom};
|
use dom::bindings::conversions::{self, DerivedFrom};
|
||||||
use dom::bindings::error::{Error, ErrorResult, Fallible};
|
use dom::bindings::error::{Error, ErrorResult, Fallible};
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::inheritance::{Castable, CharacterDataTypeId};
|
use dom::bindings::inheritance::{Castable, CharacterDataTypeId, ElementTypeId};
|
||||||
use dom::bindings::inheritance::{EventTargetTypeId, NodeTypeId};
|
use dom::bindings::inheritance::{EventTargetTypeId, HTMLElementTypeId, NodeTypeId};
|
||||||
use dom::bindings::js::Root;
|
use dom::bindings::js::Root;
|
||||||
use dom::bindings::js::RootedReference;
|
use dom::bindings::js::RootedReference;
|
||||||
use dom::bindings::js::{JS, LayoutJS, MutNullableHeap};
|
use dom::bindings::js::{JS, LayoutJS, MutNullableHeap};
|
||||||
|
@ -38,7 +37,7 @@ use dom::documenttype::DocumentType;
|
||||||
use dom::element::{Element, ElementCreator};
|
use dom::element::{Element, ElementCreator};
|
||||||
use dom::eventtarget::EventTarget;
|
use dom::eventtarget::EventTarget;
|
||||||
use dom::htmlbodyelement::HTMLBodyElement;
|
use dom::htmlbodyelement::HTMLBodyElement;
|
||||||
use dom::htmlcanvaselement::{LayoutHTMLCanvasElementHelpers, HTMLCanvasData};
|
use dom::htmlcanvaselement::LayoutHTMLCanvasElementHelpers;
|
||||||
use dom::htmlcollection::HTMLCollection;
|
use dom::htmlcollection::HTMLCollection;
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods};
|
use dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods};
|
||||||
|
@ -57,11 +56,13 @@ use euclid::size::Size2D;
|
||||||
use heapsize::{HeapSizeOf, heap_size_of};
|
use heapsize::{HeapSizeOf, heap_size_of};
|
||||||
use html5ever::tree_builder::QuirksMode;
|
use html5ever::tree_builder::QuirksMode;
|
||||||
use js::jsapi::{JSContext, JSObject, JSRuntime};
|
use js::jsapi::{JSContext, JSObject, JSRuntime};
|
||||||
use layout_interface::Msg;
|
|
||||||
use libc::{self, c_void, uintptr_t};
|
use libc::{self, c_void, uintptr_t};
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use parse::html::parse_html_fragment;
|
use parse::html::parse_html_fragment;
|
||||||
use ref_slice::ref_slice;
|
use ref_slice::ref_slice;
|
||||||
|
use script_layout_interface::message::Msg;
|
||||||
|
use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData};
|
||||||
|
use script_layout_interface::{LayoutNodeType, LayoutElementType, TrustedNodeAddress};
|
||||||
use script_traits::UntrustedNodeAddress;
|
use script_traits::UntrustedNodeAddress;
|
||||||
use selectors::matching::matches;
|
use selectors::matching::matches;
|
||||||
use selectors::parser::Selector;
|
use selectors::parser::Selector;
|
||||||
|
@ -74,6 +75,7 @@ use std::iter::{self, FilterMap, Peekable};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use string_cache::{Atom, Namespace, QualName};
|
use string_cache::{Atom, Namespace, QualName};
|
||||||
|
use style::dom::OpaqueNode;
|
||||||
use style::selector_impl::ServoSelectorImpl;
|
use style::selector_impl::ServoSelectorImpl;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util::thread_state;
|
use util::thread_state;
|
||||||
|
@ -171,7 +173,7 @@ impl NodeFlags {
|
||||||
impl Drop for Node {
|
impl Drop for Node {
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.style_and_layout_data.get().map(|d| d.dispose(self));
|
self.style_and_layout_data.get().map(|d| self.dispose(d));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,29 +186,15 @@ enum SuppressObserver {
|
||||||
Unsuppressed
|
Unsuppressed
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, HeapSizeOf)]
|
|
||||||
pub struct OpaqueStyleAndLayoutData {
|
|
||||||
#[ignore_heap_size_of = "TODO(#6910) Box value that should be counted but \
|
|
||||||
the type lives in layout"]
|
|
||||||
pub ptr: NonZero<*mut ()>
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
|
||||||
unsafe impl Send for OpaqueStyleAndLayoutData {}
|
|
||||||
|
|
||||||
no_jsmanaged_fields!(OpaqueStyleAndLayoutData);
|
|
||||||
|
|
||||||
impl OpaqueStyleAndLayoutData {
|
|
||||||
/// Sends the style and layout data, if any, back to the layout thread to be destroyed.
|
|
||||||
pub fn dispose(self, node: &Node) {
|
|
||||||
debug_assert!(thread_state::get().is_script());
|
|
||||||
let win = window_from_node(node);
|
|
||||||
node.style_and_layout_data.set(None);
|
|
||||||
win.layout_chan().send(Msg::ReapStyleAndLayoutData(self)).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
|
/// Sends the style and layout data, if any, back to the layout thread to be destroyed.
|
||||||
|
pub fn dispose(&self, data: OpaqueStyleAndLayoutData) {
|
||||||
|
debug_assert!(thread_state::get().is_script());
|
||||||
|
let win = window_from_node(self);
|
||||||
|
self.style_and_layout_data.set(None);
|
||||||
|
win.layout_chan().send(Msg::ReapStyleAndLayoutData(data)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds a new child to the end of this node's list of children.
|
/// Adds a new child to the end of this node's list of children.
|
||||||
///
|
///
|
||||||
/// Fails unless `new_child` is disconnected from the tree.
|
/// Fails unless `new_child` is disconnected from the tree.
|
||||||
|
@ -292,7 +280,7 @@ impl Node {
|
||||||
for node in child.traverse_preorder() {
|
for node in child.traverse_preorder() {
|
||||||
node.set_flag(IS_IN_DOC, false);
|
node.set_flag(IS_IN_DOC, false);
|
||||||
vtable_for(&&*node).unbind_from_tree(&context);
|
vtable_for(&&*node).unbind_from_tree(&context);
|
||||||
node.style_and_layout_data.get().map(|d| d.dispose(&node));
|
node.style_and_layout_data.get().map(|d| node.dispose(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.owner_doc().content_and_heritage_changed(self, NodeDamage::OtherNodeDamage);
|
self.owner_doc().content_and_heritage_changed(self, NodeDamage::OtherNodeDamage);
|
||||||
|
@ -340,7 +328,7 @@ impl<'a> Iterator for QuerySelectorIterator {
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
pub fn teardown(&self) {
|
pub fn teardown(&self) {
|
||||||
self.style_and_layout_data.get().map(|d| d.dispose(self));
|
self.style_and_layout_data.get().map(|d| self.dispose(d));
|
||||||
for kid in self.children() {
|
for kid in self.children() {
|
||||||
kid.teardown();
|
kid.teardown();
|
||||||
}
|
}
|
||||||
|
@ -974,6 +962,7 @@ pub trait LayoutNodeHelpers {
|
||||||
fn image_url(&self) -> Option<Url>;
|
fn image_url(&self) -> Option<Url>;
|
||||||
fn canvas_data(&self) -> Option<HTMLCanvasData>;
|
fn canvas_data(&self) -> Option<HTMLCanvasData>;
|
||||||
fn iframe_pipeline_id(&self) -> PipelineId;
|
fn iframe_pipeline_id(&self) -> PipelineId;
|
||||||
|
fn opaque(&self) -> OpaqueNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutNodeHelpers for LayoutJS<Node> {
|
impl LayoutNodeHelpers for LayoutJS<Node> {
|
||||||
|
@ -1114,6 +1103,13 @@ impl LayoutNodeHelpers for LayoutJS<Node> {
|
||||||
.expect("not an iframe element!");
|
.expect("not an iframe element!");
|
||||||
iframe_element.pipeline_id().unwrap()
|
iframe_element.pipeline_id().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
fn opaque(&self) -> OpaqueNode {
|
||||||
|
unsafe {
|
||||||
|
OpaqueNode(self.get_jsobject() as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2413,17 +2409,6 @@ impl NodeMethods for Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// The address of a node known to be valid. These are sent from script to layout,
|
|
||||||
/// and are also used in the HTML parser interface.
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Copy)]
|
|
||||||
pub struct TrustedNodeAddress(pub *const c_void);
|
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
|
||||||
unsafe impl Send for TrustedNodeAddress {}
|
|
||||||
|
|
||||||
pub fn document_from_node<T: DerivedFrom<Node> + Reflectable>(derived: &T) -> Root<Document> {
|
pub fn document_from_node<T: DerivedFrom<Node> + Reflectable>(derived: &T) -> Root<Document> {
|
||||||
derived.upcast().owner_doc()
|
derived.upcast().owner_doc()
|
||||||
}
|
}
|
||||||
|
@ -2648,3 +2633,56 @@ impl UniqueId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<LayoutNodeType> for NodeTypeId {
|
||||||
|
#[inline(always)]
|
||||||
|
fn into(self) -> LayoutNodeType {
|
||||||
|
match self {
|
||||||
|
NodeTypeId::CharacterData(CharacterDataTypeId::Comment) =>
|
||||||
|
LayoutNodeType::Comment,
|
||||||
|
NodeTypeId::Document(..) =>
|
||||||
|
LayoutNodeType::Document,
|
||||||
|
NodeTypeId::DocumentFragment =>
|
||||||
|
LayoutNodeType::DocumentFragment,
|
||||||
|
NodeTypeId::DocumentType =>
|
||||||
|
LayoutNodeType::DocumentType,
|
||||||
|
NodeTypeId::Element(e) =>
|
||||||
|
LayoutNodeType::Element(e.into()),
|
||||||
|
NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) =>
|
||||||
|
LayoutNodeType::ProcessingInstruction,
|
||||||
|
NodeTypeId::CharacterData(CharacterDataTypeId::Text) =>
|
||||||
|
LayoutNodeType::Text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<LayoutElementType> for ElementTypeId {
|
||||||
|
#[inline(always)]
|
||||||
|
fn into(self) -> LayoutElementType {
|
||||||
|
match self {
|
||||||
|
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement) =>
|
||||||
|
LayoutElementType::HTMLCanvasElement,
|
||||||
|
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement) =>
|
||||||
|
LayoutElementType::HTMLIFrameElement,
|
||||||
|
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement) =>
|
||||||
|
LayoutElementType::HTMLImageElement,
|
||||||
|
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement) =>
|
||||||
|
LayoutElementType::HTMLInputElement,
|
||||||
|
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement) =>
|
||||||
|
LayoutElementType::HTMLObjectElement,
|
||||||
|
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableCellElement(_)) =>
|
||||||
|
LayoutElementType::HTMLTableCellElement,
|
||||||
|
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableColElement) =>
|
||||||
|
LayoutElementType::HTMLTableColElement,
|
||||||
|
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableElement) =>
|
||||||
|
LayoutElementType::HTMLTableElement,
|
||||||
|
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement) =>
|
||||||
|
LayoutElementType::HTMLTableRowElement,
|
||||||
|
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableSectionElement) =>
|
||||||
|
LayoutElementType::HTMLTableSectionElement,
|
||||||
|
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement) =>
|
||||||
|
LayoutElementType::HTMLTextAreaElement,
|
||||||
|
_ => LayoutElementType::Element,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ use dom::element::Element;
|
||||||
use dom::eventtarget::EventTarget;
|
use dom::eventtarget::EventTarget;
|
||||||
use dom::location::Location;
|
use dom::location::Location;
|
||||||
use dom::navigator::Navigator;
|
use dom::navigator::Navigator;
|
||||||
use dom::node::{Node, TrustedNodeAddress, from_untrusted_node_address, window_from_node};
|
use dom::node::{Node, from_untrusted_node_address, window_from_node};
|
||||||
use dom::performance::Performance;
|
use dom::performance::Performance;
|
||||||
use dom::screen::Screen;
|
use dom::screen::Screen;
|
||||||
use dom::storage::Storage;
|
use dom::storage::Storage;
|
||||||
|
@ -42,8 +42,6 @@ use js::jsapi::{Evaluate2, HandleObject, HandleValue, JSAutoCompartment, JSConte
|
||||||
use js::jsapi::{JS_GetRuntime, JS_GC, MutableHandleValue, SetWindowProxy};
|
use js::jsapi::{JS_GetRuntime, JS_GC, MutableHandleValue, SetWindowProxy};
|
||||||
use js::rust::CompileOptionsWrapper;
|
use js::rust::CompileOptionsWrapper;
|
||||||
use js::rust::Runtime;
|
use js::rust::Runtime;
|
||||||
use layout_interface::{ContentBoxResponse, ContentBoxesResponse, ResolvedStyleResponse, ScriptReflow};
|
|
||||||
use layout_interface::{LayoutRPC, Msg, Reflow, ReflowQueryType, MarginStyleResponse};
|
|
||||||
use libc;
|
use libc;
|
||||||
use msg::constellation_msg::{FrameType, LoadData, PanicMsg, PipelineId, SubpageId};
|
use msg::constellation_msg::{FrameType, LoadData, PanicMsg, PipelineId, SubpageId};
|
||||||
use msg::constellation_msg::{WindowSizeData, WindowSizeType};
|
use msg::constellation_msg::{WindowSizeData, WindowSizeType};
|
||||||
|
@ -57,8 +55,12 @@ use open;
|
||||||
use profile_traits::mem;
|
use profile_traits::mem;
|
||||||
use profile_traits::time::{ProfilerCategory, TimerMetadata, TimerMetadataFrameType};
|
use profile_traits::time::{ProfilerCategory, TimerMetadata, TimerMetadataFrameType};
|
||||||
use profile_traits::time::{ProfilerChan, TimerMetadataReflowType, profile};
|
use profile_traits::time::{ProfilerChan, TimerMetadataReflowType, profile};
|
||||||
use reporter::CSSErrorReporter;
|
|
||||||
use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64};
|
use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64};
|
||||||
|
use script_layout_interface::TrustedNodeAddress;
|
||||||
|
use script_layout_interface::message::{Msg, Reflow, ReflowQueryType, ScriptReflow};
|
||||||
|
use script_layout_interface::reporter::CSSErrorReporter;
|
||||||
|
use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC};
|
||||||
|
use script_layout_interface::rpc::{MarginStyleResponse, ResolvedStyleResponse};
|
||||||
use script_runtime::{ScriptChan, ScriptPort};
|
use script_runtime::{ScriptChan, ScriptPort};
|
||||||
use script_thread::SendableMainThreadScriptChan;
|
use script_thread::SendableMainThreadScriptChan;
|
||||||
use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, RunnableWrapper};
|
use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, RunnableWrapper};
|
||||||
|
|
999
components/script/layout_wrapper.rs
Normal file
999
components/script/layout_wrapper.rs
Normal file
|
@ -0,0 +1,999 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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/. */
|
||||||
|
|
||||||
|
//! A safe wrapper for DOM nodes that prevents layout from mutating the DOM, from letting DOM nodes
|
||||||
|
//! escape, and from generally doing anything that it isn't supposed to. This is accomplished via
|
||||||
|
//! a simple whitelist of allowed operations, along with some lifetime magic to prevent nodes from
|
||||||
|
//! escaping.
|
||||||
|
//!
|
||||||
|
//! As a security wrapper is only as good as its whitelist, be careful when adding operations to
|
||||||
|
//! this list. The cardinal rules are:
|
||||||
|
//!
|
||||||
|
//! 1. Layout is not allowed to mutate the DOM.
|
||||||
|
//!
|
||||||
|
//! 2. Layout is not allowed to see anything with `LayoutJS` in the name, because it could hang
|
||||||
|
//! onto these objects and cause use-after-free.
|
||||||
|
//!
|
||||||
|
//! When implementing wrapper functions, be careful that you do not touch the borrow flags, or you
|
||||||
|
//! will race and cause spurious thread failure. (Note that I do not believe these races are
|
||||||
|
//! exploitable, but they'll result in brokenness nonetheless.)
|
||||||
|
//!
|
||||||
|
//! Rules of the road for this file:
|
||||||
|
//!
|
||||||
|
//! * 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()`.
|
||||||
|
//!
|
||||||
|
//! o Instead of `html_element_in_html_document()`, use
|
||||||
|
//! `html_element_in_html_document_for_layout()`.
|
||||||
|
|
||||||
|
#![allow(unsafe_code)]
|
||||||
|
|
||||||
|
use dom::bindings::inheritance::{CharacterDataTypeId, ElementTypeId};
|
||||||
|
use dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId};
|
||||||
|
use dom::bindings::js::LayoutJS;
|
||||||
|
use dom::characterdata::LayoutCharacterDataHelpers;
|
||||||
|
use dom::document::{Document, LayoutDocumentHelpers};
|
||||||
|
use dom::element::{Element, LayoutElementHelpers, RawLayoutElementHelpers};
|
||||||
|
use dom::node::{CAN_BE_FRAGMENTED, HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY};
|
||||||
|
use dom::node::{Node, LayoutNodeHelpers};
|
||||||
|
use dom::text::Text;
|
||||||
|
use gfx_traits::ByteIndex;
|
||||||
|
use msg::constellation_msg::PipelineId;
|
||||||
|
use range::Range;
|
||||||
|
use script_layout_interface::restyle_damage::RestyleDamage;
|
||||||
|
use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, LayoutNode, PseudoElementType};
|
||||||
|
use script_layout_interface::wrapper_traits::{ThreadSafeLayoutNode, ThreadSafeLayoutElement};
|
||||||
|
use script_layout_interface::{HTMLCanvasData, LayoutNodeType, TrustedNodeAddress};
|
||||||
|
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData};
|
||||||
|
use selectors::matching::{DeclarationBlock, ElementFlags};
|
||||||
|
use selectors::parser::{AttrSelector, NamespaceConstraint};
|
||||||
|
use smallvec::VecLike;
|
||||||
|
use std::cell::{Ref, RefCell, RefMut};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::mem::{transmute, transmute_copy};
|
||||||
|
use string_cache::{Atom, BorrowedAtom, BorrowedNamespace, Namespace};
|
||||||
|
use style::attr::AttrValue;
|
||||||
|
use style::computed_values::display;
|
||||||
|
use style::dom::{PresentationalHintsSynthetizer, OpaqueNode, TDocument, TElement, TNode, UnsafeNode};
|
||||||
|
use style::element_state::*;
|
||||||
|
use style::properties::{ComputedValues, ServoComputedValues};
|
||||||
|
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
|
||||||
|
use style::restyle_hints::ElementSnapshot;
|
||||||
|
use style::selector_impl::{NonTSPseudoClass, ServoSelectorImpl};
|
||||||
|
use style::servo::{PrivateStyleData, SharedStyleContext};
|
||||||
|
use url::Url;
|
||||||
|
use util::str::is_whitespace;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct ServoLayoutNode<'a> {
|
||||||
|
/// The wrapped node.
|
||||||
|
node: LayoutJS<Node>,
|
||||||
|
|
||||||
|
/// Being chained to a PhantomData prevents `LayoutNode`s from escaping.
|
||||||
|
chain: PhantomData<&'a ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PartialEq for ServoLayoutNode<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &ServoLayoutNode) -> bool {
|
||||||
|
self.node == other.node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ln> ServoLayoutNode<'ln> {
|
||||||
|
fn from_layout_js(n: LayoutJS<Node>) -> ServoLayoutNode<'ln> {
|
||||||
|
ServoLayoutNode {
|
||||||
|
node: n,
|
||||||
|
chain: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn new(address: &TrustedNodeAddress) -> ServoLayoutNode {
|
||||||
|
ServoLayoutNode::from_layout_js(LayoutJS::from_trusted_node_address(*address))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new layout node with the same lifetime as this layout node.
|
||||||
|
pub unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> ServoLayoutNode<'ln> {
|
||||||
|
ServoLayoutNode {
|
||||||
|
node: *node,
|
||||||
|
chain: self.chain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn script_type_id(&self) -> NodeTypeId {
|
||||||
|
unsafe {
|
||||||
|
self.node.type_id_for_layout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ln> TNode for ServoLayoutNode<'ln> {
|
||||||
|
type ConcreteComputedValues = ServoComputedValues;
|
||||||
|
type ConcreteElement = ServoLayoutElement<'ln>;
|
||||||
|
type ConcreteDocument = ServoLayoutDocument<'ln>;
|
||||||
|
type ConcreteRestyleDamage = RestyleDamage;
|
||||||
|
|
||||||
|
fn to_unsafe(&self) -> UnsafeNode {
|
||||||
|
unsafe {
|
||||||
|
let ptr: usize = transmute_copy(self);
|
||||||
|
(ptr, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn from_unsafe(n: &UnsafeNode) -> Self {
|
||||||
|
let (node, _) = *n;
|
||||||
|
transmute(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_text_node(&self) -> bool {
|
||||||
|
self.script_type_id() == NodeTypeId::CharacterData(CharacterDataTypeId::Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_element(&self) -> bool {
|
||||||
|
unsafe {
|
||||||
|
self.node.is_element_for_layout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dump(self) {
|
||||||
|
self.dump_indent(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opaque(&self) -> OpaqueNode {
|
||||||
|
unsafe { self.get_jsmanaged().opaque() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout_parent_node(self, reflow_root: OpaqueNode) -> Option<ServoLayoutNode<'ln>> {
|
||||||
|
if self.opaque() == reflow_root {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
self.parent_node()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn debug_id(self) -> usize {
|
||||||
|
self.opaque().0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn children_count(&self) -> u32 {
|
||||||
|
unsafe { self.node.children_count() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_element(&self) -> Option<ServoLayoutElement<'ln>> {
|
||||||
|
as_element(self.node)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_document(&self) -> Option<ServoLayoutDocument<'ln>> {
|
||||||
|
self.node.downcast().map(ServoLayoutDocument::from_layout_js)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_changed(&self) -> bool {
|
||||||
|
unsafe { self.node.get_flag(HAS_CHANGED) }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_changed(&self, value: bool) {
|
||||||
|
self.node.set_flag(HAS_CHANGED, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_dirty(&self) -> bool {
|
||||||
|
unsafe { self.node.get_flag(IS_DIRTY) }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_dirty(&self, value: bool) {
|
||||||
|
self.node.set_flag(IS_DIRTY, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_dirty_descendants(&self) -> bool {
|
||||||
|
unsafe { self.node.get_flag(HAS_DIRTY_DESCENDANTS) }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_dirty_descendants(&self, value: bool) {
|
||||||
|
self.node.set_flag(HAS_DIRTY_DESCENDANTS, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_be_fragmented(&self) -> bool {
|
||||||
|
unsafe { self.node.get_flag(CAN_BE_FRAGMENTED) }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_can_be_fragmented(&self, value: bool) {
|
||||||
|
self.node.set_flag(CAN_BE_FRAGMENTED, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn borrow_data_unchecked(&self) -> Option<*const PrivateStyleData> {
|
||||||
|
self.get_style_data().map(|d| {
|
||||||
|
&(*d.as_unsafe_cell().get()).style_data as *const _
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn borrow_data(&self) -> Option<Ref<PrivateStyleData>> {
|
||||||
|
self.get_style_data().map(|d| {
|
||||||
|
Ref::map(d.borrow(), |d| &d.style_data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mutate_data(&self) -> Option<RefMut<PrivateStyleData>> {
|
||||||
|
self.get_style_data().map(|d| {
|
||||||
|
RefMut::map(d.borrow_mut(), |d| &mut d.style_data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restyle_damage(self) -> RestyleDamage {
|
||||||
|
self.get_style_data().unwrap().borrow().restyle_damage
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_restyle_damage(self, damage: RestyleDamage) {
|
||||||
|
self.get_style_data().unwrap().borrow_mut().restyle_damage = damage;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parent_node(&self) -> Option<ServoLayoutNode<'ln>> {
|
||||||
|
unsafe {
|
||||||
|
self.node.parent_node_ref().map(|node| self.new_with_this_lifetime(&node))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first_child(&self) -> Option<ServoLayoutNode<'ln>> {
|
||||||
|
unsafe {
|
||||||
|
self.node.first_child_ref().map(|node| self.new_with_this_lifetime(&node))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last_child(&self) -> Option<ServoLayoutNode<'ln>> {
|
||||||
|
unsafe {
|
||||||
|
self.node.last_child_ref().map(|node| self.new_with_this_lifetime(&node))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prev_sibling(&self) -> Option<ServoLayoutNode<'ln>> {
|
||||||
|
unsafe {
|
||||||
|
self.node.prev_sibling_ref().map(|node| self.new_with_this_lifetime(&node))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_sibling(&self) -> Option<ServoLayoutNode<'ln>> {
|
||||||
|
unsafe {
|
||||||
|
self.node.next_sibling_ref().map(|node| self.new_with_this_lifetime(&node))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ln> LayoutNode for ServoLayoutNode<'ln> {
|
||||||
|
type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'ln>;
|
||||||
|
|
||||||
|
fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode {
|
||||||
|
ServoThreadSafeLayoutNode::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_id(&self) -> LayoutNodeType {
|
||||||
|
self.script_type_id().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_style_data(&self) -> Option<&RefCell<PartialStyleAndLayoutData>> {
|
||||||
|
unsafe {
|
||||||
|
self.get_jsmanaged().get_style_and_layout_data().map(|d| {
|
||||||
|
&**d.ptr
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) {
|
||||||
|
unsafe {
|
||||||
|
self.get_jsmanaged().init_style_and_layout_data(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
|
||||||
|
unsafe {
|
||||||
|
self.get_jsmanaged().get_style_and_layout_data()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ln> ServoLayoutNode<'ln> {
|
||||||
|
fn dump_indent(self, indent: u32) {
|
||||||
|
let mut s = String::new();
|
||||||
|
for _ in 0..indent {
|
||||||
|
s.push_str(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
s.push_str(&self.debug_str());
|
||||||
|
println!("{}", s);
|
||||||
|
|
||||||
|
for kid in self.children() {
|
||||||
|
kid.dump_indent(indent + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn debug_str(self) -> String {
|
||||||
|
format!("{:?}: changed={} dirty={} dirty_descendants={}",
|
||||||
|
self.script_type_id(), self.has_changed(), self.is_dirty(), self.has_dirty_descendants())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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(&self) -> &LayoutJS<Node> {
|
||||||
|
&self.node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A wrapper around documents that ensures ayout can only ever access safe properties.
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct ServoLayoutDocument<'ld> {
|
||||||
|
document: LayoutJS<Document>,
|
||||||
|
chain: PhantomData<&'ld ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ld> TDocument for ServoLayoutDocument<'ld> {
|
||||||
|
type ConcreteNode = ServoLayoutNode<'ld>;
|
||||||
|
type ConcreteElement = ServoLayoutElement<'ld>;
|
||||||
|
|
||||||
|
fn as_node(&self) -> ServoLayoutNode<'ld> {
|
||||||
|
ServoLayoutNode::from_layout_js(self.document.upcast())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn root_node(&self) -> Option<ServoLayoutNode<'ld>> {
|
||||||
|
self.as_node().children().find(ServoLayoutNode::is_element)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drain_modified_elements(&self) -> Vec<(ServoLayoutElement<'ld>, ElementSnapshot)> {
|
||||||
|
let elements = unsafe { self.document.drain_modified_elements() };
|
||||||
|
elements.into_iter().map(|(el, snapshot)| (ServoLayoutElement::from_layout_js(el), snapshot)).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ld> ServoLayoutDocument<'ld> {
|
||||||
|
fn from_layout_js(doc: LayoutJS<Document>) -> ServoLayoutDocument<'ld> {
|
||||||
|
ServoLayoutDocument {
|
||||||
|
document: doc,
|
||||||
|
chain: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A wrapper around elements that ensures layout can only ever access safe properties.
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct ServoLayoutElement<'le> {
|
||||||
|
element: LayoutJS<Element>,
|
||||||
|
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>;
|
||||||
|
|
||||||
|
fn as_node(&self) -> ServoLayoutNode<'le> {
|
||||||
|
ServoLayoutNode::from_layout_js(self.element.upcast())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn style_attribute(&self) -> &Option<PropertyDeclarationBlock> {
|
||||||
|
unsafe {
|
||||||
|
&*self.element.style_attribute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_state(&self) -> ElementState {
|
||||||
|
self.element.get_state_for_layout()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str> {
|
||||||
|
unsafe {
|
||||||
|
(*self.element.unsafe_get()).get_attr_val_for_layout(namespace, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_attrs(&self, name: &Atom) -> Vec<&str> {
|
||||||
|
unsafe {
|
||||||
|
(*self.element.unsafe_get()).get_attr_vals_for_layout(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'le> ServoLayoutElement<'le> {
|
||||||
|
fn from_layout_js(el: LayoutJS<Element>) -> ServoLayoutElement<'le> {
|
||||||
|
ServoLayoutElement {
|
||||||
|
element: el,
|
||||||
|
chain: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_element<'le>(node: LayoutJS<Node>) -> Option<ServoLayoutElement<'le>> {
|
||||||
|
node.downcast().map(ServoLayoutElement::from_layout_js)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
||||||
|
type Impl = ServoSelectorImpl;
|
||||||
|
|
||||||
|
fn parent_element(&self) -> Option<ServoLayoutElement<'le>> {
|
||||||
|
unsafe {
|
||||||
|
self.element.upcast().parent_node_ref().and_then(as_element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first_child_element(&self) -> Option<ServoLayoutElement<'le>> {
|
||||||
|
self.as_node().children().filter_map(|n| n.as_element()).next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last_child_element(&self) -> Option<ServoLayoutElement<'le>> {
|
||||||
|
self.as_node().rev_children().filter_map(|n| n.as_element()).next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prev_sibling_element(&self) -> Option<ServoLayoutElement<'le>> {
|
||||||
|
let mut node = self.as_node();
|
||||||
|
while let Some(sibling) = node.prev_sibling() {
|
||||||
|
if let Some(element) = sibling.as_element() {
|
||||||
|
return Some(element)
|
||||||
|
}
|
||||||
|
node = sibling;
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_sibling_element(&self) -> Option<ServoLayoutElement<'le>> {
|
||||||
|
let mut node = self.as_node();
|
||||||
|
while let Some(sibling) = node.next_sibling() {
|
||||||
|
if let Some(element) = sibling.as_element() {
|
||||||
|
return Some(element)
|
||||||
|
}
|
||||||
|
node = sibling;
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_root(&self) -> bool {
|
||||||
|
match self.as_node().parent_node() {
|
||||||
|
None => false,
|
||||||
|
Some(node) => {
|
||||||
|
match node.script_type_id() {
|
||||||
|
NodeTypeId::Document(_) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.as_node().children().all(|node| match node.script_type_id() {
|
||||||
|
NodeTypeId::Element(..) => false,
|
||||||
|
NodeTypeId::CharacterData(CharacterDataTypeId::Text) => unsafe {
|
||||||
|
node.node.downcast().unwrap().data_for_layout().is_empty()
|
||||||
|
},
|
||||||
|
_ => true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_local_name<'a>(&'a self) -> BorrowedAtom<'a> {
|
||||||
|
BorrowedAtom(self.element.local_name())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_namespace<'a>(&'a self) -> BorrowedNamespace<'a> {
|
||||||
|
BorrowedNamespace(self.element.namespace())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_non_ts_pseudo_class(&self, pseudo_class: NonTSPseudoClass) -> bool {
|
||||||
|
match pseudo_class {
|
||||||
|
// https://github.com/servo/servo/issues/8718
|
||||||
|
NonTSPseudoClass::Link |
|
||||||
|
NonTSPseudoClass::AnyLink => unsafe {
|
||||||
|
match self.as_node().script_type_id() {
|
||||||
|
// https://html.spec.whatwg.org/multipage/#selector-link
|
||||||
|
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAnchorElement)) |
|
||||||
|
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAreaElement)) |
|
||||||
|
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) =>
|
||||||
|
(*self.element.unsafe_get()).get_attr_val_for_layout(&ns!(), &atom!("href")).is_some(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NonTSPseudoClass::Visited => false,
|
||||||
|
|
||||||
|
NonTSPseudoClass::ServoNonZeroBorder => unsafe {
|
||||||
|
match (*self.element.unsafe_get()).get_attr_for_layout(&ns!(), &atom!("border")) {
|
||||||
|
None | Some(&AttrValue::UInt(_, 0)) => false,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
NonTSPseudoClass::ReadOnly =>
|
||||||
|
!self.element.get_state_for_layout().contains(pseudo_class.state_flag()),
|
||||||
|
|
||||||
|
NonTSPseudoClass::Active |
|
||||||
|
NonTSPseudoClass::Focus |
|
||||||
|
NonTSPseudoClass::Hover |
|
||||||
|
NonTSPseudoClass::Enabled |
|
||||||
|
NonTSPseudoClass::Disabled |
|
||||||
|
NonTSPseudoClass::Checked |
|
||||||
|
NonTSPseudoClass::Indeterminate |
|
||||||
|
NonTSPseudoClass::ReadWrite |
|
||||||
|
NonTSPseudoClass::PlaceholderShown =>
|
||||||
|
self.element.get_state_for_layout().contains(pseudo_class.state_flag())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_id(&self) -> Option<Atom> {
|
||||||
|
unsafe {
|
||||||
|
(*self.element.id_attribute()).clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn has_class(&self, name: &Atom) -> bool {
|
||||||
|
unsafe {
|
||||||
|
self.element.has_class_for_layout(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn each_class<F>(&self, mut callback: F) where F: FnMut(&Atom) {
|
||||||
|
unsafe {
|
||||||
|
if let Some(ref classes) = self.element.get_classes_for_layout() {
|
||||||
|
for class in *classes {
|
||||||
|
callback(class)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool where F: Fn(&str) -> bool {
|
||||||
|
let name = if self.is_html_element_in_html_document() {
|
||||||
|
&attr.lower_name
|
||||||
|
} else {
|
||||||
|
&attr.name
|
||||||
|
};
|
||||||
|
match attr.namespace {
|
||||||
|
NamespaceConstraint::Specific(ref ns) => {
|
||||||
|
self.get_attr(ns, name).map_or(false, |attr| test(attr))
|
||||||
|
},
|
||||||
|
NamespaceConstraint::Any => {
|
||||||
|
self.get_attrs(name).iter().any(|attr| test(*attr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_html_element_in_html_document(&self) -> bool {
|
||||||
|
unsafe {
|
||||||
|
self.element.html_element_in_html_document_for_layout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_flags(&self, flags: ElementFlags) {
|
||||||
|
self.element.insert_atomic_flags(flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct ServoThreadSafeLayoutNode<'ln> {
|
||||||
|
/// The wrapped node.
|
||||||
|
node: ServoLayoutNode<'ln>,
|
||||||
|
|
||||||
|
/// The pseudo-element type, with (optionally),
|
||||||
|
/// an specified display value to override the stylesheet.
|
||||||
|
pseudo: PseudoElementType<Option<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))
|
||||||
|
}
|
||||||
|
unsafe fn dangerous_next_sibling(&self) -> Option<Self> {
|
||||||
|
self.get_jsmanaged().next_sibling_ref()
|
||||||
|
.map(|node| self.new_with_this_lifetime(&node))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ln> ServoThreadSafeLayoutNode<'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>) -> ServoThreadSafeLayoutNode<'ln> {
|
||||||
|
ServoThreadSafeLayoutNode {
|
||||||
|
node: self.node.new_with_this_lifetime(node),
|
||||||
|
pseudo: PseudoElementType::Normal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new `ServoThreadSafeLayoutNode` from the given `ServoLayoutNode`.
|
||||||
|
pub fn new<'a>(node: &ServoLayoutNode<'a>) -> ServoThreadSafeLayoutNode<'a> {
|
||||||
|
ServoThreadSafeLayoutNode {
|
||||||
|
node: node.clone(),
|
||||||
|
pseudo: PseudoElementType::Normal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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(&self) -> &LayoutJS<Node> {
|
||||||
|
self.node.get_jsmanaged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
|
||||||
|
type ConcreteThreadSafeLayoutElement = ServoThreadSafeLayoutElement<'ln>;
|
||||||
|
type ChildrenIterator = ThreadSafeLayoutNodeChildrenIterator<Self>;
|
||||||
|
|
||||||
|
fn with_pseudo(&self,
|
||||||
|
pseudo: PseudoElementType<Option<display::T>>) -> ServoThreadSafeLayoutNode<'ln> {
|
||||||
|
ServoThreadSafeLayoutNode {
|
||||||
|
node: self.node.clone(),
|
||||||
|
pseudo: pseudo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opaque(&self) -> OpaqueNode {
|
||||||
|
unsafe { self.get_jsmanaged().opaque() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_id(&self) -> Option<LayoutNodeType> {
|
||||||
|
if self.pseudo != PseudoElementType::Normal {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(self.node.type_id())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn type_id_without_excluding_pseudo_elements(&self) -> LayoutNodeType {
|
||||||
|
self.node.type_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn debug_id(self) -> usize {
|
||||||
|
self.node.debug_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn children(&self) -> Self::ChildrenIterator {
|
||||||
|
ThreadSafeLayoutNodeChildrenIterator::new(*self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_element(&self) -> ServoThreadSafeLayoutElement<'ln> {
|
||||||
|
unsafe {
|
||||||
|
let element = match self.get_jsmanaged().downcast() {
|
||||||
|
Some(e) => e.unsafe_get(),
|
||||||
|
None => panic!("not an element")
|
||||||
|
};
|
||||||
|
// FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on
|
||||||
|
// implementations.
|
||||||
|
ServoThreadSafeLayoutElement {
|
||||||
|
element: &*element,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pseudo_element_type(&self) -> PseudoElementType<Option<display::T>> {
|
||||||
|
self.pseudo
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
|
||||||
|
self.node.get_style_and_layout_data()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool {
|
||||||
|
unsafe {
|
||||||
|
let text: LayoutJS<Text> = match self.get_jsmanaged().downcast() {
|
||||||
|
Some(text) => text,
|
||||||
|
None => return false
|
||||||
|
};
|
||||||
|
|
||||||
|
if !is_whitespace(text.upcast().data_for_layout()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NB: See the rules for `white-space` here:
|
||||||
|
//
|
||||||
|
// http://www.w3.org/TR/CSS21/text.html#propdef-white-space
|
||||||
|
//
|
||||||
|
// If you implement other values for this property, you will almost certainly
|
||||||
|
// want to update this check.
|
||||||
|
!self.style(context).get_inheritedtext().white_space.preserve_newlines()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restyle_damage(self) -> RestyleDamage {
|
||||||
|
self.node.restyle_damage()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_restyle_damage(self, damage: RestyleDamage) {
|
||||||
|
self.node.set_restyle_damage(damage)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_be_fragmented(&self) -> bool {
|
||||||
|
self.node.can_be_fragmented()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_text_content(&self) -> String {
|
||||||
|
let this = unsafe { self.get_jsmanaged() };
|
||||||
|
return this.text_content();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn selection(&self) -> Option<Range<ByteIndex>> {
|
||||||
|
let this = unsafe { self.get_jsmanaged() };
|
||||||
|
|
||||||
|
this.selection().map(|range| {
|
||||||
|
Range::new(ByteIndex(range.start as isize),
|
||||||
|
ByteIndex(range.len() as isize))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn image_url(&self) -> Option<Url> {
|
||||||
|
let this = unsafe { self.get_jsmanaged() };
|
||||||
|
this.image_url()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn canvas_data(&self) -> Option<HTMLCanvasData> {
|
||||||
|
let this = unsafe { self.get_jsmanaged() };
|
||||||
|
this.canvas_data()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iframe_pipeline_id(&self) -> PipelineId {
|
||||||
|
let this = unsafe { self.get_jsmanaged() };
|
||||||
|
this.iframe_pipeline_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_colspan(&self) -> u32 {
|
||||||
|
unsafe {
|
||||||
|
self.get_jsmanaged().downcast::<Element>().unwrap().get_colspan()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_style_data(&self) -> Option<&RefCell<PartialStyleAndLayoutData>> {
|
||||||
|
self.node.get_style_data()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ThreadSafeLayoutNodeChildrenIterator<ConcreteNode: ThreadSafeLayoutNode> {
|
||||||
|
current_node: Option<ConcreteNode>,
|
||||||
|
parent_node: ConcreteNode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<ConcreteNode> ThreadSafeLayoutNodeChildrenIterator<ConcreteNode>
|
||||||
|
where ConcreteNode: DangerousThreadSafeLayoutNode {
|
||||||
|
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_details_summary_pseudo()).or_else(|| {
|
||||||
|
unsafe { parent.dangerous_first_child() }
|
||||||
|
})
|
||||||
|
},
|
||||||
|
PseudoElementType::DetailsContent(_) | PseudoElementType::DetailsSummary(_) => {
|
||||||
|
unsafe { parent.dangerous_first_child() }
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
ThreadSafeLayoutNodeChildrenIterator {
|
||||||
|
current_node: first_child,
|
||||||
|
parent_node: parent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<ConcreteNode>
|
||||||
|
where ConcreteNode: DangerousThreadSafeLayoutNode {
|
||||||
|
type Item = ConcreteNode;
|
||||||
|
fn next(&mut self) -> Option<ConcreteNode> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A wrapper around elements that ensures layout can only
|
||||||
|
/// ever access safe properties and cannot race on elements.
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct ServoThreadSafeLayoutElement<'le> {
|
||||||
|
element: &'le Element,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> {
|
||||||
|
type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'le>;
|
||||||
|
|
||||||
|
fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str> {
|
||||||
|
unsafe {
|
||||||
|
self.element.get_attr_val_for_layout(namespace, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_local_name<'a>(&'a self) -> BorrowedAtom<'a> {
|
||||||
|
BorrowedAtom(self.element.local_name())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_namespace<'a>(&'a self) -> BorrowedNamespace<'a> {
|
||||||
|
BorrowedNamespace(self.element.namespace())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This implementation of `::selectors::Element` is used for implementing lazy
|
||||||
|
/// pseudo-elements.
|
||||||
|
///
|
||||||
|
/// Lazy pseudo-elements in Servo only allows selectors using safe properties,
|
||||||
|
/// i.e., local_name, attributes, so they can only be used for **private**
|
||||||
|
/// pseudo-elements (like `::-servo-details-content`).
|
||||||
|
///
|
||||||
|
/// Probably a few more of this functions can be implemented (like `has_class`,
|
||||||
|
/// `each_class`, etc), but they have no use right now.
|
||||||
|
///
|
||||||
|
/// Note that the element implementation is needed only for selector matching,
|
||||||
|
/// not for inheritance (styles are inherited appropiately).
|
||||||
|
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 {
|
||||||
|
debug!("ServoThreadSafeLayoutElement::is_html_element_in_html_document called");
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_local_name<'a>(&'a self) -> BorrowedAtom<'a> {
|
||||||
|
ThreadSafeLayoutElement::get_local_name(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_namespace<'a>(&'a self) -> BorrowedNamespace<'a> {
|
||||||
|
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> {
|
||||||
|
debug!("ServoThreadSafeLayoutElement::get_id called");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_class(&self, _name: &Atom) -> bool {
|
||||||
|
debug!("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>>> {}
|
||||||
|
}
|
|
@ -65,10 +65,12 @@ extern crate phf;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate profile_traits;
|
extern crate profile_traits;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
extern crate range;
|
||||||
extern crate ref_filter_map;
|
extern crate ref_filter_map;
|
||||||
extern crate ref_slice;
|
extern crate ref_slice;
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
extern crate rustc_serialize;
|
extern crate rustc_serialize;
|
||||||
|
extern crate script_layout_interface;
|
||||||
extern crate script_traits;
|
extern crate script_traits;
|
||||||
extern crate selectors;
|
extern crate selectors;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
@ -93,12 +95,11 @@ mod devtools;
|
||||||
pub mod document_loader;
|
pub mod document_loader;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod dom;
|
pub mod dom;
|
||||||
pub mod layout_interface;
|
pub mod layout_wrapper;
|
||||||
mod mem;
|
mod mem;
|
||||||
mod network_listener;
|
mod network_listener;
|
||||||
pub mod origin;
|
pub mod origin;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
pub mod reporter;
|
|
||||||
pub mod script_runtime;
|
pub mod script_runtime;
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub mod script_thread;
|
pub mod script_thread;
|
||||||
|
|
|
@ -61,7 +61,6 @@ use js::jsapi::{JSAutoCompartment, JSContext, JS_SetWrapObjectCallbacks};
|
||||||
use js::jsapi::{JSTracer, SetWindowProxyClass};
|
use js::jsapi::{JSTracer, SetWindowProxyClass};
|
||||||
use js::jsval::UndefinedValue;
|
use js::jsval::UndefinedValue;
|
||||||
use js::rust::Runtime;
|
use js::rust::Runtime;
|
||||||
use layout_interface::{self, NewLayoutThreadInfo, ReflowQueryType};
|
|
||||||
use mem::heap_size_of_self_and_children;
|
use mem::heap_size_of_self_and_children;
|
||||||
use msg::constellation_msg::{FrameType, LoadData, PanicMsg, PipelineId, PipelineNamespace};
|
use msg::constellation_msg::{FrameType, LoadData, PanicMsg, PipelineId, PipelineNamespace};
|
||||||
use msg::constellation_msg::{SubpageId, WindowSizeData, WindowSizeType};
|
use msg::constellation_msg::{SubpageId, WindowSizeData, WindowSizeType};
|
||||||
|
@ -77,6 +76,7 @@ use parse::html::{ParseContext, parse_html};
|
||||||
use parse::xml::{self, parse_xml};
|
use parse::xml::{self, parse_xml};
|
||||||
use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan};
|
use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan};
|
||||||
use profile_traits::time::{self, ProfilerCategory, profile};
|
use profile_traits::time::{self, ProfilerCategory, profile};
|
||||||
|
use script_layout_interface::message::{self, NewLayoutThreadInfo, ReflowQueryType};
|
||||||
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
|
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
|
||||||
use script_runtime::{ScriptPort, StackRootTLS, new_rt_and_cx, get_reports};
|
use script_runtime::{ScriptPort, StackRootTLS, new_rt_and_cx, get_reports};
|
||||||
use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent};
|
use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent};
|
||||||
|
@ -135,7 +135,7 @@ struct InProgressLoad {
|
||||||
/// The current window size associated with this pipeline.
|
/// The current window size associated with this pipeline.
|
||||||
window_size: Option<WindowSizeData>,
|
window_size: Option<WindowSizeData>,
|
||||||
/// Channel to the layout thread associated with this pipeline.
|
/// Channel to the layout thread associated with this pipeline.
|
||||||
layout_chan: Sender<layout_interface::Msg>,
|
layout_chan: Sender<message::Msg>,
|
||||||
/// The current viewport clipping rectangle applying to this pipeline, if any.
|
/// The current viewport clipping rectangle applying to this pipeline, if any.
|
||||||
clip_rect: Option<Rect<f32>>,
|
clip_rect: Option<Rect<f32>>,
|
||||||
/// Window is frozen (navigated away while loading for example).
|
/// Window is frozen (navigated away while loading for example).
|
||||||
|
@ -150,7 +150,7 @@ impl InProgressLoad {
|
||||||
/// Create a new InProgressLoad object.
|
/// Create a new InProgressLoad object.
|
||||||
fn new(id: PipelineId,
|
fn new(id: PipelineId,
|
||||||
parent_info: Option<(PipelineId, SubpageId, FrameType)>,
|
parent_info: Option<(PipelineId, SubpageId, FrameType)>,
|
||||||
layout_chan: Sender<layout_interface::Msg>,
|
layout_chan: Sender<message::Msg>,
|
||||||
window_size: Option<WindowSizeData>,
|
window_size: Option<WindowSizeData>,
|
||||||
url: Url) -> InProgressLoad {
|
url: Url) -> InProgressLoad {
|
||||||
InProgressLoad {
|
InProgressLoad {
|
||||||
|
@ -438,11 +438,11 @@ impl<'a> Drop for ScriptMemoryFailsafe<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptThreadFactory for ScriptThread {
|
impl ScriptThreadFactory for ScriptThread {
|
||||||
type Message = layout_interface::Msg;
|
type Message = message::Msg;
|
||||||
|
|
||||||
fn create(state: InitialScriptState,
|
fn create(state: InitialScriptState,
|
||||||
load_data: LoadData)
|
load_data: LoadData)
|
||||||
-> (Sender<layout_interface::Msg>, Receiver<layout_interface::Msg>) {
|
-> (Sender<message::Msg>, Receiver<message::Msg>) {
|
||||||
let panic_chan = state.panic_chan.clone();
|
let panic_chan = state.panic_chan.clone();
|
||||||
let (script_chan, script_port) = channel();
|
let (script_chan, script_port) = channel();
|
||||||
|
|
||||||
|
@ -1184,7 +1184,7 @@ impl ScriptThread {
|
||||||
|
|
||||||
// Tell layout to actually spawn the thread.
|
// Tell layout to actually spawn the thread.
|
||||||
parent_window.layout_chan()
|
parent_window.layout_chan()
|
||||||
.send(layout_interface::Msg::CreateLayoutThread(layout_creation_info))
|
.send(message::Msg::CreateLayoutThread(layout_creation_info))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Kick off the fetch for the new resource.
|
// Kick off the fetch for the new resource.
|
||||||
|
@ -1462,10 +1462,10 @@ impl ScriptThread {
|
||||||
// processed this message.
|
// processed this message.
|
||||||
let (response_chan, response_port) = channel();
|
let (response_chan, response_port) = channel();
|
||||||
let chan = &load.layout_chan;
|
let chan = &load.layout_chan;
|
||||||
if chan.send(layout_interface::Msg::PrepareToExit(response_chan)).is_ok() {
|
if chan.send(message::Msg::PrepareToExit(response_chan)).is_ok() {
|
||||||
debug!("shutting down layout for page {:?}", id);
|
debug!("shutting down layout for page {:?}", id);
|
||||||
response_port.recv().unwrap();
|
response_port.recv().unwrap();
|
||||||
chan.send(layout_interface::Msg::ExitNow).ok();
|
chan.send(message::Msg::ExitNow).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
let has_pending_loads = self.incomplete_loads.borrow().len() > 0;
|
let has_pending_loads = self.incomplete_loads.borrow().len() > 0;
|
||||||
|
@ -1523,7 +1523,7 @@ impl ScriptThread {
|
||||||
{
|
{
|
||||||
// send the final url to the layout thread.
|
// send the final url to the layout thread.
|
||||||
incomplete.layout_chan
|
incomplete.layout_chan
|
||||||
.send(layout_interface::Msg::SetFinalUrl(final_url.clone()))
|
.send(message::Msg::SetFinalUrl(final_url.clone()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// update the pipeline url
|
// update the pipeline url
|
||||||
|
@ -2126,7 +2126,7 @@ fn shut_down_layout(context_tree: &BrowsingContext) {
|
||||||
let (response_chan, response_port) = channel();
|
let (response_chan, response_port) = channel();
|
||||||
let window = context.active_window();
|
let window = context.active_window();
|
||||||
let chan = window.layout_chan().clone();
|
let chan = window.layout_chan().clone();
|
||||||
if chan.send(layout_interface::Msg::PrepareToExit(response_chan)).is_ok() {
|
if chan.send(message::Msg::PrepareToExit(response_chan)).is_ok() {
|
||||||
channels.push(chan);
|
channels.push(chan);
|
||||||
response_port.recv().unwrap();
|
response_port.recv().unwrap();
|
||||||
}
|
}
|
||||||
|
@ -2143,7 +2143,7 @@ fn shut_down_layout(context_tree: &BrowsingContext) {
|
||||||
|
|
||||||
// Destroy the layout thread. If there were node leaks, layout will now crash safely.
|
// Destroy the layout thread. If there were node leaks, layout will now crash safely.
|
||||||
for chan in channels {
|
for chan in channels {
|
||||||
chan.send(layout_interface::Msg::ExitNow).ok();
|
chan.send(message::Msg::ExitNow).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
33
components/script_layout_interface/Cargo.toml
Normal file
33
components/script_layout_interface/Cargo.toml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
[package]
|
||||||
|
name = "script_layout_interface"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = ["The Servo Project Developers"]
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "script_layout_interface"
|
||||||
|
path = "lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
app_units = {version = "0.2.3", features = ["plugins"]}
|
||||||
|
bitflags = "0.7"
|
||||||
|
canvas_traits = {path = "../canvas_traits"}
|
||||||
|
cssparser = {version = "0.5.4", features = ["heap_size", "serde-serialization"]}
|
||||||
|
euclid = {version = "0.6.4", features = ["plugins"]}
|
||||||
|
gfx_traits = {path = "../gfx_traits"}
|
||||||
|
heapsize = "0.3.0"
|
||||||
|
heapsize_plugin = "0.1.2"
|
||||||
|
ipc-channel = {git = "https://github.com/servo/ipc-channel"}
|
||||||
|
libc = "0.2"
|
||||||
|
log = "0.3.5"
|
||||||
|
msg = {path = "../msg"}
|
||||||
|
net_traits = {path = "../net_traits"}
|
||||||
|
profile_traits = {path = "../profile_traits"}
|
||||||
|
plugins = {path = "../plugins"}
|
||||||
|
range = {path = "../range"}
|
||||||
|
script_traits = {path = "../script_traits"}
|
||||||
|
selectors = {version = "0.6", features = ["heap_size"]}
|
||||||
|
string_cache = {version = "0.2.20", features = ["heap_size"]}
|
||||||
|
style = {path = "../style"}
|
||||||
|
url = {version = "1.0.0", features = ["heap_size"]}
|
||||||
|
util = {path = "../util"}
|
116
components/script_layout_interface/lib.rs
Normal file
116
components/script_layout_interface/lib.rs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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/. */
|
||||||
|
|
||||||
|
//! This module contains traits in script used generically in the rest of Servo.
|
||||||
|
//! The traits are here instead of in script so that these modules won't have
|
||||||
|
//! to depend on script.
|
||||||
|
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![feature(box_syntax)]
|
||||||
|
#![feature(custom_attribute)]
|
||||||
|
#![feature(custom_derive)]
|
||||||
|
#![feature(nonzero)]
|
||||||
|
#![feature(plugin)]
|
||||||
|
#![plugin(heapsize_plugin)]
|
||||||
|
#![plugin(plugins)]
|
||||||
|
|
||||||
|
extern crate app_units;
|
||||||
|
#[allow(unused_extern_crates)]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate bitflags;
|
||||||
|
extern crate canvas_traits;
|
||||||
|
extern crate core;
|
||||||
|
extern crate cssparser;
|
||||||
|
extern crate euclid;
|
||||||
|
extern crate gfx_traits;
|
||||||
|
extern crate heapsize;
|
||||||
|
extern crate ipc_channel;
|
||||||
|
extern crate libc;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
extern crate msg;
|
||||||
|
extern crate net_traits;
|
||||||
|
extern crate profile_traits;
|
||||||
|
extern crate range;
|
||||||
|
extern crate script_traits;
|
||||||
|
extern crate selectors;
|
||||||
|
#[macro_use(atom, ns)]
|
||||||
|
extern crate string_cache;
|
||||||
|
extern crate style;
|
||||||
|
extern crate url;
|
||||||
|
extern crate util;
|
||||||
|
|
||||||
|
pub mod message;
|
||||||
|
pub mod reporter;
|
||||||
|
pub mod restyle_damage;
|
||||||
|
pub mod rpc;
|
||||||
|
pub mod wrapper_traits;
|
||||||
|
|
||||||
|
use canvas_traits::CanvasMsg;
|
||||||
|
use core::nonzero::NonZero;
|
||||||
|
use ipc_channel::ipc::IpcSender;
|
||||||
|
use libc::c_void;
|
||||||
|
use restyle_damage::RestyleDamage;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use style::servo::PrivateStyleData;
|
||||||
|
|
||||||
|
pub struct PartialStyleAndLayoutData {
|
||||||
|
pub style_data: PrivateStyleData,
|
||||||
|
pub restyle_damage: RestyleDamage,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, HeapSizeOf)]
|
||||||
|
pub struct OpaqueStyleAndLayoutData {
|
||||||
|
#[ignore_heap_size_of = "TODO(#6910) Box value that should be counted but \
|
||||||
|
the type lives in layout"]
|
||||||
|
pub ptr: NonZero<*mut RefCell<PartialStyleAndLayoutData>>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
unsafe impl Send for OpaqueStyleAndLayoutData {}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub enum LayoutNodeType {
|
||||||
|
Comment,
|
||||||
|
Document,
|
||||||
|
DocumentFragment,
|
||||||
|
DocumentType,
|
||||||
|
Element(LayoutElementType),
|
||||||
|
ProcessingInstruction,
|
||||||
|
Text,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub enum LayoutElementType {
|
||||||
|
Element,
|
||||||
|
HTMLCanvasElement,
|
||||||
|
HTMLIFrameElement,
|
||||||
|
HTMLImageElement,
|
||||||
|
HTMLInputElement,
|
||||||
|
HTMLObjectElement,
|
||||||
|
HTMLTableCellElement,
|
||||||
|
HTMLTableColElement,
|
||||||
|
HTMLTableElement,
|
||||||
|
HTMLTableRowElement,
|
||||||
|
HTMLTableSectionElement,
|
||||||
|
HTMLTextAreaElement,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HTMLCanvasData {
|
||||||
|
pub ipc_renderer: Option<IpcSender<CanvasMsg>>,
|
||||||
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The address of a node known to be valid. These are sent from script to layout.
|
||||||
|
#[derive(Clone, PartialEq, Eq, Copy)]
|
||||||
|
pub struct TrustedNodeAddress(pub *const c_void);
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
unsafe impl Send for TrustedNodeAddress {}
|
||||||
|
|
||||||
|
pub fn is_image_data(uri: &str) -> bool {
|
||||||
|
static TYPES: &'static [&'static str] = &["data:image/png", "data:image/gif", "data:image/jpeg"];
|
||||||
|
TYPES.iter().any(|&type_| uri.starts_with(type_))
|
||||||
|
}
|
|
@ -2,10 +2,6 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
//! The high-level interface from script to layout. Using this abstract
|
|
||||||
//! interface helps reduce coupling between these two components, and enables
|
|
||||||
//! the DOM to be placed in a separate crate from layout.
|
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use euclid::point::Point2D;
|
use euclid::point::Point2D;
|
||||||
use euclid::rect::Rect;
|
use euclid::rect::Rect;
|
||||||
|
@ -14,33 +10,18 @@ use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||||
use msg::constellation_msg::{PanicMsg, PipelineId, WindowSizeData};
|
use msg::constellation_msg::{PanicMsg, PipelineId, WindowSizeData};
|
||||||
use net_traits::image_cache_thread::ImageCacheThread;
|
use net_traits::image_cache_thread::ImageCacheThread;
|
||||||
use profile_traits::mem::ReportsChan;
|
use profile_traits::mem::ReportsChan;
|
||||||
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
|
use rpc::LayoutRPC;
|
||||||
use script_traits::{StackingContextScrollState, UntrustedNodeAddress};
|
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
|
||||||
|
use script_traits::{LayoutMsg as ConstellationMsg, StackingContextScrollState};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::mpsc::{Receiver, Sender};
|
use std::sync::mpsc::{Receiver, Sender};
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use style::context::ReflowGoal;
|
use style::context::ReflowGoal;
|
||||||
use style::properties::longhands::{margin_top, margin_right, margin_bottom, margin_left, overflow_x};
|
|
||||||
use style::selector_impl::PseudoElement;
|
use style::selector_impl::PseudoElement;
|
||||||
use style::servo::Stylesheet;
|
use style::servo::Stylesheet;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util::ipc::OptionalOpaqueIpcSender;
|
use util::ipc::OptionalOpaqueIpcSender;
|
||||||
|
use {OpaqueStyleAndLayoutData, TrustedNodeAddress};
|
||||||
pub use dom::bindings::inheritance::{CharacterDataTypeId, ElementTypeId};
|
|
||||||
pub use dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId};
|
|
||||||
pub use dom::bindings::js::LayoutJS;
|
|
||||||
pub use dom::characterdata::LayoutCharacterDataHelpers;
|
|
||||||
pub use dom::document::{Document, LayoutDocumentHelpers};
|
|
||||||
pub use dom::element::{Element, LayoutElementHelpers, RawLayoutElementHelpers};
|
|
||||||
pub use dom::htmlcanvaselement::HTMLCanvasData;
|
|
||||||
pub use dom::htmlobjectelement::is_image_data;
|
|
||||||
pub use dom::node::{CAN_BE_FRAGMENTED, HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY};
|
|
||||||
pub use dom::node::LayoutNodeHelpers;
|
|
||||||
pub use dom::node::Node;
|
|
||||||
pub use dom::node::OpaqueStyleAndLayoutData;
|
|
||||||
pub use dom::node::TrustedNodeAddress;
|
|
||||||
pub use dom::text::Text;
|
|
||||||
|
|
||||||
|
|
||||||
/// Asynchronous messages that script can send to layout.
|
/// Asynchronous messages that script can send to layout.
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
|
@ -103,88 +84,6 @@ pub enum Msg {
|
||||||
SetStackingContextScrollStates(Vec<StackingContextScrollState>),
|
SetStackingContextScrollStates(Vec<StackingContextScrollState>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Synchronous messages that script can send to layout.
|
|
||||||
///
|
|
||||||
/// In general, you should use messages to talk to Layout. Use the RPC interface
|
|
||||||
/// if and only if the work is
|
|
||||||
///
|
|
||||||
/// 1) read-only with respect to LayoutThreadData,
|
|
||||||
/// 2) small,
|
|
||||||
/// 3) and really needs to be fast.
|
|
||||||
pub trait LayoutRPC {
|
|
||||||
/// Requests the dimensions of the content box, as in the `getBoundingClientRect()` call.
|
|
||||||
fn content_box(&self) -> ContentBoxResponse;
|
|
||||||
/// Requests the dimensions of all the content boxes, as in the `getClientRects()` call.
|
|
||||||
fn content_boxes(&self) -> ContentBoxesResponse;
|
|
||||||
/// Requests the geometry of this node. Used by APIs such as `clientTop`.
|
|
||||||
fn node_geometry(&self) -> NodeGeometryResponse;
|
|
||||||
/// Requests the overflow-x and overflow-y of this node. Used by `scrollTop` etc.
|
|
||||||
fn node_overflow(&self) -> NodeOverflowResponse;
|
|
||||||
/// Requests the scroll geometry of this node. Used by APIs such as `scrollTop`.
|
|
||||||
fn node_scroll_area(&self) -> NodeGeometryResponse;
|
|
||||||
/// Requests the layer id of this node. Used by APIs such as `scrollTop`
|
|
||||||
fn node_layer_id(&self) -> NodeLayerIdResponse;
|
|
||||||
/// Requests the node containing the point of interest
|
|
||||||
fn hit_test(&self) -> HitTestResponse;
|
|
||||||
/// Query layout for the resolved value of a given CSS property
|
|
||||||
fn resolved_style(&self) -> ResolvedStyleResponse;
|
|
||||||
fn offset_parent(&self) -> OffsetParentResponse;
|
|
||||||
/// Query layout for the resolve values of the margin properties for an element.
|
|
||||||
fn margin_style(&self) -> MarginStyleResponse;
|
|
||||||
|
|
||||||
fn nodes_from_point(&self, point: Point2D<f32>) -> Vec<UntrustedNodeAddress>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct MarginStyleResponse {
|
|
||||||
pub top: margin_top::computed_value::T,
|
|
||||||
pub right: margin_right::computed_value::T,
|
|
||||||
pub bottom: margin_bottom::computed_value::T,
|
|
||||||
pub left: margin_left::computed_value::T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MarginStyleResponse {
|
|
||||||
pub fn empty() -> MarginStyleResponse {
|
|
||||||
MarginStyleResponse {
|
|
||||||
top: margin_top::computed_value::T::Auto,
|
|
||||||
right: margin_right::computed_value::T::Auto,
|
|
||||||
bottom: margin_bottom::computed_value::T::Auto,
|
|
||||||
left: margin_left::computed_value::T::Auto,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NodeOverflowResponse(pub Option<Point2D<overflow_x::computed_value::T>>);
|
|
||||||
|
|
||||||
pub struct ContentBoxResponse(pub Rect<Au>);
|
|
||||||
pub struct ContentBoxesResponse(pub Vec<Rect<Au>>);
|
|
||||||
pub struct HitTestResponse {
|
|
||||||
pub node_address: Option<UntrustedNodeAddress>,
|
|
||||||
}
|
|
||||||
pub struct NodeGeometryResponse {
|
|
||||||
pub client_rect: Rect<i32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NodeLayerIdResponse {
|
|
||||||
pub layer_id: LayerId,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ResolvedStyleResponse(pub Option<String>);
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct OffsetParentResponse {
|
|
||||||
pub node_address: Option<UntrustedNodeAddress>,
|
|
||||||
pub rect: Rect<Au>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OffsetParentResponse {
|
|
||||||
pub fn empty() -> OffsetParentResponse {
|
|
||||||
OffsetParentResponse {
|
|
||||||
node_address: None,
|
|
||||||
rect: Rect::zero(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Any query to perform with this reflow.
|
/// Any query to perform with this reflow.
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
|
@ -10,7 +10,7 @@ use script_traits::ConstellationControlMsg;
|
||||||
use std::sync::{Mutex, Arc};
|
use std::sync::{Mutex, Arc};
|
||||||
use style::error_reporting::ParseErrorReporter;
|
use style::error_reporting::ParseErrorReporter;
|
||||||
|
|
||||||
#[derive(JSTraceable, HeapSizeOf)]
|
#[derive(HeapSizeOf)]
|
||||||
pub struct CSSErrorReporter {
|
pub struct CSSErrorReporter {
|
||||||
pub pipelineid: PipelineId,
|
pub pipelineid: PipelineId,
|
||||||
// Arc+Mutex combo is necessary to make this struct Sync,
|
// Arc+Mutex combo is necessary to make this struct Sync,
|
258
components/script_layout_interface/restyle_damage.rs
Normal file
258
components/script_layout_interface/restyle_damage.rs
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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/. */
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use style::computed_values::display;
|
||||||
|
use style::dom::TRestyleDamage;
|
||||||
|
use style::properties::{ComputedValues, ServoComputedValues};
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
#[doc = "Individual layout actions that may be necessary after restyling."]
|
||||||
|
pub flags RestyleDamage: u8 {
|
||||||
|
#[doc = "Repaint the node itself."]
|
||||||
|
#[doc = "Currently unused; need to decide how this propagates."]
|
||||||
|
const REPAINT = 0x01,
|
||||||
|
|
||||||
|
#[doc = "Recompute the overflow regions (bounding box of object and all descendants)."]
|
||||||
|
#[doc = "Propagates down the flow tree because the computation is bottom-up."]
|
||||||
|
const STORE_OVERFLOW = 0x02,
|
||||||
|
|
||||||
|
#[doc = "Recompute intrinsic inline_sizes (minimum and preferred)."]
|
||||||
|
#[doc = "Propagates down the flow tree because the computation is"]
|
||||||
|
#[doc = "bottom-up."]
|
||||||
|
const BUBBLE_ISIZES = 0x04,
|
||||||
|
|
||||||
|
#[doc = "Recompute actual inline-sizes and block-sizes, only taking out-of-flow children \
|
||||||
|
into account. \
|
||||||
|
Propagates up the flow tree because the computation is top-down."]
|
||||||
|
const REFLOW_OUT_OF_FLOW = 0x08,
|
||||||
|
|
||||||
|
#[doc = "Recompute actual inline_sizes and block_sizes."]
|
||||||
|
#[doc = "Propagates up the flow tree because the computation is"]
|
||||||
|
#[doc = "top-down."]
|
||||||
|
const REFLOW = 0x10,
|
||||||
|
|
||||||
|
#[doc = "Re-resolve generated content. \
|
||||||
|
Propagates up the flow tree because the computation is inorder."]
|
||||||
|
const RESOLVE_GENERATED_CONTENT = 0x20,
|
||||||
|
|
||||||
|
#[doc = "The entire flow needs to be reconstructed."]
|
||||||
|
const RECONSTRUCT_FLOW = 0x40
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TRestyleDamage for RestyleDamage {
|
||||||
|
type ConcreteComputedValues = ServoComputedValues;
|
||||||
|
fn compute(old: Option<&Arc<ServoComputedValues>>, new: &ServoComputedValues) ->
|
||||||
|
RestyleDamage { compute_damage(old, new) }
|
||||||
|
|
||||||
|
/// Returns a bitmask that represents a flow that needs to be rebuilt and reflowed.
|
||||||
|
///
|
||||||
|
/// Use this instead of `RestyleDamage::all()` because `RestyleDamage::all()` will result in
|
||||||
|
/// unnecessary sequential resolution of generated content.
|
||||||
|
fn rebuild_and_reflow() -> RestyleDamage {
|
||||||
|
REPAINT | STORE_OVERFLOW | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW | RECONSTRUCT_FLOW
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RestyleDamage {
|
||||||
|
/// Supposing a flow has the given `position` property and this damage, returns the damage that
|
||||||
|
/// we should add to the *parent* of this flow.
|
||||||
|
pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> RestyleDamage {
|
||||||
|
if child_is_absolutely_positioned {
|
||||||
|
self & (REPAINT | STORE_OVERFLOW | REFLOW_OUT_OF_FLOW | RESOLVE_GENERATED_CONTENT)
|
||||||
|
} else {
|
||||||
|
self & (REPAINT | STORE_OVERFLOW | REFLOW | REFLOW_OUT_OF_FLOW |
|
||||||
|
RESOLVE_GENERATED_CONTENT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supposing the *parent* of a flow with the given `position` property has this damage,
|
||||||
|
/// returns the damage that we should add to this flow.
|
||||||
|
pub fn damage_for_child(self,
|
||||||
|
parent_is_absolutely_positioned: bool,
|
||||||
|
child_is_absolutely_positioned: bool)
|
||||||
|
-> RestyleDamage {
|
||||||
|
match (parent_is_absolutely_positioned, child_is_absolutely_positioned) {
|
||||||
|
(false, true) => {
|
||||||
|
// Absolute children are out-of-flow and therefore insulated from changes.
|
||||||
|
//
|
||||||
|
// FIXME(pcwalton): Au contraire, if the containing block dimensions change!
|
||||||
|
self & REPAINT
|
||||||
|
}
|
||||||
|
(true, false) => {
|
||||||
|
// Changing the position of an absolutely-positioned block requires us to reflow
|
||||||
|
// its kids.
|
||||||
|
if self.contains(REFLOW_OUT_OF_FLOW) {
|
||||||
|
self | REFLOW
|
||||||
|
} else {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// TODO(pcwalton): Take floatedness into account.
|
||||||
|
self & (REPAINT | REFLOW)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for RestyleDamage {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
let mut first_elem = true;
|
||||||
|
|
||||||
|
let to_iter =
|
||||||
|
[ (REPAINT, "Repaint")
|
||||||
|
, (STORE_OVERFLOW, "StoreOverflow")
|
||||||
|
, (BUBBLE_ISIZES, "BubbleISizes")
|
||||||
|
, (REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow")
|
||||||
|
, (REFLOW, "Reflow")
|
||||||
|
, (RESOLVE_GENERATED_CONTENT, "ResolveGeneratedContent")
|
||||||
|
, (RECONSTRUCT_FLOW, "ReconstructFlow")
|
||||||
|
];
|
||||||
|
|
||||||
|
for &(damage, damage_str) in &to_iter {
|
||||||
|
if self.contains(damage) {
|
||||||
|
if !first_elem { try!(write!(f, " | ")); }
|
||||||
|
try!(write!(f, "{}", damage_str));
|
||||||
|
first_elem = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if first_elem {
|
||||||
|
try!(write!(f, "NoDamage"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NB: We need the braces inside the RHS due to Rust #8012. This particular
|
||||||
|
// version of this macro might be safe anyway, but we want to avoid silent
|
||||||
|
// breakage on modifications.
|
||||||
|
macro_rules! add_if_not_equal(
|
||||||
|
($old:ident, $new:ident, $damage:ident,
|
||||||
|
[ $($effect:ident),* ], [ $($style_struct_getter:ident.$name:ident),* ]) => ({
|
||||||
|
if $( ($old.$style_struct_getter().$name != $new.$style_struct_getter().$name) )||* {
|
||||||
|
$damage.insert($($effect)|*);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
fn compute_damage(old: Option<&Arc<ServoComputedValues>>, new: &ServoComputedValues) -> RestyleDamage {
|
||||||
|
let old: &ServoComputedValues = match old {
|
||||||
|
None => return RestyleDamage::rebuild_and_reflow(),
|
||||||
|
Some(cv) => &**cv,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut damage = RestyleDamage::empty();
|
||||||
|
|
||||||
|
// This should check every CSS property, as enumerated in the fields of
|
||||||
|
// http://doc.servo.org/style/properties/struct.ServoComputedValues.html
|
||||||
|
|
||||||
|
// FIXME: Test somehow that every property is included.
|
||||||
|
|
||||||
|
add_if_not_equal!(old, new, damage,
|
||||||
|
[
|
||||||
|
REPAINT,
|
||||||
|
STORE_OVERFLOW,
|
||||||
|
BUBBLE_ISIZES,
|
||||||
|
REFLOW_OUT_OF_FLOW,
|
||||||
|
REFLOW,
|
||||||
|
RECONSTRUCT_FLOW
|
||||||
|
], [
|
||||||
|
get_box.float, get_box.display, get_box.position, get_counters.content,
|
||||||
|
get_counters.counter_reset, get_counters.counter_increment,
|
||||||
|
get_inheritedbox._servo_under_display_none,
|
||||||
|
get_list.quotes, get_list.list_style_type,
|
||||||
|
|
||||||
|
// If these text or font properties change, we need to reconstruct the flow so that
|
||||||
|
// text shaping is re-run.
|
||||||
|
get_inheritedtext.letter_spacing, get_inheritedtext.text_rendering,
|
||||||
|
get_inheritedtext.text_transform, get_inheritedtext.word_spacing,
|
||||||
|
get_inheritedtext.overflow_wrap, get_inheritedtext.text_justify,
|
||||||
|
get_inheritedtext.white_space, get_inheritedtext.word_break, get_text.text_overflow,
|
||||||
|
get_font.font_family, get_font.font_style, get_font.font_variant, get_font.font_weight,
|
||||||
|
get_font.font_size, get_font.font_stretch,
|
||||||
|
get_inheritedbox.direction, get_inheritedbox.writing_mode,
|
||||||
|
get_inheritedbox.text_orientation,
|
||||||
|
get_text.text_decoration, get_text.unicode_bidi,
|
||||||
|
get_inheritedtable.empty_cells, get_inheritedtable.caption_side,
|
||||||
|
get_column.column_width, get_column.column_count
|
||||||
|
]) || (new.get_box().display == display::T::inline &&
|
||||||
|
add_if_not_equal!(old, new, damage,
|
||||||
|
[REPAINT, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW,
|
||||||
|
RECONSTRUCT_FLOW], [
|
||||||
|
// For inline boxes only, border/padding styles are used in flow construction (to decide
|
||||||
|
// whether to create fragments for empty flows).
|
||||||
|
get_border.border_top_width, get_border.border_right_width,
|
||||||
|
get_border.border_bottom_width, get_border.border_left_width,
|
||||||
|
get_padding.padding_top, get_padding.padding_right,
|
||||||
|
get_padding.padding_bottom, get_padding.padding_left
|
||||||
|
])) || add_if_not_equal!(old, new, damage,
|
||||||
|
[ REPAINT, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW ],
|
||||||
|
[get_border.border_top_width, get_border.border_right_width,
|
||||||
|
get_border.border_bottom_width, get_border.border_left_width,
|
||||||
|
get_margin.margin_top, get_margin.margin_right,
|
||||||
|
get_margin.margin_bottom, get_margin.margin_left,
|
||||||
|
get_padding.padding_top, get_padding.padding_right,
|
||||||
|
get_padding.padding_bottom, get_padding.padding_left,
|
||||||
|
get_position.width, get_position.height,
|
||||||
|
get_inheritedtext.line_height,
|
||||||
|
get_inheritedtext.text_align, get_inheritedtext.text_indent,
|
||||||
|
get_table.table_layout,
|
||||||
|
get_inheritedtable.border_collapse,
|
||||||
|
get_inheritedtable.border_spacing,
|
||||||
|
get_column.column_gap,
|
||||||
|
get_position.flex_direction,
|
||||||
|
get_position.flex_wrap,
|
||||||
|
get_position.justify_content,
|
||||||
|
get_position.align_items,
|
||||||
|
get_position.align_content,
|
||||||
|
get_position.order,
|
||||||
|
get_position.flex_basis,
|
||||||
|
get_position.flex_grow,
|
||||||
|
get_position.flex_shrink,
|
||||||
|
get_position.align_self
|
||||||
|
]) || add_if_not_equal!(old, new, damage,
|
||||||
|
[ REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW ], [
|
||||||
|
get_position.top, get_position.left,
|
||||||
|
get_position.right, get_position.bottom
|
||||||
|
]) || add_if_not_equal!(old, new, damage,
|
||||||
|
[ REPAINT ], [
|
||||||
|
get_color.color, get_background.background_color,
|
||||||
|
get_background.background_image, get_background.background_position,
|
||||||
|
get_background.background_repeat, get_background.background_attachment,
|
||||||
|
get_background.background_clip, get_background.background_origin,
|
||||||
|
get_background.background_size,
|
||||||
|
get_border.border_top_color, get_border.border_right_color,
|
||||||
|
get_border.border_bottom_color, get_border.border_left_color,
|
||||||
|
get_border.border_top_style, get_border.border_right_style,
|
||||||
|
get_border.border_bottom_style, get_border.border_left_style,
|
||||||
|
get_border.border_top_left_radius, get_border.border_top_right_radius,
|
||||||
|
get_border.border_bottom_left_radius, get_border.border_bottom_right_radius,
|
||||||
|
get_position.z_index, get_box._servo_overflow_clip_box,
|
||||||
|
get_inheritedtext._servo_text_decorations_in_effect,
|
||||||
|
get_pointing.cursor, get_pointing.pointer_events,
|
||||||
|
get_effects.box_shadow, get_effects.clip, get_inheritedtext.text_shadow, get_effects.filter,
|
||||||
|
get_effects.transform, get_effects.backface_visibility, get_effects.transform_style,
|
||||||
|
get_effects.transform_origin, get_effects.perspective, get_effects.perspective_origin,
|
||||||
|
get_effects.mix_blend_mode, get_inheritedbox.image_rendering,
|
||||||
|
|
||||||
|
// Note: May require REFLOW et al. if `visibility: collapse` is implemented.
|
||||||
|
get_inheritedbox.visibility
|
||||||
|
]);
|
||||||
|
|
||||||
|
// If the layer requirements of this flow have changed due to the value
|
||||||
|
// of the transform, then reflow is required to rebuild the layers.
|
||||||
|
if old.transform_requires_layer() != new.transform_requires_layer() {
|
||||||
|
damage.insert(RestyleDamage::rebuild_and_reflow());
|
||||||
|
}
|
||||||
|
|
||||||
|
damage
|
||||||
|
}
|
96
components/script_layout_interface/rpc.rs
Normal file
96
components/script_layout_interface/rpc.rs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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/. */
|
||||||
|
|
||||||
|
use app_units::Au;
|
||||||
|
use euclid::point::Point2D;
|
||||||
|
use euclid::rect::Rect;
|
||||||
|
use gfx_traits::LayerId;
|
||||||
|
use script_traits::UntrustedNodeAddress;
|
||||||
|
use style::properties::longhands::{margin_top, margin_right, margin_bottom, margin_left, overflow_x};
|
||||||
|
|
||||||
|
/// Synchronous messages that script can send to layout.
|
||||||
|
///
|
||||||
|
/// In general, you should use messages to talk to Layout. Use the RPC interface
|
||||||
|
/// if and only if the work is
|
||||||
|
///
|
||||||
|
/// 1) read-only with respect to LayoutThreadData,
|
||||||
|
/// 2) small,
|
||||||
|
/// 3) and really needs to be fast.
|
||||||
|
pub trait LayoutRPC {
|
||||||
|
/// Requests the dimensions of the content box, as in the `getBoundingClientRect()` call.
|
||||||
|
fn content_box(&self) -> ContentBoxResponse;
|
||||||
|
/// Requests the dimensions of all the content boxes, as in the `getClientRects()` call.
|
||||||
|
fn content_boxes(&self) -> ContentBoxesResponse;
|
||||||
|
/// Requests the geometry of this node. Used by APIs such as `clientTop`.
|
||||||
|
fn node_geometry(&self) -> NodeGeometryResponse;
|
||||||
|
/// Requests the overflow-x and overflow-y of this node. Used by `scrollTop` etc.
|
||||||
|
fn node_overflow(&self) -> NodeOverflowResponse;
|
||||||
|
/// Requests the scroll geometry of this node. Used by APIs such as `scrollTop`.
|
||||||
|
fn node_scroll_area(&self) -> NodeGeometryResponse;
|
||||||
|
/// Requests the layer id of this node. Used by APIs such as `scrollTop`
|
||||||
|
fn node_layer_id(&self) -> NodeLayerIdResponse;
|
||||||
|
/// Requests the node containing the point of interest
|
||||||
|
fn hit_test(&self) -> HitTestResponse;
|
||||||
|
/// Query layout for the resolved value of a given CSS property
|
||||||
|
fn resolved_style(&self) -> ResolvedStyleResponse;
|
||||||
|
fn offset_parent(&self) -> OffsetParentResponse;
|
||||||
|
/// Query layout for the resolve values of the margin properties for an element.
|
||||||
|
fn margin_style(&self) -> MarginStyleResponse;
|
||||||
|
|
||||||
|
fn nodes_from_point(&self, point: Point2D<f32>) -> Vec<UntrustedNodeAddress>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ContentBoxResponse(pub Rect<Au>);
|
||||||
|
|
||||||
|
pub struct ContentBoxesResponse(pub Vec<Rect<Au>>);
|
||||||
|
|
||||||
|
pub struct NodeGeometryResponse {
|
||||||
|
pub client_rect: Rect<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NodeOverflowResponse(pub Option<Point2D<overflow_x::computed_value::T>>);
|
||||||
|
|
||||||
|
pub struct NodeLayerIdResponse {
|
||||||
|
pub layer_id: LayerId,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HitTestResponse {
|
||||||
|
pub node_address: Option<UntrustedNodeAddress>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ResolvedStyleResponse(pub Option<String>);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct OffsetParentResponse {
|
||||||
|
pub node_address: Option<UntrustedNodeAddress>,
|
||||||
|
pub rect: Rect<Au>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OffsetParentResponse {
|
||||||
|
pub fn empty() -> OffsetParentResponse {
|
||||||
|
OffsetParentResponse {
|
||||||
|
node_address: None,
|
||||||
|
rect: Rect::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct MarginStyleResponse {
|
||||||
|
pub top: margin_top::computed_value::T,
|
||||||
|
pub right: margin_right::computed_value::T,
|
||||||
|
pub bottom: margin_bottom::computed_value::T,
|
||||||
|
pub left: margin_left::computed_value::T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MarginStyleResponse {
|
||||||
|
pub fn empty() -> MarginStyleResponse {
|
||||||
|
MarginStyleResponse {
|
||||||
|
top: margin_top::computed_value::T::Auto,
|
||||||
|
right: margin_right::computed_value::T::Auto,
|
||||||
|
bottom: margin_bottom::computed_value::T::Auto,
|
||||||
|
left: margin_left::computed_value::T::Auto,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
366
components/script_layout_interface/wrapper_traits.rs
Normal file
366
components/script_layout_interface/wrapper_traits.rs
Normal file
|
@ -0,0 +1,366 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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/. */
|
||||||
|
|
||||||
|
use HTMLCanvasData;
|
||||||
|
use LayoutNodeType;
|
||||||
|
use OpaqueStyleAndLayoutData;
|
||||||
|
use PartialStyleAndLayoutData;
|
||||||
|
use gfx_traits::{ByteIndex, LayerId, LayerType};
|
||||||
|
use msg::constellation_msg::PipelineId;
|
||||||
|
use range::Range;
|
||||||
|
use restyle_damage::RestyleDamage;
|
||||||
|
use std::cell::{Ref, RefCell};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use string_cache::{Atom, BorrowedAtom, BorrowedNamespace, Namespace};
|
||||||
|
use style::computed_values::display;
|
||||||
|
use style::dom::OpaqueNode;
|
||||||
|
use style::dom::{PresentationalHintsSynthetizer, TNode};
|
||||||
|
use style::properties::ServoComputedValues;
|
||||||
|
use style::selector_impl::{PseudoElement, PseudoElementCascadeType, ServoSelectorImpl};
|
||||||
|
use style::servo::SharedStyleContext;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
#[derive(Copy, PartialEq, Clone)]
|
||||||
|
pub enum PseudoElementType<T> {
|
||||||
|
Normal,
|
||||||
|
Before(T),
|
||||||
|
After(T),
|
||||||
|
DetailsSummary(T),
|
||||||
|
DetailsContent(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PseudoElementType<T> {
|
||||||
|
pub fn is_before(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
PseudoElementType::Before(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_replaced_content(&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(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn style_pseudo_element(&self) -> PseudoElement {
|
||||||
|
match *self {
|
||||||
|
PseudoElementType::Normal => unreachable!("style_pseudo_element called with PseudoElementType::Normal"),
|
||||||
|
PseudoElementType::Before(_) => PseudoElement::Before,
|
||||||
|
PseudoElementType::After(_) => PseudoElement::After,
|
||||||
|
PseudoElementType::DetailsSummary(_) => PseudoElement::DetailsSummary,
|
||||||
|
PseudoElementType::DetailsContent(_) => PseudoElement::DetailsContent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode;
|
||||||
|
fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode;
|
||||||
|
|
||||||
|
/// Returns the type ID of this node.
|
||||||
|
fn type_id(&self) -> LayoutNodeType;
|
||||||
|
|
||||||
|
fn get_style_data(&self) -> Option<&RefCell<PartialStyleAndLayoutData>>;
|
||||||
|
|
||||||
|
fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData);
|
||||||
|
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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>
|
||||||
|
+ ::selectors::Element<Impl=ServoSelectorImpl>;
|
||||||
|
type ChildrenIterator: Iterator<Item = Self> + Sized;
|
||||||
|
|
||||||
|
/// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode`
|
||||||
|
/// with a different pseudo-element type.
|
||||||
|
fn with_pseudo(&self, pseudo: PseudoElementType<Option<display::T>>) -> Self;
|
||||||
|
|
||||||
|
/// Converts self into an `OpaqueNode`.
|
||||||
|
fn opaque(&self) -> OpaqueNode;
|
||||||
|
|
||||||
|
/// Returns the type ID of this node.
|
||||||
|
/// Returns `None` if this is a pseudo-element; otherwise, returns `Some`.
|
||||||
|
fn type_id(&self) -> Option<LayoutNodeType>;
|
||||||
|
|
||||||
|
/// Returns the type ID of this node, without discarding pseudo-elements as
|
||||||
|
/// `type_id` does.
|
||||||
|
fn type_id_without_excluding_pseudo_elements(&self) -> LayoutNodeType;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_element_or_elements_pseudo(&self) -> bool {
|
||||||
|
match self.type_id_without_excluding_pseudo_elements() {
|
||||||
|
LayoutNodeType::Element(..) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn debug_id(self) -> usize;
|
||||||
|
|
||||||
|
/// Returns an iterator over this node's children.
|
||||||
|
fn children(&self) -> Self::ChildrenIterator;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_element(&self) -> bool { if let Some(LayoutNodeType::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;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_pseudo_element_type(&self) -> PseudoElementType<Option<display::T>>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_before_pseudo(&self) -> Option<Self> {
|
||||||
|
if self.get_style_data()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.style_data
|
||||||
|
.per_pseudo
|
||||||
|
.contains_key(&PseudoElement::Before) {
|
||||||
|
Some(self.with_pseudo(PseudoElementType::Before(None)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_after_pseudo(&self) -> Option<Self> {
|
||||||
|
if self.get_style_data()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.style_data
|
||||||
|
.per_pseudo
|
||||||
|
.contains_key(&PseudoElement::After) {
|
||||||
|
Some(self.with_pseudo(PseudoElementType::After(None)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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) {
|
||||||
|
Some(self.with_pseudo(PseudoElementType::DetailsSummary(None)))
|
||||||
|
} 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) {
|
||||||
|
let display = if self.as_element().get_attr(&ns!(), &atom!("open")).is_some() {
|
||||||
|
None // Specified by the stylesheet
|
||||||
|
} else {
|
||||||
|
Some(display::T::none)
|
||||||
|
};
|
||||||
|
Some(self.with_pseudo(PseudoElementType::DetailsContent(display)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>;
|
||||||
|
|
||||||
|
/// Returns the style results for the given node. If CSS selector matching
|
||||||
|
/// has not yet been performed, fails.
|
||||||
|
///
|
||||||
|
/// Unlike the version on TNode, this handles pseudo-elements.
|
||||||
|
#[inline]
|
||||||
|
fn style(&self, context: &SharedStyleContext) -> Ref<Arc<ServoComputedValues>> {
|
||||||
|
match self.get_pseudo_element_type() {
|
||||||
|
PseudoElementType::Normal => {
|
||||||
|
Ref::map(self.get_style_data().unwrap().borrow(), |data| {
|
||||||
|
data.style_data.style.as_ref().unwrap()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
other => {
|
||||||
|
// Precompute non-eagerly-cascaded pseudo-element styles if not
|
||||||
|
// cached before.
|
||||||
|
let style_pseudo = other.style_pseudo_element();
|
||||||
|
match style_pseudo.cascade_type() {
|
||||||
|
// Already computed during the cascade.
|
||||||
|
PseudoElementCascadeType::Eager => {},
|
||||||
|
PseudoElementCascadeType::Precomputed => {
|
||||||
|
if !self.get_style_data()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.style_data
|
||||||
|
.per_pseudo.contains_key(&style_pseudo) {
|
||||||
|
let mut data = self.get_style_data().unwrap().borrow_mut();
|
||||||
|
let new_style =
|
||||||
|
context.stylist
|
||||||
|
.precomputed_values_for_pseudo(&style_pseudo,
|
||||||
|
data.style_data.style.as_ref());
|
||||||
|
data.style_data.per_pseudo
|
||||||
|
.insert(style_pseudo.clone(), new_style.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PseudoElementCascadeType::Lazy => {
|
||||||
|
debug_assert!(self.is_element_or_elements_pseudo());
|
||||||
|
if !self.get_style_data()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.style_data
|
||||||
|
.per_pseudo.contains_key(&style_pseudo) {
|
||||||
|
let mut data = self.get_style_data().unwrap().borrow_mut();
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref::map(self.get_style_data().unwrap().borrow(), |data| {
|
||||||
|
data.style_data.per_pseudo.get(&style_pseudo).unwrap()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the already resolved style of the node.
|
||||||
|
///
|
||||||
|
/// This differs from `style(ctx)` in that if the pseudo-element has not yet
|
||||||
|
/// been computed it would panic.
|
||||||
|
///
|
||||||
|
/// This should be used just for querying layout, or when we know the
|
||||||
|
/// element style is precomputed, not from general layout itself.
|
||||||
|
#[inline]
|
||||||
|
fn resolved_style(&self) -> Ref<Arc<ServoComputedValues>> {
|
||||||
|
Ref::map(self.get_style_data().unwrap().borrow(), |data| {
|
||||||
|
match self.get_pseudo_element_type() {
|
||||||
|
PseudoElementType::Normal
|
||||||
|
=> data.style_data.style.as_ref().unwrap(),
|
||||||
|
other
|
||||||
|
=> data.style_data.per_pseudo.get(&other.style_pseudo_element()).unwrap(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn selected_style(&self, _context: &SharedStyleContext) -> Ref<Arc<ServoComputedValues>> {
|
||||||
|
Ref::map(self.get_style_data().unwrap().borrow(), |data| {
|
||||||
|
data.style_data.per_pseudo
|
||||||
|
.get(&PseudoElement::Selection)
|
||||||
|
.unwrap_or(data.style_data.style.as_ref().unwrap())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes the style from this node.
|
||||||
|
///
|
||||||
|
/// Unlike the version on TNode, this handles pseudo-elements.
|
||||||
|
fn unstyle(self) {
|
||||||
|
let mut data = self.get_style_data().unwrap().borrow_mut();
|
||||||
|
|
||||||
|
match self.get_pseudo_element_type() {
|
||||||
|
PseudoElementType::Normal => {
|
||||||
|
data.style_data.style = None;
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
data.style_data.per_pseudo.remove(&other.style_pseudo_element());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool;
|
||||||
|
|
||||||
|
fn restyle_damage(self) -> RestyleDamage;
|
||||||
|
|
||||||
|
fn set_restyle_damage(self, damage: 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 {
|
||||||
|
match self.type_id() {
|
||||||
|
Some(LayoutNodeType::Element(..)) | Some(LayoutNodeType::Text) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_be_fragmented(&self) -> bool;
|
||||||
|
|
||||||
|
fn node_text_content(&self) -> String;
|
||||||
|
|
||||||
|
/// If the insertion point is within this node, returns it. Otherwise, returns `None`.
|
||||||
|
fn selection(&self) -> Option<Range<ByteIndex>>;
|
||||||
|
|
||||||
|
/// 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>;
|
||||||
|
|
||||||
|
fn canvas_data(&self) -> Option<HTMLCanvasData>;
|
||||||
|
|
||||||
|
/// If this node is an iframe element, returns its pipeline ID. If this node is
|
||||||
|
/// not an iframe element, fails.
|
||||||
|
fn iframe_pipeline_id(&self) -> PipelineId;
|
||||||
|
|
||||||
|
fn get_colspan(&self) -> u32;
|
||||||
|
|
||||||
|
fn layer_id(&self) -> LayerId {
|
||||||
|
let layer_type = match self.get_pseudo_element_type() {
|
||||||
|
PseudoElementType::Normal => LayerType::FragmentBody,
|
||||||
|
PseudoElementType::Before(_) => LayerType::BeforePseudoContent,
|
||||||
|
PseudoElementType::After(_) => LayerType::AfterPseudoContent,
|
||||||
|
PseudoElementType::DetailsSummary(_) => LayerType::FragmentBody,
|
||||||
|
PseudoElementType::DetailsContent(_) => LayerType::FragmentBody,
|
||||||
|
};
|
||||||
|
LayerId::new_of_type(layer_type, self.opaque().id() as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layer_id_for_overflow_scroll(&self) -> LayerId {
|
||||||
|
LayerId::new_of_type(LayerType::OverflowScroll, self.opaque().id() as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_style_data(&self) -> Option<&RefCell<PartialStyleAndLayoutData>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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!
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
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 +
|
||||||
|
::selectors::Element<Impl=ServoSelectorImpl> +
|
||||||
|
PresentationalHintsSynthetizer {
|
||||||
|
type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<ConcreteThreadSafeLayoutElement = Self>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_local_name<'a>(&'a self) -> BorrowedAtom<'a>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_namespace<'a>(&'a self) -> BorrowedNamespace<'a>;
|
||||||
|
}
|
34
components/servo/Cargo.lock
generated
34
components/servo/Cargo.lock
generated
|
@ -33,6 +33,7 @@ dependencies = [
|
||||||
"profile_tests 0.0.1",
|
"profile_tests 0.0.1",
|
||||||
"profile_traits 0.0.1",
|
"profile_traits 0.0.1",
|
||||||
"script 0.0.1",
|
"script 0.0.1",
|
||||||
|
"script_layout_interface 0.0.1",
|
||||||
"script_tests 0.0.1",
|
"script_tests 0.0.1",
|
||||||
"script_traits 0.0.1",
|
"script_traits 0.0.1",
|
||||||
"style 0.0.1",
|
"style 0.0.1",
|
||||||
|
@ -814,6 +815,8 @@ dependencies = [
|
||||||
"layers 0.2.5 (git+https://github.com/servo/rust-layers)",
|
"layers 0.2.5 (git+https://github.com/servo/rust-layers)",
|
||||||
"msg 0.0.1",
|
"msg 0.0.1",
|
||||||
"plugins 0.0.1",
|
"plugins 0.0.1",
|
||||||
|
"range 0.0.1",
|
||||||
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_macros 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_macros 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -1155,6 +1158,7 @@ dependencies = [
|
||||||
"range 0.0.1",
|
"range 0.0.1",
|
||||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"script 0.0.1",
|
"script 0.0.1",
|
||||||
|
"script_layout_interface 0.0.1",
|
||||||
"script_traits 0.0.1",
|
"script_traits 0.0.1",
|
||||||
"selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1903,10 +1907,12 @@ dependencies = [
|
||||||
"plugins 0.0.1",
|
"plugins 0.0.1",
|
||||||
"profile_traits 0.0.1",
|
"profile_traits 0.0.1",
|
||||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"range 0.0.1",
|
||||||
"ref_filter_map 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ref_filter_map 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ref_slice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ref_slice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 0.1.71 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 0.1.71 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"script_layout_interface 0.0.1",
|
||||||
"script_traits 0.0.1",
|
"script_traits 0.0.1",
|
||||||
"selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1923,6 +1929,34 @@ dependencies = [
|
||||||
"xml5ever 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"xml5ever 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "script_layout_interface"
|
||||||
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"canvas_traits 0.0.1",
|
||||||
|
"cssparser 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"gfx_traits 0.0.1",
|
||||||
|
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ipc-channel 0.2.3 (git+https://github.com/servo/ipc-channel)",
|
||||||
|
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"msg 0.0.1",
|
||||||
|
"net_traits 0.0.1",
|
||||||
|
"plugins 0.0.1",
|
||||||
|
"profile_traits 0.0.1",
|
||||||
|
"range 0.0.1",
|
||||||
|
"script_traits 0.0.1",
|
||||||
|
"selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"string_cache 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"style 0.0.1",
|
||||||
|
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"util 0.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "script_tests"
|
name = "script_tests"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
|
|
@ -43,6 +43,7 @@ compiletest_helper = {path = "../../tests/compiletest/helper"}
|
||||||
plugin_compiletest = {path = "../../tests/compiletest/plugin"}
|
plugin_compiletest = {path = "../../tests/compiletest/plugin"}
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
script_layout_interface = {path = "../script_layout_interface"}
|
||||||
webrender_traits = {git = "https://github.com/servo/webrender_traits"}
|
webrender_traits = {git = "https://github.com/servo/webrender_traits"}
|
||||||
webrender = {git = "https://github.com/servo/webrender"}
|
webrender = {git = "https://github.com/servo/webrender"}
|
||||||
compositing = {path = "../compositing"}
|
compositing = {path = "../compositing"}
|
||||||
|
|
|
@ -39,6 +39,7 @@ pub extern crate profile;
|
||||||
pub extern crate profile_traits;
|
pub extern crate profile_traits;
|
||||||
pub extern crate script;
|
pub extern crate script;
|
||||||
pub extern crate script_traits;
|
pub extern crate script_traits;
|
||||||
|
pub extern crate script_layout_interface;
|
||||||
pub extern crate style;
|
pub extern crate style;
|
||||||
pub extern crate url;
|
pub extern crate url;
|
||||||
pub extern crate util;
|
pub extern crate util;
|
||||||
|
@ -229,7 +230,7 @@ fn create_constellation(opts: opts::Opts,
|
||||||
webrender_api_sender: webrender_api_sender,
|
webrender_api_sender: webrender_api_sender,
|
||||||
};
|
};
|
||||||
let constellation_chan =
|
let constellation_chan =
|
||||||
Constellation::<script::layout_interface::Msg,
|
Constellation::<script_layout_interface::message::Msg,
|
||||||
layout::layout_thread::LayoutThread,
|
layout::layout_thread::LayoutThread,
|
||||||
script::script_thread::ScriptThread>::start(initial_state);
|
script::script_thread::ScriptThread>::start(initial_state);
|
||||||
|
|
||||||
|
@ -263,7 +264,7 @@ pub fn run_content_process(token: String) {
|
||||||
|
|
||||||
script::init();
|
script::init();
|
||||||
|
|
||||||
unprivileged_content.start_all::<script::layout_interface::Msg,
|
unprivileged_content.start_all::<script_layout_interface::message::Msg,
|
||||||
layout::layout_thread::LayoutThread,
|
layout::layout_thread::LayoutThread,
|
||||||
script::script_thread::ScriptThread>(true);
|
script::script_thread::ScriptThread>(true);
|
||||||
}
|
}
|
||||||
|
|
34
ports/cef/Cargo.lock
generated
34
ports/cef/Cargo.lock
generated
|
@ -727,6 +727,8 @@ dependencies = [
|
||||||
"layers 0.2.5 (git+https://github.com/servo/rust-layers)",
|
"layers 0.2.5 (git+https://github.com/servo/rust-layers)",
|
||||||
"msg 0.0.1",
|
"msg 0.0.1",
|
||||||
"plugins 0.0.1",
|
"plugins 0.0.1",
|
||||||
|
"range 0.0.1",
|
||||||
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_macros 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_macros 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -1068,6 +1070,7 @@ dependencies = [
|
||||||
"range 0.0.1",
|
"range 0.0.1",
|
||||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"script 0.0.1",
|
"script 0.0.1",
|
||||||
|
"script_layout_interface 0.0.1",
|
||||||
"script_traits 0.0.1",
|
"script_traits 0.0.1",
|
||||||
"selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1761,10 +1764,12 @@ dependencies = [
|
||||||
"plugins 0.0.1",
|
"plugins 0.0.1",
|
||||||
"profile_traits 0.0.1",
|
"profile_traits 0.0.1",
|
||||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"range 0.0.1",
|
||||||
"ref_filter_map 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ref_filter_map 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ref_slice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ref_slice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 0.1.71 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 0.1.71 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"script_layout_interface 0.0.1",
|
||||||
"script_traits 0.0.1",
|
"script_traits 0.0.1",
|
||||||
"selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1781,6 +1786,34 @@ dependencies = [
|
||||||
"xml5ever 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"xml5ever 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "script_layout_interface"
|
||||||
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"canvas_traits 0.0.1",
|
||||||
|
"cssparser 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"gfx_traits 0.0.1",
|
||||||
|
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ipc-channel 0.2.3 (git+https://github.com/servo/ipc-channel)",
|
||||||
|
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"msg 0.0.1",
|
||||||
|
"net_traits 0.0.1",
|
||||||
|
"plugins 0.0.1",
|
||||||
|
"profile_traits 0.0.1",
|
||||||
|
"range 0.0.1",
|
||||||
|
"script_traits 0.0.1",
|
||||||
|
"selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"string_cache 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"style 0.0.1",
|
||||||
|
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"util 0.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "script_traits"
|
name = "script_traits"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -1888,6 +1921,7 @@ dependencies = [
|
||||||
"profile 0.0.1",
|
"profile 0.0.1",
|
||||||
"profile_traits 0.0.1",
|
"profile_traits 0.0.1",
|
||||||
"script 0.0.1",
|
"script 0.0.1",
|
||||||
|
"script_layout_interface 0.0.1",
|
||||||
"script_traits 0.0.1",
|
"script_traits 0.0.1",
|
||||||
"style 0.0.1",
|
"style 0.0.1",
|
||||||
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use layout::Fragment;
|
use layout::Fragment;
|
||||||
use layout::ServoThreadSafeLayoutNode;
|
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -25,23 +24,3 @@ fn test_size_of_fragment() {
|
||||||
expected, actual);
|
expected, actual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_size_of_layout_node() {
|
|
||||||
let expected = 16;
|
|
||||||
let actual = size_of::<ServoThreadSafeLayoutNode>();
|
|
||||||
|
|
||||||
if actual < expected {
|
|
||||||
panic!("Your changes have decreased the stack size of layout::wrapper::ServoThreadSafeLayoutNode \
|
|
||||||
from {} to {}. Good work! Please update the size in tests/layout/unit/size_of.rs",
|
|
||||||
expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
if actual > expected {
|
|
||||||
panic!("Your changes have increased the stack size of layout::wrapper::ServoThreadSafeLayoutNode \
|
|
||||||
from {} to {}. Please consider choosing a design which avoids this increase. \
|
|
||||||
If you feel that the increase is necessary, update the size in \
|
|
||||||
tests/unit/layout/size_of.rs.",
|
|
||||||
expected, actual);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ use script::dom::htmlelement::HTMLElement;
|
||||||
use script::dom::htmlspanelement::HTMLSpanElement;
|
use script::dom::htmlspanelement::HTMLSpanElement;
|
||||||
use script::dom::node::Node;
|
use script::dom::node::Node;
|
||||||
use script::dom::text::Text;
|
use script::dom::text::Text;
|
||||||
|
use script::layout_wrapper::ServoThreadSafeLayoutNode;
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
|
|
||||||
// Macro so that we can stringify type names
|
// Macro so that we can stringify type names
|
||||||
|
@ -45,3 +46,4 @@ sizeof_checker!(size_div, HTMLDivElement, 328);
|
||||||
sizeof_checker!(size_span, HTMLSpanElement, 328);
|
sizeof_checker!(size_span, HTMLSpanElement, 328);
|
||||||
sizeof_checker!(size_text, Text, 192);
|
sizeof_checker!(size_text, Text, 192);
|
||||||
sizeof_checker!(size_characterdata, CharacterData, 192);
|
sizeof_checker!(size_characterdata, CharacterData, 192);
|
||||||
|
sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue