servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio

<!-- Please describe your changes on the following line: -->

Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching:

* https://bugzilla.mozilla.org/show_bug.cgi?id=1311469
* https://bugzilla.mozilla.org/show_bug.cgi?id=1335941
* https://bugzilla.mozilla.org/show_bug.cgi?id=1339703

This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once.

In Stylo, there is one such lock per process (in a `lazy_static`), used for everything.

I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock.

This was previously #15998, closed accidentally.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

Source-Repo: https://github.com/servo/servo
Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
This commit is contained in:
Simon Sapin 2017-03-19 14:31:19 -07:00
parent 3fad952356
commit 33a9e6d050
73 changed files with 1468 additions and 911 deletions

5
servo/Cargo.lock generated
View File

@ -928,9 +928,7 @@ dependencies = [
"lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"selectors 0.18.0",
"servo_url 0.0.1",
"style 0.0.1",
@ -2756,8 +2754,8 @@ dependencies = [
"nsstring_vendor 0.1.0",
"num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2783,7 +2781,6 @@ dependencies = [
"cssparser 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"html5ever-atoms 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -446,7 +446,7 @@ fn translate_including_floats(cur_b: &mut Au, delta: Au, floats: &mut Floats) {
///
/// Note that flows with position 'fixed' just form a flat list as they all
/// have the Root flow as their CB.
pub struct AbsoluteAssignBSizesTraversal<'a>(pub &'a SharedStyleContext);
pub struct AbsoluteAssignBSizesTraversal<'a>(pub &'a SharedStyleContext<'a>);
impl<'a> PreorderFlowTraversal for AbsoluteAssignBSizesTraversal<'a> {
#[inline]

View File

@ -311,7 +311,7 @@ impl InlineFragmentsAccumulator {
/// An object that knows how to create flows.
pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> {
/// The layout context.
pub layout_context: &'a LayoutContext,
pub layout_context: &'a LayoutContext<'a>,
/// Satisfy the compiler about the unused parameters, which we use to improve the ergonomics of
/// the ensuing impl {} by removing the need to parameterize all the methods individually.
phantom2: PhantomData<N>,
@ -320,7 +320,7 @@ pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> {
impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
FlowConstructor<'a, ConcreteThreadSafeLayoutNode> {
/// Creates a new flow constructor.
pub fn new(layout_context: &'a LayoutContext) -> Self {
pub fn new(layout_context: &'a LayoutContext<'a>) -> Self {
FlowConstructor {
layout_context: layout_context,
phantom2: PhantomData,
@ -660,10 +660,9 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let mut style = node.style(self.style_context());
if node_is_input_or_text_area {
style = self.style_context()
.stylist
.style_for_anonymous_box(&PseudoElement::ServoInputText,
&style)
let context = self.style_context();
style = context.stylist.style_for_anonymous_box(
&context.guards, &PseudoElement::ServoInputText, &style)
}
self.create_fragments_for_node_text_content(&mut initial_fragments, node, &style)
@ -1096,11 +1095,14 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
-> ConstructionResult {
let mut legalizer = Legalizer::new();
let table_style = node.style(self.style_context());
let wrapper_style = self.style_context()
.stylist
.style_for_anonymous_box(&PseudoElement::ServoTableWrapper,
&table_style);
let table_style;
let wrapper_style;
{
let context = self.style_context();
table_style = node.style(context);
wrapper_style = context.stylist.style_for_anonymous_box(
&context.guards, &PseudoElement::ServoTableWrapper, &table_style);
}
let wrapper_fragment =
Fragment::from_opaque_node_and_style(node.opaque(),
PseudoElementType::Normal,
@ -2080,8 +2082,7 @@ impl Legalizer {
let reference_block = reference.as_block();
let mut new_style = reference_block.fragment.style.clone();
for pseudo in pseudos {
new_style = context.stylist.style_for_anonymous_box(pseudo,
&new_style)
new_style = context.stylist.style_for_anonymous_box(&context.guards, pseudo, &new_style)
}
let fragment = reference_block.fragment
.create_similar_anonymous_fragment(new_style,

View File

@ -75,9 +75,9 @@ pub fn heap_size_of_persistent_local_context() -> usize {
}
/// Layout information shared among all workers. This must be thread-safe.
pub struct LayoutContext {
pub struct LayoutContext<'a> {
/// Bits shared by the layout and style system.
pub style_context: SharedStyleContext,
pub style_context: SharedStyleContext<'a>,
/// The shared image cache thread.
pub image_cache_thread: Mutex<ImageCacheThread>,
@ -95,7 +95,7 @@ pub struct LayoutContext {
pub pending_images: Option<Mutex<Vec<PendingImage>>>
}
impl Drop for LayoutContext {
impl<'a> Drop for LayoutContext<'a> {
fn drop(&mut self) {
if !thread::panicking() {
if let Some(ref pending_images) = self.pending_images {
@ -105,7 +105,7 @@ impl Drop for LayoutContext {
}
}
impl LayoutContext {
impl<'a> LayoutContext<'a> {
#[inline(always)]
pub fn shared_context(&self) -> &SharedStyleContext {
&self.style_context

View File

@ -121,7 +121,7 @@ fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
}
pub struct DisplayListBuildState<'a> {
pub layout_context: &'a LayoutContext,
pub layout_context: &'a LayoutContext<'a>,
pub root_stacking_context: StackingContext,
pub items: HashMap<StackingContextId, Vec<DisplayItem>>,
pub stacking_context_children: HashMap<StackingContextId, Vec<StackingContext>>,

View File

@ -97,7 +97,7 @@ static KATAKANA_IROHA: [char; 47] = [
/// The generated content resolution traversal.
pub struct ResolveGeneratedContent<'a> {
/// The layout context.
layout_context: &'a LayoutContext,
layout_context: &'a LayoutContext<'a>,
/// The counter representing an ordered list item.
list_item: Counter,
/// Named CSS counters.

View File

@ -22,20 +22,20 @@ use style::traversal::PerLevelTraversalData;
use wrapper::{GetRawData, LayoutNodeHelpers, LayoutNodeLayoutData};
use wrapper::ThreadSafeLayoutNodeHelpers;
pub struct RecalcStyleAndConstructFlows {
context: LayoutContext,
pub struct RecalcStyleAndConstructFlows<'a> {
context: LayoutContext<'a>,
driver: TraversalDriver,
}
impl RecalcStyleAndConstructFlows {
pub fn layout_context(&self) -> &LayoutContext {
impl<'a> RecalcStyleAndConstructFlows<'a> {
pub fn layout_context(&self) -> &LayoutContext<'a> {
&self.context
}
}
impl RecalcStyleAndConstructFlows {
impl<'a> RecalcStyleAndConstructFlows<'a> {
/// Creates a traversal context, taking ownership of the shared layout context.
pub fn new(context: LayoutContext, driver: TraversalDriver) -> Self {
pub fn new(context: LayoutContext<'a>, driver: TraversalDriver) -> Self {
RecalcStyleAndConstructFlows {
context: context,
driver: driver,
@ -44,13 +44,13 @@ impl RecalcStyleAndConstructFlows {
/// Consumes this traversal context, returning ownership of the shared layout
/// context to the caller.
pub fn destroy(self) -> LayoutContext {
pub fn destroy(self) -> LayoutContext<'a> {
self.context
}
}
#[allow(unsafe_code)]
impl<E> DomTraversal<E> for RecalcStyleAndConstructFlows
impl<'a, E> DomTraversal<E> for RecalcStyleAndConstructFlows<'a>
where E: TElement,
E::ConcreteNode: LayoutNode,
{
@ -152,7 +152,7 @@ fn construct_flows_at<N>(context: &LayoutContext,
/// The bubble-inline-sizes traversal, the first part of layout computation. This computes
/// preferred and intrinsic inline-sizes and bubbles them up the tree.
pub struct BubbleISizes<'a> {
pub layout_context: &'a LayoutContext,
pub layout_context: &'a LayoutContext<'a>,
}
impl<'a> PostorderFlowTraversal for BubbleISizes<'a> {
@ -171,7 +171,7 @@ impl<'a> PostorderFlowTraversal for BubbleISizes<'a> {
/// The assign-inline-sizes traversal. In Gecko this corresponds to `Reflow`.
#[derive(Copy, Clone)]
pub struct AssignISizes<'a> {
pub layout_context: &'a LayoutContext,
pub layout_context: &'a LayoutContext<'a>,
}
impl<'a> PreorderFlowTraversal for AssignISizes<'a> {
@ -191,7 +191,7 @@ impl<'a> PreorderFlowTraversal for AssignISizes<'a> {
/// positions. In Gecko this corresponds to `Reflow`.
#[derive(Copy, Clone)]
pub struct AssignBSizes<'a> {
pub layout_context: &'a LayoutContext,
pub layout_context: &'a LayoutContext<'a>,
}
impl<'a> PostorderFlowTraversal for AssignBSizes<'a> {
@ -220,7 +220,7 @@ impl<'a> PostorderFlowTraversal for AssignBSizes<'a> {
#[derive(Copy, Clone)]
pub struct ComputeAbsolutePositions<'a> {
pub layout_context: &'a LayoutContext,
pub layout_context: &'a LayoutContext<'a>,
}
impl<'a> PreorderFlowTraversal for ComputeAbsolutePositions<'a> {

View File

@ -114,7 +114,9 @@ use style::error_reporting::StdoutErrorReporter;
use style::logical_geometry::LogicalPoint;
use style::media_queries::{Device, MediaType};
use style::parser::ParserContextExtraData;
use style::servo::AUTHOR_SHARED_LOCK;
use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION, STORE_OVERFLOW};
use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards};
use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets};
use style::stylist::Stylist;
use style::thread_state;
@ -214,7 +216,7 @@ pub struct LayoutThread {
WebRenderImageInfo,
BuildHasherDefault<FnvHasher>>>>,
// Webrender interface.
/// Webrender interface.
webrender_api: webrender_traits::RenderApi,
/// The timer object to control the timing of the animations. This should
@ -344,13 +346,14 @@ impl<'a, 'b: 'a> RwData<'a, 'b> {
}
fn add_font_face_rules(stylesheet: &Stylesheet,
guard: &SharedRwLockReadGuard,
device: &Device,
font_cache_thread: &FontCacheThread,
font_cache_sender: &IpcSender<()>,
outstanding_web_fonts_counter: &Arc<AtomicUsize>) {
if opts::get().load_webfonts_synchronously {
let (sender, receiver) = ipc::channel().unwrap();
stylesheet.effective_font_face_rules(&device, |font_face| {
stylesheet.effective_font_face_rules(&device, guard, |font_face| {
let effective_sources = font_face.effective_sources();
font_cache_thread.add_web_font(font_face.family.clone(),
effective_sources,
@ -358,7 +361,7 @@ fn add_font_face_rules(stylesheet: &Stylesheet,
receiver.recv().unwrap();
})
} else {
stylesheet.effective_font_face_rules(&device, |font_face| {
stylesheet.effective_font_face_rules(&device, guard, |font_face| {
let effective_sources = font_face.effective_sources();
outstanding_web_fonts_counter.fetch_add(1, Ordering::SeqCst);
font_cache_thread.add_web_font(font_face.family.clone(),
@ -406,8 +409,11 @@ impl LayoutThread {
let stylist = Arc::new(Stylist::new(device));
let outstanding_web_fonts_counter = Arc::new(AtomicUsize::new(0));
for stylesheet in &*UA_STYLESHEETS.user_or_user_agent_stylesheets {
let ua_stylesheets = &*UA_STYLESHEETS;
let guard = ua_stylesheets.shared_lock.read();
for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets {
add_font_face_rules(stylesheet,
&guard,
&stylist.device,
&font_cache_thread,
&ipc_font_cache_sender,
@ -493,16 +499,18 @@ impl LayoutThread {
}
// Create a layout context for use in building display lists, hit testing, &c.
fn build_layout_context(&self,
rw_data: &LayoutThreadData,
request_images: bool)
-> LayoutContext {
fn build_layout_context<'a>(&self,
guards: StylesheetGuards<'a>,
rw_data: &LayoutThreadData,
request_images: bool)
-> LayoutContext<'a> {
let thread_local_style_context_creation_data =
ThreadLocalStyleContextCreationInfo::new(self.new_animations_sender.clone());
LayoutContext {
style_context: SharedStyleContext {
stylist: rw_data.stylist.clone(),
guards: guards,
running_animations: self.running_animations.clone(),
expired_animations: self.expired_animations.clone(),
error_reporter: Box::new(self.error_reporter.clone()),
@ -730,8 +738,10 @@ impl LayoutThread {
// GWTODO: Need to handle unloading web fonts.
let rw_data = possibly_locked_rw_data.lock();
if stylesheet.is_effective_for_device(&rw_data.stylist.device) {
let guard = stylesheet.shared_lock.read();
if stylesheet.is_effective_for_device(&rw_data.stylist.device, &guard) {
add_font_face_rules(&*stylesheet,
&guard,
&rw_data.stylist.device,
&self.font_cache_thread,
&self.font_cache_sender,
@ -1009,8 +1019,11 @@ impl LayoutThread {
Au::from_f32_px(initial_viewport.height));
// Calculate the actual viewport as per DEVICE-ADAPT § 6
let author_guard = document.style_shared_lock().read();
let device = Device::new(MediaType::Screen, initial_viewport);
Arc::get_mut(&mut rw_data.stylist).unwrap().set_device(device, &data.document_stylesheets);
Arc::get_mut(&mut rw_data.stylist).unwrap()
.set_device(device, &author_guard, &data.document_stylesheets);
self.viewport_size =
rw_data.stylist.viewport_constraints().map_or(current_screen_size, |constraints| {
@ -1054,9 +1067,17 @@ impl LayoutThread {
}
// If the entire flow tree is invalid, then it will be reflowed anyhow.
let needs_dirtying = Arc::get_mut(&mut rw_data.stylist).unwrap().update(&data.document_stylesheets,
Some(&*UA_STYLESHEETS),
data.stylesheets_changed);
let ua_stylesheets = &*UA_STYLESHEETS;
let ua_or_user_guard = ua_stylesheets.shared_lock.read();
let guards = StylesheetGuards {
author: &author_guard,
ua_or_user: &ua_or_user_guard,
};
let needs_dirtying = Arc::get_mut(&mut rw_data.stylist).unwrap().update(
&data.document_stylesheets,
&guards,
Some(ua_stylesheets),
data.stylesheets_changed);
let needs_reflow = viewport_size_changed && !needs_dirtying;
if needs_dirtying {
if let Some(mut d) = element.mutate_data() {
@ -1102,7 +1123,7 @@ impl LayoutThread {
}
// Create a layout context for use throughout the following passes.
let mut layout_context = self.build_layout_context(&*rw_data, true);
let mut layout_context = self.build_layout_context(guards.clone(), &*rw_data, true);
// NB: Type inference falls apart here for some reason, so we need to be very verbose. :-(
let traversal_driver = if self.parallel_flag && self.parallel_traversal.is_some() {
@ -1161,7 +1182,7 @@ impl LayoutThread {
}
if opts::get().dump_rule_tree {
layout_context.style_context.stylist.rule_tree.dump_stdout();
layout_context.style_context.stylist.rule_tree.dump_stdout(&guards);
}
// GC the rule tree if some heuristics are met.
@ -1330,7 +1351,13 @@ impl LayoutThread {
page_clip_rect: max_rect(),
};
let mut layout_context = self.build_layout_context(&*rw_data, false);
let author_guard = AUTHOR_SHARED_LOCK.read();
let ua_or_user_guard = UA_STYLESHEETS.shared_lock.read();
let guards = StylesheetGuards {
author: &author_guard,
ua_or_user: &ua_or_user_guard,
};
let mut layout_context = self.build_layout_context(guards, &*rw_data, false);
if let Some(mut root_flow) = self.root_flow.clone() {
// Perform an abbreviated style recalc that operates without access to the DOM.
@ -1528,7 +1555,8 @@ fn get_root_flow_background_color(flow: &mut Flow) -> webrender_traits::ColorF {
}
fn get_ua_stylesheets() -> Result<UserAgentStylesheets, &'static str> {
fn parse_ua_stylesheet(filename: &'static str) -> Result<Stylesheet, &'static str> {
fn parse_ua_stylesheet(shared_lock: &SharedRwLock, filename: &'static str)
-> Result<Stylesheet, &'static str> {
let res = try!(read_resource_file(filename).map_err(|_| filename));
Ok(Stylesheet::from_bytes(
&res,
@ -1537,26 +1565,29 @@ fn get_ua_stylesheets() -> Result<UserAgentStylesheets, &'static str> {
None,
Origin::UserAgent,
Default::default(),
shared_lock.clone(),
None,
&StdoutErrorReporter,
ParserContextExtraData::default()))
}
let shared_lock = SharedRwLock::new();
let mut user_or_user_agent_stylesheets = vec!();
// FIXME: presentational-hints.css should be at author origin with zero specificity.
// (Does it make a difference?)
for &filename in &["user-agent.css", "servo.css", "presentational-hints.css"] {
user_or_user_agent_stylesheets.push(try!(parse_ua_stylesheet(filename)));
user_or_user_agent_stylesheets.push(try!(parse_ua_stylesheet(&shared_lock, filename)));
}
for &(ref contents, ref url) in &opts::get().user_stylesheets {
user_or_user_agent_stylesheets.push(Stylesheet::from_bytes(
&contents, url.clone(), None, None, Origin::User, Default::default(),
None, &StdoutErrorReporter, ParserContextExtraData::default()));
shared_lock.clone(), None, &StdoutErrorReporter, ParserContextExtraData::default()));
}
let quirks_mode_stylesheet = try!(parse_ua_stylesheet("quirks-mode.css"));
let quirks_mode_stylesheet = try!(parse_ua_stylesheet(&shared_lock, "quirks-mode.css"));
Ok(UserAgentStylesheets {
shared_lock: shared_lock,
user_or_user_agent_stylesheets: user_or_user_agent_stylesheets,
quirks_mode_stylesheet: quirks_mode_stylesheet,
})

View File

@ -99,6 +99,7 @@ use style::keyframes::Keyframe;
use style::media_queries::MediaList;
use style::properties::PropertyDeclarationBlock;
use style::selector_parser::{PseudoElement, Snapshot};
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
use style::stylesheets::{CssRules, KeyframesRule, MediaRule, NamespaceRule, StyleRule, ImportRule};
use style::stylesheets::SupportsRule;
use style::values::specified::Length;
@ -360,6 +361,7 @@ unsafe_no_jsmanaged_fields!(HttpsState);
unsafe_no_jsmanaged_fields!(Request);
unsafe_no_jsmanaged_fields!(RequestInit);
unsafe_no_jsmanaged_fields!(SharedRt);
unsafe_no_jsmanaged_fields!(StyleSharedRwLock);
unsafe_no_jsmanaged_fields!(TouchpadPressurePhase);
unsafe_no_jsmanaged_fields!(USVString);
unsafe_no_jsmanaged_fields!(ReferrerPolicy);
@ -500,67 +502,67 @@ unsafe impl JSTraceable for Mutex<Option<SharedRt>> {
}
}
unsafe impl JSTraceable for RwLock<FontFaceRule> {
unsafe impl JSTraceable for StyleLocked<FontFaceRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing.
}
}
unsafe impl JSTraceable for RwLock<CssRules> {
unsafe impl JSTraceable for StyleLocked<CssRules> {
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing.
}
}
unsafe impl JSTraceable for RwLock<Keyframe> {
unsafe impl JSTraceable for StyleLocked<Keyframe> {
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing.
}
}
unsafe impl JSTraceable for RwLock<KeyframesRule> {
unsafe impl JSTraceable for StyleLocked<KeyframesRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing.
}
}
unsafe impl JSTraceable for RwLock<ImportRule> {
unsafe impl JSTraceable for StyleLocked<ImportRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing.
}
}
unsafe impl JSTraceable for RwLock<SupportsRule> {
unsafe impl JSTraceable for StyleLocked<SupportsRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing.
}
}
unsafe impl JSTraceable for RwLock<MediaRule> {
unsafe impl JSTraceable for StyleLocked<MediaRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing.
}
}
unsafe impl JSTraceable for RwLock<NamespaceRule> {
unsafe impl JSTraceable for StyleLocked<NamespaceRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing.
}
}
unsafe impl JSTraceable for RwLock<StyleRule> {
unsafe impl JSTraceable for StyleLocked<StyleRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing.
}
}
unsafe impl JSTraceable for RwLock<ViewportRule> {
unsafe impl JSTraceable for StyleLocked<ViewportRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing.
}
}
unsafe impl JSTraceable for RwLock<PropertyDeclarationBlock> {
unsafe impl JSTraceable for StyleLocked<PropertyDeclarationBlock> {
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing.
}
@ -572,7 +574,7 @@ unsafe impl JSTraceable for RwLock<SharedRt> {
}
}
unsafe impl JSTraceable for RwLock<MediaList> {
unsafe impl JSTraceable for StyleLocked<MediaList> {
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing.
}

View File

@ -10,8 +10,8 @@ use dom::cssmediarule::CSSMediaRule;
use dom::cssstylesheet::CSSStyleSheet;
use dom::csssupportsrule::CSSSupportsRule;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc;
use style::shared_lock::{SharedRwLock, Locked};
use style::stylesheets::CssRules as StyleCssRules;
#[dom_struct]
@ -21,12 +21,19 @@ pub struct CSSConditionRule {
impl CSSConditionRule {
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet,
rules: Arc<RwLock<StyleCssRules>>) -> CSSConditionRule {
rules: Arc<Locked<StyleCssRules>>) -> CSSConditionRule {
CSSConditionRule {
cssgroupingrule: CSSGroupingRule::new_inherited(parent_stylesheet, rules),
}
}
pub fn parent_stylesheet(&self) -> &CSSStyleSheet {
self.cssgroupingrule.parent_stylesheet()
}
pub fn shared_lock(&self) -> &SharedRwLock {
self.cssgroupingrule.shared_lock()
}
}
impl CSSConditionRuleMethods for CSSConditionRule {

View File

@ -10,20 +10,19 @@ use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc;
use style::font_face::FontFaceRule;
use style_traits::ToCss;
use style::shared_lock::{Locked, ToCssWithGuard};
#[dom_struct]
pub struct CSSFontFaceRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
fontfacerule: Arc<RwLock<FontFaceRule>>,
fontfacerule: Arc<Locked<FontFaceRule>>,
}
impl CSSFontFaceRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc<RwLock<FontFaceRule>>)
fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc<Locked<FontFaceRule>>)
-> CSSFontFaceRule {
CSSFontFaceRule {
cssrule: CSSRule::new_inherited(parent_stylesheet),
@ -33,7 +32,7 @@ impl CSSFontFaceRule {
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
fontfacerule: Arc<RwLock<FontFaceRule>>) -> Root<CSSFontFaceRule> {
fontfacerule: Arc<Locked<FontFaceRule>>) -> Root<CSSFontFaceRule> {
reflect_dom_object(box CSSFontFaceRule::new_inherited(parent_stylesheet, fontfacerule),
window,
CSSFontFaceRuleBinding::Wrap)
@ -47,6 +46,7 @@ impl SpecificCSSRule for CSSFontFaceRule {
}
fn get_css(&self) -> DOMString {
self.fontfacerule.read().to_css_string().into()
let guard = self.cssrule.shared_lock().read();
self.fontfacerule.read_with(&guard).to_css_string(&guard).into()
}
}

View File

@ -12,21 +12,21 @@ use dom::cssrule::CSSRule;
use dom::cssrulelist::{CSSRuleList, RulesSource};
use dom::cssstylesheet::CSSStyleSheet;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc;
use style::shared_lock::{SharedRwLock, Locked};
use style::stylesheets::CssRules as StyleCssRules;
#[dom_struct]
pub struct CSSGroupingRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
rules: Arc<RwLock<StyleCssRules>>,
rules: Arc<Locked<StyleCssRules>>,
rulelist: MutNullableJS<CSSRuleList>,
}
impl CSSGroupingRule {
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet,
rules: Arc<RwLock<StyleCssRules>>) -> CSSGroupingRule {
rules: Arc<Locked<StyleCssRules>>) -> CSSGroupingRule {
CSSGroupingRule {
cssrule: CSSRule::new_inherited(parent_stylesheet),
rules: rules,
@ -40,6 +40,14 @@ impl CSSGroupingRule {
parent_stylesheet,
RulesSource::Rules(self.rules.clone())))
}
pub fn parent_stylesheet(&self) -> &CSSStyleSheet {
self.cssrule.parent_stylesheet()
}
pub fn shared_lock(&self) -> &SharedRwLock {
self.cssrule.shared_lock()
}
}
impl CSSGroupingRuleMethods for CSSGroupingRule {

View File

@ -10,21 +10,20 @@ use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::stylesheets::ImportRule;
use style_traits::ToCss;
#[dom_struct]
pub struct CSSImportRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
import_rule: Arc<RwLock<ImportRule>>,
import_rule: Arc<Locked<ImportRule>>,
}
impl CSSImportRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet,
import_rule: Arc<RwLock<ImportRule>>)
import_rule: Arc<Locked<ImportRule>>)
-> Self {
CSSImportRule {
cssrule: CSSRule::new_inherited(parent_stylesheet),
@ -35,7 +34,7 @@ impl CSSImportRule {
#[allow(unrooted_must_root)]
pub fn new(window: &Window,
parent_stylesheet: &CSSStyleSheet,
import_rule: Arc<RwLock<ImportRule>>) -> Root<Self> {
import_rule: Arc<Locked<ImportRule>>) -> Root<Self> {
reflect_dom_object(box Self::new_inherited(parent_stylesheet, import_rule),
window,
CSSImportRuleBinding::Wrap)
@ -49,6 +48,7 @@ impl SpecificCSSRule for CSSImportRule {
}
fn get_css(&self) -> DOMString {
self.import_rule.read().to_css_string().into()
let guard = self.cssrule.shared_lock().read();
self.import_rule.read_with(&guard).to_css_string(&guard).into()
}
}

View File

@ -12,21 +12,20 @@ use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSSt
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc;
use style::keyframes::Keyframe;
use style_traits::ToCss;
use style::shared_lock::{Locked, ToCssWithGuard};
#[dom_struct]
pub struct CSSKeyframeRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
keyframerule: Arc<RwLock<Keyframe>>,
keyframerule: Arc<Locked<Keyframe>>,
style_decl: MutNullableJS<CSSStyleDeclaration>,
}
impl CSSKeyframeRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc<RwLock<Keyframe>>)
fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc<Locked<Keyframe>>)
-> CSSKeyframeRule {
CSSKeyframeRule {
cssrule: CSSRule::new_inherited(parent_stylesheet),
@ -37,7 +36,7 @@ impl CSSKeyframeRule {
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
keyframerule: Arc<RwLock<Keyframe>>) -> Root<CSSKeyframeRule> {
keyframerule: Arc<Locked<Keyframe>>) -> Root<CSSKeyframeRule> {
reflect_dom_object(box CSSKeyframeRule::new_inherited(parent_stylesheet, keyframerule),
window,
CSSKeyframeRuleBinding::Wrap)
@ -48,11 +47,16 @@ impl CSSKeyframeRuleMethods for CSSKeyframeRule {
// https://drafts.csswg.org/css-animations/#dom-csskeyframerule-style
fn Style(&self) -> Root<CSSStyleDeclaration> {
self.style_decl.or_init(|| {
CSSStyleDeclaration::new(self.global().as_window(),
CSSStyleOwner::CSSRule(JS::from_ref(self.upcast()),
self.keyframerule.read().block.clone()),
None,
CSSModificationAccess::ReadWrite)
let guard = self.cssrule.shared_lock().read();
CSSStyleDeclaration::new(
self.global().as_window(),
CSSStyleOwner::CSSRule(
JS::from_ref(self.upcast()),
self.keyframerule.read_with(&guard).block.clone(),
),
None,
CSSModificationAccess::ReadWrite,
)
})
}
}
@ -64,6 +68,7 @@ impl SpecificCSSRule for CSSKeyframeRule {
}
fn get_css(&self) -> DOMString {
self.keyframerule.read().to_css_string().into()
let guard = self.cssrule.shared_lock().read();
self.keyframerule.read_with(&guard).to_css_string(&guard).into()
}
}

View File

@ -16,24 +16,23 @@ use dom::cssrulelist::{CSSRuleList, RulesSource};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use servo_atoms::Atom;
use std::sync::Arc;
use style::keyframes::{Keyframe, KeyframeSelector};
use style::parser::ParserContextExtraData;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::stylesheets::KeyframesRule;
use style_traits::ToCss;
#[dom_struct]
pub struct CSSKeyframesRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
keyframesrule: Arc<RwLock<KeyframesRule>>,
keyframesrule: Arc<Locked<KeyframesRule>>,
rulelist: MutNullableJS<CSSRuleList>,
}
impl CSSKeyframesRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc<RwLock<KeyframesRule>>)
fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc<Locked<KeyframesRule>>)
-> CSSKeyframesRule {
CSSKeyframesRule {
cssrule: CSSRule::new_inherited(parent_stylesheet),
@ -44,7 +43,7 @@ impl CSSKeyframesRule {
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
keyframesrule: Arc<RwLock<KeyframesRule>>) -> Root<CSSKeyframesRule> {
keyframesrule: Arc<Locked<KeyframesRule>>) -> Root<CSSKeyframesRule> {
reflect_dom_object(box CSSKeyframesRule::new_inherited(parent_stylesheet, keyframesrule),
window,
CSSKeyframesRuleBinding::Wrap)
@ -63,11 +62,12 @@ impl CSSKeyframesRule {
fn find_rule(&self, selector: &str) -> Option<usize> {
let mut input = Parser::new(selector);
if let Ok(sel) = KeyframeSelector::parse(&mut input) {
let guard = self.cssrule.shared_lock().read();
// This finds the *last* element matching a selector
// because that's the rule that applies. Thus, rposition
self.keyframesrule.read()
self.keyframesrule.read_with(&guard)
.keyframes.iter().rposition(|frame| {
frame.read().selector == sel
frame.read_with(&guard).selector == sel
})
} else {
None
@ -86,7 +86,8 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule {
let rule = Keyframe::parse(&rule, self.cssrule.parent_stylesheet().style_stylesheet(),
ParserContextExtraData::default());
if let Ok(rule) = rule {
self.keyframesrule.write().keyframes.push(rule);
let mut guard = self.cssrule.shared_lock().write();
self.keyframesrule.write_with(&mut guard).keyframes.push(rule);
self.rulelist().append_lazy_dom_rule();
}
}
@ -107,7 +108,8 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule {
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name
fn Name(&self) -> DOMString {
DOMString::from(&*self.keyframesrule.read().name)
let guard = self.cssrule.shared_lock().read();
DOMString::from(&*self.keyframesrule.read_with(&guard).name)
}
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name
@ -122,7 +124,8 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule {
"none" => return Err(Error::Syntax),
_ => ()
}
self.keyframesrule.write().name = Atom::from(value);
let mut guard = self.cssrule.shared_lock().write();
self.keyframesrule.write_with(&mut guard).name = Atom::from(value);
Ok(())
}
}
@ -134,7 +137,8 @@ impl SpecificCSSRule for CSSKeyframesRule {
}
fn get_css(&self) -> DOMString {
self.keyframesrule.read().to_css_string().into()
let guard = self.cssrule.shared_lock().read();
self.keyframesrule.read_with(&guard).to_css_string(&guard).into()
}
fn deparent_children(&self) {

View File

@ -14,26 +14,27 @@ use dom::cssstylesheet::CSSStyleSheet;
use dom::medialist::MediaList;
use dom::window::Window;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc;
use style::media_queries::parse_media_query_list;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::stylesheets::MediaRule;
use style_traits::ToCss;
#[dom_struct]
pub struct CSSMediaRule {
cssrule: CSSConditionRule,
cssconditionrule: CSSConditionRule,
#[ignore_heap_size_of = "Arc"]
mediarule: Arc<RwLock<MediaRule>>,
mediarule: Arc<Locked<MediaRule>>,
medialist: MutNullableJS<MediaList>,
}
impl CSSMediaRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc<RwLock<MediaRule>>)
fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc<Locked<MediaRule>>)
-> CSSMediaRule {
let list = mediarule.read().rules.clone();
let guard = parent_stylesheet.shared_lock().read();
let list = mediarule.read_with(&guard).rules.clone();
CSSMediaRule {
cssrule: CSSConditionRule::new_inherited(parent_stylesheet, list),
cssconditionrule: CSSConditionRule::new_inherited(parent_stylesheet, list),
mediarule: mediarule,
medialist: MutNullableJS::new(None),
}
@ -41,21 +42,26 @@ impl CSSMediaRule {
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
mediarule: Arc<RwLock<MediaRule>>) -> Root<CSSMediaRule> {
mediarule: Arc<Locked<MediaRule>>) -> Root<CSSMediaRule> {
reflect_dom_object(box CSSMediaRule::new_inherited(parent_stylesheet, mediarule),
window,
CSSMediaRuleBinding::Wrap)
}
fn medialist(&self) -> Root<MediaList> {
self.medialist.or_init(|| MediaList::new(self.global().as_window(),
self.mediarule.read().media_queries.clone()))
self.medialist.or_init(|| {
let guard = self.cssconditionrule.shared_lock().read();
MediaList::new(self.global().as_window(),
self.cssconditionrule.parent_stylesheet(),
self.mediarule.read_with(&guard).media_queries.clone())
})
}
/// https://drafts.csswg.org/css-conditional-3/#the-cssmediarule-interface
pub fn get_condition_text(&self) -> DOMString {
let rule = self.mediarule.read();
let list = rule.media_queries.read();
let guard = self.cssconditionrule.shared_lock().read();
let rule = self.mediarule.read_with(&guard);
let list = rule.media_queries.read_with(&guard);
list.to_css_string().into()
}
@ -63,9 +69,16 @@ impl CSSMediaRule {
pub fn set_condition_text(&self, text: DOMString) {
let mut input = Parser::new(&text);
let new_medialist = parse_media_query_list(&mut input);
let rule = self.mediarule.read();
let mut list = rule.media_queries.write();
*list = new_medialist;
let mut guard = self.cssconditionrule.shared_lock().write();
// Clone an Arc because we cant borrow `guard` twice at the same time.
// FIXME(SimonSapin): allow access to multiple objects with one write guard?
// Would need a set of usize pointer addresses or something,
// the same object is not accessed more than once.
let mqs = Arc::clone(&self.mediarule.write_with(&mut guard).media_queries);
*mqs.write_with(&mut guard) = new_medialist;
}
}
@ -76,7 +89,8 @@ impl SpecificCSSRule for CSSMediaRule {
}
fn get_css(&self) -> DOMString {
self.mediarule.read().to_css_string().into()
let guard = self.cssconditionrule.shared_lock().read();
self.mediarule.read_with(&guard).to_css_string(&guard).into()
}
}

View File

@ -11,20 +11,19 @@ use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::stylesheets::NamespaceRule;
use style_traits::ToCss;
#[dom_struct]
pub struct CSSNamespaceRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
namespacerule: Arc<RwLock<NamespaceRule>>,
namespacerule: Arc<Locked<NamespaceRule>>,
}
impl CSSNamespaceRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc<RwLock<NamespaceRule>>)
fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc<Locked<NamespaceRule>>)
-> CSSNamespaceRule {
CSSNamespaceRule {
cssrule: CSSRule::new_inherited(parent_stylesheet),
@ -34,7 +33,7 @@ impl CSSNamespaceRule {
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
namespacerule: Arc<RwLock<NamespaceRule>>) -> Root<CSSNamespaceRule> {
namespacerule: Arc<Locked<NamespaceRule>>) -> Root<CSSNamespaceRule> {
reflect_dom_object(box CSSNamespaceRule::new_inherited(parent_stylesheet, namespacerule),
window,
CSSNamespaceRuleBinding::Wrap)
@ -44,14 +43,16 @@ impl CSSNamespaceRule {
impl CSSNamespaceRuleMethods for CSSNamespaceRule {
// https://drafts.csswg.org/cssom/#dom-cssnamespacerule-prefix
fn Prefix(&self) -> DOMString {
self.namespacerule.read().prefix
let guard = self.cssrule.shared_lock().read();
self.namespacerule.read_with(&guard).prefix
.as_ref().map(|s| s.to_string().into())
.unwrap_or(DOMString::new())
}
// https://drafts.csswg.org/cssom/#dom-cssnamespacerule-namespaceuri
fn NamespaceURI(&self) -> DOMString {
(*self.namespacerule.read().url).into()
let guard = self.cssrule.shared_lock().read();
(*self.namespacerule.read_with(&guard).url).into()
}
}
@ -62,6 +63,7 @@ impl SpecificCSSRule for CSSNamespaceRule {
}
fn get_css(&self) -> DOMString {
self.namespacerule.read().to_css_string().into()
let guard = self.cssrule.shared_lock().read();
self.namespacerule.read_with(&guard).to_css_string(&guard).into()
}
}

View File

@ -20,6 +20,7 @@ use dom::cssviewportrule::CSSViewportRule;
use dom::window::Window;
use dom_struct::dom_struct;
use std::cell::Cell;
use style::shared_lock::SharedRwLock;
use style::stylesheets::CssRule as StyleCssRule;
@ -103,6 +104,10 @@ impl CSSRule {
pub fn parent_stylesheet(&self) -> &CSSStyleSheet {
&self.parent_stylesheet
}
pub fn shared_lock(&self) -> &SharedRwLock {
&self.parent_stylesheet.style_stylesheet().shared_lock
}
}
impl CSSRuleMethods for CSSRule {

View File

@ -13,8 +13,8 @@ use dom::cssrule::CSSRule;
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc;
use style::shared_lock::Locked;
use style::stylesheets::{CssRules, KeyframesRule, RulesMutateError};
#[allow(unsafe_code)]
@ -43,19 +43,20 @@ pub struct CSSRuleList {
}
pub enum RulesSource {
Rules(Arc<RwLock<CssRules>>),
Keyframes(Arc<RwLock<KeyframesRule>>),
Rules(Arc<Locked<CssRules>>),
Keyframes(Arc<Locked<KeyframesRule>>),
}
impl CSSRuleList {
#[allow(unrooted_must_root)]
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, rules: RulesSource) -> CSSRuleList {
let guard = parent_stylesheet.shared_lock().read();
let dom_rules = match rules {
RulesSource::Rules(ref rules) => {
rules.read().0.iter().map(|_| MutNullableJS::new(None)).collect()
rules.read_with(&guard).0.iter().map(|_| MutNullableJS::new(None)).collect()
}
RulesSource::Keyframes(ref rules) => {
rules.read().keyframes.iter().map(|_| MutNullableJS::new(None)).collect()
rules.read_with(&guard).keyframes.iter().map(|_| MutNullableJS::new(None)).collect()
}
};
@ -89,7 +90,12 @@ impl CSSRuleList {
let index = idx as usize;
let parent_stylesheet = self.parent_stylesheet.style_stylesheet();
let new_rule = css_rules.write().insert_rule(rule, parent_stylesheet, index, nested)?;
let new_rule = {
let mut guard = parent_stylesheet.shared_lock.write();
css_rules.write_with(&mut guard).insert_rule(rule, parent_stylesheet, index, nested)?
// Drop `guard` here,
// CSSRule::new_specific re-acquires the lock for @support and @media.
};
let parent_stylesheet = &*self.parent_stylesheet;
let dom_rule = CSSRule::new_specific(&window, parent_stylesheet, new_rule);
@ -100,10 +106,11 @@ impl CSSRuleList {
// In case of a keyframe rule, index must be valid.
pub fn remove_rule(&self, index: u32) -> ErrorResult {
let index = index as usize;
let mut guard = self.parent_stylesheet.shared_lock().write();
match self.rules {
RulesSource::Rules(ref css_rules) => {
css_rules.write().remove_rule(index)?;
css_rules.write_with(&mut guard).remove_rule(index)?;
let mut dom_rules = self.dom_rules.borrow_mut();
dom_rules[index].get().map(|r| r.detach());
dom_rules.remove(index);
@ -114,7 +121,7 @@ impl CSSRuleList {
let mut dom_rules = self.dom_rules.borrow_mut();
dom_rules[index].get().map(|r| r.detach());
dom_rules.remove(index);
kf.write().keyframes.remove(index);
kf.write_with(&mut guard).keyframes.remove(index);
Ok(())
}
}
@ -131,16 +138,17 @@ impl CSSRuleList {
self.dom_rules.borrow().get(idx as usize).map(|rule| {
rule.or_init(|| {
let parent_stylesheet = &self.parent_stylesheet;
let guard = parent_stylesheet.shared_lock().read();
match self.rules {
RulesSource::Rules(ref rules) => {
CSSRule::new_specific(self.global().as_window(),
parent_stylesheet,
rules.read().0[idx as usize].clone())
rules.read_with(&guard).0[idx as usize].clone())
}
RulesSource::Keyframes(ref rules) => {
Root::upcast(CSSKeyframeRule::new(self.global().as_window(),
parent_stylesheet,
rules.read()
rules.read_with(&guard)
.keyframes[idx as usize]
.clone()))
}

View File

@ -11,10 +11,9 @@ use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::cssrule::CSSRule;
use dom::element::Element;
use dom::node::{Node, window_from_node};
use dom::node::{Node, window_from_node, document_from_node};
use dom::window::Window;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use servo_url::ServoUrl;
use std::ascii::AsciiExt;
use std::sync::Arc;
@ -23,6 +22,7 @@ use style::parser::ParserContextExtraData;
use style::properties::{Importance, PropertyDeclarationBlock, PropertyId, LonghandId, ShorthandId};
use style::properties::{parse_one_declaration, parse_style_attribute};
use style::selector_parser::PseudoElement;
use style::shared_lock::Locked;
use style_traits::ToCss;
// http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
@ -40,7 +40,7 @@ pub enum CSSStyleOwner {
Element(JS<Element>),
CSSRule(JS<CSSRule>,
#[ignore_heap_size_of = "Arc"]
Arc<RwLock<PropertyDeclarationBlock>>),
Arc<Locked<PropertyDeclarationBlock>>),
}
impl CSSStyleOwner {
@ -55,10 +55,13 @@ impl CSSStyleOwner {
let mut changed = true;
match *self {
CSSStyleOwner::Element(ref el) => {
let document = document_from_node(&**el);
let shared_lock = document.style_shared_lock();
let mut attr = el.style_attribute().borrow_mut().take();
let result = if attr.is_some() {
let lock = attr.as_ref().unwrap();
let mut pdb = lock.write();
let mut guard = shared_lock.write();
let mut pdb = lock.write_with(&mut guard);
let result = f(&mut pdb, &mut changed);
result
} else {
@ -69,7 +72,7 @@ impl CSSStyleOwner {
// exact conditions under it changes.
changed = !pdb.declarations().is_empty();
if changed {
attr = Some(Arc::new(RwLock::new(pdb)));
attr = Some(Arc::new(shared_lock.wrap(pdb)));
}
result
@ -83,7 +86,8 @@ impl CSSStyleOwner {
//
// [1]: https://github.com/whatwg/html/issues/2306
if let Some(pdb) = attr {
let serialization = pdb.read().to_css_string();
let guard = shared_lock.read();
let serialization = pdb.read_with(&guard).to_css_string();
el.set_attribute(&local_name!("style"),
AttrValue::Declaration(serialization,
pdb));
@ -96,7 +100,10 @@ impl CSSStyleOwner {
result
}
CSSStyleOwner::CSSRule(ref rule, ref pdb) => {
let result = f(&mut *pdb.write(), &mut changed);
let result = {
let mut guard = rule.shared_lock().write();
f(&mut *pdb.write_with(&mut guard), &mut changed)
};
if changed {
rule.global().as_window().Document().invalidate_stylesheets();
}
@ -111,15 +118,20 @@ impl CSSStyleOwner {
match *self {
CSSStyleOwner::Element(ref el) => {
match *el.style_attribute().borrow() {
Some(ref pdb) => f(&pdb.read()),
Some(ref pdb) => {
let document = document_from_node(&**el);
let guard = document.style_shared_lock().read();
f(pdb.read_with(&guard))
}
None => {
let pdb = PropertyDeclarationBlock::new();
f(&pdb)
}
}
}
CSSStyleOwner::CSSRule(_, ref pdb) => {
f(&pdb.read())
CSSStyleOwner::CSSRule(ref rule, ref pdb) => {
let guard = rule.shared_lock().read();
f(pdb.read_with(&guard))
}
}
}

View File

@ -12,21 +12,20 @@ use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSSt
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::stylesheets::StyleRule;
use style_traits::ToCss;
#[dom_struct]
pub struct CSSStyleRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
stylerule: Arc<RwLock<StyleRule>>,
stylerule: Arc<Locked<StyleRule>>,
style_decl: MutNullableJS<CSSStyleDeclaration>,
}
impl CSSStyleRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc<RwLock<StyleRule>>)
fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc<Locked<StyleRule>>)
-> CSSStyleRule {
CSSStyleRule {
cssrule: CSSRule::new_inherited(parent_stylesheet),
@ -37,7 +36,7 @@ impl CSSStyleRule {
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
stylerule: Arc<RwLock<StyleRule>>) -> Root<CSSStyleRule> {
stylerule: Arc<Locked<StyleRule>>) -> Root<CSSStyleRule> {
reflect_dom_object(box CSSStyleRule::new_inherited(parent_stylesheet, stylerule),
window,
CSSStyleRuleBinding::Wrap)
@ -51,7 +50,8 @@ impl SpecificCSSRule for CSSStyleRule {
}
fn get_css(&self) -> DOMString {
self.stylerule.read().to_css_string().into()
let guard = self.cssrule.shared_lock().read();
self.stylerule.read_with(&guard).to_css_string(&guard).into()
}
}
@ -59,11 +59,16 @@ impl CSSStyleRuleMethods for CSSStyleRule {
// https://drafts.csswg.org/cssom/#dom-cssstylerule-style
fn Style(&self) -> Root<CSSStyleDeclaration> {
self.style_decl.or_init(|| {
CSSStyleDeclaration::new(self.global().as_window(),
CSSStyleOwner::CSSRule(JS::from_ref(self.upcast()),
self.stylerule.read().block.clone()),
None,
CSSModificationAccess::ReadWrite)
let guard = self.cssrule.shared_lock().read();
CSSStyleDeclaration::new(
self.global().as_window(),
CSSStyleOwner::CSSRule(
JS::from_ref(self.upcast()),
self.stylerule.read_with(&guard).block.clone()
),
None,
CSSModificationAccess::ReadWrite
)
})
}
}

View File

@ -16,6 +16,7 @@ use dom::window::Window;
use dom_struct::dom_struct;
use std::cell::Cell;
use std::sync::Arc;
use style::shared_lock::SharedRwLock;
use style::stylesheets::Stylesheet as StyleStyleSheet;
#[dom_struct]
@ -72,6 +73,10 @@ impl CSSStyleSheet {
}
}
pub fn shared_lock(&self) -> &SharedRwLock {
&self.style_stylesheet.shared_lock
}
pub fn style_stylesheet(&self) -> &StyleStyleSheet {
&self.style_stylesheet
}

View File

@ -13,33 +13,34 @@ use dom::cssrule::SpecificCSSRule;
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc;
use style::parser::ParserContext;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::stylesheets::SupportsRule;
use style::supports::SupportsCondition;
use style_traits::ToCss;
#[dom_struct]
pub struct CSSSupportsRule {
cssrule: CSSConditionRule,
cssconditionrule: CSSConditionRule,
#[ignore_heap_size_of = "Arc"]
supportsrule: Arc<RwLock<SupportsRule>>,
supportsrule: Arc<Locked<SupportsRule>>,
}
impl CSSSupportsRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc<RwLock<SupportsRule>>)
fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc<Locked<SupportsRule>>)
-> CSSSupportsRule {
let list = supportsrule.read().rules.clone();
let guard = parent_stylesheet.shared_lock().read();
let list = supportsrule.read_with(&guard).rules.clone();
CSSSupportsRule {
cssrule: CSSConditionRule::new_inherited(parent_stylesheet, list),
cssconditionrule: CSSConditionRule::new_inherited(parent_stylesheet, list),
supportsrule: supportsrule,
}
}
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
supportsrule: Arc<RwLock<SupportsRule>>) -> Root<CSSSupportsRule> {
supportsrule: Arc<Locked<SupportsRule>>) -> Root<CSSSupportsRule> {
reflect_dom_object(box CSSSupportsRule::new_inherited(parent_stylesheet, supportsrule),
window,
CSSSupportsRuleBinding::Wrap)
@ -47,7 +48,8 @@ impl CSSSupportsRule {
/// https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface
pub fn get_condition_text(&self) -> DOMString {
let rule = self.supportsrule.read();
let guard = self.cssconditionrule.shared_lock().read();
let rule = self.supportsrule.read_with(&guard);
rule.condition.to_css_string().into()
}
@ -61,7 +63,8 @@ impl CSSSupportsRule {
let url = win.Document().url();
let context = ParserContext::new_for_cssom(&url, win.css_error_reporter());
let enabled = cond.eval(&context);
let mut rule = self.supportsrule.write();
let mut guard = self.cssconditionrule.shared_lock().write();
let rule = self.supportsrule.write_with(&mut guard);
rule.condition = cond;
rule.enabled = enabled;
}
@ -75,6 +78,7 @@ impl SpecificCSSRule for CSSSupportsRule {
}
fn get_css(&self) -> DOMString {
self.supportsrule.read().to_css_string().into()
let guard = self.cssconditionrule.shared_lock().read();
self.supportsrule.read_with(&guard).to_css_string(&guard).into()
}
}

View File

@ -10,20 +10,19 @@ use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::viewport::ViewportRule;
use style_traits::ToCss;
#[dom_struct]
pub struct CSSViewportRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
viewportrule: Arc<RwLock<ViewportRule>>,
viewportrule: Arc<Locked<ViewportRule>>,
}
impl CSSViewportRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc<RwLock<ViewportRule>>) -> CSSViewportRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc<Locked<ViewportRule>>) -> CSSViewportRule {
CSSViewportRule {
cssrule: CSSRule::new_inherited(parent_stylesheet),
viewportrule: viewportrule,
@ -32,7 +31,7 @@ impl CSSViewportRule {
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
viewportrule: Arc<RwLock<ViewportRule>>) -> Root<CSSViewportRule> {
viewportrule: Arc<Locked<ViewportRule>>) -> Root<CSSViewportRule> {
reflect_dom_object(box CSSViewportRule::new_inherited(parent_stylesheet, viewportrule),
window,
CSSViewportRuleBinding::Wrap)
@ -46,6 +45,7 @@ impl SpecificCSSRule for CSSViewportRule {
}
fn get_css(&self) -> DOMString {
self.viewportrule.read().to_css_string().into()
let guard = self.cssrule.shared_lock().read();
self.viewportrule.read_with(&guard).to_css_string(&guard).into()
}
}

View File

@ -134,6 +134,8 @@ use style::attr::AttrValue;
use style::context::{QuirksMode, ReflowGoal};
use style::restyle_hints::{RestyleHint, RESTYLE_STYLE_ATTRIBUTE};
use style::selector_parser::{RestyleDamage, Snapshot};
use style::servo::AUTHOR_SHARED_LOCK;
use style::shared_lock::SharedRwLock as StyleSharedRwLock;
use style::str::{HTML_SPACE_CHARACTERS, split_html_space_chars, str_join};
use style::stylesheets::Stylesheet;
use task_source::TaskSource;
@ -220,6 +222,9 @@ pub struct Document {
scripts: MutNullableJS<HTMLCollection>,
anchors: MutNullableJS<HTMLCollection>,
applets: MutNullableJS<HTMLCollection>,
/// Lock use for style attributes and author-origin stylesheet objects in this document.
/// Can be acquired once for accessing many objects.
style_shared_lock: StyleSharedRwLock,
/// List of stylesheets associated with nodes in this document. |None| if the list needs to be refreshed.
stylesheets: DOMRefCell<Option<Vec<StylesheetInDocument>>>,
/// Whether the list of stylesheets has changed since the last reflow was triggered.
@ -1964,6 +1969,7 @@ pub trait LayoutDocumentHelpers {
unsafe fn needs_paint_from_layout(&self);
unsafe fn will_paint(&self);
unsafe fn quirks_mode(&self) -> QuirksMode;
unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock;
}
#[allow(unsafe_code)]
@ -2000,6 +2006,11 @@ impl LayoutDocumentHelpers for LayoutJS<Document> {
unsafe fn quirks_mode(&self) -> QuirksMode {
(*self.unsafe_get()).quirks_mode()
}
#[inline]
unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock {
(*self.unsafe_get()).style_shared_lock()
}
}
// https://html.spec.whatwg.org/multipage/#is-a-registrable-domain-suffix-of-or-is-equal-to
@ -2121,6 +2132,7 @@ impl Document {
scripts: Default::default(),
anchors: Default::default(),
applets: Default::default(),
style_shared_lock: AUTHOR_SHARED_LOCK.clone(),
stylesheets: DOMRefCell::new(None),
stylesheets_changed_since_reflow: Cell::new(false),
stylesheet_list: MutNullableJS::new(None),
@ -2250,6 +2262,11 @@ impl Document {
};
}
/// Return a reference to the per-document shared lock used in stylesheets.
pub fn style_shared_lock(&self) -> &StyleSharedRwLock {
&self.style_shared_lock
}
/// Returns the list of stylesheets associated with nodes in the document.
pub fn stylesheets(&self) -> Vec<Arc<Stylesheet>> {
self.ensure_stylesheets();

View File

@ -82,7 +82,6 @@ use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
use html5ever_atoms::{Prefix, LocalName, Namespace, QualName};
use js::jsapi::{HandleValue, JSAutoCompartment};
use net_traits::request::CorsSettings;
use parking_lot::RwLock;
use ref_filter_map::ref_filter_map;
use script_layout_interface::message::ReflowQueryType;
use script_thread::Runnable;
@ -108,6 +107,7 @@ use style::properties::longhands::{self, background_image, border_spacing, font_
use style::restyle_hints::RESTYLE_SELF;
use style::rule_tree::CascadeLevel;
use style::selector_parser::{NonTSPseudoClass, RestyleDamage, SelectorImpl, SelectorParser};
use style::shared_lock::{SharedRwLock, Locked};
use style::sink::Push;
use style::stylist::ApplicableDeclarationBlock;
use style::thread_state;
@ -129,7 +129,7 @@ pub struct Element {
attrs: DOMRefCell<Vec<JS<Attr>>>,
id_attribute: DOMRefCell<Option<Atom>>,
#[ignore_heap_size_of = "Arc"]
style_attribute: DOMRefCell<Option<Arc<RwLock<PropertyDeclarationBlock>>>>,
style_attribute: DOMRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>>,
attr_list: MutNullableJS<NamedNodeMap>,
class_list: MutNullableJS<DOMTokenList>,
state: Cell<ElementState>,
@ -352,7 +352,7 @@ pub trait LayoutElementHelpers {
#[allow(unsafe_code)]
unsafe fn html_element_in_html_document_for_layout(&self) -> bool;
fn id_attribute(&self) -> *const Option<Atom>;
fn style_attribute(&self) -> *const Option<Arc<RwLock<PropertyDeclarationBlock>>>;
fn style_attribute(&self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>>;
fn local_name(&self) -> &LocalName;
fn namespace(&self) -> &Namespace;
fn get_lang_for_layout(&self) -> String;
@ -384,14 +384,18 @@ impl LayoutElementHelpers for LayoutJS<Element> {
where V: Push<ApplicableDeclarationBlock>
{
#[inline]
fn from_declaration(declaration: PropertyDeclaration) -> ApplicableDeclarationBlock {
fn from_declaration(shared_lock: &SharedRwLock, declaration: PropertyDeclaration)
-> ApplicableDeclarationBlock {
ApplicableDeclarationBlock::from_declarations(
Arc::new(RwLock::new(PropertyDeclarationBlock::with_one(
Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
declaration, Importance::Normal
))),
CascadeLevel::PresHints)
}
let document = self.upcast::<Node>().owner_doc_for_layout();
let shared_lock = document.style_shared_lock();
let bgcolor = if let Some(this) = self.downcast::<HTMLBodyElement>() {
this.get_background_color()
} else if let Some(this) = self.downcast::<HTMLTableElement>() {
@ -408,6 +412,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(color) = bgcolor {
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BackgroundColor(
CSSColor { parsed: Color::RGBA(color), authored: None })));
}
@ -420,6 +425,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(url) = background {
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BackgroundImage(
background_image::SpecifiedValue(vec![
background_image::single_value::SpecifiedValue(Some(
@ -442,6 +448,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(color) = color {
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Color(
longhands::color::SpecifiedValue(CSSColor {
parsed: Color::RGBA(color),
@ -459,6 +466,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(font_family) = font_family {
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::FontFamily(
font_family::computed_value::T(vec![
font_family::computed_value::FontFamily::from_atom(
@ -469,6 +477,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(font_size) = font_size {
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::FontSize(font_size::SpecifiedValue(font_size.into()))))
}
@ -481,6 +490,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(cellspacing) = cellspacing {
let width_value = specified::Length::from_px(cellspacing as f32);
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderSpacing(
Box::new(border_spacing::SpecifiedValue {
horizontal: width_value.clone(),
@ -514,6 +524,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(size) = size {
let value = specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(size));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Width(
specified::LengthOrPercentageOrAuto::Length(value))));
}
@ -539,12 +550,14 @@ impl LayoutElementHelpers for LayoutJS<Element> {
let width_value =
specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Width(width_value)));
}
LengthOrPercentageOrAuto::Length(length) => {
let width_value = specified::LengthOrPercentageOrAuto::Length(
specified::NoCalcLength::Absolute(length));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Width(width_value)));
}
}
@ -564,12 +577,14 @@ impl LayoutElementHelpers for LayoutJS<Element> {
let height_value =
specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Height(height_value)));
}
LengthOrPercentageOrAuto::Length(length) => {
let height_value = specified::LengthOrPercentageOrAuto::Length(
specified::NoCalcLength::Absolute(length));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Height(height_value)));
}
}
@ -592,6 +607,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
// https://html.spec.whatwg.org/multipage/#textarea-effective-width
let value = specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(cols));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Width(specified::LengthOrPercentageOrAuto::Length(value))));
}
@ -610,6 +626,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
// https://html.spec.whatwg.org/multipage/#textarea-effective-height
let value = specified::NoCalcLength::FontRelative(specified::FontRelativeLength::Em(rows as CSSFloat));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Height(specified::LengthOrPercentageOrAuto::Length(value))));
}
@ -623,12 +640,16 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(border) = border {
let width_value = specified::BorderWidth::from_length(specified::Length::from_px(border as f32));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderTopWidth(Box::new(width_value.clone()))));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderLeftWidth(Box::new(width_value.clone()))));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderBottomWidth(Box::new(width_value.clone()))));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderRightWidth(Box::new(width_value))));
}
}
@ -672,7 +693,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
}
#[allow(unsafe_code)]
fn style_attribute(&self) -> *const Option<Arc<RwLock<PropertyDeclarationBlock>>> {
fn style_attribute(&self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>> {
unsafe {
(*self.unsafe_get()).style_attribute.borrow_for_layout()
}
@ -835,7 +856,7 @@ impl Element {
ns!()
}
pub fn style_attribute(&self) -> &DOMRefCell<Option<Arc<RwLock<PropertyDeclarationBlock>>>> {
pub fn style_attribute(&self) -> &DOMRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>> {
&self.style_attribute
}
@ -2170,7 +2191,7 @@ impl VirtualMethods for Element {
block
} else {
let win = window_from_node(self);
Arc::new(RwLock::new(parse_style_attribute(
Arc::new(doc.style_shared_lock().wrap(parse_style_attribute(
&attr.value(),
&doc.base_url(),
win.css_error_reporter(),

View File

@ -291,9 +291,8 @@ impl HTMLLinkElement {
// doesn't match.
let loader = StylesheetLoader::for_element(self.upcast());
loader.load(StylesheetContextSource::LinkElement {
url: url,
media: Some(media),
}, cors_setting, integrity_metadata.to_owned());
}, url, cors_setting, integrity_metadata.to_owned());
}
fn handle_favicon_url(&self, rel: &str, href: &str, sizes: &Option<String>) {

View File

@ -19,7 +19,6 @@ use dom::node::{Node, UnbindContext, document_from_node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom_struct::dom_struct;
use html5ever_atoms::LocalName;
use parking_lot::RwLock;
use servo_config::prefs::PREFS;
use std::ascii::AsciiExt;
use std::sync::Arc;
@ -99,12 +98,16 @@ impl HTMLMetaElement {
let content = content.value();
if !content.is_empty() {
if let Some(translated_rule) = ViewportRule::from_meta(&**content) {
let document = self.upcast::<Node>().owner_doc();
let shared_lock = document.style_shared_lock();
let rule = CssRule::Viewport(Arc::new(shared_lock.wrap(translated_rule)));
*self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet {
rules: CssRules::new(vec![CssRule::Viewport(Arc::new(RwLock::new(translated_rule)))]),
rules: CssRules::new(vec![rule], shared_lock),
origin: Origin::Author,
shared_lock: shared_lock.clone(),
base_url: window_from_node(self).get_url(),
namespaces: Default::default(),
media: Default::default(),
media: Arc::new(shared_lock.wrap(Default::default())),
// Viewport constraints are always recomputed on resize; they don't need to
// force all styles to be recomputed.
dirty_on_viewport_size_change: AtomicBool::new(false),

View File

@ -84,9 +84,10 @@ impl HTMLStyleElement {
let data = node.GetTextContent().expect("Element.textContent must be a string");
let mq = parse_media_query_list(&mut CssParser::new(&mq_str));
let shared_lock = node.owner_doc().style_shared_lock().clone();
let loader = StylesheetLoader::for_element(self.upcast());
let sheet = Stylesheet::from_str(&data, url, Origin::Author, mq,
Some(&loader),
shared_lock, Some(&loader),
win.css_error_reporter(),
ParserContextExtraData::default());

View File

@ -6,52 +6,62 @@ use core::default::Default;
use cssparser::Parser;
use dom::bindings::codegen::Bindings::MediaListBinding;
use dom::bindings::codegen::Bindings::MediaListBinding::MediaListMethods;
use dom::bindings::js::Root;
use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc;
use style::media_queries::{MediaQuery, parse_media_query_list};
use style::media_queries::MediaList as StyleMediaList;
use style::shared_lock::{SharedRwLock, Locked};
use style_traits::ToCss;
#[dom_struct]
pub struct MediaList {
reflector_: Reflector,
parent_stylesheet: JS<CSSStyleSheet>,
#[ignore_heap_size_of = "Arc"]
media_queries: Arc<RwLock<StyleMediaList>>,
media_queries: Arc<Locked<StyleMediaList>>,
}
impl MediaList {
#[allow(unrooted_must_root)]
pub fn new_inherited(media_queries: Arc<RwLock<StyleMediaList>>) -> MediaList {
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet,
media_queries: Arc<Locked<StyleMediaList>>) -> MediaList {
MediaList {
parent_stylesheet: JS::from_ref(parent_stylesheet),
reflector_: Reflector::new(),
media_queries: media_queries,
}
}
#[allow(unrooted_must_root)]
pub fn new(window: &Window, media_queries: Arc<RwLock<StyleMediaList>>)
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
media_queries: Arc<Locked<StyleMediaList>>)
-> Root<MediaList> {
reflect_dom_object(box MediaList::new_inherited(media_queries),
reflect_dom_object(box MediaList::new_inherited(parent_stylesheet, media_queries),
window,
MediaListBinding::Wrap)
}
fn shared_lock(&self) -> &SharedRwLock {
&self.parent_stylesheet.style_stylesheet().shared_lock
}
}
impl MediaListMethods for MediaList {
// https://drafts.csswg.org/cssom/#dom-medialist-mediatext
fn MediaText(&self) -> DOMString {
DOMString::from(self.media_queries.read().to_css_string())
let guard = self.shared_lock().read();
DOMString::from(self.media_queries.read_with(&guard).to_css_string())
}
// https://drafts.csswg.org/cssom/#dom-medialist-mediatext
fn SetMediaText(&self, value: DOMString) {
let mut media_queries = self.media_queries.write();
let mut guard = self.shared_lock().write();
let mut media_queries = self.media_queries.write_with(&mut guard);
// Step 2
if value.is_empty() {
// Step 1
@ -65,13 +75,15 @@ impl MediaListMethods for MediaList {
// https://drafts.csswg.org/cssom/#dom-medialist-length
fn Length(&self) -> u32 {
self.media_queries.read().media_queries.len() as u32
let guard = self.shared_lock().read();
self.media_queries.read_with(&guard).media_queries.len() as u32
}
// https://drafts.csswg.org/cssom/#dom-medialist-item
fn Item(&self, index: u32) -> Option<DOMString> {
self.media_queries.read().media_queries.get(index as usize)
.and_then(|query| {
let guard = self.shared_lock().read();
self.media_queries.read_with(&guard).media_queries
.get(index as usize).and_then(|query| {
let mut s = String::new();
query.to_css(&mut s).unwrap();
Some(DOMString::from_string(s))
@ -94,13 +106,14 @@ impl MediaListMethods for MediaList {
}
// Step 3
let m_serialized = m.clone().unwrap().to_css_string();
let any = self.media_queries.read().media_queries.iter()
.any(|q| m_serialized == q.to_css_string());
let mut guard = self.shared_lock().write();
let mq = self.media_queries.write_with(&mut guard);
let any = mq.media_queries.iter().any(|q| m_serialized == q.to_css_string());
if any {
return;
}
// Step 4
self.media_queries.write().media_queries.push(m.unwrap());
mq.media_queries.push(m.unwrap());
}
// https://drafts.csswg.org/cssom/#dom-medialist-deletemedium
@ -114,7 +127,8 @@ impl MediaListMethods for MediaList {
}
// Step 3
let m_serialized = m.unwrap().to_css_string();
let mut media_list = self.media_queries.write();
let mut guard = self.shared_lock().write();
let mut media_list = self.media_queries.write_with(&mut guard);
let new_vec = media_list.media_queries.drain(..)
.filter(|q| m_serialized != q.to_css_string())
.collect();

View File

@ -44,7 +44,6 @@ use dom::text::Text;
use gfx_traits::ByteIndex;
use html5ever_atoms::{LocalName, Namespace};
use msg::constellation_msg::PipelineId;
use parking_lot::RwLock;
use range::Range;
use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress};
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
@ -69,6 +68,7 @@ use style::dom::UnsafeNode;
use style::element_state::*;
use style::properties::{ComputedValues, PropertyDeclarationBlock};
use style::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl};
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
use style::sink::Push;
use style::str::is_whitespace;
use style::stylist::ApplicableDeclarationBlock;
@ -330,6 +330,10 @@ impl<'ld> ServoLayoutDocument<'ld> {
unsafe { self.document.quirks_mode() }
}
pub fn style_shared_lock(&self) -> &StyleSharedRwLock {
unsafe { self.document.style_shared_lock() }
}
pub fn from_layout_js(doc: LayoutJS<Document>) -> ServoLayoutDocument<'ld> {
ServoLayoutDocument {
document: doc,
@ -372,7 +376,7 @@ impl<'le> TElement for ServoLayoutElement<'le> {
ServoLayoutNode::from_layout_js(self.element.upcast())
}
fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>> {
fn style_attribute(&self) -> Option<&Arc<StyleLocked<PropertyDeclarationBlock>>> {
unsafe {
(*self.element.style_attribute()).as_ref()
}

View File

@ -22,13 +22,13 @@ use ipc_channel::router::ROUTER;
use net_traits::{FetchResponseListener, FetchMetadata, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy};
use net_traits::request::{CorsSettings, CredentialsMode, Destination, RequestInit, RequestMode, Type as RequestType};
use network_listener::{NetworkListener, PreInvoke};
use parking_lot::RwLock;
use script_layout_interface::message::Msg;
use servo_url::ServoUrl;
use std::mem;
use std::sync::{Arc, Mutex};
use style::media_queries::MediaList;
use style::parser::ParserContextExtraData;
use style::shared_lock::Locked as StyleLocked;
use style::stylesheets::{ImportRule, Stylesheet, Origin};
use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
@ -54,24 +54,8 @@ pub trait StylesheetOwner {
pub enum StylesheetContextSource {
// NB: `media` is just an option so we avoid cloning it.
LinkElement { media: Option<MediaList>, url: ServoUrl },
Import(Arc<RwLock<ImportRule>>),
}
impl StylesheetContextSource {
fn url(&self) -> ServoUrl {
match *self {
StylesheetContextSource::LinkElement { ref url, .. } => url.clone(),
StylesheetContextSource::Import(ref import) => {
let import = import.read();
// Look at the parser in style::stylesheets, where we don't
// trigger a load if the url is invalid.
import.url.url()
.expect("Invalid urls shouldn't enter the loader")
.clone()
}
}
}
LinkElement { media: Option<MediaList>, },
Import(Arc<Stylesheet>),
}
/// The context required for asynchronously loading an external stylesheet.
@ -79,6 +63,7 @@ pub struct StylesheetContext {
/// The element that initiated the request.
elem: Trusted<HTMLElement>,
source: StylesheetContextSource,
url: ServoUrl,
metadata: Option<Metadata>,
/// The response body received to date.
data: Vec<u8>,
@ -145,19 +130,21 @@ impl FetchResponseListener for StylesheetContext {
let loader = StylesheetLoader::for_element(&elem);
match self.source {
StylesheetContextSource::LinkElement { ref mut media, .. } => {
StylesheetContextSource::LinkElement { ref mut media } => {
let link = elem.downcast::<HTMLLinkElement>().unwrap();
// We must first check whether the generations of the context and the element match up,
// else we risk applying the wrong stylesheet when responses come out-of-order.
let is_stylesheet_load_applicable =
self.request_generation_id.map_or(true, |gen| gen == link.get_request_generation_id());
if is_stylesheet_load_applicable {
let shared_lock = document.style_shared_lock().clone();
let sheet =
Arc::new(Stylesheet::from_bytes(&data, final_url,
protocol_encoding_label,
Some(environment_encoding),
Origin::Author,
media.take().unwrap(),
shared_lock,
Some(&loader),
win.css_error_reporter(),
ParserContextExtraData::default()));
@ -171,9 +158,8 @@ impl FetchResponseListener for StylesheetContext {
win.layout_chan().send(Msg::AddStylesheet(sheet)).unwrap();
}
}
StylesheetContextSource::Import(ref import) => {
let import = import.read();
Stylesheet::update_from_bytes(&import.stylesheet,
StylesheetContextSource::Import(ref stylesheet) => {
Stylesheet::update_from_bytes(&stylesheet,
&data,
protocol_encoding_label,
Some(environment_encoding),
@ -197,8 +183,7 @@ impl FetchResponseListener for StylesheetContext {
document.decrement_script_blocking_stylesheet_count();
}
let url = self.source.url();
document.finish_load(LoadType::Stylesheet(url));
document.finish_load(LoadType::Stylesheet(self.url.clone()));
if let Some(any_failed) = owner.load_finished(successful) {
let event = if any_failed { atom!("error") } else { atom!("load") };
@ -220,15 +205,16 @@ impl<'a> StylesheetLoader<'a> {
}
impl<'a> StylesheetLoader<'a> {
pub fn load(&self, source: StylesheetContextSource, cors_setting: Option<CorsSettings>,
pub fn load(&self, source: StylesheetContextSource, url: ServoUrl,
cors_setting: Option<CorsSettings>,
integrity_metadata: String) {
let url = source.url();
let document = document_from_node(self.elem);
let gen = self.elem.downcast::<HTMLLinkElement>()
.map(HTMLLinkElement::get_request_generation_id);
let context = Arc::new(Mutex::new(StylesheetContext {
elem: Trusted::new(&*self.elem),
source: source,
url: url.clone(),
metadata: None,
data: vec![],
document: Trusted::new(&*document),
@ -285,9 +271,20 @@ impl<'a> StylesheetLoader<'a> {
}
impl<'a> StyleStylesheetLoader for StylesheetLoader<'a> {
fn request_stylesheet(&self, import: &Arc<RwLock<ImportRule>>) {
fn request_stylesheet(
&self,
media: MediaList,
make_import: &mut FnMut(MediaList) -> ImportRule,
make_arc: &mut FnMut(ImportRule) -> Arc<StyleLocked<ImportRule>>,
) -> Arc<StyleLocked<ImportRule>> {
let import = make_import(media);
let url = import.url.url().expect("Invalid urls shouldn't enter the loader").clone();
//TODO (mrnayak) : Whether we should use the original loader's CORS setting?
//Fix this when spec has more details.
self.load(StylesheetContextSource::Import(import.clone()), None, "".to_owned())
let source = StylesheetContextSource::Import(import.stylesheet.clone());
self.load(source, url, None, "".to_owned());
make_arc(import)
}
}

View File

@ -405,6 +405,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
let mut data = self.get_style_data().unwrap().borrow_mut();
let new_style =
context.stylist.precomputed_values_for_pseudo(
&context.guards,
&style_pseudo,
Some(data.styles().primary.values()),
CascadeFlags::empty());
@ -421,6 +422,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
let new_style =
context.stylist
.lazily_compute_pseudo_element_style(
&context.guards,
unsafe { &self.unsafe_get() },
&style_pseudo,
data.styles().primary.values());

View File

@ -13,7 +13,7 @@ path = "lib.rs"
doctest = false
[features]
gecko = ["nsstring_vendor", "rayon/unstable"]
gecko = ["nsstring_vendor", "rayon/unstable", "num_cpus"]
use_bindgen = ["bindgen", "regex"]
servo = ["serde/unstable", "serde", "serde_derive", "heapsize_derive",
"style_traits/servo", "servo_atoms", "html5ever-atoms",
@ -37,10 +37,10 @@ lazy_static = "0.2"
log = "0.3"
matches = "0.1"
nsstring_vendor = {path = "gecko_bindings/nsstring_vendor", optional = true}
num_cpus = {version = "1.1.0", optional = true}
num-integer = "0.1.32"
num-traits = "0.1.32"
ordered-float = "0.4"
owning_ref = "0.2.2"
parking_lot = "0.3.3"
pdqsort = "0.1.0"
rayon = "0.6"

View File

@ -415,7 +415,7 @@ fn compute_style_for_animation_step(context: &SharedStyleContext,
match step.value {
KeyframesStepValue::ComputedValues => style_from_cascade.clone(),
KeyframesStepValue::Declarations { block: ref declarations } => {
let guard = declarations.read();
let guard = declarations.read_with(context.guards.author);
// No !important in keyframes.
debug_assert!(guard.declarations().iter()

View File

@ -11,9 +11,9 @@ use app_units::Au;
use cssparser::{self, Color, RGBA};
use euclid::num::Zero;
use num_traits::ToPrimitive;
use parking_lot::RwLock;
use properties::PropertyDeclarationBlock;
use servo_url::ServoUrl;
use shared_lock::Locked;
use std::ascii::AsciiExt;
use std::str::FromStr;
use std::sync::Arc;
@ -61,7 +61,7 @@ pub enum AttrValue {
/// declarationblock for longer than needed.
Declaration(String,
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
Arc<RwLock<PropertyDeclarationBlock>>)
Arc<Locked<PropertyDeclarationBlock>>)
}
/// Shared implementation to parse an integer according to

View File

@ -17,6 +17,7 @@ use parking_lot::RwLock;
use selector_parser::PseudoElement;
use selectors::matching::ElementSelectorFlags;
use servo_config::opts;
use shared_lock::StylesheetGuards;
use std::collections::HashMap;
use std::env;
use std::fmt;
@ -61,10 +62,13 @@ pub enum QuirksMode {
///
/// There's exactly one of these during a given restyle traversal, and it's
/// shared among the worker threads.
pub struct SharedStyleContext {
pub struct SharedStyleContext<'a> {
/// The CSS selector stylist.
pub stylist: Arc<Stylist>,
/// Guards for pre-acquired locks
pub guards: StylesheetGuards<'a>,
/// The animations that are currently running.
pub running_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
@ -85,7 +89,7 @@ pub struct SharedStyleContext {
pub quirks_mode: QuirksMode,
}
impl SharedStyleContext {
impl<'a> SharedStyleContext<'a> {
/// Return a suitable viewport size in order to be used for viewport units.
pub fn viewport_size(&self) -> Size2D<Au> {
self.stylist.device.au_viewport_size()
@ -306,7 +310,7 @@ impl<E: TElement> Drop for ThreadLocalStyleContext<E> {
/// shared style context, and a mutable reference to a local one.
pub struct StyleContext<'a, E: TElement + 'a> {
/// The shared style context reference.
pub shared: &'a SharedStyleContext,
pub shared: &'a SharedStyleContext<'a>,
/// The thread-local style context (mutable) reference.
pub thread_local: &'a mut ThreadLocalStyleContext<E>,
}

View File

@ -11,10 +11,10 @@ use {Atom, Namespace, LocalName};
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use data::ElementData;
use element_state::ElementState;
use parking_lot::RwLock;
use properties::{ComputedValues, PropertyDeclarationBlock};
use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement};
use selectors::matching::ElementSelectorFlags;
use shared_lock::Locked;
use sink::Push;
use std::fmt;
use std::fmt::Debug;
@ -230,8 +230,8 @@ pub trait PresentationalHintsSynthetizer {
/// The animation rules. The first one is for Animation cascade level, and the second one is for
/// Transition cascade level.
pub struct AnimationRules(pub Option<Arc<RwLock<PropertyDeclarationBlock>>>,
pub Option<Arc<RwLock<PropertyDeclarationBlock>>>);
pub struct AnimationRules(pub Option<Arc<Locked<PropertyDeclarationBlock>>>,
pub Option<Arc<Locked<PropertyDeclarationBlock>>>);
/// The element trait, the main abstraction the style crate acts over.
pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer {
@ -252,7 +252,7 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
}
/// Get this element's style attribute.
fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>>;
fn style_attribute(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>>;
/// Get this element's animation rules.
fn get_animation_rules(&self, _pseudo: Option<&PseudoElement>) -> AnimationRules {
@ -261,13 +261,13 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
/// Get this element's animation rule.
fn get_animation_rule(&self, _pseudo: Option<&PseudoElement>)
-> Option<Arc<RwLock<PropertyDeclarationBlock>>> {
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
None
}
/// Get this element's transition rule.
fn get_transition_rule(&self, _pseudo: Option<&PseudoElement>)
-> Option<Arc<RwLock<PropertyDeclarationBlock>>> {
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
None
}

View File

@ -12,6 +12,7 @@ use media_queries::MediaList;
use parser::ParserContextExtraData;
use self::encoding::{EncodingRef, DecoderTrap};
use servo_url::ServoUrl;
use shared_lock::SharedRwLock;
use std::str;
use stylesheets::{Stylesheet, StylesheetLoader, Origin};
@ -54,6 +55,7 @@ impl Stylesheet {
environment_encoding: Option<EncodingRef>,
origin: Origin,
media: MediaList,
shared_lock: SharedRwLock,
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData)
@ -64,6 +66,7 @@ impl Stylesheet {
base_url,
origin,
media,
shared_lock,
stylesheet_loader,
error_reporter,
extra_data)

View File

@ -14,6 +14,7 @@ use computed_values::font_family::FamilyName;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
#[cfg(feature = "gecko")] use cssparser::UnicodeRange;
use parser::{ParserContext, log_css_error, Parse};
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt;
use std::iter;
use style_traits::{ToCss, OneOrMoreCommaSeparated};
@ -230,11 +231,10 @@ macro_rules! font_face_descriptors {
}
}
impl ToCss for FontFaceRule {
impl ToCssWithGuard for FontFaceRule {
// Serialization of FontFaceRule is not specced.
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write,
{
fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
dest.write_str("@font-face {\n")?;
$(
dest.write_str(concat!(" ", $m_name, ": "))?;

View File

@ -17,6 +17,7 @@ use media_queries::MediaList;
use parking_lot::RwLock;
use properties::{ComputedValues, PropertyDeclarationBlock};
use properties::animated_properties::{AnimationValue, AnimationValueMap};
use shared_lock::Locked;
use stylesheets::{CssRules, Stylesheet, StyleRule, ImportRule, MediaRule, NamespaceRule};
macro_rules! impl_arc_ffi {
@ -38,7 +39,7 @@ macro_rules! impl_arc_ffi {
}
}
impl_arc_ffi!(RwLock<CssRules> => ServoCssRules
impl_arc_ffi!(Locked<CssRules> => ServoCssRules
[Servo_CssRules_AddRef, Servo_CssRules_Release]);
impl_arc_ffi!(Stylesheet => RawServoStyleSheet
@ -47,13 +48,13 @@ impl_arc_ffi!(Stylesheet => RawServoStyleSheet
impl_arc_ffi!(ComputedValues => ServoComputedValues
[Servo_ComputedValues_AddRef, Servo_ComputedValues_Release]);
impl_arc_ffi!(RwLock<PropertyDeclarationBlock> => RawServoDeclarationBlock
impl_arc_ffi!(Locked<PropertyDeclarationBlock> => RawServoDeclarationBlock
[Servo_DeclarationBlock_AddRef, Servo_DeclarationBlock_Release]);
impl_arc_ffi!(RwLock<StyleRule> => RawServoStyleRule
impl_arc_ffi!(Locked<StyleRule> => RawServoStyleRule
[Servo_StyleRule_AddRef, Servo_StyleRule_Release]);
impl_arc_ffi!(RwLock<ImportRule> => RawServoImportRule
impl_arc_ffi!(Locked<ImportRule> => RawServoImportRule
[Servo_ImportRule_AddRef, Servo_ImportRule_Release]);
impl_arc_ffi!(AnimationValue => RawServoAnimationValue
@ -62,11 +63,11 @@ impl_arc_ffi!(AnimationValue => RawServoAnimationValue
impl_arc_ffi!(RwLock<AnimationValueMap> => RawServoAnimationValueMap
[Servo_AnimationValueMap_AddRef, Servo_AnimationValueMap_Release]);
impl_arc_ffi!(RwLock<MediaList> => RawServoMediaList
impl_arc_ffi!(Locked<MediaList> => RawServoMediaList
[Servo_MediaList_AddRef, Servo_MediaList_Release]);
impl_arc_ffi!(RwLock<MediaRule> => RawServoMediaRule
impl_arc_ffi!(Locked<MediaRule> => RawServoMediaRule
[Servo_MediaRule_AddRef, Servo_MediaRule_Release]);
impl_arc_ffi!(RwLock<NamespaceRule> => RawServoNamespaceRule
impl_arc_ffi!(Locked<NamespaceRule> => RawServoNamespaceRule
[Servo_NamespaceRule_AddRef, Servo_NamespaceRule_Release]);

View File

@ -13,6 +13,7 @@ use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
use media_queries::Device;
use parking_lot::RwLock;
use properties::ComputedValues;
use shared_lock::{StylesheetGuards, SharedRwLockReadGuard};
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender, channel};
@ -83,20 +84,20 @@ impl PerDocumentStyleDataImpl {
/// Reset the device state because it may have changed.
///
/// Implies also a stylesheet flush.
pub fn reset_device(&mut self) {
pub fn reset_device(&mut self, guard: &SharedRwLockReadGuard) {
{
let mut stylist = Arc::get_mut(&mut self.stylist).unwrap();
Arc::get_mut(&mut stylist.device).unwrap().reset();
}
self.stylesheets_changed = true;
self.flush_stylesheets();
self.flush_stylesheets(guard);
}
/// Recreate the style data if the stylesheets have changed.
pub fn flush_stylesheets(&mut self) {
pub fn flush_stylesheets(&mut self, guard: &SharedRwLockReadGuard) {
if self.stylesheets_changed {
let mut stylist = Arc::get_mut(&mut self.stylist).unwrap();
stylist.update(&self.stylesheets, None, true);
stylist.update(&self.stylesheets, &StylesheetGuards::same(guard), None, true);
self.stylesheets_changed = false;
}
}

View File

@ -0,0 +1,50 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Global style data
use num_cpus;
use rayon;
use shared_lock::SharedRwLock;
use std::cmp;
use std::env;
/// Global style data
pub struct GlobalStyleData {
/// How many threads parallel styling can use.
pub num_threads: usize,
/// The parallel styling thread pool.
pub style_thread_pool: Option<rayon::ThreadPool>,
/// Shared RWLock for CSSOM objects
pub shared_lock: SharedRwLock,
}
lazy_static! {
/// Global style data
pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = {
let stylo_threads = env::var("STYLO_THREADS")
.map(|s| s.parse::<usize>().expect("invalid STYLO_THREADS value"));
let num_threads = match stylo_threads {
Ok(num) => num,
_ => cmp::max(num_cpus::get() * 3 / 4, 1),
};
let pool = if num_threads <= 1 {
None
} else {
let configuration =
rayon::Configuration::new().set_num_threads(num_threads);
let pool = rayon::ThreadPool::new(configuration).ok();
pool
};
GlobalStyleData {
num_threads: num_threads,
style_thread_pool: pool,
shared_lock: SharedRwLock::new(),
}
};
}

View File

@ -10,6 +10,7 @@ mod non_ts_pseudo_class_list;
pub mod arc_types;
pub mod conversions;
pub mod data;
pub mod global_style_data;
pub mod media_queries;
pub mod restyle_damage;
pub mod selector_parser;

View File

@ -13,14 +13,14 @@ use traversal::{DomTraversal, PerLevelTraversalData, TraversalDriver, recalc_sty
/// This is the simple struct that Gecko uses to encapsulate a DOM traversal for
/// styling.
pub struct RecalcStyleOnly {
shared: SharedStyleContext,
pub struct RecalcStyleOnly<'a> {
shared: SharedStyleContext<'a>,
driver: TraversalDriver,
}
impl RecalcStyleOnly {
impl<'a> RecalcStyleOnly<'a> {
/// Create a `RecalcStyleOnly` traversal from a `SharedStyleContext`.
pub fn new(shared: SharedStyleContext, driver: TraversalDriver) -> Self {
pub fn new(shared: SharedStyleContext<'a>, driver: TraversalDriver) -> Self {
RecalcStyleOnly {
shared: shared,
driver: driver,
@ -28,10 +28,11 @@ impl RecalcStyleOnly {
}
}
impl<'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly {
impl<'recalc, 'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly<'recalc> {
type ThreadLocalContext = ThreadLocalStyleContext<GeckoElement<'le>>;
fn process_preorder(&self, traversal_data: &mut PerLevelTraversalData,
fn process_preorder(&self,
traversal_data: &mut PerLevelTraversalData,
thread_local: &mut Self::ThreadLocalContext,
node: GeckoNode<'le>)
{

View File

@ -20,6 +20,7 @@ use dom::{AnimationRules, LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode}
use dom::{OpaqueNode, PresentationalHintsSynthetizer};
use element_state::ElementState;
use error_reporting::StdoutErrorReporter;
use gecko::global_style_data::GLOBAL_STYLE_DATA;
use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement};
use gecko::snapshot_helpers;
use gecko_bindings::bindings;
@ -53,6 +54,7 @@ use selectors::Element;
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector};
use selectors::parser::{AttrSelector, NamespaceConstraint};
use servo_url::ServoUrl;
use shared_lock::Locked;
use sink::Push;
use std::fmt;
use std::ptr;
@ -407,12 +409,14 @@ fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -> u32 {
fn get_animation_rule(element: &GeckoElement,
pseudo: Option<&PseudoElement>,
cascade_level: CascadeLevel)
-> Option<Arc<RwLock<PropertyDeclarationBlock>>> {
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
let atom_ptr = PseudoElement::ns_atom_or_null_from_opt(pseudo);
let animation_values = Arc::new(RwLock::new(AnimationValueMap::new()));
if unsafe { Gecko_GetAnimationRule(element.0, atom_ptr, cascade_level,
HasArcFFI::arc_as_borrowed(&animation_values)) } {
Some(Arc::new(RwLock::new(PropertyDeclarationBlock::from_animation_value_map(&animation_values.read()))))
let shared_lock = &GLOBAL_STYLE_DATA.shared_lock;
Some(Arc::new(shared_lock.wrap(
PropertyDeclarationBlock::from_animation_value_map(&animation_values.read()))))
} else {
None
}
@ -425,7 +429,7 @@ impl<'le> TElement for GeckoElement<'le> {
unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
}
fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>> {
fn style_attribute(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>> {
let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0) };
declarations.map(|s| s.as_arc_opt()).unwrap_or(None)
}
@ -436,12 +440,12 @@ impl<'le> TElement for GeckoElement<'le> {
}
fn get_animation_rule(&self, pseudo: Option<&PseudoElement>)
-> Option<Arc<RwLock<PropertyDeclarationBlock>>> {
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
get_animation_rule(self, pseudo, CascadeLevel::Animations)
}
fn get_transition_rule(&self, pseudo: Option<&PseudoElement>)
-> Option<Arc<RwLock<PropertyDeclarationBlock>>> {
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
get_animation_rule(self, pseudo, CascadeLevel::Transitions)
}

View File

@ -8,13 +8,13 @@
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule};
use parking_lot::RwLock;
use parser::{ParserContext, ParserContextExtraData, log_css_error};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
use properties::{PropertyDeclarationId, LonghandId, ParsedDeclaration};
use properties::LonghandIdSet;
use properties::animated_properties::TransitionProperty;
use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
use shared_lock::{SharedRwLock, SharedRwLockReadGuard, Locked, ToCssWithGuard};
use std::fmt;
use std::sync::Arc;
use style_traits::ToCss;
@ -101,11 +101,12 @@ pub struct Keyframe {
///
/// Note that `!important` rules in keyframes don't apply, but we keep this
/// `Arc` just for convenience.
pub block: Arc<RwLock<PropertyDeclarationBlock>>,
pub block: Arc<Locked<PropertyDeclarationBlock>>,
}
impl ToCss for Keyframe {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
impl ToCssWithGuard for Keyframe {
fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
let mut iter = self.selector.percentages().iter();
try!(iter.next().unwrap().to_css(dest));
for percentage in iter {
@ -113,7 +114,7 @@ impl ToCss for Keyframe {
try!(percentage.to_css(dest));
}
try!(dest.write_str(" { "));
try!(self.block.read().to_css(dest));
try!(self.block.read_with(guard).to_css(dest));
try!(dest.write_str(" }"));
Ok(())
}
@ -125,7 +126,7 @@ impl Keyframe {
pub fn parse(css: &str,
parent_stylesheet: &Stylesheet,
extra_data: ParserContextExtraData)
-> Result<Arc<RwLock<Self>>, ()> {
-> Result<Arc<Locked<Self>>, ()> {
let error_reporter = MemoryHoleReporter;
let context = ParserContext::new_with_extra_data(parent_stylesheet.origin,
&parent_stylesheet.base_url,
@ -135,6 +136,7 @@ impl Keyframe {
let mut rule_parser = KeyframeListParser {
context: &context,
shared_lock: &parent_stylesheet.shared_lock,
};
parse_one_rule(&mut input, &mut rule_parser)
}
@ -152,7 +154,7 @@ pub enum KeyframesStepValue {
Declarations {
/// The declaration block per se.
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
block: Arc<RwLock<PropertyDeclarationBlock>>
block: Arc<Locked<PropertyDeclarationBlock>>
},
/// A synthetic step computed from the current computed values at the time
/// of the animation.
@ -178,10 +180,11 @@ pub struct KeyframesStep {
impl KeyframesStep {
#[inline]
fn new(percentage: KeyframePercentage,
value: KeyframesStepValue) -> Self {
value: KeyframesStepValue,
guard: &SharedRwLockReadGuard) -> Self {
let declared_timing_function = match value {
KeyframesStepValue::Declarations { ref block } => {
block.read().declarations().iter().any(|&(ref prop_decl, _)| {
block.read_with(guard).declarations().iter().any(|&(ref prop_decl, _)| {
match *prop_decl {
PropertyDeclaration::AnimationTimingFunction(..) => true,
_ => false,
@ -199,13 +202,14 @@ impl KeyframesStep {
}
/// Return specified TransitionTimingFunction if this KeyframesSteps has 'animation-timing-function'.
pub fn get_animation_timing_function(&self) -> Option<SpecifiedTimingFunction> {
pub fn get_animation_timing_function(&self, guard: &SharedRwLockReadGuard)
-> Option<SpecifiedTimingFunction> {
if !self.declared_timing_function {
return None;
}
match self.value {
KeyframesStepValue::Declarations { ref block } => {
let guard = block.read();
let guard = block.read_with(guard);
let &(ref declaration, _) =
guard.get(PropertyDeclarationId::Longhand(LonghandId::AnimationTimingFunction)).unwrap();
match *declaration {
@ -239,14 +243,16 @@ pub struct KeyframesAnimation {
}
/// Get all the animated properties in a keyframes animation.
fn get_animated_properties(keyframes: &[Arc<RwLock<Keyframe>>]) -> Vec<TransitionProperty> {
fn get_animated_properties(keyframes: &[Arc<Locked<Keyframe>>], guard: &SharedRwLockReadGuard)
-> Vec<TransitionProperty> {
let mut ret = vec![];
let mut seen = LonghandIdSet::new();
// NB: declarations are already deduplicated, so we don't have to check for
// it here.
for keyframe in keyframes {
let keyframe = keyframe.read();
for &(ref declaration, importance) in keyframe.block.read().declarations().iter() {
let keyframe = keyframe.read_with(&guard);
let block = keyframe.block.read_with(guard);
for &(ref declaration, importance) in block.declarations().iter() {
assert!(!importance.important());
if let Some(property) = TransitionProperty::from_declaration(declaration) {
@ -270,7 +276,8 @@ impl KeyframesAnimation {
///
/// Otherwise, this will compute and sort the steps used for the animation,
/// and return the animation object.
pub fn from_keyframes(keyframes: &[Arc<RwLock<Keyframe>>]) -> Self {
pub fn from_keyframes(keyframes: &[Arc<Locked<Keyframe>>], guard: &SharedRwLockReadGuard)
-> Self {
let mut result = KeyframesAnimation {
steps: vec![],
properties_changed: vec![],
@ -280,17 +287,17 @@ impl KeyframesAnimation {
return result;
}
result.properties_changed = get_animated_properties(keyframes);
result.properties_changed = get_animated_properties(keyframes, guard);
if result.properties_changed.is_empty() {
return result;
}
for keyframe in keyframes {
let keyframe = keyframe.read();
let keyframe = keyframe.read_with(&guard);
for percentage in keyframe.selector.0.iter() {
result.steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations {
block: keyframe.block.clone(),
}));
}, guard));
}
}
@ -300,12 +307,14 @@ impl KeyframesAnimation {
// Prepend autogenerated keyframes if appropriate.
if result.steps[0].start_percentage.0 != 0. {
result.steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.),
KeyframesStepValue::ComputedValues));
KeyframesStepValue::ComputedValues,
guard));
}
if result.steps.last().unwrap().start_percentage.0 != 1. {
result.steps.push(KeyframesStep::new(KeyframePercentage::new(1.),
KeyframesStepValue::ComputedValues));
KeyframesStepValue::ComputedValues,
guard));
}
result
@ -322,24 +331,27 @@ impl KeyframesAnimation {
/// }
struct KeyframeListParser<'a> {
context: &'a ParserContext<'a>,
shared_lock: &'a SharedRwLock,
}
/// Parses a keyframe list from CSS input.
pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser) -> Vec<Arc<RwLock<Keyframe>>> {
RuleListParser::new_for_nested_rule(input, KeyframeListParser { context: context })
.filter_map(Result::ok)
.collect()
pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser, shared_lock: &SharedRwLock)
-> Vec<Arc<Locked<Keyframe>>> {
RuleListParser::new_for_nested_rule(input, KeyframeListParser {
context: context,
shared_lock: shared_lock,
}).filter_map(Result::ok).collect()
}
enum Void {}
impl<'a> AtRuleParser for KeyframeListParser<'a> {
type Prelude = Void;
type AtRule = Arc<RwLock<Keyframe>>;
type AtRule = Arc<Locked<Keyframe>>;
}
impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
type Prelude = KeyframeSelector;
type QualifiedRule = Arc<RwLock<Keyframe>>;
type QualifiedRule = Arc<Locked<Keyframe>>;
fn parse_prelude(&mut self, input: &mut Parser) -> Result<Self::Prelude, ()> {
let start = input.position();
@ -372,9 +384,9 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
}
// `parse_important` is not called here, `!important` is not allowed in keyframe blocks.
}
Ok(Arc::new(RwLock::new(Keyframe {
Ok(Arc::new(self.shared_lock.wrap(Keyframe {
selector: prelude,
block: Arc::new(RwLock::new(block)),
block: Arc::new(self.shared_lock.wrap(block)),
})))
}
}

View File

@ -57,10 +57,10 @@ extern crate log;
#[macro_use]
extern crate matches;
#[cfg(feature = "gecko")] extern crate nsstring_vendor as nsstring;
#[cfg(feature = "gecko")] extern crate num_cpus;
extern crate num_integer;
extern crate num_traits;
extern crate ordered_float;
extern crate owning_ref;
extern crate parking_lot;
extern crate pdqsort;
extern crate rayon;
@ -99,13 +99,13 @@ pub mod keyframes;
pub mod logical_geometry;
pub mod matching;
pub mod media_queries;
pub mod owning_handle;
pub mod parallel;
pub mod parser;
pub mod restyle_hints;
pub mod rule_tree;
pub mod scoped_tls;
pub mod selector_parser;
pub mod shared_lock;
pub mod stylist;
#[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod servo;
pub mod sequential;
@ -168,6 +168,8 @@ macro_rules! reexport_computed_values {
longhand_properties_idents!(reexport_computed_values);
/// Returns whether the two arguments point to the same value.
///
/// FIXME: Remove this and use Arc::ptr_eq once we require Rust 1.17
#[inline]
pub fn arc_ptr_eq<T: 'static>(a: &Arc<T>, b: &Arc<T>) -> bool {
let a: &T = &**a;

View File

@ -541,6 +541,7 @@ trait PrivateMatchMethods: TElement {
let values =
Arc::new(cascade(&shared_context.stylist.device,
rule_node,
&shared_context.guards,
inherited_values,
layout_parent_style,
Some(&mut cascade_info),
@ -784,6 +785,7 @@ pub trait MatchMethods : TElement {
style_attribute,
animation_rules,
None,
&context.shared.guards,
&mut applicable_declarations,
&mut flags);
let primary_rule_node = compute_rule_node(context, &mut applicable_declarations);
@ -809,6 +811,7 @@ pub trait MatchMethods : TElement {
Some(context.thread_local.bloom_filter.filter()),
None, pseudo_animation_rules,
Some(&pseudo),
&context.shared.guards,
&mut applicable_declarations,
&mut flags);
@ -883,7 +886,8 @@ pub trait MatchMethods : TElement {
let new_node = context.shared.stylist.rule_tree
.update_rule_at_level(CascadeLevel::StyleAttributeNormal,
style_attribute,
primary_rules);
primary_rules,
&context.shared.guards);
if let Some(n) = new_node {
*primary_rules = n;
rule_node_changed = true;
@ -892,7 +896,8 @@ pub trait MatchMethods : TElement {
let new_node = context.shared.stylist.rule_tree
.update_rule_at_level(CascadeLevel::StyleAttributeImportant,
style_attribute,
primary_rules);
primary_rules,
&context.shared.guards);
if let Some(n) = new_node {
*primary_rules = n;
rule_node_changed = true;

View File

@ -1,89 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#![allow(unsafe_code)]
#![deny(missing_docs)]
//! A handle that encapsulate a reference to a given data along with its owner.
use owning_ref::StableAddress;
use std::ops::{Deref, DerefMut};
/// `OwningHandle` is a complement to `OwningRef`. Where `OwningRef` allows
/// consumers to pass around an owned object and a dependent reference,
/// `OwningHandle` contains an owned object and a dependent _object_.
///
/// `OwningHandle` can encapsulate a `RefMut` along with its associated
/// `RefCell`, or an `RwLockReadGuard` along with its associated `RwLock`.
/// However, the API is completely generic and there are no restrictions on
/// what types of owning and dependent objects may be used.
///
/// `OwningHandle` is created by passing an owner object (which dereferences
/// to a stable address) along with a callback which receives a pointer to
/// that stable location. The callback may then dereference the pointer and
/// mint a dependent object, with the guarantee that the returned object will
/// not outlive the referent of the pointer.
///
/// This does foist some unsafety onto the callback, which needs an `unsafe`
/// block to dereference the pointer. It would be almost good enough for
/// OwningHandle to pass a transmuted &'static reference to the callback
/// since the lifetime is infinite as far as the minted handle is concerned.
/// However, even an `Fn` callback can still allow the reference to escape
/// via a `StaticMutex` or similar, which technically violates the safety
/// contract. Some sort of language support in the lifetime system could
/// make this API a bit nicer.
pub struct OwningHandle<O, H>
where O: StableAddress,
H: Deref,
{
handle: H,
_owner: O,
}
impl<O, H> Deref for OwningHandle<O, H>
where O: StableAddress,
H: Deref,
{
type Target = H::Target;
fn deref(&self) -> &H::Target {
self.handle.deref()
}
}
unsafe impl<O, H> StableAddress for OwningHandle<O, H>
where O: StableAddress,
H: StableAddress,
{}
impl<O, H> DerefMut for OwningHandle<O, H>
where O: StableAddress,
H: DerefMut,
{
fn deref_mut(&mut self) -> &mut H::Target {
self.handle.deref_mut()
}
}
impl<O, H> OwningHandle<O, H>
where O: StableAddress,
H: Deref,
{
/// Create a new OwningHandle. The provided callback will be invoked with
/// a pointer to the object owned by `o`, and the returned value is stored
/// as the object to which this `OwningHandle` will forward `Deref` and
/// `DerefMut`.
pub fn new<F>(o: O, f: F) -> Self
where F: Fn(*const O::Target) -> H,
{
let h: H;
{
h = f(o.deref() as *const O::Target);
}
OwningHandle {
handle: h,
_owner: o,
}
}
}

View File

@ -31,6 +31,7 @@ use parser::{Parse, ParserContext, ParserContextExtraData};
use properties::animated_properties::TransitionProperty;
#[cfg(feature = "servo")] use servo_config::prefs::PREFS;
use servo_url::ServoUrl;
use shared_lock::StylesheetGuards;
use style_traits::ToCss;
use stylesheets::Origin;
#[cfg(feature = "servo")] use values::Either;
@ -1860,6 +1861,7 @@ bitflags! {
///
pub fn cascade(device: &Device,
rule_node: &StrongRuleNode,
guards: &StylesheetGuards,
parent_style: Option<<&ComputedValues>,
layout_parent_style: Option<<&ComputedValues>,
cascade_info: Option<<&mut CascadeInfo>,
@ -1882,11 +1884,12 @@ pub fn cascade(device: &Device,
// Hold locks until after the apply_declarations() call returns.
// Use filter_map because the root node has no style source.
let lock_guards = rule_node.self_and_ancestors().filter_map(|node| {
node.style_source().map(|source| (source.read(), node.importance()))
let declaration_blocks = rule_node.self_and_ancestors().filter_map(|node| {
let guard = node.cascade_level().guard(guards);
node.style_source().map(|source| (source.read(guard), node.importance()))
}).collect::<Vec<_>>();
let iter_declarations = || {
lock_guards.iter().flat_map(|&(ref source, source_importance)| {
declaration_blocks.iter().flat_map(|&(ref source, source_importance)| {
source.declarations().iter()
// Yield declarations later in source order (with more precedence) first.
.rev()

View File

@ -10,9 +10,8 @@
use arc_ptr_eq;
#[cfg(feature = "servo")]
use heapsize::HeapSizeOf;
use owning_handle::OwningHandle;
use parking_lot::{RwLock, RwLockReadGuard};
use properties::{Importance, PropertyDeclarationBlock};
use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
use std::io::{self, Write};
use std::ptr;
use std::sync::Arc;
@ -52,33 +51,9 @@ pub struct RuleTree {
#[derive(Debug, Clone)]
pub enum StyleSource {
/// A style rule stable pointer.
Style(Arc<RwLock<StyleRule>>),
Style(Arc<Locked<StyleRule>>),
/// A declaration block stable pointer.
Declarations(Arc<RwLock<PropertyDeclarationBlock>>),
}
type StyleSourceGuardHandle<'a> =
OwningHandle<
RwLockReadGuard<'a, StyleRule>,
RwLockReadGuard<'a, PropertyDeclarationBlock>>;
/// A guard for a given style source.
pub enum StyleSourceGuard<'a> {
/// A guard for a style rule.
Style(StyleSourceGuardHandle<'a>),
/// A guard for a declaration block.
Declarations(RwLockReadGuard<'a, PropertyDeclarationBlock>),
}
impl<'a> ::std::ops::Deref for StyleSourceGuard<'a> {
type Target = PropertyDeclarationBlock;
fn deref(&self) -> &Self::Target {
match *self {
StyleSourceGuard::Declarations(ref block) => &*block,
StyleSourceGuard::Style(ref handle) => &*handle,
}
}
Declarations(Arc<Locked<PropertyDeclarationBlock>>),
}
impl StyleSource {
@ -92,28 +67,26 @@ impl StyleSource {
}
}
fn dump<W: Write>(&self, writer: &mut W) {
fn dump<W: Write>(&self, guard: &SharedRwLockReadGuard, writer: &mut W) {
use self::StyleSource::*;
if let Style(ref rule) = *self {
let _ = write!(writer, "{:?}", rule.read().selectors);
let rule = rule.read_with(guard);
let _ = write!(writer, "{:?}", rule.selectors);
}
let _ = write!(writer, " -> {:?}", self.read().declarations());
let _ = write!(writer, " -> {:?}", self.read(guard).declarations());
}
/// Read the style source guard, and obtain thus read access to the
/// underlying property declaration block.
#[inline]
pub fn read<'a>(&'a self) -> StyleSourceGuard<'a> {
use self::StyleSource::*;
match *self {
Style(ref rule) => {
let owning_ref = OwningHandle::new(rule.read(), |r| unsafe { &*r }.block.read());
StyleSourceGuard::Style(owning_ref)
}
Declarations(ref block) => StyleSourceGuard::Declarations(block.read()),
}
pub fn read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a PropertyDeclarationBlock {
let block = match *self {
StyleSource::Style(ref rule) => &rule.read_with(guard).block,
StyleSource::Declarations(ref block) => block,
};
block.read_with(guard)
}
}
@ -137,15 +110,15 @@ impl RuleTree {
self.root.clone()
}
fn dump<W: Write>(&self, writer: &mut W) {
fn dump<W: Write>(&self, guards: &StylesheetGuards, writer: &mut W) {
let _ = writeln!(writer, " + RuleTree");
self.root.get().dump(writer, 0);
self.root.get().dump(guards, writer, 0);
}
/// Dump the rule tree to stdout.
pub fn dump_stdout(&self) {
pub fn dump_stdout(&self, guards: &StylesheetGuards) {
let mut stdout = io::stdout();
self.dump(&mut stdout);
self.dump(guards, &mut stdout);
}
/// Insert the given rules, that must be in proper order by specifity, and
@ -187,8 +160,9 @@ impl RuleTree {
/// the old path is still valid.
pub fn update_rule_at_level(&self,
level: CascadeLevel,
pdb: Option<&Arc<RwLock<PropertyDeclarationBlock>>>,
path: &StrongRuleNode)
pdb: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
path: &StrongRuleNode,
guards: &StylesheetGuards)
-> Option<StrongRuleNode> {
debug_assert!(level.is_unique_per_element());
// TODO(emilio): Being smarter with lifetimes we could avoid a bit of
@ -247,13 +221,13 @@ impl RuleTree {
// pretty bad styling cases already.
if let Some(pdb) = pdb {
if level.is_important() {
if pdb.read().any_important() {
if pdb.read_with(level.guard(guards)).any_important() {
current = current.ensure_child(self.root.downgrade(),
StyleSource::Declarations(pdb.clone()),
level);
}
} else {
if pdb.read().any_normal() {
if pdb.read_with(level.guard(guards)).any_normal() {
current = current.ensure_child(self.root.downgrade(),
StyleSource::Declarations(pdb.clone()),
level);
@ -307,6 +281,17 @@ pub enum CascadeLevel {
}
impl CascadeLevel {
/// Select a lock guard for this level
pub fn guard<'a>(&self, guards: &'a StylesheetGuards<'a>) -> &'a SharedRwLockReadGuard<'a> {
match *self {
CascadeLevel::UANormal |
CascadeLevel::UserNormal |
CascadeLevel::UserImportant |
CascadeLevel::UAImportant => guards.ua_or_user,
_ => guards.author,
}
}
/// Returns whether this cascade level is unique per element, in which case
/// we can replace the path in the cascade without fear.
pub fn is_unique_per_element(&self) -> bool {
@ -450,7 +435,7 @@ impl RuleNode {
}
}
fn dump<W: Write>(&self, writer: &mut W, indent: usize) {
fn dump<W: Write>(&self, guards: &StylesheetGuards, writer: &mut W, indent: usize) {
const INDENT_INCREMENT: usize = 4;
for _ in 0..indent {
@ -467,7 +452,7 @@ impl RuleNode {
match self.source {
Some(ref source) => {
source.dump(writer);
source.dump(self.level.guard(guards), writer);
}
None => {
if indent != 0 {
@ -479,7 +464,7 @@ impl RuleNode {
let _ = write!(writer, "\n");
for child in self.iter_children() {
child.get().dump(writer, indent + INDENT_INCREMENT);
child.get().dump(guards, writer, indent + INDENT_INCREMENT);
}
}
@ -627,6 +612,11 @@ impl StrongRuleNode {
self.get().source.as_ref()
}
/// The cascade level for this node
pub fn cascade_level(&self) -> CascadeLevel {
self.get().level
}
/// Get the importance that this rule node represents.
pub fn importance(&self) -> Importance {
self.get().level.importance()

View File

@ -9,3 +9,13 @@
pub mod media_queries;
pub mod restyle_damage;
pub mod selector_parser;
use shared_lock::SharedRwLock;
lazy_static! {
/// Per-process shared lock for author-origin stylesheets
///
/// FIXME: make it per-document or per-pipeline instead:
/// https://github.com/servo/servo/issues/16027
pub static ref AUTHOR_SHARED_LOCK: SharedRwLock = SharedRwLock::new();
}

View File

@ -0,0 +1,199 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Different objects protected by the same lock
use parking_lot::RwLock;
use std::cell::UnsafeCell;
use std::fmt;
use std::sync::Arc;
/// A shared read/write lock that can protect multiple objects.
#[derive(Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SharedRwLock {
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
arc: Arc<RwLock<()>>,
}
impl fmt::Debug for SharedRwLock {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("SharedRwLock")
}
}
impl SharedRwLock {
/// Create a new shared lock
pub fn new() -> Self {
SharedRwLock {
arc: Arc::new(RwLock::new(()))
}
}
/// Wrap the given data to make its access protected by this lock.
pub fn wrap<T>(&self, data: T) -> Locked<T> {
Locked {
shared_lock: self.clone(),
data: UnsafeCell::new(data),
}
}
/// Obtain the lock for reading
pub fn read(&self) -> SharedRwLockReadGuard {
self.arc.raw_read();
SharedRwLockReadGuard {
shared_lock: self
}
}
/// Obtain the lock for writing
pub fn write(&self) -> SharedRwLockWriteGuard {
self.arc.raw_write();
SharedRwLockWriteGuard {
shared_lock: self
}
}
}
/// Data protect by a shared lock.
pub struct Locked<T> {
shared_lock: SharedRwLock,
data: UnsafeCell<T>,
}
// Unsafe: the data inside `UnsafeCell` is only accessed in `read_with` and `write_with`,
// where guards ensure synchronization.
unsafe impl<T: Send> Send for Locked<T> {}
unsafe impl<T: Send + Sync> Sync for Locked<T> {}
impl<T: fmt::Debug> fmt::Debug for Locked<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let guard = self.shared_lock.read();
self.read_with(&guard).fmt(f)
}
}
impl<T> Locked<T> {
fn same_lock_as(&self, lock: &SharedRwLock) -> bool {
::arc_ptr_eq(&self.shared_lock.arc, &lock.arc)
}
/// Access the data for reading.
pub fn read_with<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
assert!(self.same_lock_as(&guard.shared_lock),
"Locked::read_with called with a guard from an unrelated SharedRwLock");
let ptr = self.data.get();
// Unsafe:
//
// * The guard guarantees that the lock is taken for reading,
// and weve checked that its the correct lock.
// * The returned reference borrows *both* the data and the guard,
// so that it can outlive neither.
unsafe {
&*ptr
}
}
/// Access the data for writing.
pub fn write_with<'a>(&'a self, guard: &'a mut SharedRwLockWriteGuard) -> &'a mut T {
assert!(self.same_lock_as(&guard.shared_lock),
"Locked::write_with called with a guard from an unrelated SharedRwLock");
let ptr = self.data.get();
// Unsafe:
//
// * The guard guarantees that the lock is taken for writing,
// and weve checked that its the correct lock.
// * The returned reference borrows *both* the data and the guard,
// so that it can outlive neither.
// * We require a mutable borrow of the guard,
// so that one write guard can only be used once at a time.
unsafe {
&mut *ptr
}
}
}
/// Proof that a shared lock was obtained for reading.
pub struct SharedRwLockReadGuard<'a> {
shared_lock: &'a SharedRwLock,
}
/// Proof that a shared lock was obtained for writing.
pub struct SharedRwLockWriteGuard<'a> {
shared_lock: &'a SharedRwLock,
}
impl<'a> Drop for SharedRwLockReadGuard<'a> {
fn drop(&mut self) {
// Unsafe: self.lock is private to this module, only ever set after `raw_read()`,
// and never copied or cloned (see `compile_time_assert` below).
unsafe {
self.shared_lock.arc.raw_unlock_read()
}
}
}
impl<'a> Drop for SharedRwLockWriteGuard<'a> {
fn drop(&mut self) {
// Unsafe: self.lock is private to this module, only ever set after `raw_write()`,
// and never copied or cloned (see `compile_time_assert` below).
unsafe {
self.shared_lock.arc.raw_unlock_write()
}
}
}
#[allow(dead_code)]
mod compile_time_assert {
use super::{SharedRwLockReadGuard, SharedRwLockWriteGuard};
trait Marker1 {}
impl<T: Clone> Marker1 for T {}
impl<'a> Marker1 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Clone
impl<'a> Marker1 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Clone
trait Marker2 {}
impl<T: Copy> Marker2 for T {}
impl<'a> Marker2 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Copy
impl<'a> Marker2 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Copy
}
/// Like ToCss, but with a lock guard given by the caller.
pub trait ToCssWithGuard {
/// Serialize `self` in CSS syntax, writing to `dest`, using the given lock guard.
fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write;
/// Serialize `self` in CSS syntax using the given lock guard and return a string.
///
/// (This is a convenience wrapper for `to_css` and probably should not be overridden.)
#[inline]
fn to_css_string(&self, guard: &SharedRwLockReadGuard) -> String {
let mut s = String::new();
self.to_css(guard, &mut s).unwrap();
s
}
}
/// Guards for a document
#[derive(Clone)]
pub struct StylesheetGuards<'a> {
/// For author-origin stylesheets
pub author: &'a SharedRwLockReadGuard<'a>,
/// For user-agent-origin and user-origin stylesheets
pub ua_or_user: &'a SharedRwLockReadGuard<'a>,
}
impl<'a> StylesheetGuards<'a> {
/// Same guard for all origins
pub fn same(guard: &'a SharedRwLockReadGuard<'a>) -> Self {
StylesheetGuards {
author: guard,
ua_or_user: guard,
}
}
}

View File

@ -21,6 +21,7 @@ use selector_parser::{SelectorImpl, SelectorParser};
use selectors::parser::SelectorList;
use servo_config::prefs::PREFS;
use servo_url::ServoUrl;
use shared_lock::{SharedRwLock, Locked, ToCssWithGuard, SharedRwLockReadGuard};
use std::cell::Cell;
use std::fmt;
use std::sync::Arc;
@ -86,8 +87,8 @@ impl From<SingleRuleParseError> for RulesMutateError {
impl CssRules {
#[allow(missing_docs)]
pub fn new(rules: Vec<CssRule>) -> Arc<RwLock<CssRules>> {
Arc::new(RwLock::new(CssRules(rules)))
pub fn new(rules: Vec<CssRule>, shared_lock: &SharedRwLock) -> Arc<Locked<CssRules>> {
Arc::new(shared_lock.wrap(CssRules(rules)))
}
fn only_ns_or_import(&self) -> bool {
@ -173,13 +174,15 @@ impl CssRules {
pub struct Stylesheet {
/// List of rules in the order they were found (important for
/// cascading order)
pub rules: Arc<RwLock<CssRules>>,
pub rules: Arc<Locked<CssRules>>,
/// List of media associated with the Stylesheet.
pub media: Arc<RwLock<MediaList>>,
pub media: Arc<Locked<MediaList>>,
/// The origin of this stylesheet.
pub origin: Origin,
/// The base url this stylesheet should use.
pub base_url: ServoUrl,
/// The lock used for objects inside this stylesheet
pub shared_lock: SharedRwLock,
/// The namespaces that apply to this stylesheet.
pub namespaces: RwLock<Namespaces>,
/// Whether this stylesheet would be dirty when the viewport size changes.
@ -191,6 +194,8 @@ pub struct Stylesheet {
/// This structure holds the user-agent and user stylesheets.
pub struct UserAgentStylesheets {
/// The lock used for user-agent stylesheets.
pub shared_lock: SharedRwLock,
/// The user or user agent stylesheets.
pub user_or_user_agent_stylesheets: Vec<Stylesheet>,
/// The quirks mode stylesheet.
@ -207,14 +212,14 @@ pub enum CssRule {
// No Charset here, CSSCharsetRule has been removed from CSSOM
// https://drafts.csswg.org/cssom/#changes-from-5-december-2013
Namespace(Arc<RwLock<NamespaceRule>>),
Import(Arc<RwLock<ImportRule>>),
Style(Arc<RwLock<StyleRule>>),
Media(Arc<RwLock<MediaRule>>),
FontFace(Arc<RwLock<FontFaceRule>>),
Viewport(Arc<RwLock<ViewportRule>>),
Keyframes(Arc<RwLock<KeyframesRule>>),
Supports(Arc<RwLock<SupportsRule>>),
Namespace(Arc<Locked<NamespaceRule>>),
Import(Arc<Locked<ImportRule>>),
Style(Arc<Locked<StyleRule>>),
Media(Arc<Locked<MediaRule>>),
FontFace(Arc<Locked<FontFaceRule>>),
Viewport(Arc<Locked<ViewportRule>>),
Keyframes(Arc<Locked<KeyframesRule>>),
Supports(Arc<Locked<SupportsRule>>),
}
#[allow(missing_docs)]
@ -291,13 +296,13 @@ impl CssRule {
/// used for others.
///
/// This will not recurse down unsupported @supports rules
pub fn with_nested_rules_and_mq<F, R>(&self, mut f: F) -> R
pub fn with_nested_rules_and_mq<F, R>(&self, guard: &SharedRwLockReadGuard, mut f: F) -> R
where F: FnMut(&[CssRule], Option<&MediaList>) -> R {
match *self {
CssRule::Import(ref lock) => {
let rule = lock.read();
let media = rule.stylesheet.media.read();
let rules = rule.stylesheet.rules.read();
let rule = lock.read_with(guard);
let media = rule.stylesheet.media.read_with(guard);
let rules = rule.stylesheet.rules.read_with(guard);
// FIXME(emilio): Include the nested rules if the stylesheet is
// loaded.
f(&rules.0, Some(&media))
@ -310,16 +315,16 @@ impl CssRule {
f(&[], None)
}
CssRule::Media(ref lock) => {
let media_rule = lock.read();
let mq = media_rule.media_queries.read();
let rules = &media_rule.rules.read().0;
let media_rule = lock.read_with(guard);
let mq = media_rule.media_queries.read_with(guard);
let rules = &media_rule.rules.read_with(guard).0;
f(rules, Some(&mq))
}
CssRule::Supports(ref lock) => {
let supports_rule = lock.read();
let supports_rule = lock.read_with(guard);
let enabled = supports_rule.enabled;
if enabled {
let rules = &supports_rule.rules.read().0;
let rules = &supports_rule.rules.read_with(guard).0;
f(rules, None)
} else {
f(&[], None)
@ -349,6 +354,7 @@ impl CssRule {
let mut rule_parser = TopLevelRuleParser {
stylesheet_origin: parent_stylesheet.origin,
context: context,
shared_lock: &parent_stylesheet.shared_lock,
loader: None,
state: Cell::new(state),
namespaces: &mut namespaces,
@ -366,18 +372,19 @@ impl CssRule {
}
}
impl ToCss for CssRule {
impl ToCssWithGuard for CssRule {
// https://drafts.csswg.org/cssom/#serialize-a-css-rule
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
match *self {
CssRule::Namespace(ref lock) => lock.read().to_css(dest),
CssRule::Import(ref lock) => lock.read().to_css(dest),
CssRule::Style(ref lock) => lock.read().to_css(dest),
CssRule::FontFace(ref lock) => lock.read().to_css(dest),
CssRule::Viewport(ref lock) => lock.read().to_css(dest),
CssRule::Keyframes(ref lock) => lock.read().to_css(dest),
CssRule::Media(ref lock) => lock.read().to_css(dest),
CssRule::Supports(ref lock) => lock.read().to_css(dest),
CssRule::Namespace(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Import(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Style(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::FontFace(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Viewport(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Media(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Supports(ref lock) => lock.read_with(guard).to_css(guard, dest),
}
}
}
@ -390,9 +397,10 @@ pub struct NamespaceRule {
pub url: Namespace,
}
impl ToCss for NamespaceRule {
impl ToCssWithGuard for NamespaceRule {
// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSNamespaceRule
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
try!(dest.write_str("@namespace "));
if let Some(ref prefix) = self.prefix {
try!(dest.write_str(&*prefix.to_string()));
@ -420,11 +428,12 @@ pub struct ImportRule {
pub stylesheet: Arc<Stylesheet>,
}
impl ToCss for ImportRule {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
impl ToCssWithGuard for ImportRule {
fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
try!(dest.write_str("@import "));
try!(self.url.to_css(dest));
let media = self.stylesheet.media.read();
let media = self.stylesheet.media.read_with(guard);
if !media.is_empty() {
try!(dest.write_str(" "));
try!(media.to_css(dest));
@ -441,12 +450,13 @@ pub struct KeyframesRule {
/// The name of the current animation.
pub name: Atom,
/// The keyframes specified for this CSS rule.
pub keyframes: Vec<Arc<RwLock<Keyframe>>>,
pub keyframes: Vec<Arc<Locked<Keyframe>>>,
}
impl ToCss for KeyframesRule {
impl ToCssWithGuard for KeyframesRule {
// Serialization of KeyframesRule is not specced.
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
try!(dest.write_str("@keyframes "));
try!(dest.write_str(&*self.name.to_string()));
try!(dest.write_str(" { "));
@ -457,8 +467,8 @@ impl ToCss for KeyframesRule {
try!(dest.write_str(" "));
}
first = false;
let keyframe = lock.read();
try!(keyframe.to_css(dest));
let keyframe = lock.read_with(&guard);
try!(keyframe.to_css(guard, dest));
}
dest.write_str(" }")
}
@ -467,20 +477,21 @@ impl ToCss for KeyframesRule {
#[allow(missing_docs)]
#[derive(Debug)]
pub struct MediaRule {
pub media_queries: Arc<RwLock<MediaList>>,
pub rules: Arc<RwLock<CssRules>>,
pub media_queries: Arc<Locked<MediaList>>,
pub rules: Arc<Locked<CssRules>>,
}
impl ToCss for MediaRule {
impl ToCssWithGuard for MediaRule {
// Serialization of MediaRule is not specced.
// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSMediaRule
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
try!(dest.write_str("@media "));
try!(self.media_queries.read().to_css(dest));
try!(self.media_queries.read_with(guard).to_css(dest));
try!(dest.write_str(" {"));
for rule in self.rules.read().0.iter() {
for rule in self.rules.read_with(guard).0.iter() {
try!(dest.write_str(" "));
try!(rule.to_css(dest));
try!(rule.to_css(guard, dest));
}
dest.write_str(" }")
}
@ -493,19 +504,20 @@ pub struct SupportsRule {
/// The parsed condition
pub condition: SupportsCondition,
/// Child rules
pub rules: Arc<RwLock<CssRules>>,
pub rules: Arc<Locked<CssRules>>,
/// The result of evaluating the condition
pub enabled: bool,
}
impl ToCss for SupportsRule {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
impl ToCssWithGuard for SupportsRule {
fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
try!(dest.write_str("@supports "));
try!(self.condition.to_css(dest));
try!(dest.write_str(" {"));
for rule in self.rules.read().0.iter() {
for rule in self.rules.read_with(guard).0.iter() {
try!(dest.write_str(" "));
try!(rule.to_css(dest));
try!(rule.to_css(guard, dest));
}
dest.write_str(" }")
}
@ -515,18 +527,19 @@ impl ToCss for SupportsRule {
#[derive(Debug)]
pub struct StyleRule {
pub selectors: SelectorList<SelectorImpl>,
pub block: Arc<RwLock<PropertyDeclarationBlock>>,
pub block: Arc<Locked<PropertyDeclarationBlock>>,
}
impl ToCss for StyleRule {
impl ToCssWithGuard for StyleRule {
// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
// Step 1
try!(self.selectors.to_css(dest));
// Step 2
try!(dest.write_str(" { "));
// Step 3
let declaration_block = self.block.read();
let declaration_block = self.block.read_with(guard);
try!(declaration_block.to_css(dest));
// Step 4
if declaration_block.declarations().len() > 0 {
@ -545,18 +558,39 @@ impl Stylesheet {
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData) {
let mut rules = existing.rules.write();
let mut namespaces = existing.namespaces.write();
let mut namespaces = Namespaces::default();
let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules(
css, &existing.base_url, existing.origin, &mut namespaces, &existing.shared_lock,
stylesheet_loader, error_reporter, extra_data,
);
assert!(rules.is_empty());
*existing.namespaces.write() = namespaces;
existing.dirty_on_viewport_size_change
.store(dirty_on_viewport_size_change, Ordering::Release);
// Acquire the lock *after* parsing, to minimize the exclusive section.
let mut guard = existing.shared_lock.write();
*existing.rules.write_with(&mut guard) = CssRules(rules);
}
fn parse_rules(css: &str,
base_url: &ServoUrl,
origin: Origin,
namespaces: &mut Namespaces,
shared_lock: &SharedRwLock,
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData)
-> (Vec<CssRule>, bool) {
let mut rules = Vec::new();
let mut input = Parser::new(css);
let rule_parser = TopLevelRuleParser {
stylesheet_origin: existing.origin,
namespaces: &mut namespaces,
stylesheet_origin: origin,
namespaces: namespaces,
shared_lock: shared_lock,
loader: stylesheet_loader,
context: ParserContext::new_with_extra_data(existing.origin,
&existing.base_url,
context: ParserContext::new_with_extra_data(origin,
base_url,
error_reporter,
extra_data),
state: Cell::new(State::Start),
@ -568,7 +602,7 @@ impl Stylesheet {
let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser);
while let Some(result) = iter.next() {
match result {
Ok(rule) => rules.0.push(rule),
Ok(rule) => rules.push(rule),
Err(range) => {
let pos = range.start;
let message = format!("Invalid rule: '{}'", iter.input.slice(range));
@ -578,8 +612,7 @@ impl Stylesheet {
}
}
existing.dirty_on_viewport_size_change
.store(input.seen_viewport_percentages(), Ordering::Release);
(rules, input.seen_viewport_percentages())
}
/// Creates an empty stylesheet and parses it with a given base url, origin
@ -591,26 +624,25 @@ impl Stylesheet {
base_url: ServoUrl,
origin: Origin,
media: MediaList,
shared_lock: SharedRwLock,
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData) -> Stylesheet {
let s = Stylesheet {
let mut namespaces = Namespaces::default();
let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules(
css, &base_url, origin, &mut namespaces, &shared_lock,
stylesheet_loader, error_reporter, extra_data,
);
Stylesheet {
origin: origin,
base_url: base_url,
namespaces: RwLock::new(Namespaces::default()),
rules: CssRules::new(vec![]),
media: Arc::new(RwLock::new(media)),
dirty_on_viewport_size_change: AtomicBool::new(false),
namespaces: RwLock::new(namespaces),
rules: CssRules::new(rules, &shared_lock),
media: Arc::new(shared_lock.wrap(media)),
shared_lock: shared_lock,
dirty_on_viewport_size_change: AtomicBool::new(dirty_on_viewport_size_change),
disabled: AtomicBool::new(false),
};
Self::update_from_str(&s,
css,
stylesheet_loader,
error_reporter,
extra_data);
s
}
}
/// Whether this stylesheet can be dirty on viewport size change.
@ -637,8 +669,8 @@ impl Stylesheet {
/// on the associated MediaList.
///
/// Always true if no associated MediaList exists.
pub fn is_effective_for_device(&self, device: &Device) -> bool {
self.media.read().evaluate(device)
pub fn is_effective_for_device(&self, device: &Device, guard: &SharedRwLockReadGuard) -> bool {
self.media.read_with(guard).evaluate(device)
}
/// Return an iterator over the effective rules within the style-sheet, as
@ -648,8 +680,9 @@ impl Stylesheet {
/// nested rules will be skipped. Use `rules` if all rules need to be
/// examined.
#[inline]
pub fn effective_rules<F>(&self, device: &Device, mut f: F) where F: FnMut(&CssRule) {
effective_rules(&self.rules.read().0, device, &mut f);
pub fn effective_rules<F>(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F)
where F: FnMut(&CssRule) {
effective_rules(&self.rules.read_with(guard).0, device, guard, &mut f);
}
/// Returns whether the stylesheet has been explicitly disabled through the
@ -670,16 +703,17 @@ impl Stylesheet {
}
}
fn effective_rules<F>(rules: &[CssRule], device: &Device, f: &mut F) where F: FnMut(&CssRule) {
fn effective_rules<F>(rules: &[CssRule], device: &Device, guard: &SharedRwLockReadGuard, f: &mut F)
where F: FnMut(&CssRule) {
for rule in rules {
f(rule);
rule.with_nested_rules_and_mq(|rules, mq| {
rule.with_nested_rules_and_mq(guard, |rules, mq| {
if let Some(media_queries) = mq {
if !media_queries.evaluate(device) {
return
}
}
effective_rules(rules, device, f)
effective_rules(rules, device, guard, f)
})
}
}
@ -689,10 +723,11 @@ macro_rules! rule_filter {
impl Stylesheet {
$(
#[allow(missing_docs)]
pub fn $method<F>(&self, device: &Device, mut f: F) where F: FnMut(&$rule_type) {
self.effective_rules(device, |rule| {
pub fn $method<F>(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F)
where F: FnMut(&$rule_type) {
self.effective_rules(device, guard, |rule| {
if let CssRule::$variant(ref lock) = *rule {
let rule = lock.read();
let rule = lock.read_with(guard);
f(&rule)
}
})
@ -718,12 +753,35 @@ pub trait StylesheetLoader {
///
/// The called code is responsible to update the `stylesheet` rules field
/// when the sheet is done loading.
fn request_stylesheet(&self, import: &Arc<RwLock<ImportRule>>);
///
/// The convoluted signature allows impls to look at MediaList and ImportRule
/// before theyre locked, while keeping the trait object-safe.
fn request_stylesheet(
&self,
media: MediaList,
make_import: &mut FnMut(MediaList) -> ImportRule,
make_arc: &mut FnMut(ImportRule) -> Arc<Locked<ImportRule>>,
) -> Arc<Locked<ImportRule>>;
}
struct NoOpLoader;
impl StylesheetLoader for NoOpLoader {
fn request_stylesheet(
&self,
media: MediaList,
make_import: &mut FnMut(MediaList) -> ImportRule,
make_arc: &mut FnMut(ImportRule) -> Arc<Locked<ImportRule>>,
) -> Arc<Locked<ImportRule>> {
make_arc(make_import(media))
}
}
struct TopLevelRuleParser<'a> {
stylesheet_origin: Origin,
namespaces: &'a mut Namespaces,
shared_lock: &'a SharedRwLock,
loader: Option<&'a StylesheetLoader>,
context: ParserContext<'a>,
state: Cell<State>,
@ -733,6 +791,7 @@ impl<'b> TopLevelRuleParser<'b> {
fn nested<'a: 'b>(&'a self) -> NestedRuleParser<'a, 'b> {
NestedRuleParser {
stylesheet_origin: self.stylesheet_origin,
shared_lock: self.shared_lock,
context: &self.context,
namespaces: self.namespaces,
}
@ -754,7 +813,7 @@ enum AtRulePrelude {
/// A @font-face rule prelude.
FontFace,
/// A @media rule prelude, with its media queries.
Media(Arc<RwLock<MediaList>>),
Media(Arc<Locked<MediaList>>),
/// An @supports rule, with its conditional
Supports(SupportsCondition),
/// A @viewport rule prelude.
@ -774,22 +833,27 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
"import" => {
if self.state.get() <= State::Imports {
self.state.set(State::Imports);
let url = try!(input.expect_url_or_string());
let url =
try!(SpecifiedUrl::parse_from_string(url,
&self.context));
let url_string = input.expect_url_or_string()?;
let specified_url = SpecifiedUrl::parse_from_string(url_string, &self.context)?;
let media =
Arc::new(RwLock::new(parse_media_query_list(input)));
let media = parse_media_query_list(input);
let is_valid_url = url.url().is_some();
let noop_loader = NoOpLoader;
let is_valid_url = specified_url.url().is_some();
let loader = if is_valid_url {
self.loader.expect("Expected a stylesheet loader for @import")
} else {
&noop_loader
};
let import_rule = Arc::new(RwLock::new(
let mut specified_url = Some(specified_url);
let arc = loader.request_stylesheet(media, &mut |media| {
ImportRule {
url: url,
url: specified_url.take().unwrap(),
stylesheet: Arc::new(Stylesheet {
rules: Arc::new(RwLock::new(CssRules(vec![]))),
media: media,
rules: CssRules::new(Vec::new(), self.shared_lock),
media: Arc::new(self.shared_lock.wrap(media)),
shared_lock: self.shared_lock.clone(),
origin: self.context.stylesheet_origin,
base_url: self.context.base_url.clone(),
namespaces: RwLock::new(Namespaces::default()),
@ -797,15 +861,10 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
disabled: AtomicBool::new(false),
})
}
));
if is_valid_url {
let loader = self.loader
.expect("Expected a stylesheet loader for @import");
loader.request_stylesheet(&import_rule);
}
return Ok(AtRuleType::WithoutBlock(CssRule::Import(import_rule)))
}, &mut |import_rule| {
Arc::new(self.shared_lock.wrap(import_rule))
});
return Ok(AtRuleType::WithoutBlock(CssRule::Import(arc)))
} else {
self.state.set(State::Invalid);
return Err(()) // "@import must be before any rule but @charset"
@ -827,12 +886,12 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
None
};
return Ok(AtRuleType::WithoutBlock(CssRule::Namespace(Arc::new(RwLock::new(
NamespaceRule {
return Ok(AtRuleType::WithoutBlock(CssRule::Namespace(Arc::new(
self.shared_lock.wrap(NamespaceRule {
prefix: opt_prefix,
url: url,
}
)))))
})
))))
} else {
self.state.set(State::Invalid);
return Err(()) // "@namespace must be before any rule but @charset and @import"
@ -879,12 +938,13 @@ impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> {
#[derive(Clone)] // shallow, relatively cheap .clone
struct NestedRuleParser<'a, 'b: 'a> {
stylesheet_origin: Origin,
shared_lock: &'a SharedRwLock,
context: &'a ParserContext<'b>,
namespaces: &'b Namespaces,
}
impl<'a, 'b> NestedRuleParser<'a, 'b> {
fn parse_nested_rules(&self, input: &mut Parser) -> Arc<RwLock<CssRules>> {
fn parse_nested_rules(&self, input: &mut Parser) -> Arc<Locked<CssRules>> {
let mut iter = RuleListParser::new_for_nested_rule(input, self.clone());
let mut rules = Vec::new();
while let Some(result) = iter.next() {
@ -897,7 +957,7 @@ impl<'a, 'b> NestedRuleParser<'a, 'b> {
}
}
}
CssRules::new(rules)
CssRules::new(rules, self.shared_lock)
}
}
@ -910,7 +970,8 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
match_ignore_ascii_case! { name,
"media" => {
let media_queries = parse_media_query_list(input);
Ok(AtRuleType::WithBlock(AtRulePrelude::Media(Arc::new(RwLock::new(media_queries)))))
let arc = Arc::new(self.shared_lock.wrap(media_queries));
Ok(AtRuleType::WithBlock(AtRulePrelude::Media(arc)))
},
"supports" => {
let cond = SupportsCondition::parse(input)?;
@ -943,31 +1004,31 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
fn parse_block(&mut self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CssRule, ()> {
match prelude {
AtRulePrelude::FontFace => {
Ok(CssRule::FontFace(Arc::new(RwLock::new(
Ok(CssRule::FontFace(Arc::new(self.shared_lock.wrap(
try!(parse_font_face_block(self.context, input))))))
}
AtRulePrelude::Media(media_queries) => {
Ok(CssRule::Media(Arc::new(RwLock::new(MediaRule {
Ok(CssRule::Media(Arc::new(self.shared_lock.wrap(MediaRule {
media_queries: media_queries,
rules: self.parse_nested_rules(input),
}))))
}
AtRulePrelude::Supports(cond) => {
let enabled = cond.eval(self.context);
Ok(CssRule::Supports(Arc::new(RwLock::new(SupportsRule {
Ok(CssRule::Supports(Arc::new(self.shared_lock.wrap(SupportsRule {
condition: cond,
rules: self.parse_nested_rules(input),
enabled: enabled,
}))))
}
AtRulePrelude::Viewport => {
Ok(CssRule::Viewport(Arc::new(RwLock::new(
Ok(CssRule::Viewport(Arc::new(self.shared_lock.wrap(
try!(ViewportRule::parse(input, self.context))))))
}
AtRulePrelude::Keyframes(name) => {
Ok(CssRule::Keyframes(Arc::new(RwLock::new(KeyframesRule {
Ok(CssRule::Keyframes(Arc::new(self.shared_lock.wrap(KeyframesRule {
name: name,
keyframes: parse_keyframe_list(&self.context, input),
keyframes: parse_keyframe_list(&self.context, input, self.shared_lock),
}))))
}
}
@ -988,9 +1049,10 @@ impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
fn parse_block(&mut self, prelude: SelectorList<SelectorImpl>, input: &mut Parser)
-> Result<CssRule, ()> {
Ok(CssRule::Style(Arc::new(RwLock::new(StyleRule {
let declarations = parse_property_declaration_list(self.context, input);
Ok(CssRule::Style(Arc::new(self.shared_lock.wrap(StyleRule {
selectors: prelude,
block: Arc::new(RwLock::new(parse_property_declaration_list(self.context, input)))
block: Arc::new(self.shared_lock.wrap(declarations))
}))))
}
}

View File

@ -12,7 +12,6 @@ use dom::{AnimationRules, PresentationalHintsSynthetizer, TElement};
use error_reporting::StdoutErrorReporter;
use keyframes::KeyframesAnimation;
use media_queries::Device;
use parking_lot::RwLock;
use pdqsort::sort_by;
use properties::{self, CascadeFlags, ComputedValues};
#[cfg(feature = "servo")]
@ -28,6 +27,7 @@ use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONA
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector};
use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector};
use selectors::parser::SelectorMethods;
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use sink::Push;
use smallvec::VecLike;
use std::borrow::Borrow;
@ -158,6 +158,7 @@ impl Stylist {
/// device is dirty, which means we need to re-evaluate media queries.
pub fn update(&mut self,
doc_stylesheets: &[Arc<Stylesheet>],
guards: &StylesheetGuards,
ua_stylesheets: Option<&UserAgentStylesheets>,
stylesheets_changed: bool) -> bool {
if !(self.is_device_dirty || stylesheets_changed) {
@ -165,7 +166,9 @@ impl Stylist {
}
let cascaded_rule = ViewportRule {
declarations: viewport::Cascade::from_stylesheets(doc_stylesheets, &self.device).finish(),
declarations: viewport::Cascade::from_stylesheets(
doc_stylesheets, guards.author, &self.device
).finish(),
};
self.viewport_constraints =
@ -193,16 +196,16 @@ impl Stylist {
if let Some(ua_stylesheets) = ua_stylesheets {
for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets {
self.add_stylesheet(&stylesheet);
self.add_stylesheet(&stylesheet, guards.ua_or_user);
}
if self.quirks_mode {
self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet);
self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet, guards.ua_or_user);
}
}
for ref stylesheet in doc_stylesheets.iter() {
self.add_stylesheet(stylesheet);
self.add_stylesheet(stylesheet, guards.author);
}
debug!("Stylist stats:");
@ -216,8 +219,9 @@ impl Stylist {
SelectorImpl::each_precomputed_pseudo_element(|pseudo| {
if let Some(map) = self.pseudos_map.remove(&pseudo) {
let declarations =
map.user_agent.get_universal_rules(CascadeLevel::UANormal,
CascadeLevel::UAImportant);
map.user_agent.get_universal_rules(
guards.ua_or_user, CascadeLevel::UANormal, CascadeLevel::UAImportant
);
self.precomputed_pseudo_element_decls.insert(pseudo, declarations);
}
});
@ -226,19 +230,19 @@ impl Stylist {
true
}
fn add_stylesheet(&mut self, stylesheet: &Stylesheet) {
if stylesheet.disabled() || !stylesheet.is_effective_for_device(&self.device) {
fn add_stylesheet(&mut self, stylesheet: &Stylesheet, guard: &SharedRwLockReadGuard) {
if stylesheet.disabled() || !stylesheet.is_effective_for_device(&self.device, guard) {
return;
}
// Cheap `Arc` clone so that the closure below can borrow `&mut Stylist`.
let device = self.device.clone();
stylesheet.effective_rules(&device, |rule| {
stylesheet.effective_rules(&device, guard, |rule| {
match *rule {
CssRule::Style(ref style_rule) => {
let guard = style_rule.read();
for selector in &guard.selectors.0 {
CssRule::Style(ref locked) => {
let style_rule = locked.read_with(&guard);
for selector in &style_rule.selectors.0 {
let map = if let Some(ref pseudo) = selector.pseudo_element {
self.pseudos_map
.entry(pseudo.clone())
@ -250,14 +254,14 @@ impl Stylist {
map.insert(Rule {
selector: selector.complex_selector.clone(),
style_rule: style_rule.clone(),
style_rule: locked.clone(),
specificity: selector.specificity,
source_order: self.rules_source_order,
});
}
self.rules_source_order += 1;
for selector in &guard.selectors.0 {
for selector in &style_rule.selectors.0 {
self.state_deps.note_selector(&selector.complex_selector);
if selector.affects_siblings() {
self.sibling_affecting_selectors.push(selector.clone());
@ -269,13 +273,14 @@ impl Stylist {
}
}
CssRule::Import(ref import) => {
let import = import.read();
self.add_stylesheet(&import.stylesheet)
let import = import.read_with(guard);
self.add_stylesheet(&import.stylesheet, guard)
}
CssRule::Keyframes(ref keyframes_rule) => {
let keyframes_rule = keyframes_rule.read();
let keyframes_rule = keyframes_rule.read_with(guard);
debug!("Found valid keyframes rule: {:?}", *keyframes_rule);
let animation = KeyframesAnimation::from_keyframes(&keyframes_rule.keyframes);
let animation = KeyframesAnimation::from_keyframes(
&keyframes_rule.keyframes, guard);
debug!("Found valid keyframe animation: {:?}", animation);
self.animations.insert(keyframes_rule.name.clone(), animation);
}
@ -294,6 +299,7 @@ impl Stylist {
/// values. The flow constructor uses this flag when constructing anonymous
/// flows.
pub fn precomputed_values_for_pseudo(&self,
guards: &StylesheetGuards,
pseudo: &PseudoElement,
parent: Option<&Arc<ComputedValues>>,
cascade_flags: CascadeFlags)
@ -327,6 +333,7 @@ impl Stylist {
let computed =
properties::cascade(&self.device,
&rule_node,
guards,
parent.map(|p| &**p),
parent.map(|p| &**p),
None,
@ -338,6 +345,7 @@ impl Stylist {
/// Returns the style for an anonymous box of the given type.
#[cfg(feature = "servo")]
pub fn style_for_anonymous_box(&self,
guards: &StylesheetGuards,
pseudo: &PseudoElement,
parent_style: &Arc<ComputedValues>)
-> Arc<ComputedValues> {
@ -362,7 +370,7 @@ impl Stylist {
if inherit_all {
cascade_flags.insert(INHERIT_ALL);
}
self.precomputed_values_for_pseudo(&pseudo, Some(parent_style), cascade_flags)
self.precomputed_values_for_pseudo(guards, &pseudo, Some(parent_style), cascade_flags)
.values.unwrap()
}
@ -374,6 +382,7 @@ impl Stylist {
/// Check the documentation on lazy pseudo-elements in
/// docs/components/style.md
pub fn lazily_compute_pseudo_element_style<E>(&self,
guards: &StylesheetGuards,
element: &E,
pseudo: &PseudoElement,
parent: &Arc<ComputedValues>)
@ -395,6 +404,7 @@ impl Stylist {
None,
AnimationRules(None, None),
Some(pseudo),
guards,
&mut declarations,
&mut flags);
@ -409,6 +419,7 @@ impl Stylist {
let computed =
properties::cascade(&self.device,
&rule_node,
guards,
Some(&**parent),
Some(&**parent),
None,
@ -461,9 +472,10 @@ impl Stylist {
/// FIXME(emilio): The semantics of the device for Servo and Gecko are
/// different enough we may want to unify them.
#[cfg(feature = "servo")]
pub fn set_device(&mut self, mut device: Device, stylesheets: &[Arc<Stylesheet>]) {
pub fn set_device(&mut self, mut device: Device, guard: &SharedRwLockReadGuard,
stylesheets: &[Arc<Stylesheet>]) {
let cascaded_rule = ViewportRule {
declarations: viewport::Cascade::from_stylesheets(stylesheets, &device).finish(),
declarations: viewport::Cascade::from_stylesheets(stylesheets, guard, &device).finish(),
};
self.viewport_constraints =
@ -473,15 +485,16 @@ impl Stylist {
device.account_for_viewport_rule(constraints);
}
fn mq_eval_changed(rules: &[CssRule], before: &Device, after: &Device) -> bool {
fn mq_eval_changed(guard: &SharedRwLockReadGuard, rules: &[CssRule],
before: &Device, after: &Device) -> bool {
for rule in rules {
let changed = rule.with_nested_rules_and_mq(|rules, mq| {
let changed = rule.with_nested_rules_and_mq(guard, |rules, mq| {
if let Some(mq) = mq {
if mq.evaluate(before) != mq.evaluate(after) {
return true
}
}
mq_eval_changed(rules, before, after)
mq_eval_changed(guard, rules, before, after)
});
if changed {
return true
@ -490,12 +503,12 @@ impl Stylist {
false
}
self.is_device_dirty |= stylesheets.iter().any(|stylesheet| {
let mq = stylesheet.media.read();
let mq = stylesheet.media.read_with(guard);
if mq.evaluate(&self.device) != mq.evaluate(&device) {
return true
}
mq_eval_changed(&stylesheet.rules.read().0, &self.device, &device)
mq_eval_changed(guard, &stylesheet.rules.read_with(guard).0, &self.device, &device)
});
self.device = Arc::new(device);
@ -528,9 +541,10 @@ impl Stylist {
&self,
element: &E,
parent_bf: Option<&BloomFilter>,
style_attribute: Option<&Arc<RwLock<PropertyDeclarationBlock>>>,
style_attribute: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
animation_rules: AnimationRules,
pseudo_element: Option<&PseudoElement>,
guards: &StylesheetGuards,
applicable_declarations: &mut V,
flags: &mut ElementSelectorFlags) -> StyleRelations
where E: TElement +
@ -556,6 +570,7 @@ impl Stylist {
// Step 1: Normal user-agent rules.
map.user_agent.get_all_matching_rules(element,
parent_bf,
guards.ua_or_user,
applicable_declarations,
&mut relations,
flags,
@ -580,6 +595,7 @@ impl Stylist {
// Step 3: User and author normal rules.
map.user.get_all_matching_rules(element,
parent_bf,
guards.ua_or_user,
applicable_declarations,
&mut relations,
flags,
@ -587,6 +603,7 @@ impl Stylist {
debug!("user normal: {:?}", relations);
map.author.get_all_matching_rules(element,
parent_bf,
guards.author,
applicable_declarations,
&mut relations,
flags,
@ -595,7 +612,7 @@ impl Stylist {
// Step 4: Normal style attributes.
if let Some(sa) = style_attribute {
if sa.read().any_normal() {
if sa.read_with(guards.author).any_normal() {
relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
Push::push(
applicable_declarations,
@ -621,6 +638,7 @@ impl Stylist {
// Step 6: Author-supplied `!important` rules.
map.author.get_all_matching_rules(element,
parent_bf,
guards.author,
applicable_declarations,
&mut relations,
flags,
@ -630,7 +648,7 @@ impl Stylist {
// Step 7: `!important` style attributes.
if let Some(sa) = style_attribute {
if sa.read().any_important() {
if sa.read_with(guards.author).any_important() {
relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
Push::push(
applicable_declarations,
@ -644,6 +662,7 @@ impl Stylist {
// Step 8: User `!important` rules.
map.user.get_all_matching_rules(element,
parent_bf,
guards.ua_or_user,
applicable_declarations,
&mut relations,
flags,
@ -657,6 +676,7 @@ impl Stylist {
// Step 9: UA `!important` rules.
map.user_agent.get_all_matching_rules(element,
parent_bf,
guards.ua_or_user,
applicable_declarations,
&mut relations,
flags,
@ -895,6 +915,7 @@ impl SelectorMap {
pub fn get_all_matching_rules<E, V>(&self,
element: &E,
parent_bf: Option<&BloomFilter>,
guard: &SharedRwLockReadGuard,
matching_rules_list: &mut V,
relations: &mut StyleRelations,
flags: &mut ElementSelectorFlags,
@ -913,6 +934,7 @@ impl SelectorMap {
parent_bf,
&self.id_hash,
&id,
guard,
matching_rules_list,
relations,
flags,
@ -924,6 +946,7 @@ impl SelectorMap {
parent_bf,
&self.class_hash,
class,
guard,
matching_rules_list,
relations,
flags,
@ -939,6 +962,7 @@ impl SelectorMap {
parent_bf,
local_name_hash,
element.get_local_name(),
guard,
matching_rules_list,
relations,
flags,
@ -947,6 +971,7 @@ impl SelectorMap {
SelectorMap::get_matching_rules(element,
parent_bf,
&self.other_rules,
guard,
matching_rules_list,
relations,
flags,
@ -960,6 +985,7 @@ impl SelectorMap {
/// Append to `rule_list` all universal Rules (rules with selector `*|*`) in
/// `self` sorted by specificity and source order.
pub fn get_universal_rules(&self,
guard: &SharedRwLockReadGuard,
cascade_level: CascadeLevel,
important_cascade_level: CascadeLevel)
-> Vec<ApplicableDeclarationBlock> {
@ -977,8 +1003,8 @@ impl SelectorMap {
for rule in self.other_rules.iter() {
if rule.selector.compound_selector.is_empty() &&
rule.selector.next.is_none() {
let guard = rule.style_rule.read();
let block = guard.block.read();
let style_rule = rule.style_rule.read_with(guard);
let block = style_rule.block.read_with(guard);
if block.any_normal() {
matching_rules_list.push(
rule.to_applicable_declaration_block(cascade_level));
@ -1006,6 +1032,7 @@ impl SelectorMap {
parent_bf: Option<&BloomFilter>,
hash: &FnvHashMap<Str, Vec<Rule>>,
key: &BorrowedStr,
guard: &SharedRwLockReadGuard,
matching_rules: &mut Vector,
relations: &mut StyleRelations,
flags: &mut ElementSelectorFlags,
@ -1019,6 +1046,7 @@ impl SelectorMap {
SelectorMap::get_matching_rules(element,
parent_bf,
rules,
guard,
matching_rules,
relations,
flags,
@ -1030,6 +1058,7 @@ impl SelectorMap {
fn get_matching_rules<E, V>(element: &E,
parent_bf: Option<&BloomFilter>,
rules: &[Rule],
guard: &SharedRwLockReadGuard,
matching_rules: &mut V,
relations: &mut StyleRelations,
flags: &mut ElementSelectorFlags,
@ -1038,8 +1067,8 @@ impl SelectorMap {
V: VecLike<ApplicableDeclarationBlock>
{
for rule in rules.iter() {
let guard = rule.style_rule.read();
let block = guard.block.read();
let style_rule = rule.style_rule.read_with(guard);
let block = style_rule.block.read_with(guard);
let any_declaration_for_importance = if cascade_level.is_important() {
block.any_important()
} else {
@ -1137,7 +1166,7 @@ pub struct Rule {
pub selector: Arc<ComplexSelector<SelectorImpl>>,
/// The actual style rule.
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
pub style_rule: Arc<RwLock<StyleRule>>,
pub style_rule: Arc<Locked<StyleRule>>,
/// The source order this style rule appears in.
pub source_order: usize,
/// The specificity of the rule this selector represents.
@ -1178,7 +1207,7 @@ impl ApplicableDeclarationBlock {
/// Constructs an applicable declaration block from a given property
/// declaration block and importance.
#[inline]
pub fn from_declarations(declarations: Arc<RwLock<PropertyDeclarationBlock>>,
pub fn from_declarations(declarations: Arc<Locked<PropertyDeclarationBlock>>,
level: CascadeLevel)
-> Self {
ApplicableDeclarationBlock {

View File

@ -312,7 +312,8 @@ pub trait DomTraversal<E: TElement> : Sync {
}
/// Helper for the function below.
fn resolve_style_internal<E, F>(context: &mut StyleContext<E>, element: E, ensure_data: &F)
fn resolve_style_internal<E, F>(context: &mut StyleContext<E>,
element: E, ensure_data: &F)
-> Option<E>
where E: TElement,
F: Fn(E),

View File

@ -15,6 +15,7 @@ use cssparser::ToCss as ParserToCss;
use euclid::size::TypedSize2D;
use media_queries::Device;
use parser::{ParserContext, log_css_error};
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::fmt;
@ -504,9 +505,10 @@ impl ViewportRule {
}
}
impl ToCss for ViewportRule {
impl ToCssWithGuard for ViewportRule {
// Serialization of ViewportRule is not specced.
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
try!(dest.write_str("@viewport { "));
let mut iter = self.declarations.iter();
try!(iter.next().unwrap().to_css(dest));
@ -555,13 +557,14 @@ impl Cascade {
}
}
pub fn from_stylesheets<'a, I>(stylesheets: I, device: &Device) -> Self
pub fn from_stylesheets<'a, I>(stylesheets: I, guard: &SharedRwLockReadGuard,
device: &Device) -> Self
where I: IntoIterator,
I::Item: AsRef<Stylesheet>,
{
let mut cascade = Self::new();
for stylesheet in stylesheets {
stylesheet.as_ref().effective_viewport_rules(device, |rule| {
stylesheet.as_ref().effective_viewport_rules(device, guard, |rule| {
for declaration in &rule.declarations {
cascade.add(Cow::Borrowed(declaration))
}

View File

@ -20,9 +20,7 @@ env_logger = {version = "0.4", default-features = false} # disable `regex` to re
lazy_static = "0.2"
libc = "0.2"
log = {version = "0.3.5", features = ["release_max_level_info"]}
num_cpus = "1.1.0"
parking_lot = "0.3"
rayon = "0.6"
selectors = {path = "../../components/selectors"}
servo_url = {path = "../../components/url"}
style = {path = "../../components/style", features = ["gecko"]}

View File

@ -6,13 +6,10 @@ use atomic_refcell::AtomicRefMut;
use cssparser::Parser;
use cssparser::ToCss as ParserToCss;
use env_logger::LogBuilder;
use num_cpus;
use parking_lot::RwLock;
use rayon;
use selectors::Element;
use servo_url::ServoUrl;
use std::borrow::Cow;
use std::cmp;
use std::env;
use std::fmt::Write;
use std::ptr;
@ -24,6 +21,7 @@ use style::data::{ElementData, ElementStyles, RestyleData};
use style::dom::{ShowSubtreeData, TElement, TNode};
use style::error_reporting::StdoutErrorReporter;
use style::gecko::data::{PerDocumentStyleData, PerDocumentStyleDataImpl};
use style::gecko::global_style_data::GLOBAL_STYLE_DATA;
use style::gecko::restyle_damage::GeckoRestyleDamage;
use style::gecko::selector_parser::{SelectorImpl, PseudoElement};
use style::gecko::traversal::RecalcStyleOnly;
@ -76,6 +74,7 @@ use style::properties::parse_one_declaration;
use style::restyle_hints::{self, RestyleHint};
use style::selector_parser::PseudoElementCascadeType;
use style::sequential;
use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked};
use style::string_cache::Atom;
use style::stylesheets::{CssRule, CssRules, ImportRule, MediaRule, NamespaceRule};
use style::stylesheets::{Origin, Stylesheet, StyleRule};
@ -85,7 +84,7 @@ use style::thread_state;
use style::timer::Timer;
use style::traversal::{resolve_style, DomTraversal, TraversalDriver};
use style_traits::ToCss;
use stylesheet_loader::StylesheetLoader;
use super::stylesheet_loader::StylesheetLoader;
/*
* For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
@ -95,44 +94,7 @@ use stylesheet_loader::StylesheetLoader;
* depend on but good enough for our purposes.
*/
struct GlobalStyleData {
// How many threads parallel styling can use.
pub num_threads: usize,
// The parallel styling thread pool.
pub style_thread_pool: Option<rayon::ThreadPool>,
}
impl GlobalStyleData {
pub fn new() -> Self {
let stylo_threads = env::var("STYLO_THREADS")
.map(|s| s.parse::<usize>().expect("invalid STYLO_THREADS value"));
let num_threads = match stylo_threads {
Ok(num) => num,
_ => cmp::max(num_cpus::get() * 3 / 4, 1),
};
let pool = if num_threads <= 1 {
None
} else {
let configuration =
rayon::Configuration::new().set_num_threads(num_threads);
let pool = rayon::ThreadPool::new(configuration).ok();
pool
};
GlobalStyleData {
num_threads: num_threads,
style_thread_pool: pool,
}
}
}
lazy_static! {
static ref GLOBAL_STYLE_DATA: GlobalStyleData = {
GlobalStyleData::new()
};
}
#[no_mangle]
pub extern "C" fn Servo_Initialize() {
@ -160,12 +122,14 @@ pub extern "C" fn Servo_Shutdown() {
gecko_properties::shutdown();
}
fn create_shared_context(per_doc_data: &PerDocumentStyleDataImpl) -> SharedStyleContext {
fn create_shared_context<'a>(guard: &'a SharedRwLockReadGuard,
per_doc_data: &PerDocumentStyleDataImpl) -> SharedStyleContext<'a> {
let local_context_data =
ThreadLocalStyleContextCreationInfo::new(per_doc_data.new_animations_sender.clone());
SharedStyleContext {
stylist: per_doc_data.stylist.clone(),
guards: StylesheetGuards::same(guard),
running_animations: per_doc_data.running_animations.clone(),
expired_animations: per_doc_data.expired_animations.clone(),
// FIXME(emilio): Stop boxing here.
@ -198,8 +162,9 @@ fn traverse_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed,
debug!("Traversing subtree:");
debug!("{:?}", ShowSubtreeData(element.as_node()));
let shared_style_context = create_shared_context(&per_doc_data);
let ref global_style_data = *GLOBAL_STYLE_DATA;
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let shared_style_context = create_shared_context(&guard, &per_doc_data);
let traversal_driver = if global_style_data.style_thread_pool.is_none() {
TraversalDriver::Sequential
@ -328,6 +293,7 @@ pub extern "C" fn Servo_Element_ClearData(element: RawGeckoElementBorrowed) {
#[no_mangle]
pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyleSheetStrong {
let global_style_data = &*GLOBAL_STYLE_DATA;
let url = ServoUrl::parse("about:blank").unwrap();
let extra_data = ParserContextExtraData::default();
let origin = match mode {
@ -335,8 +301,9 @@ pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyl
SheetParsingMode::eUserSheetFeatures => Origin::User,
SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
};
let shared_lock = global_style_data.shared_lock.clone();
Arc::new(Stylesheet::from_str(
"", url, origin, Default::default(), None,
"", url, origin, Default::default(), shared_lock, None,
&StdoutErrorReporter, extra_data)
).into_strong()
}
@ -351,6 +318,7 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
referrer: *mut ThreadSafeURIHolder,
principal: *mut ThreadSafePrincipalHolder)
-> RawServoStyleSheetStrong {
let global_style_data = &*GLOBAL_STYLE_DATA;
let input = unsafe { data.as_ref().unwrap().as_str_unchecked() };
let origin = match mode {
@ -378,8 +346,9 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
Some(ref s) => Some(s),
};
let shared_lock = global_style_data.shared_lock.clone();
Arc::new(Stylesheet::from_str(
input, url, origin, Default::default(), loader,
input, url, origin, Default::default(), shared_lock, loader,
&StdoutErrorReporter, extra_data)
).into_strong()
}
@ -413,23 +382,22 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet
};
let sheet = Stylesheet::as_arc(&stylesheet);
sheet.rules.write().0.clear();
Stylesheet::update_from_str(&sheet, input, loader,
&StdoutErrorReporter, extra_data);
Stylesheet::update_from_str(&sheet, input, loader, &StdoutErrorReporter, extra_data);
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorrowed,
raw_sheet: RawServoStyleSheetBorrowed,
flush: bool) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let sheet = HasArcFFI::as_arc(&raw_sheet);
data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet));
data.stylesheets.push(sheet.clone());
data.stylesheets_changed = true;
if flush {
data.flush_stylesheets();
data.flush_stylesheets(&guard);
}
}
@ -437,13 +405,15 @@ pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorr
pub extern "C" fn Servo_StyleSet_PrependStyleSheet(raw_data: RawServoStyleSetBorrowed,
raw_sheet: RawServoStyleSheetBorrowed,
flush: bool) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let sheet = HasArcFFI::as_arc(&raw_sheet);
data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet));
data.stylesheets.insert(0, sheet.clone());
data.stylesheets_changed = true;
if flush {
data.flush_stylesheets();
data.flush_stylesheets(&guard);
}
}
@ -452,6 +422,8 @@ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleS
raw_sheet: RawServoStyleSheetBorrowed,
raw_reference: RawServoStyleSheetBorrowed,
flush: bool) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let sheet = HasArcFFI::as_arc(&raw_sheet);
let reference = HasArcFFI::as_arc(&raw_reference);
@ -460,7 +432,7 @@ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleS
data.stylesheets.insert(index, sheet.clone());
data.stylesheets_changed = true;
if flush {
data.flush_stylesheets();
data.flush_stylesheets(&guard);
}
}
@ -468,19 +440,23 @@ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleS
pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(raw_data: RawServoStyleSetBorrowed,
raw_sheet: RawServoStyleSheetBorrowed,
flush: bool) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let sheet = HasArcFFI::as_arc(&raw_sheet);
data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet));
data.stylesheets_changed = true;
if flush {
data.flush_stylesheets();
data.flush_stylesheets(&guard);
}
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_FlushStyleSheets(raw_data: RawServoStyleSetBorrowed) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
data.flush_stylesheets();
data.flush_stylesheets(&guard);
}
#[no_mangle]
@ -491,7 +467,9 @@ pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(raw_data: RawServoStyleS
#[no_mangle]
pub extern "C" fn Servo_StyleSheet_HasRules(raw_sheet: RawServoStyleSheetBorrowed) -> bool {
!Stylesheet::as_arc(&raw_sheet).rules.read().0.is_empty()
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
!Stylesheet::as_arc(&raw_sheet).rules.read_with(&guard).0.is_empty()
}
#[no_mangle]
@ -502,7 +480,9 @@ pub extern "C" fn Servo_StyleSheet_GetRules(sheet: RawServoStyleSheetBorrowed) -
#[no_mangle]
pub extern "C" fn Servo_CssRules_ListTypes(rules: ServoCssRulesBorrowed,
result: nsTArrayBorrowed_uintptr_t) {
let rules = RwLock::<CssRules>::as_arc(&rules).read();
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rules = Locked::<CssRules>::as_arc(&rules).read_with(&guard);
let iter = rules.0.iter().map(|rule| rule.rule_type() as usize);
let (size, upper) = iter.size_hint();
debug_assert_eq!(size, upper.unwrap());
@ -514,10 +494,12 @@ pub extern "C" fn Servo_CssRules_ListTypes(rules: ServoCssRulesBorrowed,
pub extern "C" fn Servo_CssRules_InsertRule(rules: ServoCssRulesBorrowed, sheet: RawServoStyleSheetBorrowed,
rule: *const nsACString, index: u32, nested: bool,
rule_type: *mut u16) -> nsresult {
let rules = RwLock::<CssRules>::as_arc(&rules);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let rules = Locked::<CssRules>::as_arc(&rules);
let sheet = Stylesheet::as_arc(&sheet);
let rule = unsafe { rule.as_ref().unwrap().as_str_unchecked() };
match rules.write().insert_rule(rule, sheet, index as usize, nested) {
match rules.write_with(&mut guard).insert_rule(rule, sheet, index as usize, nested) {
Ok(new_rule) => {
*unsafe { rule_type.as_mut().unwrap() } = new_rule.rule_type() as u16;
nsresult::NS_OK
@ -528,8 +510,10 @@ pub extern "C" fn Servo_CssRules_InsertRule(rules: ServoCssRulesBorrowed, sheet:
#[no_mangle]
pub extern "C" fn Servo_CssRules_DeleteRule(rules: ServoCssRulesBorrowed, index: u32) -> nsresult {
let rules = RwLock::<CssRules>::as_arc(&rules);
match rules.write().remove_rule(index as usize) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let rules = Locked::<CssRules>::as_arc(&rules);
match rules.write_with(&mut guard).remove_rule(index as usize) {
Ok(_) => nsresult::NS_OK,
Err(err) => err.into()
}
@ -543,7 +527,9 @@ macro_rules! impl_basic_rule_funcs {
} => {
#[no_mangle]
pub extern "C" fn $getter(rules: ServoCssRulesBorrowed, index: u32) -> Strong<$raw_type> {
let rules = RwLock::<CssRules>::as_arc(&rules).read();
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rules = Locked::<CssRules>::as_arc(&rules).read_with(&guard);
match rules.0[index as usize] {
CssRule::$name(ref rule) => rule.clone().into_strong(),
_ => {
@ -555,15 +541,19 @@ macro_rules! impl_basic_rule_funcs {
#[no_mangle]
pub extern "C" fn $debug(rule: &$raw_type, result: *mut nsACString) {
let rule = RwLock::<$rule_type>::as_arc(&rule);
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rule = Locked::<$rule_type>::as_arc(&rule);
let result = unsafe { result.as_mut().unwrap() };
write!(result, "{:?}", *rule.read()).unwrap();
write!(result, "{:?}", *rule.read_with(&guard)).unwrap();
}
#[no_mangle]
pub extern "C" fn $to_css(rule: &$raw_type, result: *mut nsAString) {
let rule = RwLock::<$rule_type>::as_arc(&rule);
rule.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap();
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rule = Locked::<$rule_type>::as_arc(&rule);
rule.read_with(&guard).to_css(&guard, unsafe { result.as_mut().unwrap() }).unwrap();
}
}
}
@ -588,46 +578,60 @@ impl_basic_rule_funcs! { (Namespace, NamespaceRule, RawServoNamespaceRule),
#[no_mangle]
pub extern "C" fn Servo_StyleRule_GetStyle(rule: RawServoStyleRuleBorrowed) -> RawServoDeclarationBlockStrong {
let rule = RwLock::<StyleRule>::as_arc(&rule);
rule.read().block.clone().into_strong()
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rule = Locked::<StyleRule>::as_arc(&rule);
rule.read_with(&guard).block.clone().into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_StyleRule_SetStyle(rule: RawServoStyleRuleBorrowed,
declarations: RawServoDeclarationBlockBorrowed) {
let rule = RwLock::<StyleRule>::as_arc(&rule);
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
rule.write().block = declarations.clone();
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let rule = Locked::<StyleRule>::as_arc(&rule);
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
rule.write_with(&mut guard).block = declarations.clone();
}
#[no_mangle]
pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowed, result: *mut nsAString) {
let rule = RwLock::<StyleRule>::as_arc(&rule);
rule.read().selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap();
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rule = Locked::<StyleRule>::as_arc(&rule);
rule.read_with(&guard).selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap();
}
#[no_mangle]
pub extern "C" fn Servo_MediaRule_GetMedia(rule: RawServoMediaRuleBorrowed) -> RawServoMediaListStrong {
let rule = RwLock::<MediaRule>::as_arc(&rule);
rule.read().media_queries.clone().into_strong()
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rule = Locked::<MediaRule>::as_arc(&rule);
rule.read_with(&guard).media_queries.clone().into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_MediaRule_GetRules(rule: RawServoMediaRuleBorrowed) -> ServoCssRulesStrong {
let rule = RwLock::<MediaRule>::as_arc(&rule);
rule.read().rules.clone().into_strong()
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rule = Locked::<MediaRule>::as_arc(&rule);
rule.read_with(&guard).rules.clone().into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: RawServoNamespaceRuleBorrowed) -> *mut nsIAtom {
let rule = RwLock::<NamespaceRule>::as_arc(&rule);
rule.read().prefix.as_ref().unwrap_or(&atom!("")).as_ptr()
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rule = Locked::<NamespaceRule>::as_arc(&rule);
rule.read_with(&guard).prefix.as_ref().unwrap_or(&atom!("")).as_ptr()
}
#[no_mangle]
pub extern "C" fn Servo_NamespaceRule_GetURI(rule: RawServoNamespaceRuleBorrowed) -> *mut nsIAtom {
let rule = RwLock::<NamespaceRule>::as_arc(&rule);
rule.read().url.0.as_ptr()
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rule = Locked::<NamespaceRule>::as_arc(&rule);
rule.read_with(&guard).url.0.as_ptr()
}
#[no_mangle]
@ -636,6 +640,9 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null:
skip_display_fixup: bool,
raw_data: RawServoStyleSetBorrowed)
-> ServoComputedValuesStrong {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let guards = StylesheetGuards::same(&guard);
let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let atom = Atom::from(pseudo_tag);
let pseudo = PseudoElement::from_atom_unchecked(atom, /* anon_box = */ true);
@ -646,7 +653,7 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null:
if skip_display_fixup {
cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP);
}
data.stylist.precomputed_values_for_pseudo(&pseudo, maybe_parent,
data.stylist.precomputed_values_for_pseudo(&guards, &pseudo, maybe_parent,
cascade_flags)
.values.unwrap()
.into_strong()
@ -672,14 +679,16 @@ pub extern "C" fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed,
};
}
match get_pseudo_style(element, pseudo_tag, data.styles(), doc_data) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
match get_pseudo_style(&guard, element, pseudo_tag, data.styles(), doc_data) {
Some(values) => values.into_strong(),
None if !is_probe => data.styles().primary.values().clone().into_strong(),
None => Strong::null(),
}
}
fn get_pseudo_style(element: GeckoElement, pseudo_tag: *mut nsIAtom,
fn get_pseudo_style(guard: &SharedRwLockReadGuard, element: GeckoElement, pseudo_tag: *mut nsIAtom,
styles: &ElementStyles, doc_data: &PerDocumentStyleData)
-> Option<Arc<ComputedValues>>
{
@ -690,7 +699,9 @@ fn get_pseudo_style(element: GeckoElement, pseudo_tag: *mut nsIAtom,
PseudoElementCascadeType::Lazy => {
let d = doc_data.borrow_mut();
let base = styles.primary.values();
d.stylist.lazily_compute_pseudo_element_style(&element,
let guards = StylesheetGuards::same(guard);
d.stylist.lazily_compute_pseudo_element_style(&guards,
&element,
&pseudo,
base)
.map(|s| s.values().clone())
@ -725,8 +736,10 @@ pub extern "C" fn Servo_StyleSet_Init(pres_context: RawGeckoPresContextOwned)
#[no_mangle]
pub extern "C" fn Servo_StyleSet_RebuildData(raw_data: RawServoStyleSetBorrowed) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
data.reset_device();
data.reset_device(&guard);
}
#[no_mangle]
@ -768,9 +781,10 @@ pub extern "C" fn Servo_ParseProperty(property: *const nsACString, value: *const
match ParsedDeclaration::parse(id, &context, &mut Parser::new(value), false) {
Ok(parsed) => {
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut block = PropertyDeclarationBlock::new();
parsed.expand(|d| block.push(d, Importance::Normal));
Arc::new(RwLock::new(block)).into_strong()
Arc::new(global_style_data.shared_lock.wrap(block)).into_strong()
}
Err(_) => RawServoDeclarationBlockStrong::null()
}
@ -781,36 +795,47 @@ pub extern "C" fn Servo_ParseStyleAttribute(data: *const nsACString,
base: *const nsACString,
raw_extra_data: *const structs::GeckoParserExtraData)
-> RawServoDeclarationBlockStrong {
let global_style_data = &*GLOBAL_STYLE_DATA;
let value = unsafe { data.as_ref().unwrap().as_str_unchecked() };
make_context!((base, raw_extra_data) => (base_url, extra_data));
Arc::new(RwLock::new(GeckoElement::parse_style_attribute(value, &base_url, extra_data))).into_strong()
Arc::new(global_style_data.shared_lock.wrap(
GeckoElement::parse_style_attribute(value, &base_url, extra_data))).into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_CreateEmpty() -> RawServoDeclarationBlockStrong {
Arc::new(RwLock::new(PropertyDeclarationBlock::new())).into_strong()
let global_style_data = &*GLOBAL_STYLE_DATA;
Arc::new(global_style_data.shared_lock.wrap(PropertyDeclarationBlock::new())).into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_Clone(declarations: RawServoDeclarationBlockBorrowed)
-> RawServoDeclarationBlockStrong {
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
Arc::new(RwLock::new(declarations.read().clone())).into_strong()
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
Arc::new(global_style_data.shared_lock.wrap(
declarations.read_with(&guard).clone()
)).into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_Equals(a: RawServoDeclarationBlockBorrowed,
b: RawServoDeclarationBlockBorrowed)
-> bool {
*RwLock::<PropertyDeclarationBlock>::as_arc(&a).read().declarations() ==
*RwLock::<PropertyDeclarationBlock>::as_arc(&b).read().declarations()
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
*Locked::<PropertyDeclarationBlock>::as_arc(&a).read_with(&guard).declarations() ==
*Locked::<PropertyDeclarationBlock>::as_arc(&b).read_with(&guard).declarations()
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_GetCssText(declarations: RawServoDeclarationBlockBorrowed,
result: *mut nsAString) {
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap();
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.read_with(&guard).to_css(unsafe { result.as_mut().unwrap() }).unwrap();
}
#[no_mangle]
@ -819,9 +844,11 @@ pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
property_id: nsCSSPropertyID, buffer: *mut nsAString)
{
let property_id = get_property_id_from_nscsspropertyid!(property_id, ());
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let mut string = String::new();
let rv = declarations.read().single_value_to_css(&property_id, &mut string);
let rv = declarations.read_with(&guard).single_value_to_css(&property_id, &mut string);
debug_assert!(rv.is_ok());
write!(unsafe { &mut *buffer }, "{}", string).expect("Failed to copy string");
@ -829,15 +856,19 @@ pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_Count(declarations: RawServoDeclarationBlockBorrowed) -> u32 {
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.read().declarations().len() as u32
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.read_with(&guard).declarations().len() as u32
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(declarations: RawServoDeclarationBlockBorrowed,
index: u32, result: *mut nsAString) -> bool {
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
if let Some(&(ref decl, _)) = declarations.read().declarations().get(index as usize) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
if let Some(&(ref decl, _)) = declarations.read_with(&guard).declarations().get(index as usize) {
let result = unsafe { result.as_mut().unwrap() };
decl.id().to_css(result).unwrap();
true
@ -858,8 +889,12 @@ macro_rules! get_property_id_from_property {
fn get_property_value(declarations: RawServoDeclarationBlockBorrowed,
property_id: PropertyId, value: *mut nsAString) {
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.read().property_value_to_css(&property_id, unsafe { value.as_mut().unwrap() }).unwrap();
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.read_with(&guard)
.property_value_to_css(&property_id, unsafe { value.as_mut().unwrap() })
.unwrap();
}
#[no_mangle]
@ -878,8 +913,10 @@ pub extern "C" fn Servo_DeclarationBlock_GetPropertyValueById(declarations: RawS
pub extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(declarations: RawServoDeclarationBlockBorrowed,
property: *const nsACString) -> bool {
let property_id = get_property_id_from_property!(property, false);
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.read().property_priority(&property_id).important()
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.read_with(&guard).property_priority(&property_id).important()
}
fn set_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId,
@ -890,7 +927,10 @@ fn set_property(declarations: RawServoDeclarationBlockBorrowed, property_id: Pro
make_context!((base, data) => (base_url, extra_data));
if let Ok(parsed) = parse_one_declaration(property_id, value, &base_url,
&StdoutErrorReporter, extra_data) {
let mut declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations).write();
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations)
.write_with(&mut guard);
let importance = if is_important { Importance::Important } else { Importance::Normal };
let mut changed = false;
parsed.expand(|decl| {
@ -923,8 +963,10 @@ pub extern "C" fn Servo_DeclarationBlock_SetPropertyById(declarations: RawServoD
}
fn remove_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId) {
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.write().remove_property(&property_id);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.write_with(&mut guard).remove_property(&property_id);
}
#[no_mangle]
@ -941,29 +983,37 @@ pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(declarations: RawSer
#[no_mangle]
pub extern "C" fn Servo_MediaList_GetText(list: RawServoMediaListBorrowed, result: *mut nsAString) {
let list = RwLock::<MediaList>::as_arc(&list);
list.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap();
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let list = Locked::<MediaList>::as_arc(&list);
list.read_with(&guard).to_css(unsafe { result.as_mut().unwrap() }).unwrap();
}
#[no_mangle]
pub extern "C" fn Servo_MediaList_SetText(list: RawServoMediaListBorrowed, text: *const nsACString) {
let list = RwLock::<MediaList>::as_arc(&list);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let list = Locked::<MediaList>::as_arc(&list);
let text = unsafe { text.as_ref().unwrap().as_str_unchecked() };
let mut parser = Parser::new(&text);
*list.write() = parse_media_query_list(&mut parser);
*list.write_with(&mut guard) = parse_media_query_list(&mut parser);
}
#[no_mangle]
pub extern "C" fn Servo_MediaList_GetLength(list: RawServoMediaListBorrowed) -> u32 {
let list = RwLock::<MediaList>::as_arc(&list);
list.read().media_queries.len() as u32
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let list = Locked::<MediaList>::as_arc(&list);
list.read_with(&guard).media_queries.len() as u32
}
#[no_mangle]
pub extern "C" fn Servo_MediaList_GetMediumAt(list: RawServoMediaListBorrowed, index: u32,
result: *mut nsAString) -> bool {
let list = RwLock::<MediaList>::as_arc(&list);
if let Some(media_query) = list.read().media_queries.get(index as usize) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let list = Locked::<MediaList>::as_arc(&list);
if let Some(media_query) = list.read_with(&guard).media_queries.get(index as usize) {
media_query.to_css(unsafe { result.as_mut().unwrap() }).unwrap();
true
} else {
@ -974,17 +1024,21 @@ pub extern "C" fn Servo_MediaList_GetMediumAt(list: RawServoMediaListBorrowed, i
#[no_mangle]
pub extern "C" fn Servo_MediaList_AppendMedium(list: RawServoMediaListBorrowed,
new_medium: *const nsACString) {
let list = RwLock::<MediaList>::as_arc(&list);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let list = Locked::<MediaList>::as_arc(&list);
let new_medium = unsafe { new_medium.as_ref().unwrap().as_str_unchecked() };
list.write().append_medium(new_medium);
list.write_with(&mut guard).append_medium(new_medium);
}
#[no_mangle]
pub extern "C" fn Servo_MediaList_DeleteMedium(list: RawServoMediaListBorrowed,
old_medium: *const nsACString) -> bool {
let list = RwLock::<MediaList>::as_arc(&list);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let list = Locked::<MediaList>::as_arc(&list);
let old_medium = unsafe { old_medium.as_ref().unwrap().as_str_unchecked() };
list.write().delete_medium(old_medium)
list.write_with(&mut guard).delete_medium(old_medium)
}
macro_rules! get_longhand_from_id {
@ -1022,9 +1076,11 @@ pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet(declarations:
property: nsCSSPropertyID)
-> bool {
use style::properties::PropertyDeclarationId;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property, false);
declarations.read().get(PropertyDeclarationId::Longhand(long)).is_some()
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
declarations.read_with(&guard).get(PropertyDeclarationId::Longhand(long)).is_some()
}
#[no_mangle]
@ -1037,12 +1093,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(declarations:
use style::properties::{PropertyDeclaration, LonghandId};
use style::properties::longhands::_x_lang::computed_value::T as Lang;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property);
let prop = match_wrap_declared! { long,
XLang => Lang(Atom::from(value)),
};
declarations.write().push(prop, Importance::Normal);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
}
#[no_mangle]
@ -1055,7 +1113,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations:
use style::properties::longhands;
use style::values::specified::{BorderStyle, NoCalcLength};
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property);
let value = value as u32;
@ -1079,7 +1137,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations:
BorderBottomStyle => BorderStyle::from_gecko_keyword(value),
BorderLeftStyle => BorderStyle::from_gecko_keyword(value),
};
declarations.write().push(prop, Importance::Normal);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
}
#[no_mangle]
@ -1089,12 +1149,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetIntValue(declarations: RawServoDecla
use style::properties::{PropertyDeclaration, LonghandId};
use style::properties::longhands::_x_span::computed_value::T as Span;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property);
let prop = match_wrap_declared! { long,
XSpan => Span(value),
};
declarations.write().push(prop, Importance::Normal);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
}
#[no_mangle]
@ -1107,7 +1169,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations:
use style::values::specified::BorderWidth;
use style::values::specified::length::NoCalcLength;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property);
let nocalc = NoCalcLength::from_px(value);
@ -1133,7 +1195,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations:
}
),
};
declarations.write().push(prop, Importance::Normal);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
}
#[no_mangle]
@ -1144,7 +1208,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(declarations:
use style::properties::{PropertyDeclaration, LonghandId};
use style::values::specified::length::Percentage;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property);
let pc = Percentage(value);
@ -1156,7 +1220,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(declarations:
MarginBottom => pc.into(),
MarginLeft => pc.into(),
};
declarations.write().push(prop, Importance::Normal);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
}
#[no_mangle]
@ -1166,7 +1232,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(declarations:
use style::properties::{PropertyDeclaration, LonghandId};
use style::values::specified::LengthOrPercentageOrAuto;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property);
let auto = LengthOrPercentageOrAuto::Auto;
@ -1178,7 +1244,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(declarations:
MarginBottom => auto,
MarginLeft => auto,
};
declarations.write().push(prop, Importance::Normal);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
}
#[no_mangle]
@ -1188,7 +1256,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations:
use style::properties::{PropertyDeclaration, LonghandId};
use style::values::specified::{Color, CSSColor};
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property);
let cc = CSSColor { parsed: Color::CurrentColor, authored: None };
@ -1198,7 +1266,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations:
BorderBottomColor => cc,
BorderLeftColor => cc,
};
declarations.write().push(prop, Importance::Normal);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
}
#[no_mangle]
@ -1211,7 +1281,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations:
use style::properties::longhands;
use style::values::specified::{Color, CSSColor};
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property);
let rgba = convert_nscolor_to_rgba(value);
let color = CSSColor { parsed: Color::RGBA(rgba), authored: None };
@ -1224,7 +1294,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations:
Color => longhands::color::SpecifiedValue(color),
BackgroundColor => color,
};
declarations.write().push(prop, Importance::Normal);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
}
#[no_mangle]
@ -1235,13 +1307,15 @@ pub extern "C" fn Servo_DeclarationBlock_SetFontFamily(declarations:
use style::properties::PropertyDeclaration;
use style::properties::longhands::font_family::SpecifiedValue as FontFamily;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let string = unsafe { (*value).to_string() };
let mut parser = Parser::new(&string);
if let Ok(family) = FontFamily::parse(&mut parser) {
if parser.is_exhausted() {
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let decl = PropertyDeclaration::FontFamily(family);
declarations.write().push(decl, Importance::Normal);
declarations.write_with(&mut guard).push(decl, Importance::Normal);
}
}
}
@ -1252,11 +1326,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(declarat
use style::properties::PropertyDeclaration;
use style::properties::longhands::text_decoration_line;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let mut decoration = text_decoration_line::computed_value::none;
decoration |= text_decoration_line::COLOR_OVERRIDE;
let decl = PropertyDeclaration::TextDecorationLine(decoration);
declarations.write().push(decl, Importance::Normal);
declarations.write_with(&mut guard).push(decl, Importance::Normal);
}
#[no_mangle]
@ -1357,8 +1434,10 @@ pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed,
pub extern "C" fn Servo_ImportRule_GetSheet(import_rule:
RawServoImportRuleBorrowed)
-> RawServoStyleSheetStrong {
let import_rule = RwLock::<ImportRule>::as_arc(&import_rule);
import_rule.read().stylesheet.clone().into_strong()
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let import_rule = Locked::<ImportRule>::as_arc(&import_rule);
import_rule.read_with(&guard).stylesheet.clone().into_strong()
}
#[no_mangle]
@ -1402,11 +1481,13 @@ pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
raw_data: RawServoStyleSetBorrowed)
-> ServoComputedValuesStrong
{
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let element = GeckoElement(element);
let doc_data = PerDocumentStyleData::from_ffi(raw_data);
let finish = |styles: &ElementStyles| -> Arc<ComputedValues> {
let maybe_pseudo = if !pseudo_tag.is_null() {
get_pseudo_style(element, pseudo_tag, styles, doc_data)
get_pseudo_style(&guard, element, pseudo_tag, styles, doc_data)
} else {
None
};
@ -1422,7 +1503,7 @@ pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
}
// We don't have the style ready. Go ahead and compute it as necessary.
let shared = create_shared_context(&mut doc_data.borrow_mut());
let shared = create_shared_context(&guard, &mut doc_data.borrow_mut());
let mut tlc = ThreadLocalStyleContext::new(&shared);
let mut context = StyleContext {
shared: &shared,
@ -1446,6 +1527,11 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis
use style::properties::LonghandIdSet;
use style::properties::declaration_block::Importance;
use style::values::computed::Context;
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let style = ComputedValues::as_arc(&style);
@ -1472,8 +1558,8 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis
.filter(|&property| !property.mServoDeclarationBlock.mRawPtr.is_null());
for property in iter {
let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() };
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let guard = declarations.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let guard = declarations.read_with(&guard);
let anim_iter = guard.declarations()
.iter()
@ -1537,15 +1623,18 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet
use style::gecko_bindings::structs::Keyframe;
use style::properties::LonghandIdSet;
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let name = unsafe { Atom::from(name.as_ref().unwrap().as_str_unchecked()) };
let style_timing_function = unsafe { timing_function.as_ref().unwrap() };
let style = ComputedValues::as_arc(&style);
if let Some(ref animation) = data.stylist.animations().get(&name) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
for step in &animation.steps {
// Override timing_function if the keyframe has animation-timing-function.
let timing_function = if let Some(val) = step.get_animation_timing_function() {
let timing_function = if let Some(val) = step.get_animation_timing_function(&guard) {
val.into()
} else {
*style_timing_function
@ -1560,7 +1649,8 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet
fn add_computed_property_value(keyframe: *mut Keyframe,
index: usize,
style: &ComputedValues,
property: &TransitionProperty) {
property: &TransitionProperty,
shared_lock: &SharedRwLock) {
let block = style.to_declaration_block(property.clone().into());
unsafe {
(*keyframe).mPropertyValues.set_len((index + 1) as u32);
@ -1568,18 +1658,19 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet
// FIXME. Do not set computed values once we handles missing keyframes
// with additive composition.
(*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky(
Arc::new(RwLock::new(block)));
Arc::new(shared_lock.wrap(block)));
}
}
match step.value {
KeyframesStepValue::ComputedValues => {
for (index, property) in animation.properties_changed.iter().enumerate() {
add_computed_property_value(keyframe, index, style, property);
add_computed_property_value(
keyframe, index, style, property, &global_style_data.shared_lock);
}
},
KeyframesStepValue::Declarations { ref block } => {
let guard = block.read();
let guard = block.read_with(&guard);
// Filter out non-animatable properties.
let animatable =
guard.declarations()
@ -1596,8 +1687,9 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet
(*keyframe).mPropertyValues.set_len((index + 1) as u32);
(*keyframe).mPropertyValues[index].mProperty = property.into();
(*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky(
Arc::new(RwLock::new(PropertyDeclarationBlock::with_one(
declaration.clone(), Importance::Normal
Arc::new(global_style_data.shared_lock.wrap(
PropertyDeclarationBlock::with_one(
declaration.clone(), Importance::Normal
))));
if step.start_percentage.0 == 0. ||
step.start_percentage.0 == 1. {
@ -1612,7 +1704,8 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet
let mut index = unsafe { (*keyframe).mPropertyValues.len() };
for property in animation.properties_changed.iter() {
if !seen.has_transition_property_bit(&property) {
add_computed_property_value(keyframe, index, style, property);
add_computed_property_value(
keyframe, index, style, property, &global_style_data.shared_lock);
index += 1;
}
}

View File

@ -10,9 +10,7 @@ extern crate env_logger;
#[macro_use] extern crate lazy_static;
extern crate libc;
#[macro_use] extern crate log;
extern crate num_cpus;
extern crate parking_lot;
extern crate rayon;
extern crate selectors;
extern crate servo_url;
#[macro_use] extern crate style;

View File

@ -2,11 +2,12 @@
* 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 parking_lot::RwLock;
use std::sync::Arc;
use style::gecko_bindings::bindings::Gecko_LoadStyleSheet;
use style::gecko_bindings::structs::{Loader, ServoStyleSheet};
use style::gecko_bindings::sugar::ownership::HasArcFFI;
use style::media_queries::MediaList;
use style::shared_lock::Locked;
use style::stylesheets::{ImportRule, StylesheetLoader as StyleStylesheetLoader};
use style_traits::ToCss;
@ -19,11 +20,12 @@ impl StylesheetLoader {
}
impl StyleStylesheetLoader for StylesheetLoader {
fn request_stylesheet(&self, import_rule: &Arc<RwLock<ImportRule>>) {
let import = import_rule.read();
let (spec_bytes, spec_len) = import.url.as_slice_components()
.expect("Import only loads valid URLs");
fn request_stylesheet(
&self,
media: MediaList,
make_import: &mut FnMut(MediaList) -> ImportRule,
make_arc: &mut FnMut(ImportRule) -> Arc<Locked<ImportRule>>,
) -> Arc<Locked<ImportRule>> {
// TODO(emilio): We probably want to share media representation with
// Gecko in Stylo.
//
@ -32,16 +34,27 @@ impl StyleStylesheetLoader for StylesheetLoader {
// evaluate them on the main thread.
//
// Meanwhile, this works.
let media = import.stylesheet.media.read().to_css_string();
let media_string = media.to_css_string();
let import = make_import(media);
// After we get this raw pointer ImportRule will be moved into a lock and Arc
// and so the Arc<Url> pointer inside will also move,
// but the Url it points to or the allocating backing the String inside that Url wont,
// so this raw pointer will still be valid.
let (spec_bytes, spec_len): (*const u8, usize) = import.url.as_slice_components()
.expect("Import only loads valid URLs");
let arc = make_arc(import);
unsafe {
Gecko_LoadStyleSheet(self.0,
self.1,
HasArcFFI::arc_as_borrowed(import_rule),
HasArcFFI::arc_as_borrowed(&arc),
spec_bytes,
spec_len as u32,
media.as_bytes().as_ptr(),
media.len() as u32);
media_string.as_bytes().as_ptr(),
media_string.len() as u32);
}
arc
}
}

View File

@ -17,7 +17,6 @@ app_units = "0.4"
cssparser = "0.12"
euclid = "0.11"
html5ever-atoms = "0.2"
owning_ref = "0.2.2"
parking_lot = "0.3"
rayon = "0.6"
rustc-serialize = "0.3"

View File

@ -2,18 +2,19 @@
* 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 parking_lot::RwLock;
use std::sync::Arc;
use style::keyframes::{Keyframe, KeyframesAnimation, KeyframePercentage, KeyframeSelector};
use style::keyframes::{KeyframesStep, KeyframesStepValue};
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, Importance};
use style::properties::animated_properties::TransitionProperty;
use style::shared_lock::SharedRwLock;
use style::values::specified::{LengthOrPercentageOrAuto, NoCalcLength};
#[test]
fn test_empty_keyframe() {
let shared_lock = SharedRwLock::new();
let keyframes = vec![];
let animation = KeyframesAnimation::from_keyframes(&keyframes);
let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read());
let expected = KeyframesAnimation {
steps: vec![],
properties_changed: vec![],
@ -24,13 +25,14 @@ fn test_empty_keyframe() {
#[test]
fn test_no_property_in_keyframe() {
let shared_lock = SharedRwLock::new();
let keyframes = vec![
Arc::new(RwLock::new(Keyframe {
Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]),
block: Arc::new(RwLock::new(PropertyDeclarationBlock::new()))
block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::new()))
})),
];
let animation = KeyframesAnimation::from_keyframes(&keyframes);
let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read());
let expected = KeyframesAnimation {
steps: vec![],
properties_changed: vec![],
@ -41,15 +43,16 @@ fn test_no_property_in_keyframe() {
#[test]
fn test_missing_property_in_initial_keyframe() {
let shared_lock = SharedRwLock::new();
let declarations_on_initial_keyframe =
Arc::new(RwLock::new(PropertyDeclarationBlock::with_one(
Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
PropertyDeclaration::Width(
LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
Importance::Normal
)));
let declarations_on_final_keyframe =
Arc::new(RwLock::new({
Arc::new(shared_lock.wrap({
let mut block = PropertyDeclarationBlock::new();
block.push(
PropertyDeclaration::Width(
@ -65,17 +68,17 @@ fn test_missing_property_in_initial_keyframe() {
}));
let keyframes = vec![
Arc::new(RwLock::new(Keyframe {
Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]),
block: declarations_on_initial_keyframe.clone(),
})),
Arc::new(RwLock::new(Keyframe {
Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]),
block: declarations_on_final_keyframe.clone(),
})),
];
let animation = KeyframesAnimation::from_keyframes(&keyframes);
let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read());
let expected = KeyframesAnimation {
steps: vec![
KeyframesStep {
@ -97,8 +100,9 @@ fn test_missing_property_in_initial_keyframe() {
#[test]
fn test_missing_property_in_final_keyframe() {
let shared_lock = SharedRwLock::new();
let declarations_on_initial_keyframe =
Arc::new(RwLock::new({
Arc::new(shared_lock.wrap({
let mut block = PropertyDeclarationBlock::new();
block.push(
PropertyDeclaration::Width(
@ -114,24 +118,24 @@ fn test_missing_property_in_final_keyframe() {
}));
let declarations_on_final_keyframe =
Arc::new(RwLock::new(PropertyDeclarationBlock::with_one(
Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
PropertyDeclaration::Height(
LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
Importance::Normal,
)));
let keyframes = vec![
Arc::new(RwLock::new(Keyframe {
Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]),
block: declarations_on_initial_keyframe.clone(),
})),
Arc::new(RwLock::new(Keyframe {
Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]),
block: declarations_on_final_keyframe.clone(),
})),
];
let animation = KeyframesAnimation::from_keyframes(&keyframes);
let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read());
let expected = KeyframesAnimation {
steps: vec![
KeyframesStep {
@ -153,8 +157,9 @@ fn test_missing_property_in_final_keyframe() {
#[test]
fn test_missing_keyframe_in_both_of_initial_and_final_keyframe() {
let shared_lock = SharedRwLock::new();
let declarations =
Arc::new(RwLock::new({
Arc::new(shared_lock.wrap({
let mut block = PropertyDeclarationBlock::new();
block.push(
PropertyDeclaration::Width(
@ -170,22 +175,22 @@ fn test_missing_keyframe_in_both_of_initial_and_final_keyframe() {
}));
let keyframes = vec![
Arc::new(RwLock::new(Keyframe {
Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]),
block: Arc::new(RwLock::new(PropertyDeclarationBlock::new()))
block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::new()))
})),
Arc::new(RwLock::new(Keyframe {
Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.5)]),
block: declarations.clone(),
})),
];
let animation = KeyframesAnimation::from_keyframes(&keyframes);
let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read());
let expected = KeyframesAnimation {
steps: vec![
KeyframesStep {
start_percentage: KeyframePercentage(0.),
value: KeyframesStepValue::Declarations {
block: Arc::new(RwLock::new(
block: Arc::new(shared_lock.wrap(
// XXX: Should we use ComputedValues in this case?
PropertyDeclarationBlock::new()
))

View File

@ -9,7 +9,6 @@ extern crate app_units;
extern crate cssparser;
extern crate euclid;
#[macro_use] extern crate html5ever_atoms;
extern crate owning_ref;
extern crate parking_lot;
extern crate rayon;
extern crate rustc_serialize;
@ -26,7 +25,6 @@ mod attr;
mod keyframes;
mod logical_geometry;
mod media_queries;
mod owning_handle;
mod parsing;
mod properties;
mod rule_tree;

View File

@ -11,6 +11,7 @@ use style::error_reporting::ParseErrorReporter;
use style::media_queries::*;
use style::parser::ParserContextExtraData;
use style::servo::media_queries::*;
use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard};
use style::stylesheets::{Stylesheet, Origin, CssRule};
use style::values::specified;
use style_traits::ToCss;
@ -29,26 +30,27 @@ fn test_media_rule<F>(css: &str, callback: F)
let url = ServoUrl::parse("http://localhost").unwrap();
let css_str = css.to_owned();
let stylesheet = Stylesheet::from_str(
css, url, Origin::Author, Default::default(),
css, url, Origin::Author, Default::default(), SharedRwLock::new(),
None, &CSSErrorReporterTest,
ParserContextExtraData::default());
let mut rule_count = 0;
media_queries(&stylesheet.rules.read().0, &mut |mq| {
let guard = stylesheet.shared_lock.read();
media_queries(&guard, &stylesheet.rules.read_with(&guard).0, &mut |mq| {
rule_count += 1;
callback(mq, css);
});
assert!(rule_count > 0, css_str);
}
fn media_queries<F>(rules: &[CssRule], f: &mut F)
fn media_queries<F>(guard: &SharedRwLockReadGuard, rules: &[CssRule], f: &mut F)
where F: FnMut(&MediaList),
{
for rule in rules {
rule.with_nested_rules_and_mq(|rules, mq| {
rule.with_nested_rules_and_mq(guard, |rules, mq| {
if let Some(mq) = mq {
f(mq)
}
media_queries(rules, f)
media_queries(guard, rules, f)
})
}
}
@ -56,11 +58,11 @@ fn media_queries<F>(rules: &[CssRule], f: &mut F)
fn media_query_test(device: &Device, css: &str, expected_rule_count: usize) {
let url = ServoUrl::parse("http://localhost").unwrap();
let ss = Stylesheet::from_str(
css, url, Origin::Author, Default::default(),
css, url, Origin::Author, Default::default(), SharedRwLock::new(),
None, &CSSErrorReporterTest,
ParserContextExtraData::default());
let mut rule_count = 0;
ss.effective_style_rules(device, |_| rule_count += 1);
ss.effective_style_rules(device, &ss.shared_lock.read(), |_| rule_count += 1);
assert!(rule_count == expected_rule_count, css.to_owned());
}

View File

@ -1,34 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use owning_ref::RcRef;
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::{Arc, RwLock};
use style::owning_handle::OwningHandle;
#[test]
fn owning_handle() {
use std::cell::RefCell;
let cell = Rc::new(RefCell::new(2));
let cell_ref = RcRef::new(cell);
let mut handle = OwningHandle::new(cell_ref, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
assert_eq!(*handle, 2);
*handle = 3;
assert_eq!(*handle, 3);
}
#[test]
fn nested() {
let result = {
let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString"))));
let curr = RcRef::new(complex);
let curr = OwningHandle::new(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
let mut curr = OwningHandle::new(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap());
assert_eq!(*curr, "someString");
*curr = "someOtherString";
curr
};
assert_eq!(*result, "someOtherString");
}

View File

@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use cssparser::{Parser, SourcePosition};
use parking_lot::RwLock;
use rayon;
use servo_url::ServoUrl;
use std::sync::Arc;
@ -12,6 +11,7 @@ use style::media_queries::MediaList;
use style::parser::ParserContextExtraData;
use style::properties::{longhands, Importance, PropertyDeclaration, PropertyDeclarationBlock};
use style::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
use style::shared_lock::SharedRwLock;
use style::stylesheets::{Origin, Stylesheet, CssRule};
use test::{self, Bencher};
@ -44,10 +44,12 @@ fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> {
MediaList {
media_queries: vec![],
},
SharedRwLock::new(),
None,
&ErrorringErrorReporter,
ParserContextExtraData {});
let rules = s.rules.read();
let guard = s.shared_lock.read();
let rules = s.rules.read_with(&guard);
rules.0.iter().filter_map(|rule| {
match *rule {
CssRule::Style(ref style_rule) => Some(style_rule),
@ -62,9 +64,11 @@ fn test_insertion(rule_tree: &RuleTree, rules: Vec<(StyleSource, CascadeLevel)>)
rule_tree.insert_ordered_rules(rules.into_iter())
}
fn test_insertion_style_attribute(rule_tree: &RuleTree, rules: &[(StyleSource, CascadeLevel)]) -> StrongRuleNode {
fn test_insertion_style_attribute(rule_tree: &RuleTree, rules: &[(StyleSource, CascadeLevel)],
shared_lock: &SharedRwLock)
-> StrongRuleNode {
let mut rules = rules.to_vec();
rules.push((StyleSource::Declarations(Arc::new(RwLock::new(PropertyDeclarationBlock::with_one(
rules.push((StyleSource::Declarations(Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
PropertyDeclaration::Display(
longhands::display::SpecifiedValue::block),
Importance::Normal
@ -118,11 +122,12 @@ fn bench_expensive_insertion(b: &mut Bencher) {
.bar { height: 500px; } \
.baz { display: block; }");
let shared_lock = SharedRwLock::new();
b.iter(|| {
let _gc = AutoGCRuleTree::new(&r);
for _ in 0..(4000 + 400) {
test::black_box(test_insertion_style_attribute(&r, &rules_matched));
test::black_box(test_insertion_style_attribute(&r, &rules_matched, &shared_lock));
}
});
}
@ -167,6 +172,7 @@ fn bench_expensive_insersion_parallel(b: &mut Bencher) {
.bar { height: 500px; } \
.baz { display: block; }");
let shared_lock = SharedRwLock::new();
b.iter(|| {
let _gc = AutoGCRuleTree::new(&r);
@ -175,12 +181,14 @@ fn bench_expensive_insersion_parallel(b: &mut Bencher) {
s.spawn(|s| {
for _ in 0..1000 {
test::black_box(test_insertion_style_attribute(&r,
&rules_matched));
&rules_matched,
&shared_lock));
}
s.spawn(|_| {
for _ in 0..100 {
test::black_box(test_insertion_style_attribute(&r,
&rules_matched));
&rules_matched,
&shared_lock));
}
})
})

View File

@ -20,6 +20,7 @@ use style::properties::Importance;
use style::properties::{CSSWideKeyword, DeclaredValueOwned, PropertyDeclaration, PropertyDeclarationBlock};
use style::properties::longhands;
use style::properties::longhands::animation_play_state;
use style::shared_lock::SharedRwLock;
use style::stylesheets::{Origin, Namespaces};
use style::stylesheets::{Stylesheet, NamespaceRule, CssRule, CssRules, StyleRule, KeyframesRule};
use style::values::specified::{LengthOrPercentageOrAuto, Percentage};
@ -62,24 +63,25 @@ fn test_parse_stylesheet() {
}";
let url = ServoUrl::parse("about::test").unwrap();
let stylesheet = Stylesheet::from_str(css, url.clone(), Origin::UserAgent, Default::default(),
None,
SharedRwLock::new(), None,
&CSSErrorReporterTest,
ParserContextExtraData::default());
let mut namespaces = Namespaces::default();
namespaces.default = Some(ns!(html));
let expected = Stylesheet {
origin: Origin::UserAgent,
media: Default::default(),
media: Arc::new(stylesheet.shared_lock.wrap(Default::default())),
shared_lock: stylesheet.shared_lock.clone(),
namespaces: RwLock::new(namespaces),
base_url: url,
dirty_on_viewport_size_change: AtomicBool::new(false),
disabled: AtomicBool::new(false),
rules: CssRules::new(vec![
CssRule::Namespace(Arc::new(RwLock::new(NamespaceRule {
CssRule::Namespace(Arc::new(stylesheet.shared_lock.wrap(NamespaceRule {
prefix: None,
url: NsAtom::from("http://www.w3.org/1999/xhtml")
}))),
CssRule::Style(Arc::new(RwLock::new(StyleRule {
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
Selector {
complex_selector: Arc::new(ComplexSelector {
@ -107,7 +109,7 @@ fn test_parse_stylesheet() {
specificity: (0 << 20) + (1 << 10) + (1 << 0),
},
]),
block: Arc::new(RwLock::new(block_from(vec![
block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::Display(longhands::display::SpecifiedValue::none),
Importance::Important),
(PropertyDeclaration::Custom(Atom::from("a"),
@ -115,7 +117,7 @@ fn test_parse_stylesheet() {
Importance::Important),
]))),
}))),
CssRule::Style(Arc::new(RwLock::new(StyleRule {
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
Selector {
complex_selector: Arc::new(ComplexSelector {
@ -152,12 +154,12 @@ fn test_parse_stylesheet() {
specificity: (0 << 20) + (0 << 10) + (1 << 0),
},
]),
block: Arc::new(RwLock::new(block_from(vec![
block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::Display(longhands::display::SpecifiedValue::block),
Importance::Normal),
]))),
}))),
CssRule::Style(Arc::new(RwLock::new(StyleRule {
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
Selector {
complex_selector: Arc::new(ComplexSelector {
@ -183,7 +185,7 @@ fn test_parse_stylesheet() {
specificity: (1 << 20) + (1 << 10) + (0 << 0),
},
]),
block: Arc::new(RwLock::new(block_from(vec![
block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::BackgroundColor(
longhands::background_color::SpecifiedValue {
authored: Some("blue".to_owned().into_boxed_str()),
@ -233,22 +235,22 @@ fn test_parse_stylesheet() {
Importance::Normal),
]))),
}))),
CssRule::Keyframes(Arc::new(RwLock::new(KeyframesRule {
CssRule::Keyframes(Arc::new(stylesheet.shared_lock.wrap(KeyframesRule {
name: "foo".into(),
keyframes: vec![
Arc::new(RwLock::new(Keyframe {
Arc::new(stylesheet.shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(
vec![KeyframePercentage::new(0.)]),
block: Arc::new(RwLock::new(block_from(vec![
block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::Width(
LengthOrPercentageOrAuto::Percentage(Percentage(0.))),
Importance::Normal),
])))
})),
Arc::new(RwLock::new(Keyframe {
Arc::new(stylesheet.shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(
vec![KeyframePercentage::new(1.)]),
block: Arc::new(RwLock::new(block_from(vec![
block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::Width(
LengthOrPercentageOrAuto::Percentage(Percentage(1.))),
Importance::Normal),
@ -261,7 +263,7 @@ fn test_parse_stylesheet() {
]
})))
]),
], &stylesheet.shared_lock),
};
assert_eq!(format!("{:#?}", stylesheet), format!("{:#?}", expected));
@ -324,7 +326,7 @@ fn test_report_error_stylesheet() {
let errors = error_reporter.errors.clone();
Stylesheet::from_str(css, url.clone(), Origin::UserAgent, Default::default(),
None,
SharedRwLock::new(), None,
&error_reporter,
ParserContextExtraData::default());

View File

@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use html5ever_atoms::LocalName;
use parking_lot::RwLock;
use selectors::parser::LocalName as LocalNameSelector;
use servo_atoms::Atom;
use std::sync::Arc;
@ -11,40 +10,43 @@ use style::properties::{PropertyDeclarationBlock, PropertyDeclaration};
use style::properties::{longhands, Importance};
use style::rule_tree::CascadeLevel;
use style::selector_parser::SelectorParser;
use style::shared_lock::SharedRwLock;
use style::stylesheets::StyleRule;
use style::stylist::{Rule, SelectorMap};
use style::thread_state;
/// Helper method to get some Rules from selector strings.
/// Each sublist of the result contains the Rules for one StyleRule.
fn get_mock_rules(css_selectors: &[&str]) -> Vec<Vec<Rule>> {
css_selectors.iter().enumerate().map(|(i, selectors)| {
fn get_mock_rules(css_selectors: &[&str]) -> (Vec<Vec<Rule>>, SharedRwLock) {
let shared_lock = SharedRwLock::new();
(css_selectors.iter().enumerate().map(|(i, selectors)| {
let selectors = SelectorParser::parse_author_origin_no_namespace(selectors).unwrap();
let rule = Arc::new(RwLock::new(StyleRule {
let locked = Arc::new(shared_lock.wrap(StyleRule {
selectors: selectors,
block: Arc::new(RwLock::new(PropertyDeclarationBlock::with_one(
block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
PropertyDeclaration::Display(
longhands::display::SpecifiedValue::block),
Importance::Normal
))),
}));
let guard = rule.read();
guard.selectors.0.iter().map(|s| {
let guard = shared_lock.read();
let rule = locked.read_with(&guard);
rule.selectors.0.iter().map(|s| {
Rule {
selector: s.complex_selector.clone(),
style_rule: rule.clone(),
style_rule: locked.clone(),
specificity: s.specificity,
source_order: i,
}
}).collect()
}).collect()
}).collect(), shared_lock)
}
fn get_mock_map(selectors: &[&str]) -> SelectorMap {
fn get_mock_map(selectors: &[&str]) -> (SelectorMap, SharedRwLock) {
let mut map = SelectorMap::new();
let selector_rules = get_mock_rules(selectors);
let (selector_rules, shared_lock) = get_mock_rules(selectors);
for rules in selector_rules.into_iter() {
for rule in rules.into_iter() {
@ -52,12 +54,12 @@ fn get_mock_map(selectors: &[&str]) -> SelectorMap {
}
}
map
(map, shared_lock)
}
#[test]
fn test_rule_ordering_same_specificity() {
let rules_list = get_mock_rules(&["a.intro", "img.sidebar"]);
let (rules_list, _) = get_mock_rules(&["a.intro", "img.sidebar"]);
let a = &rules_list[0][0];
let b = &rules_list[1][0];
assert!((a.specificity, a.source_order) < ((b.specificity, b.source_order)),
@ -67,21 +69,21 @@ fn test_rule_ordering_same_specificity() {
#[test]
fn test_get_id_name() {
let rules_list = get_mock_rules(&[".intro", "#top"]);
let (rules_list, _) = get_mock_rules(&[".intro", "#top"]);
assert_eq!(SelectorMap::get_id_name(&rules_list[0][0]), None);
assert_eq!(SelectorMap::get_id_name(&rules_list[1][0]), Some(Atom::from("top")));
}
#[test]
fn test_get_class_name() {
let rules_list = get_mock_rules(&[".intro.foo", "#top"]);
let (rules_list, _) = get_mock_rules(&[".intro.foo", "#top"]);
assert_eq!(SelectorMap::get_class_name(&rules_list[0][0]), Some(Atom::from("intro")));
assert_eq!(SelectorMap::get_class_name(&rules_list[1][0]), None);
}
#[test]
fn test_get_local_name() {
let rules_list = get_mock_rules(&["img.foo", "#top", "IMG", "ImG"]);
let (rules_list, _) = get_mock_rules(&["img.foo", "#top", "IMG", "ImG"]);
let check = |i: usize, names: Option<(&str, &str)>| {
assert!(SelectorMap::get_local_name(&rules_list[i][0])
== names.map(|(name, lower_name)| LocalNameSelector {
@ -96,7 +98,7 @@ fn test_get_local_name() {
#[test]
fn test_insert() {
let rules_list = get_mock_rules(&[".intro.foo", "#top"]);
let (rules_list, _) = get_mock_rules(&[".intro.foo", "#top"]);
let mut selector_map = SelectorMap::new();
selector_map.insert(rules_list[1][0].clone());
assert_eq!(1, selector_map.id_hash.get(&Atom::from("top")).unwrap()[0].source_order);
@ -108,10 +110,11 @@ fn test_insert() {
#[test]
fn test_get_universal_rules() {
thread_state::initialize(thread_state::LAYOUT);
let map = get_mock_map(&["*|*", "#foo > *|*", ".klass", "#id"]);
let (map, shared_lock) = get_mock_map(&["*|*", "#foo > *|*", ".klass", "#id"]);
let decls = map.get_universal_rules(CascadeLevel::UserNormal,
CascadeLevel::UserImportant);
let guard = shared_lock.read();
let decls = map.get_universal_rules(
&guard, CascadeLevel::UserNormal, CascadeLevel::UserImportant);
assert_eq!(decls.len(), 1);
}

View File

@ -9,6 +9,7 @@ use servo_config::prefs::{PREFS, PrefValue};
use servo_url::ServoUrl;
use style::media_queries::{Device, MediaType};
use style::parser::{ParserContext, ParserContextExtraData};
use style::shared_lock::SharedRwLock;
use style::stylesheets::{Stylesheet, Origin};
use style::values::specified::LengthOrPercentageOrAuto::{self, Auto};
use style::values::specified::NoCalcLength::{self, ViewportPercentage};
@ -19,11 +20,15 @@ use style_traits::viewport::*;
macro_rules! stylesheet {
($css:expr, $origin:ident, $error_reporter:expr) => {
stylesheet!($css, $origin, $error_reporter, SharedRwLock::new())
};
($css:expr, $origin:ident, $error_reporter:expr, $shared_lock:expr) => {
Box::new(Stylesheet::from_str(
$css,
ServoUrl::parse("http://localhost").unwrap(),
Origin::$origin,
Default::default(),
$shared_lock,
None,
&$error_reporter,
ParserContextExtraData::default()
@ -39,7 +44,7 @@ fn test_viewport_rule<F>(css: &str,
PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true));
let stylesheet = stylesheet!(css, Author, CSSErrorReporterTest);
let mut rule_count = 0;
stylesheet.effective_viewport_rules(&device, |rule| {
stylesheet.effective_viewport_rules(&device, &stylesheet.shared_lock.read(), |rule| {
rule_count += 1;
callback(&rule.declarations, css);
});
@ -251,24 +256,31 @@ fn multiple_stylesheets_cascading() {
PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true));
let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.));
let error_reporter = CSSErrorReporterTest;
let shared_lock = SharedRwLock::new();
let stylesheets = vec![
stylesheet!("@viewport { min-width: 100px; min-height: 100px; zoom: 1; }", UserAgent, error_reporter),
stylesheet!("@viewport { min-width: 200px; min-height: 200px; }", User, error_reporter),
stylesheet!("@viewport { min-width: 300px; }", Author, error_reporter)];
stylesheet!("@viewport { min-width: 100px; min-height: 100px; zoom: 1; }",
UserAgent, error_reporter, shared_lock.clone()),
stylesheet!("@viewport { min-width: 200px; min-height: 200px; }",
User, error_reporter, shared_lock.clone()),
stylesheet!("@viewport { min-width: 300px; }",
Author, error_reporter, shared_lock.clone())
];
let declarations = Cascade::from_stylesheets(&stylesheets, &device).finish();
let declarations = Cascade::from_stylesheets(&stylesheets, &shared_lock.read(), &device).finish();
assert_decl_len!(declarations == 3);
assert_decl_eq!(&declarations[0], UserAgent, Zoom: Zoom::Number(1.));
assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px));
assert_decl_eq!(&declarations[2], Author, MinWidth: viewport_length!(300., px));
let stylesheets = vec![
stylesheet!("@viewport { min-width: 100px !important; }", UserAgent, error_reporter),
stylesheet!("@viewport { min-width: 100px !important; }",
UserAgent, error_reporter, shared_lock.clone()),
stylesheet!("@viewport { min-width: 200px !important; min-height: 200px !important; }",
User, error_reporter),
User, error_reporter, shared_lock.clone()),
stylesheet!("@viewport { min-width: 300px !important; min-height: 300px !important; zoom: 3 !important; }",
Author, error_reporter)];
let declarations = Cascade::from_stylesheets(&stylesheets, &device).finish();
Author, error_reporter, shared_lock.clone())
];
let declarations = Cascade::from_stylesheets(&stylesheets, &shared_lock.read(), &device).finish();
assert_decl_len!(declarations == 3);
assert_decl_eq!(&declarations[0], UserAgent, MinWidth: viewport_length!(100., px), !important);
assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px), !important);

View File

@ -21,8 +21,5 @@ extern crate style_traits;
mod sanity_checks;
mod size_of;
#[path = "../../../ports/geckolib/stylesheet_loader.rs"]
mod stylesheet_loader;
mod servo_function_signatures;

View File

@ -10,6 +10,9 @@ use style::gecko_properties::*;
include!(concat!(env!("OUT_DIR"), "/check_bindings.rs"));
#[path = "../../../ports/geckolib/stylesheet_loader.rs"]
mod stylesheet_loader;
#[allow(non_snake_case, unused_unsafe, private_no_mangle_fns)]
mod glue {
// this module pretends to be glue.rs, with the safe functions swapped for unsafe ones. This is