mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
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:
commit
d3ba09e588
17 changed files with 844 additions and 101 deletions
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
36
components/style/properties/shorthand/inherited_svg.mako.rs
Normal file
36
components/style/properties/shorthand/inherited_svg.mako.rs
Normal 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>
|
|
@ -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.)
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue