aboutsummaryrefslogtreecommitdiffstats
path: root/components/style/values/specified/svg.rs
diff options
context:
space:
mode:
authorCYBAI <cyb.ai.815@gmail.com>2018-01-10 21:00:33 +0800
committerCYBAI <cyb.ai.815@gmail.com>2018-01-10 21:26:33 +0800
commit2bc02bc78de7cf3028b9a78979ae7cf08046f7bd (patch)
tree3067a3c2bcb6f11c7a491fd12a5a1515de951ede /components/style/values/specified/svg.rs
parente2c89df8eeb5f2dbac1436335aea52099a622d0d (diff)
downloadservo-2bc02bc78de7cf3028b9a78979ae7cf08046f7bd.tar.gz
servo-2bc02bc78de7cf3028b9a78979ae7cf08046f7bd.zip
style: Move paint-order outside of mako
Diffstat (limited to 'components/style/values/specified/svg.rs')
-rw-r--r--components/style/values/specified/svg.rs138
1 files changed, 137 insertions, 1 deletions
diff --git a/components/style/values/specified/svg.rs b/components/style/values/specified/svg.rs
index 8f6b62a71e9..63f14b741e0 100644
--- a/components/style/values/specified/svg.rs
+++ b/components/style/values/specified/svg.rs
@@ -6,7 +6,8 @@
use cssparser::Parser;
use parser::{Parse, ParserContext};
-use style_traits::{CommaWithSpace, ParseError, Separator, StyleParseErrorKind};
+use std::fmt;
+use style_traits::{CommaWithSpace, ParseError, Separator, StyleParseErrorKind, ToCss};
use values::generics::svg as generic;
use values::specified::{LengthOrPercentage, NonNegativeLengthOrPercentage, NonNegativeNumber};
use values::specified::{Number, Opacity, SpecifiedUrl};
@@ -124,3 +125,138 @@ impl Parse for SVGOpacity {
}
}
}
+
+/// The specified value for a single CSS paint-order property.
+#[repr(u8)]
+#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, ToCss)]
+pub enum PaintOrder {
+ /// `normal` variant
+ Normal = 0,
+ /// `fill` variant
+ Fill = 1,
+ /// `stroke` variant
+ Stroke = 2,
+ /// `markers` variant
+ Markers = 3,
+}
+
+/// Number of non-normal components
+const PAINT_ORDER_COUNT: u8 = 3;
+
+/// Number of bits for each component
+const PAINT_ORDER_SHIFT: u8 = 2;
+
+/// Mask with above bits set
+const PAINT_ORDER_MASK: u8 = 0b11;
+
+/// The specified value is tree `PaintOrder` values packed into the
+/// bitfields below, 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(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)]
+pub struct SVGPaintOrder(pub u8);
+
+impl SVGPaintOrder {
+ /// Get default `paint-order` with `0`
+ pub fn normal() -> Self {
+ SVGPaintOrder(0)
+ }
+
+ /// Get variant of `paint-order`
+ pub fn order_at(&self, pos: u8) -> PaintOrder {
+ // Safe because PaintOrder covers all possible patterns.
+ unsafe { ::std::mem::transmute((self.0 >> pos * PAINT_ORDER_SHIFT) & PAINT_ORDER_MASK) }
+ }
+}
+
+impl Parse for SVGPaintOrder {
+ fn parse<'i, 't>(
+ _context: &ParserContext,
+ input: &mut Parser<'i, 't>
+ ) -> Result<SVGPaintOrder, ParseError<'i>> {
+ if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) {
+ return Ok(SVGPaintOrder::normal())
+ }
+
+ 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: Result<_, ParseError> = input.try(|input| {
+ try_match_ident_ignore_ascii_case! { input,
+ "fill" => Ok(PaintOrder::Fill),
+ "stroke" => Ok(PaintOrder::Stroke),
+ "markers" => Ok(PaintOrder::Markers),
+ }
+ });
+
+ match result {
+ Ok(val) => {
+ if (seen & (1 << val as u8)) != 0 {
+ // don't parse the same ident twice
+ return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+ }
+
+ value |= (val as u8) << (pos * PAINT_ORDER_SHIFT);
+ seen |= 1 << (val as u8);
+ pos += 1;
+ }
+ Err(_) => break,
+ }
+ }
+
+ if value == 0 {
+ // Couldn't find any keyword
+ return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+ }
+
+ // fill in rest
+ for i in pos..PAINT_ORDER_COUNT {
+ for paint in 0..PAINT_ORDER_COUNT {
+ // if not seen, set bit at position, mark as seen
+ if (seen & (1 << paint)) == 0 {
+ seen |= 1 << paint;
+ value |= paint << (i * PAINT_ORDER_SHIFT);
+ break;
+ }
+ }
+ }
+
+ Ok(SVGPaintOrder(value))
+ }
+}
+
+impl ToCss for SVGPaintOrder {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ if self.0 == 0 {
+ return dest.write_str("normal")
+ }
+
+ let mut last_pos_to_serialize = 0;
+ for i in (1..PAINT_ORDER_COUNT).rev() {
+ let component = self.order_at(i);
+ let earlier_component = self.order_at(i - 1);
+ if component < earlier_component {
+ last_pos_to_serialize = i - 1;
+ break;
+ }
+ }
+
+ for pos in 0..last_pos_to_serialize + 1 {
+ if pos != 0 {
+ dest.write_str(" ")?
+ }
+ self.order_at(pos).to_css(dest)?;
+ }
+ Ok(())
+ }
+}