Parse stylesheets without acquiring a shared lock.

This commit is contained in:
Simon Sapin 2017-03-18 14:25:25 +01:00
parent cc046300f0
commit d9491187dc
4 changed files with 42 additions and 42 deletions

View file

@ -159,13 +159,10 @@ impl FetchResponseListener for StylesheetContext {
}
}
StylesheetContextSource::Import(ref stylesheet) => {
let mut guard = document.style_shared_lock().write();
Stylesheet::update_from_bytes(&stylesheet,
&data,
protocol_encoding_label,
Some(environment_encoding),
&mut guard,
Some(&loader),
win.css_error_reporter(),
ParserContextExtraData::default());

View file

@ -12,7 +12,7 @@ use media_queries::MediaList;
use parser::ParserContextExtraData;
use self::encoding::{EncodingRef, DecoderTrap};
use servo_url::ServoUrl;
use shared_lock::{SharedRwLock, SharedRwLockWriteGuard};
use shared_lock::SharedRwLock;
use std::str;
use stylesheets::{Stylesheet, StylesheetLoader, Origin};
@ -78,7 +78,6 @@ impl Stylesheet {
bytes: &[u8],
protocol_encoding_label: Option<&str>,
environment_encoding: Option<EncodingRef>,
guard: &mut SharedRwLockWriteGuard,
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData) {
@ -86,7 +85,6 @@ impl Stylesheet {
bytes, protocol_encoding_label, environment_encoding);
Self::update_from_str(existing,
&string,
guard,
stylesheet_loader,
error_reporter,
extra_data)

View file

@ -21,8 +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};
use shared_lock::{SharedRwLockReadGuard, SharedRwLockWriteGuard};
use shared_lock::{SharedRwLock, Locked, ToCssWithGuard, SharedRwLockReadGuard};
use std::cell::Cell;
use std::fmt;
use std::sync::Arc;
@ -556,23 +555,42 @@ impl Stylesheet {
/// Updates an empty stylesheet from a given string of text.
pub fn update_from_str(existing: &Stylesheet,
css: &str,
guard: &mut SharedRwLockWriteGuard,
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData) {
let mut rules = existing.rules.write_with(guard);
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,
shared_lock: &existing.shared_lock,
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),
@ -584,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));
@ -594,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
@ -611,28 +628,21 @@ impl Stylesheet {
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::new(), &shared_lock),
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(false),
dirty_on_viewport_size_change: AtomicBool::new(dirty_on_viewport_size_change),
disabled: AtomicBool::new(false),
};
{
let mut guard = s.shared_lock.write();
Self::update_from_str(&s,
css,
&mut guard,
stylesheet_loader,
error_reporter,
extra_data);
}
s
}
/// Whether this stylesheet can be dirty on viewport size change.

View file

@ -362,8 +362,6 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet
referrer: *mut ThreadSafeURIHolder,
principal: *mut ThreadSafePrincipalHolder)
{
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let input = unsafe { data.as_ref().unwrap().as_str_unchecked() };
let extra_data = unsafe { ParserContextExtraData {
base: Some(GeckoArcURI::new(base)),
@ -384,10 +382,7 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet
};
let sheet = Stylesheet::as_arc(&stylesheet);
sheet.rules.write_with(&mut guard).0.clear();
Stylesheet::update_from_str(&sheet, input, &mut guard, loader,
&StdoutErrorReporter, extra_data);
Stylesheet::update_from_str(&sheet, input, loader, &StdoutErrorReporter, extra_data);
}
#[no_mangle]