diff options
43 files changed, 527 insertions, 269 deletions
diff --git a/Cargo.lock b/Cargo.lock index 9811dc986c6..cb09c8d5ba4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1403,7 +1403,9 @@ dependencies = [ name = "layout_tests" version = "0.0.1" dependencies = [ + "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "layout 0.0.1", + "script_layout_interface 0.0.1", ] [[package]] diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index eb2a964ac23..cbe8e31667e 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -903,7 +903,8 @@ impl<Window: WindowMethods> IOCompositor<Window> { match ServoUrl::parse(&url_string) { Ok(url) => { let msg = match self.root_pipeline { - Some(ref pipeline) => ConstellationMsg::LoadUrl(pipeline.id, LoadData::new(url, None, None)), + Some(ref pipeline) => + ConstellationMsg::LoadUrl(pipeline.id, LoadData::new(url, Some(pipeline.id), None, None)), None => ConstellationMsg::InitLoadUrl(url) }; if let Err(e) = self.constellation_chan.send(msg) { diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 731486c4e16..01a59070730 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -101,7 +101,7 @@ use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory}; use script_traits::{LogEntry, ServiceWorkerMsg, webdriver_msg}; use script_traits::{MozBrowserErrorType, MozBrowserEvent, WebDriverCommandMsg, WindowSizeData}; -use script_traits::{SWManagerMsg, ScopeThings, WindowSizeType}; +use script_traits::{SWManagerMsg, ScopeThings, UpdatePipelineIdReason, WindowSizeType}; use serde::{Deserialize, Serialize}; use servo_config::opts; use servo_config::prefs::PREFS; @@ -599,17 +599,31 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> let (event_loop, host) = match sandbox { IFrameSandboxState::IFrameSandboxed => (None, None), - IFrameSandboxState::IFrameUnsandboxed => match reg_host(&load_data.url) { - None => (None, None), - Some(host) => { - let event_loop = self.event_loops.get(&top_level_frame_id) - .and_then(|map| map.get(&host)) - .and_then(|weak| weak.upgrade()); - match event_loop { - None => (None, Some(host)), - Some(event_loop) => (Some(event_loop.clone()), None), + IFrameSandboxState::IFrameUnsandboxed => { + // If this is an about:blank load, it must share the creator's event loop. + // This must match the logic in the script thread when determining the proper origin. + if load_data.url.as_str() != "about:blank" { + match reg_host(&load_data.url) { + None => (None, None), + Some(host) => { + let event_loop = self.event_loops.get(&top_level_frame_id) + .and_then(|map| map.get(&host)) + .and_then(|weak| weak.upgrade()); + match event_loop { + None => (None, Some(host)), + Some(event_loop) => (Some(event_loop.clone()), None), + } + }, } - }, + } else if let Some(parent) = parent_info + .and_then(|(pipeline_id, _)| self.pipelines.get(&pipeline_id)) { + (Some(parent.event_loop.clone()), None) + } else if let Some(creator) = load_data.creator_pipeline_id + .and_then(|pipeline_id| self.pipelines.get(&pipeline_id)) { + (Some(creator.event_loop.clone()), None) + } else { + (None, None) + } }, }; @@ -735,7 +749,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } /// Create a new frame and update the internal bookkeeping. - fn new_frame(&mut self, frame_id: FrameId, pipeline_id: PipelineId, load_data: LoadData) { + fn new_frame(&mut self, + frame_id: FrameId, + pipeline_id: PipelineId, + load_data: LoadData) { let frame = Frame::new(frame_id, pipeline_id, load_data); self.frames.insert(frame_id, frame); @@ -915,11 +932,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> load_info.info.new_pipeline_id); self.handle_script_loaded_url_in_iframe_msg(load_info); } - FromScriptMsg::ScriptLoadedAboutBlankInIFrame(load_info, lc) => { + FromScriptMsg::ScriptNewIFrame(load_info, layout_sender) => { debug!("constellation got loaded `about:blank` in iframe message {:?} {:?}", load_info.parent_pipeline_id, load_info.new_pipeline_id); - self.handle_script_loaded_about_blank_in_iframe_msg(load_info, lc); + self.handle_script_new_iframe(load_info, layout_sender); } FromScriptMsg::ChangeRunningAnimationsState(pipeline_id, animation_state) => { self.handle_change_running_animations_state(pipeline_id, animation_state) @@ -1277,10 +1294,19 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // Notify the browser chrome that the pipeline has failed self.trigger_mozbrowsererror(top_level_frame_id, reason, backtrace); - let pipeline_id = self.frames.get(&top_level_frame_id).map(|frame| frame.pipeline_id); - let pipeline_url = pipeline_id.and_then(|id| self.pipelines.get(&id).map(|pipeline| pipeline.url.clone())); - let parent_info = pipeline_id.and_then(|id| self.pipelines.get(&id).and_then(|pipeline| pipeline.parent_info)); - let window_size = pipeline_id.and_then(|id| self.pipelines.get(&id).and_then(|pipeline| pipeline.size)); + let (window_size, pipeline_id) = { + let frame = self.frames.get(&top_level_frame_id); + let window_size = frame.and_then(|frame| frame.size); + let pipeline_id = frame.map(|frame| frame.pipeline_id); + (window_size, pipeline_id) + }; + + let (pipeline_url, parent_info) = { + let pipeline = pipeline_id.and_then(|id| self.pipelines.get(&id)); + let pipeline_url = pipeline.map(|pipeline| pipeline.url.clone()); + let parent_info = pipeline.and_then(|pipeline| pipeline.parent_info); + (pipeline_url, parent_info) + }; self.close_frame_children(top_level_frame_id, DiscardBrowsingContext::No, ExitPipelineMode::Force); @@ -1295,7 +1321,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> warn!("creating replacement pipeline for about:failure"); let new_pipeline_id = PipelineId::new(); - let load_data = LoadData::new(failure_url, None, None); + let load_data = LoadData::new(failure_url, None, None, None); let sandbox = IFrameSandboxState::IFrameSandboxed; self.new_pipeline(new_pipeline_id, top_level_frame_id, parent_info, window_size, load_data.clone(), sandbox, false); @@ -1340,7 +1366,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> let window_size = self.window_size.initial_viewport; let root_pipeline_id = PipelineId::new(); let root_frame_id = self.root_frame_id; - let load_data = LoadData::new(url.clone(), None, None); + let load_data = LoadData::new(url.clone(), None, None, None); let sandbox = IFrameSandboxState::IFrameUnsandboxed; self.new_pipeline(root_pipeline_id, root_frame_id, None, Some(window_size), load_data.clone(), sandbox, false); self.handle_load_start_msg(root_pipeline_id); @@ -1353,29 +1379,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } fn handle_frame_size_msg(&mut self, - iframe_sizes: Vec<(PipelineId, TypedSize2D<f32, CSSPixel>)>) { - for (pipeline_id, size) in iframe_sizes { - let result = { - let pipeline = match self.pipelines.get_mut(&pipeline_id) { - Some(pipeline) => pipeline, - None => continue, - }; - - if pipeline.size == Some(size) { - continue; - } - - pipeline.size = Some(size); - let msg = ConstellationControlMsg::Resize(pipeline_id, WindowSizeData { - initial_viewport: size, - device_pixel_ratio: self.window_size.device_pixel_ratio, - }, WindowSizeType::Initial); - - pipeline.event_loop.send(msg) + iframe_sizes: Vec<(FrameId, TypedSize2D<f32, CSSPixel>)>) { + for (frame_id, size) in iframe_sizes { + let window_size = WindowSizeData { + initial_viewport: size, + device_pixel_ratio: self.window_size.device_pixel_ratio, }; - if let Err(e) = result { - self.handle_send_error(pipeline_id, e); - } + + self.resize_frame(window_size, WindowSizeType::Initial, frame_id); } } @@ -1423,12 +1434,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> }; // TODO - loaddata here should have referrer info (not None, None) - LoadData::new(url, None, None) + LoadData::new(url, Some(source_pipeline.id), None, None) }); let is_private = load_info.info.is_private || source_pipeline.is_private; - let window_size = old_pipeline.and_then(|old_pipeline| old_pipeline.size); + let window_size = self.frames.get(&load_info.info.frame_id).and_then(|frame| frame.size); (load_data, window_size, is_private) }; @@ -1456,9 +1467,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> is_private); } - fn handle_script_loaded_about_blank_in_iframe_msg(&mut self, - load_info: IFrameLoadInfo, - layout_sender: IpcSender<LayoutControlMsg>) { + fn handle_script_new_iframe(&mut self, + load_info: IFrameLoadInfo, + layout_sender: IpcSender<LayoutControlMsg>) { let IFrameLoadInfo { parent_pipeline_id, new_pipeline_id, @@ -1486,12 +1497,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.compositor_proxy.clone_compositor_proxy(), is_private || parent_pipeline.is_private, url.clone(), - None, parent_pipeline.visible) }; // TODO: Referrer? - let load_data = LoadData::new(url, None, None); + let load_data = LoadData::new(url, Some(parent_pipeline_id), None, None); let replace_instant = if replace { self.frames.get(&frame_id).map(|frame| frame.instant) @@ -1641,7 +1651,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // changes would be overridden by changing the subframe associated with source_id. // Create the new pipeline - let window_size = self.pipelines.get(&source_id).and_then(|source| source.size); + let window_size = self.frames.get(&root_frame_id).and_then(|frame| frame.size); let new_pipeline_id = PipelineId::new(); let sandbox = IFrameSandboxState::IFrameUnsandboxed; let replace_instant = if replace { @@ -1959,7 +1969,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> }, WebDriverCommandMsg::Refresh(pipeline_id, reply) => { let load_data = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => LoadData::new(pipeline.url.clone(), None, None), + Some(pipeline) => LoadData::new(pipeline.url.clone(), None, None, None), None => return warn!("Pipeline {:?} Refresh after closure.", pipeline_id), }; self.load_url_for_webdriver(pipeline_id, load_data, reply, true); @@ -2019,8 +2029,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> let load_data = entry.load_data; let (parent_info, window_size, is_private) = match self.frames.get(&frame_id) { Some(frame) => match self.pipelines.get(&frame.pipeline_id) { - Some(pipeline) => (pipeline.parent_info, pipeline.size, pipeline.is_private), - None => (None, None, false), + Some(pipeline) => (pipeline.parent_info, frame.size, pipeline.is_private), + None => (None, frame.size, false), }, None => return warn!("no frame to traverse"), }; @@ -2101,7 +2111,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // Update the owning iframe to point to the new pipeline id. // This makes things like contentDocument work correctly. if let Some((parent_pipeline_id, _)) = parent_info { - let msg = ConstellationControlMsg::UpdatePipelineId(parent_pipeline_id, frame_id, pipeline_id); + let msg = ConstellationControlMsg::UpdatePipelineId(parent_pipeline_id, + frame_id, pipeline_id, UpdatePipelineIdReason::Traversal); let result = match self.pipelines.get(&parent_pipeline_id) { None => return warn!("Pipeline {:?} child traversed after closure.", parent_pipeline_id), Some(pipeline) => pipeline.event_loop.send(msg), @@ -2245,7 +2256,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } if new_frame { - self.new_frame(frame_change.frame_id, frame_change.new_pipeline_id, frame_change.load_data); + self.new_frame(frame_change.frame_id, + frame_change.new_pipeline_id, + frame_change.load_data); self.update_activity(frame_change.new_pipeline_id); self.notify_history_changed(frame_change.new_pipeline_id); }; @@ -2275,7 +2288,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> if let Some(pipeline) = self.pipelines.get(&pipeline_id) { if let Some((parent_pipeline_id, _)) = pipeline.parent_info { if let Some(parent_pipeline) = self.pipelines.get(&parent_pipeline_id) { - let msg = ConstellationControlMsg::FramedContentChanged(parent_pipeline_id, pipeline.frame_id); + let msg = ConstellationControlMsg::UpdatePipelineId(parent_pipeline_id, + pipeline.frame_id, pipeline_id, UpdatePipelineIdReason::Navigation); let _ = parent_pipeline.event_loop.send(msg); } } @@ -2298,45 +2312,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> fn handle_window_size_msg(&mut self, new_size: WindowSizeData, size_type: WindowSizeType) { debug!("handle_window_size_msg: {:?}", new_size.initial_viewport.to_untyped()); - if let Some(frame) = self.frames.get(&self.root_frame_id) { - // Send Resize (or ResizeInactive) messages to each - // pipeline in the frame tree. - let pipeline_id = frame.pipeline_id; - let pipeline = match self.pipelines.get(&pipeline_id) { - None => return warn!("Pipeline {:?} resized after closing.", pipeline_id), - Some(pipeline) => pipeline, - }; - let _ = pipeline.event_loop.send(ConstellationControlMsg::Resize( - pipeline.id, - new_size, - size_type - )); - let pipelines = frame.prev.iter().chain(frame.next.iter()) - .filter_map(|entry| entry.pipeline_id) - .filter_map(|pipeline_id| self.pipelines.get(&pipeline_id)); - for pipeline in pipelines { - let _ = pipeline.event_loop.send(ConstellationControlMsg::ResizeInactive( - pipeline.id, - new_size - )); - } - } - - // Send resize message to any pending pipelines that aren't loaded yet. - for pending_frame in &self.pending_frames { - let pipeline_id = pending_frame.new_pipeline_id; - let pipeline = match self.pipelines.get(&pipeline_id) { - None => { warn!("Pending pipeline {:?} is closed", pipeline_id); continue; } - Some(pipeline) => pipeline, - }; - if pipeline.parent_info.is_none() { - let _ = pipeline.event_loop.send(ConstellationControlMsg::Resize( - pipeline.id, - new_size, - size_type - )); - } - } + let frame_id = self.root_frame_id; + self.resize_frame(new_size, size_type, frame_id); if let Some(resize_channel) = self.webdriver.resize_channel.take() { let _ = resize_channel.send(new_size); @@ -2422,7 +2399,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // size for the pipeline, then its painting should be up to date. If the constellation // *hasn't* received a size, it could be that the layer was hidden by script before the // compositor discovered it, so we just don't check the layer. - if let Some(size) = pipeline.size { + if let Some(size) = frame.size { // If the rectangle for this pipeline is zero sized, it will // never be painted. In this case, don't query the layout // thread as it won't contribute to the final output image. @@ -2509,6 +2486,54 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.set_activity(pipeline_id, self.get_activity(pipeline_id)); } + /// Handle updating the size of a frame. This notifies every pipeline in the frame of the new + /// size. + fn resize_frame(&mut self, new_size: WindowSizeData, size_type: WindowSizeType, frame_id: FrameId) { + if let Some(frame) = self.frames.get_mut(&frame_id) { + frame.size = Some(new_size.initial_viewport); + } + + if let Some(frame) = self.frames.get(&frame_id) { + // Send Resize (or ResizeInactive) messages to each + // pipeline in the frame tree. + let pipeline_id = frame.pipeline_id; + let pipeline = match self.pipelines.get(&pipeline_id) { + None => return warn!("Pipeline {:?} resized after closing.", pipeline_id), + Some(pipeline) => pipeline, + }; + let _ = pipeline.event_loop.send(ConstellationControlMsg::Resize( + pipeline.id, + new_size, + size_type + )); + let pipelines = frame.prev.iter().chain(frame.next.iter()) + .filter_map(|entry| entry.pipeline_id) + .filter_map(|pipeline_id| self.pipelines.get(&pipeline_id)); + for pipeline in pipelines { + let _ = pipeline.event_loop.send(ConstellationControlMsg::ResizeInactive( + pipeline.id, + new_size + )); + } + } + + // Send resize message to any pending pipelines that aren't loaded yet. + for pending_frame in &self.pending_frames { + let pipeline_id = pending_frame.new_pipeline_id; + let pipeline = match self.pipelines.get(&pipeline_id) { + None => { warn!("Pending pipeline {:?} is closed", pipeline_id); continue; } + Some(pipeline) => pipeline, + }; + if pipeline.frame_id == frame_id { + let _ = pipeline.event_loop.send(ConstellationControlMsg::Resize( + pipeline.id, + new_size, + size_type + )); + } + } + } + fn clear_joint_session_future(&mut self, frame_id: FrameId) { let frame_ids: Vec<FrameId> = self.full_frame_tree_iter(frame_id) .map(|frame| frame.id) @@ -2652,7 +2677,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.pipelines.get(&frame.pipeline_id).map(|pipeline: &Pipeline| { let mut frame_tree = SendableFrameTree { pipeline: pipeline.to_sendable(), - size: pipeline.size, + size: frame.size, children: vec!(), }; diff --git a/components/constellation/frame.rs b/components/constellation/frame.rs index 74aabee2de0..ac85c14d214 100644 --- a/components/constellation/frame.rs +++ b/components/constellation/frame.rs @@ -2,6 +2,7 @@ * 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 euclid::size::TypedSize2D; use msg::constellation_msg::{FrameId, PipelineId}; use pipeline::Pipeline; use script_traits::LoadData; @@ -9,6 +10,7 @@ use std::collections::HashMap; use std::iter::once; use std::mem::replace; use std::time::Instant; +use style_traits::CSSPixel; /// A frame in the frame tree. /// Each frame is the constellation's view of a browsing context. @@ -22,13 +24,16 @@ pub struct Frame { /// The frame id. pub id: FrameId, - /// The timestamp for the current session history entry + /// The size of the frame. + pub size: Option<TypedSize2D<f32, CSSPixel>>, + + /// The timestamp for the current session history entry. pub instant: Instant, - /// The pipeline for the current session history entry + /// The pipeline for the current session history entry. pub pipeline_id: PipelineId, - /// The load data for the current session history entry + /// The load data for the current session history entry. pub load_data: LoadData, /// The past session history, ordered chronologically. @@ -44,6 +49,7 @@ impl Frame { pub fn new(id: FrameId, pipeline_id: PipelineId, load_data: LoadData) -> Frame { Frame { id: id, + size: None, pipeline_id: pipeline_id, instant: Instant::now(), load_data: load_data, diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index aa380a8e5c1..60401f4313c 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -76,10 +76,6 @@ pub struct Pipeline { /// The title of the most recently-loaded page. pub title: Option<String>, - /// The size of the frame. - /// TODO: move this field to `Frame`. - pub size: Option<TypedSize2D<f32, CSSPixel>>, - /// Whether this pipeline is currently running animations. Pipelines that are running /// animations cause composites to be continually scheduled. pub running_animations: bool, @@ -291,7 +287,6 @@ impl Pipeline { state.compositor_proxy, state.is_private, url, - state.window_size, state.prev_visibility.unwrap_or(true))) } @@ -305,7 +300,6 @@ impl Pipeline { compositor_proxy: Box<CompositorProxy + 'static + Send>, is_private: bool, url: ServoUrl, - size: Option<TypedSize2D<f32, CSSPixel>>, visible: bool) -> Pipeline { let pipeline = Pipeline { @@ -318,7 +312,6 @@ impl Pipeline { url: url, title: None, children: vec!(), - size: size, running_animations: false, visible: visible, is_private: is_private, diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 472a34529ca..5f9a783c896 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -34,7 +34,7 @@ use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT}; use ipc_channel::ipc; use list_item::ListItemFlow; use model::{self, MaybeAuto, specified}; -use msg::constellation_msg::PipelineId; +use msg::constellation_msg::FrameId; use net_traits::image::base::PixelFormat; use net_traits::image_cache::UsePlaceholder; use range::Range; @@ -173,7 +173,7 @@ pub struct DisplayListBuildState<'a> { /// Vector containing iframe sizes, used to inform the constellation about /// new iframe sizes - pub iframe_sizes: Vec<(PipelineId, TypedSize2D<f32, CSSPixel>)>, + pub iframe_sizes: Vec<(FrameId, TypedSize2D<f32, CSSPixel>)>, /// A stack of clips used to cull display list entries that are outside the /// rendered region. @@ -1809,7 +1809,7 @@ impl FragmentDisplayListBuilding for Fragment { let size = Size2D::new(item.bounds().size.width.to_f32_px(), item.bounds().size.height.to_f32_px()); - state.iframe_sizes.push((fragment_info.pipeline_id, TypedSize2D::from_untyped(&size))); + state.iframe_sizes.push((fragment_info.frame_id, TypedSize2D::from_untyped(&size))); state.add_display_item(item); } diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 9f98ff318ec..c4dfefcc696 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -26,7 +26,7 @@ use ipc_channel::ipc::IpcSender; use layout_debug; use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, SizeConstraint}; use model::{style_length, ToGfxMatrix}; -use msg::constellation_msg::PipelineId; +use msg::constellation_msg::{FrameId, PipelineId}; use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder}; use range::*; @@ -467,19 +467,23 @@ impl ImageFragmentInfo { } } -/// A fragment that represents an inline frame (iframe). This stores the pipeline ID so that the +/// A fragment that represents an inline frame (iframe). This stores the frame ID so that the /// size of this iframe can be communicated via the constellation to the iframe's own layout thread. #[derive(Clone)] pub struct IframeFragmentInfo { - /// The pipeline ID of this iframe. + /// The frame ID of this iframe. + pub frame_id: FrameId, + /// The pipelineID of this iframe. pub pipeline_id: PipelineId, } impl IframeFragmentInfo { /// Creates the information specific to an iframe fragment. pub fn new<N: ThreadSafeLayoutNode>(node: &N) -> IframeFragmentInfo { + let frame_id = node.iframe_frame_id(); let pipeline_id = node.iframe_pipeline_id(); IframeFragmentInfo { + frame_id: frame_id, pipeline_id: pipeline_id, } } diff --git a/components/layout/lib.rs b/components/layout/lib.rs index abdf6ff04c0..1df46c557f4 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -93,6 +93,7 @@ pub mod wrapper; // For unit tests: pub use fragment::Fragment; pub use fragment::SpecificFragmentInfo; +pub use self::data::PersistentLayoutData; /// Returns whether the two arguments point to the same value. /// diff --git a/components/layout/model.rs b/components/layout/model.rs index 531d37038d7..aba7c3f3927 100644 --- a/components/layout/model.rs +++ b/components/layout/model.rs @@ -143,16 +143,19 @@ impl MarginCollapseInfo { may_collapse_through = may_collapse_through && match fragment.style().content_block_size() { LengthOrPercentageOrAuto::Auto => true, - LengthOrPercentageOrAuto::Length(Au(0)) => true, - LengthOrPercentageOrAuto::Percentage(0.) => true, - LengthOrPercentageOrAuto::Percentage(_) if - containing_block_size.is_none() => true, - _ => false, + LengthOrPercentageOrAuto::Length(Au(v)) => v == 0, + LengthOrPercentageOrAuto::Percentage(v) => { + v == 0. || containing_block_size.is_none() + } + LengthOrPercentageOrAuto::Calc(_) => false, }; if may_collapse_through { match fragment.style().min_block_size() { - LengthOrPercentage::Length(Au(0)) | LengthOrPercentage::Percentage(0.) => { + LengthOrPercentage::Length(Au(0)) => { + FinalMarginState::MarginsCollapseThrough + }, + LengthOrPercentage::Percentage(v) if v == 0. => { FinalMarginState::MarginsCollapseThrough }, _ => { diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index 5b5110099f6..02d4157f20c 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -310,3 +310,4 @@ pub enum FrameType { IFrame, MozBrowserIFrame, } + diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index 4397364f68f..53867c755f8 100755 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -345,7 +345,7 @@ impl HTMLFormElement { let _target = submitter.target(); // TODO: Handle browsing contexts, partially loaded documents (step 16-17) - let mut load_data = LoadData::new(action_components, doc.get_referrer_policy(), Some(doc.url())); + let mut load_data = LoadData::new(action_components, None, doc.get_referrer_policy(), Some(doc.url())); // Step 18 match (&*scheme, method) { diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index bee9f1a50c7..1e6615ce36a 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -44,7 +44,7 @@ use msg::constellation_msg::{FrameType, FrameId, PipelineId, TraversalDirection} use net_traits::response::HttpsState; use script_layout_interface::message::ReflowQueryType; use script_thread::{ScriptThread, Runnable}; -use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, LoadData}; +use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, LoadData, UpdatePipelineIdReason}; use script_traits::{MozBrowserEvent, NewLayoutInfo, ScriptMsg as ConstellationMsg}; use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed}; use servo_atoms::Atom; @@ -70,6 +70,12 @@ bitflags! { } #[derive(PartialEq)] +pub enum NavigationType { + InitialAboutBlank, + Regular, +} + +#[derive(PartialEq)] enum ProcessingMode { FirstTime, NotFirstTime, @@ -80,6 +86,7 @@ pub struct HTMLIFrameElement { htmlelement: HTMLElement, frame_id: FrameId, pipeline_id: Cell<Option<PipelineId>>, + pending_pipeline_id: Cell<Option<PipelineId>>, sandbox: MutNullableJS<DOMTokenList>, sandbox_allowance: Cell<Option<SandboxAllowance>>, load_blocker: DOMRefCell<Option<LoadBlocker>>, @@ -108,12 +115,14 @@ impl HTMLIFrameElement { pub fn generate_new_pipeline_id(&self) -> (Option<PipelineId>, PipelineId) { let old_pipeline_id = self.pipeline_id.get(); let new_pipeline_id = PipelineId::new(); - self.pipeline_id.set(Some(new_pipeline_id)); debug!("Frame {} created pipeline {}.", self.frame_id, new_pipeline_id); (old_pipeline_id, new_pipeline_id) } - pub fn navigate_or_reload_child_browsing_context(&self, load_data: Option<LoadData>, replace: bool) { + pub fn navigate_or_reload_child_browsing_context(&self, + load_data: Option<LoadData>, + nav_type: NavigationType, + replace: bool) { let sandboxed = if self.is_sandboxed() { IFrameSandboxed } else { @@ -136,6 +145,7 @@ impl HTMLIFrameElement { let window = window_from_node(self); let (old_pipeline_id, new_pipeline_id) = self.generate_new_pipeline_id(); + self.pending_pipeline_id.set(Some(new_pipeline_id)); let private_iframe = self.privatebrowsing(); let frame_type = if self.Mozbrowser() { FrameType::MozBrowserIFrame } else { FrameType::IFrame }; @@ -149,37 +159,41 @@ impl HTMLIFrameElement { replace: replace, }; - if load_data.as_ref().map_or(false, |d| d.url.as_str() == "about:blank") { - let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap(); - - global_scope - .constellation_chan() - .send(ConstellationMsg::ScriptLoadedAboutBlankInIFrame(load_info, pipeline_sender)) - .unwrap(); - - let new_layout_info = NewLayoutInfo { - parent_info: Some((global_scope.pipeline_id(), frame_type)), - new_pipeline_id: new_pipeline_id, - frame_id: self.frame_id, - load_data: load_data.unwrap(), - pipeline_port: pipeline_receiver, - content_process_shutdown_chan: None, - window_size: None, - layout_threads: PREFS.get("layout.threads").as_u64().expect("count") as usize, - }; - - ScriptThread::process_attach_layout(new_layout_info, document.origin().clone()); - } else { - let load_info = IFrameLoadInfoWithData { - info: load_info, - load_data: load_data, - old_pipeline_id: old_pipeline_id, - sandbox: sandboxed, - }; - global_scope + match nav_type { + NavigationType::InitialAboutBlank => { + let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap(); + + global_scope + .constellation_chan() + .send(ConstellationMsg::ScriptNewIFrame(load_info, pipeline_sender)) + .unwrap(); + + let new_layout_info = NewLayoutInfo { + parent_info: Some((global_scope.pipeline_id(), frame_type)), + new_pipeline_id: new_pipeline_id, + frame_id: self.frame_id, + load_data: load_data.unwrap(), + pipeline_port: pipeline_receiver, + content_process_shutdown_chan: None, + window_size: None, + layout_threads: PREFS.get("layout.threads").as_u64().expect("count") as usize, + }; + + self.pipeline_id.set(Some(new_pipeline_id)); + ScriptThread::process_attach_layout(new_layout_info, document.origin().clone()); + }, + NavigationType::Regular => { + let load_info = IFrameLoadInfoWithData { + info: load_info, + load_data: load_data, + old_pipeline_id: old_pipeline_id, + sandbox: sandboxed, + }; + global_scope .constellation_chan() .send(ConstellationMsg::ScriptLoadedURLInIFrame(load_info)) .unwrap(); + } } if PREFS.is_mozbrowser_enabled() { @@ -192,9 +206,10 @@ impl HTMLIFrameElement { fn process_the_iframe_attributes(&self, mode: ProcessingMode) { // TODO: srcdoc + let window = window_from_node(self); + // https://github.com/whatwg/html/issues/490 if mode == ProcessingMode::FirstTime && !self.upcast::<Element>().has_attribute(&local_name!("src")) { - let window = window_from_node(self); let event_loop = window.dom_manipulation_task_source(); let _ = event_loop.queue(box IFrameLoadEventSteps::new(self), window.upcast()); @@ -205,9 +220,15 @@ impl HTMLIFrameElement { // TODO: check ancestor browsing contexts for same URL + let creator_pipeline_id = if url.as_str() == "about:blank" { + Some(window.upcast::<GlobalScope>().pipeline_id()) + } else { + None + }; + let document = document_from_node(self); - self.navigate_or_reload_child_browsing_context( - Some(LoadData::new(url, document.get_referrer_policy(), Some(document.url()))), false); + let load_data = LoadData::new(url, creator_pipeline_id, document.get_referrer_policy(), Some(document.url())); + self.navigate_or_reload_child_browsing_context(Some(load_data), NavigationType::Regular, false); } #[allow(unsafe_code)] @@ -225,19 +246,30 @@ impl HTMLIFrameElement { // Synchronously create a new context and navigate it to about:blank. let url = ServoUrl::parse("about:blank").unwrap(); let document = document_from_node(self); - let load_data = LoadData::new(url, - document.get_referrer_policy(), - Some(document.url().clone())); - self.navigate_or_reload_child_browsing_context(Some(load_data), false); + let pipeline_id = Some(window_from_node(self).upcast::<GlobalScope>().pipeline_id()); + let load_data = LoadData::new(url, pipeline_id, document.get_referrer_policy(), Some(document.url().clone())); + self.navigate_or_reload_child_browsing_context(Some(load_data), NavigationType::InitialAboutBlank, false); } - pub fn update_pipeline_id(&self, new_pipeline_id: PipelineId) { + pub fn update_pipeline_id(&self, new_pipeline_id: PipelineId, reason: UpdatePipelineIdReason) { + if self.pending_pipeline_id.get() != Some(new_pipeline_id) && reason == UpdatePipelineIdReason::Navigation { + return; + } + self.pipeline_id.set(Some(new_pipeline_id)); - let mut blocker = self.load_blocker.borrow_mut(); - LoadBlocker::terminate(&mut blocker); + // Only terminate the load blocker if the pipeline id was updated due to a traversal. + // The load blocker will be terminated for a navigation in iframe_load_event_steps. + if reason == UpdatePipelineIdReason::Traversal { + let mut blocker = self.load_blocker.borrow_mut(); + LoadBlocker::terminate(&mut blocker); + } self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); + let window = window_from_node(self); + window.reflow(ReflowGoal::ForDisplay, + ReflowQueryType::NoQuery, + ReflowReason::FramedContentChanged); } fn new_inherited(local_name: LocalName, @@ -247,6 +279,7 @@ impl HTMLIFrameElement { htmlelement: HTMLElement::new_inherited(local_name, prefix, document), frame_id: FrameId::new(), pipeline_id: Cell::new(None), + pending_pipeline_id: Cell::new(None), sandbox: Default::default(), sandbox_allowance: Cell::new(None), load_blocker: DOMRefCell::new(None), @@ -296,7 +329,7 @@ impl HTMLIFrameElement { pub fn iframe_load_event_steps(&self, loaded_pipeline: PipelineId) { // TODO(#9592): assert that the load blocker is present at all times when we // can guarantee that it's created for the case of iframe.reload(). - if Some(loaded_pipeline) != self.pipeline_id() { return; } + if Some(loaded_pipeline) != self.pending_pipeline_id.get() { return; } // TODO A cross-origin child document would not be easily accessible // from this script thread. It's unclear how to implement @@ -330,7 +363,8 @@ impl HTMLIFrameElement { } pub trait HTMLIFrameElementLayoutMethods { - fn pipeline_id(self) -> Option<PipelineId>; + fn pipeline_id(&self) -> Option<PipelineId>; + fn frame_id(&self) -> FrameId; fn get_width(&self) -> LengthOrPercentageOrAuto; fn get_height(&self) -> LengthOrPercentageOrAuto; } @@ -338,12 +372,21 @@ pub trait HTMLIFrameElementLayoutMethods { impl HTMLIFrameElementLayoutMethods for LayoutJS<HTMLIFrameElement> { #[inline] #[allow(unsafe_code)] - fn pipeline_id(self) -> Option<PipelineId> { + fn pipeline_id(&self) -> Option<PipelineId> { unsafe { (*self.unsafe_get()).pipeline_id.get() } } + #[inline] + #[allow(unsafe_code)] + fn frame_id(&self) -> FrameId { + unsafe { + (*self.unsafe_get()).frame_id + } + } + + #[allow(unsafe_code)] fn get_width(&self) -> LengthOrPercentageOrAuto { unsafe { @@ -563,7 +606,7 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement { fn Reload(&self, _hard_reload: bool) -> ErrorResult { if self.Mozbrowser() { if self.upcast::<Node>().is_in_doc_with_browsing_context() { - self.navigate_or_reload_child_browsing_context(None, true); + self.navigate_or_reload_child_browsing_context(None, NavigationType::Regular, true); } Ok(()) } else { @@ -739,6 +782,7 @@ impl VirtualMethods for HTMLIFrameElement { // a new iframe. Without this, the constellation gets very // confused. self.pipeline_id.set(None); + self.pending_pipeline_id.set(None); } } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 31e48b5b695..81a06850757 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -61,7 +61,7 @@ use heapsize::{HeapSizeOf, heap_size_of}; use html5ever::{Prefix, Namespace, QualName}; use js::jsapi::{JSContext, JSObject, JSRuntime}; use libc::{self, c_void, uintptr_t}; -use msg::constellation_msg::PipelineId; +use msg::constellation_msg::{FrameId, PipelineId}; use ref_slice::ref_slice; use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData, SVGSVGData}; use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddress}; @@ -970,6 +970,7 @@ pub trait LayoutNodeHelpers { fn image_url(&self) -> Option<ServoUrl>; fn canvas_data(&self) -> Option<HTMLCanvasData>; fn svg_data(&self) -> Option<SVGSVGData>; + fn iframe_frame_id(&self) -> FrameId; fn iframe_pipeline_id(&self) -> PipelineId; fn opaque(&self) -> OpaqueNode; } @@ -1120,6 +1121,12 @@ impl LayoutNodeHelpers for LayoutJS<Node> { .map(|svg| svg.data()) } + fn iframe_frame_id(&self) -> FrameId { + let iframe_element = self.downcast::<HTMLIFrameElement>() + .expect("not an iframe element!"); + iframe_element.frame_id() + } + fn iframe_pipeline_id(&self) -> PipelineId { let iframe_element = self.downcast::<HTMLIFrameElement>() .expect("not an iframe element!"); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 98abc5cad74..dbcbd054743 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1537,10 +1537,10 @@ impl Window { } } + let pipeline_id = self.upcast::<GlobalScope>().pipeline_id(); self.main_thread_script_chan().send( - MainThreadScriptMsg::Navigate(self.upcast::<GlobalScope>().pipeline_id(), - LoadData::new(url, referrer_policy, Some(doc.url())), - replace)).unwrap(); + MainThreadScriptMsg::Navigate(pipeline_id, + LoadData::new(url, Some(pipeline_id), referrer_policy, Some(doc.url())), replace)).unwrap(); } pub fn handle_fire_timer(&self, timer_id: TimerEventId) { diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index dec2123149b..3d4b90eaeab 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -44,7 +44,7 @@ use dom::node::{LayoutNodeHelpers, Node}; use dom::text::Text; use gfx_traits::ByteIndex; use html5ever::{LocalName, Namespace}; -use msg::constellation_msg::PipelineId; +use msg::constellation_msg::{FrameId, PipelineId}; use range::Range; use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData}; @@ -908,6 +908,11 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { this.svg_data() } + fn iframe_frame_id(&self) -> FrameId { + let this = unsafe { self.get_jsmanaged() }; + this.iframe_frame_id() + } + fn iframe_pipeline_id(&self) -> PipelineId { let this = unsafe { self.get_jsmanaged() }; this.iframe_pipeline_id() diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 8cd6ee86222..8a861e92570 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -45,7 +45,7 @@ use dom::element::Element; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::globalscope::GlobalScope; use dom::htmlanchorelement::HTMLAnchorElement; -use dom::htmliframeelement::HTMLIFrameElement; +use dom::htmliframeelement::{HTMLIFrameElement, NavigationType}; use dom::mutationobserver::MutationObserver; use dom::node::{Node, NodeDamage, window_from_node}; use dom::serviceworker::TrustedServiceWorkerAddress; @@ -87,7 +87,7 @@ use script_runtime::{ScriptPort, StackRootTLS, get_reports, new_rt_and_cx}; use script_traits::{CompositorEvent, ConstellationControlMsg}; use script_traits::{DocumentActivity, DiscardBrowsingContext, EventResult}; use script_traits::{InitialScriptState, LayoutMsg, LoadData, MouseButton, MouseEventType, MozBrowserEvent}; -use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg}; +use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg, UpdatePipelineIdReason}; use script_traits::{ScriptThreadFactory, TimerEvent, TimerSchedulerMsg, TimerSource}; use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WindowSizeData, WindowSizeType}; use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent}; @@ -555,8 +555,8 @@ impl ScriptThreadFactory for ScriptThread { let mut failsafe = ScriptMemoryFailsafe::new(&script_thread); let origin = MutableOrigin::new(load_data.url.origin()); - let new_load = InProgressLoad::new(id, frame_id, parent_info, layout_chan, window_size, - load_data.url.clone(), origin); + let new_load = InProgressLoad::new(id, frame_id, parent_info, + layout_chan, window_size, load_data.url.clone(), origin); script_thread.start_page_load(new_load, load_data); let reporter_name = format!("script-reporter-{}", id); @@ -827,7 +827,22 @@ impl ScriptThread { FromConstellation(ConstellationControlMsg::AttachLayout( new_layout_info)) => { self.profile_event(ScriptThreadEventCategory::AttachLayout, || { - let origin = MutableOrigin::new(new_layout_info.load_data.url.origin()); + // If this is an about:blank load, it must share the creator's origin. + // This must match the logic in the constellation when creating a new pipeline + let origin = if new_layout_info.load_data.url.as_str() != "about:blank" { + MutableOrigin::new(new_layout_info.load_data.url.origin()) + } else if let Some(parent) = new_layout_info.parent_info + .and_then(|(pipeline_id, _)| self.documents.borrow() + .find_document(pipeline_id)) { + parent.origin().clone() + } else if let Some(creator) = new_layout_info.load_data.creator_pipeline_id + .and_then(|pipeline_id| self.documents.borrow() + .find_document(pipeline_id)) { + creator.origin().clone() + } else { + MutableOrigin::new(ImmutableOrigin::new_opaque()) + }; + self.handle_new_layout(new_layout_info, origin); }) } @@ -1043,10 +1058,12 @@ impl ScriptThread { event), ConstellationControlMsg::UpdatePipelineId(parent_pipeline_id, frame_id, - new_pipeline_id) => + new_pipeline_id, + reason) => self.handle_update_pipeline_id(parent_pipeline_id, frame_id, - new_pipeline_id), + new_pipeline_id, + reason), ConstellationControlMsg::FocusIFrame(parent_pipeline_id, frame_id) => self.handle_focus_iframe_msg(parent_pipeline_id, frame_id), ConstellationControlMsg::WebDriverScriptCommand(pipeline_id, msg) => @@ -1062,8 +1079,6 @@ impl ScriptThread { self.handle_frame_load_event(parent_id, frame_id, child_id), ConstellationControlMsg::DispatchStorageEvent(pipeline_id, storage, url, key, old_value, new_value) => self.handle_storage_event(pipeline_id, storage, url, key, old_value, new_value), - ConstellationControlMsg::FramedContentChanged(parent_pipeline_id, frame_id) => - self.handle_framed_content_changed(parent_pipeline_id, frame_id), ConstellationControlMsg::ReportCSSError(pipeline_id, filename, line, column, msg) => self.handle_css_error_reporting(pipeline_id, filename, line, column, msg), ConstellationControlMsg::Reload(pipeline_id) => @@ -1399,20 +1414,6 @@ impl ScriptThread { } } - fn handle_framed_content_changed(&self, - parent_pipeline_id: PipelineId, - frame_id: FrameId) { - let doc = self.documents.borrow().find_document(parent_pipeline_id).unwrap(); - let frame_element = doc.find_iframe(frame_id); - if let Some(ref frame_element) = frame_element { - frame_element.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); - let window = doc.window(); - window.reflow(ReflowGoal::ForDisplay, - ReflowQueryType::NoQuery, - ReflowReason::FramedContentChanged); - } - } - fn handle_post_message_msg(&self, pipeline_id: PipelineId, origin: Option<ImmutableOrigin>, data: Vec<u8>) { match { self.documents.borrow().find_window(pipeline_id) } { None => return warn!("postMessage after pipeline {} closed.", pipeline_id), @@ -1443,10 +1444,11 @@ impl ScriptThread { fn handle_update_pipeline_id(&self, parent_pipeline_id: PipelineId, frame_id: FrameId, - new_pipeline_id: PipelineId) { + new_pipeline_id: PipelineId, + reason: UpdatePipelineIdReason) { let frame_element = self.documents.borrow().find_iframe(parent_pipeline_id, frame_id); if let Some(frame_element) = frame_element { - frame_element.update_pipeline_id(new_pipeline_id); + frame_element.update_pipeline_id(new_pipeline_id, reason); } } @@ -2065,7 +2067,7 @@ impl ScriptThread { Some(frame_id) => { let iframe = self.documents.borrow().find_iframe(parent_pipeline_id, frame_id); if let Some(iframe) = iframe { - iframe.navigate_or_reload_child_browsing_context(Some(load_data), replace); + iframe.navigate_or_reload_child_browsing_context(Some(load_data), NavigationType::Regular, replace); } } None => { diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index 46d9bf2aadc..ddeed0d6366 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -50,6 +50,7 @@ use servo_url::ServoUrl; use std::sync::atomic::AtomicIsize; use style::data::ElementData; +#[repr(C)] pub struct PartialPersistentLayoutData { /// Data that the style system associates with a node. When the /// style system is being used standalone, this is all that hangs @@ -59,6 +60,9 @@ pub struct PartialPersistentLayoutData { /// Information needed during parallel traversals. pub parallel: DomParallelInfo, + + // Required alignment for safe transmutes between PersistentLayoutData and PartialPersistentLayoutData. + _align: [u64; 0] } impl PartialPersistentLayoutData { @@ -66,6 +70,7 @@ impl PartialPersistentLayoutData { PartialPersistentLayoutData { style_data: ElementData::new(None), parallel: DomParallelInfo::new(), + _align: [], } } } diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs index 52caf77805b..9683d049775 100644 --- a/components/script_layout_interface/wrapper_traits.rs +++ b/components/script_layout_interface/wrapper_traits.rs @@ -11,7 +11,7 @@ use SVGSVGData; use atomic_refcell::AtomicRefCell; use gfx_traits::{ByteIndex, FragmentType, combine_id_with_fragment_type}; use html5ever::{Namespace, LocalName}; -use msg::constellation_msg::PipelineId; +use msg::constellation_msg::{FrameId, PipelineId}; use range::Range; use servo_url::ServoUrl; use std::fmt::Debug; @@ -271,6 +271,10 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Debug + GetLayoutData + NodeInfo fn svg_data(&self) -> Option<SVGSVGData>; + /// If this node is an iframe element, returns its frame ID. If this node is + /// not an iframe element, fails. + fn iframe_frame_id(&self) -> FrameId; + /// 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; diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 954c1386fa2..29baf8821e6 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -134,6 +134,8 @@ pub enum LayoutControlMsg { pub struct LoadData { /// The URL. pub url: ServoUrl, + /// The creator pipeline id if this is an about:blank load. + pub creator_pipeline_id: Option<PipelineId>, /// The method. #[serde(deserialize_with = "::hyper_serde::deserialize", serialize_with = "::hyper_serde::serialize")] @@ -152,9 +154,14 @@ pub struct LoadData { impl LoadData { /// Create a new `LoadData` object. - pub fn new(url: ServoUrl, referrer_policy: Option<ReferrerPolicy>, referrer_url: Option<ServoUrl>) -> LoadData { + pub fn new(url: ServoUrl, + creator_pipeline_id: Option<PipelineId>, + referrer_policy: Option<ReferrerPolicy>, + referrer_url: Option<ServoUrl>) + -> LoadData { LoadData { url: url, + creator_pipeline_id: creator_pipeline_id, method: Method::Get, headers: Headers::new(), data: None, @@ -211,6 +218,15 @@ pub enum DocumentActivity { FullyActive, } +/// The reason why the pipeline id of an iframe is being updated. +#[derive(Copy, Clone, PartialEq, Eq, Hash, HeapSizeOf, Debug, Deserialize, Serialize)] +pub enum UpdatePipelineIdReason { + /// The pipeline id is being updated due to a navigation. + Navigation, + /// The pipeline id is being updated due to a history traversal. + Traversal, +} + /// Messages sent from the constellation or layout to the script thread. #[derive(Deserialize, Serialize)] pub enum ConstellationControlMsg { @@ -249,7 +265,7 @@ pub enum ConstellationControlMsg { MozBrowserEvent(PipelineId, Option<FrameId>, MozBrowserEvent), /// Updates the current pipeline ID of a given iframe. /// First PipelineId is for the parent, second is the new PipelineId for the frame. - UpdatePipelineId(PipelineId, FrameId, PipelineId), + UpdatePipelineId(PipelineId, FrameId, PipelineId, UpdatePipelineIdReason), /// Set an iframe to be focused. Used when an element in an iframe gains focus. /// PipelineId is for the parent, FrameId is for the actual frame. FocusIFrame(PipelineId, FrameId), @@ -274,9 +290,6 @@ pub enum ConstellationControlMsg { /// Cause a `storage` event to be dispatched at the appropriate window. /// The strings are key, old value and new value. DispatchStorageEvent(PipelineId, StorageType, ServoUrl, Option<String>, Option<String>, Option<String>), - /// Notifies a parent pipeline that one of its child frames is now active. - /// PipelineId is for the parent, FrameId is the child frame. - FramedContentChanged(PipelineId, FrameId), /// Report an error from a CSS parser for the given pipeline ReportCSSError(PipelineId, String, usize, usize, String), /// Reload the given page. @@ -312,7 +325,6 @@ impl fmt::Debug for ConstellationControlMsg { WebFontLoaded(..) => "WebFontLoaded", DispatchFrameLoadEvent { .. } => "DispatchFrameLoadEvent", DispatchStorageEvent(..) => "DispatchStorageEvent", - FramedContentChanged(..) => "FramedContentChanged", ReportCSSError(..) => "ReportCSSError", Reload(..) => "Reload", WebVREvents(..) => "WebVREvents", diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 47a7b103c8c..0402e3ddad6 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -34,8 +34,8 @@ use webrender_traits::ClipId; pub enum LayoutMsg { /// Indicates whether this pipeline is currently running animations. ChangeRunningAnimationsState(PipelineId, AnimationState), - /// Inform the constellation of the size of the pipeline's viewport. - FrameSizes(Vec<(PipelineId, TypedSize2D<f32, CSSPixel>)>), + /// Inform the constellation of the size of the frame's viewport. + FrameSizes(Vec<(FrameId, TypedSize2D<f32, CSSPixel>)>), /// Requests that the constellation inform the compositor of the a cursor change. SetCursor(Cursor), /// Notifies the constellation that the viewport has been constrained in some manner @@ -120,8 +120,8 @@ pub enum ScriptMsg { VisibilityChangeComplete(PipelineId, bool), /// A load has been requested in an IFrame. ScriptLoadedURLInIFrame(IFrameLoadInfoWithData), - /// A load of `about:blank` has been completed in an IFrame. - ScriptLoadedAboutBlankInIFrame(IFrameLoadInfo, IpcSender<LayoutControlMsg>), + /// A load of the initial `about:blank` has been completed in an IFrame. + ScriptNewIFrame(IFrameLoadInfo, IpcSender<LayoutControlMsg>), /// Requests that the constellation set the contents of the clipboard SetClipboardContents(String), /// Mark a new document as active diff --git a/components/style/attr.rs b/components/style/attr.rs index 101810212b7..bbf8d53a430 100644 --- a/components/style/attr.rs +++ b/components/style/attr.rs @@ -375,7 +375,7 @@ impl ::std::ops::Deref for AttrValue { pub fn parse_nonzero_length(value: &str) -> LengthOrPercentageOrAuto { match parse_length(value) { LengthOrPercentageOrAuto::Length(x) if x == Au::zero() => LengthOrPercentageOrAuto::Auto, - LengthOrPercentageOrAuto::Percentage(0.) => LengthOrPercentageOrAuto::Auto, + LengthOrPercentageOrAuto::Percentage(x) if x == 0. => LengthOrPercentageOrAuto::Auto, x => x, } } diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs index 8376587d5ac..ad964b4b21d 100644 --- a/components/style/build_gecko.rs +++ b/components/style/build_gecko.rs @@ -153,6 +153,15 @@ mod bindings { } if cfg!(target_os = "linux") { builder = builder.clang_arg("-DOS_LINUX=1"); + // We may be cross-compiling with a clang that defaults to + // a different architecture, so we should explicitly specify + // the bitness being used here. Specifying --target instead + // leads to difficulties with LLVM search paths. + if cfg!(target_arch = "x86") { + builder = builder.clang_arg("-m32") + } else if cfg!(target_arch = "x86_64") { + builder = builder.clang_arg("-m64") + } } else if cfg!(target_os = "solaris") { builder = builder.clang_arg("-DOS_SOLARIS=1"); } else if cfg!(target_os = "dragonfly") { diff --git a/components/style/element_state.rs b/components/style/element_state.rs index 1c94580554b..30e67060f3f 100644 --- a/components/style/element_state.rs +++ b/components/style/element_state.rs @@ -115,5 +115,9 @@ bitflags! { const IN_HANDLER_VULNERABLE_NO_UPDATE_STATE = 1 << 42, /// https://drafts.csswg.org/selectors-4/#the-focus-within-pseudo const IN_FOCUS_WITHIN_STATE = 1 << 43, + /// Non-standard & undocumented. + const IN_AUTOFILL_STATE = 1 << 50, + /// Non-standard & undocumented. + const IN_AUTOFILL_PREVIEW_STATE = 1 << 51, } } diff --git a/components/style/gecko/generated/bindings.rs b/components/style/gecko/generated/bindings.rs index c365ff677a1..13fe500e0c4 100644 --- a/components/style/gecko/generated/bindings.rs +++ b/components/style/gecko/generated/bindings.rs @@ -250,16 +250,16 @@ pub type RawServoSupportsRuleBorrowed<'a> = &'a RawServoSupportsRule; pub type RawServoSupportsRuleBorrowedOrNull<'a> = Option<&'a RawServoSupportsRule>; enum RawServoSupportsRuleVoid { } pub struct RawServoSupportsRule(RawServoSupportsRuleVoid); -pub type RawServoRuleNodeStrong = ::gecko_bindings::sugar::ownership::Strong<RawServoRuleNode>; -pub type RawServoRuleNodeBorrowed<'a> = &'a RawServoRuleNode; -pub type RawServoRuleNodeBorrowedOrNull<'a> = Option<&'a RawServoRuleNode>; -enum RawServoRuleNodeVoid { } -pub struct RawServoRuleNode(RawServoRuleNodeVoid); pub type RawServoDocumentRuleStrong = ::gecko_bindings::sugar::ownership::Strong<RawServoDocumentRule>; pub type RawServoDocumentRuleBorrowed<'a> = &'a RawServoDocumentRule; pub type RawServoDocumentRuleBorrowedOrNull<'a> = Option<&'a RawServoDocumentRule>; enum RawServoDocumentRuleVoid { } pub struct RawServoDocumentRule(RawServoDocumentRuleVoid); +pub type RawServoRuleNodeStrong = ::gecko_bindings::sugar::ownership::Strong<RawServoRuleNode>; +pub type RawServoRuleNodeBorrowed<'a> = &'a RawServoRuleNode; +pub type RawServoRuleNodeBorrowedOrNull<'a> = Option<&'a RawServoRuleNode>; +enum RawServoRuleNodeVoid { } +pub struct RawServoRuleNode(RawServoRuleNodeVoid); pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned<RawServoStyleSet>; pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<RawServoStyleSet>; pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet; @@ -422,16 +422,16 @@ extern "C" { pub fn Servo_SupportsRule_Release(ptr: RawServoSupportsRuleBorrowed); } extern "C" { - pub fn Servo_RuleNode_AddRef(ptr: RawServoRuleNodeBorrowed); + pub fn Servo_DocumentRule_AddRef(ptr: RawServoDocumentRuleBorrowed); } extern "C" { - pub fn Servo_RuleNode_Release(ptr: RawServoRuleNodeBorrowed); + pub fn Servo_DocumentRule_Release(ptr: RawServoDocumentRuleBorrowed); } extern "C" { - pub fn Servo_DocumentRule_AddRef(ptr: RawServoDocumentRuleBorrowed); + pub fn Servo_RuleNode_AddRef(ptr: RawServoRuleNodeBorrowed); } extern "C" { - pub fn Servo_DocumentRule_Release(ptr: RawServoDocumentRuleBorrowed); + pub fn Servo_RuleNode_Release(ptr: RawServoRuleNodeBorrowed); } extern "C" { pub fn Servo_StyleSet_Drop(ptr: RawServoStyleSetOwned); @@ -1588,6 +1588,9 @@ extern "C" { -> bool; } extern "C" { + pub fn Gecko_SetJemallocThreadLocalArena(enabled: bool); +} +extern "C" { pub fn Servo_Element_ClearData(node: RawGeckoElementBorrowed); } extern "C" { diff --git a/components/style/gecko/global_style_data.rs b/components/style/gecko/global_style_data.rs index b1f62b0eac0..3cbace9b90a 100644 --- a/components/style/gecko/global_style_data.rs +++ b/components/style/gecko/global_style_data.rs @@ -6,6 +6,7 @@ use context::StyleSystemOptions; use gecko_bindings::bindings::{Gecko_RegisterProfilerThread, Gecko_UnregisterProfilerThread}; +use gecko_bindings::bindings::Gecko_SetJemallocThreadLocalArena; use num_cpus; use rayon; use shared_lock::SharedRwLock; @@ -33,6 +34,9 @@ fn thread_name(index: usize) -> String { } fn thread_startup(index: usize) { + unsafe { + Gecko_SetJemallocThreadLocalArena(true); + } let name = thread_name(index); let name = CString::new(name).unwrap(); unsafe { @@ -44,6 +48,7 @@ fn thread_startup(index: usize) { fn thread_shutdown(_: usize) { unsafe { Gecko_UnregisterProfilerThread(); + Gecko_SetJemallocThreadLocalArena(false); } } diff --git a/components/style/gecko/non_ts_pseudo_class_list.rs b/components/style/gecko/non_ts_pseudo_class_list.rs index 4d9b91384a1..145126656c2 100644 --- a/components/style/gecko/non_ts_pseudo_class_list.rs +++ b/components/style/gecko/non_ts_pseudo_class_list.rs @@ -38,7 +38,9 @@ * possible. * * $gecko_type can be either "_" or an ident in Gecko's CSSPseudoClassType. - * $state can be either "_" or an expression of type ElementState. + * $state can be either "_" or an expression of type ElementState. If present, + * the semantics are that the pseudo-class matches if any of the bits in + * $state are set on the element. * $flags can be either "_" or an expression of type NonTSPseudoClassFlag, * see selector_parser.rs for more details. */ @@ -73,6 +75,8 @@ macro_rules! apply_non_ts_list { ("-moz-broken", MozBroken, mozBroken, IN_BROKEN_STATE, _), ("-moz-loading", MozLoading, mozLoading, IN_LOADING_STATE, _), ("-moz-suppressed", MozSuppressed, mozSuppressed, IN_SUPPRESSED_STATE, PSEUDO_CLASS_INTERNAL), + ("-moz-autofill", MozAutofill, mozAutofill, IN_AUTOFILL_STATE, PSEUDO_CLASS_INTERNAL), + ("-moz-autofill-preview", MozAutofillPreview, mozAutofillPreview, IN_AUTOFILL_PREVIEW_STATE, PSEUDO_CLASS_INTERNAL), ("-moz-handler-clicktoplay", MozHandlerClickToPlay, mozHandlerClickToPlay, IN_HANDLER_CLICK_TO_PLAY_STATE, PSEUDO_CLASS_INTERNAL), ("-moz-handler-vulnerable-updatable", MozHandlerVulnerableUpdatable, mozHandlerVulnerableUpdatable, IN_HANDLER_VULNERABLE_UPDATABLE_STATE, PSEUDO_CLASS_INTERNAL), diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 5461bd7768e..a14348f4914 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -406,6 +406,12 @@ impl<'le> GeckoElement<'le> { }, } } + + fn may_have_animations(&self) -> bool { + use gecko_bindings::structs::nsINode_BooleanFlag; + self.as_node().bool_flags() & + (1u32 << nsINode_BooleanFlag::ElementHasAnimations as u32) != 0 + } } /// Converts flags from the layout used by rust-selectors to the layout used @@ -764,15 +770,15 @@ impl<'le> TElement for GeckoElement<'le> { } fn has_animations(&self) -> bool { - unsafe { Gecko_ElementHasAnimations(self.0) } + self.may_have_animations() && unsafe { Gecko_ElementHasAnimations(self.0) } } fn has_css_animations(&self) -> bool { - unsafe { Gecko_ElementHasCSSAnimations(self.0) } + self.may_have_animations() && unsafe { Gecko_ElementHasCSSAnimations(self.0) } } fn has_css_transitions(&self) -> bool { - unsafe { Gecko_ElementHasCSSTransitions(self.0) } + self.may_have_animations() && unsafe { Gecko_ElementHasCSSTransitions(self.0) } } fn get_css_transitions_info(&self) @@ -1174,7 +1180,9 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { NonTSPseudoClass::MozUIInvalid | NonTSPseudoClass::MozMeterOptimum | NonTSPseudoClass::MozMeterSubOptimum | - NonTSPseudoClass::MozMeterSubSubOptimum => { + NonTSPseudoClass::MozMeterSubSubOptimum | + NonTSPseudoClass::MozAutofill | + NonTSPseudoClass::MozAutofillPreview => { // NB: It's important to use `intersect` instead of `contains` // here, to handle `:any-link` correctly. self.get_state().intersects(pseudo_class.state_flag()) diff --git a/components/style/properties/data.py b/components/style/properties/data.py index eb1706e691e..8bb1fc86988 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -18,7 +18,8 @@ SYSTEM_FONT_LONGHANDS = """font_family font_size font_style font_variant_position font_weight font_size_adjust font_variant_alternates font_variant_ligatures font_variant_east_asian - font_variant_numeric font_language_override""".split() + font_variant_numeric font_language_override + font_feature_settings""".split() def maybe_moz_logical_alias(product, side, prop): diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index f83757fb5e8..6691603499f 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -22,7 +22,7 @@ impl ToCss for SpecifiedValue { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { - SpecifiedValue::Value(v) => v.to_css(dest), + SpecifiedValue::Value(ref v) => v.to_css(dest), SpecifiedValue::System(_) => Ok(()) } } @@ -47,17 +47,17 @@ fn to_computed_value(&self, _context: &Context) -> computed_value::T { match *self { - SpecifiedValue::Value(v) => v, + SpecifiedValue::Value(ref v) => v.clone(), SpecifiedValue::System(_) => { <%self:nongecko_unreachable> - _context.cached_system_font.as_ref().unwrap().${name} + _context.cached_system_font.as_ref().unwrap().${name}.clone() </%self:nongecko_unreachable> } } } fn from_computed_value(other: &computed_value::T) -> Self { - SpecifiedValue::Value(*other) + SpecifiedValue::Value(other.clone()) } } </%def> @@ -337,14 +337,14 @@ ${helpers.single_keyword_system("font-style", <% font_variant_caps_custom_consts= { "small-caps": "SMALLCAPS", - "all-small": "ALLSMALL", + "all-small-caps": "ALLSMALL", "petite-caps": "PETITECAPS", - "all-petite": "ALLPETITE", + "all-petite-caps": "ALLPETITE", "titling-caps": "TITLING" } %> ${helpers.single_keyword_system("font-variant-caps", "normal small-caps", - extra_gecko_values="all-small petite-caps unicase titling-caps", + extra_gecko_values="all-small-caps petite-caps all-petite-caps unicase titling-caps", gecko_constant_prefix="NS_FONT_VARIANT_CAPS", gecko_ffi_name="mFont.variantCaps", spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-caps", @@ -891,9 +891,10 @@ ${helpers.single_keyword_system("font-variant-caps", } } + #[allow(unused_mut)] pub fn cascade_specified_font_size(context: &mut Context, specified_value: &SpecifiedValue, - computed: Au, + mut computed: Au, parent: &Font) { if let SpecifiedValue::Keyword(kw, fraction) = *specified_value { @@ -914,6 +915,22 @@ ${helpers.single_keyword_system("font-variant-caps", context.mutate_style().font_size_keyword = None; } + // we could use clone_language and clone_font_family() here but that's + // expensive. Do it only in gecko mode for now. + % if product == "gecko": + use gecko_bindings::structs::nsIAtom; + // if the language or generic changed, we need to recalculate + // the font size from the stored font-size origin information. + if context.style().get_font().gecko().mLanguage.raw::<nsIAtom>() != + context.inherited_style().get_font().gecko().mLanguage.raw::<nsIAtom>() || + context.style().get_font().gecko().mGenericID != + context.inherited_style().get_font().gecko().mGenericID { + if let Some((kw, ratio)) = context.style().font_size_keyword { + computed = kw.to_computed_value(context).scale_by(ratio); + } + } + % endif + let parent_unconstrained = context.mutate_style() .mutate_font() .apply_font_size(computed, @@ -1760,17 +1777,24 @@ ${helpers.single_keyword_system("font-variant-position", spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-position", animation_value_type="none")} -<%helpers:longhand name="font-feature-settings" products="gecko" animation_value_type="none" extra_prefixes="moz" +<%helpers:longhand name="font-feature-settings" products="gecko" animation_value_type="none" + extra_prefixes="moz" boxed="True" spec="https://drafts.csswg.org/css-fonts/#propdef-font-feature-settings"> + use properties::longhands::system_font::SystemFont; use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; use values::computed::ComputedValueAsSpecified; - pub use self::computed_value::T as SpecifiedValue; - impl ComputedValueAsSpecified for SpecifiedValue {} + #[derive(Debug, Clone, PartialEq)] + pub enum SpecifiedValue { + Value(computed_value::T), + System(SystemFont) + } no_viewport_percentage!(SpecifiedValue); + <%self:simple_system_boilerplate name="font_feature_settings"></%self:simple_system_boilerplate> + pub mod computed_value { use cssparser::Parser; use parser::{Parse, ParserContext}; @@ -1874,13 +1898,18 @@ ${helpers.single_keyword_system("font-variant-position", computed_value::T::Normal } + #[inline] + pub fn get_initial_specified_value() -> SpecifiedValue { + SpecifiedValue::Value(computed_value::T::Normal) + } + /// normal | <feature-tag-value># pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { if input.try(|input| input.expect_ident_matching("normal")).is_ok() { - Ok(computed_value::T::Normal) + Ok(SpecifiedValue::Value(computed_value::T::Normal)) } else { input.parse_comma_separated(|i| computed_value::FeatureTagValue::parse(context, i)) - .map(computed_value::T::Tag) + .map(computed_value::T::Tag).map(SpecifiedValue::Value) } } </%helpers:longhand> @@ -2373,6 +2402,7 @@ ${helpers.single_keyword("-moz-math-variant", % endfor font_language_override: longhands::font_language_override::computed_value ::T(system.languageOverride), + font_feature_settings: longhands::font_feature_settings::get_initial_value(), system_font: *self, }; unsafe { bindings::Gecko_nsFont_Destroy(&mut system); } diff --git a/components/style/properties/shorthand/font.mako.rs b/components/style/properties/shorthand/font.mako.rs index f82aea164cc..409e0717013 100644 --- a/components/style/properties/shorthand/font.mako.rs +++ b/components/style/properties/shorthand/font.mako.rs @@ -15,7 +15,8 @@ ${'font-variant-ligatures' if product == 'gecko' or data.testing else ''} ${'font-variant-numeric' if product == 'gecko' or data.testing else ''} ${'font-variant-position' if product == 'gecko' or data.testing else ''} - ${'font-language-override' if product == 'gecko' or data.testing else ''}" + ${'font-language-override' if product == 'gecko' or data.testing else ''} + ${'font-feature-settings' if product == 'gecko' or data.testing else ''}" spec="https://drafts.csswg.org/css-fonts-3/#propdef-font"> use properties::longhands::{font_family, font_style, font_weight, font_stretch}; use properties::longhands::{font_size, line_height, font_variant_caps}; @@ -25,7 +26,7 @@ gecko_sub_properties = "kerning language_override size_adjust \ variant_alternates variant_east_asian \ variant_ligatures variant_numeric \ - variant_position".split() + variant_position feature_settings".split() %> % if product == "gecko" or data.testing: % for prop in gecko_sub_properties: diff --git a/components/style/restyle_hints.rs b/components/style/restyle_hints.rs index b90dc0350fc..539ddb41561 100644 --- a/components/style/restyle_hints.rs +++ b/components/style/restyle_hints.rs @@ -343,7 +343,7 @@ impl<'a, E> Element for ElementWrapper<'a, E> &mut |_, _| {}) } match self.snapshot().and_then(|s| s.state()) { - Some(snapshot_state) => snapshot_state.contains(flag), + Some(snapshot_state) => snapshot_state.intersects(flag), None => { self.element.match_non_ts_pseudo_class(pseudo_class, relations, diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 0312c601df9..5addd13be6d 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -221,8 +221,9 @@ impl LengthOrPercentage { pub fn is_definitely_zero(&self) -> bool { use self::LengthOrPercentage::*; match *self { - Length(Au(0)) | Percentage(0.0) => true, - Length(_) | Percentage(_) | Calc(_) => false + Length(Au(0)) => true, + Percentage(p) => p == 0.0, + Length(_) | Calc(_) => false } } @@ -312,8 +313,9 @@ impl LengthOrPercentageOrAuto { pub fn is_definitely_zero(&self) -> bool { use self::LengthOrPercentageOrAuto::*; match *self { - Length(Au(0)) | Percentage(0.0) => true, - Length(_) | Percentage(_) | Calc(_) | Auto => false + Length(Au(0)) => true, + Percentage(p) => p == 0.0, + Length(_) | Calc(_) | Auto => false } } } diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index 5c8845a5605..2062786adf8 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -266,14 +266,13 @@ pub enum AbsoluteLength { impl AbsoluteLength { fn is_zero(&self) -> bool { match *self { - AbsoluteLength::Px(0.) - | AbsoluteLength::In(0.) - | AbsoluteLength::Cm(0.) - | AbsoluteLength::Mm(0.) - | AbsoluteLength::Q(0.) - | AbsoluteLength::Pt(0.) - | AbsoluteLength::Pc(0.) => true, - _ => false, + AbsoluteLength::Px(v) + | AbsoluteLength::In(v) + | AbsoluteLength::Cm(v) + | AbsoluteLength::Mm(v) + | AbsoluteLength::Q(v) + | AbsoluteLength::Pt(v) + | AbsoluteLength::Pc(v) => v == 0., } } } diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs index 210c5b0f9c8..250ad21813b 100644 --- a/components/webdriver_server/lib.rs +++ b/components/webdriver_server/lib.rs @@ -357,7 +357,7 @@ impl Handler { let (sender, receiver) = ipc::channel().unwrap(); - let load_data = LoadData::new(url, None, None); + let load_data = LoadData::new(url, Some(pipeline_id), None, None); let cmd_msg = WebDriverCommandMsg::LoadUrl(pipeline_id, load_data, sender.clone()); self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap(); diff --git a/python/servo/devenv_commands.py b/python/servo/devenv_commands.py index 314c5c2b8c1..f7df09ce754 100644 --- a/python/servo/devenv_commands.py +++ b/python/servo/devenv_commands.py @@ -226,11 +226,23 @@ class MachCommands(CommandBase): env=self.build_env()) @Command('rustup', - description='Update the Rust version to latest master', + description='Update the Rust version to latest Nightly', category='devenv') - def rustup(self): - url = "https://api.github.com/repos/rust-lang/rust/git/refs/heads/master" - commit = json.load(urllib2.urlopen(url))["object"]["sha"] + @CommandArgument('--master', + action='store_true', + help='Use the latest commit of the "master" branch') + def rustup(self, master=False): + if master: + url = "https://api.github.com/repos/rust-lang/rust/git/refs/heads/master" + commit = json.load(urllib2.urlopen(url))["object"]["sha"] + else: + import toml + import re + url = "https://static.rust-lang.org/dist/channel-rust-nightly.toml" + version = toml.load(urllib2.urlopen(url))["pkg"]["rustc"]["version"] + short_commit = re.search("\(([0-9a-f]+) ", version).group(1) + url = "https://api.github.com/repos/rust-lang/rust/commits/" + short_commit + commit = json.load(urllib2.urlopen(url))["sha"] filename = path.join(self.context.topdir, "rust-commit-hash") with open(filename, "w") as f: f.write(commit + "\n") diff --git a/tests/unit/layout/Cargo.toml b/tests/unit/layout/Cargo.toml index 283964447d2..d0c5024a73e 100644 --- a/tests/unit/layout/Cargo.toml +++ b/tests/unit/layout/Cargo.toml @@ -10,4 +10,6 @@ path = "lib.rs" doctest = false [dependencies] +atomic_refcell = "0.1" layout = {path = "../../../components/layout"} +script_layout_interface = {path = "../../../components/script_layout_interface"} diff --git a/tests/unit/layout/align_of.rs b/tests/unit/layout/align_of.rs new file mode 100644 index 00000000000..fe13b8fed94 --- /dev/null +++ b/tests/unit/layout/align_of.rs @@ -0,0 +1,26 @@ +/* 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 atomic_refcell::AtomicRefCell; +use layout::PersistentLayoutData; +use script_layout_interface::PartialPersistentLayoutData; +use std::mem::align_of; + +fn check_layout_alignment(expected: usize, current: usize) { + if current != expected { + panic!("Your changes have altered the mem alignment of the PartialPersistentLayoutData \ + struct to {}, but it must match the {}-alignment of PersistentLayoutData struct. \ + Please fix alignment in components/script_layout_interface/lib.rs", + current, expected); + } +} + +#[test] +fn test_persistent_layout_data_alignment() { + check_layout_alignment(align_of::<PersistentLayoutData>(), + align_of::<PartialPersistentLayoutData>()); + + check_layout_alignment(align_of::<AtomicRefCell<PersistentLayoutData>>(), + align_of::<AtomicRefCell<PartialPersistentLayoutData>>()); +} diff --git a/tests/unit/layout/lib.rs b/tests/unit/layout/lib.rs index 59092bf4d9a..12091f920d6 100644 --- a/tests/unit/layout/lib.rs +++ b/tests/unit/layout/lib.rs @@ -2,6 +2,9 @@ * 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/. */ +extern crate atomic_refcell; extern crate layout; +extern crate script_layout_interface; +#[cfg(test)] mod align_of; #[cfg(all(test, target_pointer_width = "64"))] mod size_of; diff --git a/tests/unit/style/parsing/font.rs b/tests/unit/style/parsing/font.rs index 4513f79ce98..607f0ecb967 100644 --- a/tests/unit/style/parsing/font.rs +++ b/tests/unit/style/parsing/font.rs @@ -4,6 +4,7 @@ use parsing::parse; use style::properties::longhands::{font_feature_settings, font_weight}; +use style::properties::longhands::font_feature_settings::SpecifiedValue; use style::properties::longhands::font_feature_settings::computed_value; use style::properties::longhands::font_feature_settings::computed_value::FeatureTagValue; use style_traits::ToCss; @@ -14,7 +15,7 @@ fn font_feature_settings_should_parse_properly() { use std::io::Cursor; let normal = parse_longhand!(font_feature_settings, "normal"); - let normal_computed = computed_value::T::Normal; + let normal_computed = SpecifiedValue::Value(computed_value::T::Normal); assert_eq!(normal, normal_computed); let mut a_d_bytes = Cursor::new(b"abcd"); @@ -24,34 +25,34 @@ fn font_feature_settings_should_parse_properly() { let efgh = e_h_bytes.read_u32::<BigEndian>().unwrap(); let on = parse_longhand!(font_feature_settings, "\"abcd\" on"); - let on_computed = computed_value::T::Tag(vec![ + let on_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ FeatureTagValue { tag: abcd, value: 1 } - ]); + ])); assert_eq!(on, on_computed); let off = parse_longhand!(font_feature_settings, "\"abcd\" off"); - let off_computed = computed_value::T::Tag(vec![ + let off_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ FeatureTagValue { tag: abcd, value: 0 } - ]); + ])); assert_eq!(off, off_computed); let no_value = parse_longhand!(font_feature_settings, "\"abcd\""); - let no_value_computed = computed_value::T::Tag(vec![ + let no_value_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ FeatureTagValue { tag: abcd, value: 1 } - ]); + ])); assert_eq!(no_value, no_value_computed); let pos_integer = parse_longhand!(font_feature_settings, "\"abcd\" 100"); - let pos_integer_computed = computed_value::T::Tag(vec![ + let pos_integer_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ FeatureTagValue { tag: abcd, value: 100 } - ]); + ])); assert_eq!(pos_integer, pos_integer_computed); let multiple = parse_longhand!(font_feature_settings, "\"abcd\" off, \"efgh\""); - let multiple_computed = computed_value::T::Tag(vec![ + let multiple_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ FeatureTagValue { tag: abcd, value: 0 }, FeatureTagValue { tag: efgh, value: 1 } - ]); + ])); assert_eq!(multiple, multiple_computed); } diff --git a/tests/unit/style/properties/serialization.rs b/tests/unit/style/properties/serialization.rs index f164b656ce1..426597e56b4 100644 --- a/tests/unit/style/properties/serialization.rs +++ b/tests/unit/style/properties/serialization.rs @@ -653,7 +653,8 @@ mod shorthand_serialization { font-kerning: auto; \ font-variant-caps: normal; \ font-variant-position: normal; \ - font-language-override: normal;"; + font-language-override: normal; \ + font-feature-settings: normal;"; let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap(); diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 90d74745236..24d4a7ee7da 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -331418,6 +331418,12 @@ {} ] ], + "html/semantics/embedded-content/the-iframe-element/content_document_changes_only_after_load_matures.html": [ + [ + "/html/semantics/embedded-content/the-iframe-element/content_document_changes_only_after_load_matures.html", + {} + ] + ], "html/semantics/embedded-content/the-iframe-element/cross_origin_parentage.html": [ [ "/html/semantics/embedded-content/the-iframe-element/cross_origin_parentage.html", @@ -570683,6 +570689,10 @@ "56df0cb79a1af927a0209c0bbbb5edb25ccaee5f", "testharness" ], + "html/semantics/embedded-content/the-iframe-element/content_document_changes_only_after_load_matures.html": [ + "46708fc218e559fba7049a36888a7c8a24c22672", + "testharness" + ], "html/semantics/embedded-content/the-iframe-element/cross_origin_child.html": [ "a42082bb612b280eda5aa598ed750cfce3edd537", "support" diff --git a/tests/wpt/mozilla/meta/css/matchMedia.html.ini b/tests/wpt/mozilla/meta/css/matchMedia.html.ini index 8c726be5a03..dded0e3276d 100644 --- a/tests/wpt/mozilla/meta/css/matchMedia.html.ini +++ b/tests/wpt/mozilla/meta/css/matchMedia.html.ini @@ -1,4 +1,5 @@ [matchMedia.html] + disabled: true type: testharness [window.matchMedia exists] expected: FAIL diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-iframe-element/content_document_changes_only_after_load_matures.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-iframe-element/content_document_changes_only_after_load_matures.html new file mode 100644 index 00000000000..2cb85700230 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-iframe-element/content_document_changes_only_after_load_matures.html @@ -0,0 +1,21 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Iframe's contentDocument should only change after its pending load has matured.</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body></body> +<script> +async_test(function(t) { + var iframe = document.createElement("iframe"); + document.body.appendChild(iframe); + iframe.onload = t.step_func(function() { + assert_true(iframe.contentDocument.location.toString().includes("support/blank.htm")); + t.done(); + }); + + assert_equals(iframe.contentDocument.location.toString(), "about:blank"); + iframe.src = "support/blank.htm?pipe=trickle(d2)"; + // The location of the contentDocument should not change until the new document has matured. + assert_equals(iframe.contentDocument.location.toString(), "about:blank"); +}, "contentDocument should only change after a load matures."); +</script> |