Skip to content

Commit

Permalink
Replace RwLock<MediaList> with shared_lock::Locked<MediaList>
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonSapin committed Mar 19, 2017
1 parent 8feb9e8 commit c5a7294
Show file tree
Hide file tree
Showing 18 changed files with 117 additions and 42 deletions.
17 changes: 12 additions & 5 deletions components/layout_thread/lib.rs
Expand Up @@ -115,6 +115,7 @@ use style::logical_geometry::LogicalPoint;
use style::media_queries::{Device, MediaType};
use style::parser::ParserContextExtraData;
use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION, STORE_OVERFLOW};
use style::shared_lock::SharedRwLock;
use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets};
use style::stylist::Stylist;
use style::thread_state;
Expand Down Expand Up @@ -934,6 +935,7 @@ impl LayoutThread {
possibly_locked_rw_data: &mut RwData<'a, 'b>) {
let document = unsafe { ServoLayoutNode::new(&data.document) };
let document = document.as_document().unwrap();
let style_guard = document.style_shared_lock().read();
self.quirks_mode = Some(document.quirks_mode());

// FIXME(pcwalton): Combine `ReflowGoal` and `ReflowQueryType`. Then remove this assert.
Expand Down Expand Up @@ -1010,7 +1012,8 @@ impl LayoutThread {

// Calculate the actual viewport as per DEVICE-ADAPT § 6
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, &style_guard, &data.document_stylesheets);

self.viewport_size =
rw_data.stylist.viewport_constraints().map_or(current_screen_size, |constraints| {
Expand Down Expand Up @@ -1528,7 +1531,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,
Expand All @@ -1537,26 +1541,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,
})
Expand Down
2 changes: 2 additions & 0 deletions components/script/dom/bindings/trace.rs
Expand Up @@ -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;
use style::stylesheets::{CssRules, KeyframesRule, MediaRule, NamespaceRule, StyleRule, ImportRule};
use style::stylesheets::SupportsRule;
use style::values::specified::Length;
Expand Down Expand Up @@ -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);
Expand Down
16 changes: 16 additions & 0 deletions components/script/dom/document.rs
Expand Up @@ -134,6 +134,7 @@ 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::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;
Expand Down Expand Up @@ -220,6 +221,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.
Expand Down Expand Up @@ -1964,6 +1968,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)]
Expand Down Expand Up @@ -2000,6 +2005,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
Expand Down Expand Up @@ -2121,6 +2131,7 @@ impl Document {
scripts: Default::default(),
anchors: Default::default(),
applets: Default::default(),
style_shared_lock: StyleSharedRwLock::new(),
stylesheets: DOMRefCell::new(None),
stylesheets_changed_since_reflow: Cell::new(false),
stylesheet_list: MutNullableJS::new(None),
Expand Down Expand Up @@ -2250,6 +2261,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();
Expand Down
5 changes: 4 additions & 1 deletion components/script/dom/htmlmetaelement.rs
Expand Up @@ -99,12 +99,15 @@ 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();
*self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet {
rules: CssRules::new(vec![CssRule::Viewport(Arc::new(RwLock::new(translated_rule)))]),
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),
Expand Down
3 changes: 2 additions & 1 deletion components/script/dom/htmlstyleelement.rs
Expand Up @@ -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());

Expand Down
5 changes: 5 additions & 0 deletions components/script/layout_wrapper.rs
Expand Up @@ -69,6 +69,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;
use style::sink::Push;
use style::str::is_whitespace;
use style::stylist::ApplicableDeclarationBlock;
Expand Down Expand Up @@ -330,6 +331,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,
Expand Down
2 changes: 2 additions & 0 deletions components/script/stylesheet_loader.rs
Expand Up @@ -152,12 +152,14 @@ impl FetchResponseListener for StylesheetContext {
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()));
Expand Down
3 changes: 3 additions & 0 deletions components/style/encoding_support.rs
Expand Up @@ -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};

