Auto merge of #15627 - Manishearth:stylo-svg, r=heycam

stylo: Finish all SVG properties

reviewed in bug https://bugzilla.mozilla.org/show_bug.cgi?id=1338388

<!-- 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/15627)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-02-18 04:13:59 -08:00 committed by GitHub
commit d3ba09e588
17 changed files with 844 additions and 101 deletions

View file

@ -365,6 +365,7 @@ mod bindings {
"nsStylePadding",
"nsStylePosition",
"nsStyleSVG",
"nsStyleSVGPaint",
"nsStyleSVGReset",
"nsStyleTable",
"nsStyleTableBorder",
@ -383,6 +384,7 @@ mod bindings {
"PropertyValuePair",
"Runnable",
"ServoAttrSnapshot",
"ServoBundledURI",
"ServoElementSnapshot",
"SheetParsingMode",
"StaticRefPtr",
@ -506,6 +508,7 @@ mod bindings {
.whitelisted_function("Servo_.*")
.whitelisted_function("Gecko_.*");
let structs_types = [
"mozilla::css::URLValue",
"RawGeckoDocument",
"RawGeckoElement",
"RawGeckoKeyframeList",
@ -523,6 +526,7 @@ mod bindings {
"FontFamilyList",
"FontFamilyType",
"Keyframe",
"ServoBundledURI",
"ServoElementSnapshot",
"SheetParsingMode",
"StyleBasicShape",
@ -550,6 +554,7 @@ mod bindings {
"nsStyleCoord_CalcValue",
"nsStyleDisplay",
"nsStyleEffects",
"nsStyleFilter",
"nsStyleFont",
"nsStyleGradient",
"nsStyleGradientStop",
@ -565,6 +570,7 @@ mod bindings {
"nsStylePosition",
"nsStyleQuoteValues",
"nsStyleSVG",
"nsStyleSVGPaint",
"nsStyleSVGReset",
"nsStyleTable",
"nsStyleTableBorder",

View file

@ -3,6 +3,7 @@
pub use nsstring::{nsACString, nsAString};
type nsACString_internal = nsACString;
type nsAString_internal = nsAString;
use gecko_bindings::structs::mozilla::css::URLValue;
use gecko_bindings::structs::RawGeckoDocument;
use gecko_bindings::structs::RawGeckoElement;
use gecko_bindings::structs::RawGeckoKeyframeList;
@ -20,6 +21,7 @@ use gecko_bindings::structs::TraversalRootBehavior;
use gecko_bindings::structs::FontFamilyList;
use gecko_bindings::structs::FontFamilyType;
use gecko_bindings::structs::Keyframe;
use gecko_bindings::structs::ServoBundledURI;
use gecko_bindings::structs::ServoElementSnapshot;
use gecko_bindings::structs::SheetParsingMode;
use gecko_bindings::structs::StyleBasicShape;
@ -69,6 +71,9 @@ unsafe impl Sync for nsStyleDisplay {}
use gecko_bindings::structs::nsStyleEffects;
unsafe impl Send for nsStyleEffects {}
unsafe impl Sync for nsStyleEffects {}
use gecko_bindings::structs::nsStyleFilter;
unsafe impl Send for nsStyleFilter {}
unsafe impl Sync for nsStyleFilter {}
use gecko_bindings::structs::nsStyleFont;
unsafe impl Send for nsStyleFont {}
unsafe impl Sync for nsStyleFont {}
@ -114,6 +119,9 @@ unsafe impl Sync for nsStyleQuoteValues {}
use gecko_bindings::structs::nsStyleSVG;
unsafe impl Send for nsStyleSVG {}
unsafe impl Sync for nsStyleSVG {}
use gecko_bindings::structs::nsStyleSVGPaint;
unsafe impl Send for nsStyleSVGPaint {}
unsafe impl Sync for nsStyleSVGPaint {}
use gecko_bindings::structs::nsStyleSVGReset;
unsafe impl Send for nsStyleSVGReset {}
unsafe impl Sync for nsStyleSVGReset {}
@ -590,11 +598,7 @@ extern "C" {
}
extern "C" {
pub fn Gecko_SetListStyleImage(style_struct: *mut nsStyleList,
string_bytes: *const u8,
string_length: u32,
base_uri: *mut ThreadSafeURIHolder,
referrer: *mut ThreadSafeURIHolder,
principal: *mut ThreadSafePrincipalHolder);
uri: ServoBundledURI);
}
extern "C" {
pub fn Gecko_CopyListStyleImageFrom(dest: *mut nsStyleList,
@ -615,17 +619,6 @@ extern "C" {
pub fn Gecko_CopyCursorArrayFrom(dest: *mut nsStyleUserInterface,
src: *const nsStyleUserInterface);
}
extern "C" {
pub fn Gecko_SetMozBinding(style_struct: *mut nsStyleDisplay,
string_bytes: *const u8, string_length: u32,
base_uri: *mut ThreadSafeURIHolder,
referrer: *mut ThreadSafeURIHolder,
principal: *mut ThreadSafePrincipalHolder);
}
extern "C" {
pub fn Gecko_CopyMozBindingFrom(des: *mut nsStyleDisplay,
src: *const nsStyleDisplay);
}
extern "C" {
pub fn Gecko_GetNodeFlags(node: RawGeckoNodeBorrowed) -> u32;
}
@ -707,6 +700,10 @@ extern "C" {
pub fn Gecko_NewBasicShape(type_: StyleBasicShapeType)
-> *mut StyleBasicShape;
}
extern "C" {
pub fn Gecko_StyleClipPath_SetURLValue(clip: *mut StyleClipPath,
uri: ServoBundledURI);
}
extern "C" {
pub fn Gecko_ResetFilters(effects: *mut nsStyleEffects, new_len: usize);
}
@ -714,6 +711,38 @@ extern "C" {
pub fn Gecko_CopyFiltersFrom(aSrc: *mut nsStyleEffects,
aDest: *mut nsStyleEffects);
}
extern "C" {
pub fn Gecko_nsStyleFilter_SetURLValue(effects: *mut nsStyleFilter,
uri: ServoBundledURI);
}
extern "C" {
pub fn Gecko_nsStyleSVGPaint_CopyFrom(dest: *mut nsStyleSVGPaint,
src: *const nsStyleSVGPaint);
}
extern "C" {
pub fn Gecko_nsStyleSVGPaint_SetURLValue(paint: *mut nsStyleSVGPaint,
uri: ServoBundledURI);
}
extern "C" {
pub fn Gecko_nsStyleSVGPaint_Reset(paint: *mut nsStyleSVGPaint);
}
extern "C" {
pub fn Gecko_nsStyleSVG_SetDashArrayLength(svg: *mut nsStyleSVG,
len: u32);
}
extern "C" {
pub fn Gecko_nsStyleSVG_CopyDashArray(dst: *mut nsStyleSVG,
src: *const nsStyleSVG);
}
extern "C" {
pub fn Gecko_NewURLValue(uri: ServoBundledURI) -> *mut URLValue;
}
extern "C" {
pub fn Gecko_AddRefCSSURLValueArbitraryThread(aPtr: *mut URLValue);
}
extern "C" {
pub fn Gecko_ReleaseCSSURLValueArbitraryThread(aPtr: *mut URLValue);
}
extern "C" {
pub fn Gecko_FillAllBackgroundLists(layers: *mut nsStyleImageLayers,
max_len: u32);

View file

@ -25363,6 +25363,23 @@ pub mod root {
pub type ThreadSafePrincipalHolder =
root::nsMainThreadPtrHolder<root::nsIPrincipal>;
pub type ThreadSafeURIHolder = root::nsMainThreadPtrHolder<root::nsIURI>;
#[repr(C)]
#[derive(Debug, Copy)]
pub struct ServoBundledURI {
pub mURLString: *const u8,
pub mURLStringLength: u32,
pub mBaseURI: *mut root::ThreadSafeURIHolder,
pub mReferrer: *mut root::ThreadSafeURIHolder,
pub mPrincipal: *mut root::ThreadSafePrincipalHolder,
}
#[test]
fn bindgen_test_layout_ServoBundledURI() {
assert_eq!(::std::mem::size_of::<ServoBundledURI>() , 40usize);
assert_eq!(::std::mem::align_of::<ServoBundledURI>() , 8usize);
}
impl Clone for ServoBundledURI {
fn clone(&self) -> Self { *self }
}
pub type nsMediaFeatureValueGetter =
::std::option::Option<unsafe extern "C" fn(aPresContext:
*mut root::nsPresContext,

View file

@ -24719,6 +24719,23 @@ pub mod root {
pub type ThreadSafePrincipalHolder =
root::nsMainThreadPtrHolder<root::nsIPrincipal>;
pub type ThreadSafeURIHolder = root::nsMainThreadPtrHolder<root::nsIURI>;
#[repr(C)]
#[derive(Debug, Copy)]
pub struct ServoBundledURI {
pub mURLString: *const u8,
pub mURLStringLength: u32,
pub mBaseURI: *mut root::ThreadSafeURIHolder,
pub mReferrer: *mut root::ThreadSafeURIHolder,
pub mPrincipal: *mut root::ThreadSafePrincipalHolder,
}
#[test]
fn bindgen_test_layout_ServoBundledURI() {
assert_eq!(::std::mem::size_of::<ServoBundledURI>() , 40usize);
assert_eq!(::std::mem::align_of::<ServoBundledURI>() , 8usize);
}
impl Clone for ServoBundledURI {
fn clone(&self) -> Self { *self }
}
pub type nsMediaFeatureValueGetter =
::std::option::Option<unsafe extern "C" fn(aPresContext:
*mut root::nsPresContext,

View file

@ -264,6 +264,9 @@ impl_threadsafe_refcount!(::gecko_bindings::structs::nsStyleQuoteValues,
impl_threadsafe_refcount!(::gecko_bindings::structs::nsCSSValueSharedList,
Gecko_AddRefCSSValueSharedListArbitraryThread,
Gecko_ReleaseCSSValueSharedListArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::mozilla::css::URLValue,
Gecko_AddRefCSSURLValueArbitraryThread,
Gecko_ReleaseCSSURLValueArbitraryThread);
/// A Gecko `ThreadSafePrincipalHolder` wrapped in a safe refcounted pointer, to
/// use during stylesheet parsing and style computation.
pub type GeckoArcPrincipal = RefPtr<::gecko_bindings::structs::ThreadSafePrincipalHolder>;

View file

@ -110,6 +110,22 @@ impl<T> Parse for Vec<T> where T: Parse + OneOrMoreCommaSeparated {
}
}
/// Parse a non-empty space-separated or comma-separated list of objects parsed by parse_one
pub fn parse_space_or_comma_separated<F, T>(input: &mut Parser, mut parse_one: F)
-> Result<Vec<T>, ()>
where F: FnMut(&mut Parser) -> Result<T, ()> {
let first = parse_one(input)?;
let mut vec = vec![first];
loop {
let _ = input.try(|i| i.expect_comma());
if let Ok(val) = input.try(|i| parse_one(i)) {
vec.push(val)
} else {
break
}
}
Ok(vec)
}
impl Parse for UnicodeRange {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
UnicodeRange::parse(input)

View file

@ -11,6 +11,7 @@
<%namespace name="helpers" file="/helpers.mako.rs" />
use app_units::Au;
use cssparser::Color;
use custom_properties::ComputedValuesMap;
use gecko_bindings::bindings;
% for style_struct in data.style_structs:
@ -25,7 +26,6 @@ use gecko_bindings::bindings::Gecko_CopyFontFamilyFrom;
use gecko_bindings::bindings::Gecko_CopyImageValueFrom;
use gecko_bindings::bindings::Gecko_CopyListStyleImageFrom;
use gecko_bindings::bindings::Gecko_CopyListStyleTypeFrom;
use gecko_bindings::bindings::Gecko_CopyMozBindingFrom;
use gecko_bindings::bindings::Gecko_EnsureImageLayersLength;
use gecko_bindings::bindings::Gecko_FontFamilyList_AppendGeneric;
use gecko_bindings::bindings::Gecko_FontFamilyList_AppendNamed;
@ -36,7 +36,6 @@ use gecko_bindings::bindings::Gecko_NewCSSShadowArray;
use gecko_bindings::bindings::Gecko_SetListStyleImage;
use gecko_bindings::bindings::Gecko_SetListStyleImageNone;
use gecko_bindings::bindings::Gecko_SetListStyleType;
use gecko_bindings::bindings::Gecko_SetMozBinding;
use gecko_bindings::bindings::Gecko_SetNullImageValue;
use gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull;
use gecko_bindings::bindings::{Gecko_ResetFilters, Gecko_CopyFiltersFrom};
@ -274,6 +273,19 @@ def set_gecko_property(ffi_name, expr):
}
</%def>
/// Convert a Servo color into an nscolor; with currentColor as 0
///
/// Call sites will need to be updated after https://bugzilla.mozilla.org/show_bug.cgi?id=760345
fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
match color {
Color::RGBA(rgba) => {
convert_rgba_to_nscolor(&rgba)
},
Color::CurrentColor => 0,
}
}
<%def name="impl_color_setter(ident, gecko_ffi_name, complex_color=True)">
#[allow(unreachable_code)]
#[allow(non_snake_case)]
@ -281,12 +293,7 @@ def set_gecko_property(ffi_name, expr):
% if complex_color:
let result = v.into();
% else:
use cssparser::Color;
let result = match v {
Color::RGBA(rgba) => convert_rgba_to_nscolor(&rgba),
// FIXME #13547
Color::CurrentColor => 0,
};
let result = color_to_nscolor_zero_currentcolor(v);
% endif
${set_gecko_property(gecko_ffi_name, "result")}
}
@ -306,7 +313,6 @@ def set_gecko_property(ffi_name, expr):
% if complex_color:
${get_gecko_property(gecko_ffi_name)}.into()
% else:
use cssparser::Color;
Color::RGBA(convert_nscolor_to_rgba(${get_gecko_property(gecko_ffi_name)}))
% endif
}
@ -369,6 +375,58 @@ def set_gecko_property(ffi_name, expr):
% endif
</%def>
<%def name="impl_svg_paint(ident, gecko_ffi_name, need_clone=False, complex_color=True)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, mut v: longhands::${ident}::computed_value::T) {
use values::computed::SVGPaintKind;
use self::structs::nsStyleSVGPaintType;
let ref mut paint = ${get_gecko_property(gecko_ffi_name)};
unsafe {
bindings::Gecko_nsStyleSVGPaint_Reset(paint);
}
let fallback = v.fallback.take();
match v.kind {
SVGPaintKind::None => return,
SVGPaintKind::ContextFill => {
paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_ContextFill;
}
SVGPaintKind::ContextStroke => {
paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_ContextStroke;
}
SVGPaintKind::PaintServer(url) => {
unsafe {
if let Some(ffi) = url.for_ffi() {
bindings::Gecko_nsStyleSVGPaint_SetURLValue(paint, ffi);
} else {
return;
}
}
}
SVGPaintKind::Color(color) => {
paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_Color;
unsafe {
*paint.mPaint.mColor.as_mut() = color_to_nscolor_zero_currentcolor(color);
}
}
}
if let Some(fallback) = fallback {
paint.mFallbackColor = color_to_nscolor_zero_currentcolor(fallback);
}
}
#[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) {
unsafe {
bindings::Gecko_nsStyleSVGPaint_CopyFrom(
&mut ${get_gecko_property(gecko_ffi_name)},
& ${get_gecko_property(gecko_ffi_name, "other")}
);
}
}
</%def>
<%def name="impl_app_units(ident, gecko_ffi_name, need_clone, round_to_pixels=False)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
@ -455,6 +513,41 @@ def set_gecko_property(ffi_name, expr):
% endif
</%def>
<%def name="impl_css_url(ident, gecko_ffi_name, need_clone=False)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
use gecko_bindings::sugar::refptr::RefPtr;
match v {
Either::First(url) => {
let refptr = unsafe {
if let Some(ffi) = url.for_ffi() {
let ptr = bindings::Gecko_NewURLValue(ffi);
RefPtr::from_addrefed(ptr)
} else {
self.gecko.${gecko_ffi_name}.clear();
return;
}
};
self.gecko.${gecko_ffi_name}.set_move(refptr)
}
Either::Second(_none) => {
unsafe {
self.gecko.${gecko_ffi_name}.clear();
}
}
}
}
#[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) {
unsafe {
self.gecko.${gecko_ffi_name}.set(&other.gecko.${gecko_ffi_name});
}
}
% if need_clone:
<% raise Exception("Do not know how to handle clone ") %>
% endif
</%def>
<%def name="impl_logical(name, need_clone=False, **kwargs)">
${helpers.logical_setter(name, need_clone)}
</%def>
@ -543,6 +636,8 @@ impl Debug for ${style_struct.gecko_struct_name} {
"Number": impl_simple,
"Opacity": impl_simple,
"CSSColor": impl_color,
"SVGPaint": impl_svg_paint,
"UrlOrNone": impl_css_url,
}
def longhand_method(longhand):
@ -1221,7 +1316,7 @@ fn static_assert() {
animation-name animation-delay animation-duration
animation-direction animation-fill-mode animation-play-state
animation-iteration-count animation-timing-function
-moz-binding page-break-before page-break-after
page-break-before page-break-after
scroll-snap-points-x scroll-snap-points-y transform
scroll-snap-type-y scroll-snap-coordinate
perspective-origin transform-origin""" %>
@ -1316,33 +1411,6 @@ fn static_assert() {
<%call expr="impl_coord_copy('vertical_align', 'mVerticalAlign')"></%call>
#[allow(non_snake_case)]
pub fn set__moz_binding(&mut self, v: longhands::_moz_binding::computed_value::T) {
use values::Either;
match v {
Either::Second(_none) => debug_assert!(self.gecko.mBinding.mRawPtr.is_null()),
Either::First(ref url) => {
let extra_data = url.extra_data();
let (ptr, len) = match url.as_slice_components() {
Ok(value) => value,
Err(_) => (ptr::null(), 0),
};
unsafe {
Gecko_SetMozBinding(&mut self.gecko,
ptr,
len as u32,
extra_data.base.get(),
extra_data.referrer.get(),
extra_data.principal.get());
}
}
}
}
#[allow(non_snake_case)]
pub fn copy__moz_binding_from(&mut self, other: &Self) {
unsafe { Gecko_CopyMozBindingFrom(&mut self.gecko, &other.gecko); }
}
// Temp fix for Bugzilla bug 24000.
// Map 'auto' and 'avoid' to false, and 'always', 'left', and 'right' to true.
// "A conforming user agent may interpret the values 'left' and 'right'
@ -2066,17 +2134,13 @@ fn static_assert() {
}
}
Either::First(ref url) => {
let (ptr, len) = match url.as_slice_components() {
Ok(value) | Err(value) => value
};
let extra_data = url.extra_data();
unsafe {
Gecko_SetListStyleImage(&mut self.gecko,
ptr,
len as u32,
extra_data.base.get(),
extra_data.referrer.get(),
extra_data.principal.get());
if let Some(ffi) = url.for_ffi() {
Gecko_SetListStyleImage(&mut self.gecko,
ffi);
} else {
Gecko_SetListStyleImageNone(&mut self.gecko);
}
}
// We don't need to record this struct as uncacheable, like when setting
// background-image to a url() value, since only properties in reset structs
@ -2147,7 +2211,6 @@ fn static_assert() {
<%self:impl_trait style_struct_name="Effects"
skip_longhands="box-shadow filter">
pub fn set_box_shadow(&mut self, v: longhands::box_shadow::computed_value::T) {
use cssparser::Color;
self.gecko.mBoxShadow.replace_with_new(v.0.len() as u32);
@ -2178,8 +2241,6 @@ fn static_assert() {
}
pub fn clone_box_shadow(&self) -> longhands::box_shadow::computed_value::T {
use cssparser::Color;
let buf = self.gecko.mBoxShadow.iter().map(|shadow| {
longhands::box_shadow::single_value::computed_value::T {
offset_x: Au(shadow.mXOffset),
@ -2194,7 +2255,6 @@ fn static_assert() {
}
pub fn set_filter(&mut self, v: longhands::filter::computed_value::T) {
use cssparser::Color;
use properties::longhands::filter::computed_value::Filter::*;
use gecko_bindings::structs::nsCSSShadowArray;
use gecko_bindings::structs::nsStyleFilter;
@ -2279,6 +2339,13 @@ fn static_assert() {
Color::CurrentColor => 0,
};
}
Url(ref url) => {
unsafe {
if let Some(ffi) = url.for_ffi() {
bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, ffi);
}
}
}
}
}
}
@ -2316,7 +2383,6 @@ fn static_assert() {
${impl_keyword('text_align', 'mTextAlign', text_align_keyword, need_clone=False)}
pub fn set_text_shadow(&mut self, v: longhands::text_shadow::computed_value::T) {
use cssparser::Color;
self.gecko.mTextShadow.replace_with_new(v.0.len() as u32);
for (servo, gecko_shadow) in v.0.into_iter()
@ -2344,7 +2410,6 @@ fn static_assert() {
}
pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T {
use cssparser::Color;
let buf = self.gecko.mTextShadow.iter().map(|shadow| {
longhands::text_shadow::computed_value::TextShadow {
@ -2636,7 +2701,13 @@ clip-path
clip_path.mType = StyleShapeSourceType::None;
match v {
ShapeSource::Url(..) => warn!("stylo: clip-path: url() not yet implemented"),
ShapeSource::Url(ref url) => {
unsafe {
if let Some(ffi) = url.for_ffi() {
bindings::Gecko_StyleClipPath_SetURLValue(clip_path, ffi);
}
}
}
ShapeSource::None => {} // don't change the type
ShapeSource::Box(reference) => {
clip_path.mReferenceBox = reference.into();
@ -2726,32 +2797,51 @@ clip-path
Gecko_CopyClipPathValueFrom(&mut self.gecko.mClipPath, &other.gecko.mClipPath);
}
}
</%self:impl_trait>
pub fn clone_clip_path(&self) -> longhands::clip_path::computed_value::T {
use gecko_bindings::structs::StyleShapeSourceType;
use gecko_bindings::structs::StyleGeometryBox;
use values::computed::basic_shape::*;
let ref clip_path = self.gecko.mClipPath;
<%self:impl_trait style_struct_name="InheritedSVG"
skip_longhands="paint-order stroke-dasharray"
skip_additionals="*">
pub fn set_paint_order(&mut self, v: longhands::paint_order::computed_value::T) {
use self::longhands::paint_order;
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 StyleGeometryBox::NoBox = clip_path.mReferenceBox {
None
} else {
Some(clip_path.mReferenceBox.into())
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!(),
};
let union = clip_path.__bindgen_anon_1;
let shape = unsafe { &**union.mBasicShape.as_ref() };
ShapeSource::Shape(shape.into(), reference)
order |= geckoval << (pos * structs::NS_STYLE_PAINT_ORDER_BITWIDTH as u8);
}
self.gecko.mPaintOrder = order;
}
}
${impl_simple_copy('paint_order', 'mPaintOrder')}
pub fn set_stroke_dasharray(&mut self, v: longhands::stroke_dasharray::computed_value::T) {
unsafe {
bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut self.gecko, v.0.len() as u32);
}
for (mut gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v.0.into_iter()) {
match servo {
Either::First(lop) => gecko.set(lop),
Either::Second(number) => gecko.set_value(CoordDataValue::Factor(number)),
}
}
}
pub fn copy_stroke_dasharray_from(&mut self, other: &Self) {
unsafe {
bindings::Gecko_nsStyleSVG_CopyDashArray(&mut self.gecko, &other.gecko);
}
}
</%self:impl_trait>

View file

@ -66,7 +66,8 @@
We assume that the default/initial value is an empty vector for these.
`initial_value` need not be defined for these.
</%doc>
<%def name="vector_longhand(name, gecko_only=False, allow_empty=False, delegate_animate=False, **kwargs)">
<%def name="vector_longhand(name, gecko_only=False, allow_empty=False,
delegate_animate=False, space_separated_allowed=False, **kwargs)">
<%call expr="longhand(name, **kwargs)">
% if not gecko_only:
use std::fmt;
@ -86,6 +87,7 @@
use properties::{CSSWideKeyword, DeclaredValue, ShorthandId};
use values::computed::{Context, ToComputedValue};
use values::{computed, specified};
use values::{Auto, Either, None_, Normal};
${caller.body()}
}
@ -166,16 +168,23 @@
}
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
use parser::parse_space_or_comma_separated;
<%
parse_func = "Parser::parse_comma_separated"
if space_separated_allowed:
parse_func = "parse_space_or_comma_separated"
%>
% if allow_empty:
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
Ok(SpecifiedValue(Vec::new()))
} else {
input.parse_comma_separated(|parser| {
${parse_func}(input, |parser| {
single_value::parse(context, parser)
}).map(SpecifiedValue)
}
% else:
input.parse_comma_separated(|parser| {
${parse_func}(input, |parser| {
single_value::parse(context, parser)
}).map(SpecifiedValue)
% endif

View file

@ -1922,6 +1922,7 @@ ${helpers.single_keyword("-moz-appearance",
${helpers.predefined_type("-moz-binding", "UrlOrNone", "Either::Second(None_)",
products="gecko",
animatable="False",
gecko_ffi_name="mBinding",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-binding)",
disable_when_testing="True",
boxed=True)}

View file

@ -94,6 +94,7 @@ ${helpers.predefined_type("clip",
use style_traits::{self, ToCss};
use values::{CSSFloat, HasViewportPercentage};
use values::specified::{Angle, CSSColor, Length, Shadow};
use values::specified::url::SpecifiedUrl;
impl HasViewportPercentage for SpecifiedValue {
fn has_viewport_percentage(&self) -> bool {
@ -129,6 +130,7 @@ ${helpers.predefined_type("clip",
Sepia(CSSFloat),
% if product == "gecko":
DropShadow(Shadow),
Url(SpecifiedUrl),
% endif
}
@ -136,7 +138,8 @@ ${helpers.predefined_type("clip",
use app_units::Au;
use values::CSSFloat;
use values::computed::{CSSColor, Shadow};
use values::specified::{Angle};
use values::specified::Angle;
use values::specified::url::SpecifiedUrl;
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
@ -152,6 +155,7 @@ ${helpers.predefined_type("clip",
Sepia(CSSFloat),
% if product == "gecko":
DropShadow(Shadow),
Url(SpecifiedUrl),
% endif
}
@ -262,6 +266,11 @@ ${helpers.predefined_type("clip",
try!(shadow.color.to_css(dest));
try!(dest.write_str(")"));
}
computed_value::Filter::Url(ref url) => {
dest.write_str("url(")?;
url.to_css(dest)?;
dest.write_str(")")?;
}
% endif
}
Ok(())
@ -302,6 +311,11 @@ ${helpers.predefined_type("clip",
}
try!(dest.write_str(")"));
}
SpecifiedFilter::Url(ref url) => {
dest.write_str("url(")?;
url.to_css(dest)?;
dest.write_str(")")?;
}
% endif
}
Ok(())
@ -319,6 +333,11 @@ ${helpers.predefined_type("clip",
return Ok(SpecifiedValue(filters))
}
loop {
% if product == "gecko":
if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
filters.push(SpecifiedFilter::Url(url));
} else
% endif
if let Ok(function_name) = input.try(|input| input.expect_function()) {
filters.push(try!(input.parse_nested_block(|input| {
match_ignore_ascii_case! { function_name,
@ -375,6 +394,9 @@ ${helpers.predefined_type("clip",
SpecifiedFilter::DropShadow(ref shadow) => {
computed_value::Filter::DropShadow(shadow.to_computed_value(context))
},
SpecifiedFilter::Url(ref url) => {
computed_value::Filter::Url(url.to_computed_value(context))
}
% endif
}
}).collect() }
@ -394,9 +416,14 @@ ${helpers.predefined_type("clip",
computed_value::Filter::Saturate(factor) => SpecifiedFilter::Saturate(factor),
computed_value::Filter::Sepia(factor) => SpecifiedFilter::Sepia(factor),
% if product == "gecko":
computed_value::Filter::DropShadow(shadow) => {
computed_value::Filter::DropShadow(ref shadow) => {
SpecifiedFilter::DropShadow(
ToComputedValue::from_computed_value(&shadow),
ToComputedValue::from_computed_value(shadow),
)
}
computed_value::Filter::Url(ref url) => {
SpecifiedFilter::Url(
ToComputedValue::from_computed_value(url),
)
}
% endif

View file

@ -33,6 +33,14 @@ ${helpers.single_keyword("color-interpolation-filters", "auto sRGB linearRGB",
animatable=False,
spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty")}
${helpers.predefined_type(
"fill", "SVGPaint",
"::values::computed::SVGPaint::black()",
products="gecko",
animatable=False,
boxed=True,
spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint")}
${helpers.predefined_type("fill-opacity", "Opacity", "1.0",
products="gecko", animatable=False,
spec="https://www.w3.org/TR/SVG11/painting.html#FillOpacityProperty")}
@ -49,6 +57,23 @@ ${helpers.single_keyword("shape-rendering",
animatable=False,
spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty")}
${helpers.predefined_type(
"stroke", "SVGPaint",
"Default::default()",
products="gecko",
animatable=False,
boxed=True,
spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint")}
${helpers.predefined_type(
"stroke-width", "LengthOrPercentage",
"computed::LengthOrPercentage::one()",
"parse_numbers_are_pixels_non_negative",
products="gecko",
animatable=True,
needs_context=False,
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth")}
${helpers.single_keyword("stroke-linecap", "butt round square",
products="gecko", animatable=False,
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty")}
@ -67,6 +92,23 @@ ${helpers.predefined_type("stroke-opacity", "Opacity", "1.0",
products="gecko", animatable=False,
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty")}
${helpers.predefined_type("stroke-dasharray", "LoPOrNumber", "Either::Second(0.0)",
"parse_non_negative",
vector="True",
products="gecko",
animatable="False",
space_separated_allowed="True",
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}
${helpers.predefined_type(
"stroke-dashoffset", "LengthOrPercentage",
"computed::LengthOrPercentage::zero()",
"parse_numbers_are_pixels",
products="gecko",
animatable=True,
needs_context=False,
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}
// Section 14 - Clipping, Masking and Compositing
${helpers.single_keyword("clip-rule", "nonzero evenodd",
products="gecko",
@ -74,3 +116,153 @@ ${helpers.single_keyword("clip-rule", "nonzero evenodd",
gecko_inexhaustive=True,
animatable=False,
spec="https://www.w3.org/TR/SVG11/masking.html#ClipRuleProperty")}
${helpers.predefined_type("marker-start", "UrlOrNone", "Either::Second(None_)",
products="gecko",
animatable="False",
spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}
${helpers.predefined_type("marker-mid", "UrlOrNone", "Either::Second(None_)",
products="gecko",
animatable="False",
spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}
${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
products="gecko",
animatable="False",
spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}
<%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)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SpecifiedValue(pub u8);
pub mod computed_value {
pub use super::SpecifiedValue as T;
}
pub fn get_initial_value() -> SpecifiedValue {
SpecifiedValue(NORMAL)
}
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>

View file

@ -0,0 +1,36 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
<%namespace name="helpers" file="/helpers.mako.rs" />
<%helpers:shorthand name="marker" products="gecko"
sub_properties="marker-start marker-end marker-mid"
spec="https://www.w3.org/TR/SVG2/painting.html#MarkerShorthand">
use values::specified::UrlOrNone;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
let url = UrlOrNone::parse(context, input)?;
Ok(Longhands {
marker_start: url.clone(),
marker_mid: url.clone(),
marker_end: url,
})
}
impl<'a> LonghandsToSerialize<'a> {
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
if let DeclaredValue::Value(ref start) = *self.marker_start {
if let DeclaredValue::Value(ref mid) = *self.marker_mid {
if let DeclaredValue::Value(ref end) = *self.marker_end {
if start == mid && mid == end {
start.to_css(dest)?;
}
}
}
}
Ok(())
}
}
</%helpers:shorthand>

View file

@ -4,7 +4,7 @@
//! `<length>` computed values, and related ones.
use app_units::Au;
use app_units::{Au, AU_PER_PX};
use ordered_float::NotNaN;
use std::fmt;
use style_traits::ToCss;
@ -195,6 +195,12 @@ impl LengthOrPercentage {
LengthOrPercentage::Length(Au(0))
}
#[inline]
/// 1px length value for SVG defaults
pub fn one() -> LengthOrPercentage {
LengthOrPercentage::Length(Au(AU_PER_PX))
}
/// Returns true if the computed value is absolute 0 or 0%.
///
/// (Returns false for calc() values, even if ones that may resolve to zero.)

View file

@ -10,7 +10,7 @@ use font_metrics::FontMetricsProvider;
use properties::ComputedValues;
use std::fmt;
use style_traits::ToCss;
use super::{CSSFloat, specified};
use super::{CSSFloat, RGBA, specified};
pub use cssparser::Color as CSSColor;
pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientKind, Image};
@ -19,7 +19,7 @@ pub use super::{Auto, Either, None_};
#[cfg(feature = "gecko")]
pub use super::specified::{AlignJustifyContent, AlignJustifySelf};
pub use super::specified::{Angle, BorderStyle, GridLine, Time, UrlOrNone};
pub use super::specified::url::UrlExtraData;
pub use super::specified::url::{SpecifiedUrl, UrlExtraData};
pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone};
pub use self::position::Position;
@ -185,6 +185,83 @@ pub type Number = CSSFloat;
pub type Opacity = CSSFloat;
/// An SVG paint value
///
/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SVGPaint {
/// The paint source
pub kind: SVGPaintKind,
/// The fallback color
pub fallback: Option<CSSColor>,
}
impl Default for SVGPaint {
fn default() -> Self {
SVGPaint {
kind: SVGPaintKind::None,
fallback: None,
}
}
}
impl SVGPaint {
/// Opaque black color
pub fn black() -> Self {
let rgba = RGBA::from_floats(0., 0., 0., 1.);
SVGPaint {
kind: SVGPaintKind::Color(CSSColor::RGBA(rgba)),
fallback: None,
}
}
}
/// An SVG paint value without the fallback
///
/// Whereas the spec only allows PaintServer
/// to have a fallback, Gecko lets the context
/// properties have a fallback as well.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum SVGPaintKind {
/// `none`
None,
/// `<color>`
Color(CSSColor),
/// `url(...)`
PaintServer(SpecifiedUrl),
/// `context-fill`
ContextFill,
/// `context-stroke`
ContextStroke,
}
impl ToCss for SVGPaintKind {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
SVGPaintKind::None => dest.write_str("none"),
SVGPaintKind::ContextStroke => dest.write_str("context-stroke"),
SVGPaintKind::ContextFill => dest.write_str("context-fill"),
SVGPaintKind::Color(ref color) => color.to_css(dest),
SVGPaintKind::PaintServer(ref server) => server.to_css(dest),
}
}
}
impl ToCss for SVGPaint {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.kind.to_css(dest)?;
if let Some(ref fallback) = self.fallback {
fallback.to_css(dest)?;
}
Ok(())
}
}
/// <length> | <percentage> | <number>
pub type LoPOrNumber = Either<LengthOrPercentage, Number>;
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]

View file

@ -987,6 +987,34 @@ impl LengthOrPercentage {
LengthOrPercentage::parse_internal(input, AllowedNumericType::NonNegative)
}
/// Parse a length, treating dimensionless numbers as pixels
///
/// https://www.w3.org/TR/SVG2/types.html#presentation-attribute-css-value
pub fn parse_numbers_are_pixels(input: &mut Parser) -> Result<LengthOrPercentage, ()> {
if let Ok(lop) = input.try(|i| Self::parse_internal(i, AllowedNumericType::All)) {
Ok(lop)
} else {
let num = input.expect_number()?;
Ok(LengthOrPercentage::Length(NoCalcLength::Absolute(Au((AU_PER_PX * num) as i32))))
}
}
/// Parse a non-negative length, treating dimensionless numbers as pixels
///
/// This is nonstandard behavior used by Firefox for SVG
pub fn parse_numbers_are_pixels_non_negative(input: &mut Parser) -> Result<LengthOrPercentage, ()> {
if let Ok(lop) = input.try(|i| Self::parse_internal(i, AllowedNumericType::NonNegative)) {
Ok(lop)
} else {
let num = input.expect_number()?;
if num >= 0. {
Ok(LengthOrPercentage::Length(NoCalcLength::Absolute(Au((AU_PER_PX * num) as i32))))
} else {
Err(())
}
}
}
/// Extract value from ref without a clone, replacing it with a 0 Au
///
/// Use when you need to move out of a length array without cloning

View file

@ -670,6 +670,175 @@ impl Shadow {
}
}
no_viewport_percentage!(SVGPaint);
/// An SVG paint value
///
/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SVGPaint {
/// The paint source
pub kind: SVGPaintKind,
/// The fallback color
pub fallback: Option<CSSColor>,
}
/// An SVG paint value without the fallback
///
/// Whereas the spec only allows PaintServer
/// to have a fallback, Gecko lets the context
/// properties have a fallback as well.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum SVGPaintKind {
/// `none`
None,
/// `<color>`
Color(CSSColor),
/// `url(...)`
PaintServer(SpecifiedUrl),
/// `context-fill`
ContextFill,
/// `context-stroke`
ContextStroke,
}
impl SVGPaintKind {
fn parse_ident(input: &mut Parser) -> Result<Self, ()> {
Ok(match_ignore_ascii_case! { input.expect_ident()?,
"none" => SVGPaintKind::None,
"context-fill" => SVGPaintKind::ContextFill,
"context-stroke" => SVGPaintKind::ContextStroke,
_ => return Err(())
})
}
}
impl Parse for SVGPaint {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
let fallback = input.try(|i| CSSColor::parse(context, i));
Ok(SVGPaint {
kind: SVGPaintKind::PaintServer(url),
fallback: fallback.ok(),
})
} else if let Ok(kind) = input.try(SVGPaintKind::parse_ident) {
if kind == SVGPaintKind::None {
Ok(SVGPaint {
kind: kind,
fallback: None,
})
} else {
let fallback = input.try(|i| CSSColor::parse(context, i));
Ok(SVGPaint {
kind: kind,
fallback: fallback.ok(),
})
}
} else if let Ok(color) = input.try(|i| CSSColor::parse(context, i)) {
Ok(SVGPaint {
kind: SVGPaintKind::Color(color),
fallback: None,
})
} else {
Err(())
}
}
}
impl ToCss for SVGPaintKind {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
SVGPaintKind::None => dest.write_str("none"),
SVGPaintKind::ContextStroke => dest.write_str("context-stroke"),
SVGPaintKind::ContextFill => dest.write_str("context-fill"),
SVGPaintKind::Color(ref color) => color.to_css(dest),
SVGPaintKind::PaintServer(ref server) => server.to_css(dest),
}
}
}
impl ToCss for SVGPaint {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.kind.to_css(dest)?;
if let Some(ref fallback) = self.fallback {
fallback.to_css(dest)?;
}
Ok(())
}
}
impl ToComputedValue for SVGPaint {
type ComputedValue = super::computed::SVGPaint;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
super::computed::SVGPaint {
kind: self.kind.to_computed_value(context),
fallback: self.fallback.as_ref().map(|f| f.to_computed_value(context))
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
SVGPaint {
kind: ToComputedValue::from_computed_value(&computed.kind),
fallback: computed.fallback.as_ref().map(ToComputedValue::from_computed_value)
}
}
}
impl ToComputedValue for SVGPaintKind {
type ComputedValue = super::computed::SVGPaintKind;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
SVGPaintKind::None => super::computed::SVGPaintKind::None,
SVGPaintKind::ContextStroke => super::computed::SVGPaintKind::ContextStroke,
SVGPaintKind::ContextFill => super::computed::SVGPaintKind::ContextFill,
SVGPaintKind::Color(ref color) => {
super::computed::SVGPaintKind::Color(color.to_computed_value(context))
}
SVGPaintKind::PaintServer(ref server) => {
super::computed::SVGPaintKind::PaintServer(server.to_computed_value(context))
}
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
super::computed::SVGPaintKind::None => SVGPaintKind::None,
super::computed::SVGPaintKind::ContextStroke => SVGPaintKind::ContextStroke,
super::computed::SVGPaintKind::ContextFill => SVGPaintKind::ContextFill,
super::computed::SVGPaintKind::Color(ref color) => {
SVGPaintKind::Color(ToComputedValue::from_computed_value(color))
}
super::computed::SVGPaintKind::PaintServer(ref server) => {
SVGPaintKind::PaintServer(ToComputedValue::from_computed_value(server))
}
}
}
}
/// <length> | <percentage> | <number>
pub type LoPOrNumber = Either<LengthOrPercentage, Number>;
impl LoPOrNumber {
/// parse a <length-percentage> | <number> enforcing that the contents aren't negative
pub fn parse_non_negative(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if let Ok(lop) = input.try(LengthOrPercentage::parse_non_negative) {
Ok(Either::First(lop))
} else if let Ok(num) = input.try(Number::parse_non_negative) {
Ok(Either::Second(num))
} else {
Err(())
}
}
}
impl HasViewportPercentage for ClipRect {
fn has_viewport_percentage(&self) -> bool {

View file

@ -6,6 +6,8 @@
use cssparser::{CssStringWriter, Parser};
#[cfg(feature = "gecko")]
use gecko_bindings::structs::ServoBundledURI;
#[cfg(feature = "gecko")]
use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
use parser::{Parse, ParserContext};
#[cfg(feature = "gecko")]
@ -167,6 +169,24 @@ impl SpecifiedUrl {
extra_data: UrlExtraData {}
}
}
/// Create a bundled URI suitable for sending to Gecko
/// to be constructed into a css::URLValue
#[cfg(feature = "gecko")]
pub fn for_ffi(&self) -> Option<ServoBundledURI> {
let extra_data = self.extra_data();
let (ptr, len) = match self.as_slice_components() {
Ok(value) => value,
Err(_) => return None,
};
Some(ServoBundledURI {
mURLString: ptr,
mURLStringLength: len as u32,
mBaseURI: extra_data.base.get(),
mReferrer: extra_data.referrer.get(),
mPrincipal: extra_data.principal.get(),
})
}
}
impl PartialEq for SpecifiedUrl {