diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2016-10-13 22:31:20 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-13 22:31:20 -0500 |
commit | 41df7056610e474a9a2efe4c807f480e976d0c1d (patch) | |
tree | eba7b6638a0c97e5454dfe81c31555445280f97d | |
parent | a80abf6c1dd0f14b40499d55129a53d397c3a3cd (diff) | |
parent | bb736f41d32c1cb6117bbf327f2a6efa7deebd0c (diff) | |
download | servo-41df7056610e474a9a2efe4c807f480e976d0c1d.tar.gz servo-41df7056610e474a9a2efe4c807f480e976d0c1d.zip |
Auto merge of #13754 - Manishearth:refptr, r=emilio,mystor
Add sugar for RefPtr<T>; use for `quotes` property
Carry-over from https://bugzilla.mozilla.org/show_bug.cgi?id=1309848
r=mystor,emilio
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13754)
<!-- Reviewable:end -->
-rwxr-xr-x | components/style/binding_tools/regen.py | 2 | ||||
-rw-r--r-- | components/style/gecko_bindings/bindings.rs | 14 | ||||
-rw-r--r-- | components/style/gecko_bindings/mod.rs | 1 | ||||
-rw-r--r-- | components/style/gecko_bindings/ptr.rs | 64 | ||||
-rw-r--r-- | components/style/gecko_bindings/sugar/mod.rs | 1 | ||||
-rw-r--r-- | components/style/gecko_bindings/sugar/refptr.rs | 237 | ||||
-rw-r--r-- | components/style/parser.rs | 2 | ||||
-rw-r--r-- | components/style/properties/gecko.mako.rs | 29 | ||||
-rw-r--r-- | components/style/properties/longhand/box.mako.rs | 2 | ||||
-rw-r--r-- | components/style/properties/longhand/list.mako.rs | 2 | ||||
-rw-r--r-- | components/style/values/specified/mod.rs | 2 | ||||
-rw-r--r-- | ports/geckolib/glue.rs | 10 |
12 files changed, 287 insertions, 79 deletions
diff --git a/components/style/binding_tools/regen.py b/components/style/binding_tools/regen.py index d179cc879f4..792b24e9656 100755 --- a/components/style/binding_tools/regen.py +++ b/components/style/binding_tools/regen.py @@ -228,7 +228,7 @@ COMPILATION_TARGETS = { "StyleBasicShapeType", "StyleBasicShape", "nsCSSShadowArray", "nsIPrincipal", "nsIURI", "RawGeckoNode", "RawGeckoElement", "RawGeckoDocument", - "nsString" + "nsString", "nsStyleQuoteValues" ], "servo_nullable_arc_types": [ "ServoComputedValues", "RawServoStyleSheet", diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index a7efe16be71..4def95850e1 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -164,6 +164,9 @@ use gecko_bindings::structs::RawGeckoNode; use gecko_bindings::structs::RawGeckoElement; use gecko_bindings::structs::RawGeckoDocument; use gecko_bindings::structs::nsString; +use gecko_bindings::structs::nsStyleQuoteValues; +unsafe impl Send for nsStyleQuoteValues {} +unsafe impl Sync for nsStyleQuoteValues {} extern "C" { pub fn Gecko_EnsureTArrayCapacity(aArray: *mut ::std::os::raw::c_void, @@ -544,6 +547,17 @@ extern "C" { *mut nsCSSShadowArray); } extern "C" { + pub fn Gecko_NewStyleQuoteValues(len: u32) -> *mut nsStyleQuoteValues; +} +extern "C" { + pub fn Gecko_AddRefQuoteValuesArbitraryThread(aPtr: + *mut nsStyleQuoteValues); +} +extern "C" { + pub fn Gecko_ReleaseQuoteValuesArbitraryThread(aPtr: + *mut nsStyleQuoteValues); +} +extern "C" { pub fn Gecko_Construct_nsStyleFont(ptr: *mut nsStyleFont); } extern "C" { diff --git a/components/style/gecko_bindings/mod.rs b/components/style/gecko_bindings/mod.rs index 877af7b6ca9..7201bdb2668 100644 --- a/components/style/gecko_bindings/mod.rs +++ b/components/style/gecko_bindings/mod.rs @@ -4,7 +4,6 @@ #[allow(dead_code, improper_ctypes, non_camel_case_types)] pub mod bindings; -pub mod ptr; // FIXME: We allow `improper_ctypes` (for now), because the lint doesn't allow // foreign structs to have `PhantomData`. We should remove this once the lint diff --git a/components/style/gecko_bindings/ptr.rs b/components/style/gecko_bindings/ptr.rs deleted file mode 100644 index 6d97e6613d0..00000000000 --- a/components/style/gecko_bindings/ptr.rs +++ /dev/null @@ -1,64 +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 gecko_bindings::bindings::*; -use heapsize::HeapSizeOf; -use std::fmt::{self, Debug}; - -// Defines an Arc-like type that manages a refcounted Gecko object stored -// in a ThreadSafeFooHolder smart pointer (for those Gecko classes that -// do not have thread-safe refcounting support) or as raw pointers (for -// those that do have thread-safe refcounting support). Used in tandem -// with the NS_DECL_(HOLDER|THREADSAFE)_FFI_REFCOUNTING-defined types and -// functions in Gecko. -macro_rules! define_arc { - ($arc_type:ident, $name:ident, $gecko_type:ident, $addref: ident, $release: ident) => ( - #[derive(PartialEq)] - pub struct $arc_type { - ptr: *mut $gecko_type, - } - - impl $arc_type { - pub fn new(data: *mut $gecko_type) -> $arc_type { - debug_assert!(!data.is_null()); - unsafe { $addref(data); } - $arc_type { - ptr: data - } - } - - pub fn as_raw(&self) -> *mut $gecko_type { self.ptr } - } - - unsafe impl Send for $arc_type {} - unsafe impl Sync for $arc_type {} - - impl Clone for $arc_type { - fn clone(&self) -> $arc_type { - $arc_type::new(self.ptr) - } - } - - impl Drop for $arc_type { - fn drop(&mut self) { - unsafe { $release(self.ptr); } - } - } - - impl HeapSizeOf for $arc_type { - fn heap_size_of_children(&self) -> usize { 0 } - } - - impl Debug for $arc_type { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, stringify!($name)) - } - } - ) -} - -define_arc!(GeckoArcPrincipal, Principal, ThreadSafePrincipalHolder, - Gecko_AddRefPrincipalArbitraryThread, Gecko_ReleasePrincipalArbitraryThread); -define_arc!(GeckoArcURI, URI, ThreadSafeURIHolder, - Gecko_AddRefURIArbitraryThread, Gecko_ReleaseURIArbitraryThread); diff --git a/components/style/gecko_bindings/sugar/mod.rs b/components/style/gecko_bindings/sugar/mod.rs index eb4460c63bc..5c7eb198184 100644 --- a/components/style/gecko_bindings/sugar/mod.rs +++ b/components/style/gecko_bindings/sugar/mod.rs @@ -8,4 +8,5 @@ mod ns_style_auto_array; pub mod ns_style_coord; mod ns_t_array; pub mod ownership; +pub mod refptr; mod style_complex_color; diff --git a/components/style/gecko_bindings/sugar/refptr.rs b/components/style/gecko_bindings/sugar/refptr.rs new file mode 100644 index 00000000000..9c7dcfddc63 --- /dev/null +++ b/components/style/gecko_bindings/sugar/refptr.rs @@ -0,0 +1,237 @@ +/* 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 gecko_bindings::structs; +use heapsize::HeapSizeOf; +use std::{mem, ptr}; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; + +/// Trait for all objects that have Addref() and Release +/// methods and can be placed inside RefPtr<T> +pub unsafe trait RefCounted { + fn addref(&self); + unsafe fn release(&self); +} + +/// Trait for types which can be shared across threads in RefPtr +pub unsafe trait ThreadSafeRefCounted: RefCounted {} + +#[derive(Debug)] +pub struct RefPtr<T: RefCounted> { + ptr: *mut T, + _marker: PhantomData<T>, +} + +/// A RefPtr that we know is uniquely owned +/// +/// This is basically Box<T>, with the additional +/// guarantee that the box can be safely interpreted +/// as a RefPtr<T> (with refcount 1) +/// +/// This is useful when you wish to create a refptr +/// and mutate it temporarily, while it is still +/// uniquely owned. +pub struct UniqueRefPtr<T: RefCounted>(RefPtr<T>); + +// There is no safe conversion from &T to RefPtr<T> (like Gecko has) +// because this lets you break UniqueRefPtr's guarantee + +impl<T: RefCounted> RefPtr<T> { + /// Create a new RefPtr from an already addrefed + /// pointer obtained from FFI. Pointer + /// must be valid, non-null and have been addrefed + pub unsafe fn from_addrefed(ptr: *mut T) -> Self { + debug_assert!(!ptr.is_null()); + RefPtr { + ptr: ptr, + _marker: PhantomData, + } + } + + /// Create a new RefPtr from a pointer obtained + /// from FFI. Pointer must be valid and non null. + /// This method calls addref() internally + pub unsafe fn new(ptr: *mut T) -> Self { + debug_assert!(!ptr.is_null()); + let ret = RefPtr { + ptr: ptr, + _marker: PhantomData, + }; + ret.addref(); + ret + } + + /// Produces an FFI-compatible RefPtr that can be stored in + /// style structs. + /// + /// structs::RefPtr does not have a destructor, so this may leak + pub fn forget(self) -> structs::RefPtr<T> { + let ret = structs::RefPtr { + mRawPtr: self.ptr, + }; + mem::forget(self); + ret + } + + /// Returns the raw inner pointer + /// to be fed back into FFI + pub fn get(&self) -> *mut T { + self.ptr + } + + /// Addref the inner data + /// + /// Leaky on its own + pub fn addref(&self) { + unsafe { (*self.ptr).addref(); } + } + + /// Release the inner data + /// + /// Call only when the data actuall needs releasing + pub unsafe fn release(&self) { + (*self.ptr).release(); + } +} + +impl<T: RefCounted> UniqueRefPtr<T> { + /// Create a unique refptr from an already addrefed + /// pointer obtained from FFI. The refcount must be one. + /// The pointer must be valid and non null + pub unsafe fn from_addrefed(ptr: *mut T) -> Self { + UniqueRefPtr(RefPtr::from_addrefed(ptr)) + } + + /// Convert to a RefPtr so that it can be used + pub fn get(self) -> RefPtr<T> { + self.0 + } +} + +impl<T: RefCounted> Deref for RefPtr<T> { + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.ptr } + } +} + +impl<T: RefCounted> Deref for UniqueRefPtr<T> { + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.0.ptr } + } +} + +impl<T: RefCounted> DerefMut for UniqueRefPtr<T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.0.ptr } + } +} + +impl<T: RefCounted> structs::RefPtr<T> { + /// Produces a Rust-side RefPtr from an FFI RefPtr, bumping the refcount + /// + /// Must be called on a valid, non-null structs::RefPtr<T> + pub unsafe fn to_safe(&self) -> RefPtr<T> { + debug_assert!(!self.mRawPtr.is_null()); + let r = RefPtr { + ptr: self.mRawPtr, + _marker: PhantomData, + }; + r.addref(); + r + } + /// Produces a Rust-side RefPtr, consuming the existing one (and not bumping the refcount) + pub unsafe fn into_safe(self) -> RefPtr<T> { + debug_assert!(!self.mRawPtr.is_null()); + RefPtr { + ptr: self.mRawPtr, + _marker: PhantomData, + } + } + + /// Replace a structs::RefPtr<T> with a different one, appropriately addref/releasing + /// + /// Both `self` and `other` must be valid, but can be null + pub unsafe fn set(&mut self, other: &Self) { + if !self.mRawPtr.is_null() { + (*self.mRawPtr).release(); + self.mRawPtr = ptr::null_mut(); + } + if !other.mRawPtr.is_null() { + *self = other.to_safe().forget(); + } + } + + /// Replace a `structs::RefPtr<T>` with a `RefPtr<T>`, + /// consuming the `RefPtr<T>`, and releasing the old + /// value in `self` if necessary. + /// + /// `self` must be valid, possibly null + pub fn set_move(&mut self, other: RefPtr<T>) { + if !self.mRawPtr.is_null() { + unsafe { (*self.mRawPtr).release(); } + } + *self = other.forget(); + } +} + +impl<T: RefCounted> Drop for RefPtr<T> { + fn drop(&mut self) { + unsafe { self.release() } + } +} + +impl<T: RefCounted> Clone for RefPtr<T> { + fn clone(&self) -> Self { + self.addref(); + RefPtr { + ptr: self.ptr, + _marker: PhantomData, + } + } +} + +impl<T: RefCounted> HeapSizeOf for RefPtr<T> { + fn heap_size_of_children(&self) -> usize { 0 } +} + +impl<T: RefCounted> PartialEq for RefPtr<T> { + fn eq(&self, other: &Self) -> bool { + self.ptr == other.ptr + } +} + +unsafe impl<T: ThreadSafeRefCounted> Send for RefPtr<T> {} +unsafe impl<T: ThreadSafeRefCounted> Sync for RefPtr<T> {} + +// Companion of NS_DECL_THREADSAFE_FFI_REFCOUNTING +// +// Gets you a free RefCounted impl +macro_rules! impl_threadsafe_refcount { + ($t:ty, $addref:ident, $release:ident) => ( + unsafe impl RefCounted for $t { + fn addref(&self) { + unsafe { ::gecko_bindings::bindings::$addref(self as *const _ as *mut _) } + } + unsafe fn release(&self) { + ::gecko_bindings::bindings::$release(self as *const _ as *mut _) + } + } + unsafe impl ThreadSafeRefCounted for $t {} + ); +} + +impl_threadsafe_refcount!(::gecko_bindings::bindings::ThreadSafePrincipalHolder, + Gecko_AddRefPrincipalArbitraryThread, + Gecko_ReleasePrincipalArbitraryThread); +impl_threadsafe_refcount!(::gecko_bindings::bindings::ThreadSafeURIHolder, + Gecko_AddRefURIArbitraryThread, + Gecko_ReleaseURIArbitraryThread); +impl_threadsafe_refcount!(::gecko_bindings::structs::nsStyleQuoteValues, + Gecko_AddRefQuoteValuesArbitraryThread, + Gecko_ReleaseQuoteValuesArbitraryThread); +pub type GeckoArcPrincipal = RefPtr<::gecko_bindings::bindings::ThreadSafePrincipalHolder>; +pub type GeckoArcURI = RefPtr<::gecko_bindings::bindings::ThreadSafeURIHolder>; diff --git a/components/style/parser.rs b/components/style/parser.rs index db281ec24e2..1cf46a80d09 100644 --- a/components/style/parser.rs +++ b/components/style/parser.rs @@ -7,7 +7,7 @@ use cssparser::{Parser, SourcePosition}; use error_reporting::ParseErrorReporter; #[cfg(feature = "gecko")] -use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI}; +use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI}; use selector_impl::TheSelectorImpl; use selectors::parser::ParserContext as SelectorParserContext; use stylesheets::Origin; diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 2561cd557f0..9dc9e8ceb96 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -896,9 +896,9 @@ fn static_assert() { Gecko_SetMozBinding(&mut self.gecko, url.as_str().as_ptr(), url.as_str().len() as u32, - extra_data.base.as_raw(), - extra_data.referrer.as_raw(), - extra_data.principal.as_raw()); + extra_data.base.get(), + extra_data.referrer.get(), + extra_data.principal.get()); } } } @@ -1448,7 +1448,7 @@ fn static_assert() { </%self:simple_image_array_property> </%self:impl_trait> -<%self:impl_trait style_struct_name="List" skip_longhands="list-style-type" skip_additionals="*"> +<%self:impl_trait style_struct_name="List" skip_longhands="list-style-type quotes" skip_additionals="*"> ${impl_keyword_setter("list_style_type", "__LIST_STYLE_TYPE__", data.longhands_by_name["list-style-type"].keyword)} @@ -1458,6 +1458,27 @@ fn static_assert() { } } + pub fn set_quotes(&mut self, other: longhands::quotes::computed_value::T) { + use gecko_bindings::bindings::Gecko_NewStyleQuoteValues; + use gecko_bindings::sugar::refptr::UniqueRefPtr; + use nsstring::nsCString; + + let mut refptr = unsafe { + UniqueRefPtr::from_addrefed(Gecko_NewStyleQuoteValues(other.0.len() as u32)) + }; + + for (servo, gecko) in other.0.into_iter().zip(refptr.mQuotePairs.iter_mut()) { + gecko.first.assign_utf8(&nsCString::from(&*servo.0)); + gecko.second.assign_utf8(&nsCString::from(&*servo.1)); + } + + unsafe { self.gecko.mQuotes.set_move(refptr.get()) } + } + + pub fn copy_quotes_from(&mut self, other: &Self) { + unsafe { self.gecko.mQuotes.set(&other.gecko.mQuotes); } + } + </%self:impl_trait> <%self:impl_trait style_struct_name="Effects" diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 896b5fa09ba..378cd88bc45 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -922,7 +922,7 @@ ${helpers.single_keyword("-moz-appearance", // Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-binding <%helpers:longhand name="-moz-binding" products="gecko" animatable="False" disable_when_testing="True"> use cssparser::{CssStringWriter, ToCss}; - use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI}; + use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI}; use std::fmt::{self, Write}; use url::Url; use values::specified::UrlExtraData; diff --git a/components/style/properties/longhand/list.mako.rs b/components/style/properties/longhand/list.mako.rs index 62eed32f53b..77e0af5797a 100644 --- a/components/style/properties/longhand/list.mako.rs +++ b/components/style/properties/longhand/list.mako.rs @@ -104,7 +104,7 @@ ${helpers.single_keyword("list-style-type", """ } </%helpers:longhand> -<%helpers:longhand name="quotes" products="servo" animatable="False"> +<%helpers:longhand name="quotes" animatable="False"> use std::borrow::Cow; use std::fmt; use values::NoViewportPercentage; diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index f1694aa340d..f8a456d2076 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -6,7 +6,7 @@ use app_units::Au; use cssparser::{self, Parser, ToCss, Token}; use euclid::size::Size2D; #[cfg(feature = "gecko")] -use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI}; +use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI}; use parser::{Parse, ParserContext}; #[cfg(feature = "gecko")] use parser::ParserContextExtraData; diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 9238cd1e7b9..124e75072cd 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -31,13 +31,13 @@ use style::gecko_bindings::bindings::{ServoDeclarationBlockBorrowed, ServoDeclar 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::ptr::{GeckoArcPrincipal, GeckoArcURI}; use style::gecko_bindings::structs::{SheetParsingMode, nsIAtom}; use style::gecko_bindings::structs::ServoElementSnapshot; use style::gecko_bindings::structs::nsRestyleHint; use style::gecko_bindings::structs::nsString; use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasBoxFFI}; use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong}; +use style::gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI}; use style::parallel; use style::parser::{ParserContext, ParserContextExtraData}; use style::properties::{ComputedValues, Importance, PropertyDeclaration}; @@ -186,11 +186,11 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(bytes: *const u8, let base_str = unsafe { from_utf8_unchecked(slice::from_raw_parts(base_bytes, base_length as usize)) }; let url = Url::parse(base_str).unwrap(); - let extra_data = ParserContextExtraData { + let extra_data = unsafe { ParserContextExtraData { base: Some(GeckoArcURI::new(base)), referrer: Some(GeckoArcURI::new(referrer)), principal: Some(GeckoArcPrincipal::new(principal)), - }; + }}; let sheet = Arc::new(Stylesheet::from_str(input, url, origin, Box::new(StdoutErrorReporter), extra_data)); unsafe { @@ -390,11 +390,11 @@ pub extern "C" fn Servo_ParseProperty(property_bytes: *const u8, let base_str = unsafe { from_utf8_unchecked(slice::from_raw_parts(base_bytes, base_length as usize)) }; let base_url = Url::parse(base_str).unwrap(); - let extra_data = ParserContextExtraData { + let extra_data = unsafe { ParserContextExtraData { base: Some(GeckoArcURI::new(base)), referrer: Some(GeckoArcURI::new(referrer)), principal: Some(GeckoArcPrincipal::new(principal)), - }; + }}; let context = ParserContext::new_with_extra_data(Origin::Author, &base_url, Box::new(StdoutErrorReporter), |