mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Auto merge of #18627 - emilio:paint-order, r=nox
style: paint-order serialization fixes. See each commit for details. <!-- 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/18627) <!-- Reviewable:end -->
This commit is contained in:
commit
bbb5c8436e
2 changed files with 91 additions and 108 deletions
|
@ -5060,51 +5060,14 @@ clip-path
|
||||||
<%self:impl_trait style_struct_name="InheritedSVG"
|
<%self:impl_trait style_struct_name="InheritedSVG"
|
||||||
skip_longhands="paint-order stroke-dasharray -moz-context-properties">
|
skip_longhands="paint-order stroke-dasharray -moz-context-properties">
|
||||||
pub fn set_paint_order(&mut self, v: longhands::paint_order::computed_value::T) {
|
pub fn set_paint_order(&mut self, v: longhands::paint_order::computed_value::T) {
|
||||||
use self::longhands::paint_order;
|
self.gecko.mPaintOrder = v.0;
|
||||||
|
|
||||||
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')}
|
${impl_simple_copy('paint_order', 'mPaintOrder')}
|
||||||
|
|
||||||
pub fn clone_paint_order(&self) -> longhands::paint_order::computed_value::T {
|
pub fn clone_paint_order(&self) -> longhands::paint_order::computed_value::T {
|
||||||
use self::longhands::paint_order::{COUNT, FILL, MARKERS, NORMAL, SHIFT, STROKE};
|
use properties::longhands::paint_order::computed_value::T;
|
||||||
use self::longhands::paint_order::computed_value::T;
|
T(self.gecko.mPaintOrder)
|
||||||
|
|
||||||
if self.gecko.mPaintOrder == structs::NS_STYLE_PAINT_ORDER_NORMAL as u8 {
|
|
||||||
return T(NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
const PAINT_ORDER_BITWIDTH: u8 = structs::NS_STYLE_PAINT_ORDER_BITWIDTH as u8;
|
|
||||||
let mask = (1 << PAINT_ORDER_BITWIDTH) - 1;
|
|
||||||
let mut order = 0;
|
|
||||||
for pos in 0..COUNT {
|
|
||||||
let value =
|
|
||||||
match (self.gecko.mPaintOrder >> pos * PAINT_ORDER_BITWIDTH & mask) as u32 {
|
|
||||||
structs::NS_STYLE_PAINT_ORDER_FILL => FILL,
|
|
||||||
structs::NS_STYLE_PAINT_ORDER_STROKE => STROKE,
|
|
||||||
structs::NS_STYLE_PAINT_ORDER_MARKERS => MARKERS,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
order |= value << (pos * SHIFT);
|
|
||||||
};
|
|
||||||
T(order)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_stroke_dasharray(&mut self, v: longhands::stroke_dasharray::computed_value::T) {
|
pub fn set_stroke_dasharray(&mut self, v: longhands::stroke_dasharray::computed_value::T) {
|
||||||
|
|
|
@ -137,21 +137,27 @@ ${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
|
||||||
pub const NORMAL: u8 = 0;
|
/// The specified value for a single CSS paint-order property.
|
||||||
pub const FILL: u8 = 1;
|
#[repr(u8)]
|
||||||
pub const STROKE: u8 = 2;
|
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, ToCss)]
|
||||||
pub const MARKERS: u8 = 3;
|
pub enum PaintOrder {
|
||||||
|
Normal = 0,
|
||||||
|
Fill = 1,
|
||||||
|
Stroke = 2,
|
||||||
|
Markers = 3,
|
||||||
|
}
|
||||||
|
|
||||||
// number of bits for each component
|
/// Number of non-normal components.
|
||||||
pub const SHIFT: u8 = 2;
|
const COUNT: u8 = 3;
|
||||||
// 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
|
/// 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
|
/// Each pair can be set to FILL, STROKE, or MARKERS
|
||||||
/// Lowest significant bit pairs are highest priority.
|
/// Lowest significant bit pairs are highest priority.
|
||||||
|
@ -165,74 +171,83 @@ ${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue)]
|
#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue)]
|
||||||
pub struct SpecifiedValue(pub u8);
|
pub struct SpecifiedValue(pub u8);
|
||||||
|
|
||||||
|
impl SpecifiedValue {
|
||||||
|
fn normal() -> Self {
|
||||||
|
SpecifiedValue(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod computed_value {
|
pub mod computed_value {
|
||||||
pub use super::SpecifiedValue as T;
|
pub use super::SpecifiedValue as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_initial_value() -> SpecifiedValue {
|
pub fn get_initial_value() -> SpecifiedValue {
|
||||||
SpecifiedValue(NORMAL)
|
SpecifiedValue::normal()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpecifiedValue {
|
impl SpecifiedValue {
|
||||||
pub fn bits_at(&self, pos: u8) -> u8 {
|
fn order_at(&self, pos: u8) -> PaintOrder {
|
||||||
(self.0 >> pos * SHIFT) & MASK
|
// 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>)
|
pub fn parse<'i, 't>(
|
||||||
-> Result<SpecifiedValue,ParseError<'i>> {
|
_context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>
|
||||||
|
) -> Result<SpecifiedValue,ParseError<'i>> {
|
||||||
if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) {
|
if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) {
|
||||||
Ok(SpecifiedValue(0))
|
return Ok(SpecifiedValue::normal())
|
||||||
} 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 mut value = 0;
|
||||||
let result: Result<_, ParseError> = input.try(|i| {
|
// bitfield representing what we've seen so far
|
||||||
try_match_ident_ignore_ascii_case! { i.expect_ident()?,
|
// bit 1 is fill, bit 2 is stroke, bit 3 is markers
|
||||||
"fill" => Ok(FILL),
|
let mut seen = 0;
|
||||||
"stroke" => Ok(STROKE),
|
let mut pos = 0;
|
||||||
"markers" => Ok(MARKERS),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
match result {
|
loop {
|
||||||
Ok(val) => {
|
let result: Result<_, ParseError> = input.try(|i| {
|
||||||
if (seen & (1 << val)) != 0 {
|
try_match_ident_ignore_ascii_case! { i.expect_ident()?,
|
||||||
// don't parse the same ident twice
|
"fill" => Ok(PaintOrder::Fill),
|
||||||
return Err(StyleParseError::UnspecifiedError.into())
|
"stroke" => Ok(PaintOrder::Stroke),
|
||||||
} else {
|
"markers" => Ok(PaintOrder::Markers),
|
||||||
value |= val << (pos * SHIFT);
|
|
||||||
seen |= 1 << val;
|
|
||||||
pos += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => break,
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
if value == 0 {
|
match result {
|
||||||
// couldn't find any keyword
|
Ok(val) => {
|
||||||
Err(StyleParseError::UnspecifiedError.into())
|
if (seen & (1 << val as u8)) != 0 {
|
||||||
} else {
|
// don't parse the same ident twice
|
||||||
// fill in rest
|
return Err(StyleParseError::UnspecifiedError.into())
|
||||||
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))
|
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(StyleParseError::UnspecifiedError.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
impl ToCss for SpecifiedValue {
|
||||||
|
@ -241,16 +256,21 @@ ${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
|
||||||
return dest.write_str("normal")
|
return dest.write_str("normal")
|
||||||
}
|
}
|
||||||
|
|
||||||
for pos in 0..COUNT {
|
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 {
|
if pos != 0 {
|
||||||
dest.write_str(" ")?
|
dest.write_str(" ")?
|
||||||
}
|
}
|
||||||
match self.bits_at(pos) {
|
self.order_at(pos).to_css(dest)?;
|
||||||
FILL => dest.write_str("fill")?,
|
|
||||||
STROKE => dest.write_str("stroke")?,
|
|
||||||
MARKERS => dest.write_str("markers")?,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue