diff options
Diffstat (limited to 'components')
60 files changed, 796 insertions, 476 deletions
diff --git a/components/bluetooth/lib.rs b/components/bluetooth/lib.rs index 5b24690ddd6..0207c9e6f74 100644 --- a/components/bluetooth/lib.rs +++ b/components/bluetooth/lib.rs @@ -424,10 +424,15 @@ impl BluetoothManager { adapter: &mut BluetoothAdapter, device_id: &str) -> Vec<BluetoothGATTService> { - let services = match self.get_device(adapter, device_id) { + let mut services = match self.get_device(adapter, device_id) { Some(d) => d.get_gatt_services().unwrap_or(vec!()), None => vec!(), }; + + services.retain(|s| !uuid_is_blocklisted(&s.get_uuid().unwrap_or(String::new()), Blocklist::All) && + self.allowed_services + .get(device_id) + .map_or(false, |uuids| uuids.contains(&s.get_uuid().unwrap_or(String::new())))); for service in &services { self.cached_services.insert(service.get_id(), service.clone()); self.service_to_device.insert(service.get_id(), device_id.to_owned()); @@ -461,11 +466,12 @@ impl BluetoothManager { adapter: &mut BluetoothAdapter, service_id: &str) -> Vec<BluetoothGATTCharacteristic> { - let characteristics = match self.get_gatt_service(adapter, service_id) { + let mut characteristics = match self.get_gatt_service(adapter, service_id) { Some(s) => s.get_gatt_characteristics().unwrap_or(vec!()), None => vec!(), }; + characteristics.retain(|c| !uuid_is_blocklisted(&c.get_uuid().unwrap_or(String::new()), Blocklist::All)); for characteristic in &characteristics { self.cached_characteristics.insert(characteristic.get_id(), characteristic.clone()); self.characteristic_to_service.insert(characteristic.get_id(), service_id.to_owned()); @@ -524,11 +530,12 @@ impl BluetoothManager { adapter: &mut BluetoothAdapter, characteristic_id: &str) -> Vec<BluetoothGATTDescriptor> { - let descriptors = match self.get_gatt_characteristic(adapter, characteristic_id) { + let mut descriptors = match self.get_gatt_characteristic(adapter, characteristic_id) { Some(c) => c.get_gatt_descriptors().unwrap_or(vec!()), None => vec!(), }; + descriptors.retain(|d| !uuid_is_blocklisted(&d.get_uuid().unwrap_or(String::new()), Blocklist::All)); for descriptor in &descriptors { self.cached_descriptors.insert(descriptor.get_id(), descriptor.clone()); self.descriptor_to_characteristic.insert(descriptor.get_id(), characteristic_id.to_owned()); @@ -743,10 +750,6 @@ impl BluetoothManager { } } } - services_vec.retain(|s| !uuid_is_blocklisted(&s.uuid, Blocklist::All) && - self.allowed_services - .get(&device_id) - .map_or(false, |uuids| uuids.contains(&s.uuid))); // Step 7. if services_vec.is_empty() { @@ -919,7 +922,6 @@ impl BluetoothManager { ); } } - characteristics_vec.retain(|c| !uuid_is_blocklisted(&c.uuid, Blocklist::All)); // Step 7. if characteristics_vec.is_empty() { @@ -987,7 +989,6 @@ impl BluetoothManager { ); } } - descriptors_vec.retain(|d| !uuid_is_blocklisted(&d.uuid, Blocklist::All)); // Step 7. if descriptors_vec.is_empty() { diff --git a/components/bluetooth/test.rs b/components/bluetooth/test.rs index 8578db79aa5..e2c6e639e82 100644 --- a/components/bluetooth/test.rs +++ b/components/bluetooth/test.rs @@ -99,7 +99,7 @@ const SERIAL_NUMBER_STRING_UUID: &'static str = "00002a25-0000-1000-8000-00805f9 // Descriptor UUIDs const BLOCKLIST_EXCLUDE_READS_DESCRIPTOR_UUID: &'static str = "aaaaaaaa-aaaa-1181-0510-810819516110"; -const BLOCKLIST_DESCRIPTOR_UUID: &'static str = "07711111-6104-0970-7011-1107105110aaa"; +const BLOCKLIST_DESCRIPTOR_UUID: &'static str = "07711111-6104-0970-7011-1107105110aa"; // https://www.bluetooth.com/specifications/gatt/ // viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_user_description.xml const CHARACTERISTIC_USER_DESCRIPTION_UUID: &'static str = "00002901-0000-1000-8000-00805f9b34fb"; diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 8f0c12e5bf7..1fc3a5b27f5 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -39,7 +39,7 @@ use util::geometry::ScreenPx; use util::opts; use util::prefs::PREFS; use webrender; -use webrender_traits::{self, ScrollEventPhase}; +use webrender_traits::{self, ScrollEventPhase, ServoScrollRootId}; use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg}; #[derive(Debug, PartialEq)] @@ -493,9 +493,9 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.title_for_main_frame(); } - (Msg::ScrollFragmentPoint(pipeline_id, point, _), + (Msg::ScrollFragmentPoint(pipeline_id, scroll_root_id, point, _), ShutdownState::NotShuttingDown) => { - self.scroll_fragment_to_point(pipeline_id, point); + self.scroll_fragment_to_point(pipeline_id, scroll_root_id, point); } (Msg::MoveTo(point), @@ -761,9 +761,13 @@ impl<Window: WindowMethods> IOCompositor<Window> { } fn scroll_fragment_to_point(&mut self, - _pipeline_id: PipelineId, - _point: Point2D<f32>) { - println!("TODO: Support scroll_fragment_to_point again"); + pipeline_id: PipelineId, + scroll_root_id: ScrollRootId, + point: Point2D<f32>) { + self.webrender_api.scroll_layers_with_scroll_root_id( + point, + pipeline_id.to_webrender(), + ServoScrollRootId(scroll_root_id.0)); } fn handle_window_message(&mut self, event: WindowEvent) { diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs index f8f35e995d7..0a7962c7917 100644 --- a/components/compositing/compositor_thread.rs +++ b/components/compositing/compositor_thread.rs @@ -8,6 +8,7 @@ use SendableFrameTree; use compositor::CompositingReason; use euclid::point::Point2D; use euclid::size::Size2D; +use gfx_traits::ScrollRootId; use ipc_channel::ipc::IpcSender; use msg::constellation_msg::{Key, KeyModifiers, KeyState, PipelineId}; use net_traits::image::base::Image; @@ -72,7 +73,7 @@ pub enum Msg { ShutdownComplete, /// Scroll a page in a window - ScrollFragmentPoint(PipelineId, Point2D<f32>, bool), + ScrollFragmentPoint(PipelineId, ScrollRootId, Point2D<f32>, bool), /// Alerts the compositor that the current page has changed its title. ChangePageTitle(PipelineId, Option<String>), /// Alerts the compositor that the current page has changed its URL. diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 19e70c90bfc..c64e3ee3811 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -1038,8 +1038,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.handle_alert(pipeline_id, message, sender); } - FromScriptMsg::ScrollFragmentPoint(pipeline_id, point, smooth) => { + FromScriptMsg::ScrollFragmentPoint(pipeline_id, scroll_root_id, point, smooth) => { self.compositor_proxy.send(ToCompositorMsg::ScrollFragmentPoint(pipeline_id, + scroll_root_id, point, smooth)); } diff --git a/components/jstraceable_derive/lib.rs b/components/jstraceable_derive/lib.rs index 527c517ef07..3d3c785d971 100644 --- a/components/jstraceable_derive/lib.rs +++ b/components/jstraceable_derive/lib.rs @@ -41,10 +41,11 @@ fn expand_string(input: &str) -> String { } let tokens = quote! { - impl #impl_generics ::dom::bindings::trace::JSTraceable for #name #ty_generics #where_clause { + #[allow(unsafe_code)] + unsafe impl #impl_generics ::dom::bindings::trace::JSTraceable for #name #ty_generics #where_clause { #[inline] #[allow(unused_variables, unused_imports)] - fn trace(&self, tracer: *mut ::js::jsapi::JSTracer) { + unsafe fn trace(&self, tracer: *mut ::js::jsapi::JSTracer) { use ::dom::bindings::trace::JSTraceable; match *self { #match_body diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 4505ac10192..0c34a147655 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -15,7 +15,6 @@ use block::{BlockFlow, BlockStackingContextType}; use canvas_traits::{CanvasData, CanvasMsg, FromLayoutMsg}; use context::SharedLayoutContext; use euclid::{Matrix4D, Point2D, Radians, Rect, SideOffsets2D, Size2D}; -use euclid::point::TypedPoint2D; use flex::FlexFlow; use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED}; use flow_ref::FlowRef; @@ -98,6 +97,7 @@ pub struct DisplayListBuildState<'a> { pub scroll_roots: HashMap<ScrollRootId, ScrollRoot>, pub stacking_context_id_stack: Vec<StackingContextId>, pub scroll_root_id_stack: Vec<ScrollRootId>, + pub processing_scroll_root_element: bool, } impl<'a> DisplayListBuildState<'a> { @@ -111,6 +111,7 @@ impl<'a> DisplayListBuildState<'a> { scroll_roots: HashMap::new(), stacking_context_id_stack: vec!(stacking_context_id), scroll_root_id_stack: vec!(ScrollRootId::root()), + processing_scroll_root_element: false, } } @@ -162,6 +163,14 @@ impl<'a> DisplayListBuildState<'a> { cursor: Option<Cursor>, section: DisplayListSection) -> BaseDisplayItem { + let scroll_root_id = if (section == DisplayListSection::BackgroundAndBorders || + section == DisplayListSection::BlockBackgroundsAndBorders) && + self.processing_scroll_root_element { + self.parent_scroll_root_id() + } else { + self.scroll_root_id() + }; + BaseDisplayItem::new(&bounds, DisplayItemMetadata { node: node, @@ -170,7 +179,7 @@ impl<'a> DisplayListBuildState<'a> { &clip, section, self.stacking_context_id(), - self.scroll_root_id()) + scroll_root_id) } pub fn to_display_list(mut self) -> DisplayList { @@ -1977,21 +1986,25 @@ impl BlockFlowDisplayListBuilding for BlockFlow { if self.has_scrolling_overflow() { let size = self.base.overflow.scroll.size; - let mut clip = self.fragment.stacking_relative_border_box( + let coordinate_system = if establishes_stacking_context { + CoordinateSystem::Own + } else { + CoordinateSystem::Parent + }; + + let border_box = self.fragment.stacking_relative_border_box( &self.base.stacking_relative_position, &self.base.early_absolute_position_info.relative_containing_block_size, self.base.early_absolute_position_info.relative_containing_block_mode, - CoordinateSystem::Parent); - if establishes_stacking_context { - clip = Rect::new(TypedPoint2D::zero(), clip.size); - } + coordinate_system); let parent_id = state.parent_scroll_root_id(); + state.processing_scroll_root_element = true; state.add_scroll_root( ScrollRoot { id: self.base.scroll_root_id, parent_id: parent_id, - clip: clip, + clip: self.fragment.stacking_relative_content_box(&border_box), size: size, } ); @@ -2012,6 +2025,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow { &self.base.clip); self.base.build_display_items_for_debugging_tint(state, self.fragment.node); + + state.processing_scroll_root_element = false; } fn switch_coordinate_system_if_necessary(&mut self) { diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 6f441d737c3..df7a6510ff2 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -406,7 +406,10 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static { /// Print any extra children (such as fragments) contained in this Flow /// for debugging purposes. Any items inserted into the tree will become /// children of this flow. - fn print_extra_flow_children(&self, _: &mut PrintTree) { + fn print_extra_flow_children(&self, _: &mut PrintTree) { } + + fn scroll_root_id(&self) -> ScrollRootId { + base(self).scroll_root_id } } diff --git a/components/layout/query.rs b/components/layout/query.rs index d34dbc59f07..765cd2bdab4 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -12,13 +12,14 @@ use euclid::size::Size2D; use flow::{self, Flow}; use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo}; use gfx::display_list::{DisplayItemMetadata, DisplayList, OpaqueNode, ScrollOffsetMap}; +use gfx_traits::ScrollRootId; use ipc_channel::ipc::IpcSender; use opaque_node::OpaqueNodeMethods; 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::{NodeOverflowResponse, OffsetParentResponse}; -use script_layout_interface::rpc::ResolvedStyleResponse; +use script_layout_interface::rpc::{NodeScrollRootIdResponse, ResolvedStyleResponse}; use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use script_traits::LayoutMsg as ConstellationMsg; use script_traits::UntrustedNodeAddress; @@ -64,6 +65,9 @@ pub struct LayoutThreadData { /// A queued response for the node at a given point pub hit_test_response: (Option<DisplayItemMetadata>, bool), + /// A queued response for the scroll root id for a given node. + pub scroll_root_id_response: Option<ScrollRootId>, + /// A pair of overflow property in x and y pub overflow_response: NodeOverflowResponse, @@ -178,6 +182,12 @@ impl LayoutRPC for LayoutRPCImpl { } } + fn node_scroll_root_id(&self) -> NodeScrollRootIdResponse { + NodeScrollRootIdResponse(self.0.lock() + .unwrap().scroll_root_id_response + .expect("scroll_root_id is not correctly fetched")) + } + /// Retrieves the resolved value for a CSS style property. fn resolved_style(&self) -> ResolvedStyleResponse { let &LayoutRPCImpl(ref rw_data) = self; @@ -578,6 +588,11 @@ pub fn process_node_geometry_request<N: LayoutNode>(requested_node: N, layout_ro iterator.client_rect } +pub fn process_node_scroll_root_id_request<N: LayoutNode>(requested_node: N) -> ScrollRootId { + let layout_node = requested_node.to_threadsafe(); + layout_node.scroll_root_id() +} + pub fn process_node_scroll_area_request< N: LayoutNode>(requested_node: N, layout_root: &mut Flow) -> Rect<i32> { let mut iterator = UnioningFragmentScrollAreaIterator::new(requested_node.opaque()); diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 85330e3a6cb..04f35183ff4 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -72,7 +72,7 @@ use layout::parallel; use layout::query::{LayoutRPCImpl, LayoutThreadData, process_content_box_request, process_content_boxes_request}; use layout::query::{process_margin_style_query, process_node_overflow_request, process_resolved_style_request}; use layout::query::{process_node_geometry_request, process_node_scroll_area_request}; -use layout::query::process_offset_parent_query; +use layout::query::{process_node_scroll_root_id_request, process_offset_parent_query}; use layout::sequential; use layout::traversal::{ComputeAbsolutePositions, RecalcStyleAndConstructFlows}; use layout::webrender_helpers::WebRenderDisplayListConverter; @@ -462,6 +462,7 @@ impl LayoutThread { content_boxes_response: Vec::new(), client_rect_response: Rect::zero(), hit_test_response: (None, false), + scroll_root_id_response: None, scroll_area_response: Rect::zero(), overflow_response: NodeOverflowResponse(None), resolved_style_response: None, @@ -1012,6 +1013,9 @@ impl LayoutThread { ReflowQueryType::NodeOverflowQuery(_) => { rw_data.overflow_response = NodeOverflowResponse(None); }, + ReflowQueryType::NodeScrollRootIdQuery(_) => { + rw_data.scroll_root_id_response = None; + }, ReflowQueryType::ResolvedStyleQuery(_, _, _) => { rw_data.resolved_style_response = None; }, @@ -1239,6 +1243,10 @@ impl LayoutThread { let node = unsafe { ServoLayoutNode::new(&node) }; rw_data.overflow_response = process_node_overflow_request(node); }, + ReflowQueryType::NodeScrollRootIdQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.scroll_root_id_response = Some(process_node_scroll_root_id_request(node)); + }, ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) => { let node = unsafe { ServoLayoutNode::new(&node) }; let layout_context = LayoutContext::new(&shared_layout_context); @@ -1561,9 +1569,9 @@ fn reflow_query_type_needs_display_list(query_type: &ReflowQueryType) -> bool { ReflowQueryType::HitTestQuery(..) => true, ReflowQueryType::ContentBoxQuery(_) | ReflowQueryType::ContentBoxesQuery(_) | ReflowQueryType::NodeGeometryQuery(_) | ReflowQueryType::NodeScrollGeometryQuery(_) | - ReflowQueryType::NodeOverflowQuery(_) | ReflowQueryType::ResolvedStyleQuery(..) | - ReflowQueryType::OffsetParentQuery(_) | ReflowQueryType::MarginStyleQuery(_) | - ReflowQueryType::NoQuery => false, + ReflowQueryType::NodeOverflowQuery(_) | ReflowQueryType::NodeScrollRootIdQuery(_) | + ReflowQueryType::ResolvedStyleQuery(..) | ReflowQueryType::OffsetParentQuery(_) | + ReflowQueryType::MarginStyleQuery(_) | ReflowQueryType::NoQuery => false, } } diff --git a/components/script/devtools.rs b/components/script/devtools.rs index 9e6a0f1e528..1b1ef4596d6 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use devtools_traits::{AutoMargins, CONSOLE_API, CachedConsoleMessage, CachedConsoleMessageTypes}; -use devtools_traits::{ComputedNodeLayout, ConsoleAPI, PageError, ScriptToDevtoolsControlMsg}; +use devtools_traits::{ComputedNodeLayout, ConsoleAPI, PageError}; use devtools_traits::{EvaluateJSReply, Modification, NodeInfo, PAGE_ERROR, TimelineMarker}; use devtools_traits::TimelineMarkerType; use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods; @@ -17,6 +17,7 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::Root; use dom::bindings::reflector::Reflectable; use dom::bindings::str::DOMString; +use dom::document::AnimationFrameCallback; use dom::element::Element; use dom::globalscope::GlobalScope; use dom::node::{Node, window_from_node}; @@ -253,11 +254,7 @@ pub fn handle_request_animation_frame(documents: &Documents, id: PipelineId, actor_name: String) { if let Some(doc) = documents.find_document(id) { - let devtools_sender = doc.window().upcast::<GlobalScope>().devtools_chan().unwrap().clone(); - doc.request_animation_frame(box move |time| { - let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name, time); - devtools_sender.send(msg).unwrap(); - }); + doc.request_animation_frame(AnimationFrameCallback::DevtoolsFramerateTick { actor_name }); } } diff --git a/components/script/docs/JS-Servos-only-GC.md b/components/script/docs/JS-Servos-only-GC.md index e7237853217..c8129241a84 100644 --- a/components/script/docs/JS-Servos-only-GC.md +++ b/components/script/docs/JS-Servos-only-GC.md @@ -122,8 +122,8 @@ which has an area, and the trait provides a way to get that object's area. Now let's look at the `JSTraceable` trait, which we use for tracing: ```rust -pub trait JSTraceable { - fn trace(&self, trc: *mut JSTracer); +pub unsafe trait JSTraceable { + unsafe fn trace(&self, trc: *mut JSTracer); } ``` @@ -182,7 +182,7 @@ pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Ref } impl<T: Reflectable> JSTraceable for JS<T> { - fn trace(&self, trc: *mut JSTracer) { + unsafe fn trace(&self, trc: *mut JSTracer) { trace_reflector(trc, "", unsafe { (**self.ptr).reflector() }); } } diff --git a/components/script/dom/abstractworkerglobalscope.rs b/components/script/dom/abstractworkerglobalscope.rs index e584e41c62a..dc4bf15c89e 100644 --- a/components/script/dom/abstractworkerglobalscope.rs +++ b/components/script/dom/abstractworkerglobalscope.rs @@ -5,6 +5,7 @@ use dom::abstractworker::WorkerScriptMsg; use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::Reflectable; +use dom::bindings::trace::JSTraceable; use script_runtime::{ScriptChan, CommonScriptMsg, ScriptPort}; use std::sync::mpsc::{Receiver, Sender}; @@ -17,7 +18,7 @@ pub struct SendableWorkerScriptChan<T: Reflectable> { pub worker: Trusted<T>, } -impl<T: Reflectable + 'static> ScriptChan for SendableWorkerScriptChan<T> { +impl<T: JSTraceable + Reflectable + 'static> ScriptChan for SendableWorkerScriptChan<T> { fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> { self.sender.send((self.worker.clone(), msg)).map_err(|_| ()) } @@ -39,7 +40,7 @@ pub struct WorkerThreadWorkerChan<T: Reflectable> { pub worker: Trusted<T>, } -impl<T: Reflectable + 'static> ScriptChan for WorkerThreadWorkerChan<T> { +impl<T: JSTraceable + Reflectable + 'static> ScriptChan for WorkerThreadWorkerChan<T> { fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> { self.sender .send((self.worker.clone(), WorkerScriptMsg::Common(msg))) diff --git a/components/script/dom/bindings/js.rs b/components/script/dom/bindings/js.rs index 528b1213ccb..9ddf3fc46fc 100644 --- a/components/script/dom/bindings/js.rs +++ b/components/script/dom/bindings/js.rs @@ -105,10 +105,10 @@ impl<T: Reflectable> Deref for JS<T> { } } -impl<T: Reflectable> JSTraceable for JS<T> { - fn trace(&self, trc: *mut JSTracer) { +unsafe impl<T: Reflectable> JSTraceable for JS<T> { + unsafe fn trace(&self, trc: *mut JSTracer) { #[cfg(debug_assertions)] - let trace_str = format!("for {} on heap", unsafe { type_name::<T>() }); + let trace_str = format!("for {} on heap", type_name::<T>()); #[cfg(debug_assertions)] let trace_info = &trace_str[..]; #[cfg(not(debug_assertions))] @@ -116,7 +116,7 @@ impl<T: Reflectable> JSTraceable for JS<T> { trace_reflector(trc, trace_info, - unsafe { (**self.ptr).reflector() }); + (**self.ptr).reflector()); } } diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 8323c6996ae..6da8e9a1c5f 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -15,7 +15,7 @@ //! This is typically derived via a `#[dom_struct]` //! (implies `#[derive(JSTraceable)]`) annotation. //! Non-JS-managed types have an empty inline `trace()` method, -//! achieved via `no_jsmanaged_fields!` or similar. +//! achieved via `unsafe_no_jsmanaged_fields!` or similar. //! 3. For all fields, `Foo::trace()` //! calls `trace()` on the field. //! For example, for fields of type `JS<T>`, `JS<T>::trace()` calls @@ -26,14 +26,14 @@ //! 5. When the GC finishes tracing, it [`finalizes`](../index.html#destruction) //! any reflectors that were not reachable. //! -//! The `no_jsmanaged_fields!()` macro adds an empty implementation of `JSTraceable` to -//! a datatype. +//! The `unsafe_no_jsmanaged_fields!()` macro adds an empty implementation of +//! `JSTraceable` to a datatype. +use app_units::Au; use canvas_traits::{CanvasGradientStop, LinearGradientStyle, RadialGradientStyle}; use canvas_traits::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle}; use cssparser::RGBA; -use devtools_traits::CSSError; -use devtools_traits::WorkerId; +use devtools_traits::{CSSError, TimelineMarkerType, WorkerId}; use dom::abstractworker::SharedRt; use dom::bindings::cell::DOMRefCell; use dom::bindings::js::{JS, Root}; @@ -70,35 +70,38 @@ use net_traits::response::{Response, ResponseBody}; use net_traits::response::HttpsState; use net_traits::storage_thread::StorageType; use offscreen_gl_context::GLLimits; +use parking_lot::RwLock; 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}; use script_traits::{UntrustedNodeAddress, WindowSizeData, WindowSizeType}; use serde::{Deserialize, Serialize}; use servo_atoms::Atom; use servo_url::ServoUrl; use smallvec::SmallVec; -use std::boxed::FnBox; use std::cell::{Cell, UnsafeCell}; use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use std::hash::{BuildHasher, Hash}; use std::ops::{Deref, DerefMut}; use std::path::PathBuf; use std::rc::Rc; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::sync::mpsc::{Receiver, Sender}; use std::time::{SystemTime, Instant}; use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto}; use style::element_state::*; +use style::font_face::FontFaceRule; +use style::keyframes::Keyframe; use style::media_queries::MediaList; use style::properties::PropertyDeclarationBlock; use style::selector_parser::{PseudoElement, Snapshot}; +use style::stylesheets::{CssRules, KeyframesRule, MediaRule, NamespaceRule, StyleRule}; use style::values::specified::Length; +use style::viewport::ViewportRule; use time::Duration; use url::Origin as UrlOrigin; use uuid::Uuid; @@ -106,18 +109,18 @@ use webrender_traits::{WebGLBufferId, WebGLError, WebGLFramebufferId, WebGLProgr use webrender_traits::{WebGLRenderbufferId, WebGLShaderId, WebGLTextureId}; /// A trait to allow tracing (only) DOM objects. -pub trait JSTraceable { +pub unsafe trait JSTraceable { /// Trace `self`. - fn trace(&self, trc: *mut JSTracer); + unsafe fn trace(&self, trc: *mut JSTracer); } -no_jsmanaged_fields!(CSSError); +unsafe_no_jsmanaged_fields!(CSSError); -no_jsmanaged_fields!(EncodingRef); +unsafe_no_jsmanaged_fields!(EncodingRef); -no_jsmanaged_fields!(Reflector); +unsafe_no_jsmanaged_fields!(Reflector); -no_jsmanaged_fields!(Duration); +unsafe_no_jsmanaged_fields!(Duration); /// Trace a `JSVal`. pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap<JSVal>) { @@ -154,40 +157,44 @@ pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: &Heap<*mut JS } } -impl<T: JSTraceable> JSTraceable for Rc<T> { - fn trace(&self, trc: *mut JSTracer) { +unsafe impl<T: JSTraceable> JSTraceable for Rc<T> { + unsafe fn trace(&self, trc: *mut JSTracer) { (**self).trace(trc) } } -impl<T: JSTraceable + ?Sized> JSTraceable for Box<T> { - fn trace(&self, trc: *mut JSTracer) { +unsafe impl<T: JSTraceable> JSTraceable for Arc<T> { + unsafe fn trace(&self, trc: *mut JSTracer) { (**self).trace(trc) } } -impl<T: JSTraceable + Copy> JSTraceable for Cell<T> { - fn trace(&self, trc: *mut JSTracer) { +unsafe impl<T: JSTraceable + ?Sized> JSTraceable for Box<T> { + unsafe fn trace(&self, trc: *mut JSTracer) { + (**self).trace(trc) + } +} + +unsafe impl<T: JSTraceable + Copy> JSTraceable for Cell<T> { + unsafe fn trace(&self, trc: *mut JSTracer) { self.get().trace(trc) } } -impl<T: JSTraceable> JSTraceable for UnsafeCell<T> { - fn trace(&self, trc: *mut JSTracer) { - unsafe { (*self.get()).trace(trc) } +unsafe impl<T: JSTraceable> JSTraceable for UnsafeCell<T> { + unsafe fn trace(&self, trc: *mut JSTracer) { + (*self.get()).trace(trc) } } -impl<T: JSTraceable> JSTraceable for DOMRefCell<T> { - fn trace(&self, trc: *mut JSTracer) { - unsafe { - (*self).borrow_for_gc_trace().trace(trc) - } +unsafe impl<T: JSTraceable> JSTraceable for DOMRefCell<T> { + unsafe fn trace(&self, trc: *mut JSTracer) { + (*self).borrow_for_gc_trace().trace(trc) } } -impl JSTraceable for Heap<*mut JSObject> { - fn trace(&self, trc: *mut JSTracer) { +unsafe impl JSTraceable for Heap<*mut JSObject> { + unsafe fn trace(&self, trc: *mut JSTracer) { if self.get().is_null() { return; } @@ -195,34 +202,34 @@ impl JSTraceable for Heap<*mut JSObject> { } } -impl JSTraceable for Heap<JSVal> { - fn trace(&self, trc: *mut JSTracer) { +unsafe impl JSTraceable for Heap<JSVal> { + unsafe fn trace(&self, trc: *mut JSTracer) { trace_jsval(trc, "heap value", self); } } // XXXManishearth Check if the following three are optimized to no-ops -// if e.trace() is a no-op (e.g it is an no_jsmanaged_fields type) -impl<T: JSTraceable> JSTraceable for Vec<T> { +// if e.trace() is a no-op (e.g it is an unsafe_no_jsmanaged_fields type) +unsafe impl<T: JSTraceable> JSTraceable for Vec<T> { #[inline] - fn trace(&self, trc: *mut JSTracer) { + unsafe fn trace(&self, trc: *mut JSTracer) { for e in &*self { e.trace(trc); } } } -impl<T: JSTraceable> JSTraceable for VecDeque<T> { +unsafe impl<T: JSTraceable> JSTraceable for VecDeque<T> { #[inline] - fn trace(&self, trc: *mut JSTracer) { + unsafe fn trace(&self, trc: *mut JSTracer) { for e in &*self { e.trace(trc); } } } -impl<T: JSTraceable> JSTraceable for (T, T, T, T) { - fn trace(&self, trc: *mut JSTracer) { +unsafe impl<T: JSTraceable> JSTraceable for (T, T, T, T) { + unsafe fn trace(&self, trc: *mut JSTracer) { self.0.trace(trc); self.1.trace(trc); self.2.trace(trc); @@ -231,26 +238,26 @@ impl<T: JSTraceable> JSTraceable for (T, T, T, T) { } // XXXManishearth Check if the following three are optimized to no-ops -// if e.trace() is a no-op (e.g it is an no_jsmanaged_fields type) -impl<T: JSTraceable + 'static> JSTraceable for SmallVec<[T; 1]> { +// if e.trace() is a no-op (e.g it is an unsafe_no_jsmanaged_fields type) +unsafe impl<T: JSTraceable + 'static> JSTraceable for SmallVec<[T; 1]> { #[inline] - fn trace(&self, trc: *mut JSTracer) { + unsafe fn trace(&self, trc: *mut JSTracer) { for e in self.iter() { e.trace(trc); } } } -impl<T: JSTraceable> JSTraceable for Option<T> { +unsafe impl<T: JSTraceable> JSTraceable for Option<T> { #[inline] - fn trace(&self, trc: *mut JSTracer) { + unsafe fn trace(&self, trc: *mut JSTracer) { self.as_ref().map(|e| e.trace(trc)); } } -impl<T: JSTraceable, U: JSTraceable> JSTraceable for Result<T, U> { +unsafe impl<T: JSTraceable, U: JSTraceable> JSTraceable for Result<T, U> { #[inline] - fn trace(&self, trc: *mut JSTracer) { + unsafe fn trace(&self, trc: *mut JSTracer) { match *self { Ok(ref inner) => inner.trace(trc), Err(ref inner) => inner.trace(trc), @@ -258,13 +265,13 @@ impl<T: JSTraceable, U: JSTraceable> JSTraceable for Result<T, U> { } } -impl<K, V, S> JSTraceable for HashMap<K, V, S> +unsafe impl<K, V, S> JSTraceable for HashMap<K, V, S> where K: Hash + Eq + JSTraceable, V: JSTraceable, S: BuildHasher { #[inline] - fn trace(&self, trc: *mut JSTracer) { + unsafe fn trace(&self, trc: *mut JSTracer) { for (k, v) in &*self { k.trace(trc); v.trace(trc); @@ -272,9 +279,21 @@ impl<K, V, S> JSTraceable for HashMap<K, V, S> } } -impl<K: Ord + JSTraceable, V: JSTraceable> JSTraceable for BTreeMap<K, V> { +unsafe impl<T, S> JSTraceable for HashSet<T, S> + where T: Hash + Eq + JSTraceable, + S: BuildHasher +{ #[inline] - fn trace(&self, trc: *mut JSTracer) { + unsafe fn trace(&self, trc: *mut JSTracer) { + for v in &*self { + v.trace(trc); + } + } +} + +unsafe impl<K: Ord + JSTraceable, V: JSTraceable> JSTraceable for BTreeMap<K, V> { + #[inline] + unsafe fn trace(&self, trc: *mut JSTracer) { for (k, v) in self { k.trace(trc); v.trace(trc); @@ -282,18 +301,18 @@ impl<K: Ord + JSTraceable, V: JSTraceable> JSTraceable for BTreeMap<K, V> { } } -impl<A: JSTraceable, B: JSTraceable> JSTraceable for (A, B) { +unsafe impl<A: JSTraceable, B: JSTraceable> JSTraceable for (A, B) { #[inline] - fn trace(&self, trc: *mut JSTracer) { + unsafe fn trace(&self, trc: *mut JSTracer) { let (ref a, ref b) = *self; a.trace(trc); b.trace(trc); } } -impl<A: JSTraceable, B: JSTraceable, C: JSTraceable> JSTraceable for (A, B, C) { +unsafe impl<A: JSTraceable, B: JSTraceable, C: JSTraceable> JSTraceable for (A, B, C) { #[inline] - fn trace(&self, trc: *mut JSTracer) { + unsafe fn trace(&self, trc: *mut JSTracer) { let (ref a, ref b, ref c) = *self; a.trace(trc); b.trace(trc); @@ -301,139 +320,258 @@ impl<A: JSTraceable, B: JSTraceable, C: JSTraceable> JSTraceable for (A, B, C) { } } -no_jsmanaged_fields!(bool, f32, f64, String, ServoUrl, AtomicBool, AtomicUsize, UrlOrigin, Uuid, char); -no_jsmanaged_fields!(usize, u8, u16, u32, u64); -no_jsmanaged_fields!(isize, i8, i16, i32, i64); -no_jsmanaged_fields!(Sender<T>); -no_jsmanaged_fields!(Receiver<T>); -no_jsmanaged_fields!(Point2D<T>); -no_jsmanaged_fields!(Rect<T>); -no_jsmanaged_fields!(Size2D<T>); -no_jsmanaged_fields!(Arc<T>); -no_jsmanaged_fields!(Image, ImageMetadata, ImageCacheChan, ImageCacheThread); -no_jsmanaged_fields!(Metadata); -no_jsmanaged_fields!(NetworkError); -no_jsmanaged_fields!(Atom, Prefix, LocalName, Namespace, QualName); -no_jsmanaged_fields!(Trusted<T: Reflectable>); -no_jsmanaged_fields!(TrustedPromise); -no_jsmanaged_fields!(PropertyDeclarationBlock); -no_jsmanaged_fields!(HashSet<T>); +unsafe_no_jsmanaged_fields!(bool, f32, f64, String, ServoUrl, AtomicBool, AtomicUsize, UrlOrigin, Uuid, char); +unsafe_no_jsmanaged_fields!(usize, u8, u16, u32, u64); +unsafe_no_jsmanaged_fields!(isize, i8, i16, i32, i64); +unsafe_no_jsmanaged_fields!(Image, ImageMetadata, ImageCacheChan, ImageCacheThread); +unsafe_no_jsmanaged_fields!(Metadata); +unsafe_no_jsmanaged_fields!(NetworkError); +unsafe_no_jsmanaged_fields!(Atom, Prefix, LocalName, Namespace, QualName); +unsafe_no_jsmanaged_fields!(TrustedPromise); +unsafe_no_jsmanaged_fields!(PropertyDeclarationBlock); // These three are interdependent, if you plan to put jsmanaged data // in one of these make sure it is propagated properly to containing structs -no_jsmanaged_fields!(FrameId, FrameType, WindowSizeData, WindowSizeType, PipelineId); -no_jsmanaged_fields!(TimerEventId, TimerSource); -no_jsmanaged_fields!(WorkerId); -no_jsmanaged_fields!(BufferQueue, QuirksMode); -no_jsmanaged_fields!(Runtime); -no_jsmanaged_fields!(Headers, Method); -no_jsmanaged_fields!(WindowProxyHandler); -no_jsmanaged_fields!(UntrustedNodeAddress); -no_jsmanaged_fields!(LengthOrPercentageOrAuto); -no_jsmanaged_fields!(RGBA); -no_jsmanaged_fields!(EuclidLength<Unit, T>); -no_jsmanaged_fields!(Matrix2D<T>); -no_jsmanaged_fields!(Matrix4D<T>); -no_jsmanaged_fields!(StorageType); -no_jsmanaged_fields!(CanvasGradientStop, LinearGradientStyle, RadialGradientStyle); -no_jsmanaged_fields!(LineCapStyle, LineJoinStyle, CompositionOrBlending); -no_jsmanaged_fields!(RepetitionStyle); -no_jsmanaged_fields!(WebGLError, GLLimits); -no_jsmanaged_fields!(TimeProfilerChan); -no_jsmanaged_fields!(MemProfilerChan); -no_jsmanaged_fields!(PseudoElement); -no_jsmanaged_fields!(Length); -no_jsmanaged_fields!(ElementState); -no_jsmanaged_fields!(DOMString); -no_jsmanaged_fields!(Mime); -no_jsmanaged_fields!(AttrIdentifier); -no_jsmanaged_fields!(AttrValue); -no_jsmanaged_fields!(Snapshot); -no_jsmanaged_fields!(PendingRestyle); -no_jsmanaged_fields!(HttpsState); -no_jsmanaged_fields!(Request); -no_jsmanaged_fields!(RequestInit); -no_jsmanaged_fields!(SharedRt); -no_jsmanaged_fields!(TouchpadPressurePhase); -no_jsmanaged_fields!(USVString); -no_jsmanaged_fields!(ReferrerPolicy); -no_jsmanaged_fields!(Response); -no_jsmanaged_fields!(ResponseBody); -no_jsmanaged_fields!(ResourceThreads); -no_jsmanaged_fields!(StatusCode); -no_jsmanaged_fields!(SystemTime); -no_jsmanaged_fields!(Instant); -no_jsmanaged_fields!(RelativePos); -no_jsmanaged_fields!(OpaqueStyleAndLayoutData); -no_jsmanaged_fields!(PathBuf); -no_jsmanaged_fields!(CSSErrorReporter); -no_jsmanaged_fields!(WebGLBufferId); -no_jsmanaged_fields!(WebGLFramebufferId); -no_jsmanaged_fields!(WebGLProgramId); -no_jsmanaged_fields!(WebGLRenderbufferId); -no_jsmanaged_fields!(WebGLShaderId); -no_jsmanaged_fields!(WebGLTextureId); -no_jsmanaged_fields!(MediaList); - -impl JSTraceable for Box<ScriptChan + Send> { +unsafe_no_jsmanaged_fields!(FrameId, FrameType, WindowSizeData, WindowSizeType, PipelineId); +unsafe_no_jsmanaged_fields!(TimerEventId, TimerSource); +unsafe_no_jsmanaged_fields!(TimelineMarkerType); +unsafe_no_jsmanaged_fields!(WorkerId); +unsafe_no_jsmanaged_fields!(BufferQueue, QuirksMode); +unsafe_no_jsmanaged_fields!(Runtime); +unsafe_no_jsmanaged_fields!(Headers, Method); +unsafe_no_jsmanaged_fields!(WindowProxyHandler); +unsafe_no_jsmanaged_fields!(UntrustedNodeAddress); +unsafe_no_jsmanaged_fields!(LengthOrPercentageOrAuto); +unsafe_no_jsmanaged_fields!(RGBA); +unsafe_no_jsmanaged_fields!(StorageType); +unsafe_no_jsmanaged_fields!(CanvasGradientStop, LinearGradientStyle, RadialGradientStyle); +unsafe_no_jsmanaged_fields!(LineCapStyle, LineJoinStyle, CompositionOrBlending); +unsafe_no_jsmanaged_fields!(RepetitionStyle); +unsafe_no_jsmanaged_fields!(WebGLError, GLLimits); +unsafe_no_jsmanaged_fields!(TimeProfilerChan); +unsafe_no_jsmanaged_fields!(MemProfilerChan); +unsafe_no_jsmanaged_fields!(PseudoElement); +unsafe_no_jsmanaged_fields!(Length); +unsafe_no_jsmanaged_fields!(ElementState); +unsafe_no_jsmanaged_fields!(DOMString); +unsafe_no_jsmanaged_fields!(Mime); +unsafe_no_jsmanaged_fields!(AttrIdentifier); +unsafe_no_jsmanaged_fields!(AttrValue); +unsafe_no_jsmanaged_fields!(Snapshot); +unsafe_no_jsmanaged_fields!(PendingRestyle); +unsafe_no_jsmanaged_fields!(HttpsState); +unsafe_no_jsmanaged_fields!(Request); +unsafe_no_jsmanaged_fields!(RequestInit); +unsafe_no_jsmanaged_fields!(SharedRt); +unsafe_no_jsmanaged_fields!(TouchpadPressurePhase); +unsafe_no_jsmanaged_fields!(USVString); +unsafe_no_jsmanaged_fields!(ReferrerPolicy); +unsafe_no_jsmanaged_fields!(Response); +unsafe_no_jsmanaged_fields!(ResponseBody); +unsafe_no_jsmanaged_fields!(ResourceThreads); +unsafe_no_jsmanaged_fields!(StatusCode); +unsafe_no_jsmanaged_fields!(SystemTime); +unsafe_no_jsmanaged_fields!(Instant); +unsafe_no_jsmanaged_fields!(RelativePos); +unsafe_no_jsmanaged_fields!(OpaqueStyleAndLayoutData); +unsafe_no_jsmanaged_fields!(PathBuf); +unsafe_no_jsmanaged_fields!(CSSErrorReporter); +unsafe_no_jsmanaged_fields!(WebGLBufferId); +unsafe_no_jsmanaged_fields!(WebGLFramebufferId); +unsafe_no_jsmanaged_fields!(WebGLProgramId); +unsafe_no_jsmanaged_fields!(WebGLRenderbufferId); +unsafe_no_jsmanaged_fields!(WebGLShaderId); +unsafe_no_jsmanaged_fields!(WebGLTextureId); +unsafe_no_jsmanaged_fields!(MediaList); + +unsafe impl<'a> JSTraceable for &'a str { + #[inline] + unsafe fn trace(&self, _: *mut JSTracer) { + // Do nothing + } +} + +unsafe impl<A, B> JSTraceable for fn(A) -> B { + #[inline] + unsafe fn trace(&self, _: *mut JSTracer) { + // Do nothing + } +} + +unsafe impl<T> JSTraceable for IpcSender<T> where T: Deserialize + Serialize { + #[inline] + unsafe fn trace(&self, _: *mut JSTracer) { + // Do nothing + } +} + +// Safe thanks to the Send bound. +unsafe impl JSTraceable for Box<LayoutRPC + Send + 'static> { + #[inline] + unsafe fn trace(&self, _: *mut JSTracer) { + // Do nothing + } +} + +unsafe impl JSTraceable for () { + #[inline] + unsafe fn trace(&self, _: *mut JSTracer) { + // Do nothing + } +} + +unsafe impl<T> JSTraceable for IpcReceiver<T> where T: Deserialize + Serialize { + #[inline] + unsafe fn trace(&self, _: *mut JSTracer) { + // Do nothing + } +} + +unsafe impl<T: Reflectable> JSTraceable for Trusted<T> { + #[inline] + unsafe fn trace(&self, _: *mut JSTracer) { + // Do nothing + } +} + +unsafe impl<T: Send> JSTraceable for Receiver<T> { + #[inline] + unsafe fn trace(&self, _: *mut JSTracer) { + // Do nothing + } +} + +unsafe impl<T: Send> JSTraceable for Sender<T> { #[inline] - fn trace(&self, _trc: *mut JSTracer) { + unsafe fn trace(&self, _: *mut JSTracer) { // Do nothing } } -impl JSTraceable for Box<FnBox(f64, )> { +unsafe impl JSTraceable for Matrix2D<f32> { #[inline] - fn trace(&self, _trc: *mut JSTracer) { + unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing } } -impl<'a> JSTraceable for &'a str { +unsafe impl JSTraceable for Matrix4D<f64> { #[inline] - fn trace(&self, _: *mut JSTracer) { + unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing } } -impl<A, B> JSTraceable for fn(A) -> B { +unsafe impl JSTraceable for Point2D<f32> { #[inline] - fn trace(&self, _: *mut JSTracer) { + unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing } } -impl<T> JSTraceable for IpcSender<T> where T: Deserialize + Serialize { +unsafe impl<T> JSTraceable for EuclidLength<u64, T> { #[inline] - fn trace(&self, _: *mut JSTracer) { + unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing } } -impl JSTraceable for Box<LayoutRPC + 'static> { +unsafe impl JSTraceable for Rect<Au> { #[inline] - fn trace(&self, _: *mut JSTracer) { + unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing } } -impl JSTraceable for () { +unsafe impl JSTraceable for Rect<f32> { #[inline] - fn trace(&self, _: *mut JSTracer) { + unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing } } -impl<T> JSTraceable for IpcReceiver<T> where T: Deserialize + Serialize { +unsafe impl JSTraceable for Size2D<i32> { #[inline] - fn trace(&self, _: *mut JSTracer) { + unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing } } +unsafe impl JSTraceable for Mutex<Option<SharedRt>> { + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing. + } +} + +unsafe impl JSTraceable for RwLock<FontFaceRule> { + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing. + } +} + +unsafe impl JSTraceable for RwLock<CssRules> { + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing. + } +} + +unsafe impl JSTraceable for RwLock<Keyframe> { + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing. + } +} + +unsafe impl JSTraceable for RwLock<KeyframesRule> { + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing. + } +} + +unsafe impl JSTraceable for RwLock<MediaRule> { + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing. + } +} + +unsafe impl JSTraceable for RwLock<NamespaceRule> { + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing. + } +} + +unsafe impl JSTraceable for RwLock<StyleRule> { + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing. + } +} + +unsafe impl JSTraceable for RwLock<ViewportRule> { + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing. + } +} + +unsafe impl JSTraceable for RwLock<PropertyDeclarationBlock> { + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing. + } +} + +unsafe impl JSTraceable for RwLock<SharedRt> { + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing. + } +} + +unsafe impl JSTraceable for RwLock<MediaList> { + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing. + } +} + /// Homemade trait object for JSTraceable things struct TraceableInfo { pub ptr: *const libc::c_void, - pub trace: fn(obj: *const libc::c_void, tracer: *mut JSTracer), + pub trace: unsafe fn(obj: *const libc::c_void, tracer: *mut JSTracer), } /// Holds a set of JSTraceables that need to be rooted @@ -474,8 +612,8 @@ impl RootedTraceableSet { unsafe fn add<T: JSTraceable>(traceable: &T) { ROOTED_TRACEABLES.with(|ref traceables| { - fn trace<T: JSTraceable>(obj: *const libc::c_void, tracer: *mut JSTracer) { - let obj: &T = unsafe { &*(obj as *const T) }; + unsafe fn trace<T: JSTraceable>(obj: *const libc::c_void, tracer: *mut JSTracer) { + let obj: &T = &*(obj as *const T); obj.trace(tracer); } diff --git a/components/script/dom/bindings/weakref.rs b/components/script/dom/bindings/weakref.rs index 761aaf7721c..68feff79180 100644 --- a/components/script/dom/bindings/weakref.rs +++ b/components/script/dom/bindings/weakref.rs @@ -133,7 +133,11 @@ impl<T: WeakReferenceable> PartialEq<T> for WeakRef<T> { } } -no_jsmanaged_fields!(WeakRef<T: WeakReferenceable>); +unsafe impl<T: WeakReferenceable> JSTraceable for WeakRef<T> { + unsafe fn trace(&self, _: *mut JSTracer) { + // Do nothing. + } +} impl<T: WeakReferenceable> Drop for WeakRef<T> { fn drop(&mut self) { @@ -188,17 +192,15 @@ impl<T: WeakReferenceable> HeapSizeOf for MutableWeakRef<T> { } } -impl<T: WeakReferenceable> JSTraceable for MutableWeakRef<T> { - fn trace(&self, _: *mut JSTracer) { +unsafe impl<T: WeakReferenceable> JSTraceable for MutableWeakRef<T> { + unsafe fn trace(&self, _: *mut JSTracer) { let ptr = self.cell.get(); - unsafe { - let should_drop = match *ptr { - Some(ref value) => !value.is_alive(), - None => false, - }; - if should_drop { - mem::drop((*ptr).take().unwrap()); - } + let should_drop = match *ptr { + Some(ref value) => !value.is_alive(), + None => false, + }; + if should_drop { + mem::drop((*ptr).take().unwrap()); } } } diff --git a/components/script/dom/bluetooth.rs b/components/script/dom/bluetooth.rs index aa2c4c4639a..61a9588dfab 100644 --- a/components/script/dom/bluetooth.rs +++ b/components/script/dom/bluetooth.rs @@ -21,9 +21,6 @@ use dom::bindings::reflector::{Reflectable, reflect_dom_object}; use dom::bindings::str::DOMString; use dom::bluetoothadvertisingdata::BluetoothAdvertisingData; use dom::bluetoothdevice::BluetoothDevice; -use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic; -use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor; -use dom::bluetoothremotegattservice::BluetoothRemoteGATTService; use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID}; use dom::eventtarget::EventTarget; use dom::globalscope::GlobalScope; @@ -90,9 +87,6 @@ impl<Listener: AsyncBluetoothListener + Reflectable> BluetoothResponseListener f pub struct Bluetooth { eventtarget: EventTarget, device_instance_map: DOMRefCell<HashMap<String, MutHeap<JS<BluetoothDevice>>>>, - service_instance_map: DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTService>>>>, - characteristic_instance_map: DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTCharacteristic>>>>, - descriptor_instance_map: DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTDescriptor>>>>, } impl Bluetooth { @@ -100,9 +94,6 @@ impl Bluetooth { Bluetooth { eventtarget: EventTarget::new_inherited(), device_instance_map: DOMRefCell::new(HashMap::new()), - service_instance_map: DOMRefCell::new(HashMap::new()), - characteristic_instance_map: DOMRefCell::new(HashMap::new()), - descriptor_instance_map: DOMRefCell::new(HashMap::new()), } } @@ -112,19 +103,6 @@ impl Bluetooth { BluetoothBinding::Wrap) } - pub fn get_service_map(&self) -> &DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTService>>>> { - &self.service_instance_map - } - - pub fn get_characteristic_map(&self) - -> &DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTCharacteristic>>>> { - &self.characteristic_instance_map - } - - pub fn get_descriptor_map(&self) -> &DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTDescriptor>>>> { - &self.descriptor_instance_map - } - fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> { self.global().as_window().bluetooth_thread() } diff --git a/components/script/dom/bluetoothdevice.rs b/components/script/dom/bluetoothdevice.rs index 4af6b2a4f59..5bd3bd8233d 100644 --- a/components/script/dom/bluetoothdevice.rs +++ b/components/script/dom/bluetoothdevice.rs @@ -2,17 +2,26 @@ * 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 bluetooth_traits::{BluetoothCharacteristicMsg, BluetoothDescriptorMsg, BluetoothServiceMsg}; +use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::BluetoothDeviceBinding; use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods; +use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::js::{JS, Root, MutHeap, MutNullableHeap}; use dom::bindings::reflector::{Reflectable, reflect_dom_object}; use dom::bindings::str::DOMString; use dom::bluetooth::Bluetooth; use dom::bluetoothadvertisingdata::BluetoothAdvertisingData; +use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties; +use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic; +use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor; use dom::bluetoothremotegattserver::BluetoothRemoteGATTServer; +use dom::bluetoothremotegattservice::BluetoothRemoteGATTService; use dom::eventtarget::EventTarget; use dom::globalscope::GlobalScope; +use std::collections::HashMap; + // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothdevice #[dom_struct] @@ -23,6 +32,9 @@ pub struct BluetoothDevice { ad_data: MutHeap<JS<BluetoothAdvertisingData>>, gatt: MutNullableHeap<JS<BluetoothRemoteGATTServer>>, context: MutHeap<JS<Bluetooth>>, + attribute_instance_map: (DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTService>>>>, + DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTCharacteristic>>>>, + DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTDescriptor>>>>), } impl BluetoothDevice { @@ -38,6 +50,9 @@ impl BluetoothDevice { ad_data: MutHeap::new(ad_data), gatt: Default::default(), context: MutHeap::new(context), + attribute_instance_map: (DOMRefCell::new(HashMap::new()), + DOMRefCell::new(HashMap::new()), + DOMRefCell::new(HashMap::new())), } } @@ -55,8 +70,68 @@ impl BluetoothDevice { BluetoothDeviceBinding::Wrap) } - pub fn get_context(&self) -> Root<Bluetooth> { - self.context.get() + pub fn get_or_create_service(&self, + service: &BluetoothServiceMsg, + server: &BluetoothRemoteGATTServer) + -> Root<BluetoothRemoteGATTService> { + let (ref service_map_ref, _, _) = self.attribute_instance_map; + let mut service_map = service_map_ref.borrow_mut(); + if let Some(existing_service) = service_map.get(&service.instance_id) { + return existing_service.get(); + } + let bt_service = BluetoothRemoteGATTService::new(&server.global(), + &server.Device(), + DOMString::from(service.uuid.clone()), + service.is_primary, + service.instance_id.clone()); + service_map.insert(service.instance_id.clone(), MutHeap::new(&bt_service)); + return bt_service; + } + + pub fn get_or_create_characteristic(&self, + characteristic: &BluetoothCharacteristicMsg, + service: &BluetoothRemoteGATTService) + -> Root<BluetoothRemoteGATTCharacteristic> { + let (_, ref characteristic_map_ref, _) = self.attribute_instance_map; + let mut characteristic_map = characteristic_map_ref.borrow_mut(); + if let Some(existing_characteristic) = characteristic_map.get(&characteristic.instance_id) { + return existing_characteristic.get(); + } + let properties = + BluetoothCharacteristicProperties::new(&service.global(), + characteristic.broadcast, + characteristic.read, + characteristic.write_without_response, + characteristic.write, + characteristic.notify, + characteristic.indicate, + characteristic.authenticated_signed_writes, + characteristic.reliable_write, + characteristic.writable_auxiliaries); + let bt_characteristic = BluetoothRemoteGATTCharacteristic::new(&service.global(), + service, + DOMString::from(characteristic.uuid.clone()), + &properties, + characteristic.instance_id.clone()); + characteristic_map.insert(characteristic.instance_id.clone(), MutHeap::new(&bt_characteristic)); + return bt_characteristic; + } + + pub fn get_or_create_descriptor(&self, + descriptor: &BluetoothDescriptorMsg, + characteristic: &BluetoothRemoteGATTCharacteristic) + -> Root<BluetoothRemoteGATTDescriptor> { + let (_, _, ref descriptor_map_ref) = self.attribute_instance_map; + let mut descriptor_map = descriptor_map_ref.borrow_mut(); + if let Some(existing_descriptor) = descriptor_map.get(&descriptor.instance_id) { + return existing_descriptor.get(); + } + let bt_descriptor = BluetoothRemoteGATTDescriptor::new(&characteristic.global(), + characteristic, + DOMString::from(descriptor.uuid.clone()), + descriptor.instance_id.clone()); + descriptor_map.insert(descriptor.instance_id.clone(), MutHeap::new(&bt_descriptor)); + return bt_descriptor; } } diff --git a/components/script/dom/bluetoothremotegattcharacteristic.rs b/components/script/dom/bluetoothremotegattcharacteristic.rs index 3c3c86001fb..ecbb77b64a2 100644 --- a/components/script/dom/bluetoothremotegattcharacteristic.rs +++ b/components/script/dom/bluetoothremotegattcharacteristic.rs @@ -21,7 +21,6 @@ use dom::bindings::reflector::{Reflectable, reflect_dom_object}; use dom::bindings::str::{ByteString, DOMString}; use dom::bluetooth::{AsyncBluetoothListener, response_async}; use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties; -use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor; use dom::bluetoothremotegattservice::BluetoothRemoteGATTService; use dom::bluetoothuuid::{BluetoothDescriptorUUID, BluetoothUUID}; use dom::eventtarget::EventTarget; @@ -330,21 +329,13 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic { fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) { + let device = self.Service().Device(); match response { // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren // Step 7. BluetoothResponse::GetDescriptor(descriptor) => { - let context = self.service.get().get_device().get_context(); - let mut descriptor_map = context.get_descriptor_map().borrow_mut(); - if let Some(existing_descriptor) = descriptor_map.get(&descriptor.instance_id) { - return promise.resolve_native(promise_cx, &existing_descriptor.get()); - } - let bt_descriptor = BluetoothRemoteGATTDescriptor::new(&self.global(), - self, - DOMString::from(descriptor.uuid), - descriptor.instance_id.clone()); - descriptor_map.insert(descriptor.instance_id, MutHeap::new(&bt_descriptor)); + let bt_descriptor = device.get_or_create_descriptor(&descriptor, &self); promise.resolve_native(promise_cx, &bt_descriptor); }, // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors @@ -352,21 +343,8 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic { // Step 7. BluetoothResponse::GetDescriptors(descriptors_vec) => { let mut descriptors = vec!(); - let context = self.service.get().get_device().get_context(); - let mut descriptor_map = context.get_descriptor_map().borrow_mut(); for descriptor in descriptors_vec { - let bt_descriptor = match descriptor_map.get(&descriptor.instance_id) { - Some(existing_descriptor) => existing_descriptor.get(), - None => { - BluetoothRemoteGATTDescriptor::new(&self.global(), - self, - DOMString::from(descriptor.uuid), - descriptor.instance_id.clone()) - }, - }; - if !descriptor_map.contains_key(&descriptor.instance_id) { - descriptor_map.insert(descriptor.instance_id, MutHeap::new(&bt_descriptor)); - } + let bt_descriptor = device.get_or_create_descriptor(&descriptor, &self); descriptors.push(bt_descriptor); } promise.resolve_native(promise_cx, &descriptors); diff --git a/components/script/dom/bluetoothremotegattserver.rs b/components/script/dom/bluetoothremotegattserver.rs index 06c11f0aa21..f325414e230 100644 --- a/components/script/dom/bluetoothremotegattserver.rs +++ b/components/script/dom/bluetoothremotegattserver.rs @@ -11,10 +11,8 @@ use dom::bindings::error::Error::{self, Network, Security}; use dom::bindings::error::ErrorResult; use dom::bindings::js::{JS, MutHeap, Root}; use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; -use dom::bindings::str::DOMString; use dom::bluetooth::{AsyncBluetoothListener, response_async}; use dom::bluetoothdevice::BluetoothDevice; -use dom::bluetoothremotegattservice::BluetoothRemoteGATTService; use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID}; use dom::globalscope::GlobalScope; use dom::promise::Promise; @@ -90,7 +88,10 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { fn Disconnect(&self) -> ErrorResult { // TODO: Step 1: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer. - // TODO: Step 2: Check if this.connected is false here too. + // Step 2. + if !self.Connected() { + return Ok(()); + } let (sender, receiver) = ipc::channel().unwrap(); self.get_bluetooth_thread().send( BluetoothRequest::GATTServerDisconnect(String::from(self.Device().Id()), sender)).unwrap(); @@ -197,6 +198,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { impl AsyncBluetoothListener for BluetoothRemoteGATTServer { fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) { + let device = self.Device(); match response { // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect BluetoothResponse::GATTServerConnect(connected) => { @@ -210,17 +212,7 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTServer { // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren // Step 7. BluetoothResponse::GetPrimaryService(service) => { - let context = self.device.get().get_context(); - let mut service_map = context.get_service_map().borrow_mut(); - if let Some(existing_service) = service_map.get(&service.instance_id) { - promise.resolve_native(promise_cx, &existing_service.get()); - } - let bt_service = BluetoothRemoteGATTService::new(&self.global(), - &self.device.get(), - DOMString::from(service.uuid), - service.is_primary, - service.instance_id.clone()); - service_map.insert(service.instance_id, MutHeap::new(&bt_service)); + let bt_service = device.get_or_create_service(&service, &self); promise.resolve_native(promise_cx, &bt_service); }, // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices @@ -228,22 +220,8 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTServer { // Step 7. BluetoothResponse::GetPrimaryServices(services_vec) => { let mut services = vec!(); - let context = self.device.get().get_context(); - let mut service_map = context.get_service_map().borrow_mut(); for service in services_vec { - let bt_service = match service_map.get(&service.instance_id) { - Some(existing_service) => existing_service.get(), - None => { - BluetoothRemoteGATTService::new(&self.global(), - &self.device.get(), - DOMString::from(service.uuid), - service.is_primary, - service.instance_id.clone()) - }, - }; - if !service_map.contains_key(&service.instance_id) { - service_map.insert(service.instance_id, MutHeap::new(&bt_service)); - } + let bt_service = device.get_or_create_service(&service, &self); services.push(bt_service); } promise.resolve_native(promise_cx, &services); diff --git a/components/script/dom/bluetoothremotegattservice.rs b/components/script/dom/bluetoothremotegattservice.rs index ef922e9b385..60fcc694ed8 100644 --- a/components/script/dom/bluetoothremotegattservice.rs +++ b/components/script/dom/bluetoothremotegattservice.rs @@ -14,9 +14,7 @@ use dom::bindings::js::{JS, MutHeap, Root}; use dom::bindings::reflector::{Reflectable, reflect_dom_object}; use dom::bindings::str::DOMString; use dom::bluetooth::{AsyncBluetoothListener, response_async}; -use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties; use dom::bluetoothdevice::BluetoothDevice; -use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic; use dom::bluetoothuuid::{BluetoothCharacteristicUUID, BluetoothServiceUUID, BluetoothUUID}; use dom::eventtarget::EventTarget; use dom::globalscope::GlobalScope; @@ -64,10 +62,6 @@ impl BluetoothRemoteGATTService { BluetoothRemoteGATTServiceBinding::Wrap) } - pub fn get_device(&self) -> Root<BluetoothDevice> { - self.device.get() - } - fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> { self.global().as_window().bluetooth_thread() } @@ -276,33 +270,13 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { impl AsyncBluetoothListener for BluetoothRemoteGATTService { fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) { + let device = self.Device(); match response { // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren // Step 7. BluetoothResponse::GetCharacteristic(characteristic) => { - let context = self.device.get().get_context(); - let mut characteristic_map = context.get_characteristic_map().borrow_mut(); - if let Some(existing_characteristic) = characteristic_map.get(&characteristic.instance_id) { - return promise.resolve_native(promise_cx, &existing_characteristic.get()); - } - let properties = - BluetoothCharacteristicProperties::new(&self.global(), - characteristic.broadcast, - characteristic.read, - characteristic.write_without_response, - characteristic.write, - characteristic.notify, - characteristic.indicate, - characteristic.authenticated_signed_writes, - characteristic.reliable_write, - characteristic.writable_auxiliaries); - let bt_characteristic = BluetoothRemoteGATTCharacteristic::new(&self.global(), - self, - DOMString::from(characteristic.uuid), - &properties, - characteristic.instance_id.clone()); - characteristic_map.insert(characteristic.instance_id, MutHeap::new(&bt_characteristic)); + let bt_characteristic = device.get_or_create_characteristic(&characteristic, &self); promise.resolve_native(promise_cx, &bt_characteristic); }, // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics @@ -310,34 +284,8 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTService { // Step 7. BluetoothResponse::GetCharacteristics(characteristics_vec) => { let mut characteristics = vec!(); - let context = self.device.get().get_context(); - let mut characteristic_map = context.get_characteristic_map().borrow_mut(); for characteristic in characteristics_vec { - let bt_characteristic = match characteristic_map.get(&characteristic.instance_id) { - Some(existing_characteristic) => existing_characteristic.get(), - None => { - let properties = - BluetoothCharacteristicProperties::new(&self.global(), - characteristic.broadcast, - characteristic.read, - characteristic.write_without_response, - characteristic.write, - characteristic.notify, - characteristic.indicate, - characteristic.authenticated_signed_writes, - characteristic.reliable_write, - characteristic.writable_auxiliaries); - - BluetoothRemoteGATTCharacteristic::new(&self.global(), - self, - DOMString::from(characteristic.uuid), - &properties, - characteristic.instance_id.clone()) - }, - }; - if !characteristic_map.contains_key(&characteristic.instance_id) { - characteristic_map.insert(characteristic.instance_id, MutHeap::new(&bt_characteristic)); - } + let bt_characteristic = device.get_or_create_characteristic(&characteristic, &self); characteristics.push(bt_characteristic); } promise.resolve_native(promise_cx, &characteristics); diff --git a/components/script/dom/bluetoothuuid.rs b/components/script/dom/bluetoothuuid.rs index fbf49142aa3..e16d8141e50 100644 --- a/components/script/dom/bluetoothuuid.rs +++ b/components/script/dom/bluetoothuuid.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::UnionTypes::StringOrUnsignedLong; -use dom::bindings::error::Error::Syntax; +use dom::bindings::error::Error::Type; use dom::bindings::error::Fallible; use dom::bindings::reflector::Reflector; use dom::bindings::str::DOMString; @@ -267,7 +267,19 @@ const BASE_UUID: &'static str = "-0000-1000-8000-00805f9b34fb"; const SERVICE_PREFIX: &'static str = "org.bluetooth.service"; const CHARACTERISTIC_PREFIX: &'static str = "org.bluetooth.characteristic"; const DESCRIPTOR_PREFIX: &'static str = "org.bluetooth.descriptor"; -const VALID_UUID_REGEX: &'static str = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; +const VALID_UUID_REGEX: &'static str = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"; +// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=314 +const UUID_ERROR_MESSAGE: &'static str = "It must be a valid UUID alias (e.g. 0x1234), \ + UUID (lowercase hex characters e.g. '00001234-0000-1000-8000-00805f9b34fb'),\nor recognized standard name from"; +// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=321 +const SERVICES_ERROR_MESSAGE: &'static str = "https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx\ + \ne.g. 'alert_notification'."; +// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=327 +const CHARACTERISTIC_ERROR_MESSAGE: &'static str = "https://developer.bluetooth.org/gatt/characteristics/Pages/\ + CharacteristicsHome.aspx\ne.g. 'aerobic_heart_rate_lower_limit'."; +// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=333 +const DESCRIPTOR_ERROR_MESSAGE: &'static str = "https://developer.bluetooth.org/gatt/descriptors/Pages/\ + DescriptorsHomePage.aspx\ne.g. 'gatt.characteristic_presentation_format'."; impl BluetoothUUID { // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-canonicaluuid @@ -296,7 +308,7 @@ impl BluetoothUUID { resolve_uuid_name(name, BLUETOOTH_ASSIGNED_SERVICES, SERVICE_PREFIX) } - pub fn characteristic(name: BluetoothServiceUUID) -> Fallible<UUID> { + pub fn characteristic(name: BluetoothCharacteristicUUID) -> Fallible<UUID> { resolve_uuid_name(name, BLUETOOTH_ASSIGNED_CHARCTERISTICS, CHARACTERISTIC_PREFIX) } @@ -325,22 +337,35 @@ fn resolve_uuid_name( prefix: &str) -> Fallible<DOMString> { match name { - // Step 1 + // Step 1. StringOrUnsignedLong::UnsignedLong(unsigned32) => { Ok(canonical_uuid(unsigned32)) }, StringOrUnsignedLong::String(dstring) => { - // Step 2 + // Step 2. let regex = Regex::new(VALID_UUID_REGEX).unwrap(); if regex.is_match(&*dstring) { Ok(dstring) } else { - // Step 3 + // Step 3. let concatenated = format!("{}.{}", prefix, dstring); let is_in_table = assigned_numbers_table.iter().find(|p| p.0 == concatenated); match is_in_table { Some(&(_, alias)) => Ok(canonical_uuid(alias)), - None => Err(Syntax), + None => { + let (attribute_type, error_url_message) = match prefix { + SERVICE_PREFIX => ("Service", SERVICES_ERROR_MESSAGE), + CHARACTERISTIC_PREFIX => ("Characteristic", CHARACTERISTIC_ERROR_MESSAGE), + DESCRIPTOR_PREFIX => ("Descriptor", DESCRIPTOR_ERROR_MESSAGE), + _ => unreachable!(), + }; + // Step 4. + return Err(Type(format!("Invalid {} name : '{}'.\n{} {}", + attribute_type, + dstring, + UUID_ERROR_MESSAGE, + error_url_message))); + }, } } }, diff --git a/components/script/dom/crypto.rs b/components/script/dom/crypto.rs index 22466f3f14c..4120456c77c 100644 --- a/components/script/dom/crypto.rs +++ b/components/script/dom/crypto.rs @@ -15,7 +15,7 @@ use js::jsapi::{JSContext, JSObject}; use js::jsapi::{JS_GetArrayBufferViewType, Type}; use rand::{OsRng, Rng}; -no_jsmanaged_fields!(OsRng); +unsafe_no_jsmanaged_fields!(OsRng); // https://developer.mozilla.org/en-US/docs/Web/API/Crypto #[dom_struct] diff --git a/components/script/dom/cssrulelist.rs b/components/script/dom/cssrulelist.rs index 5f594c27d8c..9c55f561806 100644 --- a/components/script/dom/cssrulelist.rs +++ b/components/script/dom/cssrulelist.rs @@ -16,8 +16,10 @@ use parking_lot::RwLock; use std::sync::Arc; use style::stylesheets::{CssRules, KeyframesRule, RulesMutateError}; -no_jsmanaged_fields!(RulesSource); -no_jsmanaged_fields!(CssRules); +#[allow(unsafe_code)] +unsafe_no_jsmanaged_fields!(RulesSource); + +unsafe_no_jsmanaged_fields!(CssRules); impl From<RulesMutateError> for Error { fn from(other: RulesMutateError) -> Self { diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index cf63dfcfb9a..468f127f7ad 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -3,9 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use core::nonzero::NonZero; +use devtools_traits::ScriptToDevtoolsControlMsg; use document_loader::{DocumentLoader, LoadType}; use dom::activation::{ActivationSource, synthetic_click_activation}; use dom::attr::Attr; +use dom::bindings::callback::ExceptionHandling; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::DOMRectBinding::DOMRectMethods; use dom::bindings::codegen::Bindings::DocumentBinding; @@ -18,7 +20,7 @@ use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter; use dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods; use dom::bindings::codegen::Bindings::TouchBinding::TouchMethods; -use dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, WindowMethods}; +use dom::bindings::codegen::Bindings::WindowBinding::{FrameRequestCallback, ScrollBehavior, WindowMethods}; use dom::bindings::codegen::UnionTypes::NodeOrString; use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId}; @@ -87,6 +89,7 @@ use dom::window::{ReflowReason, Window}; use encoding::EncodingRef; use encoding::all::UTF_8; use euclid::point::Point2D; +use gfx_traits::ScrollRootId; use html5ever::tree_builder::{LimitedQuirks, NoQuirks, Quirks, QuirksMode}; use html5ever_atoms::{LocalName, QualName}; use ipc_channel::ipc::{self, IpcSender}; @@ -111,7 +114,6 @@ use servo_atoms::Atom; use servo_url::ServoUrl; use std::ascii::AsciiExt; use std::borrow::ToOwned; -use std::boxed::FnBox; use std::cell::{Cell, Ref, RefMut}; use std::collections::HashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -232,8 +234,7 @@ pub struct Document { animation_frame_ident: Cell<u32>, /// https://html.spec.whatwg.org/multipage/#list-of-animation-frame-callbacks /// List of animation frame callbacks - #[ignore_heap_size_of = "closures are hard"] - animation_frame_list: DOMRefCell<Vec<(u32, Option<Box<FnBox(f64)>>)>>, + animation_frame_list: DOMRefCell<Vec<(u32, Option<AnimationFrameCallback>)>>, /// Whether we're in the process of running animation callbacks. /// /// Tracking this is not necessary for correctness. Instead, it is an optimization to avoid @@ -641,7 +642,10 @@ impl Document { if let Some((x, y)) = point { // Step 3 - self.window.perform_a_scroll(x, y, ScrollBehavior::Instant, + self.window.perform_a_scroll(x, + y, + ScrollRootId::root(), + ScrollBehavior::Instant, target.r()); } } @@ -1479,7 +1483,7 @@ impl Document { } /// https://html.spec.whatwg.org/multipage/#dom-window-requestanimationframe - pub fn request_animation_frame(&self, callback: Box<FnBox(f64)>) -> u32 { + pub fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 { let ident = self.animation_frame_ident.get() + 1; self.animation_frame_ident.set(ident); @@ -1520,7 +1524,7 @@ impl Document { for (_, callback) in animation_frame_list.drain(..) { if let Some(callback) = callback { - callback(*timing); + callback.call(self, *timing); } } @@ -3201,3 +3205,29 @@ pub enum FocusEventType { Focus, // Element gained focus. Doesn't bubble. Blur, // Element lost focus. Doesn't bubble. } + +#[derive(HeapSizeOf, JSTraceable)] +pub enum AnimationFrameCallback { + DevtoolsFramerateTick { actor_name: String }, + FrameRequestCallback { + #[ignore_heap_size_of = "Rc is hard"] + callback: Rc<FrameRequestCallback> + }, +} + +impl AnimationFrameCallback { + fn call(&self, document: &Document, now: f64) { + match *self { + AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => { + let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now); + let devtools_sender = document.window().upcast::<GlobalScope>().devtools_chan().unwrap(); + devtools_sender.send(msg).unwrap(); + } + AnimationFrameCallback::FrameRequestCallback { ref callback } => { + // TODO(jdm): The spec says that any exceptions should be suppressed: + // https://github.com/servo/servo/issues/6928 + let _ = callback.Call__(Finite::wrap(now), ExceptionHandling::Report); + } + } + } +} diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index c322b96a555..87674c835d0 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -109,6 +109,7 @@ impl HTMLIFrameElement { 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) } @@ -692,6 +693,7 @@ impl VirtualMethods for HTMLIFrameElement { // iframe attributes for the "first time"." if self.upcast::<Node>().is_in_doc_with_browsing_context() { debug!("iframe {} bound to browsing context.", self.frame_id); + debug_assert!(tree_in_doc, "is_in_doc_with_bc, but not tree_in_doc"); self.create_nested_browsing_context(); self.process_the_iframe_attributes(ProcessingMode::FirstTime); } @@ -705,6 +707,7 @@ impl VirtualMethods for HTMLIFrameElement { // https://html.spec.whatwg.org/multipage/#a-browsing-context-is-discarded if let Some(pipeline_id) = self.pipeline_id.get() { + debug!("Unbinding pipeline {} from frame {}.", pipeline_id, self.frame_id); let window = window_from_node(self); // The only reason we're waiting for the iframe to be totally diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index f0518c55f88..e158caac17e 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -50,7 +50,7 @@ use style::parser::ParserContextExtraData; use style::str::HTML_SPACE_CHARACTERS; use style::stylesheets::{Stylesheet, Origin}; -no_jsmanaged_fields!(Stylesheet); +unsafe_no_jsmanaged_fields!(Stylesheet); #[dom_struct] pub struct HTMLLinkElement { diff --git a/components/script/dom/keyboardevent.rs b/components/script/dom/keyboardevent.rs index 99cc61e021f..38a25d4dc1e 100644 --- a/components/script/dom/keyboardevent.rs +++ b/components/script/dom/keyboardevent.rs @@ -19,7 +19,7 @@ use msg::constellation_msg::{Key, KeyModifiers}; use std::borrow::Cow; use std::cell::Cell; -no_jsmanaged_fields!(Key); +unsafe_no_jsmanaged_fields!(Key); #[dom_struct] pub struct KeyboardEvent { diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index 53c5bd20115..99b06bae39d 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -302,38 +302,31 @@ macro_rules! make_nonzero_dimension_setter( /// For use on non-jsmanaged types /// Use #[derive(JSTraceable)] on JS managed types -macro_rules! no_jsmanaged_fields( - ([$ty:ident; $count:expr]) => ( - impl $crate::dom::bindings::trace::JSTraceable for [$ty; $count] { - #[inline] - fn trace(&self, _: *mut ::js::jsapi::JSTracer) { - // Do nothing - } - } - ); +macro_rules! unsafe_no_jsmanaged_fields( ($($ty:ident),+) => ( $( - impl $crate::dom::bindings::trace::JSTraceable for $ty { + #[allow(unsafe_code)] + unsafe impl $crate::dom::bindings::trace::JSTraceable for $ty { #[inline] - fn trace(&self, _: *mut ::js::jsapi::JSTracer) { + unsafe fn trace(&self, _: *mut ::js::jsapi::JSTracer) { // Do nothing } } )+ ); - ($ty:ident<$($gen:ident),+>) => ( - impl<$($gen),+> $crate::dom::bindings::trace::JSTraceable for $ty<$($gen),+> { - #[inline] - fn trace(&self, _: *mut ::js::jsapi::JSTracer) { - // Do nothing - } - } - ); - ($ty:ident<$($gen:ident: $bound:ident),+>) => ( - impl<$($gen: $bound),+> $crate::dom::bindings::trace::JSTraceable for $ty<$($gen),+> { +); + +macro_rules! jsmanaged_array( + ($count:expr) => ( + #[allow(unsafe_code)] + unsafe impl<T> $crate::dom::bindings::trace::JSTraceable for [T; $count] + where T: $crate::dom::bindings::trace::JSTraceable + { #[inline] - fn trace(&self, _: *mut ::js::jsapi::JSTracer) { - // Do nothing + unsafe fn trace(&self, tracer: *mut ::js::jsapi::JSTracer) { + for v in self.iter() { + v.trace(tracer); + } } } ); diff --git a/components/script/dom/mediaquerylist.rs b/components/script/dom/mediaquerylist.rs index 8b77bc4155b..86f67cdd8a1 100644 --- a/components/script/dom/mediaquerylist.rs +++ b/components/script/dom/mediaquerylist.rs @@ -143,8 +143,9 @@ impl WeakMediaQueryListVec { } } -impl JSTraceable for WeakMediaQueryListVec { - fn trace(&self, _: *mut JSTracer) { +#[allow(unsafe_code)] +unsafe impl JSTraceable for WeakMediaQueryListVec { + unsafe fn trace(&self, _: *mut JSTracer) { self.cell.borrow_mut().retain_alive() } } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index f08b1480eef..5f979bd8c9f 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -2566,7 +2566,7 @@ struct UniqueId { cell: UnsafeCell<Option<Box<Uuid>>>, } -no_jsmanaged_fields!(UniqueId); +unsafe_no_jsmanaged_fields!(UniqueId); impl HeapSizeOf for UniqueId { #[allow(unsafe_code)] diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index b2507aeab3b..723239ea3d3 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -1262,8 +1262,8 @@ impl HeapSizeOf for WeakRangeVec { } #[allow(unsafe_code)] -impl JSTraceable for WeakRangeVec { - fn trace(&self, _: *mut JSTracer) { - unsafe { (*self.cell.get()).retain_alive() } +unsafe impl JSTraceable for WeakRangeVec { + unsafe fn trace(&self, _: *mut JSTracer) { + (*self.cell.get()).retain_alive() } } diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs index 0f806171a9b..ac6330c3ca2 100644 --- a/components/script/dom/servoparser/html.rs +++ b/components/script/dom/servoparser/html.rs @@ -96,8 +96,9 @@ impl Tokenizer { } } -impl JSTraceable for HtmlTokenizer<TreeBuilder<JS<Node>, Sink>> { - fn trace(&self, trc: *mut JSTracer) { +#[allow(unsafe_code)] +unsafe impl JSTraceable for HtmlTokenizer<TreeBuilder<JS<Node>, Sink>> { + unsafe fn trace(&self, trc: *mut JSTracer) { struct Tracer(*mut JSTracer); let tracer = Tracer(trc); @@ -105,7 +106,7 @@ impl JSTraceable for HtmlTokenizer<TreeBuilder<JS<Node>, Sink>> { type Handle = JS<Node>; #[allow(unrooted_must_root)] fn trace_handle(&self, node: &JS<Node>) { - node.trace(self.0); + unsafe { node.trace(self.0); } } } diff --git a/components/script/dom/servoparser/xml.rs b/components/script/dom/servoparser/xml.rs index 9d527ce21d1..bcbfa6c4169 100644 --- a/components/script/dom/servoparser/xml.rs +++ b/components/script/dom/servoparser/xml.rs @@ -72,8 +72,9 @@ impl Tokenizer { } } -impl JSTraceable for XmlTokenizer<XmlTreeBuilder<JS<Node>, Sink>> { - fn trace(&self, trc: *mut JSTracer) { +#[allow(unsafe_code)] +unsafe impl JSTraceable for XmlTokenizer<XmlTreeBuilder<JS<Node>, Sink>> { + unsafe fn trace(&self, trc: *mut JSTracer) { struct Tracer(*mut JSTracer); let tracer = Tracer(trc); @@ -81,7 +82,7 @@ impl JSTraceable for XmlTokenizer<XmlTreeBuilder<JS<Node>, Sink>> { type Handle = JS<Node>; #[allow(unrooted_must_root)] fn trace_handle(&self, node: JS<Node>) { - node.trace(self.0); + unsafe { node.trace(self.0); } } } diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs index 9a1e4663152..ad20a127e17 100644 --- a/components/script/dom/webgltexture.rs +++ b/components/script/dom/webgltexture.rs @@ -26,7 +26,7 @@ pub enum TexParameterValue { const MAX_LEVEL_COUNT: usize = 31; const MAX_FACE_COUNT: usize = 6; -no_jsmanaged_fields!([ImageInfo; MAX_LEVEL_COUNT * MAX_FACE_COUNT]); +jsmanaged_array!(MAX_LEVEL_COUNT * MAX_FACE_COUNT); #[dom_struct] pub struct WebGLTexture { diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 3b1bd124398..77a569ef65a 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -6,7 +6,6 @@ use app_units::Au; use bluetooth_traits::BluetoothRequest; use cssparser::Parser; use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType}; -use dom::bindings::callback::ExceptionHandling; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState}; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; @@ -30,7 +29,7 @@ use dom::bindings::utils::{GlobalStaticData, WindowProxyHandler}; use dom::browsingcontext::BrowsingContext; use dom::crypto::Crypto; use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration}; -use dom::document::Document; +use dom::document::{AnimationFrameCallback, Document}; use dom::element::Element; use dom::event::Event; use dom::globalscope::GlobalScope; @@ -48,6 +47,7 @@ use dom::storage::Storage; use dom::testrunner::TestRunner; use euclid::{Point2D, Rect, Size2D}; use fetch; +use gfx_traits::ScrollRootId; use ipc_channel::ipc::{self, IpcSender}; use js::jsapi::{HandleObject, HandleValue, JSAutoCompartment, JSContext}; use js::jsapi::{JS_GC, JS_GetRuntime, SetWindowProxy}; @@ -67,7 +67,8 @@ 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_layout_interface::rpc::{MarginStyleResponse, NodeScrollRootIdResponse}; +use script_layout_interface::rpc::ResolvedStyleResponse; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThreadEventCategory}; use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable, RunnableWrapper}; use script_thread::SendableMainThreadScriptChan; @@ -197,7 +198,7 @@ pub struct Window { /// A handle to perform RPC calls into the layout, quickly. #[ignore_heap_size_of = "trait objects are hard"] - layout_rpc: Box<LayoutRPC + 'static>, + layout_rpc: Box<LayoutRPC + Send + 'static>, /// The current size of the window, in pixels. window_size: Cell<Option<WindowSizeData>>, @@ -599,15 +600,8 @@ impl WindowMethods for Window { /// https://html.spec.whatwg.org/multipage/#dom-window-requestanimationframe fn RequestAnimationFrame(&self, callback: Rc<FrameRequestCallback>) -> u32 { - let doc = self.Document(); - - let callback = move |now: f64| { - // TODO: @jdm The spec says that any exceptions should be suppressed; - // https://github.com/servo/servo/issues/6928 - let _ = callback.Call__(Finite::wrap(now), ExceptionHandling::Report); - }; - - doc.request_animation_frame(Box::new(callback)) + self.Document() + .request_animation_frame(AnimationFrameCallback::FrameRequestCallback { callback }) } /// https://html.spec.whatwg.org/multipage/#dom-window-cancelanimationframe @@ -967,13 +961,20 @@ impl Window { //TODO Step 11 //let document = self.Document(); // Step 12 - self.perform_a_scroll(x.to_f32().unwrap_or(0.0f32), y.to_f32().unwrap_or(0.0f32), - behavior, None); + self.perform_a_scroll(x.to_f32().unwrap_or(0.0f32), + y.to_f32().unwrap_or(0.0f32), + ScrollRootId::root(), + behavior, + None); } /// https://drafts.csswg.org/cssom-view/#perform-a-scroll - pub fn perform_a_scroll(&self, x: f32, y: f32, - behavior: ScrollBehavior, element: Option<&Element>) { + pub fn perform_a_scroll(&self, + x: f32, + y: f32, + scroll_root_id: ScrollRootId, + behavior: ScrollBehavior, + element: Option<&Element>) { //TODO Step 1 let point = Point2D::new(x, y); let smooth = match behavior { @@ -992,7 +993,7 @@ impl Window { let global_scope = self.upcast::<GlobalScope>(); let message = ConstellationMsg::ScrollFragmentPoint( - global_scope.pipeline_id(), point, smooth); + global_scope.pipeline_id(), scroll_root_id, point, smooth); global_scope.constellation_chan().send(message).unwrap(); } @@ -1273,11 +1274,24 @@ impl Window { } // https://drafts.csswg.org/cssom-view/#dom-element-scroll - pub fn scroll_node(&self, _node: TrustedNodeAddress, - x_: f64, y_: f64, behavior: ScrollBehavior) { + pub fn scroll_node(&self, + node: TrustedNodeAddress, + x_: f64, + y_: f64, + behavior: ScrollBehavior) { + if !self.reflow(ReflowGoal::ForScriptQuery, + ReflowQueryType::NodeScrollRootIdQuery(node), + ReflowReason::Query) { + return; + } + let NodeScrollRootIdResponse(scroll_root_id) = self.layout_rpc.node_scroll_root_id(); + // Step 12 - self.perform_a_scroll(x_.to_f32().unwrap_or(0.0f32), y_.to_f32().unwrap_or(0.0f32), - behavior, None); + self.perform_a_scroll(x_.to_f32().unwrap_or(0.0f32), + y_.to_f32().unwrap_or(0.0f32), + scroll_root_id, + behavior, + None); } pub fn resolved_style_query(&self, @@ -1547,7 +1561,7 @@ impl Window { parent_info: Option<(PipelineId, FrameType)>, window_size: Option<WindowSizeData>) -> Root<Window> { - let layout_rpc: Box<LayoutRPC> = { + let layout_rpc: Box<LayoutRPC + Send> = { let (rpc_send, rpc_recv) = channel(); layout_chan.send(Msg::GetRPC(rpc_send)).unwrap(); rpc_recv.recv().unwrap() @@ -1649,6 +1663,7 @@ fn debug_reflow_events(id: PipelineId, goal: &ReflowGoal, query_type: &ReflowQue ReflowQueryType::NodeGeometryQuery(_n) => "\tNodeGeometryQuery", ReflowQueryType::NodeOverflowQuery(_n) => "\tNodeOverFlowQuery", ReflowQueryType::NodeScrollGeometryQuery(_n) => "\tNodeScrollGeometryQuery", + ReflowQueryType::NodeScrollRootIdQuery(_n) => "\tNodeScrollRootIdQuery", ReflowQueryType::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery", ReflowQueryType::OffsetParentQuery(_n) => "\tOffsetParentQuery", ReflowQueryType::MarginStyleQuery(_n) => "\tMarginStyleQuery", diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 292de083c84..b7706114ad1 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -240,14 +240,7 @@ impl XMLHttpRequest { } fn process_response_eof(&mut self, response: Result<(), NetworkError>) { - let rv = match response { - Ok(()) => { - self.xhr.root().process_response_complete(self.gen_id, Ok(())) - } - Err(e) => { - self.xhr.root().process_response_complete(self.gen_id, Err(e)) - } - }; + let rv = self.xhr.root().process_response_complete(self.gen_id, response); *self.sync_status.borrow_mut() = Some(rv); } } diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index 8838787defc..a6d4815090f 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -477,6 +477,10 @@ impl<'le> TElement for ServoLayoutElement<'le> { }) } } + + fn skip_root_and_item_based_display_fixup(&self) -> bool { + false + } } impl<'le> PartialEq for ServoLayoutElement<'le> { diff --git a/components/script/lib.rs b/components/script/lib.rs index cf3aadf1658..e80e9553956 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -6,7 +6,7 @@ #![feature(conservative_impl_trait)] #![feature(const_fn)] #![feature(core_intrinsics)] -#![feature(fnbox)] +#![feature(field_init_shorthand)] #![feature(mpsc_select)] #![feature(nonzero)] #![feature(on_unimplemented)] diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs index 154353c71e8..f65b145c4ec 100644 --- a/components/script/script_runtime.rs +++ b/components/script/script_runtime.rs @@ -10,7 +10,7 @@ use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::PromiseBinding::PromiseJobCallback; use dom::bindings::js::{Root, RootCollection, RootCollectionPtr, trace_roots}; use dom::bindings::refcounted::{LiveDOMReferences, trace_refcounted_objects}; -use dom::bindings::trace::trace_traceables; +use dom::bindings::trace::{JSTraceable, trace_traceables}; use dom::bindings::utils::DOM_CALLBACKS; use dom::globalscope::GlobalScope; use js::glue::CollectServoSizes; @@ -48,7 +48,7 @@ pub enum CommonScriptMsg { } /// A cloneable interface for communicating with an event loop. -pub trait ScriptChan { +pub trait ScriptChan: JSTraceable { /// Send a message to the associated event loop. fn send(&self, msg: CommonScriptMsg) -> Result<(), ()>; /// Clone this handle. diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs index 7fc50f0da14..581adbb45bc 100644 --- a/components/script_layout_interface/message.rs +++ b/components/script_layout_interface/message.rs @@ -94,6 +94,7 @@ pub enum ReflowQueryType { ContentBoxesQuery(TrustedNodeAddress), NodeOverflowQuery(TrustedNodeAddress), HitTestQuery(Point2D<f32>, Point2D<f32>, bool), + NodeScrollRootIdQuery(TrustedNodeAddress), NodeGeometryQuery(TrustedNodeAddress), NodeScrollGeometryQuery(TrustedNodeAddress), ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, Atom), diff --git a/components/script_layout_interface/rpc.rs b/components/script_layout_interface/rpc.rs index 94deab19b2b..6e19b3f3bcf 100644 --- a/components/script_layout_interface/rpc.rs +++ b/components/script_layout_interface/rpc.rs @@ -5,6 +5,7 @@ use app_units::Au; use euclid::point::Point2D; use euclid::rect::Rect; +use gfx_traits::ScrollRootId; use script_traits::UntrustedNodeAddress; use style::properties::longhands::{margin_top, margin_right, margin_bottom, margin_left, overflow_x}; @@ -27,6 +28,8 @@ pub trait LayoutRPC { 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 scroll root id of this node. Used by APIs such as `scrollTop` + fn node_scroll_root_id(&self) -> NodeScrollRootIdResponse; /// Requests the node containing the point of interest fn hit_test(&self) -> HitTestResponse; /// Query layout for the resolved value of a given CSS property @@ -48,6 +51,8 @@ pub struct NodeGeometryResponse { pub struct NodeOverflowResponse(pub Option<Point2D<overflow_x::computed_value::T>>); +pub struct NodeScrollRootIdResponse(pub ScrollRootId); + pub struct HitTestResponse { pub node_address: Option<UntrustedNodeAddress>, } diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs index 428642ce93b..1d1f32bf4b6 100644 --- a/components/script_layout_interface/wrapper_traits.rs +++ b/components/script_layout_interface/wrapper_traits.rs @@ -8,7 +8,7 @@ use HTMLCanvasData; use LayoutNodeType; use OpaqueStyleAndLayoutData; use SVGSVGData; -use gfx_traits::ByteIndex; +use gfx_traits::{ByteIndex, FragmentType, ScrollRootId}; use html5ever_atoms::{Namespace, LocalName}; use msg::constellation_msg::PipelineId; use range::Range; @@ -264,6 +264,20 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Debug + GetLayoutData + NodeInfo fn iframe_pipeline_id(&self) -> PipelineId; fn get_colspan(&self) -> u32; + + fn fragment_type(&self) -> FragmentType { + match self.get_pseudo_element_type() { + PseudoElementType::Normal => FragmentType::FragmentBody, + PseudoElementType::Before(_) => FragmentType::BeforePseudoContent, + PseudoElementType::After(_) => FragmentType::AfterPseudoContent, + PseudoElementType::DetailsSummary(_) => FragmentType::FragmentBody, + PseudoElementType::DetailsContent(_) => FragmentType::FragmentBody, + } + } + + fn scroll_root_id(&self) -> ScrollRootId { + ScrollRootId::new_of_type(self.opaque().id() as usize, self.fragment_type()) + } } // This trait is only public so that it can be implemented by the gecko wrapper. diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 7ef20af9fbc..e91a034fec9 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -16,6 +16,7 @@ use canvas_traits::CanvasMsg; use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; use euclid::point::Point2D; use euclid::size::Size2D; +use gfx_traits::ScrollRootId; use ipc_channel::ipc::IpcSender; use msg::constellation_msg::{FrameId, PipelineId, TraversalDirection}; use msg::constellation_msg::{Key, KeyModifiers, KeyState}; @@ -121,7 +122,7 @@ pub enum ScriptMsg { /// Check if an alert dialog box should be presented Alert(PipelineId, String, IpcSender<bool>), /// Scroll a page in a window - ScrollFragmentPoint(PipelineId, Point2D<f32>, bool), + ScrollFragmentPoint(PipelineId, ScrollRootId, Point2D<f32>, bool), /// Set title of current page /// https://html.spec.whatwg.org/multipage/#document.title SetTitle(PipelineId, Option<String>), diff --git a/components/style/dom.rs b/components/style/dom.rs index da476cedbaf..5c66bbc0e0f 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -269,4 +269,9 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre fn mutate_data(&self) -> Option<AtomicRefMut<ElementData>> { self.get_data().map(|x| x.borrow_mut()) } + + /// Whether we should skip any root- or item-based display property + /// blockification on this element. (This function exists so that Gecko + /// native anonymous content can opt out of this style fixup.) + fn skip_root_and_item_based_display_fixup(&self) -> bool; } diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 5a8c462db9e..6b124d55d20 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -371,6 +371,15 @@ impl<'le> TElement for GeckoElement<'le> { fn get_data(&self) -> Option<&AtomicRefCell<ElementData>> { unsafe { self.0.mServoData.get().as_ref() } } + + fn skip_root_and_item_based_display_fixup(&self) -> bool { + // We don't want to fix up display values of native anonymous content. + // Additionally, we want to skip root-based display fixup for document + // level native anonymous content subtree roots, since they're not + // really roots from the style fixup perspective. Checking that we + // are NAC handles both cases. + self.flags() & (NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE as u32) != 0 + } } impl<'le> PartialEq for GeckoElement<'le> { diff --git a/components/style/gecko_bindings/structs_debug.rs b/components/style/gecko_bindings/structs_debug.rs index 2fa43b82fcc..4cfdc5899ed 100644 --- a/components/style/gecko_bindings/structs_debug.rs +++ b/components/style/gecko_bindings/structs_debug.rs @@ -2596,17 +2596,17 @@ pub enum StyleDisplay { Contents = 24, WebkitBox = 25, WebkitInlineBox = 26, - Box = 27, - InlineBox = 28, - XulGrid = 29, - InlineXulGrid = 30, - XulGridGroup = 31, - XulGridLine = 32, - Stack = 33, - InlineStack = 34, - Deck = 35, - Groupbox = 36, - Popup = 37, + MozBox = 27, + MozInlineBox = 28, + MozGrid = 29, + MozInlineGrid = 30, + MozGridGroup = 31, + MozGridLine = 32, + MozStack = 33, + MozInlineStack = 34, + MozDeck = 35, + MozGroupbox = 36, + MozPopup = 37, } /** * A class for holding strong references to handle-managed objects. diff --git a/components/style/gecko_bindings/structs_release.rs b/components/style/gecko_bindings/structs_release.rs index 3d2bf88dbb7..11b1f6ea393 100644 --- a/components/style/gecko_bindings/structs_release.rs +++ b/components/style/gecko_bindings/structs_release.rs @@ -2570,17 +2570,17 @@ pub enum StyleDisplay { Contents = 24, WebkitBox = 25, WebkitInlineBox = 26, - Box = 27, - InlineBox = 28, - XulGrid = 29, - InlineXulGrid = 30, - XulGridGroup = 31, - XulGridLine = 32, - Stack = 33, - InlineStack = 34, - Deck = 35, - Groupbox = 36, - Popup = 37, + MozBox = 27, + MozInlineBox = 28, + MozGrid = 29, + MozInlineGrid = 30, + MozGridGroup = 31, + MozGridLine = 32, + MozStack = 33, + MozInlineStack = 34, + MozDeck = 35, + MozGroupbox = 36, + MozPopup = 37, } /** * A class for holding strong references to handle-managed objects. diff --git a/components/style/keyframes.rs b/components/style/keyframes.rs index 831627d42c3..474e4c8b539 100644 --- a/components/style/keyframes.rs +++ b/components/style/keyframes.rs @@ -14,7 +14,7 @@ use std::sync::Arc; use style_traits::ToCss; use stylesheets::{MemoryHoleReporter, Stylesheet}; -/// A number from 1 to 100, indicating the percentage of the animation where +/// A number from 0 to 1, indicating the percentage of the animation where /// this keyframe should run. #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] @@ -30,6 +30,12 @@ impl ::std::cmp::Ord for KeyframePercentage { impl ::std::cmp::Eq for KeyframePercentage { } +impl ToCss for KeyframePercentage { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + write!(dest, "{}%", self.0 * 100.0) + } +} + impl KeyframePercentage { #[inline] pub fn new(value: f32) -> KeyframePercentage { @@ -93,10 +99,10 @@ pub struct Keyframe { impl ToCss for Keyframe { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { let mut iter = self.selector.percentages().iter(); - try!(write!(dest, "{}%", iter.next().unwrap().0)); + try!(iter.next().unwrap().to_css(dest)); for percentage in iter { try!(write!(dest, ", ")); - try!(write!(dest, "{}%", percentage.0)); + try!(percentage.to_css(dest)); } try!(dest.write_str(" { ")); try!(self.block.read().to_css(dest)); diff --git a/components/style/matching.rs b/components/style/matching.rs index e883d11bc3e..3b0a396507d 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -14,7 +14,7 @@ use cascade_info::CascadeInfo; use context::{SharedStyleContext, StyleContext}; use data::{ComputedStyle, ElementData, ElementStyles, PseudoStyles}; use dom::{TElement, TNode, TRestyleDamage, UnsafeNode}; -use properties::{CascadeFlags, ComputedValues, SHAREABLE, cascade}; +use properties::{CascadeFlags, ComputedValues, SHAREABLE, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade}; use properties::longhands::display::computed_value as display; use rule_tree::StrongRuleNode; use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl}; @@ -405,6 +405,9 @@ trait PrivateMatchMethods: TElement { if booleans.shareable { cascade_flags.insert(SHAREABLE) } + if self.skip_root_and_item_based_display_fixup() { + cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP) + } let this_style = match parent_style { Some(ref parent_style) => { diff --git a/components/style/properties/data.py b/components/style/properties/data.py index afddf0f4bb7..cdf4560783b 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -28,7 +28,9 @@ def to_camel_case(ident): class Keyword(object): def __init__(self, name, values, gecko_constant_prefix=None, gecko_enum_prefix=None, custom_consts=None, - extra_gecko_values=None, extra_servo_values=None): + extra_gecko_values=None, extra_servo_values=None, + gecko_strip_moz_prefix=True, + gecko_inexhaustive=None): self.name = name self.values = values.split() if gecko_constant_prefix and gecko_enum_prefix: @@ -39,6 +41,8 @@ class Keyword(object): self.extra_gecko_values = (extra_gecko_values or "").split() self.extra_servo_values = (extra_servo_values or "").split() self.consts_map = {} if custom_consts is None else custom_consts + self.gecko_strip_moz_prefix = gecko_strip_moz_prefix + self.gecko_inexhaustive = gecko_inexhaustive or (gecko_enum_prefix is None) def gecko_values(self): return self.values + self.extra_gecko_values @@ -55,7 +59,7 @@ class Keyword(object): raise Exception("Bad product: " + product) def gecko_constant(self, value): - moz_stripped = value.replace("-moz-", '') + moz_stripped = value.replace("-moz-", '') if self.gecko_strip_moz_prefix else value parts = moz_stripped.split('-') if self.gecko_enum_prefix: parts = [p.title() for p in parts] diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index a9afd64c5b0..c424ca705a7 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -255,7 +255,9 @@ def set_gecko_property(ffi_name, expr): % for value in keyword.values_for('gecko'): structs::${keyword.gecko_constant(value)} => Keyword::${to_rust_ident(value)}, % endfor + % if keyword.gecko_inexhaustive: x => panic!("Found unexpected value in style struct for ${ident} property: {:?}", x), + % endif } } </%def> @@ -1026,9 +1028,31 @@ fn static_assert() { <% display_keyword = Keyword("display", "inline block inline-block table inline-table table-row-group " + "table-header-group table-footer-group table-row table-column-group " + "table-column table-cell table-caption list-item flex none " + - "-moz-box -moz-inline-box", - gecko_enum_prefix="StyleDisplay") %> - ${impl_keyword('display', 'mDisplay', display_keyword, True)} + "inline-flex grid inline-grid ruby ruby-base ruby-base-container " + + "ruby-text ruby-text-container contents -webkit-box -webkit-inline-box " + + "-moz-box -moz-inline-box -moz-grid -moz-inline-grid -moz-grid-group " + + "-moz-grid-line -moz-stack -moz-inline-stack -moz-deck -moz-popup " + + "-moz-groupbox", + gecko_enum_prefix="StyleDisplay", + gecko_strip_moz_prefix=False) %> + + pub fn set_display(&mut self, v: longhands::display::computed_value::T) { + use properties::longhands::display::computed_value::T as Keyword; + // FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts + let result = match v { + % for value in display_keyword.values_for('gecko'): + Keyword::${to_rust_ident(value)} => + structs::${display_keyword.gecko_constant(value)}, + % endfor + }; + self.gecko.mDisplay = result; + self.gecko.mOriginalDisplay = result; + } + pub fn copy_display_from(&mut self, other: &Self) { + self.gecko.mDisplay = other.gecko.mDisplay; + self.gecko.mOriginalDisplay = other.gecko.mOriginalDisplay; + } + <%call expr="impl_keyword_clone('display', 'mDisplay', display_keyword)"></%call> // overflow-y is implemented as a newtype of overflow-x, so we need special handling. // We could generalize this if we run into other newtype keywords. diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 4fdbeda88c8..5d58fd6db5c 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -329,7 +329,7 @@ keyword_kwargs = {a: kwargs.pop(a, None) for a in [ 'gecko_constant_prefix', 'gecko_enum_prefix', 'extra_gecko_values', 'extra_servo_values', - 'custom_consts', + 'custom_consts', 'gecko_inexhaustive', ]} %> diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs index c4ccfeb032f..0393064d532 100644 --- a/components/style/properties/longhand/border.mako.rs +++ b/components/style/properties/longhand/border.mako.rs @@ -58,11 +58,13 @@ ${helpers.single_keyword("box-decoration-break", "slice clone", gecko_enum_prefix="StyleBoxDecorationBreak", + gecko_inexhaustive=True, products="gecko", animatable=False)} ${helpers.single_keyword("-moz-float-edge", "content-box margin-box", gecko_ffi_name="mFloatEdge", gecko_enum_prefix="StyleFloatEdge", + gecko_inexhaustive=True, products="gecko", animatable=False)} diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index c48d4948376..818ed9316e1 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -22,7 +22,11 @@ none """.split() if product == "gecko": - values += "-moz-box -moz-inline-box".split() + values += """inline-flex grid inline-grid ruby ruby-base ruby-base-container + ruby-text ruby-text-container contents -webkit-box -webkit-inline-box + -moz-box -moz-inline-box -moz-grid -moz-inline-grid -moz-grid-group + -moz-grid-line -moz-stack -moz-inline-stack -moz-deck -moz-popup + -moz-groupbox""".split() %> pub use self::computed_value::T as SpecifiedValue; use values::computed::ComputedValueAsSpecified; @@ -92,6 +96,7 @@ ${helpers.single_keyword("position", "static absolute relative fixed", animatable="False" need_clone="True" gecko_enum_prefix="StyleFloat" + gecko_inexhaustive="True" gecko_ffi_name="mFloat"> use values::NoViewportPercentage; impl NoViewportPercentage for SpecifiedValue {} diff --git a/components/style/properties/longhand/inherited_svg.mako.rs b/components/style/properties/longhand/inherited_svg.mako.rs index 8bff77f9c37..6a0b00eced9 100644 --- a/components/style/properties/longhand/inherited_svg.mako.rs +++ b/components/style/properties/longhand/inherited_svg.mako.rs @@ -35,6 +35,7 @@ ${helpers.predefined_type("fill-opacity", "Opacity", "1.0", ${helpers.single_keyword("fill-rule", "nonzero evenodd", gecko_enum_prefix="StyleFillRule", + gecko_inexhaustive=True, products="gecko", animatable=False)} ${helpers.single_keyword("shape-rendering", @@ -60,4 +61,5 @@ ${helpers.predefined_type("stroke-opacity", "Opacity", "1.0", ${helpers.single_keyword("clip-rule", "nonzero evenodd", products="gecko", gecko_enum_prefix="StyleFillRule", + gecko_inexhaustive=True, animatable=False)} diff --git a/components/style/properties/longhand/pointing.mako.rs b/components/style/properties/longhand/pointing.mako.rs index d5306f376a9..412e2fe080c 100644 --- a/components/style/properties/longhand/pointing.mako.rs +++ b/components/style/properties/longhand/pointing.mako.rs @@ -151,15 +151,18 @@ ${helpers.single_keyword("pointer-events", "auto none", animatable=False)} ${helpers.single_keyword("-moz-user-input", "none enabled disabled", products="gecko", gecko_ffi_name="mUserInput", gecko_enum_prefix="StyleUserInput", + gecko_inexhaustive=True, animatable=False)} ${helpers.single_keyword("-moz-user-modify", "read-only read-write write-only", products="gecko", gecko_ffi_name="mUserModify", gecko_enum_prefix="StyleUserModify", + gecko_inexhaustive=True, animatable=False)} ${helpers.single_keyword("-moz-user-focus", "ignore normal select-after select-before select-menu select-same select-all none", products="gecko", gecko_ffi_name="mUserFocus", gecko_enum_prefix="StyleUserFocus", + gecko_inexhaustive=True, animatable=False)} diff --git a/components/style/properties/longhand/ui.mako.rs b/components/style/properties/longhand/ui.mako.rs index f815c1d8518..cd537677f6f 100644 --- a/components/style/properties/longhand/ui.mako.rs +++ b/components/style/properties/longhand/ui.mako.rs @@ -16,4 +16,5 @@ ${helpers.single_keyword("ime-mode", "normal auto active disabled inactive", ${helpers.single_keyword("-moz-user-select", "auto text none all", products="gecko", gecko_ffi_name="mUserSelect", gecko_enum_prefix="StyleUserSelect", + gecko_inexhaustive=True, animatable=False)} diff --git a/components/style/properties/longhand/xul.mako.rs b/components/style/properties/longhand/xul.mako.rs index 23c1da1246b..bc64308a115 100644 --- a/components/style/properties/longhand/xul.mako.rs +++ b/components/style/properties/longhand/xul.mako.rs @@ -11,6 +11,7 @@ ${helpers.single_keyword("-moz-box-align", "stretch start center baseline end", products="gecko", gecko_ffi_name="mBoxAlign", gecko_enum_prefix="StyleBoxAlign", + gecko_inexhaustive=True, animatable=False)} ${helpers.predefined_type("-moz-box-flex", "Number", "0.0", "parse_non_negative", diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 97e3271e8b6..46688434651 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -1436,6 +1436,8 @@ bitflags! { /// Whether to inherit all styles from the parent. If this flag is not present, /// non-inherited styles are reset to their initial values. const INHERIT_ALL = 0x02, + /// Whether to skip any root element and flex/grid item display style fixup. + const SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP = 0x04, } } @@ -1630,30 +1632,50 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>, longhands::position::SpecifiedValue::absolute | longhands::position::SpecifiedValue::fixed); let floated = style.get_box().clone_float() != longhands::float::SpecifiedValue::none; - let is_flex_item = - context.inherited_style.get_box().clone_display() == computed_values::display::T::flex; - if positioned || floated || is_root_element || is_flex_item { + // FIXME(heycam): We should look past any display:contents ancestors to + // determine if we are a flex or grid item, but we don't have access to + // grandparent or higher style here. + let is_item = matches!(context.inherited_style.get_box().clone_display(), + % if product == "gecko": + computed_values::display::T::grid | + % endif + computed_values::display::T::flex); + let (blockify_root, blockify_item) = match flags.contains(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP) { + false => (is_root_element, is_item), + true => (false, false), + }; + if positioned || floated || blockify_root || blockify_item { use computed_values::display::T; let specified_display = style.get_box().clone_display(); let computed_display = match specified_display { - T::inline_table => { - Some(T::table) - } - T::inline | T::inline_block | - T::table_row_group | T::table_column | - T::table_column_group | T::table_header_group | - T::table_footer_group | T::table_row | T::table_cell | - T::table_caption => { - Some(T::block) - } - _ => None + // Values that have a corresponding block-outside version. + T::inline_table => Some(T::table), + % if product == "gecko": + T::inline_flex => Some(T::flex), + T::inline_grid => Some(T::grid), + T::_webkit_inline_box => Some(T::_webkit_box), + % endif + + // Special handling for contents and list-item on the root element for Gecko. + % if product == "gecko": + T::contents | T::list_item if blockify_root => Some(T::block), + % endif + + // Values that are not changed by blockification. + T::block | T::flex | T::list_item | T::table => None, + % if product == "gecko": + T::contents | T::grid | T::_webkit_box => None, + % endif + + // Everything becomes block. + _ => Some(T::block), }; if let Some(computed_display) = computed_display { let box_ = style.mutate_box(); box_.set_display(computed_display); % if product == "servo": - box_.set__servo_display_for_hypothetical_box(if is_root_element || is_flex_item { + box_.set__servo_display_for_hypothetical_box(if blockify_root || blockify_item { computed_display } else { specified_display |