Bug 1353966 - Part 6: Implement discrete type animation for counters related properties. r?hiro draft
authorDaisuke Akatsuka <dakatsuka@mozilla.com>
Fri, 19 May 2017 11:10:20 +0900
changeset 580996 6bc549d2546df526be38e65cc8862dc6d2ff9372
parent 580995 667ff0838077177c73727b18973edb464e3080a4
child 580997 9477c92bfcb7004a4a7a3d95b0311d7d1b1a8199
push id59742
push userbmo:dakatsuka@mozilla.com
push dateFri, 19 May 2017 06:56:54 +0000
reviewershiro
bugs1353966
milestone55.0a1
Bug 1353966 - Part 6: Implement discrete type animation for counters related properties. r?hiro In this patch, implement following counters related properties. * content * counter-increment * counter-reset MozReview-Commit-ID: JhYJZMFilB2
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/longhand/counters.mako.rs
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1325,16 +1325,21 @@ Gecko_SetContentDataImage(nsStyleContent
 void
 Gecko_SetContentDataArray(nsStyleContentData* aContent,
                           nsStyleContentType aType, uint32_t aLen)
 {
   nsCSSValue::Array* arr = nsCSSValue::Array::Create(aLen);
   aContent->SetCounters(aType, arr);
 }
 
+const mozilla::css::URLValueData*
+Gecko_GetContentDataImageURLValue(const nsStyleContentData* aContent) {
+  return aContent->GetImageRequest()->GetImageValue();
+}
+
 nsStyleGradient*
 Gecko_CreateGradient(uint8_t aShape,
                      uint8_t aSize,
                      bool aRepeating,
                      bool aLegacySyntax,
                      uint32_t aStopCount)
 {
   nsStyleGradient* result = new nsStyleGradient();
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -320,16 +320,17 @@ void Gecko_SetCursorImage(nsCursorImage*
 void Gecko_CopyCursorArrayFrom(nsStyleUserInterface* dest,
                                const nsStyleUserInterface* src);
 
 void Gecko_SetContentDataImageValue(nsStyleContentData* aList,
                                     mozilla::css::ImageValue* aImageValue);
 // XXX cku: remove this function after gecko and stylo side are both ready
 void Gecko_SetContentDataImage(nsStyleContentData* content_data, ServoBundledURI uri);
 void Gecko_SetContentDataArray(nsStyleContentData* content_data, nsStyleContentType type, uint32_t len);
+const mozilla::css::URLValueData* Gecko_GetContentDataImageURLValue(const nsStyleContentData* content_data);
 
 // Dirtiness tracking.
 uint32_t Gecko_GetNodeFlags(RawGeckoNodeBorrowed node);
 void Gecko_SetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
 void Gecko_UnsetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
 void Gecko_SetOwnerDocumentNeedsStyleFlush(RawGeckoElementBorrowed element);
 
 // Incremental restyle.
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -4601,16 +4601,105 @@ clip-path
 
     pub fn copy_content_from(&mut self, other: &Self) {
         use gecko_bindings::bindings::Gecko_CopyStyleContentsFrom;
         unsafe {
             Gecko_CopyStyleContentsFrom(&mut self.gecko, &other.gecko)
         }
     }
 
+    pub fn clone_content(&self) -> longhands::content::computed_value::T {
+        use properties::longhands::content::computed_value::{T, ContentItem};
+        use gecko_bindings::bindings::Gecko_GetContentDataImageURLValue;
+        use gecko_bindings::structs::nsStringBuffer;
+        use gecko_bindings::structs::nsStyleContentType::*;
+        use gecko_bindings::structs::root::nsIAtom;
+        use gecko_string_cache::Atom;
+        use values::specified::url::SpecifiedUrl;
+        use values::generics::CounterStyleOrNone;
+        use values::CustomIdent;
+
+        if self.gecko.mContents.is_empty() {
+            return T::normal;
+        }
+
+        unsafe fn string_from_char_array(chars: *mut u16) -> String {
+            let data = chars as *const u16;
+            let mut length = 0;
+            let mut iter = data;
+            while *iter != 0 {
+                length += 1;
+                iter = iter.offset(1);
+            }
+            let char_vec = ::std::slice::from_raw_parts(data, length as usize);
+            String::from_utf16(char_vec).unwrap()
+        }
+
+        unsafe fn string_from_ns_string_buffer(buffer: *mut nsStringBuffer) -> String {
+            debug_assert!(!buffer.is_null());
+            string_from_char_array(buffer.offset(1) as *mut u16)
+        }
+
+        unsafe fn list_item_style_from_ns_atom(ns_atom: *mut nsIAtom ) -> CounterStyleOrNone {
+            CounterStyleOrNone::Name(CustomIdent(Atom::from_addrefed(ns_atom)))
+        }
+
+        T::Content(
+            self.gecko.mContents.iter().map(|gecko_content| {
+                match gecko_content.mType {
+                    eStyleContentType_OpenQuote => ContentItem::OpenQuote,
+                    eStyleContentType_CloseQuote => ContentItem::CloseQuote,
+                    eStyleContentType_NoOpenQuote => ContentItem::NoOpenQuote,
+                    eStyleContentType_NoCloseQuote => ContentItem::NoCloseQuote,
+                    eStyleContentType_AltContent => ContentItem::MozAltContent,
+                    eStyleContentType_String => {
+                        let gecko_chars = unsafe { *gecko_content.mContent.mString.as_ref() };
+                        let string = unsafe { string_from_char_array(gecko_chars) };
+                        ContentItem::String(string)
+                    },
+                    eStyleContentType_Attr => {
+                        let gecko_chars = unsafe { *gecko_content.mContent.mString.as_ref() };
+                        let string = unsafe { string_from_char_array(gecko_chars) };
+                        match string.find('|') {
+                            None => {
+                                ContentItem::Attr(None, string)
+                            },
+                            index => {
+                                let (ns, val) = string.split_at(index.unwrap());
+                                ContentItem::Attr(Some(String::from(ns)), String::from(val))
+                            }
+                        }
+                    },
+                    eStyleContentType_Counter => {
+                        let gecko_array = unsafe { & **gecko_content.mContent.mCounters.as_ref() };
+                        let string = unsafe { string_from_ns_string_buffer(*gecko_array[0].mValue.mString.as_ref()) };
+                        let gecko_atom = unsafe { *gecko_array[1].mValue.mAtom.as_ref() as *mut nsIAtom };
+                        let style = unsafe { list_item_style_from_ns_atom(gecko_atom) };
+                        ContentItem::Counter(string, style)
+                    },
+                    eStyleContentType_Counters => {
+                        let gecko_array = unsafe { & **gecko_content.mContent.mCounters.as_ref() };
+                        let name = unsafe { string_from_ns_string_buffer(*gecko_array[0].mValue.mString.as_ref()) };
+                        let sep = unsafe { string_from_ns_string_buffer(*gecko_array[1].mValue.mString.as_ref()) };
+                        let gecko_atom = unsafe { *gecko_array[2].mValue.mAtom.as_ref() as *mut nsIAtom };
+                        let style = unsafe { list_item_style_from_ns_atom(gecko_atom) };
+                        ContentItem::Counters(name, sep, style)
+                    },
+                    eStyleContentType_Image => {
+                        unsafe {
+                            let ref gecko_image_url = *Gecko_GetContentDataImageURLValue(gecko_content);
+                            ContentItem::Url(SpecifiedUrl::from_gecko_url(gecko_image_url))
+                        }
+                    },
+                    _ => ContentItem::MozAltContent
+                }
+            }).collect()
+        )
+    }
+
     % for counter_property in ["Increment", "Reset"]:
         pub fn set_counter_${counter_property.lower()}(&mut self, v: longhands::counter_increment::computed_value::T) {
             unsafe {
                 bindings::Gecko_ClearAndResizeCounter${counter_property}s(&mut self.gecko,
                                                                       v.0.len() as u32);
                 for (i, (name, value)) in v.0.into_iter().enumerate() {
                     self.gecko.m${counter_property}s[i].mCounter.assign(name.0.as_slice());
                     self.gecko.m${counter_property}s[i].mValue = value;
@@ -4618,16 +4707,27 @@ clip-path
             }
         }
 
         pub fn copy_counter_${counter_property.lower()}_from(&mut self, other: &Self) {
             unsafe {
                 bindings::Gecko_CopyCounter${counter_property}sFrom(&mut self.gecko, &other.gecko)
             }
         }
+
+        pub fn clone_counter_${counter_property.lower()}(&self) -> longhands::counter_increment::computed_value::T {
+            use values::CustomIdent;
+            use gecko_string_cache::Atom;
+
+            longhands::counter_increment::computed_value::T(
+                self.gecko.m${counter_property}s.iter().map(|ref gecko_counter| {
+                    (CustomIdent(Atom::from(gecko_counter.mCounter.to_string())), gecko_counter.mValue)
+                }).collect()
+            )
+        }
     % endfor
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="UI" skip_longhands="-moz-force-broken-image-icon">
     #[allow(non_snake_case)]
     pub fn set__moz_force_broken_image_icon(&mut self, v: longhands::_moz_force_broken_image_icon::computed_value::T) {
         self.gecko.mForceBrokenImageIcon = v.0 as u8;
     }
--- a/servo/components/style/properties/longhand/counters.mako.rs
+++ b/servo/components/style/properties/longhand/counters.mako.rs
@@ -1,17 +1,17 @@
 /* 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/. */
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 <% data.new_style_struct("Counters", inherited=False, gecko_name="Content") %>
 
-<%helpers:longhand name="content" boxed="True" animation_value_type="none"
+<%helpers:longhand name="content" boxed="True" animation_value_type="discrete"
                    spec="https://drafts.csswg.org/css-content/#propdef-content">
     use cssparser::Token;
     use std::ascii::AsciiExt;
     use values::computed::ComputedValueAsSpecified;
     #[cfg(feature = "gecko")]
     use values::generics::CounterStyleOrNone;
     use values::specified::url::SpecifiedUrl;
     use values::HasViewportPercentage;
@@ -247,17 +247,17 @@
         if !content.is_empty() {
             Ok(SpecifiedValue::Content(content))
         } else {
             Err(())
         }
     }
 </%helpers:longhand>
 
-<%helpers:longhand name="counter-increment" animation_value_type="none"
+<%helpers:longhand name="counter-increment" animation_value_type="discrete"
                    spec="https://drafts.csswg.org/css-lists/#propdef-counter-increment">
     use std::fmt;
     use style_traits::ToCss;
     use super::content;
     use values::{HasViewportPercentage, CustomIdent};
 
     use cssparser::{Token, serialize_identifier};
     use std::borrow::{Cow, ToOwned};
@@ -369,17 +369,17 @@
         if !counters.is_empty() {
             Ok(SpecifiedValue(counters))
         } else {
             Err(())
         }
     }
 </%helpers:longhand>
 
-<%helpers:longhand name="counter-reset" animation_value_type="none"
+<%helpers:longhand name="counter-reset" animation_value_type="discrete"
                    spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset">
     pub use super::counter_increment::{SpecifiedValue, computed_value, get_initial_value};
     use super::counter_increment::parse_common;
 
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
         parse_common(context, 0, input)
     }
 </%helpers:longhand>