mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 11:55:49 +00:00
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:
parent
3fad952356
commit
33a9e6d050
5
servo/Cargo.lock
generated
5
servo/Cargo.lock
generated
@ -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)",
|
||||
|
@ -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]
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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>>,
|
||||
|
@ -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.
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
})
|
||||
|
@ -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.
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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 can’t 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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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()))
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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(),
|
||||
|
@ -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>) {
|
||||
|
@ -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),
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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"
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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>,
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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, ": "))?;
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
50
servo/components/style/gecko/global_style_data.rs
Normal file
50
servo/components/style/gecko/global_style_data.rs
Normal 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(),
|
||||
}
|
||||
};
|
||||
}
|
@ -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;
|
||||
|
@ -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>)
|
||||
{
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)),
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
}
|
||||
|
199
servo/components/style/shared_lock.rs
Normal file
199
servo/components/style/shared_lock.rs
Normal 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 we’ve checked that it’s 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 we’ve checked that it’s 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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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 they’re 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))
|
||||
}))))
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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"]}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 won’t,
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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()
|
||||
))
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
@ -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));
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user