Bug 1338388 - Part 8: stylo: Add paint-order bitfield; r?heycam
MozReview-Commit-ID: 4QKKzJ1DVYP
--- 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>
+