Skip to content

Commit

Permalink
Auto merge of #19737 - CYBAI:move-paint-order-out-of-mako, r=emilio
Browse files Browse the repository at this point in the history
style: Move paint-order outside of mako

This is a sub-PR of #19015
r? emilio

---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #19736
- [x] These changes do not require tests

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/19737)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Jan 10, 2018
2 parents e2c89df + 2bc02bc commit ad622a4
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 148 deletions.
150 changes: 5 additions & 145 deletions components/style/properties/longhand/inherited_svg.mako.rs
Expand Up @@ -130,151 +130,11 @@ ${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}

<%helpers:longhand name="paint-order"
animation_value_type="discrete"
gecko_pref="svg.paint-order.enabled"
products="gecko"
spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder">
use std::fmt;
use style_traits::ToCss;

/// 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 = 0,
Fill = 1,
Stroke = 2,
Markers = 3,
}

/// Number of non-normal components.
const COUNT: u8 = 3;

/// Number of bits for each component
const SHIFT: u8 = 2;

/// Mask with above bits set
const 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 SpecifiedValue(pub u8);

impl SpecifiedValue {
fn normal() -> Self {
SpecifiedValue(0)
}
}

pub mod computed_value {
pub use super::SpecifiedValue as T;
}

pub fn get_initial_value() -> SpecifiedValue {
SpecifiedValue::normal()
}

impl SpecifiedValue {
fn order_at(&self, pos: u8) -> PaintOrder {
// Safe because PaintOrder covers all possible patterns.
unsafe { ::std::mem::transmute((self.0 >> pos * SHIFT) & MASK) }
}
}

pub fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<SpecifiedValue,ParseError<'i>> {
if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) {
return Ok(SpecifiedValue::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 * 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..COUNT {
for paint in 0..COUNT {
// 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")
}

let mut last_pos_to_serialize = 0;
for i in (1..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(())
}
}
</%helpers:longhand>
${helpers.predefined_type("paint-order", "SVGPaintOrder", "computed::SVGPaintOrder::normal()",
products="gecko",
animation_value_type="discrete",
gecko_pref="svg.paint-order.enabled",
spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder")}

<%helpers:vector_longhand name="-moz-context-properties"
animation_value_type="none"
Expand Down
3 changes: 2 additions & 1 deletion components/style/values/computed/mod.rs
Expand Up @@ -60,7 +60,8 @@ pub use self::list::ListStyleType;
pub use self::outline::OutlineStyle;
pub use self::percentage::Percentage;
pub use self::position::{Position, GridAutoFlow, GridTemplateAreas};
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray, SVGWidth};
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::table::XSpan;
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextAlign, TextOverflow, WordSpacing};
pub use self::time::Time;
Expand Down
2 changes: 2 additions & 0 deletions components/style/values/computed/svg.rs
Expand Up @@ -11,6 +11,8 @@ use values::computed::{NonNegativeNumber, NonNegativeLengthOrPercentage, Number}
use values::computed::Opacity;
use values::generics::svg as generic;

pub use values::specified::SVGPaintOrder;

/// Computed SVG Paint value
pub type SVGPaint = generic::SVGPaint<RGBA, ComputedUrl>;
/// Computed SVG Paint Kind value
Expand Down
3 changes: 2 additions & 1 deletion components/style/values/specified/mod.rs
Expand Up @@ -56,7 +56,8 @@ pub use self::outline::OutlineStyle;
pub use self::rect::LengthOrNumberRect;
pub use self::percentage::Percentage;
pub use self::position::{Position, PositionComponent, GridAutoFlow, GridTemplateAreas};
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray, SVGWidth};
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::table::XSpan;
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextDecorationLine};
pub use self::text::{TextAlign, TextAlignKeyword, TextOverflow, WordSpacing};
Expand Down
138 changes: 137 additions & 1 deletion components/style/values/specified/svg.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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(())
}
}

0 comments on commit ad622a4

Please sign in to comment.