Expand Down Expand Up @@ -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)
Expand All @@ -64,6 +66,7 @@ impl Stylesheet {
base_url,
origin,
media,
shared_lock,
stylesheet_loader,
error_reporter,
extra_data)
Expand Down
37 changes: 26 additions & 11 deletions components/style/stylesheets.rs
Expand Up @@ -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, SharedRwLockReadGuard};
use std::cell::Cell;
use std::fmt;
use std::sync::Arc;
Expand Down Expand Up @@ -175,11 +176,13 @@ pub struct Stylesheet {
/// cascading order)
pub rules: Arc<RwLock<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.
Expand All @@ -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.
Expand Down Expand Up @@ -291,12 +296,12 @@ 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 media = rule.stylesheet.media.read_with(guard);
let rules = rule.stylesheet.rules.read();
// FIXME(emilio): Include the nested rules if the stylesheet is
// loaded.
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -424,7 +430,8 @@ impl ToCss for ImportRule {
fn to_css<W>(&self, 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 guard = self.stylesheet.shared_lock.read(); // FIXME: have the caller pass this?
let media = self.stylesheet.media.read_with(&guard);
if !media.is_empty() {
try!(dest.write_str(" "));
try!(media.to_css(dest));
Expand Down Expand Up @@ -554,6 +561,7 @@ impl Stylesheet {
let rule_parser = TopLevelRuleParser {
stylesheet_origin: existing.origin,
namespaces: &mut namespaces,
shared_lock: &existing.shared_lock,
loader: stylesheet_loader,
context: ParserContext::new_with_extra_data(existing.origin,
&existing.base_url,
Expand Down Expand Up @@ -591,6 +599,7 @@ impl Stylesheet {
base_url: ServoUrl,
origin: Origin,
media: MediaList,
shared_lock: SharedRwLock,
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData) -> Stylesheet {
Expand All @@ -599,7 +608,8 @@ impl Stylesheet {
base_url: base_url,
namespaces: RwLock::new(Namespaces::default()),
rules: CssRules::new(vec![]),
media: Arc::new(RwLock::new(media)),
media: Arc::new(shared_lock.wrap(media)),
shared_lock: shared_lock.clone(),
dirty_on_viewport_size_change: AtomicBool::new(false),
disabled: AtomicBool::new(false),
};
Expand Down Expand Up @@ -638,7 +648,8 @@ impl Stylesheet {
///
/// Always true if no associated MediaList exists.
pub fn is_effective_for_device(&self, device: &Device) -> bool {
self.media.read().evaluate(device)
let guard = self.shared_lock.read(); // FIXME: have the caller pass this?
self.media.read_with(&guard).evaluate(device)
}

/// Return an iterator over the effective rules within the style-sheet, as
Expand All @@ -649,7 +660,8 @@ impl Stylesheet {
/// 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);
let guard = self.shared_lock.read(); // FIXME: have the caller pass this?
effective_rules(&self.rules.read().0, device, &guard, &mut f);
}

/// Returns whether the stylesheet has been explicitly disabled through the
Expand All @@ -670,16 +682,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)
})
}
}
Expand Down Expand Up @@ -724,6 +737,7 @@ pub trait StylesheetLoader {
struct TopLevelRuleParser<'a> {
stylesheet_origin: Origin,
namespaces: &'a mut Namespaces,
shared_lock: &'a SharedRwLock,
loader: Option<&'a StylesheetLoader>,
context: ParserContext<'a>,
state: Cell<State>,
Expand Down Expand Up @@ -780,7 +794,7 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
&self.context));

let media =
Arc::new(RwLock::new(parse_media_query_list(input)));
Arc::new(self.shared_lock.wrap(parse_media_query_list(input)));

let is_valid_url = url.url().is_some();

Expand All @@ -790,6 +804,7 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
stylesheet: Arc::new(Stylesheet {
rules: Arc::new(RwLock::new(CssRules(vec![]))),
media: media,
shared_lock: self.shared_lock.clone(),
origin: self.context.stylesheet_origin,
base_url: self.context.base_url.clone(),
namespaces: RwLock::new(Namespaces::default()),
Expand Down

0 comments on commit c5a7294

Please sign in to comment.