servo: Merge #12878 - stylo: Support clip-path (from Manishearth:clip-path); r=heycam

Todo:

 - [x] `set_clip_path` (probably needs a bunch of gecko bindings for running constructors/destructors)
 - [ ] Ensure that I've ordered the coordinates correctly
 - [ ] Check that it works
 - [x] Might want to convert NS_STYLE_FILL_RULE and NS_RADIUS to enum classes

Depends on:

 - https://github.com/servo/rust-bindgen/pull/29
 - https://github.com/Manishearth/gecko-dev/compare/servo:stylo...Manishearth:clip-path

Source-Repo: https://github.com/servo/servo
Source-Revision: 609d47b44fdd31b712100839e1d4c5db15dbafcd
This commit is contained in:
Manish Goregaokar 2016-08-19 14:24:08 -05:00
Родитель e6c75b7e31
Коммит 1f0fe40018
14 изменённых файлов: 627 добавлений и 14 удалений

Просмотреть файл

@ -79,3 +79,182 @@ impl From<nsStyleCoord_CalcValue> for LengthOrPercentage {
}
}
}
pub mod basic_shape {
use euclid::size::Size2D;
use gecko_bindings::structs::StyleClipPathGeometryBox;
use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleFillRule};
use gecko_bindings::structs::{nsStyleCoord, nsStyleCorners, nsStyleImageLayers_Position};
use gecko_bindings::sugar::ns_style_coord::{CoordDataMut, CoordDataValue};
use gecko_values::GeckoStyleCoordConvertible;
use std::borrow::Borrow;
use values::computed::basic_shape::*;
use values::computed::position::Position;
use values::computed::{BorderRadiusSize, LengthOrPercentage};
// using Borrow so that we can have a non-moving .into()
impl<T: Borrow<StyleBasicShape>> From<T> for BasicShape {
fn from(other: T) -> Self {
let other = other.borrow();
match other.mType {
StyleBasicShapeType::Inset => {
let t = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[0]);
let r = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[1]);
let b = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[2]);
let l = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[3]);
let round = (&other.mRadius).into();
BasicShape::Inset(InsetRect {
top: t.expect("inset() offset should be a length, percentage, or calc value"),
right: r.expect("inset() offset should be a length, percentage, or calc value"),
bottom: b.expect("inset() offset should be a length, percentage, or calc value"),
left: l.expect("inset() offset should be a length, percentage, or calc value"),
round: Some(round),
})
}
StyleBasicShapeType::Circle => {
BasicShape::Circle(Circle {
radius: (&other.mCoordinates[0]).into(),
position: (&other.mPosition).into()
})
}
StyleBasicShapeType::Ellipse => {
BasicShape::Ellipse(Ellipse {
semiaxis_x: (&other.mCoordinates[0]).into(),
semiaxis_y: (&other.mCoordinates[1]).into(),
position: (&other.mPosition).into()
})
}
StyleBasicShapeType::Polygon => {
let fill_rule = if other.mFillRule == StyleFillRule::Evenodd {
FillRule::EvenOdd
} else {
FillRule::NonZero
};
let mut coords = Vec::with_capacity(other.mCoordinates.len() / 2);
for i in 0..(other.mCoordinates.len() / 2) {
let x = 2 * i;
let y = x + 1;
coords.push((LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[x])
.expect("polygon() coordinate should be a length, percentage, or calc value"),
LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[y])
.expect("polygon() coordinate should be a length, percentage, or calc value")
))
}
BasicShape::Polygon(Polygon {
fill: fill_rule,
coordinates: coords,
})
}
}
}
}
impl<T: Borrow<nsStyleCorners>> From<T> for BorderRadius {
fn from(other: T) -> Self {
let other = other.borrow();
let get_corner = |index| {
BorderRadiusSize(Size2D::new(
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index))
.expect("<border-radius> should be a length, percentage, or calc value"),
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1))
.expect("<border-radius> should be a length, percentage, or calc value")))
};
BorderRadius {
top_left: get_corner(0),
top_right: get_corner(2),
bottom_right: get_corner(4),
bottom_left: get_corner(6),
}
}
}
// Can't be a From impl since we need to set an existing
// nsStyleCorners, not create a new one
impl BorderRadius {
pub fn set_corners(&self, other: &mut nsStyleCorners) {
let mut set_corner = |field: &BorderRadiusSize, index| {
field.0.width.to_gecko_style_coord(&mut other.data_at_mut(index));
field.0.height.to_gecko_style_coord(&mut other.data_at_mut(index + 1));
};
set_corner(&self.top_left, 0);
set_corner(&self.top_right, 2);
set_corner(&self.bottom_right, 4);
set_corner(&self.bottom_left, 6);
}
}
/// We use None for a nonexistant radius, but Gecko uses (0 0 0 0 / 0 0 0 0)
pub fn set_corners_from_radius(radius: Option<BorderRadius>, other: &mut nsStyleCorners) {
if let Some(radius) = radius {
radius.set_corners(other);
} else {
for i in 0..8 {
other.data_at_mut(i).set_value(CoordDataValue::Coord(0));
}
}
}
// Can't be a From impl since we need to set an existing
// nsStyleImageLayers_Position, not create a new one
impl From<Position> for nsStyleImageLayers_Position {
fn from(other: Position) -> Self {
nsStyleImageLayers_Position {
mXPosition: other.horizontal.into(),
mYPosition: other.vertical.into()
}
}
}
impl<T: Borrow<nsStyleCoord>> From<T> for ShapeRadius {
fn from(other: T) -> Self {
let other = other.borrow();
ShapeRadius::from_gecko_style_coord(other)
.expect("<shape-radius> should be a length, percentage, calc, or keyword value")
}
}
impl<T: Borrow<nsStyleImageLayers_Position>> From<T> for Position {
fn from(other: T) -> Self {
let other = other.borrow();
Position {
horizontal: other.mXPosition.into(),
vertical: other.mYPosition.into(),
}
}
}
impl From<GeometryBox> for StyleClipPathGeometryBox {
fn from(reference: GeometryBox) -> Self {
use gecko_bindings::structs::StyleClipPathGeometryBox::*;
match reference {
GeometryBox::ShapeBox(ShapeBox::Content) => Content,
GeometryBox::ShapeBox(ShapeBox::Padding) => Padding,
GeometryBox::ShapeBox(ShapeBox::Border) => Border,
GeometryBox::ShapeBox(ShapeBox::Margin) => Margin,
GeometryBox::Fill => Fill,
GeometryBox::Stroke => Stroke,
GeometryBox::View => View,
}
}
}
// Will panic on NoBox
// Ideally these would be implemented on Option<T>,
// but coherence doesn't like that and TryFrom isn't stable
impl From<StyleClipPathGeometryBox> for GeometryBox {
fn from(reference: StyleClipPathGeometryBox) -> Self {
use gecko_bindings::structs::StyleClipPathGeometryBox::*;
match reference {
NoBox => panic!("Shouldn't convert NoBox to GeometryBox"),
Content => GeometryBox::ShapeBox(ShapeBox::Content),
Padding => GeometryBox::ShapeBox(ShapeBox::Padding),
Border => GeometryBox::ShapeBox(ShapeBox::Border),
Margin => GeometryBox::ShapeBox(ShapeBox::Margin),
Fill => GeometryBox::Fill,
Stroke => GeometryBox::Stroke,
View => GeometryBox::View,
}
}
}
}

