diff --git a/components/style/binding_tools/regen.py b/components/style/binding_tools/regen.py index 62302733fac..3c2fbccb8b0 100755 --- a/components/style/binding_tools/regen.py +++ b/components/style/binding_tools/regen.py @@ -309,7 +309,7 @@ COMPILATION_TARGETS = { ], "servo_nullable_arc_types": [ "ServoComputedValues", "RawServoStyleSheet", - "ServoDeclarationBlock" + "RawServoDeclarationBlock" ], "servo_owned_types": [ "RawServoStyleSet", @@ -319,6 +319,7 @@ COMPILATION_TARGETS = { "RawGeckoNode", "RawGeckoElement", "RawGeckoDocument", + "RawServoDeclarationBlockStrong", ], "whitelist_functions": [ "Servo_.*", diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 999ca1071ca..bb8ba94fc16 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -9,10 +9,11 @@ #![allow(unsafe_code)] use app_units::Au; -use gecko_bindings::bindings::{RawServoStyleSheet, ServoComputedValues}; +use gecko_bindings::bindings::{RawServoStyleSheet, ServoComputedValues, RawServoDeclarationBlock}; use gecko_bindings::structs::nsStyleCoord_CalcValue; use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI}; -use properties::ComputedValues; +use parking_lot::RwLock; +use properties::{ComputedValues, PropertyDeclarationBlock}; use stylesheets::Stylesheet; use values::computed::{CalcLengthOrPercentage, LengthOrPercentage, LengthOrPercentageOrAuto}; @@ -25,6 +26,11 @@ unsafe impl HasFFI for ComputedValues { } unsafe impl HasArcFFI for ComputedValues {} +unsafe impl HasFFI for RwLock { + type FFIType = RawServoDeclarationBlock; +} +unsafe impl HasArcFFI for RwLock {} + impl From for nsStyleCoord_CalcValue { fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue { let has_percentage = other.percentage.is_some(); diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 621fef9b5fa..d0dc0b7d9ff 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -30,7 +30,7 @@ use gecko_bindings::structs::{NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO, NODE_IS_DIRT use gecko_bindings::structs::{RawGeckoDocument, RawGeckoElement, RawGeckoNode}; use gecko_bindings::structs::{nsChangeHint, nsIAtom, nsIContent, nsStyleContext}; use gecko_bindings::structs::OpaqueStyleData; -use gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasFFI}; +use gecko_bindings::sugar::ownership::FFIArcHelpers; use libc::uintptr_t; use parking_lot::RwLock; use parser::ParserContextExtraData; @@ -45,7 +45,6 @@ use std::fmt; use std::ops::BitOr; use std::ptr; use std::sync::Arc; -use std::sync::atomic::{AtomicBool, AtomicPtr}; use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; use url::Url; @@ -57,35 +56,6 @@ impl NonOpaqueStyleData { } } - -pub struct GeckoDeclarationBlock { - pub declarations: Option>>, - // XXX The following two fields are made atomic to work around the - // ownership system so that they can be changed inside a shared - // instance. It wouldn't provide safety as Rust usually promises, - // but it is fine as far as we only access them in a single thread. - // If we need to access them in different threads, we would need - // to redesign how it works with MiscContainer in Gecko side. - pub cache: AtomicPtr, - pub immutable: AtomicBool, -} - -impl PartialEq for GeckoDeclarationBlock { - fn eq(&self, other: &GeckoDeclarationBlock) -> bool { - match (&self.declarations, &other.declarations) { - (&None, &None) => true, - (&Some(ref s), &Some(ref other)) => *s.read() == *other.read(), - _ => false, - } - } -} - -unsafe impl HasFFI for GeckoDeclarationBlock { - type FFIType = bindings::ServoDeclarationBlock; -} -unsafe impl HasArcFFI for GeckoDeclarationBlock {} - - // We can eliminate OpaqueStyleData when the bindings move into the style crate. fn to_opaque_style_data(d: *mut NonOpaqueStyleData) -> *mut OpaqueStyleData { d as *mut OpaqueStyleData @@ -438,8 +408,8 @@ impl<'a> Iterator for GeckoChildrenIterator<'a> { *self = GeckoChildrenIterator::Current(next); curr }, - GeckoChildrenIterator::GeckoIterator(ref it) => unsafe { - Gecko_GetNextStyleChild(&it).map(GeckoNode) + GeckoChildrenIterator::GeckoIterator(ref mut it) => unsafe { + Gecko_GetNextStyleChild(it).map(GeckoNode) } } } @@ -486,13 +456,13 @@ impl<'le> fmt::Debug for GeckoElement<'le> { } impl<'le> GeckoElement<'le> { - pub fn parse_style_attribute(value: &str) -> Option { + pub fn parse_style_attribute(value: &str) -> PropertyDeclarationBlock { // FIXME(bholley): Real base URL and error reporter. let base_url = &*DUMMY_BASE_URL; // FIXME(heycam): Needs real ParserContextExtraData so that URLs parse // properly. let extra_data = ParserContextExtraData::default(); - Some(parse_style_attribute(value, &base_url, Box::new(StdoutErrorReporter), extra_data)) + parse_style_attribute(value, &base_url, Box::new(StdoutErrorReporter), extra_data) } } @@ -512,12 +482,7 @@ impl<'le> TElement for GeckoElement<'le> { fn style_attribute(&self) -> Option<&Arc>> { let declarations = unsafe { Gecko_GetServoDeclarationBlock(self.0) }; - if declarations.is_none() { - None - } else { - let declarations = GeckoDeclarationBlock::arc_from_borrowed(&declarations).unwrap(); - declarations.declarations.as_ref().map(|r| r as *const Arc<_>).map(|ptr| unsafe { &*ptr }) - } + declarations.map(|s| s.as_arc_opt()).unwrap_or(None) } fn get_state(&self) -> ElementState { diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index 4def95850e1..53276228757 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -10,17 +10,19 @@ pub type RawServoStyleSheetBorrowedOrNull<'a> = Option<&'a RawServoStyleSheet>; pub type RawServoStyleSheetBorrowed<'a> = &'a RawServoStyleSheet; enum RawServoStyleSheetVoid{ } pub struct RawServoStyleSheet(RawServoStyleSheetVoid); -pub type ServoDeclarationBlockStrong = ::gecko_bindings::sugar::ownership::Strong; -pub type ServoDeclarationBlockBorrowedOrNull<'a> = Option<&'a ServoDeclarationBlock>; -pub type ServoDeclarationBlockBorrowed<'a> = &'a ServoDeclarationBlock; -enum ServoDeclarationBlockVoid{ } -pub struct ServoDeclarationBlock(ServoDeclarationBlockVoid); +pub type RawServoDeclarationBlockStrong = ::gecko_bindings::sugar::ownership::Strong; +pub type RawServoDeclarationBlockBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlock>; +pub type RawServoDeclarationBlockBorrowed<'a> = &'a RawServoDeclarationBlock; +enum RawServoDeclarationBlockVoid{ } +pub struct RawServoDeclarationBlock(RawServoDeclarationBlockVoid); pub type RawGeckoNodeBorrowed<'a> = &'a RawGeckoNode; pub type RawGeckoNodeBorrowedOrNull<'a> = Option<&'a RawGeckoNode>; pub type RawGeckoElementBorrowed<'a> = &'a RawGeckoElement; pub type RawGeckoElementBorrowedOrNull<'a> = Option<&'a RawGeckoElement>; pub type RawGeckoDocumentBorrowed<'a> = &'a RawGeckoDocument; pub type RawGeckoDocumentBorrowedOrNull<'a> = Option<&'a RawGeckoDocument>; +pub type RawServoDeclarationBlockStrongBorrowed<'a> = &'a RawServoDeclarationBlockStrong; +pub type RawServoDeclarationBlockStrongBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlockStrong>; pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet; pub type RawServoStyleSetBorrowedMut<'a> = &'a mut RawServoStyleSet; pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned; @@ -176,14 +178,6 @@ extern "C" { pub fn Gecko_ClearPODTArray(aArray: *mut ::std::os::raw::c_void, aElementSize: usize, aElementAlign: usize); } -#[repr(C)] -#[derive(Debug, Copy)] -pub struct nsHTMLCSSStyleSheet { - pub _address: u8, -} -impl Clone for nsHTMLCSSStyleSheet { - fn clone(&self) -> Self { *self } -} extern "C" { pub fn Gecko_ChildrenCount(node: RawGeckoNodeBorrowed) -> u32; } @@ -242,7 +236,7 @@ extern "C" { pub fn Gecko_DropStyleChildrenIterator(it: StyleChildrenIteratorOwned); } extern "C" { - pub fn Gecko_GetNextStyleChild(it: StyleChildrenIteratorBorrowed) + pub fn Gecko_GetNextStyleChild(it: StyleChildrenIteratorBorrowedMut) -> RawGeckoNodeBorrowedOrNull; } extern "C" { @@ -370,7 +364,7 @@ extern "C" { } extern "C" { pub fn Gecko_GetServoDeclarationBlock(element: RawGeckoElementBorrowed) - -> ServoDeclarationBlockBorrowedOrNull; + -> RawServoDeclarationBlockStrongBorrowedOrNull; } extern "C" { pub fn Gecko_Atomize(aString: *const ::std::os::raw::c_char, aLength: u32) @@ -865,49 +859,35 @@ extern "C" { base: *mut ThreadSafeURIHolder, referrer: *mut ThreadSafeURIHolder, principal: *mut ThreadSafePrincipalHolder) - -> ServoDeclarationBlockStrong; + -> RawServoDeclarationBlockStrong; } extern "C" { pub fn Servo_RestyleWithAddedDeclaration(declarations: - ServoDeclarationBlockBorrowed, + RawServoDeclarationBlockBorrowed, previous_style: ServoComputedValuesBorrowed) -> ServoComputedValuesStrong; } extern "C" { - pub fn Servo_ParseStyleAttribute(bytes: *const u8, length: u32, - cache: *mut nsHTMLCSSStyleSheet) - -> ServoDeclarationBlockStrong; + pub fn Servo_ParseStyleAttribute(bytes: *const u8, length: u32) + -> RawServoDeclarationBlockStrong; } extern "C" { pub fn Servo_DeclarationBlock_AddRef(declarations: - ServoDeclarationBlockBorrowed); + RawServoDeclarationBlockBorrowed); } extern "C" { pub fn Servo_DeclarationBlock_Release(declarations: - ServoDeclarationBlockBorrowed); + RawServoDeclarationBlockBorrowed); } extern "C" { - pub fn Servo_DeclarationBlock_Equals(a: ServoDeclarationBlockBorrowed, - b: ServoDeclarationBlockBorrowed) + pub fn Servo_DeclarationBlock_Equals(a: RawServoDeclarationBlockBorrowed, + b: RawServoDeclarationBlockBorrowed) -> bool; } -extern "C" { - pub fn Servo_DeclarationBlock_GetCache(declarations: - ServoDeclarationBlockBorrowed) - -> *mut nsHTMLCSSStyleSheet; -} -extern "C" { - pub fn Servo_DeclarationBlock_SetImmutable(declarations: - ServoDeclarationBlockBorrowed); -} -extern "C" { - pub fn Servo_DeclarationBlock_ClearCachePointer(declarations: - ServoDeclarationBlockBorrowed); -} extern "C" { pub fn Servo_DeclarationBlock_SerializeOneValue(declarations: - ServoDeclarationBlockBorrowed, + RawServoDeclarationBlockBorrowed, buffer: *mut nsString); } extern "C" { diff --git a/components/style/gecko_bindings/sugar/ownership.rs b/components/style/gecko_bindings/sugar/ownership.rs index bd3148366bb..4b5401f3eaf 100644 --- a/components/style/gecko_bindings/sugar/ownership.rs +++ b/components/style/gecko_bindings/sugar/ownership.rs @@ -161,6 +161,20 @@ impl Strong { } } + #[inline] + /// Given a reference to a strong FFI reference, + /// converts it to a reference to a servo-side Arc + /// Returns None on null. + /// + /// Strong -> Arc + pub fn as_arc_opt(&self) -> Option<&Arc> where U: HasArcFFI { + if self.is_null() { + None + } else { + unsafe { Some(transmute(self)) } + } + } + #[inline] /// Produces a null strong FFI reference pub fn null() -> Self { diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 124e75072cd..c540e21684f 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -8,11 +8,9 @@ use env_logger; use euclid::Size2D; use parking_lot::RwLock; use std::mem::transmute; -use std::ptr; use std::slice; use std::str::from_utf8_unchecked; use std::sync::{Arc, Mutex}; -use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; use style::arc_ptr_eq; use style::context::{LocalStyleContextCreationInfo, ReflowGoal, SharedStyleContext}; use style::dom::{NodeInfo, TElement, TNode}; @@ -21,16 +19,16 @@ use style::gecko::data::{NUM_THREADS, PerDocumentStyleData}; use style::gecko::selector_impl::{GeckoSelectorImpl, PseudoElement}; use style::gecko::snapshot::GeckoElementSnapshot; use style::gecko::traversal::RecalcStyleOnly; -use style::gecko::wrapper::{DUMMY_BASE_URL, GeckoDeclarationBlock}; use style::gecko::wrapper::{GeckoElement, GeckoNode}; +use style::gecko::wrapper::DUMMY_BASE_URL; use style::gecko_bindings::bindings::{RawGeckoElementBorrowed, RawGeckoNodeBorrowed}; +use style::gecko_bindings::bindings::{RawServoDeclarationBlockBorrowed, RawServoDeclarationBlockStrong}; use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSetOwned}; use style::gecko_bindings::bindings::{RawServoStyleSheetBorrowed, ServoComputedValuesBorrowed}; use style::gecko_bindings::bindings::{RawServoStyleSheetStrong, ServoComputedValuesStrong}; -use style::gecko_bindings::bindings::{ServoDeclarationBlockBorrowed, ServoDeclarationBlockStrong}; use style::gecko_bindings::bindings::{ThreadSafePrincipalHolder, ThreadSafeURIHolder}; -use style::gecko_bindings::bindings::{nsHTMLCSSStyleSheet, ServoComputedValuesBorrowedOrNull}; use style::gecko_bindings::bindings::Gecko_Utf8SliceToString; +use style::gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull; use style::gecko_bindings::structs::{SheetParsingMode, nsIAtom}; use style::gecko_bindings::structs::ServoElementSnapshot; use style::gecko_bindings::structs::nsRestyleHint; @@ -127,32 +125,28 @@ pub extern "C" fn Servo_RestyleSubtree(node: RawGeckoNodeBorrowed, } #[no_mangle] -pub extern "C" fn Servo_RestyleWithAddedDeclaration(declarations: ServoDeclarationBlockBorrowed, +pub extern "C" fn Servo_RestyleWithAddedDeclaration(declarations: RawServoDeclarationBlockBorrowed, previous_style: ServoComputedValuesBorrowed) -> ServoComputedValuesStrong { - match GeckoDeclarationBlock::as_arc(&declarations).declarations { - Some(ref declarations) => { - let declaration_block = ApplicableDeclarationBlock { - mixed_declarations: declarations.clone(), - importance: Importance::Normal, - source_order: 0, - specificity: ::std::u32::MAX, - }; - let previous_style = ComputedValues::as_arc(&previous_style); + let declarations = RwLock::::as_arc(&declarations); + let declaration_block = ApplicableDeclarationBlock { + mixed_declarations: declarations.clone(), + importance: Importance::Normal, + source_order: 0, + specificity: ::std::u32::MAX, + }; + let previous_style = ComputedValues::as_arc(&previous_style); - // FIXME (bug 1303229): Use the actual viewport size here - let (computed, _) = cascade(Size2D::new(Au(0), Au(0)), - &[declaration_block], - false, - Some(previous_style), - None, - None, - Box::new(StdoutErrorReporter)); - Arc::new(computed).into_strong() - }, - None => ServoComputedValuesStrong::null(), - } + // FIXME (bug 1303229): Use the actual viewport size here + let (computed, _) = cascade(Size2D::new(Au(0), Au(0)), + &[declaration_block], + false, + Some(previous_style), + None, + None, + Box::new(StdoutErrorReporter)); + Arc::new(computed).into_strong() } #[no_mangle] @@ -381,7 +375,7 @@ pub extern "C" fn Servo_ParseProperty(property_bytes: *const u8, base: *mut ThreadSafeURIHolder, referrer: *mut ThreadSafeURIHolder, principal: *mut ThreadSafePrincipalHolder) - -> ServoDeclarationBlockStrong { + -> RawServoDeclarationBlockStrong { // All this string wrangling is temporary until the Gecko string bindings land (bug 1294742). let name = unsafe { from_utf8_unchecked(slice::from_raw_parts(property_bytes, property_length as usize)) }; @@ -404,97 +398,70 @@ pub extern "C" fn Servo_ParseProperty(property_bytes: *const u8, match PropertyDeclaration::parse(name, &context, &mut Parser::new(value_str), &mut results, false) { PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {}, - _ => return ServoDeclarationBlockStrong::null(), + _ => return RawServoDeclarationBlockStrong::null(), } let results = results.into_iter().map(|r| (r, Importance::Normal)).collect(); - Arc::new(GeckoDeclarationBlock { - declarations: Some(Arc::new(RwLock::new(PropertyDeclarationBlock { - declarations: results, - important_count: 0, - }))), - cache: AtomicPtr::new(ptr::null_mut()), - immutable: AtomicBool::new(false), - }).into_strong() + Arc::new(RwLock::new(PropertyDeclarationBlock { + declarations: results, + important_count: 0, + })).into_strong() } + #[no_mangle] -pub extern "C" fn Servo_ParseStyleAttribute(bytes: *const u8, length: u32, - cache: *mut nsHTMLCSSStyleSheet) - -> ServoDeclarationBlockStrong { +pub extern "C" fn Servo_ParseStyleAttribute(bytes: *const u8, length: u32) + -> RawServoDeclarationBlockStrong { let value = unsafe { from_utf8_unchecked(slice::from_raw_parts(bytes, length as usize)) }; - Arc::new(GeckoDeclarationBlock { - declarations: GeckoElement::parse_style_attribute(value).map(|block| { - Arc::new(RwLock::new(block)) - }), - cache: AtomicPtr::new(cache), - immutable: AtomicBool::new(false), - }).into_strong() + Arc::new(RwLock::new(GeckoElement::parse_style_attribute(value))).into_strong() } #[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_AddRef(declarations: ServoDeclarationBlockBorrowed) { - unsafe { GeckoDeclarationBlock::addref(declarations) }; +pub extern "C" fn Servo_DeclarationBlock_AddRef(declarations: RawServoDeclarationBlockBorrowed) { + unsafe { RwLock::::addref(declarations) }; } #[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_Release(declarations: ServoDeclarationBlockBorrowed) { - unsafe { GeckoDeclarationBlock::release(declarations) }; +pub extern "C" fn Servo_DeclarationBlock_Release(declarations: RawServoDeclarationBlockBorrowed) { + unsafe { RwLock::::release(declarations) }; } #[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_Equals(a: ServoDeclarationBlockBorrowed, - b: ServoDeclarationBlockBorrowed) +pub extern "C" fn Servo_DeclarationBlock_Equals(a: RawServoDeclarationBlockBorrowed, + b: RawServoDeclarationBlockBorrowed) -> bool { - GeckoDeclarationBlock::as_arc(&a) == GeckoDeclarationBlock::as_arc(&b) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_GetCache(declarations: ServoDeclarationBlockBorrowed) - -> *mut nsHTMLCSSStyleSheet { - GeckoDeclarationBlock::as_arc(&declarations).cache.load(Ordering::Relaxed) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_SetImmutable(declarations: ServoDeclarationBlockBorrowed) { - GeckoDeclarationBlock::as_arc(&declarations).immutable.store(true, Ordering::Relaxed) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_ClearCachePointer(declarations: ServoDeclarationBlockBorrowed) { - GeckoDeclarationBlock::as_arc(&declarations).cache.store(ptr::null_mut(), Ordering::Relaxed) + *RwLock::::as_arc(&a).read() == *RwLock::::as_arc(&b).read() } #[no_mangle] pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue( - declarations: ServoDeclarationBlockBorrowed, + declarations: RawServoDeclarationBlockBorrowed, buffer: *mut nsString) { let mut string = String::new(); - if let Some(ref declarations) = GeckoDeclarationBlock::as_arc(&declarations).declarations { - declarations.read().to_css(&mut string).unwrap(); - // FIXME: We are expecting |declarations| to be a declaration block with either a single - // longhand property-declaration or a series of longhand property-declarations that make - // up a single shorthand property. As a result, it should be possible to serialize - // |declarations| as a single declaration. However, we only want to return the *value* from - // that single declaration. For now, we just manually strip the property name, colon, - // leading spacing, and trailing space. In future we should find a more robust way to do - // this. - // - // See https://github.com/servo/servo/issues/13423 - debug_assert!(string.find(':').is_some()); - let position = string.find(':').unwrap(); - // Get the value after the first colon and any following whitespace. - let value = &string[(position + 1)..].trim_left(); - debug_assert!(value.ends_with(';')); - let length = value.len() - 1; // Strip last semicolon. + let declarations = RwLock::::as_arc(&declarations); + declarations.read().to_css(&mut string).unwrap(); + // FIXME: We are expecting |declarations| to be a declaration block with either a single + // longhand property-declaration or a series of longhand property-declarations that make + // up a single shorthand property. As a result, it should be possible to serialize + // |declarations| as a single declaration. However, we only want to return the *value* from + // that single declaration. For now, we just manually strip the property name, colon, + // leading spacing, and trailing space. In future we should find a more robust way to do + // this. + // + // See https://github.com/servo/servo/issues/13423 + debug_assert!(string.find(':').is_some()); + let position = string.find(':').unwrap(); + // Get the value after the first colon and any following whitespace. + let value = &string[(position + 1)..].trim_left(); + debug_assert!(value.ends_with(';')); + let length = value.len() - 1; // Strip last semicolon. - // FIXME: Once we have nsString bindings for Servo (bug 1294742), we should be able to drop - // this and fill in |buffer| directly. - unsafe { - Gecko_Utf8SliceToString(buffer, value.as_ptr(), length); - } + // FIXME: Once we have nsString bindings for Servo (bug 1294742), we should be able to drop + // this and fill in |buffer| directly. + unsafe { + Gecko_Utf8SliceToString(buffer, value.as_ptr(), length); } }