From 46afc56c41500c2a98e6d5a387479edfb095b5a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 11 Aug 2016 22:01:14 -0700 Subject: [PATCH] stylo: Implement support for the contents property. --- components/style/properties/gecko.mako.rs | 87 +++++++++++++++++++ ports/geckolib/gecko_bindings/bindings.rs | 3 + .../gecko_bindings/sugar/ns_t_array.rs | 34 +++++++- 3 files changed, 120 insertions(+), 4 deletions(-) diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index d8697e7611a..085c35219c3 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1355,6 +1355,93 @@ fn static_assert() { ${impl_coord_copy('column_width', 'mColumnWidth')} +<%self:impl_trait style_struct_name="Counters" + skip_longhands="content"> + pub fn set_content(&mut self, v: longhands::content::computed_value::T) { + use properties::longhands::content::computed_value::T; + use properties::longhands::content::computed_value::ContentItem; + use gecko_bindings::structs::nsStyleContentData; + use gecko_bindings::structs::nsStyleContentType::*; + use gecko_bindings::bindings::Gecko_ClearStyleContents; + + // Converts a string as utf16, and returns an owned, zero-terminated raw buffer. + fn as_utf16_and_forget(s: &str) -> *mut u16 { + use std::mem; + let mut vec = s.encode_utf16().collect::>(); + vec.push(0u16); + let ptr = vec.as_mut_ptr(); + mem::forget(vec); + ptr + } + + #[inline(always)] + #[cfg(debug_assertions)] + fn set_image_tracked(contents: &mut nsStyleContentData, val: bool) { + contents.mImageTracked = val; + } + + #[inline(always)] + #[cfg(not(debug_assertions))] + fn set_image_tracked(_contents: &mut nsStyleContentData, _val: bool) {} + + // Ensure destructors run, otherwise we could leak. + if !self.gecko.mContents.is_empty() { + unsafe { + Gecko_ClearStyleContents(&mut self.gecko); + } + } + + match v { + T::none | + T::normal => {}, // Do nothing, already cleared. + T::Content(items) => { + // NB: set_len also reserves the appropriate space. + unsafe { self.gecko.mContents.set_len(items.len() as u32) } + for (i, item) in items.into_iter().enumerate() { + // TODO: Servo lacks support for attr(), and URIs, + // We don't support images, but need to remember to + // explicitly initialize mImageTracked in debug builds. + set_image_tracked(&mut self.gecko.mContents[i], false); + // NB: Gecko compares the mString value if type is not image + // or URI independently of whatever gets there. In the quote + // cases, they set it to null, so do the same here. + unsafe { + *self.gecko.mContents[i].mContent.mString.as_mut() = ptr::null_mut(); + } + match item { + ContentItem::String(value) => { + self.gecko.mContents[i].mType = eStyleContentType_String; + unsafe { + // NB: we share allocators, so doing this is fine. + *self.gecko.mContents[i].mContent.mString.as_mut() = + as_utf16_and_forget(&value); + } + } + ContentItem::OpenQuote + => self.gecko.mContents[i].mType = eStyleContentType_OpenQuote, + ContentItem::CloseQuote + => self.gecko.mContents[i].mType = eStyleContentType_CloseQuote, + ContentItem::NoOpenQuote + => self.gecko.mContents[i].mType = eStyleContentType_NoOpenQuote, + ContentItem::NoCloseQuote + => self.gecko.mContents[i].mType = eStyleContentType_NoCloseQuote, + ContentItem::Counter(..) | + ContentItem::Counters(..) + => self.gecko.mContents[i].mType = eStyleContentType_Uninitialized, + } + } + } + } + } + + pub fn copy_content_from(&mut self, other: &Self) { + use gecko_bindings::bindings::Gecko_CopyStyleContentsFrom; + unsafe { + Gecko_CopyStyleContentsFrom(&mut self.gecko, &other.gecko) + } + } + + <%def name="define_ffi_struct_accessor(style_struct)"> #[no_mangle] #[allow(non_snake_case, unused_variables)] diff --git a/ports/geckolib/gecko_bindings/bindings.rs b/ports/geckolib/gecko_bindings/bindings.rs index 99baada7fe9..1acaeb72925 100644 --- a/ports/geckolib/gecko_bindings/bindings.rs +++ b/ports/geckolib/gecko_bindings/bindings.rs @@ -314,6 +314,9 @@ extern "C" { capacity: usize, elem_size: usize); pub fn Gecko_ClearPODTArray(array: *mut ::std::os::raw::c_void, elem_size: usize, elem_align: usize); + pub fn Gecko_ClearStyleContents(content: *mut nsStyleContent); + pub fn Gecko_CopyStyleContentsFrom(content: *mut nsStyleContent, + other: *const nsStyleContent); pub fn Gecko_EnsureImageLayersLength(layers: *mut nsStyleImageLayers, len: usize); pub fn Gecko_InitializeImageLayer(layer: *mut Layer, diff --git a/ports/geckolib/gecko_bindings/sugar/ns_t_array.rs b/ports/geckolib/gecko_bindings/sugar/ns_t_array.rs index ec6b72d5c16..3615f30d246 100644 --- a/ports/geckolib/gecko_bindings/sugar/ns_t_array.rs +++ b/ports/geckolib/gecko_bindings/sugar/ns_t_array.rs @@ -2,7 +2,7 @@ * 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 bindings::Gecko_EnsureTArrayCapacity; +use bindings; use std::mem; use std::ops::{Deref, DerefMut}; use std::os::raw::c_void; @@ -38,6 +38,7 @@ impl nsTArray { // unsafe, since header may be in shared static or something unsafe fn header_mut<'a>(&'a mut self) -> &'a mut nsTArrayHeader { debug_assert!(!self.mBuffer.is_null()); + mem::transmute(self.mBuffer) } @@ -47,12 +48,37 @@ impl nsTArray { (self.mBuffer as *const nsTArrayHeader).offset(1) as *mut _ } - fn ensure_capacity(&mut self, cap: usize) { - unsafe { - Gecko_EnsureTArrayCapacity(self as *mut nsTArray as *mut c_void, cap, mem::size_of::()) + /// Ensures the array has enough capacity at least to hold `cap` elements. + /// + /// NOTE: This doesn't call the constructor on the values! + pub fn ensure_capacity(&mut self, cap: usize) { + if cap >= self.len() { + unsafe { + bindings::Gecko_EnsureTArrayCapacity(self as *mut nsTArray as *mut _, + cap, mem::size_of::()) + } } } + /// Clears the array storage without calling the destructor on the values. + #[inline] + pub unsafe fn clear(&mut self) { + if self.len() != 0 { + bindings::Gecko_ClearPODTArray(self as *mut nsTArray as *mut _, + mem::size_of::(), + mem::align_of::()); + } + } + + + /// Clears a POD array. This is safe since copy types are memcopyable. + #[inline] + pub fn clear_pod(&mut self) + where T: Copy + { + unsafe { self.clear() } + } + // unsafe because the array may contain uninits // This will not call constructors, either manually // add bindings or run the typed ensurecapacity call