From e5cab3667165765669f2546aa683cfe73e0494af Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Tue, 14 Jun 2016 16:05:08 +0100 Subject: [PATCH 01/30] Move ByteIndex to gfx_traits. --- components/gfx/text/glyph.rs | 10 ++-------- components/gfx_traits/Cargo.toml | 2 ++ components/gfx_traits/lib.rs | 11 +++++++++++ components/servo/Cargo.lock | 2 ++ ports/cef/Cargo.lock | 2 ++ 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/components/gfx/text/glyph.rs b/components/gfx/text/glyph.rs index fe9dc415625..9e5e7cf732e 100644 --- a/components/gfx/text/glyph.rs +++ b/components/gfx/text/glyph.rs @@ -11,6 +11,8 @@ use std::cmp::{Ordering, PartialOrd}; use std::vec::Vec; use std::{fmt, mem, u16}; +pub use gfx_traits::ByteIndex; + /// 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 @@ -426,14 +428,6 @@ pub struct GlyphStore { 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 { /// Initializes the glyph store, but doesn't actually shape anything. /// diff --git a/components/gfx_traits/Cargo.toml b/components/gfx_traits/Cargo.toml index 18b2d5abce8..133faf344b3 100644 --- a/components/gfx_traits/Cargo.toml +++ b/components/gfx_traits/Cargo.toml @@ -13,6 +13,8 @@ azure = {git = "https://github.com/servo/rust-azure", features = ["plugins"]} layers = {git = "https://github.com/servo/rust-layers", features = ["plugins"]} msg = {path = "../msg"} plugins = {path = "../plugins"} +range = {path = "../range"} +rustc-serialize = "0.3" euclid = {version = "0.6.5", features = ["plugins"]} heapsize = "0.3.0" heapsize_plugin = "0.1.2" diff --git a/components/gfx_traits/lib.rs b/components/gfx_traits/lib.rs index eb832c1c788..a131792331d 100644 --- a/components/gfx_traits/lib.rs +++ b/components/gfx_traits/lib.rs @@ -15,6 +15,9 @@ extern crate euclid; extern crate heapsize; extern crate layers; extern crate msg; +#[macro_use] +extern crate range; +extern crate rustc_serialize; extern crate serde; pub mod color; @@ -25,6 +28,7 @@ use azure::azure_hl::Color; use euclid::Matrix4D; use euclid::rect::Rect; use msg::constellation_msg::PipelineId; +use range::RangeIndex; use std::fmt::{self, Debug, Formatter}; 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) +} diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index caba1fc1beb..83f29f58b55 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -814,6 +814,8 @@ dependencies = [ "layers 0.2.5 (git+https://github.com/servo/rust-layers)", "msg 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_macros 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 69af9dcbedf..4f38089fbc3 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -727,6 +727,8 @@ dependencies = [ "layers 0.2.5 (git+https://github.com/servo/rust-layers)", "msg 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_macros 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", ] From 5c03dd8eb15290c7e47e8a15172051c751a1109c Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Tue, 14 Jun 2016 19:29:43 +0100 Subject: [PATCH 02/30] Introduce a script_layout_interface crate and move RestyleDamage to it. --- components/layout/Cargo.toml | 1 + components/layout/animation.rs | 2 +- components/layout/block.rs | 2 +- components/layout/construct.rs | 2 +- components/layout/data.rs | 2 +- components/layout/flex.rs | 2 +- components/layout/flow.rs | 2 +- components/layout/fragment.rs | 2 +- components/layout/generated_content.rs | 2 +- components/layout/incremental.rs | 256 +---------------- components/layout/inline.rs | 3 +- components/layout/layout_thread.rs | 4 +- components/layout/lib.rs | 1 + components/layout/list_item.rs | 2 +- components/layout/sequential.rs | 2 +- components/layout/table.rs | 2 +- components/layout/table_cell.rs | 2 +- components/layout/traversal.rs | 2 +- components/layout/wrapper.rs | 2 +- components/script_layout_interface/Cargo.toml | 14 + components/script_layout_interface/lib.rs | 18 ++ .../script_layout_interface/restyle_damage.rs | 258 ++++++++++++++++++ components/servo/Cargo.lock | 10 + ports/cef/Cargo.lock | 10 + 24 files changed, 332 insertions(+), 271 deletions(-) create mode 100644 components/script_layout_interface/Cargo.toml create mode 100644 components/script_layout_interface/lib.rs create mode 100644 components/script_layout_interface/restyle_damage.rs diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml index f200aa86607..c6b1727d1d5 100644 --- a/components/layout/Cargo.toml +++ b/components/layout/Cargo.toml @@ -31,6 +31,7 @@ profile_traits = {path = "../profile_traits"} range = {path = "../range"} rustc-serialize = "0.3" script = {path = "../script"} +script_layout_interface = {path = "../script_layout_interface"} script_traits = {path = "../script_traits"} selectors = {version = "0.6", features = ["heap_size"]} serde_json = "0.7" diff --git a/components/layout/animation.rs b/components/layout/animation.rs index e9a530e7d90..cc87a2824a4 100644 --- a/components/layout/animation.rs +++ b/components/layout/animation.rs @@ -6,9 +6,9 @@ use flow::{self, Flow}; use gfx::display_list::OpaqueNode; -use incremental::RestyleDamage; use ipc_channel::ipc::IpcSender; use msg::constellation_msg::PipelineId; +use script_layout_interface::restyle_damage::RestyleDamage; use script_traits::{AnimationState, LayoutMsg as ConstellationMsg}; use std::collections::HashMap; use std::collections::hash_map::Entry; diff --git a/components/layout/block.rs b/components/layout/block.rs index 6571d7d708a..9fc527d98d5 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -45,12 +45,12 @@ use fragment::SpecificFragmentInfo; use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, HAS_LAYER, Overflow}; use gfx::display_list::{ClippingRegion, StackingContext}; use gfx_traits::{LayerId, StackingContextId}; -use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT}; use layout_debug; use layout_thread::DISPLAY_PORT_SIZE_FACTOR; use model::{CollapsibleMargins, MaybeAuto, specified, specified_or_none}; use model::{self, IntrinsicISizes, MarginCollapseInfo}; 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::fmt; use std::sync::Arc; diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 49546fb2663..3066f8f6ae5 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -28,7 +28,6 @@ use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo}; use fragment::{InlineAbsoluteHypotheticalFragmentInfo, TableColumnFragmentInfo}; use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo}; use gfx::display_list::OpaqueNode; -use incremental::{BUBBLE_ISIZES, RECONSTRUCT_FLOW, RestyleDamage}; use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, InlineFragmentNodeFlags}; use inline::{InlineFragmentNodeInfo, LAST_FRAGMENT_OF_ELEMENT}; use list_item::{ListItemFlow, ListStyleTypeContent}; @@ -37,6 +36,7 @@ use parallel; use script::layout_interface::is_image_data; use script::layout_interface::{CharacterDataTypeId, ElementTypeId}; use script::layout_interface::{HTMLElementTypeId, NodeTypeId}; +use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, RECONSTRUCT_FLOW, RestyleDamage}; use std::borrow::ToOwned; use std::collections::LinkedList; use std::marker::PhantomData; diff --git a/components/layout/data.rs b/components/layout/data.rs index 10c72667aae..d189814f788 100644 --- a/components/layout/data.rs +++ b/components/layout/data.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use construct::ConstructionResult; -use incremental::RestyleDamage; +use script_layout_interface::restyle_damage::RestyleDamage; use style::servo::PrivateStyleData; /// Data that layout associates with a node. diff --git a/components/layout/flex.rs b/components/layout/flex.rs index b977124bf80..dd279bbdfdf 100644 --- a/components/layout/flex.rs +++ b/components/layout/flex.rs @@ -19,9 +19,9 @@ use flow_ref::{self, FlowRef}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use gfx::display_list::StackingContext; use gfx_traits::StackingContextId; -use incremental::{REFLOW, REFLOW_OUT_OF_FLOW}; use layout_debug; use model::{IntrinsicISizes, MaybeAuto, MinMaxConstraint}; +use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW}; use std::cmp::max; use std::sync::Arc; use style::computed_values::flex_direction; diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 350092acc90..79aa1daaaa5 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -36,12 +36,12 @@ use flow_ref::{self, FlowRef, WeakFlowRef}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo}; use gfx::display_list::{ClippingRegion, StackingContext}; use gfx_traits::{LayerId, LayerType, StackingContextId}; -use incremental::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage}; use inline::InlineFlow; use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo}; use multicol::MulticolFlow; use parallel::FlowParallelInfo; use rustc_serialize::{Encodable, Encoder}; +use script_layout_interface::restyle_damage::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage}; use std::iter::Zip; use std::slice::IterMut; use std::sync::Arc; diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 80664d720c8..9aa7cf43338 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -18,7 +18,6 @@ use gfx::display_list::{BLUR_INFLATION_FACTOR, OpaqueNode}; use gfx::text::glyph::ByteIndex; use gfx::text::text_run::{TextRun, TextRunSlice}; use gfx_traits::{FragmentType, LayerId, LayerType, StackingContextId}; -use incremental::{RECONSTRUCT_FLOW, RestyleDamage}; use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFragmentContext, InlineFragmentNodeInfo}; use inline::{InlineMetrics, LAST_FRAGMENT_OF_ELEMENT}; use ipc_channel::ipc::IpcSender; @@ -31,6 +30,7 @@ use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder}; use range::*; use rustc_serialize::{Encodable, Encoder}; use script::layout_interface::HTMLCanvasData; +use script_layout_interface::restyle_damage::{RECONSTRUCT_FLOW, RestyleDamage}; use std::borrow::ToOwned; use std::cmp::{max, min}; use std::collections::LinkedList; diff --git a/components/layout/generated_content.rs b/components/layout/generated_content.rs index a7e9c8f463a..b6264859faa 100644 --- a/components/layout/generated_content.rs +++ b/components/layout/generated_content.rs @@ -13,7 +13,7 @@ use flow::InorderFlowTraversal; use flow::{self, AFFECTS_COUNTERS, Flow, HAS_COUNTER_AFFECTING_CHILDREN, ImmutableFlowUtils}; use fragment::{Fragment, GeneratedContentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo}; use gfx::display_list::OpaqueNode; -use incremental::{RESOLVE_GENERATED_CONTENT, RestyleDamage}; +use script_layout_interface::restyle_damage::{RESOLVE_GENERATED_CONTENT, RestyleDamage}; use smallvec::SmallVec; use std::collections::{HashMap, LinkedList}; use std::sync::Arc; diff --git a/components/layout/incremental.rs b/components/layout/incremental.rs index a95a60e002a..14644be6ddc 100644 --- a/components/layout/incremental.rs +++ b/components/layout/incremental.rs @@ -3,46 +3,9 @@ * 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 std::fmt; -use std::sync::Arc; -use style::computed_values::{display, float}; +use script_layout_interface::restyle_damage::{RestyleDamage, REFLOW, RECONSTRUCT_FLOW}; +use style::computed_values::float; 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! { pub flags SpecialRestyleDamage: u8 { @@ -52,221 +15,6 @@ bitflags! { } } -impl TRestyleDamage for RestyleDamage { - type ConcreteComputedValues = ServoComputedValues; - fn compute(old: Option<&Arc>, 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>, 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 { fn compute_layout_damage(self) -> SpecialRestyleDamage; fn reflow_entire_document(self); diff --git a/components/layout/inline.rs b/components/layout/inline.rs index 5387f943070..e0e390557db 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -21,10 +21,11 @@ use gfx::display_list::{OpaqueNode, StackingContext}; use gfx::font::FontMetrics; use gfx::font_context::FontContext; use gfx_traits::StackingContextId; -use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RESOLVE_GENERATED_CONTENT}; use layout_debug; use model::IntrinsicISizesContribution; 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 std::cmp::max; use std::collections::VecDeque; use std::sync::Arc; diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index bedc72791c6..abe3fd7d33a 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -29,8 +29,7 @@ use gfx::font_context; use gfx::paint_thread::LayoutToPaintMsg; use gfx_traits::{color, Epoch, FragmentType, LayerId, ScrollPolicy, StackingContextId}; use heapsize::HeapSizeOf; -use incremental::LayoutDamageComputation; -use incremental::{REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW, REFLOW, REFLOW_ENTIRE_DOCUMENT}; +use incremental::{LayoutDamageComputation, REFLOW_ENTIRE_DOCUMENT}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; use layout_debug; @@ -51,6 +50,7 @@ use script::layout_interface::OpaqueStyleAndLayoutData; use script::layout_interface::{LayoutRPC, OffsetParentResponse, NodeOverflowResponse, MarginStyleResponse}; use script::layout_interface::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow}; use script::reporter::CSSErrorReporter; +use script_layout_interface::restyle_damage::{REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW, REFLOW}; use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg}; use script_traits::{StackingContextScrollState, UntrustedNodeAddress}; use sequential; diff --git a/components/layout/lib.rs b/components/layout/lib.rs index 88f08610eba..62da36cff87 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -47,6 +47,7 @@ extern crate profile_traits; extern crate range; extern crate rustc_serialize; extern crate script; +extern crate script_layout_interface; extern crate script_traits; extern crate selectors; extern crate serde_json; diff --git a/components/layout/list_item.rs b/components/layout/list_item.rs index de079325e69..be0620b817d 100644 --- a/components/layout/list_item.rs +++ b/components/layout/list_item.rs @@ -19,8 +19,8 @@ use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, GeneratedC use generated_content; use gfx::display_list::StackingContext; use gfx_traits::StackingContextId; -use incremental::RESOLVE_GENERATED_CONTENT; use inline::InlineMetrics; +use script_layout_interface::restyle_damage::RESOLVE_GENERATED_CONTENT; use std::sync::Arc; use style::computed_values::{list_style_type, position}; use style::logical_geometry::LogicalSize; diff --git a/components/layout/sequential.rs b/components/layout/sequential.rs index 6663843f572..a761251b77f 100644 --- a/components/layout/sequential.rs +++ b/components/layout/sequential.rs @@ -16,7 +16,7 @@ use flow_ref::{self, FlowRef}; use fragment::FragmentBorderBoxIterator; use generated_content::ResolveGeneratedContent; 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 util::opts; diff --git a/components/layout/table.rs b/components/layout/table.rs index 5b7f26eb9d9..14845532ef0 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -18,9 +18,9 @@ use flow_list::MutFlowListIterator; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use gfx::display_list::StackingContext; use gfx_traits::StackingContextId; -use incremental::{REFLOW, REFLOW_OUT_OF_FLOW}; use layout_debug; use model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto}; +use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW}; use std::cmp; use std::fmt; use std::sync::Arc; diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index a579ecb6c12..1038328b7af 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -16,9 +16,9 @@ use flow::{self, Flow, FlowClass, OpaqueFlow}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use gfx::display_list::StackingContext; use gfx_traits::StackingContextId; -use incremental::REFLOW; use layout_debug; use model::MaybeAuto; +use script_layout_interface::restyle_damage::REFLOW; use std::fmt; use std::sync::Arc; use style::computed_values::{border_collapse, border_top_style, vertical_align}; diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index bd07e1f72bb..b1ccaf638c3 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -10,7 +10,7 @@ use display_list_builder::DisplayListBuildState; use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal}; use flow::{PreorderFlowTraversal, self}; 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 std::mem; use style::context::StyleContext; use style::matching::MatchMethods; diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 3c18e909bae..7a20337607e 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -35,7 +35,6 @@ use data::{LayoutDataFlags, PrivateLayoutData}; use gfx::display_list::OpaqueNode; use gfx::text::glyph::ByteIndex; use gfx_traits::{LayerId, LayerType}; -use incremental::RestyleDamage; use msg::constellation_msg::PipelineId; use opaque_node::OpaqueNodeMethods; use range::Range; @@ -45,6 +44,7 @@ use script::layout_interface::{HTMLCanvasData, HTMLElementTypeId, LayoutCharacte use script::layout_interface::{LayoutDocumentHelpers, LayoutElementHelpers, LayoutJS}; use script::layout_interface::{LayoutNodeHelpers, Node, NodeTypeId, OpaqueStyleAndLayoutData}; use script::layout_interface::{RawLayoutElementHelpers, Text, TrustedNodeAddress}; +use script_layout_interface::restyle_damage::RestyleDamage; use selectors::matching::{DeclarationBlock, ElementFlags}; use selectors::parser::{AttrSelector, NamespaceConstraint}; use smallvec::VecLike; diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml new file mode 100644 index 00000000000..3069b1a3b8d --- /dev/null +++ b/components/script_layout_interface/Cargo.toml @@ -0,0 +1,14 @@ +[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] +bitflags = "0.7" +plugins = {path = "../plugins"} +style = {path = "../style"} diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs new file mode 100644 index 00000000000..1aed95b6210 --- /dev/null +++ b/components/script_layout_interface/lib.rs @@ -0,0 +1,18 @@ +/* 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(plugin)] +#![plugin(plugins)] + +#[allow(unused_extern_crates)] +#[macro_use] +extern crate bitflags; +extern crate style; + +pub mod restyle_damage; diff --git a/components/script_layout_interface/restyle_damage.rs b/components/script_layout_interface/restyle_damage.rs new file mode 100644 index 00000000000..56a068a2237 --- /dev/null +++ b/components/script_layout_interface/restyle_damage.rs @@ -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>, 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>, 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 +} diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 83f29f58b55..d2e8c8a42e4 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1157,6 +1157,7 @@ dependencies = [ "range 0.0.1", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "script 0.0.1", + "script_layout_interface 0.0.1", "script_traits 0.0.1", "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)", @@ -1924,6 +1925,15 @@ dependencies = [ "xml5ever 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "script_layout_interface" +version = "0.0.1" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "plugins 0.0.1", + "style 0.0.1", +] + [[package]] name = "script_tests" version = "0.0.1" diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 4f38089fbc3..4edf3ccacc0 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -1070,6 +1070,7 @@ dependencies = [ "range 0.0.1", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "script 0.0.1", + "script_layout_interface 0.0.1", "script_traits 0.0.1", "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)", @@ -1782,6 +1783,15 @@ dependencies = [ "xml5ever 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "script_layout_interface" +version = "0.0.1" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "plugins 0.0.1", + "style 0.0.1", +] + [[package]] name = "script_traits" version = "0.0.1" From 5cab8ff8d243038f498922c5960e1161bd8aafd7 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Tue, 14 Jun 2016 20:07:28 +0100 Subject: [PATCH 03/30] Make OpaqueStyleAndLayoutData::dispose a method on Node. --- components/script/dom/node.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index a3289cca56e..4554ac3210c 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -171,7 +171,7 @@ impl NodeFlags { impl Drop for Node { #[allow(unsafe_code)] 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)); } } @@ -196,17 +196,15 @@ 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 { + /// 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. /// /// Fails unless `new_child` is disconnected from the tree. @@ -292,7 +290,7 @@ impl Node { for node in child.traverse_preorder() { node.set_flag(IS_IN_DOC, false); 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); @@ -340,7 +338,7 @@ impl<'a> Iterator for QuerySelectorIterator { impl Node { 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() { kid.teardown(); } From 6aaf3e6a0153725c2c458b791cc18c72c1e46115 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 00:00:28 +0100 Subject: [PATCH 04/30] Move OpaqueStyleAndLayoutData to script_layout_interface. --- components/layout/layout_thread.rs | 2 +- components/layout/wrapper.rs | 3 ++- components/script/Cargo.toml | 1 + components/script/dom/bindings/trace.rs | 2 ++ components/script/dom/node.rs | 14 +------------- components/script/layout_interface.rs | 2 +- components/script/lib.rs | 1 + components/script_layout_interface/Cargo.toml | 2 ++ components/script_layout_interface/lib.rs | 18 ++++++++++++++++++ components/servo/Cargo.lock | 3 +++ ports/cef/Cargo.lock | 3 +++ 11 files changed, 35 insertions(+), 16 deletions(-) diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index abe3fd7d33a..d0c27743667 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -46,10 +46,10 @@ use query::process_offset_parent_query; 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_overflow_request, process_resolved_style_request, process_margin_style_query}; -use script::layout_interface::OpaqueStyleAndLayoutData; use script::layout_interface::{LayoutRPC, OffsetParentResponse, NodeOverflowResponse, MarginStyleResponse}; use script::layout_interface::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow}; use script::reporter::CSSErrorReporter; +use script_layout_interface::OpaqueStyleAndLayoutData; use script_layout_interface::restyle_damage::{REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW, REFLOW}; use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg}; use script_traits::{StackingContextScrollState, UntrustedNodeAddress}; diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 7a20337607e..82c3d1416d5 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -42,8 +42,9 @@ use script::layout_interface::{CAN_BE_FRAGMENTED, HAS_CHANGED, HAS_DIRTY_DESCEND use script::layout_interface::{CharacterDataTypeId, Document, Element, ElementTypeId}; use script::layout_interface::{HTMLCanvasData, HTMLElementTypeId, LayoutCharacterDataHelpers}; use script::layout_interface::{LayoutDocumentHelpers, LayoutElementHelpers, LayoutJS}; -use script::layout_interface::{LayoutNodeHelpers, Node, NodeTypeId, OpaqueStyleAndLayoutData}; +use script::layout_interface::{LayoutNodeHelpers, Node, NodeTypeId}; use script::layout_interface::{RawLayoutElementHelpers, Text, TrustedNodeAddress}; +use script_layout_interface::OpaqueStyleAndLayoutData; use script_layout_interface::restyle_damage::RestyleDamage; use selectors::matching::{DeclarationBlock, ElementFlags}; use selectors::parser::{AttrSelector, NamespaceConstraint}; diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 911f1b9cc67..bbb086a308d 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -52,6 +52,7 @@ ref_filter_map = "1.0" ref_slice = "1.0" regex = "0.1.43" rustc-serialize = "0.3" +script_layout_interface = {path = "../script_layout_interface"} script_traits = {path = "../script_traits"} selectors = {version = "0.6", features = ["heap_size"]} serde = "0.7" diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 34ec7d19e14..070a3e1b954 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -67,6 +67,7 @@ use net_traits::{Metadata, NetworkError, ResourceThreads}; use offscreen_gl_context::GLLimits; use profile_traits::mem::ProfilerChan as MemProfilerChan; use profile_traits::time::ProfilerChan as TimeProfilerChan; +use script_layout_interface::OpaqueStyleAndLayoutData; use script_runtime::ScriptChan; use script_traits::{TimerEventId, TimerSource, TouchpadPressurePhase, UntrustedNodeAddress}; use serde::{Deserialize, Serialize}; @@ -328,6 +329,7 @@ no_jsmanaged_fields!(ReferrerPolicy); no_jsmanaged_fields!(ResourceThreads); no_jsmanaged_fields!(SystemTime); no_jsmanaged_fields!(SelectedFileId); +no_jsmanaged_fields!(OpaqueStyleAndLayoutData); impl JSTraceable for Box { #[inline] diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 4554ac3210c..a6834d487d4 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -5,7 +5,6 @@ //! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements. use app_units::Au; -use core::nonzero::NonZero; use devtools_traits::NodeInfo; use document_loader::DocumentLoader; use dom::attr::Attr; @@ -62,6 +61,7 @@ use libc::{self, c_void, uintptr_t}; use msg::constellation_msg::PipelineId; use parse::html::parse_html_fragment; use ref_slice::ref_slice; +use script_layout_interface::OpaqueStyleAndLayoutData; use script_traits::UntrustedNodeAddress; use selectors::matching::matches; use selectors::parser::Selector; @@ -184,18 +184,6 @@ enum SuppressObserver { 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 Node { /// Sends the style and layout data, if any, back to the layout thread to be destroyed. pub fn dispose(&self, data: OpaqueStyleAndLayoutData) { diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index 37b6d169481..ae68cc0ec55 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -14,6 +14,7 @@ use ipc_channel::ipc::{IpcReceiver, IpcSender}; use msg::constellation_msg::{PanicMsg, PipelineId, WindowSizeData}; use net_traits::image_cache_thread::ImageCacheThread; use profile_traits::mem::ReportsChan; +use script_layout_interface::OpaqueStyleAndLayoutData; use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg}; use script_traits::{StackingContextScrollState, UntrustedNodeAddress}; use std::sync::Arc; @@ -37,7 +38,6 @@ 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; diff --git a/components/script/lib.rs b/components/script/lib.rs index 307376854ca..a47d549cc31 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -68,6 +68,7 @@ extern crate ref_filter_map; extern crate ref_slice; extern crate regex; extern crate rustc_serialize; +extern crate script_layout_interface; extern crate script_traits; extern crate selectors; extern crate serde; diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index 3069b1a3b8d..cbc36fa02c4 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -10,5 +10,7 @@ path = "lib.rs" [dependencies] bitflags = "0.7" +heapsize = "0.3.0" +heapsize_plugin = "0.1.2" plugins = {path = "../plugins"} style = {path = "../style"} diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index 1aed95b6210..b2e3b6fd475 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -7,12 +7,30 @@ //! to depend on script. #![deny(unsafe_code)] +#![feature(custom_attribute)] +#![feature(custom_derive)] +#![feature(nonzero)] #![feature(plugin)] +#![plugin(heapsize_plugin)] #![plugin(plugins)] #[allow(unused_extern_crates)] #[macro_use] extern crate bitflags; +extern crate core; +extern crate heapsize; extern crate style; pub mod restyle_damage; + +use core::nonzero::NonZero; + +#[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 {} diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index d2e8c8a42e4..5636de1687b 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1909,6 +1909,7 @@ dependencies = [ "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)", "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", "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)", @@ -1930,6 +1931,8 @@ name = "script_layout_interface" version = "0.0.1" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", "plugins 0.0.1", "style 0.0.1", ] diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 4edf3ccacc0..8467c3bd56d 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -1767,6 +1767,7 @@ dependencies = [ "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)", "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", "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)", @@ -1788,6 +1789,8 @@ name = "script_layout_interface" version = "0.0.1" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", "plugins 0.0.1", "style 0.0.1", ] From bea96f60e322dae5262c4024a0b3d65f469b2979 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 00:16:49 +0100 Subject: [PATCH 05/30] Introduce PartialStyleAndLayoutData. --- components/layout/layout_thread.rs | 5 +++-- components/layout/wrapper.rs | 4 ++-- components/script_layout_interface/lib.rs | 10 +++++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index d0c27743667..64d37f889d4 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -49,13 +49,14 @@ use query::{process_node_overflow_request, process_resolved_style_request, proce use script::layout_interface::{LayoutRPC, OffsetParentResponse, NodeOverflowResponse, MarginStyleResponse}; use script::layout_interface::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow}; use script::reporter::CSSErrorReporter; -use script_layout_interface::OpaqueStyleAndLayoutData; use script_layout_interface::restyle_damage::{REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW, REFLOW}; +use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData}; use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg}; use script_traits::{StackingContextScrollState, UntrustedNodeAddress}; use sequential; use serde_json; use std::borrow::ToOwned; +use std::cell::RefCell; use std::collections::HashMap; use std::hash::BuildHasherDefault; use std::ops::{Deref, DerefMut}; @@ -1480,7 +1481,7 @@ impl LayoutThread { /// 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. unsafe fn handle_reap_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) { - let ptr: *mut () = *data.ptr; + let ptr: *mut RefCell = *data.ptr; let non_opaque: NonOpaqueStyleAndLayoutData = ptr as *mut _; let _ = Box::from_raw(non_opaque); } diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 82c3d1416d5..88c001ca4d6 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -44,8 +44,8 @@ use script::layout_interface::{HTMLCanvasData, HTMLElementTypeId, LayoutCharacte use script::layout_interface::{LayoutDocumentHelpers, LayoutElementHelpers, LayoutJS}; use script::layout_interface::{LayoutNodeHelpers, Node, NodeTypeId}; use script::layout_interface::{RawLayoutElementHelpers, Text, TrustedNodeAddress}; -use script_layout_interface::OpaqueStyleAndLayoutData; use script_layout_interface::restyle_damage::RestyleDamage; +use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData}; use selectors::matching::{DeclarationBlock, ElementFlags}; use selectors::parser::{AttrSelector, NamespaceConstraint}; use smallvec::VecLike; @@ -127,7 +127,7 @@ impl<'ln> ServoLayoutNode<'ln> { let ptr: NonOpaqueStyleAndLayoutData = Box::into_raw(box RefCell::new(PrivateLayoutData::new())); let opaque = OpaqueStyleAndLayoutData { - ptr: unsafe { NonZero::new(ptr as *mut ()) } + ptr: unsafe { NonZero::new(ptr as *mut RefCell) } }; unsafe { self.node.init_style_and_layout_data(opaque); diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index b2e3b6fd475..7c1a4e28e29 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -24,12 +24,20 @@ extern crate style; pub mod restyle_damage; use core::nonzero::NonZero; +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 ()> + pub ptr: NonZero<*mut RefCell> } #[allow(unsafe_code)] From 72632ac16d873f143610696c95e39e9e372f6208 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 00:24:51 +0100 Subject: [PATCH 06/30] Implement get_style_data() methods. --- components/layout/wrapper.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 88c001ca4d6..5c81c5c1fb5 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -79,6 +79,8 @@ pub trait LayoutNode: TNode { /// Returns the type ID of this node. fn type_id(&self) -> NodeTypeId; + fn get_style_data(&self) -> Option<&RefCell>; + /// Similar to borrow_data*, but returns the full PrivateLayoutData rather /// than only the PrivateStyleData. unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData>; @@ -292,6 +294,14 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> { } } + fn get_style_data(&self) -> Option<&RefCell> { + unsafe { + self.get_jsmanaged().get_style_and_layout_data().map(|d| { + &**d.ptr + }) + } + } + unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData> { self.get_jsmanaged().get_style_and_layout_data().map(|opaque| { let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; @@ -932,6 +942,8 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { 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>; } // This trait is only public so that it can be implemented by the gecko wrapper. @@ -1159,6 +1171,10 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { self.get_jsmanaged().downcast::().unwrap().get_colspan() } } + + fn get_style_data(&self) -> Option<&RefCell> { + self.node.get_style_data() + } } pub struct ThreadSafeLayoutNodeChildrenIterator { From d50c1667863efe901032886a355c5891090a9933 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 00:33:52 +0100 Subject: [PATCH 07/30] Use get_style_data() where possible. --- components/layout/wrapper.rs | 56 +++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 5c81c5c1fb5..8d86459a068 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -231,23 +231,29 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { } unsafe fn borrow_data_unchecked(&self) -> Option<*const PrivateStyleData> { - self.borrow_layout_data_unchecked().map(|d| &(*d).style_data as *const PrivateStyleData) + self.get_style_data().map(|d| { + &(*d.as_unsafe_cell().get()).style_data as *const _ + }) } fn borrow_data(&self) -> Option> { - self.borrow_layout_data().map(|d| Ref::map(d, |d| &d.style_data)) + self.get_style_data().map(|d| { + Ref::map(d.borrow(), |d| &d.style_data) + }) } fn mutate_data(&self) -> Option> { - self.mutate_layout_data().map(|d| RefMut::map(d, |d| &mut d.style_data)) + self.get_style_data().map(|d| { + RefMut::map(d.borrow_mut(), |d| &mut d.style_data) + }) } fn restyle_damage(self) -> RestyleDamage { - self.borrow_layout_data().unwrap().restyle_damage + self.get_style_data().unwrap().borrow().restyle_damage } fn set_restyle_damage(self, damage: RestyleDamage) { - self.mutate_layout_data().unwrap().restyle_damage = damage; + self.get_style_data().unwrap().borrow_mut().restyle_damage = damage; } fn parent_node(&self) -> Option> { @@ -716,8 +722,11 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { #[inline] fn get_before_pseudo(&self) -> Option { - if self.borrow_layout_data().unwrap() - .style_data.per_pseudo + if self.get_style_data() + .unwrap() + .borrow() + .style_data + .per_pseudo .contains_key(&PseudoElement::Before) { Some(self.with_pseudo(PseudoElementType::Before(None))) } else { @@ -727,8 +736,11 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { #[inline] fn get_after_pseudo(&self) -> Option { - if self.borrow_layout_data().unwrap() - .style_data.per_pseudo + if self.get_style_data() + .unwrap() + .borrow() + .style_data + .per_pseudo .contains_key(&PseudoElement::After) { Some(self.with_pseudo(PseudoElementType::After(None))) } else { @@ -783,7 +795,7 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { fn style(&self, context: &SharedStyleContext) -> Ref> { match self.get_pseudo_element_type() { PseudoElementType::Normal => { - Ref::map(self.borrow_layout_data().unwrap(), |data| { + Ref::map(self.get_style_data().unwrap().borrow(), |data| { data.style_data.style.as_ref().unwrap() }) }, @@ -795,10 +807,12 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { // Already computed during the cascade. PseudoElementCascadeType::Eager => {}, PseudoElementCascadeType::Precomputed => { - if !self.borrow_layout_data() - .unwrap().style_data + if !self.get_style_data() + .unwrap() + .borrow() + .style_data .per_pseudo.contains_key(&style_pseudo) { - let mut data = self.mutate_layout_data().unwrap(); + let mut data = self.get_style_data().unwrap().borrow_mut(); let new_style = context.stylist .precomputed_values_for_pseudo(&style_pseudo, @@ -809,10 +823,12 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { } PseudoElementCascadeType::Lazy => { debug_assert!(self.is_element_or_elements_pseudo()); - if !self.borrow_layout_data() - .unwrap().style_data + if !self.get_style_data() + .unwrap() + .borrow() + .style_data .per_pseudo.contains_key(&style_pseudo) { - let mut data = self.mutate_layout_data().unwrap(); + let mut data = self.get_style_data().unwrap().borrow_mut(); let new_style = context.stylist .lazily_compute_pseudo_element_style( @@ -825,7 +841,7 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { } } - Ref::map(self.borrow_layout_data().unwrap(), |data| { + Ref::map(self.get_style_data().unwrap().borrow(), |data| { data.style_data.per_pseudo.get(&style_pseudo).unwrap() }) } @@ -841,7 +857,7 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { /// element style is precomputed, not from general layout itself. #[inline] fn resolved_style(&self) -> Ref> { - Ref::map(self.borrow_layout_data().unwrap(), |data| { + Ref::map(self.get_style_data().unwrap().borrow(), |data| { match self.get_pseudo_element_type() { PseudoElementType::Normal => data.style_data.style.as_ref().unwrap(), @@ -853,7 +869,7 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { #[inline] fn selected_style(&self, _context: &SharedStyleContext) -> Ref> { - Ref::map(self.borrow_layout_data().unwrap(), |data| { + 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()) @@ -864,7 +880,7 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { /// /// Unlike the version on TNode, this handles pseudo-elements. fn unstyle(self) { - let mut data = self.mutate_layout_data().unwrap(); + let mut data = self.get_style_data().unwrap().borrow_mut(); match self.get_pseudo_element_type() { PseudoElementType::Normal => { From 8b05833e52fea898e2e917013ddbfcc47061b2c3 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 00:56:12 +0100 Subject: [PATCH 08/30] Split initialize_data into two. The first one handles the layout-specific part, and calls the second one to handle the script-specific part. --- components/layout/wrapper.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 8d86459a068..9f6dd2bdaef 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -81,6 +81,8 @@ pub trait LayoutNode: TNode { fn get_style_data(&self) -> Option<&RefCell>; + fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData); + /// Similar to borrow_data*, but returns the full PrivateLayoutData rather /// than only the PrivateStyleData. unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData>; @@ -131,9 +133,7 @@ impl<'ln> ServoLayoutNode<'ln> { let opaque = OpaqueStyleAndLayoutData { ptr: unsafe { NonZero::new(ptr as *mut RefCell) } }; - unsafe { - self.node.init_style_and_layout_data(opaque); - } + self.init_style_and_layout_data(opaque); } } } @@ -308,6 +308,12 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> { } } + fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) { + unsafe { + self.get_jsmanaged().init_style_and_layout_data(data); + } + } + unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData> { self.get_jsmanaged().get_style_and_layout_data().map(|opaque| { let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; From 310cb5a32697d53dda62dd188f51e6ba90d34af8 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 01:06:07 +0100 Subject: [PATCH 09/30] Introduce get_style_and_layout_data() methods. --- components/layout/wrapper.rs | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 9f6dd2bdaef..4ab9b97ce64 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -82,6 +82,7 @@ pub trait LayoutNode: TNode { fn get_style_data(&self) -> Option<&RefCell>; fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData); + fn get_style_and_layout_data(&self) -> Option; /// Similar to borrow_data*, but returns the full PrivateLayoutData rather /// than only the PrivateStyleData. @@ -314,8 +315,14 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> { } } + fn get_style_and_layout_data(&self) -> Option { + unsafe { + self.get_jsmanaged().get_style_and_layout_data() + } + } + unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData> { - self.get_jsmanaged().get_style_and_layout_data().map(|opaque| { + self.get_style_and_layout_data().map(|opaque| { let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; &(*(*container).as_unsafe_cell().get()) as *const PrivateLayoutData }) @@ -323,7 +330,7 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> { fn borrow_layout_data(&self) -> Option> { unsafe { - self.get_jsmanaged().get_style_and_layout_data().map(|opaque| { + self.get_style_and_layout_data().map(|opaque| { let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; (*container).borrow() }) @@ -332,7 +339,7 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> { fn mutate_layout_data(&self) -> Option> { unsafe { - self.get_jsmanaged().get_style_and_layout_data().map(|opaque| { + self.get_style_and_layout_data().map(|opaque| { let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; (*container).borrow_mut() }) @@ -781,6 +788,8 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { } } + fn get_style_and_layout_data(&self) -> Option; + /// Borrows the layout data immutably. Fails on a conflicting borrow. /// /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. @@ -1101,12 +1110,26 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { self.pseudo } + fn get_style_and_layout_data(&self) -> Option { + self.node.get_style_and_layout_data() + } + fn borrow_layout_data(&self) -> Option> { - self.node.borrow_layout_data() + unsafe { + self.get_style_and_layout_data().map(|opaque| { + let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; + (*container).borrow() + }) + } } fn mutate_layout_data(&self) -> Option> { - self.node.mutate_layout_data() + unsafe { + self.get_style_and_layout_data().map(|opaque| { + let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; + (*container).borrow_mut() + }) + } } fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool { From c910ef2072f7d0fb311b212712994abac62b811c Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 01:17:35 +0100 Subject: [PATCH 10/30] Introduce a LayoutNodeLayoutData trait for methods to stay in layout. --- components/layout/layout_thread.rs | 2 +- components/layout/wrapper.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index 64d37f889d4..d72653dc634 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -85,7 +85,7 @@ use util::thread_state; use util::workqueue::WorkQueue; use webrender_helpers::{WebRenderDisplayListConverter, WebRenderFrameBuilder}; use webrender_traits; -use wrapper::{LayoutNode, NonOpaqueStyleAndLayoutData, ServoLayoutNode}; +use wrapper::{LayoutNode, LayoutNodeLayoutData, NonOpaqueStyleAndLayoutData, ServoLayoutNode}; /// 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; diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 4ab9b97ce64..2acb1636f4e 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -83,7 +83,9 @@ pub trait LayoutNode: TNode { fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData); fn get_style_and_layout_data(&self) -> Option; +} +pub trait LayoutNodeLayoutData { /// Similar to borrow_data*, but returns the full PrivateLayoutData rather /// than only the PrivateStyleData. unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData>; @@ -320,7 +322,9 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> { self.get_jsmanaged().get_style_and_layout_data() } } +} +impl LayoutNodeLayoutData for T { unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData> { self.get_style_and_layout_data().map(|opaque| { let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; From 16d6555f4d8f8298df9e1808dafc0b55a17c8055 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 01:22:21 +0100 Subject: [PATCH 11/30] Move some more methods into the LayoutNodeLayoutData trait. --- components/layout/traversal.rs | 2 +- components/layout/wrapper.rs | 32 +++++++++++++++++--------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index b1ccaf638c3..14289683d4d 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -18,7 +18,7 @@ use style::traversal::{DomTraversalContext, STYLE_BLOOM}; use style::traversal::{put_thread_local_bloom_filter, recalc_style_at}; use util::opts; use util::tid::tid; -use wrapper::{LayoutNode, ServoLayoutNode, ThreadSafeLayoutNode}; +use wrapper::{LayoutNode, LayoutNodeLayoutData, ServoLayoutNode, ThreadSafeLayoutNode}; pub struct RecalcStyleAndConstructFlows<'lc> { context: LayoutContext<'lc>, diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 2acb1636f4e..f5d77472e70 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -91,6 +91,8 @@ pub trait LayoutNodeLayoutData { unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData>; fn borrow_layout_data(&self) -> Option>; fn mutate_layout_data(&self) -> Option>; + fn initialize_data(self); + fn flow_debug_id(self) -> usize; } #[derive(Copy, Clone)] @@ -128,17 +130,6 @@ impl<'ln> ServoLayoutNode<'ln> { chain: self.chain, } } - - pub fn initialize_data(self) { - if unsafe { self.borrow_data_unchecked() }.is_none() { - let ptr: NonOpaqueStyleAndLayoutData = - Box::into_raw(box RefCell::new(PrivateLayoutData::new())); - let opaque = OpaqueStyleAndLayoutData { - ptr: unsafe { NonZero::new(ptr as *mut RefCell) } - }; - self.init_style_and_layout_data(opaque); - } - } } impl<'ln> TNode for ServoLayoutNode<'ln> { @@ -349,6 +340,21 @@ impl LayoutNodeLayoutData for T { }) } } + + fn initialize_data(self) { + if unsafe { self.borrow_data_unchecked() }.is_none() { + let ptr: NonOpaqueStyleAndLayoutData = + Box::into_raw(box RefCell::new(PrivateLayoutData::new())); + let opaque = OpaqueStyleAndLayoutData { + ptr: unsafe { NonZero::new(ptr as *mut RefCell) } + }; + self.init_style_and_layout_data(opaque); + } + } + + fn flow_debug_id(self) -> usize { + self.borrow_layout_data().map_or(0, |d| d.flow_construction_result.debug_id()) + } } @@ -372,10 +378,6 @@ impl<'ln> ServoLayoutNode<'ln> { self.type_id(), self.has_changed(), self.is_dirty(), self.has_dirty_descendants()) } - pub fn flow_debug_id(self) -> usize { - self.borrow_layout_data().map_or(0, |d| d.flow_construction_result.debug_id()) - } - /// 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 { From 1039de8e7de73d69930849ec60ff22649af7f131 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 08:45:28 +0100 Subject: [PATCH 12/30] Introduce a node_text_content method. --- components/layout/wrapper.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index f5d77472e70..ce360602525 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -949,6 +949,8 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { /// FIXME(pcwalton): This might have too much copying and/or allocation. Profile this. fn text_content(&self) -> TextContent; + fn node_text_content(&self) -> String; + /// If the insertion point is within this node, returns it. Otherwise, returns `None`. fn selection(&self) -> Option>; @@ -1189,8 +1191,12 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { }; } + return TextContent::Text(self.node_text_content()); + } + + fn node_text_content(&self) -> String { let this = unsafe { self.get_jsmanaged() }; - return TextContent::Text(this.text_content()); + return this.text_content(); } fn selection(&self) -> Option> { From dac8878467e36c78893542abba3d372f403b2166 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 08:54:08 +0100 Subject: [PATCH 13/30] Introduce ThreadSafeLayoutNode::borrow_layout_data_unchecked. --- components/layout/wrapper.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index ce360602525..72685fbc577 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -796,6 +796,9 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { fn get_style_and_layout_data(&self) -> Option; + #[inline(always)] + unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData>; + /// Borrows the layout data immutably. Fails on a conflicting borrow. /// /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. @@ -1122,6 +1125,13 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { self.node.get_style_and_layout_data() } + unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData> { + self.get_style_and_layout_data().map(|opaque| { + let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; + &(*(*container).as_unsafe_cell().get()) as *const PrivateLayoutData + }) + } + fn borrow_layout_data(&self) -> Option> { unsafe { self.get_style_and_layout_data().map(|opaque| { @@ -1171,7 +1181,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { fn flags(self) -> LayoutDataFlags { unsafe { - (*self.node.borrow_layout_data_unchecked().unwrap()).flags + (*self.borrow_layout_data_unchecked().unwrap()).flags } } From afc7118a6706cc3af6879b7d032d5e693abd4707 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 08:54:12 +0100 Subject: [PATCH 14/30] Introduce a ThreadSafeLayoutNodeHelpers trait for methods to stay in layout. --- components/layout/construct.rs | 3 +- components/layout/query.rs | 2 +- components/layout/traversal.rs | 3 +- components/layout/wrapper.rs | 179 +++++++++++++++++---------------- 4 files changed, 98 insertions(+), 89 deletions(-) diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 3066f8f6ae5..8c79618a6ed 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -60,7 +60,8 @@ use traversal::PostorderNodeMutTraversal; use url::Url; use util::linked_list; use util::opts; -use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; +use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutElement}; +use wrapper::{ThreadSafeLayoutNode, ThreadSafeLayoutNodeHelpers}; /// The results of flow construction for a DOM node. #[derive(Clone)] diff --git a/components/layout/query.rs b/components/layout/query.rs index 59da80802af..728cf75e7a9 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -34,7 +34,7 @@ use style::properties::style_structs; use style::selector_impl::PseudoElement; use style::values::AuExtensionMethods; use style_traits::cursor::Cursor; -use wrapper::{LayoutNode, ThreadSafeLayoutNode}; +use wrapper::{LayoutNode, ThreadSafeLayoutNode, ThreadSafeLayoutNodeHelpers}; pub struct LayoutRPCImpl(pub Arc>); diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 14289683d4d..27734312e1f 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -18,7 +18,8 @@ use style::traversal::{DomTraversalContext, STYLE_BLOOM}; use style::traversal::{put_thread_local_bloom_filter, recalc_style_at}; use util::opts; use util::tid::tid; -use wrapper::{LayoutNode, LayoutNodeLayoutData, ServoLayoutNode, ThreadSafeLayoutNode}; +use wrapper::{LayoutNode, LayoutNodeLayoutData, ServoLayoutNode}; +use wrapper::{ThreadSafeLayoutNode, ThreadSafeLayoutNodeHelpers}; pub struct RecalcStyleAndConstructFlows<'lc> { context: LayoutContext<'lc>, diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 72685fbc577..ce4fe30c075 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -724,8 +724,6 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { fn debug_id(self) -> usize; - fn flow_debug_id(self) -> usize; - /// Returns an iterator over this node's children. fn children(&self) -> Self::ChildrenIterator; @@ -796,21 +794,6 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { fn get_style_and_layout_data(&self) -> Option; - #[inline(always)] - unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData>; - - /// Borrows the layout data immutably. Fails on a conflicting borrow. - /// - /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. - #[inline(always)] - fn borrow_layout_data(&self) -> Option>; - - /// Borrows the layout data mutably. Fails on a conflicting borrow. - /// - /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. - #[inline(always)] - fn mutate_layout_data(&self) -> Option>; - /// Returns the style results for the given node. If CSS selector matching /// has not yet been performed, fails. /// @@ -922,19 +905,6 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { fn set_restyle_damage(self, damage: RestyleDamage); - /// Returns the layout data flags for this node. - fn flags(self) -> LayoutDataFlags; - - /// Adds the given flags to this node. - fn insert_flags(self, new_flags: LayoutDataFlags) { - self.mutate_layout_data().unwrap().flags.insert(new_flags); - } - - /// Removes the given flags from this node. - fn remove_flags(self, flags: LayoutDataFlags) { - self.mutate_layout_data().unwrap().flags.remove(flags); - } - /// 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 { @@ -946,12 +916,6 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { fn can_be_fragmented(&self) -> bool; - /// If this is a text node, generated content, or a form element, copies out - /// its content. Otherwise, panics. - /// - /// FIXME(pcwalton): This might have too much copying and/or allocation. Profile this. - fn text_content(&self) -> TextContent; - fn node_text_content(&self) -> String; /// If the insertion point is within this node, returns it. Otherwise, returns `None`. @@ -988,6 +952,39 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { fn get_style_data(&self) -> Option<&RefCell>; } +pub trait ThreadSafeLayoutNodeHelpers { + fn flow_debug_id(self) -> usize; + + unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData>; + + /// Borrows the layout data immutably. Fails on a conflicting borrow. + /// + /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. + #[inline(always)] + fn borrow_layout_data(&self) -> Option>; + + /// Borrows the layout data mutably. Fails on a conflicting borrow. + /// + /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. + #[inline(always)] + fn mutate_layout_data(&self) -> Option>; + + /// Returns the layout data flags for this node. + fn flags(self) -> LayoutDataFlags; + + /// Adds the given flags to this node. + fn insert_flags(self, new_flags: LayoutDataFlags); + + /// Removes the given flags from this node. + fn remove_flags(self, flags: LayoutDataFlags); + + /// If this is a text node, generated content, or a form element, copies out + /// its content. Otherwise, panics. + /// + /// FIXME(pcwalton): This might have too much copying and/or allocation. Profile this. + fn text_content(&self) -> TextContent; +} + // 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! pub trait DangerousThreadSafeLayoutNode: ThreadSafeLayoutNode { @@ -1095,10 +1092,6 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { self.node.debug_id() } - fn flow_debug_id(self) -> usize { - self.node.flow_debug_id() - } - fn children(&self) -> Self::ChildrenIterator { ThreadSafeLayoutNodeChildrenIterator::new(*self) } @@ -1125,31 +1118,6 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { self.node.get_style_and_layout_data() } - unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData> { - self.get_style_and_layout_data().map(|opaque| { - let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; - &(*(*container).as_unsafe_cell().get()) as *const PrivateLayoutData - }) - } - - fn borrow_layout_data(&self) -> Option> { - unsafe { - self.get_style_and_layout_data().map(|opaque| { - let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; - (*container).borrow() - }) - } - } - - fn mutate_layout_data(&self) -> Option> { - unsafe { - self.get_style_and_layout_data().map(|opaque| { - let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; - (*container).borrow_mut() - }) - } - } - fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool { unsafe { let text: LayoutJS = match self.get_jsmanaged().downcast() { @@ -1179,31 +1147,10 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { self.node.set_restyle_damage(damage) } - fn flags(self) -> LayoutDataFlags { - unsafe { - (*self.borrow_layout_data_unchecked().unwrap()).flags - } - } - fn can_be_fragmented(&self) -> bool { self.node.can_be_fragmented() } - fn text_content(&self) -> TextContent { - if self.pseudo.is_replaced_content() { - let style = self.resolved_style(); - - return match style.as_ref().get_counters().content { - content::T::Content(ref value) if !value.is_empty() => { - TextContent::GeneratedContent((*value).clone()) - } - _ => TextContent::GeneratedContent(vec![]), - }; - } - - return TextContent::Text(self.node_text_content()); - } - fn node_text_content(&self) -> String { let this = unsafe { self.get_jsmanaged() }; return this.text_content(); @@ -1244,6 +1191,66 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { } } +impl ThreadSafeLayoutNodeHelpers for T { + fn flow_debug_id(self) -> usize { + self.borrow_layout_data().map_or(0, |d| d.flow_construction_result.debug_id()) + } + + unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData> { + self.get_style_and_layout_data().map(|opaque| { + let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; + &(*(*container).as_unsafe_cell().get()) as *const PrivateLayoutData + }) + } + + fn borrow_layout_data(&self) -> Option> { + unsafe { + self.get_style_and_layout_data().map(|opaque| { + let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; + (*container).borrow() + }) + } + } + + fn mutate_layout_data(&self) -> Option> { + unsafe { + self.get_style_and_layout_data().map(|opaque| { + let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; + (*container).borrow_mut() + }) + } + } + + fn flags(self) -> LayoutDataFlags { + unsafe { + (*self.borrow_layout_data_unchecked().unwrap()).flags + } + } + + fn insert_flags(self, new_flags: LayoutDataFlags) { + self.mutate_layout_data().unwrap().flags.insert(new_flags); + } + + fn remove_flags(self, flags: LayoutDataFlags) { + self.mutate_layout_data().unwrap().flags.remove(flags); + } + + fn text_content(&self) -> TextContent { + if self.get_pseudo_element_type().is_replaced_content() { + let style = self.resolved_style(); + + return match style.as_ref().get_counters().content { + content::T::Content(ref value) if !value.is_empty() => { + TextContent::GeneratedContent((*value).clone()) + } + _ => TextContent::GeneratedContent(vec![]), + }; + } + + return TextContent::Text(self.node_text_content()); + } +} + pub struct ThreadSafeLayoutNodeChildrenIterator { current_node: Option, parent_node: ConcreteNode, From 6b847eb93ab750b5029c54365cca64f450e9b154 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 10:12:37 +0100 Subject: [PATCH 15/30] Introduce LayoutNodeType and LayoutElementType enums. --- components/layout/construct.rs | 79 +++++++++-------------- components/layout/wrapper.rs | 39 ++++++----- components/script/dom/node.rs | 58 ++++++++++++++++- components/script_layout_interface/lib.rs | 27 ++++++++ 4 files changed, 137 insertions(+), 66 deletions(-) diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 8c79618a6ed..c600b0ce8e6 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -34,9 +34,8 @@ use list_item::{ListItemFlow, ListStyleTypeContent}; use multicol::{MulticolFlow, MulticolColumnFlow}; use parallel; use script::layout_interface::is_image_data; -use script::layout_interface::{CharacterDataTypeId, ElementTypeId}; -use script::layout_interface::{HTMLElementTypeId, NodeTypeId}; use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, RECONSTRUCT_FLOW, RestyleDamage}; +use script_layout_interface::{LayoutNodeType, LayoutElementType}; use std::borrow::ToOwned; use std::collections::LinkedList; use std::marker::PhantomData; @@ -304,44 +303,35 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> /// Builds the fragment for the given block or subclass thereof. fn build_fragment_for_block(&mut self, node: &ConcreteThreadSafeLayoutNode) -> Fragment { let specific_fragment_info = match node.type_id() { - Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLIFrameElement))) => { + Some(LayoutNodeType::Element(LayoutElementType::HTMLIFrameElement)) => { SpecificFragmentInfo::Iframe(IframeFragmentInfo::new(node)) } - Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLImageElement))) => { + Some(LayoutNodeType::Element(LayoutElementType::HTMLImageElement)) => { let image_info = box ImageFragmentInfo::new(node, node.image_url(), &self.layout_context); SpecificFragmentInfo::Image(image_info) } - Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLObjectElement))) => { + Some(LayoutNodeType::Element(LayoutElementType::HTMLObjectElement)) => { let image_info = box ImageFragmentInfo::new(node, node.object_data(), &self.layout_context); SpecificFragmentInfo::Image(image_info) } - Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLTableElement))) => { + Some(LayoutNodeType::Element(LayoutElementType::HTMLTableElement)) => { SpecificFragmentInfo::TableWrapper } - Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLTableColElement))) => { + Some(LayoutNodeType::Element(LayoutElementType::HTMLTableColElement)) => { SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node)) } - Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLTableCellElement(_)))) => { + Some(LayoutNodeType::Element(LayoutElementType::HTMLTableCellElement)) => { SpecificFragmentInfo::TableCell } - Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLTableRowElement))) | - Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLTableSectionElement))) => { + Some(LayoutNodeType::Element(LayoutElementType::HTMLTableRowElement)) | + Some(LayoutNodeType::Element(LayoutElementType::HTMLTableSectionElement)) => { SpecificFragmentInfo::TableRow } - Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLCanvasElement))) => { + Some(LayoutNodeType::Element(LayoutElementType::HTMLCanvasElement)) => { let data = node.canvas_data().unwrap(); SpecificFragmentInfo::Canvas(box CanvasFragmentInfo::new(node, data, self.layout_context)) } @@ -690,16 +680,13 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> -> ConstructionResult { let mut initial_fragments = IntermediateInlineFragments::new(); let node_is_input_or_text_area = - node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLInputElement))) || - node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLTextAreaElement))); + node.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLInputElement)) || + node.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLTextAreaElement)); if node.get_pseudo_element_type().is_replaced_content() || node_is_input_or_text_area { // A TextArea's text contents are displayed through the input text // box, so don't construct them. - if node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLTextAreaElement))) { + if node.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLTextAreaElement)) { for kid in node.children() { self.set_flow_construction_result(&kid, ConstructionResult::None) } @@ -971,7 +958,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> // fragment that needs to be generated for this inline node. let mut fragments = IntermediateInlineFragments::new(); 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) } (PseudoElementType::Normal, _) => { @@ -1525,7 +1512,7 @@ impl<'a, ConcreteThreadSafeLayoutNode> PostorderNodeMutTraversal { + Some(LayoutNodeType::Element(_)) => { let style = node.style(self.style_context()); let original_display = style.get_box()._servo_display_for_hypothetical_box; let munged_display = match original_display { @@ -1534,13 +1521,13 @@ impl<'a, ConcreteThreadSafeLayoutNode> PostorderNodeMutTraversal + Some(LayoutNodeType::Text) => (display::T::inline, float::T::none, position::T::static_), - Some(NodeTypeId::CharacterData(CharacterDataTypeId::Comment)) | - Some(NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)) | - Some(NodeTypeId::DocumentType) | - Some(NodeTypeId::DocumentFragment) | - Some(NodeTypeId::Document(_)) => { + Some(LayoutNodeType::Comment) | + Some(LayoutNodeType::ProcessingInstruction) | + Some(LayoutNodeType::DocumentType) | + Some(LayoutNodeType::DocumentFragment) | + Some(LayoutNodeType::Document) => { (display::T::none, float::T::none, position::T::static_) } }; @@ -1679,19 +1666,17 @@ impl NodeUtils for ConcreteThreadSafeLayoutNode where ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode { fn is_replaced_content(&self) -> bool { match self.type_id() { - Some(NodeTypeId::CharacterData(_)) | - Some(NodeTypeId::DocumentType) | - Some(NodeTypeId::DocumentFragment) | - Some(NodeTypeId::Document(_)) | - Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLImageElement))) | - Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLIFrameElement))) | - Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLCanvasElement))) => true, - Some(NodeTypeId::Element(ElementTypeId::HTMLElement( - HTMLElementTypeId::HTMLObjectElement))) => self.has_object_data(), - Some(NodeTypeId::Element(_)) => false, + Some(LayoutNodeType::Comment) | + Some(LayoutNodeType::ProcessingInstruction) | + Some(LayoutNodeType::Text) | + Some(LayoutNodeType::DocumentType) | + Some(LayoutNodeType::DocumentFragment) | + Some(LayoutNodeType::Document) | + Some(LayoutNodeType::Element(LayoutElementType::HTMLImageElement)) | + Some(LayoutNodeType::Element(LayoutElementType::HTMLIFrameElement)) | + Some(LayoutNodeType::Element(LayoutElementType::HTMLCanvasElement)) => true, + Some(LayoutNodeType::Element(LayoutElementType::HTMLObjectElement)) => self.has_object_data(), + Some(LayoutNodeType::Element(_)) => false, None => self.get_pseudo_element_type().is_replaced_content(), } } diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index ce4fe30c075..d8a61bb2a27 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -44,6 +44,7 @@ use script::layout_interface::{HTMLCanvasData, HTMLElementTypeId, LayoutCharacte use script::layout_interface::{LayoutDocumentHelpers, LayoutElementHelpers, LayoutJS}; use script::layout_interface::{LayoutNodeHelpers, Node, NodeTypeId}; use script::layout_interface::{RawLayoutElementHelpers, Text, TrustedNodeAddress}; +use script_layout_interface::LayoutNodeType; use script_layout_interface::restyle_damage::RestyleDamage; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData}; use selectors::matching::{DeclarationBlock, ElementFlags}; @@ -77,7 +78,7 @@ pub trait LayoutNode: TNode { fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode; /// Returns the type ID of this node. - fn type_id(&self) -> NodeTypeId; + fn type_id(&self) -> LayoutNodeType; fn get_style_data(&self) -> Option<&RefCell>; @@ -130,6 +131,12 @@ impl<'ln> ServoLayoutNode<'ln> { chain: self.chain, } } + + fn script_type_id(&self) -> NodeTypeId { + unsafe { + self.node.type_id_for_layout() + } + } } impl<'ln> TNode for ServoLayoutNode<'ln> { @@ -151,7 +158,7 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { } fn is_text_node(&self) -> bool { - self.type_id() == NodeTypeId::CharacterData(CharacterDataTypeId::Text) + self.script_type_id() == NodeTypeId::CharacterData(CharacterDataTypeId::Text) } fn is_element(&self) -> bool { @@ -288,10 +295,8 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> { ServoThreadSafeLayoutNode::new(self) } - fn type_id(&self) -> NodeTypeId { - unsafe { - self.node.type_id_for_layout() - } + fn type_id(&self) -> LayoutNodeType { + self.script_type_id().into() } fn get_style_data(&self) -> Option<&RefCell> { @@ -375,7 +380,7 @@ impl<'ln> ServoLayoutNode<'ln> { fn debug_str(self) -> String { format!("{:?}: changed={} dirty={} dirty_descendants={}", - self.type_id(), self.has_changed(), self.is_dirty(), self.has_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 @@ -526,7 +531,7 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { match self.as_node().parent_node() { None => false, Some(node) => { - match node.type_id() { + match node.script_type_id() { NodeTypeId::Document(_) => true, _ => false } @@ -535,7 +540,7 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { } fn is_empty(&self) -> bool { - self.as_node().children().all(|node| match node.type_id() { + 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() @@ -559,7 +564,7 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { // https://github.com/servo/servo/issues/8718 NonTSPseudoClass::Link | NonTSPseudoClass::AnyLink => unsafe { - match self.as_node().type_id() { + 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)) | @@ -708,16 +713,16 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { /// Returns the type ID of this node. /// Returns `None` if this is a pseudo-element; otherwise, returns `Some`. - fn type_id(&self) -> Option; + fn type_id(&self) -> Option; /// Returns the type ID of this node, without discarding pseudo-elements as /// `type_id` does. - fn type_id_without_excluding_pseudo_elements(&self) -> NodeTypeId; + 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() { - NodeTypeId::Element(..) => true, + LayoutNodeType::Element(..) => true, _ => false, } } @@ -728,7 +733,7 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { fn children(&self) -> Self::ChildrenIterator; #[inline] - fn is_element(&self) -> bool { if let Some(NodeTypeId::Element(_)) = self.type_id() { true } else { false } } + 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] @@ -909,7 +914,7 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { /// `empty_cells` per CSS 2.1 § 17.6.1.1. fn is_content(&self) -> bool { match self.type_id() { - Some(NodeTypeId::Element(..)) | Some(NodeTypeId::CharacterData(CharacterDataTypeId::Text)) => true, + Some(LayoutNodeType::Element(..)) | Some(LayoutNodeType::Text) => true, _ => false } } @@ -1075,7 +1080,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { OpaqueNodeMethods::from_jsmanaged(unsafe { self.get_jsmanaged() }) } - fn type_id(&self) -> Option { + fn type_id(&self) -> Option { if self.pseudo != PseudoElementType::Normal { return None } @@ -1084,7 +1089,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { } #[inline] - fn type_id_without_excluding_pseudo_elements(&self) -> NodeTypeId { + fn type_id_without_excluding_pseudo_elements(&self) -> LayoutNodeType { self.node.type_id() } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index a6834d487d4..b803f41766c 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -21,8 +21,8 @@ use dom::bindings::codegen::UnionTypes::NodeOrString; use dom::bindings::conversions::{self, DerivedFrom}; use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::global::GlobalRef; -use dom::bindings::inheritance::{Castable, CharacterDataTypeId}; -use dom::bindings::inheritance::{EventTargetTypeId, NodeTypeId}; +use dom::bindings::inheritance::{Castable, CharacterDataTypeId, ElementTypeId}; +use dom::bindings::inheritance::{EventTargetTypeId, HTMLElementTypeId, NodeTypeId}; use dom::bindings::js::Root; use dom::bindings::js::RootedReference; use dom::bindings::js::{JS, LayoutJS, MutNullableHeap}; @@ -62,6 +62,7 @@ use msg::constellation_msg::PipelineId; use parse::html::parse_html_fragment; use ref_slice::ref_slice; use script_layout_interface::OpaqueStyleAndLayoutData; +use script_layout_interface::{LayoutNodeType, LayoutElementType}; use script_traits::UntrustedNodeAddress; use selectors::matching::matches; use selectors::parser::Selector; @@ -2634,3 +2635,56 @@ impl UniqueId { } } } + +impl Into 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 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, + } + } +} diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index 7c1a4e28e29..0b3e1bce3e6 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -42,3 +42,30 @@ pub struct OpaqueStyleAndLayoutData { #[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, +} From 000e2de57a7b458900778e4528025482f88a269d Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 14:05:05 +0100 Subject: [PATCH 16/30] Move HTMLCanvasData to script_layout_interface. --- components/layout/fragment.rs | 2 +- components/layout/wrapper.rs | 4 ++-- components/script/dom/htmlcanvaselement.rs | 7 +------ components/script/dom/node.rs | 4 ++-- components/script/layout_interface.rs | 1 - components/script_layout_interface/Cargo.toml | 2 ++ components/script_layout_interface/lib.rs | 10 ++++++++++ components/servo/Cargo.lock | 2 ++ ports/cef/Cargo.lock | 2 ++ 9 files changed, 22 insertions(+), 12 deletions(-) diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 9aa7cf43338..42fab6a7b8c 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -29,7 +29,7 @@ use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder}; use range::*; 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 std::borrow::ToOwned; use std::cmp::{max, min}; diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index d8a61bb2a27..f96020e287e 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -40,12 +40,12 @@ use opaque_node::OpaqueNodeMethods; use range::Range; use script::layout_interface::{CAN_BE_FRAGMENTED, HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY}; use script::layout_interface::{CharacterDataTypeId, Document, Element, ElementTypeId}; -use script::layout_interface::{HTMLCanvasData, HTMLElementTypeId, LayoutCharacterDataHelpers}; +use script::layout_interface::{HTMLElementTypeId, LayoutCharacterDataHelpers}; use script::layout_interface::{LayoutDocumentHelpers, LayoutElementHelpers, LayoutJS}; use script::layout_interface::{LayoutNodeHelpers, Node, NodeTypeId}; use script::layout_interface::{RawLayoutElementHelpers, Text, TrustedNodeAddress}; -use script_layout_interface::LayoutNodeType; use script_layout_interface::restyle_damage::RestyleDamage; +use script_layout_interface::{HTMLCanvasData, LayoutNodeType}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData}; use selectors::matching::{DeclarationBlock, ElementFlags}; use selectors::parser::{AttrSelector, NamespaceConstraint}; diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 95073d49cd3..add54917e6d 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -30,6 +30,7 @@ use ipc_channel::ipc::{self, IpcSender}; use js::jsapi::{HandleValue, JSContext}; use offscreen_gl_context::GLContextAttributes; use rustc_serialize::base64::{STANDARD, ToBase64}; +use script_layout_interface::HTMLCanvasData; use std::iter::repeat; use string_cache::Atom; use style::attr::AttrValue; @@ -92,12 +93,6 @@ impl HTMLCanvasElement { } } -pub struct HTMLCanvasData { - pub ipc_renderer: Option>, - pub width: u32, - pub height: u32, -} - pub trait LayoutHTMLCanvasElementHelpers { fn data(&self) -> HTMLCanvasData; } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index b803f41766c..f73abf1bd17 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -37,7 +37,7 @@ use dom::documenttype::DocumentType; use dom::element::{Element, ElementCreator}; use dom::eventtarget::EventTarget; use dom::htmlbodyelement::HTMLBodyElement; -use dom::htmlcanvaselement::{LayoutHTMLCanvasElementHelpers, HTMLCanvasData}; +use dom::htmlcanvaselement::LayoutHTMLCanvasElementHelpers; use dom::htmlcollection::HTMLCollection; use dom::htmlelement::HTMLElement; use dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods}; @@ -61,7 +61,7 @@ use libc::{self, c_void, uintptr_t}; use msg::constellation_msg::PipelineId; use parse::html::parse_html_fragment; use ref_slice::ref_slice; -use script_layout_interface::OpaqueStyleAndLayoutData; +use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData}; use script_layout_interface::{LayoutNodeType, LayoutElementType}; use script_traits::UntrustedNodeAddress; use selectors::matching::matches; diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index ae68cc0ec55..a7018507828 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -33,7 +33,6 @@ 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; diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index cbc36fa02c4..32ff5c4dd2a 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -10,7 +10,9 @@ path = "lib.rs" [dependencies] bitflags = "0.7" +canvas_traits = {path = "../canvas_traits"} heapsize = "0.3.0" heapsize_plugin = "0.1.2" +ipc-channel = {git = "https://github.com/servo/ipc-channel"} plugins = {path = "../plugins"} style = {path = "../style"} diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index 0b3e1bce3e6..e7fa1e3ae6c 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -17,13 +17,17 @@ #[allow(unused_extern_crates)] #[macro_use] extern crate bitflags; +extern crate canvas_traits; extern crate core; extern crate heapsize; +extern crate ipc_channel; extern crate style; pub mod restyle_damage; +use canvas_traits::CanvasMsg; use core::nonzero::NonZero; +use ipc_channel::ipc::IpcSender; use restyle_damage::RestyleDamage; use std::cell::RefCell; use style::servo::PrivateStyleData; @@ -69,3 +73,9 @@ pub enum LayoutElementType { HTMLTableSectionElement, HTMLTextAreaElement, } + +pub struct HTMLCanvasData { + pub ipc_renderer: Option>, + pub width: u32, + pub height: u32, +} diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 5636de1687b..12e003e0177 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1931,8 +1931,10 @@ name = "script_layout_interface" version = "0.0.1" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "canvas_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)", "plugins 0.0.1", "style 0.0.1", ] diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 8467c3bd56d..60c7a11a4a6 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -1789,8 +1789,10 @@ name = "script_layout_interface" version = "0.0.1" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "canvas_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)", "plugins 0.0.1", "style 0.0.1", ] From 0d0b268138674598e4c9c6e979b9245cfbc795d6 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 15:04:04 +0100 Subject: [PATCH 17/30] Move LayoutNode and related traits to script_layout_interface. --- components/layout/construct.rs | 4 +- components/layout/flow.rs | 2 +- components/layout/fragment.rs | 2 +- components/layout/generated_content.rs | 2 +- components/layout/inline.rs | 2 +- components/layout/layout_thread.rs | 3 +- components/layout/query.rs | 3 +- components/layout/table_cell.rs | 2 +- components/layout/traversal.rs | 4 +- components/layout/wrapper.rs | 351 +---------------- components/script_layout_interface/Cargo.toml | 6 + components/script_layout_interface/lib.rs | 8 + .../script_layout_interface/wrapper_traits.rs | 366 ++++++++++++++++++ components/servo/Cargo.lock | 6 + ports/cef/Cargo.lock | 6 + 15 files changed, 408 insertions(+), 359 deletions(-) create mode 100644 components/script_layout_interface/wrapper_traits.rs diff --git a/components/layout/construct.rs b/components/layout/construct.rs index c600b0ce8e6..27c6f629ca6 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -35,6 +35,7 @@ use multicol::{MulticolFlow, MulticolColumnFlow}; use parallel; use script::layout_interface::is_image_data; use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, RECONSTRUCT_FLOW, RestyleDamage}; +use script_layout_interface::wrapper_traits::{ThreadSafeLayoutNode, PseudoElementType, ThreadSafeLayoutElement}; use script_layout_interface::{LayoutNodeType, LayoutElementType}; use std::borrow::ToOwned; use std::collections::LinkedList; @@ -59,8 +60,7 @@ use traversal::PostorderNodeMutTraversal; use url::Url; use util::linked_list; use util::opts; -use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutElement}; -use wrapper::{ThreadSafeLayoutNode, ThreadSafeLayoutNodeHelpers}; +use wrapper::{TextContent, ThreadSafeLayoutNodeHelpers}; /// The results of flow construction for a DOM node. #[derive(Clone)] diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 79aa1daaaa5..3dc7fac29dc 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -42,6 +42,7 @@ use multicol::MulticolFlow; use parallel::FlowParallelInfo; 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::slice::IterMut; use std::sync::Arc; @@ -60,7 +61,6 @@ use table_row::TableRowFlow; use table_rowgroup::TableRowGroupFlow; use table_wrapper::TableWrapperFlow; use util::print_tree::PrintTree; -use wrapper::{PseudoElementType, ThreadSafeLayoutNode}; /// Virtual methods that make up a float context. /// diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 42fab6a7b8c..28d88e48da3 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -31,6 +31,7 @@ use range::*; use rustc_serialize::{Encodable, Encoder}; 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::cmp::{max, min}; use std::collections::LinkedList; @@ -49,7 +50,6 @@ use text; use text::TextRunScanner; use url::Url; use util; -use wrapper::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; /// 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 diff --git a/components/layout/generated_content.rs b/components/layout/generated_content.rs index b6264859faa..33a1d21f0d1 100644 --- a/components/layout/generated_content.rs +++ b/components/layout/generated_content.rs @@ -14,6 +14,7 @@ use flow::{self, AFFECTS_COUNTERS, Flow, HAS_COUNTER_AFFECTING_CHILDREN, Immutab use fragment::{Fragment, GeneratedContentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo}; use gfx::display_list::OpaqueNode; use script_layout_interface::restyle_damage::{RESOLVE_GENERATED_CONTENT, RestyleDamage}; +use script_layout_interface::wrapper_traits::PseudoElementType; use smallvec::SmallVec; use std::collections::{HashMap, LinkedList}; use std::sync::Arc; @@ -22,7 +23,6 @@ use style::computed_values::{display, list_style_type}; use style::dom::TRestyleDamage; use style::properties::{ComputedValues, ServoComputedValues}; use text::TextRunScanner; -use wrapper::PseudoElementType; // Decimal styles per CSS-COUNTER-STYLES § 6.1: static DECIMAL: [char; 10] = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ]; diff --git a/components/layout/inline.rs b/components/layout/inline.rs index e0e390557db..2b366acedac 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -26,6 +26,7 @@ use model::IntrinsicISizesContribution; 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::collections::VecDeque; use std::sync::Arc; @@ -39,7 +40,6 @@ use text; use unicode_bidi; use util; use util::print_tree::PrintTree; -use wrapper::PseudoElementType; // From gfxFontConstants.h in Firefox static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20; diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index d72653dc634..0493bf9b32e 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -50,6 +50,7 @@ use script::layout_interface::{LayoutRPC, OffsetParentResponse, NodeOverflowResp use script::layout_interface::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow}; use script::reporter::CSSErrorReporter; use script_layout_interface::restyle_damage::{REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW, REFLOW}; +use script_layout_interface::wrapper_traits::LayoutNode; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData}; use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg}; use script_traits::{StackingContextScrollState, UntrustedNodeAddress}; @@ -85,7 +86,7 @@ use util::thread_state; use util::workqueue::WorkQueue; use webrender_helpers::{WebRenderDisplayListConverter, WebRenderFrameBuilder}; use webrender_traits; -use wrapper::{LayoutNode, LayoutNodeLayoutData, NonOpaqueStyleAndLayoutData, ServoLayoutNode}; +use wrapper::{LayoutNodeLayoutData, NonOpaqueStyleAndLayoutData, ServoLayoutNode}; /// 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; diff --git a/components/layout/query.rs b/components/layout/query.rs index 728cf75e7a9..89b03457175 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -19,6 +19,7 @@ use opaque_node::OpaqueNodeMethods; use script::layout_interface::{ContentBoxResponse, NodeOverflowResponse, ContentBoxesResponse, NodeGeometryResponse}; use script::layout_interface::{HitTestResponse, LayoutRPC, OffsetParentResponse, NodeLayerIdResponse}; use script::layout_interface::{ResolvedStyleResponse, MarginStyleResponse}; +use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode}; use script_traits::LayoutMsg as ConstellationMsg; use script_traits::UntrustedNodeAddress; use sequential; @@ -34,7 +35,7 @@ use style::properties::style_structs; use style::selector_impl::PseudoElement; use style::values::AuExtensionMethods; use style_traits::cursor::Cursor; -use wrapper::{LayoutNode, ThreadSafeLayoutNode, ThreadSafeLayoutNodeHelpers}; +use wrapper::ThreadSafeLayoutNodeHelpers; pub struct LayoutRPCImpl(pub Arc>); diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index 1038328b7af..4f043e351c4 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -19,6 +19,7 @@ use gfx_traits::StackingContextId; use layout_debug; use model::MaybeAuto; use script_layout_interface::restyle_damage::REFLOW; +use script_layout_interface::wrapper_traits::ThreadSafeLayoutNode; use std::fmt; use std::sync::Arc; 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_row::{CollapsedBorder, CollapsedBorderProvenance}; use util::print_tree::PrintTree; -use wrapper::ThreadSafeLayoutNode; /// A table formatting context. #[derive(RustcEncodable)] diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 27734312e1f..f7f963fdb41 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -11,6 +11,7 @@ use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal}; use flow::{PreorderFlowTraversal, self}; use gfx::display_list::OpaqueNode; 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 style::context::StyleContext; use style::matching::MatchMethods; @@ -18,8 +19,7 @@ use style::traversal::{DomTraversalContext, STYLE_BLOOM}; use style::traversal::{put_thread_local_bloom_filter, recalc_style_at}; use util::opts; use util::tid::tid; -use wrapper::{LayoutNode, LayoutNodeLayoutData, ServoLayoutNode}; -use wrapper::{ThreadSafeLayoutNode, ThreadSafeLayoutNodeHelpers}; +use wrapper::{LayoutNodeLayoutData, ServoLayoutNode, ThreadSafeLayoutNodeHelpers}; pub struct RecalcStyleAndConstructFlows<'lc> { context: LayoutContext<'lc>, diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index f96020e287e..4c4a77f12e9 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -34,7 +34,6 @@ use core::nonzero::NonZero; use data::{LayoutDataFlags, PrivateLayoutData}; use gfx::display_list::OpaqueNode; use gfx::text::glyph::ByteIndex; -use gfx_traits::{LayerId, LayerType}; use msg::constellation_msg::PipelineId; use opaque_node::OpaqueNodeMethods; use range::Range; @@ -45,6 +44,8 @@ use script::layout_interface::{LayoutDocumentHelpers, LayoutElementHelpers, Layo use script::layout_interface::{LayoutNodeHelpers, Node, NodeTypeId}; use script::layout_interface::{RawLayoutElementHelpers, Text, TrustedNodeAddress}; 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}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData}; use selectors::matching::{DeclarationBlock, ElementFlags}; @@ -53,7 +54,6 @@ use smallvec::VecLike; use std::cell::{Ref, RefCell, RefMut}; use std::marker::PhantomData; use std::mem::{transmute, transmute_copy}; -use std::sync::Arc; use string_cache::{Atom, BorrowedAtom, BorrowedNamespace, Namespace}; use style::attr::AttrValue; use style::computed_values::content::ContentItem; @@ -63,29 +63,13 @@ use style::element_state::*; use style::properties::{ComputedValues, ServoComputedValues}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock}; use style::restyle_hints::ElementSnapshot; -use style::selector_impl::{NonTSPseudoClass, PseudoElement, PseudoElementCascadeType, ServoSelectorImpl}; +use style::selector_impl::{NonTSPseudoClass, ServoSelectorImpl}; use style::servo::{PrivateStyleData, SharedStyleContext}; use url::Url; use util::str::is_whitespace; pub type NonOpaqueStyleAndLayoutData = *mut RefCell; -/// 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>; - - fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData); - fn get_style_and_layout_data(&self) -> Option; -} - pub trait LayoutNodeLayoutData { /// Similar to borrow_data*, but returns the full PrivateLayoutData rather /// than only the PrivateStyleData. @@ -650,313 +634,6 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { } } -#[derive(Copy, PartialEq, Clone)] -pub enum PseudoElementType { - Normal, - Before(T), - After(T), - DetailsSummary(T), - DetailsContent(T), -} - -impl PseudoElementType { - 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 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 - + ::selectors::Element; - type ChildrenIterator: Iterator + Sized; - - /// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode` - /// with a different pseudo-element type. - fn with_pseudo(&self, pseudo: PseudoElementType>) -> 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; - - /// 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>; - - #[inline] - fn get_before_pseudo(&self) -> Option { - 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 { - 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 { - 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 { - 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; - - /// 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> { - 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> { - 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> { - 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>; - - /// 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; - - fn canvas_data(&self) -> Option; - - /// 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>; -} - pub trait ThreadSafeLayoutNodeHelpers { fn flow_debug_id(self) -> usize; @@ -990,28 +667,6 @@ pub trait ThreadSafeLayoutNodeHelpers { fn text_content(&self) -> TextContent; } -// 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! -pub trait DangerousThreadSafeLayoutNode: ThreadSafeLayoutNode { - unsafe fn dangerous_first_child(&self) -> Option; - unsafe fn dangerous_next_sibling(&self) -> Option; -} - -pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + - ::selectors::Element + - PresentationalHintsSynthetizer { - type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode; - - #[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>; -} - #[derive(Copy, Clone)] pub struct ServoThreadSafeLayoutNode<'ln> { /// The wrapped node. diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index 32ff5c4dd2a..5765f4a5e90 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -11,8 +11,14 @@ path = "lib.rs" [dependencies] bitflags = "0.7" canvas_traits = {path = "../canvas_traits"} +gfx_traits = {path = "../gfx_traits"} heapsize = "0.3.0" heapsize_plugin = "0.1.2" ipc-channel = {git = "https://github.com/servo/ipc-channel"} +msg = {path = "../msg"} plugins = {path = "../plugins"} +range = {path = "../range"} +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"]} diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index e7fa1e3ae6c..8917aad6a76 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -19,11 +19,19 @@ extern crate bitflags; extern crate canvas_traits; extern crate core; +extern crate gfx_traits; extern crate heapsize; extern crate ipc_channel; +extern crate msg; +extern crate range; +extern crate selectors; +#[macro_use(atom, ns)] +extern crate string_cache; extern crate style; +extern crate url; pub mod restyle_damage; +pub mod wrapper_traits; use canvas_traits::CanvasMsg; use core::nonzero::NonZero; diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs new file mode 100644 index 00000000000..145f9dd067b --- /dev/null +++ b/components/script_layout_interface/wrapper_traits.rs @@ -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 { + Normal, + Before(T), + After(T), + DetailsSummary(T), + DetailsContent(T), +} + +impl PseudoElementType { + 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>; + + fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData); + fn get_style_and_layout_data(&self) -> Option; +} + +/// 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 + + ::selectors::Element; + type ChildrenIterator: Iterator + Sized; + + /// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode` + /// with a different pseudo-element type. + fn with_pseudo(&self, pseudo: PseudoElementType>) -> 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; + + /// 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>; + + #[inline] + fn get_before_pseudo(&self) -> Option { + 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 { + 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 { + 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 { + 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; + + /// 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> { + 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> { + 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> { + 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>; + + /// 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; + + fn canvas_data(&self) -> Option; + + /// 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>; +} + +// 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; + unsafe fn dangerous_next_sibling(&self) -> Option; +} + +pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + + ::selectors::Element + + PresentationalHintsSynthetizer { + type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode; + + #[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>; +} diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 12e003e0177..251356da56c 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1932,11 +1932,17 @@ version = "0.0.1" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "canvas_traits 0.0.1", + "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)", + "msg 0.0.1", "plugins 0.0.1", + "range 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)", ] [[package]] diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 60c7a11a4a6..1d8d416e22c 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -1790,11 +1790,17 @@ version = "0.0.1" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "canvas_traits 0.0.1", + "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)", + "msg 0.0.1", "plugins 0.0.1", + "range 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)", ] [[package]] From 14a7e9bce1bcb1c42ca051e40f569bef89a34caa Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 17:00:10 +0100 Subject: [PATCH 18/30] Remove unused OpaqueNodeMethods::from_script_node. --- components/layout/opaque_node.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/components/layout/opaque_node.rs b/components/layout/opaque_node.rs index a05a49d48e6..db80d45fe1d 100644 --- a/components/layout/opaque_node.rs +++ b/components/layout/opaque_node.rs @@ -8,13 +8,9 @@ use gfx::display_list::OpaqueNode; use libc::{c_void, uintptr_t}; use script::layout_interface::LayoutJS; use script::layout_interface::Node; -use script::layout_interface::TrustedNodeAddress; use script_traits::UntrustedNodeAddress; 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) -> Self; @@ -24,12 +20,6 @@ pub trait OpaqueNodeMethods { } 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) -> OpaqueNode { unsafe { let ptr: uintptr_t = node.get_jsobject() as uintptr_t; From 7de3d165ad7041e833f8f59187468b589a3ebf82 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 17:10:46 +0100 Subject: [PATCH 19/30] Introduce LayoutJS::opaque() to replace OpaqueNodeMethods::from_jsmanaged(). --- components/layout/opaque_node.rs | 16 +--------------- components/layout/wrapper.rs | 4 ++-- components/script/dom/node.rs | 9 +++++++++ 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/components/layout/opaque_node.rs b/components/layout/opaque_node.rs index db80d45fe1d..41a4ccd5617 100644 --- a/components/layout/opaque_node.rs +++ b/components/layout/opaque_node.rs @@ -2,31 +2,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#![allow(unsafe_code)] - use gfx::display_list::OpaqueNode; -use libc::{c_void, uintptr_t}; -use script::layout_interface::LayoutJS; -use script::layout_interface::Node; +use libc::c_void; use script_traits::UntrustedNodeAddress; pub trait OpaqueNodeMethods { - /// Converts a DOM node to an `OpaqueNode'. - fn from_jsmanaged(node: &LayoutJS) -> Self; - /// Converts this node to an `UntrustedNodeAddress`. An `UntrustedNodeAddress` is just the type /// of node that script expects to receive in a hit test. fn to_untrusted_node_address(&self) -> UntrustedNodeAddress; } impl OpaqueNodeMethods for OpaqueNode { - fn from_jsmanaged(node: &LayoutJS) -> OpaqueNode { - unsafe { - let ptr: uintptr_t = node.get_jsobject() as uintptr_t; - OpaqueNode(ptr) - } - } - fn to_untrusted_node_address(&self) -> UntrustedNodeAddress { UntrustedNodeAddress(self.0 as *const c_void) } diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 4c4a77f12e9..2be1c47a05f 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -156,7 +156,7 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { } fn opaque(&self) -> OpaqueNode { - OpaqueNodeMethods::from_jsmanaged(unsafe { self.get_jsmanaged() }) + unsafe { self.get_jsmanaged().opaque() } } fn layout_parent_node(self, reflow_root: OpaqueNode) -> Option> { @@ -732,7 +732,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { } fn opaque(&self) -> OpaqueNode { - OpaqueNodeMethods::from_jsmanaged(unsafe { self.get_jsmanaged() }) + unsafe { self.get_jsmanaged().opaque() } } fn type_id(&self) -> Option { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index f73abf1bd17..cf3257e7137 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -75,6 +75,7 @@ use std::iter::{self, FilterMap, Peekable}; use std::mem; use std::ops::Range; use string_cache::{Atom, Namespace, QualName}; +use style::dom::OpaqueNode; use style::selector_impl::ServoSelectorImpl; use url::Url; use util::thread_state; @@ -961,6 +962,7 @@ pub trait LayoutNodeHelpers { fn image_url(&self) -> Option; fn canvas_data(&self) -> Option; fn iframe_pipeline_id(&self) -> PipelineId; + fn opaque(&self) -> OpaqueNode; } impl LayoutNodeHelpers for LayoutJS { @@ -1101,6 +1103,13 @@ impl LayoutNodeHelpers for LayoutJS { .expect("not an iframe element!"); iframe_element.pipeline_id().unwrap() } + + #[allow(unsafe_code)] + fn opaque(&self) -> OpaqueNode { + unsafe { + OpaqueNode(self.get_jsobject() as usize) + } + } } From a8bb3d8d2243aac133f48c99e502a6a037c404e2 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 17:35:49 +0100 Subject: [PATCH 20/30] Make ServoLayoutNode::debug_id() less convoluted. --- components/layout/wrapper.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 2be1c47a05f..b41621da81b 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -35,7 +35,6 @@ use data::{LayoutDataFlags, PrivateLayoutData}; use gfx::display_list::OpaqueNode; use gfx::text::glyph::ByteIndex; use msg::constellation_msg::PipelineId; -use opaque_node::OpaqueNodeMethods; use range::Range; use script::layout_interface::{CAN_BE_FRAGMENTED, HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY}; use script::layout_interface::{CharacterDataTypeId, Document, Element, ElementTypeId}; @@ -168,7 +167,7 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { } fn debug_id(self) -> usize { - self.opaque().to_untrusted_node_address().0 as usize + self.opaque().0 } fn children_count(&self) -> u32 { From 0c726cfe6b38df6ec5e1653ba4a8e5d046b0850d Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 20:35:52 +0100 Subject: [PATCH 21/30] Make RecalcStyleAndConstructFlows generic over the LayoutNode implementation. --- components/layout/traversal.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index f7f963fdb41..0571f903ea4 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -14,19 +14,26 @@ use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_ use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode}; use std::mem; use style::context::StyleContext; +use style::dom::TNode; use style::matching::MatchMethods; +use style::properties::ServoComputedValues; +use style::selector_impl::ServoSelectorImpl; use style::traversal::{DomTraversalContext, STYLE_BLOOM}; use style::traversal::{put_thread_local_bloom_filter, recalc_style_at}; use util::opts; use util::tid::tid; -use wrapper::{LayoutNodeLayoutData, ServoLayoutNode, ThreadSafeLayoutNodeHelpers}; +use wrapper::{LayoutNodeLayoutData, ThreadSafeLayoutNodeHelpers}; pub struct RecalcStyleAndConstructFlows<'lc> { context: LayoutContext<'lc>, root: OpaqueNode, } -impl<'lc, 'ln> DomTraversalContext> for RecalcStyleAndConstructFlows<'lc> { +impl<'lc, N> DomTraversalContext for RecalcStyleAndConstructFlows<'lc> + where N: LayoutNode + TNode, + N::ConcreteElement: ::selectors::Element + +{ type SharedContext = SharedLayoutContext; #[allow(unsafe_code)] fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self { @@ -66,7 +73,7 @@ impl<'lc, 'ln> DomTraversalContext> 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 // parser. node.initialize_data(); @@ -74,7 +81,7 @@ impl<'lc, 'ln> DomTraversalContext> for RecalcStyleAndConst 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. From 0616a60fd96199426d04cd75467906fca243af9c Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 17:35:54 +0100 Subject: [PATCH 22/30] Move ServoLayoutNode and related structs to script. --- components/layout/wrapper.rs | 970 +-------------------------- components/script/Cargo.toml | 1 + components/script/layout_wrapper.rs | 996 ++++++++++++++++++++++++++++ components/script/lib.rs | 2 + components/servo/Cargo.lock | 1 + ports/cef/Cargo.lock | 1 + 6 files changed, 1006 insertions(+), 965 deletions(-) create mode 100644 components/script/layout_wrapper.rs diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index b41621da81b..a7949fc75b1 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -32,40 +32,13 @@ use core::nonzero::NonZero; use data::{LayoutDataFlags, PrivateLayoutData}; -use gfx::display_list::OpaqueNode; -use gfx::text::glyph::ByteIndex; -use msg::constellation_msg::PipelineId; -use range::Range; -use script::layout_interface::{CAN_BE_FRAGMENTED, HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY}; -use script::layout_interface::{CharacterDataTypeId, Document, Element, ElementTypeId}; -use script::layout_interface::{HTMLElementTypeId, LayoutCharacterDataHelpers}; -use script::layout_interface::{LayoutDocumentHelpers, LayoutElementHelpers, LayoutJS}; -use script::layout_interface::{LayoutNodeHelpers, Node, NodeTypeId}; -use script::layout_interface::{RawLayoutElementHelpers, Text, TrustedNodeAddress}; -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}; +use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode}; 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::content::ContentItem; -use style::computed_values::{content, display}; -use style::dom::{PresentationalHintsSynthetizer, 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; +use style::computed_values::content::{self, ContentItem}; +use style::properties::ComputedValues; + +pub use script::layout_wrapper::*; pub type NonOpaqueStyleAndLayoutData = *mut RefCell; @@ -79,230 +52,6 @@ pub trait LayoutNodeLayoutData { fn flow_debug_id(self) -> usize; } -#[derive(Copy, Clone)] -pub struct ServoLayoutNode<'a> { - /// The wrapped node. - node: LayoutJS, - - /// 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) -> 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) -> 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> { - 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> { - as_element(self.node) - } - - fn as_document(&self) -> Option> { - 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> { - self.get_style_data().map(|d| { - Ref::map(d.borrow(), |d| &d.style_data) - }) - } - - fn mutate_data(&self) -> Option> { - 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> { - unsafe { - self.node.parent_node_ref().map(|node| self.new_with_this_lifetime(&node)) - } - } - - fn first_child(&self) -> Option> { - unsafe { - self.node.first_child_ref().map(|node| self.new_with_this_lifetime(&node)) - } - } - - fn last_child(&self) -> Option> { - unsafe { - self.node.last_child_ref().map(|node| self.new_with_this_lifetime(&node)) - } - } - - fn prev_sibling(&self) -> Option> { - unsafe { - self.node.prev_sibling_ref().map(|node| self.new_with_this_lifetime(&node)) - } - } - - fn next_sibling(&self) -> Option> { - 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> { - 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 { - unsafe { - self.get_jsmanaged().get_style_and_layout_data() - } - } -} - impl LayoutNodeLayoutData for T { unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData> { self.get_style_and_layout_data().map(|opaque| { @@ -345,294 +94,6 @@ impl LayoutNodeLayoutData for T { } } - -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 { - &self.node - } -} - -// A wrapper around documents that ensures ayout can only ever access safe properties. -#[derive(Copy, Clone)] -pub struct ServoLayoutDocument<'ld> { - document: LayoutJS, - 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> { - 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) -> 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, - chain: PhantomData<&'le ()>, -} - -impl<'le> PresentationalHintsSynthetizer for ServoLayoutElement<'le> { - fn synthesize_presentational_hints_for_legacy_attributes(&self, hints: &mut V) - where V: VecLike>> - { - 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 { - 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) -> ServoLayoutElement<'le> { - ServoLayoutElement { - element: el, - chain: PhantomData, - } - } -} - -fn as_element<'le>(node: LayoutJS) -> Option> { - node.downcast().map(ServoLayoutElement::from_layout_js) -} - -impl<'le> ::selectors::Element for ServoLayoutElement<'le> { - type Impl = ServoSelectorImpl; - - fn parent_element(&self) -> Option> { - unsafe { - self.element.upcast().parent_node_ref().and_then(as_element) - } - } - - fn first_child_element(&self) -> Option> { - self.as_node().children().filter_map(|n| n.as_element()).next() - } - - fn last_child_element(&self) -> Option> { - self.as_node().rev_children().filter_map(|n| n.as_element()).next() - } - - fn prev_sibling_element(&self) -> Option> { - 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> { - 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 { - 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(&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(&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); - } -} - pub trait ThreadSafeLayoutNodeHelpers { fn flow_debug_id(self) -> usize; @@ -666,190 +127,6 @@ pub trait ThreadSafeLayoutNodeHelpers { fn text_content(&self) -> TextContent; } -#[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>, -} - -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.get_jsmanaged().first_child_ref() - .map(|node| self.new_with_this_lifetime(&node)) - } - unsafe fn dangerous_next_sibling(&self) -> Option { - 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) -> 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 { - self.node.get_jsmanaged() - } -} - -impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { - type ConcreteThreadSafeLayoutElement = ServoThreadSafeLayoutElement<'ln>; - type ChildrenIterator = ThreadSafeLayoutNodeChildrenIterator; - - fn with_pseudo(&self, - pseudo: PseudoElementType>) -> ServoThreadSafeLayoutNode<'ln> { - ServoThreadSafeLayoutNode { - node: self.node.clone(), - pseudo: pseudo, - } - } - - fn opaque(&self) -> OpaqueNode { - unsafe { self.get_jsmanaged().opaque() } - } - - fn type_id(&self) -> Option { - 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> { - self.pseudo - } - - fn get_style_and_layout_data(&self) -> Option { - self.node.get_style_and_layout_data() - } - - fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool { - unsafe { - let text: LayoutJS = 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> { - 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 { - let this = unsafe { self.get_jsmanaged() }; - this.image_url() - } - - fn canvas_data(&self) -> Option { - 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::().unwrap().get_colspan() - } - } - - fn get_style_data(&self) -> Option<&RefCell> { - self.node.get_style_data() - } -} - impl ThreadSafeLayoutNodeHelpers for T { fn flow_debug_id(self) -> usize { self.borrow_layout_data().map_or(0, |d| d.flow_construction_result.debug_id()) @@ -910,133 +187,6 @@ impl ThreadSafeLayoutNodeHelpers for T { } } -pub struct ThreadSafeLayoutNodeChildrenIterator { - current_node: Option, - parent_node: ConcreteNode, -} - -impl ThreadSafeLayoutNodeChildrenIterator - where ConcreteNode: DangerousThreadSafeLayoutNode { - pub fn new(parent: ConcreteNode) -> Self { - let first_child: Option = 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 Iterator for ThreadSafeLayoutNodeChildrenIterator - where ConcreteNode: DangerousThreadSafeLayoutNode { - type Item = ConcreteNode; - fn next(&mut self) -> Option { - 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()) - } -} - pub enum TextContent { Text(String), GeneratedContent(Vec), @@ -1050,113 +200,3 @@ impl TextContent { } } } - -/// 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 { - warn!("ServoThreadSafeLayoutElement::parent_element called"); - None - } - - fn first_child_element(&self) -> Option { - warn!("ServoThreadSafeLayoutElement::first_child_element called"); - None - } - - // Skips non-element nodes - fn last_child_element(&self) -> Option { - warn!("ServoThreadSafeLayoutElement::last_child_element called"); - None - } - - // Skips non-element nodes - fn prev_sibling_element(&self) -> Option { - warn!("ServoThreadSafeLayoutElement::prev_sibling_element called"); - None - } - - // Skips non-element nodes - fn next_sibling_element(&self) -> Option { - 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 { - debug!("ServoThreadSafeLayoutElement::get_id called"); - None - } - - fn has_class(&self, _name: &Atom) -> bool { - debug!("ServoThreadSafeLayoutElement::has_class called"); - false - } - - fn match_attr(&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(&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(&self, _hints: &mut V) - where V: VecLike>> {} -} diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index bbb086a308d..fc1911288d9 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -48,6 +48,7 @@ phf_macros = "0.7.13" plugins = {path = "../plugins"} profile_traits = {path = "../profile_traits"} rand = "0.3" +range = {path = "../range"} ref_filter_map = "1.0" ref_slice = "1.0" regex = "0.1.43" diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs new file mode 100644 index 00000000000..405e31005af --- /dev/null +++ b/components/script/layout_wrapper.rs @@ -0,0 +1,996 @@ +/* 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 gfx_traits::ByteIndex; +use layout_interface::{CAN_BE_FRAGMENTED, HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY}; +use layout_interface::{CharacterDataTypeId, Document, Element, ElementTypeId}; +use layout_interface::{HTMLElementTypeId, LayoutCharacterDataHelpers}; +use layout_interface::{LayoutDocumentHelpers, LayoutElementHelpers, LayoutJS}; +use layout_interface::{LayoutNodeHelpers, Node, NodeTypeId}; +use layout_interface::{RawLayoutElementHelpers, Text, TrustedNodeAddress}; +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}; +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, + + /// 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) -> 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) -> 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> { + 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> { + as_element(self.node) + } + + fn as_document(&self) -> Option> { + 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> { + self.get_style_data().map(|d| { + Ref::map(d.borrow(), |d| &d.style_data) + }) + } + + fn mutate_data(&self) -> Option> { + 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> { + unsafe { + self.node.parent_node_ref().map(|node| self.new_with_this_lifetime(&node)) + } + } + + fn first_child(&self) -> Option> { + unsafe { + self.node.first_child_ref().map(|node| self.new_with_this_lifetime(&node)) + } + } + + fn last_child(&self) -> Option> { + unsafe { + self.node.last_child_ref().map(|node| self.new_with_this_lifetime(&node)) + } + } + + fn prev_sibling(&self) -> Option> { + unsafe { + self.node.prev_sibling_ref().map(|node| self.new_with_this_lifetime(&node)) + } + } + + fn next_sibling(&self) -> Option> { + 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> { + 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 { + 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 { + &self.node + } +} + +// A wrapper around documents that ensures ayout can only ever access safe properties. +#[derive(Copy, Clone)] +pub struct ServoLayoutDocument<'ld> { + document: LayoutJS, + 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> { + 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) -> 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, + chain: PhantomData<&'le ()>, +} + +impl<'le> PresentationalHintsSynthetizer for ServoLayoutElement<'le> { + fn synthesize_presentational_hints_for_legacy_attributes(&self, hints: &mut V) + where V: VecLike>> + { + 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 { + 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) -> ServoLayoutElement<'le> { + ServoLayoutElement { + element: el, + chain: PhantomData, + } + } +} + +fn as_element<'le>(node: LayoutJS) -> Option> { + node.downcast().map(ServoLayoutElement::from_layout_js) +} + +impl<'le> ::selectors::Element for ServoLayoutElement<'le> { + type Impl = ServoSelectorImpl; + + fn parent_element(&self) -> Option> { + unsafe { + self.element.upcast().parent_node_ref().and_then(as_element) + } + } + + fn first_child_element(&self) -> Option> { + self.as_node().children().filter_map(|n| n.as_element()).next() + } + + fn last_child_element(&self) -> Option> { + self.as_node().rev_children().filter_map(|n| n.as_element()).next() + } + + fn prev_sibling_element(&self) -> Option> { + 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> { + 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 { + 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(&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(&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>, +} + +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.get_jsmanaged().first_child_ref() + .map(|node| self.new_with_this_lifetime(&node)) + } + unsafe fn dangerous_next_sibling(&self) -> Option { + 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) -> 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 { + self.node.get_jsmanaged() + } +} + +impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { + type ConcreteThreadSafeLayoutElement = ServoThreadSafeLayoutElement<'ln>; + type ChildrenIterator = ThreadSafeLayoutNodeChildrenIterator; + + fn with_pseudo(&self, + pseudo: PseudoElementType>) -> ServoThreadSafeLayoutNode<'ln> { + ServoThreadSafeLayoutNode { + node: self.node.clone(), + pseudo: pseudo, + } + } + + fn opaque(&self) -> OpaqueNode { + unsafe { self.get_jsmanaged().opaque() } + } + + fn type_id(&self) -> Option { + 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> { + self.pseudo + } + + fn get_style_and_layout_data(&self) -> Option { + self.node.get_style_and_layout_data() + } + + fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool { + unsafe { + let text: LayoutJS = 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> { + 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 { + let this = unsafe { self.get_jsmanaged() }; + this.image_url() + } + + fn canvas_data(&self) -> Option { + 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::().unwrap().get_colspan() + } + } + + fn get_style_data(&self) -> Option<&RefCell> { + self.node.get_style_data() + } +} + +pub struct ThreadSafeLayoutNodeChildrenIterator { + current_node: Option, + parent_node: ConcreteNode, +} + +impl ThreadSafeLayoutNodeChildrenIterator + where ConcreteNode: DangerousThreadSafeLayoutNode { + pub fn new(parent: ConcreteNode) -> Self { + let first_child: Option = 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 Iterator for ThreadSafeLayoutNodeChildrenIterator + where ConcreteNode: DangerousThreadSafeLayoutNode { + type Item = ConcreteNode; + fn next(&mut self) -> Option { + 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 { + warn!("ServoThreadSafeLayoutElement::parent_element called"); + None + } + + fn first_child_element(&self) -> Option { + warn!("ServoThreadSafeLayoutElement::first_child_element called"); + None + } + + // Skips non-element nodes + fn last_child_element(&self) -> Option { + warn!("ServoThreadSafeLayoutElement::last_child_element called"); + None + } + + // Skips non-element nodes + fn prev_sibling_element(&self) -> Option { + warn!("ServoThreadSafeLayoutElement::prev_sibling_element called"); + None + } + + // Skips non-element nodes + fn next_sibling_element(&self) -> Option { + 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 { + debug!("ServoThreadSafeLayoutElement::get_id called"); + None + } + + fn has_class(&self, _name: &Atom) -> bool { + debug!("ServoThreadSafeLayoutElement::has_class called"); + false + } + + fn match_attr(&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(&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(&self, _hints: &mut V) + where V: VecLike>> {} +} diff --git a/components/script/lib.rs b/components/script/lib.rs index a47d549cc31..c191c203889 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -64,6 +64,7 @@ extern crate phf; #[macro_use] extern crate profile_traits; extern crate rand; +extern crate range; extern crate ref_filter_map; extern crate ref_slice; extern crate regex; @@ -94,6 +95,7 @@ pub mod document_loader; #[macro_use] pub mod dom; pub mod layout_interface; +pub mod layout_wrapper; mod mem; mod network_listener; pub mod origin; diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 251356da56c..908b46a123f 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1905,6 +1905,7 @@ dependencies = [ "plugins 0.0.1", "profile_traits 0.0.1", "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_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)", diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 1d8d416e22c..7052457476a 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -1763,6 +1763,7 @@ dependencies = [ "plugins 0.0.1", "profile_traits 0.0.1", "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_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)", From 68d603a6d0a059965d2fa604d153b531cb16d404 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Thu, 16 Jun 2016 00:51:23 +0100 Subject: [PATCH 23/30] Move TrustedNodeAddress to script_layout_interface. --- components/script/dom/bindings/js.rs | 2 +- components/script/dom/node.rs | 13 +------------ components/script/dom/window.rs | 3 ++- components/script/layout_interface.rs | 3 +-- components/script/layout_wrapper.rs | 4 ++-- components/script_layout_interface/Cargo.toml | 1 + components/script_layout_interface/lib.rs | 9 +++++++++ components/servo/Cargo.lock | 1 + ports/cef/Cargo.lock | 1 + 9 files changed, 19 insertions(+), 18 deletions(-) diff --git a/components/script/dom/bindings/js.rs b/components/script/dom/bindings/js.rs index f8ddb80e44b..12ff0aa8823 100644 --- a/components/script/dom/bindings/js.rs +++ b/components/script/dom/bindings/js.rs @@ -33,7 +33,7 @@ use dom::node::Node; use heapsize::HeapSizeOf; use js::jsapi::{Heap, JSObject, JSTracer}; use js::jsval::JSVal; -use layout_interface::TrustedNodeAddress; +use script_layout_interface::TrustedNodeAddress; use script_thread::STACK_ROOTS; use std::cell::UnsafeCell; use std::default::Default; diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index cf3257e7137..fdb9deed87b 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -62,7 +62,7 @@ use msg::constellation_msg::PipelineId; use parse::html::parse_html_fragment; use ref_slice::ref_slice; use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData}; -use script_layout_interface::{LayoutNodeType, LayoutElementType}; +use script_layout_interface::{LayoutNodeType, LayoutElementType, TrustedNodeAddress}; use script_traits::UntrustedNodeAddress; use selectors::matching::matches; use selectors::parser::Selector; @@ -2409,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 + Reflectable>(derived: &T) -> Root { derived.upcast().owner_doc() } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 03fbe2b2a2b..f2f3195c875 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -31,7 +31,7 @@ use dom::element::Element; use dom::eventtarget::EventTarget; use dom::location::Location; 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::screen::Screen; use dom::storage::Storage; @@ -59,6 +59,7 @@ use profile_traits::time::{ProfilerCategory, TimerMetadata, TimerMetadataFrameTy use profile_traits::time::{ProfilerChan, TimerMetadataReflowType, profile}; use reporter::CSSErrorReporter; use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64}; +use script_layout_interface::TrustedNodeAddress; use script_runtime::{ScriptChan, ScriptPort}; use script_thread::SendableMainThreadScriptChan; use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, RunnableWrapper}; diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index a7018507828..cb645ef6439 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -14,7 +14,7 @@ use ipc_channel::ipc::{IpcReceiver, IpcSender}; use msg::constellation_msg::{PanicMsg, PipelineId, WindowSizeData}; use net_traits::image_cache_thread::ImageCacheThread; use profile_traits::mem::ReportsChan; -use script_layout_interface::OpaqueStyleAndLayoutData; +use script_layout_interface::{OpaqueStyleAndLayoutData, TrustedNodeAddress}; use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg}; use script_traits::{StackingContextScrollState, UntrustedNodeAddress}; use std::sync::Arc; @@ -37,7 +37,6 @@ 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::TrustedNodeAddress; pub use dom::text::Text; diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index 405e31005af..1ef916ea500 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -36,13 +36,13 @@ use layout_interface::{CharacterDataTypeId, Document, Element, ElementTypeId}; use layout_interface::{HTMLElementTypeId, LayoutCharacterDataHelpers}; use layout_interface::{LayoutDocumentHelpers, LayoutElementHelpers, LayoutJS}; use layout_interface::{LayoutNodeHelpers, Node, NodeTypeId}; -use layout_interface::{RawLayoutElementHelpers, Text, TrustedNodeAddress}; +use layout_interface::{RawLayoutElementHelpers, Text}; 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}; +use script_layout_interface::{HTMLCanvasData, LayoutNodeType, TrustedNodeAddress}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData}; use selectors::matching::{DeclarationBlock, ElementFlags}; use selectors::parser::{AttrSelector, NamespaceConstraint}; diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index 5765f4a5e90..79d0c10682c 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -15,6 +15,7 @@ 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" msg = {path = "../msg"} plugins = {path = "../plugins"} range = {path = "../range"} diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index 8917aad6a76..d9037311f6a 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -22,6 +22,7 @@ extern crate core; extern crate gfx_traits; extern crate heapsize; extern crate ipc_channel; +extern crate libc; extern crate msg; extern crate range; extern crate selectors; @@ -36,6 +37,7 @@ 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; @@ -87,3 +89,10 @@ pub struct HTMLCanvasData { 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 {} diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 908b46a123f..91cf4ddbb2f 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1937,6 +1937,7 @@ dependencies = [ "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)", "msg 0.0.1", "plugins 0.0.1", "range 0.0.1", diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 7052457476a..0c34232fb20 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -1795,6 +1795,7 @@ dependencies = [ "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)", "msg 0.0.1", "plugins 0.0.1", "range 0.0.1", From 86bfd2cc9f14b95c3b6376c6b723ddf77af3fc35 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Thu, 16 Jun 2016 02:07:57 +0100 Subject: [PATCH 24/30] Move LayoutRPC to script_layout_interface. --- components/layout/layout_thread.rs | 2 +- components/layout/query.rs | 8 +- components/script/dom/bindings/trace.rs | 2 +- components/script/dom/window.rs | 5 +- components/script/layout_interface.rs | 88 +---------------- components/script_layout_interface/Cargo.toml | 3 + components/script_layout_interface/lib.rs | 4 + components/script_layout_interface/rpc.rs | 96 +++++++++++++++++++ components/servo/Cargo.lock | 3 + ports/cef/Cargo.lock | 3 + 10 files changed, 122 insertions(+), 92 deletions(-) create mode 100644 components/script_layout_interface/rpc.rs diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index 0493bf9b32e..14179c38985 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -46,10 +46,10 @@ use query::process_offset_parent_query; 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_overflow_request, process_resolved_style_request, process_margin_style_query}; -use script::layout_interface::{LayoutRPC, OffsetParentResponse, NodeOverflowResponse, MarginStyleResponse}; use script::layout_interface::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow}; 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}; diff --git a/components/layout/query.rs b/components/layout/query.rs index 89b03457175..e558496f82d 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -16,9 +16,11 @@ use gfx::display_list::OpaqueNode; use gfx_traits::LayerId; use layout_thread::LayoutThreadData; use opaque_node::OpaqueNodeMethods; -use script::layout_interface::{ContentBoxResponse, NodeOverflowResponse, ContentBoxesResponse, NodeGeometryResponse}; -use script::layout_interface::{HitTestResponse, LayoutRPC, OffsetParentResponse, NodeLayerIdResponse}; -use script::layout_interface::{ResolvedStyleResponse, MarginStyleResponse}; +use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse}; +use script_layout_interface::rpc::{HitTestResponse, LayoutRPC}; +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::UntrustedNodeAddress; diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 070a3e1b954..4abfc8fd58d 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -55,7 +55,6 @@ use js::glue::{CallObjectTracer, CallUnbarrieredObjectTracer, CallValueTracer}; use js::jsapi::{GCTraceKindToAscii, Heap, TraceKind, JSObject, JSTracer}; use js::jsval::JSVal; use js::rust::Runtime; -use layout_interface::LayoutRPC; use libc; use msg::constellation_msg::{FrameType, PipelineId, SubpageId, WindowSizeData, WindowSizeType, ReferrerPolicy}; use net_traits::filemanager_thread::SelectedFileId; @@ -68,6 +67,7 @@ use offscreen_gl_context::GLLimits; use profile_traits::mem::ProfilerChan as MemProfilerChan; use profile_traits::time::ProfilerChan as TimeProfilerChan; use script_layout_interface::OpaqueStyleAndLayoutData; +use script_layout_interface::rpc::LayoutRPC; use script_runtime::ScriptChan; use script_traits::{TimerEventId, TimerSource, TouchpadPressurePhase, UntrustedNodeAddress}; use serde::{Deserialize, Serialize}; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index f2f3195c875..6dc43f8b925 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -42,8 +42,7 @@ use js::jsapi::{Evaluate2, HandleObject, HandleValue, JSAutoCompartment, JSConte use js::jsapi::{JS_GetRuntime, JS_GC, MutableHandleValue, SetWindowProxy}; use js::rust::CompileOptionsWrapper; use js::rust::Runtime; -use layout_interface::{ContentBoxResponse, ContentBoxesResponse, ResolvedStyleResponse, ScriptReflow}; -use layout_interface::{LayoutRPC, Msg, Reflow, ReflowQueryType, MarginStyleResponse}; +use layout_interface::{Msg, Reflow, ReflowQueryType, ScriptReflow}; use libc; use msg::constellation_msg::{FrameType, LoadData, PanicMsg, PipelineId, SubpageId}; use msg::constellation_msg::{WindowSizeData, WindowSizeType}; @@ -60,6 +59,8 @@ use profile_traits::time::{ProfilerChan, TimerMetadataReflowType, profile}; use reporter::CSSErrorReporter; use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64}; use script_layout_interface::TrustedNodeAddress; +use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC}; +use script_layout_interface::rpc::{MarginStyleResponse, ResolvedStyleResponse}; use script_runtime::{ScriptChan, ScriptPort}; use script_thread::SendableMainThreadScriptChan; use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, RunnableWrapper}; diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index cb645ef6439..3c5516e4b8d 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -14,14 +14,14 @@ use ipc_channel::ipc::{IpcReceiver, IpcSender}; use msg::constellation_msg::{PanicMsg, PipelineId, WindowSizeData}; use net_traits::image_cache_thread::ImageCacheThread; use profile_traits::mem::ReportsChan; +use script_layout_interface::rpc::LayoutRPC; use script_layout_interface::{OpaqueStyleAndLayoutData, TrustedNodeAddress}; -use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg}; -use script_traits::{StackingContextScrollState, UntrustedNodeAddress}; +use script_traits::{ConstellationControlMsg, LayoutControlMsg}; +use script_traits::{LayoutMsg as ConstellationMsg, StackingContextScrollState}; use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender}; use string_cache::Atom; 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::servo::Stylesheet; use url::Url; @@ -101,88 +101,6 @@ pub enum Msg { SetStackingContextScrollStates(Vec), } -/// 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) -> Vec; -} - -#[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>); - -pub struct ContentBoxResponse(pub Rect); -pub struct ContentBoxesResponse(pub Vec>); -pub struct HitTestResponse { - pub node_address: Option, -} -pub struct NodeGeometryResponse { - pub client_rect: Rect, -} - -pub struct NodeLayerIdResponse { - pub layer_id: LayerId, -} - -pub struct ResolvedStyleResponse(pub Option); - -#[derive(Clone)] -pub struct OffsetParentResponse { - pub node_address: Option, - pub rect: Rect, -} - -impl OffsetParentResponse { - pub fn empty() -> OffsetParentResponse { - OffsetParentResponse { - node_address: None, - rect: Rect::zero(), - } - } -} /// Any query to perform with this reflow. #[derive(PartialEq)] diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index 79d0c10682c..a4ace11ae26 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -9,8 +9,10 @@ name = "script_layout_interface" path = "lib.rs" [dependencies] +app_units = {version = "0.2.3", features = ["plugins"]} bitflags = "0.7" canvas_traits = {path = "../canvas_traits"} +euclid = {version = "0.6.4", features = ["plugins"]} gfx_traits = {path = "../gfx_traits"} heapsize = "0.3.0" heapsize_plugin = "0.1.2" @@ -19,6 +21,7 @@ libc = "0.2" msg = {path = "../msg"} 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"} diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index d9037311f6a..123792a6c6f 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -14,17 +14,20 @@ #![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 euclid; extern crate gfx_traits; extern crate heapsize; extern crate ipc_channel; extern crate libc; extern crate msg; extern crate range; +extern crate script_traits; extern crate selectors; #[macro_use(atom, ns)] extern crate string_cache; @@ -32,6 +35,7 @@ extern crate style; extern crate url; pub mod restyle_damage; +pub mod rpc; pub mod wrapper_traits; use canvas_traits::CanvasMsg; diff --git a/components/script_layout_interface/rpc.rs b/components/script_layout_interface/rpc.rs new file mode 100644 index 00000000000..21cac2a19c2 --- /dev/null +++ b/components/script_layout_interface/rpc.rs @@ -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) -> Vec; +} + +pub struct ContentBoxResponse(pub Rect); + +pub struct ContentBoxesResponse(pub Vec>); + +pub struct NodeGeometryResponse { + pub client_rect: Rect, +} + +pub struct NodeOverflowResponse(pub Option>); + +pub struct NodeLayerIdResponse { + pub layer_id: LayerId, +} + +pub struct HitTestResponse { + pub node_address: Option, +} + +pub struct ResolvedStyleResponse(pub Option); + +#[derive(Clone)] +pub struct OffsetParentResponse { + pub node_address: Option, + pub rect: Rect, +} + +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, + } + } +} diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 91cf4ddbb2f..172aac35d99 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1931,8 +1931,10 @@ dependencies = [ 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", + "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)", @@ -1941,6 +1943,7 @@ dependencies = [ "msg 0.0.1", "plugins 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", diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 0c34232fb20..1f9b568c7ef 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -1789,8 +1789,10 @@ dependencies = [ 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", + "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)", @@ -1799,6 +1801,7 @@ dependencies = [ "msg 0.0.1", "plugins 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", From 7bbabf27669463563d6743458bf248c2611d621e Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Thu, 16 Jun 2016 02:17:33 +0100 Subject: [PATCH 25/30] Remove unused re-exports from layout_interface. --- components/script/layout_interface.rs | 11 ----------- components/script/layout_wrapper.rs | 15 +++++++++------ 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index 3c5516e4b8d..b06940ea227 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -27,18 +27,7 @@ use style::servo::Stylesheet; use url::Url; use util::ipc::OptionalOpaqueIpcSender; -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::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::text::Text; - /// Asynchronous messages that script can send to layout. pub enum Msg { diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index 1ef916ea500..2fc6991310e 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -30,13 +30,16 @@ #![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 layout_interface::{CAN_BE_FRAGMENTED, HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY}; -use layout_interface::{CharacterDataTypeId, Document, Element, ElementTypeId}; -use layout_interface::{HTMLElementTypeId, LayoutCharacterDataHelpers}; -use layout_interface::{LayoutDocumentHelpers, LayoutElementHelpers, LayoutJS}; -use layout_interface::{LayoutNodeHelpers, Node, NodeTypeId}; -use layout_interface::{RawLayoutElementHelpers, Text}; use msg::constellation_msg::PipelineId; use range::Range; use script_layout_interface::restyle_damage::RestyleDamage; From 0c506cf1df22148a0688b679f27ed85d62d6486d Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Thu, 16 Jun 2016 09:29:20 +0100 Subject: [PATCH 26/30] Remove the wrapper::ServoThreadSafeLayoutNode re-export. --- components/layout/lib.rs | 1 - tests/unit/layout/size_of.rs | 21 --------------------- tests/unit/script/size_of.rs | 2 ++ 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/components/layout/lib.rs b/components/layout/lib.rs index 62da36cff87..d1eb3cf41ba 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -103,4 +103,3 @@ mod wrapper; // For unit tests: pub use fragment::Fragment; -pub use wrapper::ServoThreadSafeLayoutNode; diff --git a/tests/unit/layout/size_of.rs b/tests/unit/layout/size_of.rs index 033916647ee..320f85e0169 100644 --- a/tests/unit/layout/size_of.rs +++ b/tests/unit/layout/size_of.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use layout::Fragment; -use layout::ServoThreadSafeLayoutNode; use std::mem::size_of; #[test] @@ -25,23 +24,3 @@ fn test_size_of_fragment() { expected, actual); } } - -#[test] -fn test_size_of_layout_node() { - let expected = 16; - let actual = size_of::(); - - 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); - } -} diff --git a/tests/unit/script/size_of.rs b/tests/unit/script/size_of.rs index fc9cf6f09bf..21b8e4a4ba2 100644 --- a/tests/unit/script/size_of.rs +++ b/tests/unit/script/size_of.rs @@ -10,6 +10,7 @@ use script::dom::htmlelement::HTMLElement; use script::dom::htmlspanelement::HTMLSpanElement; use script::dom::node::Node; use script::dom::text::Text; +use script::layout_wrapper::ServoThreadSafeLayoutNode; use std::mem::size_of; // 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_text, Text, 192); sizeof_checker!(size_characterdata, CharacterData, 192); +sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16); From 65b93c20b7be0008ba6d49a49f8119524451ef95 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Thu, 16 Jun 2016 09:35:58 +0100 Subject: [PATCH 27/30] Remove the layout_wrapper re-exports from layout::wrapper. --- components/layout/layout_thread.rs | 3 ++- components/layout/wrapper.rs | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index 14179c38985..15b756a42e4 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -47,6 +47,7 @@ use query::{LayoutRPCImpl, process_content_box_request, process_content_boxes_re 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 script::layout_interface::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow}; +use script::layout_wrapper::ServoLayoutNode; 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}; @@ -86,7 +87,7 @@ use util::thread_state; use util::workqueue::WorkQueue; use webrender_helpers::{WebRenderDisplayListConverter, WebRenderFrameBuilder}; use webrender_traits; -use wrapper::{LayoutNodeLayoutData, NonOpaqueStyleAndLayoutData, ServoLayoutNode}; +use wrapper::{LayoutNodeLayoutData, NonOpaqueStyleAndLayoutData}; /// 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; diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index a7949fc75b1..6db7f8b7cc2 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -38,8 +38,6 @@ use std::cell::{Ref, RefCell, RefMut}; use style::computed_values::content::{self, ContentItem}; use style::properties::ComputedValues; -pub use script::layout_wrapper::*; - pub type NonOpaqueStyleAndLayoutData = *mut RefCell; pub trait LayoutNodeLayoutData { From 2c50318ee7c05ab926e27d225a3409c8da86c991 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Thu, 16 Jun 2016 09:44:40 +0100 Subject: [PATCH 28/30] Move is_image_data to script_layout_interface. --- components/layout/construct.rs | 3 +-- components/script/dom/htmlobjectelement.rs | 5 ----- components/script/layout_interface.rs | 2 -- components/script_layout_interface/lib.rs | 5 +++++ 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 27c6f629ca6..40ffdc42047 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -33,10 +33,9 @@ use inline::{InlineFragmentNodeInfo, LAST_FRAGMENT_OF_ELEMENT}; use list_item::{ListItemFlow, ListStyleTypeContent}; use multicol::{MulticolFlow, MulticolColumnFlow}; use parallel; -use script::layout_interface::is_image_data; use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, RECONSTRUCT_FLOW, RestyleDamage}; use script_layout_interface::wrapper_traits::{ThreadSafeLayoutNode, PseudoElementType, ThreadSafeLayoutElement}; -use script_layout_interface::{LayoutNodeType, LayoutElementType}; +use script_layout_interface::{LayoutNodeType, LayoutElementType, is_image_data}; use std::borrow::ToOwned; use std::collections::LinkedList; use std::marker::PhantomData; diff --git a/components/script/dom/htmlobjectelement.rs b/components/script/dom/htmlobjectelement.rs index 268ff17e9cf..13798632e17 100644 --- a/components/script/dom/htmlobjectelement.rs +++ b/components/script/dom/htmlobjectelement.rs @@ -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 { // https://html.spec.whatwg.org/multipage/#dom-cva-validity fn Validity(&self) -> Root { diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index b06940ea227..350c8150109 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -27,8 +27,6 @@ use style::servo::Stylesheet; use url::Url; use util::ipc::OptionalOpaqueIpcSender; -pub use dom::htmlobjectelement::is_image_data; - /// Asynchronous messages that script can send to layout. pub enum Msg { /// Adds the given stylesheet to the document. diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index 123792a6c6f..33d6696b782 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -100,3 +100,8 @@ 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_)) +} From 9e2e0ff98c7c42b6bfb24f0846dc0c82e36e7d2c Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Thu, 16 Jun 2016 12:28:43 +0100 Subject: [PATCH 29/30] Move the remainder of layout_interface into script_layout_interface. --- components/layout/layout_thread.rs | 2 +- components/script/dom/document.rs | 2 +- components/script/dom/htmliframeelement.rs | 2 +- components/script/dom/htmllinkelement.rs | 2 +- components/script/dom/htmlstyleelement.rs | 2 +- components/script/dom/node.rs | 2 +- components/script/dom/window.rs | 2 +- components/script/lib.rs | 1 - components/script/script_thread.rs | 22 +++++++++---------- components/script_layout_interface/Cargo.toml | 3 +++ components/script_layout_interface/lib.rs | 4 ++++ .../message.rs} | 8 ++----- components/servo/Cargo.lock | 4 ++++ components/servo/Cargo.toml | 1 + components/servo/lib.rs | 5 +++-- ports/cef/Cargo.lock | 4 ++++ 16 files changed, 39 insertions(+), 27 deletions(-) rename components/{script/layout_interface.rs => script_layout_interface/message.rs} (94%) diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index 15b756a42e4..22f9f0c802f 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -46,9 +46,9 @@ use query::process_offset_parent_query; 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_overflow_request, process_resolved_style_request, process_margin_style_query}; -use script::layout_interface::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow}; use script::layout_wrapper::ServoLayoutNode; use script::reporter::CSSErrorReporter; +use script_layout_interface::message::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow}; 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; diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 4dfb484a301..a69537d3c1c 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -92,7 +92,6 @@ use html5ever::tree_builder::{LimitedQuirks, NoQuirks, Quirks, QuirksMode}; use ipc_channel::ipc::{self, IpcSender}; use js::jsapi::JS_GetRuntime; use js::jsapi::{JSContext, JSObject, JSRuntime}; -use layout_interface::{Msg, ReflowQueryType}; use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER}; use msg::constellation_msg::{Key, KeyModifiers, KeyState}; use msg::constellation_msg::{PipelineId, ReferrerPolicy, SubpageId}; @@ -103,6 +102,7 @@ use net_traits::{AsyncResponseTarget, PendingAsyncLoad, IpcSend}; use num_traits::ToPrimitive; use origin::Origin; use parse::{ParserRoot, ParserRef, MutNullableParserField}; +use script_layout_interface::message::{Msg, ReflowQueryType}; use script_thread::{MainThreadScriptMsg, Runnable}; use script_traits::UntrustedNodeAddress; use script_traits::{AnimationState, MouseButton, MouseEventType, MozBrowserEvent}; diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 86146b8e915..22e67d162d9 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -38,9 +38,9 @@ use dom::window::{ReflowReason, Window}; use ipc_channel::ipc; use js::jsapi::{JSAutoCompartment, RootedValue, JSContext, MutableHandleValue}; use js::jsval::{UndefinedValue, NullValue}; -use layout_interface::ReflowQueryType; use msg::constellation_msg::{FrameType, LoadData, NavigationDirection, PipelineId, SubpageId}; use net_traits::response::HttpsState; +use script_layout_interface::message::ReflowQueryType; use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed}; use script_traits::{IFrameLoadInfo, MozBrowserEvent, ScriptMsg as ConstellationMsg}; use std::cell::Cell; diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index 79b6ed32f0b..ab2c2a99887 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -25,9 +25,9 @@ use hyper::header::ContentType; use hyper::mime::{Mime, TopLevel, SubLevel}; use ipc_channel::ipc; use ipc_channel::router::ROUTER; -use layout_interface::Msg; use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata, NetworkError}; use network_listener::{NetworkListener, PreInvoke}; +use script_layout_interface::message::Msg; use script_traits::{MozBrowserEvent, ScriptMsg as ConstellationMsg}; use std::ascii::AsciiExt; use std::borrow::ToOwned; diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index c972cb77bb5..47409402855 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -14,7 +14,7 @@ use dom::element::Element; use dom::htmlelement::HTMLElement; use dom::node::{ChildrenMutation, Node, document_from_node, window_from_node}; use dom::virtualmethods::VirtualMethods; -use layout_interface::Msg; +use script_layout_interface::message::Msg; use std::sync::Arc; use string_cache::Atom; use style::media_queries::parse_media_query_list; diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index fdb9deed87b..53a3f355b9d 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -56,11 +56,11 @@ use euclid::size::Size2D; use heapsize::{HeapSizeOf, heap_size_of}; use html5ever::tree_builder::QuirksMode; use js::jsapi::{JSContext, JSObject, JSRuntime}; -use layout_interface::Msg; use libc::{self, c_void, uintptr_t}; use msg::constellation_msg::PipelineId; use parse::html::parse_html_fragment; 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; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 6dc43f8b925..eab2e31c907 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -42,7 +42,6 @@ use js::jsapi::{Evaluate2, HandleObject, HandleValue, JSAutoCompartment, JSConte use js::jsapi::{JS_GetRuntime, JS_GC, MutableHandleValue, SetWindowProxy}; use js::rust::CompileOptionsWrapper; use js::rust::Runtime; -use layout_interface::{Msg, Reflow, ReflowQueryType, ScriptReflow}; use libc; use msg::constellation_msg::{FrameType, LoadData, PanicMsg, PipelineId, SubpageId}; use msg::constellation_msg::{WindowSizeData, WindowSizeType}; @@ -59,6 +58,7 @@ use profile_traits::time::{ProfilerChan, TimerMetadataReflowType, profile}; use reporter::CSSErrorReporter; 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::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC}; use script_layout_interface::rpc::{MarginStyleResponse, ResolvedStyleResponse}; use script_runtime::{ScriptChan, ScriptPort}; diff --git a/components/script/lib.rs b/components/script/lib.rs index c191c203889..33467a5dd34 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -94,7 +94,6 @@ mod devtools; pub mod document_loader; #[macro_use] pub mod dom; -pub mod layout_interface; pub mod layout_wrapper; mod mem; mod network_listener; diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 3459e5ddcfa..8418071e908 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -61,7 +61,6 @@ use js::jsapi::{JSAutoCompartment, JSContext, JS_SetWrapObjectCallbacks}; use js::jsapi::{JSTracer, SetWindowProxyClass}; use js::jsval::UndefinedValue; use js::rust::Runtime; -use layout_interface::{self, NewLayoutThreadInfo, ReflowQueryType}; use mem::heap_size_of_self_and_children; use msg::constellation_msg::{FrameType, LoadData, PanicMsg, PipelineId, PipelineNamespace}; use msg::constellation_msg::{SubpageId, WindowSizeData, WindowSizeType}; @@ -77,6 +76,7 @@ use parse::html::{ParseContext, parse_html}; use parse::xml::{self, parse_xml}; use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan}; use profile_traits::time::{self, ProfilerCategory, profile}; +use script_layout_interface::message::{self, NewLayoutThreadInfo, ReflowQueryType}; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory}; use script_runtime::{ScriptPort, StackRootTLS, new_rt_and_cx, get_reports}; use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent}; @@ -135,7 +135,7 @@ struct InProgressLoad { /// The current window size associated with this pipeline. window_size: Option, /// Channel to the layout thread associated with this pipeline. - layout_chan: Sender, + layout_chan: Sender, /// The current viewport clipping rectangle applying to this pipeline, if any. clip_rect: Option>, /// Window is frozen (navigated away while loading for example). @@ -150,7 +150,7 @@ impl InProgressLoad { /// Create a new InProgressLoad object. fn new(id: PipelineId, parent_info: Option<(PipelineId, SubpageId, FrameType)>, - layout_chan: Sender, + layout_chan: Sender, window_size: Option, url: Url) -> InProgressLoad { InProgressLoad { @@ -438,11 +438,11 @@ impl<'a> Drop for ScriptMemoryFailsafe<'a> { } impl ScriptThreadFactory for ScriptThread { - type Message = layout_interface::Msg; + type Message = message::Msg; fn create(state: InitialScriptState, load_data: LoadData) - -> (Sender, Receiver) { + -> (Sender, Receiver) { let panic_chan = state.panic_chan.clone(); let (script_chan, script_port) = channel(); @@ -1184,7 +1184,7 @@ impl ScriptThread { // Tell layout to actually spawn the thread. parent_window.layout_chan() - .send(layout_interface::Msg::CreateLayoutThread(layout_creation_info)) + .send(message::Msg::CreateLayoutThread(layout_creation_info)) .unwrap(); // Kick off the fetch for the new resource. @@ -1462,10 +1462,10 @@ impl ScriptThread { // processed this message. let (response_chan, response_port) = channel(); 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); 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; @@ -1523,7 +1523,7 @@ impl ScriptThread { { // send the final url to the layout thread. incomplete.layout_chan - .send(layout_interface::Msg::SetFinalUrl(final_url.clone())) + .send(message::Msg::SetFinalUrl(final_url.clone())) .unwrap(); // update the pipeline url @@ -2126,7 +2126,7 @@ fn shut_down_layout(context_tree: &BrowsingContext) { let (response_chan, response_port) = channel(); let window = context.active_window(); 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); 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. for chan in channels { - chan.send(layout_interface::Msg::ExitNow).ok(); + chan.send(message::Msg::ExitNow).ok(); } } diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index a4ace11ae26..226df50f386 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -19,6 +19,8 @@ heapsize_plugin = "0.1.2" ipc-channel = {git = "https://github.com/servo/ipc-channel"} libc = "0.2" msg = {path = "../msg"} +net_traits = {path = "../net_traits"} +profile_traits = {path = "../profile_traits"} plugins = {path = "../plugins"} range = {path = "../range"} script_traits = {path = "../script_traits"} @@ -26,3 +28,4 @@ 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"} diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index 33d6696b782..929730f3909 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -26,6 +26,8 @@ extern crate heapsize; extern crate ipc_channel; extern crate libc; extern crate msg; +extern crate net_traits; +extern crate profile_traits; extern crate range; extern crate script_traits; extern crate selectors; @@ -33,7 +35,9 @@ extern crate selectors; extern crate string_cache; extern crate style; extern crate url; +extern crate util; +pub mod message; pub mod restyle_damage; pub mod rpc; pub mod wrapper_traits; diff --git a/components/script/layout_interface.rs b/components/script_layout_interface/message.rs similarity index 94% rename from components/script/layout_interface.rs rename to components/script_layout_interface/message.rs index 350c8150109..e3c8a14e4c3 100644 --- a/components/script/layout_interface.rs +++ b/components/script_layout_interface/message.rs @@ -2,10 +2,6 @@ * 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/. */ -//! 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 euclid::point::Point2D; use euclid::rect::Rect; @@ -14,8 +10,7 @@ use ipc_channel::ipc::{IpcReceiver, IpcSender}; use msg::constellation_msg::{PanicMsg, PipelineId, WindowSizeData}; use net_traits::image_cache_thread::ImageCacheThread; use profile_traits::mem::ReportsChan; -use script_layout_interface::rpc::LayoutRPC; -use script_layout_interface::{OpaqueStyleAndLayoutData, TrustedNodeAddress}; +use rpc::LayoutRPC; use script_traits::{ConstellationControlMsg, LayoutControlMsg}; use script_traits::{LayoutMsg as ConstellationMsg, StackingContextScrollState}; use std::sync::Arc; @@ -26,6 +21,7 @@ use style::selector_impl::PseudoElement; use style::servo::Stylesheet; use url::Url; use util::ipc::OptionalOpaqueIpcSender; +use {OpaqueStyleAndLayoutData, TrustedNodeAddress}; /// Asynchronous messages that script can send to layout. pub enum Msg { diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 172aac35d99..a495d668266 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -33,6 +33,7 @@ dependencies = [ "profile_tests 0.0.1", "profile_traits 0.0.1", "script 0.0.1", + "script_layout_interface 0.0.1", "script_tests 0.0.1", "script_traits 0.0.1", "style 0.0.1", @@ -1941,13 +1942,16 @@ dependencies = [ "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)", "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]] diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index b7956a6b198..dc1dc080e73 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -43,6 +43,7 @@ compiletest_helper = {path = "../../tests/compiletest/helper"} plugin_compiletest = {path = "../../tests/compiletest/plugin"} [dependencies] +script_layout_interface = {path = "../script_layout_interface"} webrender_traits = {git = "https://github.com/servo/webrender_traits"} webrender = {git = "https://github.com/servo/webrender"} compositing = {path = "../compositing"} diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 363cd3bec4f..5f98a1894b6 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -39,6 +39,7 @@ pub extern crate profile; pub extern crate profile_traits; pub extern crate script; pub extern crate script_traits; +pub extern crate script_layout_interface; pub extern crate style; pub extern crate url; pub extern crate util; @@ -229,7 +230,7 @@ fn create_constellation(opts: opts::Opts, webrender_api_sender: webrender_api_sender, }; let constellation_chan = - Constellation::::start(initial_state); @@ -263,7 +264,7 @@ pub fn run_content_process(token: String) { script::init(); - unprivileged_content.start_all::(true); } diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 1f9b568c7ef..62d2223caf4 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -1799,13 +1799,16 @@ dependencies = [ "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)", "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]] @@ -1915,6 +1918,7 @@ dependencies = [ "profile 0.0.1", "profile_traits 0.0.1", "script 0.0.1", + "script_layout_interface 0.0.1", "script_traits 0.0.1", "style 0.0.1", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", From b56821a01f8ec8f28c37cb46568340ecb145834c Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Thu, 16 Jun 2016 16:01:50 +0100 Subject: [PATCH 30/30] Move CSSErrorReporter to script_layout_interface. --- components/layout/layout_thread.rs | 2 +- components/script/dom/bindings/trace.rs | 2 ++ components/script/dom/window.rs | 2 +- components/script/lib.rs | 1 - components/script_layout_interface/Cargo.toml | 2 ++ components/script_layout_interface/lib.rs | 5 +++++ components/{script => script_layout_interface}/reporter.rs | 2 +- components/servo/Cargo.lock | 2 ++ ports/cef/Cargo.lock | 2 ++ 9 files changed, 16 insertions(+), 4 deletions(-) rename components/{script => script_layout_interface}/reporter.rs (98%) diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index 22f9f0c802f..a65b1452a09 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -47,8 +47,8 @@ use query::{LayoutRPCImpl, process_content_box_request, process_content_boxes_re 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 script::layout_wrapper::ServoLayoutNode; -use script::reporter::CSSErrorReporter; use script_layout_interface::message::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow}; +use script_layout_interface::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; diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 4abfc8fd58d..cd4a0f5d3ca 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -67,6 +67,7 @@ use offscreen_gl_context::GLLimits; use profile_traits::mem::ProfilerChan as MemProfilerChan; 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_traits::{TimerEventId, TimerSource, TouchpadPressurePhase, UntrustedNodeAddress}; @@ -330,6 +331,7 @@ no_jsmanaged_fields!(ResourceThreads); no_jsmanaged_fields!(SystemTime); no_jsmanaged_fields!(SelectedFileId); no_jsmanaged_fields!(OpaqueStyleAndLayoutData); +no_jsmanaged_fields!(CSSErrorReporter); impl JSTraceable for Box { #[inline] diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index eab2e31c907..58fe8b6ad40 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -55,10 +55,10 @@ use open; use profile_traits::mem; use profile_traits::time::{ProfilerCategory, TimerMetadata, TimerMetadataFrameType}; use profile_traits::time::{ProfilerChan, TimerMetadataReflowType, profile}; -use reporter::CSSErrorReporter; 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}; diff --git a/components/script/lib.rs b/components/script/lib.rs index 33467a5dd34..3fe7cb83113 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -99,7 +99,6 @@ mod mem; mod network_listener; pub mod origin; pub mod parse; -pub mod reporter; pub mod script_runtime; #[allow(unsafe_code)] pub mod script_thread; diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index 226df50f386..287c72ee2c0 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -12,12 +12,14 @@ path = "lib.rs" 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"} diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index 929730f3909..c2e06e3dcf7 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -7,6 +7,7 @@ //! to depend on script. #![deny(unsafe_code)] +#![feature(box_syntax)] #![feature(custom_attribute)] #![feature(custom_derive)] #![feature(nonzero)] @@ -20,11 +21,14 @@ extern crate app_units; 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; @@ -38,6 +42,7 @@ extern crate url; extern crate util; pub mod message; +pub mod reporter; pub mod restyle_damage; pub mod rpc; pub mod wrapper_traits; diff --git a/components/script/reporter.rs b/components/script_layout_interface/reporter.rs similarity index 98% rename from components/script/reporter.rs rename to components/script_layout_interface/reporter.rs index 39b9e81d333..4561f2d63ca 100644 --- a/components/script/reporter.rs +++ b/components/script_layout_interface/reporter.rs @@ -10,7 +10,7 @@ use script_traits::ConstellationControlMsg; use std::sync::{Mutex, Arc}; use style::error_reporting::ParseErrorReporter; -#[derive(JSTraceable, HeapSizeOf)] +#[derive(HeapSizeOf)] pub struct CSSErrorReporter { pub pipelineid: PipelineId, // Arc+Mutex combo is necessary to make this struct Sync, diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index a495d668266..8b331211227 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1935,12 +1935,14 @@ 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", diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 62d2223caf4..0c8cfa3ec88 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -1792,12 +1792,14 @@ 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",