Просмотреть файл

@ -7,12 +7,13 @@
use app_units::Au;
use cssparser::RGBA;
use gecko_bindings::structs::nsStyleCoord;
use gecko_bindings::structs::{NS_RADIUS_CLOSEST_SIDE, NS_RADIUS_FARTHEST_SIDE};
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
use std::cmp::max;
use values::computed::Angle;
use values::computed::basic_shape::ShapeRadius;
use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
pub trait StyleCoordHelpers {
fn set<T: GeckoStyleCoordConvertible>(&mut self, val: T);
}
@ -94,6 +95,28 @@ impl GeckoStyleCoordConvertible for LengthOrPercentageOrNone {
}
}
impl GeckoStyleCoordConvertible for ShapeRadius {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
match *self {
ShapeRadius::ClosestSide => {
coord.set_value(CoordDataValue::Enumerated(NS_RADIUS_CLOSEST_SIDE))
}
ShapeRadius::FarthestSide => {
coord.set_value(CoordDataValue::Enumerated(NS_RADIUS_FARTHEST_SIDE))
}
ShapeRadius::Length(lop) => lop.to_gecko_style_coord(coord),
}
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
match coord.as_value() {
CoordDataValue::Enumerated(NS_RADIUS_CLOSEST_SIDE) => Some(ShapeRadius::ClosestSide),
CoordDataValue::Enumerated(NS_RADIUS_FARTHEST_SIDE) => Some(ShapeRadius::FarthestSide),
_ => LengthOrPercentage::from_gecko_style_coord(coord).map(ShapeRadius::Length),
}
}
}
impl<T: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for Option<T> {
fn to_gecko_style_coord<U: CoordDataMut>(&self, coord: &mut U) {
if let Some(ref me) = *self {

Просмотреть файл

@ -81,3 +81,11 @@ impl<'a> ParserContext<'a> {
pub fn log_css_error(input: &mut Parser, position: SourcePosition, message: &str, parsercontext: &ParserContext) {
parsercontext.error_reporter.report_error(input, position, message);
}
// XXXManishearth Replace all specified value parse impls with impls of this
// trait. This will make it easy to write more generic values in the future.
// There may need to be two traits -- one for parsing with context, and one
// for parsing without
pub trait Parse {
fn parse(input: &mut Parser) -> Result<Self, ()> where Self: Sized;
}

Просмотреть файл

@ -1265,7 +1265,7 @@ fn static_assert() {
</%self:impl_trait>
<%self:impl_trait style_struct_name="SVG"
skip_longhands="flood-color lighting-color stop-color"
skip_longhands="flood-color lighting-color stop-color clip-path"
skip_additionals="*">
<% impl_color("flood_color", "mFloodColor") %>
@ -1274,6 +1274,140 @@ fn static_assert() {
<% impl_color("stop_color", "mStopColor") %>
pub fn set_clip_path(&mut self, v: longhands::clip_path::computed_value::T) {
use gecko_bindings::bindings::{Gecko_NewBasicShape, Gecko_DestroyClipPath};
use gecko_bindings::structs::StyleClipPathGeometryBox;
use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleShapeSourceType};
use gecko_bindings::structs::{StyleClipPath, StyleFillRule};
use gecko_conversions::basic_shape::set_corners_from_radius;
use gecko_values::GeckoStyleCoordConvertible;
use values::computed::basic_shape::*;
let ref mut clip_path = self.gecko.mClipPath;
// clean up existing struct
unsafe { Gecko_DestroyClipPath(clip_path) };
clip_path.mType = StyleShapeSourceType::None_;
match v {
ShapeSource::Url(..) => println!("stylo: clip-path: url() not yet implemented"),
ShapeSource::None => {} // don't change the type
ShapeSource::Box(reference) => {
clip_path.mReferenceBox = reference.into();
clip_path.mType = StyleShapeSourceType::Box;
}
ShapeSource::Shape(servo_shape, maybe_box) => {
clip_path.mReferenceBox = maybe_box.map(Into::into)
.unwrap_or(StyleClipPathGeometryBox::NoBox);
clip_path.mType = StyleShapeSourceType::Shape;
fn init_shape(clip_path: &mut StyleClipPath, ty: StyleBasicShapeType) -> &mut StyleBasicShape {
unsafe {
// We have to be very careful to avoid a copy here!
let ref mut union = clip_path.StyleShapeSource_nsStyleStruct_h_unnamed_26;
let mut shape: &mut *mut StyleBasicShape = union.mBasicShape.as_mut();
*shape = Gecko_NewBasicShape(ty);
&mut **shape
}
}
match servo_shape {
BasicShape::Inset(rect) => {
let mut shape = init_shape(clip_path, StyleBasicShapeType::Inset);
unsafe { shape.mCoordinates.set_len(4) };
// set_len() can't call constructors, so the coordinates
// can contain any value. set_value() attempts to free
// allocated coordinates, so we don't want to feed it
// garbage values which it may misinterpret.
// Instead, we use leaky_set_value to blindly overwrite
// the garbage data without
// attempting to clean up.
shape.mCoordinates[0].leaky_set_null();
rect.top.to_gecko_style_coord(&mut shape.mCoordinates[0]);
shape.mCoordinates[1].leaky_set_null();
rect.right.to_gecko_style_coord(&mut shape.mCoordinates[1]);
shape.mCoordinates[2].leaky_set_null();
rect.bottom.to_gecko_style_coord(&mut shape.mCoordinates[2]);
shape.mCoordinates[3].leaky_set_null();
rect.left.to_gecko_style_coord(&mut shape.mCoordinates[3]);
set_corners_from_radius(rect.round, &mut shape.mRadius);
}
BasicShape::Circle(circ) => {
let mut shape = init_shape(clip_path, StyleBasicShapeType::Circle);
unsafe { shape.mCoordinates.set_len(1) };
shape.mCoordinates[0].leaky_set_null();
circ.radius.to_gecko_style_coord(&mut shape.mCoordinates[0]);
shape.mPosition = circ.position.into();
}
BasicShape::Ellipse(el) => {
let mut shape = init_shape(clip_path, StyleBasicShapeType::Ellipse);
unsafe { shape.mCoordinates.set_len(2) };
shape.mCoordinates[0].leaky_set_null();
el.semiaxis_x.to_gecko_style_coord(&mut shape.mCoordinates[0]);
shape.mCoordinates[1].leaky_set_null();
el.semiaxis_y.to_gecko_style_coord(&mut shape.mCoordinates[1]);
shape.mPosition = el.position.into();
}
BasicShape::Polygon(poly) => {
let mut shape = init_shape(clip_path, StyleBasicShapeType::Polygon);
unsafe {
shape.mCoordinates.set_len(poly.coordinates.len() as u32 * 2);
}
for (i, coord) in poly.coordinates.iter().enumerate() {
shape.mCoordinates[2 * i].leaky_set_null();
shape.mCoordinates[2 * i + 1].leaky_set_null();
coord.0.to_gecko_style_coord(&mut shape.mCoordinates[2 * i]);
coord.1.to_gecko_style_coord(&mut shape.mCoordinates[2 * i + 1]);
}
shape.mFillRule = if poly.fill == FillRule::EvenOdd {
StyleFillRule::Evenodd
} else {
StyleFillRule::Nonzero
};
}
}
}
}
}
pub fn copy_clip_path_from(&mut self, other: &Self) {
use gecko_bindings::bindings::Gecko_CopyClipPathValueFrom;
unsafe {
Gecko_CopyClipPathValueFrom(&mut self.gecko.mClipPath, &other.gecko.mClipPath);
}
}
pub fn clone_clip_path(&self) -> longhands::clip_path::computed_value::T {
use gecko_bindings::structs::StyleShapeSourceType;
use gecko_bindings::structs::StyleClipPathGeometryBox;
use values::computed::basic_shape::*;
let ref clip_path = self.gecko.mClipPath;
match clip_path.mType {
StyleShapeSourceType::None_ => ShapeSource::None,
StyleShapeSourceType::Box => {
ShapeSource::Box(clip_path.mReferenceBox.into())
}
StyleShapeSourceType::URL => {
warn!("stylo: clip-path: url() not implemented yet");
Default::default()
}
StyleShapeSourceType::Shape => {
let reference = if let StyleClipPathGeometryBox::NoBox = clip_path.mReferenceBox {
None
} else {
Some(clip_path.mReferenceBox.into())
};
let union = clip_path.StyleShapeSource_nsStyleStruct_h_unnamed_26;
let shape = unsafe { &**union.mBasicShape.as_ref() };
ShapeSource::Shape(shape.into(), reference)
}
}
}
</%self:impl_trait>
<%self:impl_trait style_struct_name="Color"

Просмотреть файл

@ -49,3 +49,31 @@ ${helpers.predefined_type(
// https://www.w3.org/TR/css-masking-1/
${helpers.single_keyword("mask-type", "luminance alpha",
products="gecko", animatable=False)}
<%helpers:longhand name="clip-path" animatable="False" products="gecko">
use cssparser::ToCss;
use std::fmt;
use values::LocalToCss;
use values::NoViewportPercentage;
use values::specified::basic_shape::{ShapeSource, GeometryBox};
pub mod computed_value {
use app_units::Au;
use values::computed::basic_shape::{ShapeSource, GeometryBox};
pub type T = ShapeSource<GeometryBox>;
}
pub type SpecifiedValue = ShapeSource<GeometryBox>;
#[inline]
pub fn get_initial_value() -> computed_value::T {
Default::default()
}
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
ShapeSource::parse(context, input)
}
impl NoViewportPercentage for SpecifiedValue {}
</%helpers:longhand>

Просмотреть файл

@ -10,10 +10,46 @@
use cssparser::ToCss;
use properties::shorthands::serialize_four_sides;
use std::fmt;
use url::Url;
use values::computed::UrlExtraData;
use values::computed::position::Position;
use values::computed::{BorderRadiusSize, LengthOrPercentage};
pub use values::specified::basic_shape::FillRule;
pub use values::specified::basic_shape::{FillRule, GeometryBox, ShapeBox};
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum ShapeSource<T> {
Url(Url, UrlExtraData),
Shape(BasicShape, Option<T>),
Box(T),
None,
}
impl<T> Default for ShapeSource<T> {
fn default() -> Self {
ShapeSource::None
}
}
impl<T: ToCss> ToCss for ShapeSource<T> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
use values::LocalToCss;
match *self {
ShapeSource::Url(ref url, _) => url.to_css(dest),
ShapeSource::Shape(ref shape, Some(ref reference)) => {
try!(shape.to_css(dest));
try!(dest.write_str(" "));
reference.to_css(dest)
}
ShapeSource::Shape(ref shape, None) => shape.to_css(dest),
ShapeSource::Box(ref reference) => reference.to_css(dest),
ShapeSource::None => dest.write_str("none"),
}
}
}
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]

Просмотреть файл

@ -8,13 +8,111 @@
//! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape
use cssparser::{Parser, ToCss};
use parser::{ParserContext, Parse};
use properties::shorthands::{parse_four_sides, serialize_four_sides};
use std::fmt;
use url::Url;
use values::computed::basic_shape as computed_basic_shape;
use values::computed::{Context, ToComputedValue, ComputedValueAsSpecified};
use values::specified::UrlExtraData;
use values::specified::position::Position;
use values::specified::{BorderRadiusSize, LengthOrPercentage, Percentage};
/// A shape source, for some reference box
///
/// clip-path uses ShapeSource<GeometryBox>,
/// shape-outside uses ShapeSource<ShapeBox>
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum ShapeSource<T> {
Url(Url, UrlExtraData),
Shape(BasicShape, Option<T>),
Box(T),
None,
}
impl<T> Default for ShapeSource<T> {
fn default() -> Self {
ShapeSource::None
}
}
impl<T: ToCss> ToCss for ShapeSource<T> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
use values::LocalToCss;
match *self {
ShapeSource::Url(ref url, _) => url.to_css(dest),
ShapeSource::Shape(ref shape, Some(ref reference)) => {
try!(shape.to_css(dest));
try!(dest.write_str(" "));
reference.to_css(dest)
}
ShapeSource::Shape(ref shape, None) => shape.to_css(dest),
ShapeSource::Box(ref reference) => reference.to_css(dest),
ShapeSource::None => dest.write_str("none"),
}
}
}
impl<T: Parse + PartialEq + Copy> ShapeSource<T> {
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if let Ok(_) = input.try(|input| input.expect_ident_matching("none")) {
Ok(ShapeSource::None)
} else if let Ok(url) = input.try(|input| input.expect_url()) {
match UrlExtraData::make_from(context) {
Some(extra_data) => {
Ok(ShapeSource::Url(context.parse_url(&url), extra_data))
},
None => Err(()),
}
} else {
fn parse_component<U: Parse>(input: &mut Parser, component: &mut Option<U>) -> bool {
if component.is_some() {
return false; // already parsed this component
}
*component = input.try(U::parse).ok();
component.is_some()
}
let mut shape = None;
let mut reference = None;
loop {
if !parse_component(input, &mut shape) &&
!parse_component(input, &mut reference) {
break;
}
}
match (shape, reference) {
(Some(shape), _) => Ok(ShapeSource::Shape(shape, reference)),
(None, Some(reference)) => Ok(ShapeSource::Box(reference)),
(None, None) => Err(()),
}
}
}
}
impl<T: ToComputedValue> ToComputedValue for ShapeSource<T> {
type ComputedValue = computed_basic_shape::ShapeSource<T::ComputedValue>;
#[inline]
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
match *self {
ShapeSource::Url(ref url, ref data) => {
computed_basic_shape::ShapeSource::Url(url.clone(), data.clone())
}
ShapeSource::Shape(ref shape, ref reference) => {
computed_basic_shape::ShapeSource::Shape(
shape.to_computed_value(cx),
reference.as_ref().map(|ref r| r.to_computed_value(cx)))
}
ShapeSource::Box(ref reference) => {
computed_basic_shape::ShapeSource::Box(reference.to_computed_value(cx))
}
ShapeSource::None => computed_basic_shape::ShapeSource::None,
}
}
}
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum BasicShape {
@ -24,8 +122,8 @@ pub enum BasicShape {
Polygon(Polygon),
}
impl BasicShape {
pub fn parse(input: &mut Parser) -> Result<BasicShape, ()> {
impl Parse for BasicShape {
fn parse(input: &mut Parser) -> Result<BasicShape, ()> {
match_ignore_ascii_case! { try!(input.expect_function()),
"inset" => {
Ok(BasicShape::Inset(
@ -528,3 +626,77 @@ impl ToCss for FillRule {
}
}
}
/// https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box
#[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum GeometryBox {
Fill,
Stroke,
View,
ShapeBox(ShapeBox),
}
impl Parse for GeometryBox {
fn parse(input: &mut Parser) -> Result<Self, ()> {
if let Ok(shape_box) = input.try(ShapeBox::parse) {
Ok(GeometryBox::ShapeBox(shape_box))
} else {
match_ignore_ascii_case! { try!(input.expect_ident()),
"fill-box" => Ok(GeometryBox::Fill),
"stroke-box" => Ok(GeometryBox::Stroke),
"view-box" => Ok(GeometryBox::View),
_ => Err(())
}
}
}
}
impl ToCss for GeometryBox {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
GeometryBox::Fill => dest.write_str("fill-box"),
GeometryBox::Stroke => dest.write_str("stroke-box"),
GeometryBox::View => dest.write_str("view-box"),
GeometryBox::ShapeBox(s) => s.to_css(dest),
}
}
}
impl ComputedValueAsSpecified for GeometryBox {}
// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box
#[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum ShapeBox {
Margin,
// https://drafts.csswg.org/css-backgrounds-3/#box
Border,
Padding,
Content,
}
impl Parse for ShapeBox {
fn parse(input: &mut Parser) -> Result<Self, ()> {
match_ignore_ascii_case! { try!(input.expect_ident()),
"margin-box" => Ok(ShapeBox::Margin),
"border-box" => Ok(ShapeBox::Border),
"padding-box" => Ok(ShapeBox::Padding),
"content-box" => Ok(ShapeBox::Content),
_ => Err(())
}
}
}
impl ToCss for ShapeBox {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
ShapeBox::Margin => dest.write_str("margin-box"),
ShapeBox::Border => dest.write_str("border-box"),
ShapeBox::Padding => dest.write_str("padding-box"),
ShapeBox::Content => dest.write_str("content-box"),
}
}
}
impl ComputedValueAsSpecified for ShapeBox {}

Просмотреть файл

@ -141,7 +141,8 @@ COMPILATION_TARGETS = {
"nsStyleCoord::Calc", "nsRestyleHint", "ServoElementSnapshot",
"nsChangeHint", "SheetParsingMode", "nsMainThreadPtrHandle",
"nsMainThreadPtrHolder", "nscolor", "nsFont", "FontFamilyList",
"FontFamilyType", "nsIAtom", "nsStyleContext"
"FontFamilyType", "nsIAtom", "nsStyleContext", "StyleClipPath",
"StyleBasicShapeType", "StyleBasicShape"
],
"void_types": [
"nsINode", "nsIDocument", "nsIPrincipal", "nsIURI",

Просмотреть файл

@ -152,6 +152,9 @@ use structs::nsStyleContext;
unsafe impl Send for nsStyleContext {}
unsafe impl Sync for nsStyleContext {}
impl HeapSizeOf for nsStyleContext { fn heap_size_of_children(&self) -> usize { 0 } }
use structs::StyleClipPath;
use structs::StyleBasicShapeType;
use structs::StyleBasicShape;
pub type RawGeckoNode = nsINode;
pub enum Element { }
@ -326,6 +329,11 @@ extern "C" {
pub fn Gecko_SetStyleCoordCalcValue(unit: *mut nsStyleUnit,
value: *mut nsStyleUnion,
calc: CalcValue);
pub fn Gecko_CopyClipPathValueFrom(dst: *mut StyleClipPath,
src: *const StyleClipPath);
pub fn Gecko_DestroyClipPath(clip: *mut StyleClipPath);
pub fn Gecko_NewBasicShape(type_: StyleBasicShapeType)
-> *mut StyleBasicShape;
pub fn Gecko_AddRefCalcArbitraryThread(aPtr: *mut Calc);
pub fn Gecko_ReleaseCalcArbitraryThread(aPtr: *mut Calc);
pub fn Servo_StylesheetFromUTF8Bytes(bytes: *const u8, length: u32,

Просмотреть файл

@ -5452,7 +5452,7 @@ fn bindgen_test_layout_nsStyleSides() {
assert_eq!(::std::mem::align_of::<nsStyleSides>() , 8usize);
}
/**
* Class that represents a set of top-left/top-right/bottom-left/bottom-right
* Class that represents a set of top-left/top-right/bottom-right/bottom-left
* nsStyleCoord pairs. This is used to hold the dimensions of the
* corners of a box (for, e.g., border-radius and outline-radius).
*/
@ -6375,8 +6375,7 @@ fn bindgen_test_layout_StyleAnimation() {
#[repr(C)]
#[derive(Debug)]
pub struct StyleBasicShape {
pub mRefCnt: nsAutoRefCnt,
pub _mOwningThread: nsAutoOwningThread,
pub mRefCnt: ThreadSafeAutoRefCnt,
pub mType: StyleBasicShapeType,
pub mFillRule: StyleFillRule,
pub mCoordinates: nsTArray<nsStyleCoord>,
@ -6385,7 +6384,7 @@ pub struct StyleBasicShape {
}
#[test]
fn bindgen_test_layout_StyleBasicShape() {
assert_eq!(::std::mem::size_of::<StyleBasicShape>() , 128usize);
assert_eq!(::std::mem::size_of::<StyleBasicShape>() , 120usize);
assert_eq!(::std::mem::align_of::<StyleBasicShape>() , 8usize);
}
#[repr(C)]

Просмотреть файл

@ -5431,7 +5431,7 @@ fn bindgen_test_layout_nsStyleSides() {
assert_eq!(::std::mem::align_of::<nsStyleSides>() , 8usize);
}
/**
* Class that represents a set of top-left/top-right/bottom-left/bottom-right
* Class that represents a set of top-left/top-right/bottom-right/bottom-left
* nsStyleCoord pairs. This is used to hold the dimensions of the
* corners of a box (for, e.g., border-radius and outline-radius).
*/
@ -6353,8 +6353,7 @@ fn bindgen_test_layout_StyleAnimation() {
#[repr(C)]
#[derive(Debug)]
pub struct StyleBasicShape {
pub mRefCnt: nsAutoRefCnt,
pub _mOwningThread: nsAutoOwningThread,
pub mRefCnt: ThreadSafeAutoRefCnt,
pub mType: StyleBasicShapeType,
pub mFillRule: StyleFillRule,
pub mCoordinates: nsTArray<nsStyleCoord>,
@ -6363,7 +6362,7 @@ pub struct StyleBasicShape {
}
#[test]
fn bindgen_test_layout_StyleBasicShape() {
assert_eq!(::std::mem::size_of::<StyleBasicShape>() , 128usize);
assert_eq!(::std::mem::size_of::<StyleBasicShape>() , 120usize);
assert_eq!(::std::mem::align_of::<StyleBasicShape>() , 8usize);
}
#[repr(C)]

Просмотреть файл

@ -211,6 +211,17 @@ pub trait CoordDataMut : CoordData {
*union = other.union();
}
/// Useful for initializing uninits
/// (set_value may segfault on uninits)
fn leaky_set_null(&mut self) {
use structs::nsStyleUnit::*;
unsafe {
let (unit, union) = self.values_mut();
*unit = eStyleUnit_Null;
*union.mInt.as_mut() = 0;
}
}
#[inline(always)]
fn set_value(&mut self, value: CoordDataValue) {
use self::CoordDataValue::*;

Просмотреть файл

@ -1172,6 +1172,8 @@ pub enum nsICSSAnonBoxPseudo {}
pub static nsGkAtoms_minheight: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms13minimum_scaleE"]
pub static nsGkAtoms_minimum_scale: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms9minlengthE"]
pub static nsGkAtoms_minlength: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms6minposE"]
pub static nsGkAtoms_minpos: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms9minusSignE"]
@ -3838,6 +3840,8 @@ pub enum nsICSSAnonBoxPseudo {}
pub static nsGkAtoms_onmozinterruptbegin: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms17onmozinterruptendE"]
pub static nsGkAtoms_onmozinterruptend: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms14ondevicechangeE"]
pub static nsGkAtoms_ondevicechange: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms12cdataTagNameE"]
pub static nsGkAtoms_cdataTagName: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms14commentTagNameE"]
@ -6083,6 +6087,8 @@ pub enum nsICSSAnonBoxPseudo {}
pub static nsGkAtoms_minheight: *mut nsIAtom;
#[link_name = "?minimum_scale@nsGkAtoms@@2PEAVnsIAtom@@EA"]
pub static nsGkAtoms_minimum_scale: *mut nsIAtom;
#[link_name = "?minlength@nsGkAtoms@@2PEAVnsIAtom@@EA"]
pub static nsGkAtoms_minlength: *mut nsIAtom;
#[link_name = "?minpos@nsGkAtoms@@2PEAVnsIAtom@@EA"]
pub static nsGkAtoms_minpos: *mut nsIAtom;
#[link_name = "?minusSign@nsGkAtoms@@2PEAVnsIAtom@@EA"]
@ -8749,6 +8755,8 @@ pub enum nsICSSAnonBoxPseudo {}
pub static nsGkAtoms_onmozinterruptbegin: *mut nsIAtom;
#[link_name = "?onmozinterruptend@nsGkAtoms@@2PEAVnsIAtom@@EA"]
pub static nsGkAtoms_onmozinterruptend: *mut nsIAtom;
#[link_name = "?ondevicechange@nsGkAtoms@@2PEAVnsIAtom@@EA"]
pub static nsGkAtoms_ondevicechange: *mut nsIAtom;
#[link_name = "?cdataTagName@nsGkAtoms@@2PEAVnsIAtom@@EA"]
pub static nsGkAtoms_cdataTagName: *mut nsIAtom;
#[link_name = "?commentTagName@nsGkAtoms@@2PEAVnsIAtom@@EA"]
@ -10994,6 +11002,8 @@ pub enum nsICSSAnonBoxPseudo {}
pub static nsGkAtoms_minheight: *mut nsIAtom;
#[link_name = "?minimum_scale@nsGkAtoms@@2PAVnsIAtom@@A"]
pub static nsGkAtoms_minimum_scale: *mut nsIAtom;
#[link_name = "?minlength@nsGkAtoms@@2PAVnsIAtom@@A"]
pub static nsGkAtoms_minlength: *mut nsIAtom;
#[link_name = "?minpos@nsGkAtoms@@2PAVnsIAtom@@A"]
pub static nsGkAtoms_minpos: *mut nsIAtom;
#[link_name = "?minusSign@nsGkAtoms@@2PAVnsIAtom@@A"]
@ -13660,6 +13670,8 @@ pub enum nsICSSAnonBoxPseudo {}
pub static nsGkAtoms_onmozinterruptbegin: *mut nsIAtom;
#[link_name = "?onmozinterruptend@nsGkAtoms@@2PAVnsIAtom@@A"]
pub static nsGkAtoms_onmozinterruptend: *mut nsIAtom;
#[link_name = "?ondevicechange@nsGkAtoms@@2PAVnsIAtom@@A"]
pub static nsGkAtoms_ondevicechange: *mut nsIAtom;
#[link_name = "?cdataTagName@nsGkAtoms@@2PAVnsIAtom@@A"]
pub static nsGkAtoms_cdataTagName: *mut nsIAtom;
#[link_name = "?commentTagName@nsGkAtoms@@2PAVnsIAtom@@A"]
@ -15332,6 +15344,7 @@ macro_rules! atom {
("min") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_min as *mut _) };
("minheight") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_minheight as *mut _) };
("minimum-scale") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_minimum_scale as *mut _) };
("minlength") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_minlength as *mut _) };
("minpos") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_minpos as *mut _) };
("minus-sign") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_minusSign as *mut _) };
("minwidth") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_minwidth as *mut _) };
@ -16665,6 +16678,7 @@ macro_rules! atom {
("ondevicelight") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_ondevicelight as *mut _) };
("onmozinterruptbegin") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_onmozinterruptbegin as *mut _) };
("onmozinterruptend") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_onmozinterruptend as *mut _) };
("ondevicechange") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_ondevicechange as *mut _) };
("#cdata-section") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_cdataTagName as *mut _) };
("#comment") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_commentTagName as *mut _) };
("#document") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::nsGkAtoms_documentNodeName as *mut _) };

Просмотреть файл

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use parsing::parse;
use style::parser::Parse;
use style::values::specified::basic_shape::*;
// Ensure that basic-shape sub-functions parse as both basic shapes