Bug 1338388 - Part 8: stylo: Add paint-order bitfield; r?heycam draft
authorManish Goregaokar <manishearth@gmail.com>
Thu, 09 Feb 2017 17:43:52 -0800
changeset 486531 62f8444622902894f534ac912af973ea79922c0e
parent 486530 18821229c1eaedaa7039dc0e9c9b3954dfd15524
child 486532 998b816e75f7f1057b7ecc29c03efd603e63f1ec
push id46017
push userbmo:manishearth@gmail.com
push dateSat, 18 Feb 2017 08:18:38 +0000
reviewersheycam
bugs1338388
milestone54.0a1
Bug 1338388 - Part 8: stylo: Add paint-order bitfield; r?heycam MozReview-Commit-ID: 4QKKzJ1DVYP
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/longhand/inherited_svg.mako.rs
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -2795,18 +2795,41 @@ clip-path
         use gecko_bindings::bindings::Gecko_CopyClipPathValueFrom;
         unsafe {
             Gecko_CopyClipPathValueFrom(&mut self.gecko.mClipPath, &other.gecko.mClipPath);
         }
     }
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="InheritedSVG"
-                  skip_longhands=""
+                  skip_longhands="paint-order"
                   skip_additionals="*">
+    pub fn set_paint_order(&mut self, v: longhands::paint_order::computed_value::T) {
+        use self::longhands::paint_order;
+
+        if v.0 == 0 {
+            self.gecko.mPaintOrder = structs::NS_STYLE_PAINT_ORDER_NORMAL as u8;
+        } else {
+            let mut order = 0;
+
+            for pos in 0..3 {
+                let geckoval = match v.bits_at(pos) {
+                    paint_order::FILL => structs::NS_STYLE_PAINT_ORDER_FILL as u8,
+                    paint_order::STROKE => structs::NS_STYLE_PAINT_ORDER_STROKE as u8,
+                    paint_order::MARKERS => structs::NS_STYLE_PAINT_ORDER_MARKERS as u8,
+                    _ => unreachable!(),
+                };
+                order |= geckoval << (pos * structs::NS_STYLE_PAINT_ORDER_BITWIDTH as u8);
+            }
+
+            self.gecko.mPaintOrder = order;
+        }
+    }
+
+    ${impl_simple_copy('paint_order', 'mPaintOrder')}
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="Color"
                   skip_longhands="*">
     pub fn set_color(&mut self, v: longhands::color::computed_value::T) {
         let result = convert_rgba_to_nscolor(&v);
         ${set_gecko_property("mColor", "result")}
     }
--- a/servo/components/style/properties/longhand/inherited_svg.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_svg.mako.rs
@@ -114,8 +114,137 @@
                           boxed=True)}
 
 ${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
                           products="gecko",
                           animatable="False",
                           spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties",
                           boxed=True)}
 
+<%helpers:longhand name="paint-order"
+                   animatable="False"
+                   products="gecko"
+                   spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder">
+
+    use values::computed::ComputedValueAsSpecified;
+    use std::fmt;
+    use style_traits::ToCss;
+    use values::HasViewportPercentage;
+
+    pub const NORMAL: u8 = 0;
+    pub const FILL: u8 = 1;
+    pub const STROKE: u8 = 2;
+    pub const MARKERS: u8 = 3;
+
+    // number of bits for each component
+    pub const SHIFT: u8 = 2;
+    // mask with above bits set
+    pub const MASK: u8 = 0b11;
+    // number of non-normal keyword values
+    pub const COUNT: u8 = 3;
+    // all keywords
+    pub const ALL: [u8; 3] = [FILL, STROKE, MARKERS];
+
+    /// Represented as a six-bit field, of 3 two-bit pairs
+    ///
+    /// Each pair can be set to FILL, STROKE, or MARKERS
+    /// Lowest significant bit pairs are highest priority.
+    ///  `normal` is the empty bitfield. The three pairs are
+    /// never zero in any case other than `normal`.
+    ///
+    /// Higher priority values, i.e. the values specified first,
+    /// will be painted first (and may be covered by paintings of lower priority)
+    #[derive(PartialEq, Clone, Copy, Debug)]
+    pub struct SpecifiedValue(pub u8);
+
+    pub mod computed_value {
+        pub use super::SpecifiedValue as T;
+    }
+
+    impl SpecifiedValue {
+        pub fn bits_at(&self, pos: u8) -> u8 {
+            (self.0 >> pos * SHIFT) & MASK
+        }
+    }
+
+    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
+        if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) {
+            Ok(SpecifiedValue(0))
+        } else {
+            let mut value = 0;
+            // bitfield representing what we've seen so far
+            // bit 1 is fill, bit 2 is stroke, bit 3 is markers
+            let mut seen = 0;
+            let mut pos = 0;
+
+            loop {
+
+                let result = input.try(|i| {
+                    match_ignore_ascii_case! { i.expect_ident()?,
+                        "fill" => Ok(FILL),
+                        "stroke" => Ok(STROKE),
+                        "markers" => Ok(MARKERS),
+                        _ => Err(())
+                    }
+                });
+
+                match result {
+                    Ok(val) => {
+                        if (seen & (1 << val)) != 0 {
+                            // don't parse the same ident twice
+                            return Err(())
+                        } else {
+                            value |= val << (pos * SHIFT);
+                            seen |= 1 << val;
+                            pos += 1;
+                        }
+                    }
+                    Err(()) => break,
+                }
+            }
+
+            if value == 0 {
+                // couldn't find any keyword
+                Err(())
+            } else {
+                // fill in rest
+                for i in pos..COUNT {
+                    for paint in &ALL {
+                        // if not seen, set bit at position, mark as seen
+                        if (seen & (1 << paint)) == 0 {
+                            seen |= 1 << paint;
+                            value |= paint << (i * SHIFT);
+                            break;
+                        }
+                    }
+                }
+
+                Ok(SpecifiedValue(value))
+            }
+        }
+    }
+
+    impl ToCss for SpecifiedValue {
+        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+            if self.0 == 0 {
+                return dest.write_str("normal")
+            }
+
+            for pos in 0..COUNT {
+                if pos != 0 {
+                    dest.write_str(" ")?
+                }
+                match self.bits_at(pos) {
+                    FILL => dest.write_str("fill")?,
+                    STROKE => dest.write_str("stroke")?,
+                    MARKERS => dest.write_str("markers")?,
+                    _ => unreachable!(),
+                }
+            }
+            Ok(())
+        }
+    }
+
+    no_viewport_percentage!(SpecifiedValue);
+
+    impl ComputedValueAsSpecified for SpecifiedValue { }
+</%helpers:longhand>
+