mirror of
https://github.com/servo/servo.git
synced 2025-08-08 06:55:31 +01:00
Auto merge of #21897 - emilio:gecko-sync, r=emilio
style: Sync changes from mozilla-central. See each individual commit for details. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21897) <!-- Reviewable:end -->
This commit is contained in:
commit
68e55ead42
22 changed files with 402 additions and 486 deletions
|
@ -6,7 +6,17 @@ autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated usi
|
||||||
* 1. Get the latest cbindgen using `cargo install --force cbindgen`
|
* 1. Get the latest cbindgen using `cargo install --force cbindgen`
|
||||||
* a. Alternatively, you can clone `https://github.com/eqrion/cbindgen` and use a tagged release
|
* a. Alternatively, you can clone `https://github.com/eqrion/cbindgen` and use a tagged release
|
||||||
* 2. Run `rustup run nightly cbindgen toolkit/library/rust/ --lockfile Cargo.lock --crate style -o layout/style/ServoStyleConsts.h`
|
* 2. Run `rustup run nightly cbindgen toolkit/library/rust/ --lockfile Cargo.lock --crate style -o layout/style/ServoStyleConsts.h`
|
||||||
*/"""
|
*/
|
||||||
|
class nsAtom;
|
||||||
|
namespace mozilla {
|
||||||
|
namespace css {
|
||||||
|
struct URLValue;
|
||||||
|
}
|
||||||
|
// Work-around weird cbindgen renaming.
|
||||||
|
typedef css::URLValue StyleURLValue;
|
||||||
|
typedef nsAtom StylensAtom;
|
||||||
|
}
|
||||||
|
"""
|
||||||
include_guard = "mozilla_ServoStyleConsts_h"
|
include_guard = "mozilla_ServoStyleConsts_h"
|
||||||
include_version = true
|
include_version = true
|
||||||
braces = "SameLine"
|
braces = "SameLine"
|
||||||
|
@ -15,6 +25,10 @@ tab_width = 2
|
||||||
language = "C++"
|
language = "C++"
|
||||||
namespaces = ["mozilla"]
|
namespaces = ["mozilla"]
|
||||||
|
|
||||||
|
[parse]
|
||||||
|
parse_deps = true
|
||||||
|
include = ["cssparser"]
|
||||||
|
|
||||||
[struct]
|
[struct]
|
||||||
derive_eq = true
|
derive_eq = true
|
||||||
|
|
||||||
|
@ -25,9 +39,16 @@ derive_helper_methods = true
|
||||||
prefix = "Style"
|
prefix = "Style"
|
||||||
include = [
|
include = [
|
||||||
"StyleAppearance",
|
"StyleAppearance",
|
||||||
|
"StyleComputedFontStretchRange",
|
||||||
|
"StyleComputedFontStyleDescriptor",
|
||||||
|
"StyleComputedFontWeightRange",
|
||||||
"StyleDisplay",
|
"StyleDisplay",
|
||||||
"StyleDisplayMode",
|
"StyleDisplayMode",
|
||||||
"StyleFillRule",
|
"StyleFillRule",
|
||||||
"StylePathCommand"
|
"StyleFontDisplay",
|
||||||
|
"StyleFontFaceSourceListComponent",
|
||||||
|
"StyleFontLanguageOverride",
|
||||||
|
"StylePathCommand",
|
||||||
|
"StyleUnicodeRange",
|
||||||
]
|
]
|
||||||
item_types = ["enums", "structs", "typedefs"]
|
item_types = ["enums", "structs", "typedefs"]
|
||||||
|
|
|
@ -24,7 +24,7 @@ use style_traits::values::SequenceWriter;
|
||||||
use values::computed::font::FamilyName;
|
use values::computed::font::FamilyName;
|
||||||
use values::generics::font::FontStyle as GenericFontStyle;
|
use values::generics::font::FontStyle as GenericFontStyle;
|
||||||
use values::specified::Angle;
|
use values::specified::Angle;
|
||||||
use values::specified::font::{AbsoluteFontWeight, FontStretch as SpecifiedFontStretch};
|
use values::specified::font::{AbsoluteFontWeight, FontStretch};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use values::specified::font::{SpecifiedFontFeatureSettings, SpecifiedFontVariationSettings};
|
use values::specified::font::{SpecifiedFontFeatureSettings, SpecifiedFontVariationSettings};
|
||||||
use values::specified::font::SpecifiedFontStyle;
|
use values::specified::font::SpecifiedFontStyle;
|
||||||
|
@ -45,6 +45,19 @@ impl OneOrMoreSeparated for Source {
|
||||||
type S = Comma;
|
type S = Comma;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A POD representation for Gecko. All pointers here are non-owned and as such
|
||||||
|
/// can't outlive the rule they came from, but we can't enforce that via C++.
|
||||||
|
///
|
||||||
|
/// All the strings are of course utf8.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
#[repr(u8)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub enum FontFaceSourceListComponent {
|
||||||
|
Url(*const ::gecko_bindings::structs::mozilla::css::URLValue),
|
||||||
|
Local(*mut ::gecko_bindings::structs::nsAtom),
|
||||||
|
FormatHint { length: usize, utf8_bytes: *const u8 },
|
||||||
|
}
|
||||||
|
|
||||||
/// A `UrlSource` represents a font-face source that has been specified with a
|
/// A `UrlSource` represents a font-face source that has been specified with a
|
||||||
/// `url()` function.
|
/// `url()` function.
|
||||||
///
|
///
|
||||||
|
@ -84,6 +97,7 @@ impl ToCss for UrlSource {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
||||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)]
|
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)]
|
||||||
|
#[repr(u8)]
|
||||||
pub enum FontDisplay {
|
pub enum FontDisplay {
|
||||||
Auto,
|
Auto,
|
||||||
Block,
|
Block,
|
||||||
|
@ -92,41 +106,83 @@ pub enum FontDisplay {
|
||||||
Optional,
|
Optional,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_range {
|
||||||
|
($range:ident, $component:ident) => {
|
||||||
|
impl Parse for $range {
|
||||||
|
fn parse<'i, 't>(
|
||||||
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<Self, ParseError<'i>> {
|
||||||
|
let first = $component::parse(context, input)?;
|
||||||
|
let second = input
|
||||||
|
.try(|input| $component::parse(context, input))
|
||||||
|
.unwrap_or_else(|_| first.clone());
|
||||||
|
Ok($range(first, second))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ToCss for $range {
|
||||||
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
|
where
|
||||||
|
W: fmt::Write,
|
||||||
|
{
|
||||||
|
self.0.to_css(dest)?;
|
||||||
|
if self.0 != self.1 {
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
self.1.to_css(dest)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The font-weight descriptor:
|
/// The font-weight descriptor:
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-weight
|
/// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-weight
|
||||||
#[derive(Clone, Debug, PartialEq, ToCss)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct FontWeight(pub AbsoluteFontWeight, pub Option<AbsoluteFontWeight>);
|
pub struct FontWeightRange(pub AbsoluteFontWeight, pub AbsoluteFontWeight);
|
||||||
|
impl_range!(FontWeightRange, AbsoluteFontWeight);
|
||||||
|
|
||||||
impl Parse for FontWeight {
|
/// The computed representation of the above so Gecko can read them easily.
|
||||||
fn parse<'i, 't>(
|
///
|
||||||
context: &ParserContext,
|
/// This one is needed because cbindgen doesn't know how to generate
|
||||||
input: &mut Parser<'i, 't>,
|
/// specified::Number.
|
||||||
) -> Result<Self, ParseError<'i>> {
|
#[repr(C)]
|
||||||
let first = AbsoluteFontWeight::parse(context, input)?;
|
#[allow(missing_docs)]
|
||||||
let second = input
|
pub struct ComputedFontWeightRange(f32, f32);
|
||||||
.try(|input| AbsoluteFontWeight::parse(context, input))
|
|
||||||
.ok();
|
impl FontWeightRange {
|
||||||
Ok(FontWeight(first, second))
|
/// Returns a computed font-stretch range.
|
||||||
|
pub fn compute(&self) -> ComputedFontWeightRange {
|
||||||
|
ComputedFontWeightRange(self.0.compute().0, self.1.compute().0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The font-stretch descriptor:
|
/// The font-stretch descriptor:
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-stretch
|
/// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-stretch
|
||||||
#[derive(Clone, Debug, PartialEq, ToCss)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct FontStretch(pub SpecifiedFontStretch, pub Option<SpecifiedFontStretch>);
|
pub struct FontStretchRange(pub FontStretch, pub FontStretch);
|
||||||
|
impl_range!(FontStretchRange, FontStretch);
|
||||||
|
|
||||||
impl Parse for FontStretch {
|
/// The computed representation of the above, so that
|
||||||
fn parse<'i, 't>(
|
/// Gecko can read them easily.
|
||||||
context: &ParserContext,
|
#[repr(C)]
|
||||||
input: &mut Parser<'i, 't>,
|
#[allow(missing_docs)]
|
||||||
) -> Result<Self, ParseError<'i>> {
|
pub struct ComputedFontStretchRange(f32, f32);
|
||||||
let first = SpecifiedFontStretch::parse(context, input)?;
|
|
||||||
let second = input
|
impl FontStretchRange {
|
||||||
.try(|input| SpecifiedFontStretch::parse(context, input))
|
/// Returns a computed font-stretch range.
|
||||||
.ok();
|
pub fn compute(&self) -> ComputedFontStretchRange {
|
||||||
Ok(FontStretch(first, second))
|
fn compute_stretch(s: &FontStretch) -> f32 {
|
||||||
|
match *s {
|
||||||
|
FontStretch::Keyword(ref kw) => kw.compute().0,
|
||||||
|
FontStretch::Stretch(ref p) => p.get(),
|
||||||
|
FontStretch::System(..) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComputedFontStretchRange(compute_stretch(&self.0), compute_stretch(&self.1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +197,16 @@ pub enum FontStyle {
|
||||||
Oblique(Angle, Angle),
|
Oblique(Angle, Angle),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The computed representation of the above, with angles in degrees, so that
|
||||||
|
/// Gecko can read them easily.
|
||||||
|
#[repr(u8)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub enum ComputedFontStyleDescriptor {
|
||||||
|
Normal,
|
||||||
|
Italic,
|
||||||
|
Oblique(f32, f32),
|
||||||
|
}
|
||||||
|
|
||||||
impl Parse for FontStyle {
|
impl Parse for FontStyle {
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
|
@ -185,6 +251,22 @@ impl ToCss for FontStyle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FontStyle {
|
||||||
|
/// Returns a computed font-style descriptor.
|
||||||
|
pub fn compute(&self) -> ComputedFontStyleDescriptor {
|
||||||
|
match *self {
|
||||||
|
FontStyle::Normal => ComputedFontStyleDescriptor::Normal,
|
||||||
|
FontStyle::Italic => ComputedFontStyleDescriptor::Italic,
|
||||||
|
FontStyle::Oblique(ref first, ref second) => {
|
||||||
|
ComputedFontStyleDescriptor::Oblique(
|
||||||
|
SpecifiedFontStyle::compute_angle_degrees(first),
|
||||||
|
SpecifiedFontStyle::compute_angle_degrees(second),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse the block inside a `@font-face` rule.
|
/// Parse the block inside a `@font-face` rule.
|
||||||
///
|
///
|
||||||
/// Note that the prelude parsing code lives in the `stylesheets` module.
|
/// Note that the prelude parsing code lives in the `stylesheets` module.
|
||||||
|
@ -459,10 +541,10 @@ font_face_descriptors! {
|
||||||
"font-style" style / mStyle: FontStyle,
|
"font-style" style / mStyle: FontStyle,
|
||||||
|
|
||||||
/// The weight of this font face.
|
/// The weight of this font face.
|
||||||
"font-weight" weight / mWeight: FontWeight,
|
"font-weight" weight / mWeight: FontWeightRange,
|
||||||
|
|
||||||
/// The stretch of this font face.
|
/// The stretch of this font face.
|
||||||
"font-stretch" stretch / mStretch: FontStretch,
|
"font-stretch" stretch / mStretch: FontStretchRange,
|
||||||
|
|
||||||
/// The display of this font face.
|
/// The display of this font face.
|
||||||
"font-display" display / mDisplay: FontDisplay,
|
"font-display" display / mDisplay: FontDisplay,
|
||||||
|
|
|
@ -17,7 +17,7 @@ use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataVa
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use stylesheets::{Origin, RulesMutateError};
|
use stylesheets::{Origin, RulesMutateError};
|
||||||
use values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image};
|
use values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image};
|
||||||
use values::computed::{Integer, LengthOrPercentage, LengthOrPercentageOrAuto};
|
use values::computed::{Integer, LengthOrPercentage, LengthOrPercentageOrAuto, NonNegativeLengthOrPercentageOrAuto};
|
||||||
use values::computed::{Percentage, TextAlign};
|
use values::computed::{Percentage, TextAlign};
|
||||||
use values::computed::image::LineDirection;
|
use values::computed::image::LineDirection;
|
||||||
use values::computed::url::ComputedImageUrl;
|
use values::computed::url::ComputedImageUrl;
|
||||||
|
@ -106,6 +106,26 @@ impl From<nsStyleCoord_CalcValue> for LengthOrPercentageOrAuto {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(emilio): A lot of these impl From should probably become explicit or
|
||||||
|
// disappear as we move more stuff to cbindgen.
|
||||||
|
impl From<nsStyleCoord_CalcValue> for NonNegativeLengthOrPercentageOrAuto {
|
||||||
|
fn from(other: nsStyleCoord_CalcValue) -> Self {
|
||||||
|
use style_traits::values::specified::AllowedNumericType;
|
||||||
|
use values::generics::NonNegative;
|
||||||
|
NonNegative(if other.mLength < 0 || other.mPercent < 0. {
|
||||||
|
LengthOrPercentageOrAuto::Calc(
|
||||||
|
CalcLengthOrPercentage::with_clamping_mode(
|
||||||
|
Au(other.mLength).into(),
|
||||||
|
if other.mHasPercent { Some(Percentage(other.mPercent)) } else { None },
|
||||||
|
AllowedNumericType::NonNegative,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
other.into()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Angle> for CoordDataValue {
|
impl From<Angle> for CoordDataValue {
|
||||||
fn from(reference: Angle) -> Self {
|
fn from(reference: Angle) -> Self {
|
||||||
match reference {
|
match reference {
|
||||||
|
|
|
@ -479,7 +479,7 @@ lazy_static! {
|
||||||
/// to support new types in these entries and (2) ensuring that either
|
/// to support new types in these entries and (2) ensuring that either
|
||||||
/// nsPresContext::MediaFeatureValuesChanged is called when the value that
|
/// nsPresContext::MediaFeatureValuesChanged is called when the value that
|
||||||
/// would be returned by the evaluator function could change.
|
/// would be returned by the evaluator function could change.
|
||||||
pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 47] = [
|
pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 48] = [
|
||||||
feature!(
|
feature!(
|
||||||
atom!("width"),
|
atom!("width"),
|
||||||
AllowsRanges::Yes,
|
AllowsRanges::Yes,
|
||||||
|
@ -660,6 +660,7 @@ lazy_static! {
|
||||||
system_metric_feature!(atom!("-moz-menubar-drag")),
|
system_metric_feature!(atom!("-moz-menubar-drag")),
|
||||||
system_metric_feature!(atom!("-moz-swipe-animation-enabled")),
|
system_metric_feature!(atom!("-moz-swipe-animation-enabled")),
|
||||||
system_metric_feature!(atom!("-moz-gtk-csd-available")),
|
system_metric_feature!(atom!("-moz-gtk-csd-available")),
|
||||||
|
system_metric_feature!(atom!("-moz-gtk-csd-transparent-background")),
|
||||||
system_metric_feature!(atom!("-moz-gtk-csd-minimize-button")),
|
system_metric_feature!(atom!("-moz-gtk-csd-minimize-button")),
|
||||||
system_metric_feature!(atom!("-moz-gtk-csd-maximize-button")),
|
system_metric_feature!(atom!("-moz-gtk-csd-maximize-button")),
|
||||||
system_metric_feature!(atom!("-moz-gtk-csd-close-button")),
|
system_metric_feature!(atom!("-moz-gtk-csd-close-button")),
|
||||||
|
|
|
@ -15,34 +15,11 @@ sys.path.insert(0, os.path.join(os.path.dirname(GECKO_DIR), "properties"))
|
||||||
|
|
||||||
import build
|
import build
|
||||||
|
|
||||||
PRELUDE = """
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
/* Autogenerated file created by components/style/gecko/regen_atoms.py, DO NOT EDIT DIRECTLY */
|
|
||||||
"""[1:] # NOQA: E501
|
|
||||||
|
|
||||||
|
|
||||||
# Matches lines like `GK_ATOM(foo, "foo", 0x12345678, nsStaticAtom, PseudoElementAtom)`.
|
# Matches lines like `GK_ATOM(foo, "foo", 0x12345678, nsStaticAtom, PseudoElementAtom)`.
|
||||||
PATTERN = re.compile('^GK_ATOM\(([^,]*),[^"]*"([^"]*)",\s*(0x[0-9a-f]+),\s*([^,]*),\s*([^)]*)\)',
|
PATTERN = re.compile('^GK_ATOM\(([^,]*),[^"]*"([^"]*)",\s*(0x[0-9a-f]+),\s*([^,]*),\s*([^)]*)\)',
|
||||||
re.MULTILINE)
|
re.MULTILINE)
|
||||||
FILE = "include/nsGkAtomList.h"
|
FILE = "include/nsGkAtomList.h"
|
||||||
CLASS = "nsGkAtoms"
|
|
||||||
|
|
||||||
|
|
||||||
def gnu_symbolify(ident):
|
|
||||||
return "_ZN{}{}{}{}E".format(len(CLASS), CLASS, len(ident), ident)
|
|
||||||
|
|
||||||
|
|
||||||
def msvc64_symbolify(ident, ty):
|
|
||||||
return "?{}@{}@@2PEAV{}@@EA".format(ident, CLASS, ty)
|
|
||||||
|
|
||||||
|
|
||||||
def msvc32_symbolify(ident, ty):
|
|
||||||
# Prepend "\x01" to avoid LLVM prefixing the mangled name with "_".
|
|
||||||
# See https://github.com/rust-lang/rust/issues/36097
|
|
||||||
return "\\x01?{}@{}@@2PAV{}@@A".format(ident, CLASS, ty)
|
|
||||||
|
|
||||||
|
|
||||||
def map_atom(ident):
|
def map_atom(ident):
|
||||||
|
@ -54,7 +31,7 @@ def map_atom(ident):
|
||||||
|
|
||||||
class Atom:
|
class Atom:
|
||||||
def __init__(self, ident, value, hash, ty, atom_type):
|
def __init__(self, ident, value, hash, ty, atom_type):
|
||||||
self.ident = "{}_{}".format(CLASS, ident)
|
self.ident = "nsGkAtoms_{}".format(ident)
|
||||||
self.original_ident = ident
|
self.original_ident = ident
|
||||||
self.value = value
|
self.value = value
|
||||||
self.hash = hash
|
self.hash = hash
|
||||||
|
@ -68,15 +45,6 @@ class Atom:
|
||||||
if self.is_anon_box():
|
if self.is_anon_box():
|
||||||
assert self.is_inheriting_anon_box() or self.is_non_inheriting_anon_box()
|
assert self.is_inheriting_anon_box() or self.is_non_inheriting_anon_box()
|
||||||
|
|
||||||
def gnu_symbol(self):
|
|
||||||
return gnu_symbolify(self.original_ident)
|
|
||||||
|
|
||||||
def msvc32_symbol(self):
|
|
||||||
return msvc32_symbolify(self.original_ident, self.ty)
|
|
||||||
|
|
||||||
def msvc64_symbol(self):
|
|
||||||
return msvc64_symbolify(self.original_ident, self.ty)
|
|
||||||
|
|
||||||
def type(self):
|
def type(self):
|
||||||
return self.ty
|
return self.ty
|
||||||
|
|
||||||
|
@ -144,73 +112,94 @@ class FileAvoidWrite(BytesIO):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
IMPORTS = ("\nuse gecko_bindings::structs::nsStaticAtom;"
|
PRELUDE = '''
|
||||||
"\nuse string_cache::Atom;\n\n")
|
/* 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/. */
|
||||||
|
|
||||||
ATOM_TEMPLATE = (" #[link_name = \"{link_name}\"]\n"
|
// Autogenerated file created by components/style/gecko/regen_atoms.py.
|
||||||
" pub static {name}: *mut {type};")
|
// DO NOT EDIT DIRECTLY
|
||||||
|
'''[1:]
|
||||||
|
|
||||||
UNSAFE_STATIC = ("#[inline(always)]\n"
|
IMPORTS = '''
|
||||||
"pub unsafe fn atom_from_static(ptr: *mut nsStaticAtom) -> Atom {\n"
|
use gecko_bindings::structs::nsStaticAtom;
|
||||||
" Atom::from_static(ptr)\n"
|
use string_cache::Atom;
|
||||||
"}\n\n")
|
'''
|
||||||
|
|
||||||
CFG_IF = '''
|
UNSAFE_STATIC = '''
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn atom_from_static(ptr: *const nsStaticAtom) -> Atom {
|
||||||
|
Atom::from_static(ptr)
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
SATOMS_TEMPLATE = '''
|
||||||
|
#[link_name = \"{link_name}\"]
|
||||||
|
pub static nsGkAtoms_sAtoms: *const nsStaticAtom;
|
||||||
|
'''[1:]
|
||||||
|
|
||||||
|
CFG_IF_TEMPLATE = '''
|
||||||
cfg_if! {{
|
cfg_if! {{
|
||||||
if #[cfg(not(target_env = "msvc"))] {{
|
if #[cfg(not(target_env = "msvc"))] {{
|
||||||
extern {{
|
extern {{
|
||||||
{gnu}
|
{gnu}\
|
||||||
}}
|
}}
|
||||||
}} else if #[cfg(target_pointer_width = "64")] {{
|
}} else if #[cfg(target_pointer_width = "64")] {{
|
||||||
extern {{
|
extern {{
|
||||||
{msvc64}
|
{msvc64}\
|
||||||
}}
|
}}
|
||||||
}} else {{
|
}} else {{
|
||||||
extern {{
|
extern {{
|
||||||
{msvc32}
|
{msvc32}\
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
}}
|
}}\n
|
||||||
'''
|
'''
|
||||||
|
|
||||||
RULE_TEMPLATE = ('("{atom}") =>\n '
|
CONST_TEMPLATE = '''
|
||||||
'{{{{ '
|
pub const k_{name}: isize = {index};
|
||||||
'#[allow(unsafe_code)] #[allow(unused_unsafe)]'
|
'''[1:]
|
||||||
'unsafe {{ $crate::string_cache::atom_macro::atom_from_static'
|
|
||||||
'($crate::string_cache::atom_macro::{name} as *mut _) }}'
|
|
||||||
' }}}};')
|
|
||||||
|
|
||||||
MACRO = '''
|
RULE_TEMPLATE = '''
|
||||||
|
("{atom}") =>
|
||||||
|
{{{{
|
||||||
|
use $crate::string_cache::atom_macro;
|
||||||
|
#[allow(unsafe_code)] #[allow(unused_unsafe)]
|
||||||
|
unsafe {{ atom_macro::atom_from_static(atom_macro::nsGkAtoms_sAtoms.offset(atom_macro::k_{name})) }}
|
||||||
|
}}}};
|
||||||
|
'''[1:]
|
||||||
|
|
||||||
|
MACRO_TEMPLATE = '''
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! atom {{
|
macro_rules! atom {{
|
||||||
{}
|
{body}\
|
||||||
}}
|
}}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def write_atom_macro(atoms, file_name):
|
def write_atom_macro(atoms, file_name):
|
||||||
def get_symbols(func):
|
|
||||||
return '\n'.join([ATOM_TEMPLATE.format(name=atom.ident,
|
|
||||||
link_name=func(atom),
|
|
||||||
type=atom.type()) for atom in atoms])
|
|
||||||
|
|
||||||
with FileAvoidWrite(file_name) as f:
|
with FileAvoidWrite(file_name) as f:
|
||||||
f.write(PRELUDE)
|
f.write(PRELUDE)
|
||||||
f.write(IMPORTS)
|
f.write(IMPORTS)
|
||||||
|
|
||||||
for ty in sorted(set([atom.type() for atom in atoms])):
|
|
||||||
if ty != "nsStaticAtom":
|
|
||||||
f.write("pub enum {} {{}}\n\n".format(ty))
|
|
||||||
|
|
||||||
f.write(UNSAFE_STATIC)
|
f.write(UNSAFE_STATIC)
|
||||||
|
|
||||||
gnu_symbols = get_symbols(Atom.gnu_symbol)
|
gnu_name='_ZN9nsGkAtoms6sAtomsE'
|
||||||
msvc32_symbols = get_symbols(Atom.msvc32_symbol)
|
gnu_symbols = SATOMS_TEMPLATE.format(link_name=gnu_name)
|
||||||
msvc64_symbols = get_symbols(Atom.msvc64_symbol)
|
|
||||||
f.write(CFG_IF.format(gnu=gnu_symbols, msvc32=msvc32_symbols, msvc64=msvc64_symbols))
|
# Prepend "\x01" to avoid LLVM prefixing the mangled name with "_".
|
||||||
|
# See https://github.com/rust-lang/rust/issues/36097
|
||||||
|
msvc32_name = '\\x01?sAtoms@nsGkAtoms@@0QBVnsStaticAtom@@B'
|
||||||
|
msvc32_symbols = SATOMS_TEMPLATE.format(link_name=msvc32_name)
|
||||||
|
|
||||||
|
msvc64_name = '?sAtoms@nsGkAtoms@@0QEBVnsStaticAtom@@EB'
|
||||||
|
msvc64_symbols = SATOMS_TEMPLATE.format(link_name=msvc64_name)
|
||||||
|
|
||||||
|
f.write(CFG_IF_TEMPLATE.format(gnu=gnu_symbols, msvc32=msvc32_symbols, msvc64=msvc64_symbols))
|
||||||
|
|
||||||
|
consts = [CONST_TEMPLATE.format(name=atom.ident, index=i) for (i, atom) in enumerate(atoms)]
|
||||||
|
f.write('{}'.format(''.join(consts)))
|
||||||
|
|
||||||
macro_rules = [RULE_TEMPLATE.format(atom=atom.value, name=atom.ident) for atom in atoms]
|
macro_rules = [RULE_TEMPLATE.format(atom=atom.value, name=atom.ident) for atom in atoms]
|
||||||
f.write(MACRO.format('\n'.join(macro_rules)))
|
f.write(MACRO_TEMPLATE.format(body=''.join(macro_rules)))
|
||||||
|
|
||||||
|
|
||||||
def write_pseudo_elements(atoms, target_filename):
|
def write_pseudo_elements(atoms, target_filename):
|
||||||
|
|
|
@ -4,201 +4,9 @@
|
||||||
|
|
||||||
//! Bindings for CSS Rule objects
|
//! Bindings for CSS Rule objects
|
||||||
|
|
||||||
use byteorder::{BigEndian, WriteBytesExt};
|
|
||||||
use counter_style::{self, CounterBound};
|
use counter_style::{self, CounterBound};
|
||||||
use cssparser::UnicodeRange;
|
|
||||||
use font_face::{FontDisplay, FontWeight, FontStretch, FontStyle, Source};
|
|
||||||
use gecko_bindings::structs::{self, nsCSSValue};
|
use gecko_bindings::structs::{self, nsCSSValue};
|
||||||
use gecko_bindings::sugar::ns_css_value::ToNsCssValue;
|
use gecko_bindings::sugar::ns_css_value::ToNsCssValue;
|
||||||
use properties::longhands::font_language_override;
|
|
||||||
use std::str;
|
|
||||||
use values::computed::font::FamilyName;
|
|
||||||
use values::generics::font::FontTag;
|
|
||||||
use values::specified::font::{AbsoluteFontWeight, FontStretch as SpecifiedFontStretch};
|
|
||||||
use values::specified::font::{SpecifiedFontFeatureSettings, SpecifiedFontVariationSettings};
|
|
||||||
use values::specified::font::SpecifiedFontStyle;
|
|
||||||
|
|
||||||
impl<'a> ToNsCssValue for &'a FamilyName {
|
|
||||||
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
|
||||||
nscssvalue.set_string_from_atom(&self.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ToNsCssValue for &'a SpecifiedFontStretch {
|
|
||||||
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
|
||||||
let number = match *self {
|
|
||||||
SpecifiedFontStretch::Stretch(ref p) => p.get(),
|
|
||||||
SpecifiedFontStretch::Keyword(ref kw) => kw.compute().0,
|
|
||||||
SpecifiedFontStretch::System(..) => unreachable!(),
|
|
||||||
};
|
|
||||||
nscssvalue.set_font_stretch(number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ToNsCssValue for &'a AbsoluteFontWeight {
|
|
||||||
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
|
||||||
nscssvalue.set_font_weight(self.compute().0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToNsCssValue for FontTag {
|
|
||||||
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
|
||||||
let mut raw = [0u8; 4];
|
|
||||||
(&mut raw[..]).write_u32::<BigEndian>(self.0).unwrap();
|
|
||||||
nscssvalue.set_string(str::from_utf8(&raw).unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ToNsCssValue for &'a SpecifiedFontFeatureSettings {
|
|
||||||
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
|
||||||
if self.0.is_empty() {
|
|
||||||
nscssvalue.set_normal();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nscssvalue.set_pair_list(self.0.iter().map(|entry| {
|
|
||||||
let mut index = nsCSSValue::null();
|
|
||||||
index.set_integer(entry.value.value());
|
|
||||||
(entry.tag.into(), index)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ToNsCssValue for &'a SpecifiedFontVariationSettings {
|
|
||||||
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
|
||||||
if self.0.is_empty() {
|
|
||||||
nscssvalue.set_normal();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nscssvalue.set_pair_list(self.0.iter().map(|entry| {
|
|
||||||
let mut value = nsCSSValue::null();
|
|
||||||
value.set_number(entry.value.into());
|
|
||||||
(entry.tag.into(), value)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! descriptor_range_conversion {
|
|
||||||
($name:ident) => {
|
|
||||||
impl<'a> ToNsCssValue for &'a $name {
|
|
||||||
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
|
||||||
let $name(ref first, ref second) = *self;
|
|
||||||
let second = match *second {
|
|
||||||
None => {
|
|
||||||
nscssvalue.set_from(first);
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
Some(ref second) => second,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut a = nsCSSValue::null();
|
|
||||||
let mut b = nsCSSValue::null();
|
|
||||||
|
|
||||||
a.set_from(first);
|
|
||||||
b.set_from(second);
|
|
||||||
|
|
||||||
nscssvalue.set_pair(&a, &b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
descriptor_range_conversion!(FontWeight);
|
|
||||||
descriptor_range_conversion!(FontStretch);
|
|
||||||
|
|
||||||
impl<'a> ToNsCssValue for &'a FontStyle {
|
|
||||||
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
|
||||||
match *self {
|
|
||||||
FontStyle::Normal => nscssvalue.set_normal(),
|
|
||||||
FontStyle::Italic => nscssvalue.set_enum(structs::NS_FONT_STYLE_ITALIC as i32),
|
|
||||||
FontStyle::Oblique(ref first, ref second) => {
|
|
||||||
let mut a = nsCSSValue::null();
|
|
||||||
let mut b = nsCSSValue::null();
|
|
||||||
|
|
||||||
a.set_font_style(SpecifiedFontStyle::compute_angle(first).degrees());
|
|
||||||
b.set_font_style(SpecifiedFontStyle::compute_angle(second).degrees());
|
|
||||||
|
|
||||||
nscssvalue.set_pair(&a, &b);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ToNsCssValue for &'a font_language_override::SpecifiedValue {
|
|
||||||
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
|
||||||
match *self {
|
|
||||||
font_language_override::SpecifiedValue::Normal => nscssvalue.set_normal(),
|
|
||||||
font_language_override::SpecifiedValue::Override(ref lang) => {
|
|
||||||
nscssvalue.set_string(&*lang)
|
|
||||||
},
|
|
||||||
// This path is unreachable because the descriptor is only specified by the user.
|
|
||||||
font_language_override::SpecifiedValue::System(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ToNsCssValue for &'a Vec<Source> {
|
|
||||||
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
|
||||||
let src_len = self.iter().fold(0, |acc, src| {
|
|
||||||
acc + match *src {
|
|
||||||
// Each format hint takes one position in the array of mSrc.
|
|
||||||
Source::Url(ref url) => url.format_hints.len() + 1,
|
|
||||||
Source::Local(_) => 1,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let mut target_srcs = nscssvalue
|
|
||||||
.set_array(src_len as i32)
|
|
||||||
.as_mut_slice()
|
|
||||||
.iter_mut();
|
|
||||||
macro_rules! next {
|
|
||||||
() => {
|
|
||||||
target_srcs
|
|
||||||
.next()
|
|
||||||
.expect("Length of target_srcs should be enough")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
for src in self.iter() {
|
|
||||||
match *src {
|
|
||||||
Source::Url(ref url) => {
|
|
||||||
next!().set_url(&url.url);
|
|
||||||
for hint in url.format_hints.iter() {
|
|
||||||
next!().set_font_format(&hint);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Source::Local(ref family) => {
|
|
||||||
next!().set_local_font(&family.name);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debug_assert!(target_srcs.next().is_none(), "Should have filled all slots");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ToNsCssValue for &'a Vec<UnicodeRange> {
|
|
||||||
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
|
||||||
let target_ranges = nscssvalue
|
|
||||||
.set_array((self.len() * 2) as i32)
|
|
||||||
.as_mut_slice()
|
|
||||||
.chunks_mut(2);
|
|
||||||
for (range, target) in self.iter().zip(target_ranges) {
|
|
||||||
target[0].set_integer(range.start as i32);
|
|
||||||
target[1].set_integer(range.end as i32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ToNsCssValue for &'a FontDisplay {
|
|
||||||
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
|
||||||
nscssvalue.set_enum(match *self {
|
|
||||||
FontDisplay::Auto => structs::NS_FONT_DISPLAY_AUTO,
|
|
||||||
FontDisplay::Block => structs::NS_FONT_DISPLAY_BLOCK,
|
|
||||||
FontDisplay::Swap => structs::NS_FONT_DISPLAY_SWAP,
|
|
||||||
FontDisplay::Fallback => structs::NS_FONT_DISPLAY_FALLBACK,
|
|
||||||
FontDisplay::Optional => structs::NS_FONT_DISPLAY_OPTIONAL,
|
|
||||||
} as i32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ToNsCssValue for &'a counter_style::System {
|
impl<'a> ToNsCssValue for &'a counter_style::System {
|
||||||
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
fn convert(self, nscssvalue: &mut nsCSSValue) {
|
||||||
|
|
|
@ -273,14 +273,18 @@ impl ToComputedValue for SpecifiedImageUrl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_computed_url<W>(url_value_data: &URLValueData, dest: &mut CssWriter<W>) -> fmt::Result
|
fn serialize_computed_url<W>(
|
||||||
|
url_value_data: &URLValueData,
|
||||||
|
dest: &mut CssWriter<W>,
|
||||||
|
get_url: unsafe extern "C" fn(*const URLValueData, *mut nsCString),
|
||||||
|
) -> fmt::Result
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
dest.write_str("url(")?;
|
dest.write_str("url(")?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut string = nsCString::new();
|
let mut string = nsCString::new();
|
||||||
bindings::Gecko_GetComputedURLSpec(url_value_data, &mut string);
|
get_url(url_value_data, &mut string);
|
||||||
string.as_str_unchecked().to_css(dest)?;
|
string.as_str_unchecked().to_css(dest)?;
|
||||||
}
|
}
|
||||||
dest.write_char(')')
|
dest.write_char(')')
|
||||||
|
@ -298,7 +302,11 @@ impl ToCss for ComputedUrl {
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
serialize_computed_url(&self.0.url_value._base, dest)
|
serialize_computed_url(
|
||||||
|
&self.0.url_value._base,
|
||||||
|
dest,
|
||||||
|
bindings::Gecko_GetComputedURLSpec,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +327,11 @@ impl ToCss for ComputedImageUrl {
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
serialize_computed_url(&self.0.image_value._base, dest)
|
serialize_computed_url(
|
||||||
|
&self.0.image_value._base,
|
||||||
|
dest,
|
||||||
|
bindings::Gecko_GetComputedImageURLSpec,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ use std::mem;
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use values::computed::{Angle, Length, LengthOrPercentage, Percentage};
|
use values::computed::{Angle, Length, LengthOrPercentage, Percentage};
|
||||||
use values::specified::url::SpecifiedUrl;
|
|
||||||
|
|
||||||
impl nsCSSValue {
|
impl nsCSSValue {
|
||||||
/// Create a CSSValue with null unit, useful to be used as a return value.
|
/// Create a CSSValue with null unit, useful to be used as a return value.
|
||||||
|
@ -167,31 +166,6 @@ impl nsCSSValue {
|
||||||
unsafe { bindings::Gecko_CSSValue_SetAtomIdent(self, s.into_addrefed()) }
|
unsafe { bindings::Gecko_CSSValue_SetAtomIdent(self, s.into_addrefed()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set to a font format.
|
|
||||||
pub fn set_font_format(&mut self, s: &str) {
|
|
||||||
self.set_string_internal(s, nsCSSUnit::eCSSUnit_Font_Format);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set to a local font value.
|
|
||||||
pub fn set_local_font(&mut self, s: &Atom) {
|
|
||||||
self.set_string_from_atom_internal(s, nsCSSUnit::eCSSUnit_Local_Font);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set to a font stretch.
|
|
||||||
pub fn set_font_stretch(&mut self, s: f32) {
|
|
||||||
unsafe { bindings::Gecko_CSSValue_SetFontStretch(self, s) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set to a font style
|
|
||||||
pub fn set_font_style(&mut self, s: f32) {
|
|
||||||
unsafe { bindings::Gecko_CSSValue_SetFontSlantStyle(self, s) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set to a font weight
|
|
||||||
pub fn set_font_weight(&mut self, w: f32) {
|
|
||||||
unsafe { bindings::Gecko_CSSValue_SetFontWeight(self, w) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_int_internal(&mut self, value: i32, unit: nsCSSUnit) {
|
fn set_int_internal(&mut self, value: i32, unit: nsCSSUnit) {
|
||||||
unsafe { bindings::Gecko_CSSValue_SetInt(self, value, unit) }
|
unsafe { bindings::Gecko_CSSValue_SetInt(self, value, unit) }
|
||||||
}
|
}
|
||||||
|
@ -211,11 +185,6 @@ impl nsCSSValue {
|
||||||
unsafe { bindings::Gecko_CSSValue_SetFloat(self, number, nsCSSUnit::eCSSUnit_Number) }
|
unsafe { bindings::Gecko_CSSValue_SetFloat(self, number, nsCSSUnit::eCSSUnit_Number) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set to a url value
|
|
||||||
pub fn set_url(&mut self, url: &SpecifiedUrl) {
|
|
||||||
unsafe { bindings::Gecko_CSSValue_SetURL(self, url.url_value.get()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set to an array of given length
|
/// Set to an array of given length
|
||||||
pub fn set_array(&mut self, len: i32) -> &mut nsCSSValue_Array {
|
pub fn set_array(&mut self, len: i32) -> &mut nsCSSValue_Array {
|
||||||
unsafe { bindings::Gecko_CSSValue_SetArray(self, len) }
|
unsafe { bindings::Gecko_CSSValue_SetArray(self, len) }
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
|
|
||||||
#![allow(unsafe_code)]
|
#![allow(unsafe_code)]
|
||||||
|
|
||||||
|
// This is needed for the constants in atom_macro.rs, because we have some
|
||||||
|
// atoms whose names differ only by case, e.g. datetime and dateTime.
|
||||||
|
#![allow(non_upper_case_globals)]
|
||||||
|
|
||||||
//! A drop-in replacement for string_cache, but backed by Gecko `nsAtom`s.
|
//! A drop-in replacement for string_cache, but backed by Gecko `nsAtom`s.
|
||||||
|
|
||||||
use gecko_bindings::bindings::Gecko_AddRefAtom;
|
use gecko_bindings::bindings::Gecko_AddRefAtom;
|
||||||
|
@ -280,7 +284,7 @@ impl Atom {
|
||||||
/// that way, now we have sugar for is_static, creating atoms using
|
/// that way, now we have sugar for is_static, creating atoms using
|
||||||
/// Atom::from_raw should involve almost no overhead.
|
/// Atom::from_raw should involve almost no overhead.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn from_static(ptr: *mut nsStaticAtom) -> Self {
|
pub unsafe fn from_static(ptr: *const nsStaticAtom) -> Self {
|
||||||
let atom = Atom(ptr as *mut WeakAtom);
|
let atom = Atom(ptr as *mut WeakAtom);
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
atom.is_static(),
|
atom.is_static(),
|
||||||
|
|
|
@ -20,6 +20,7 @@ use selector_parser::PseudoElement;
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
use shared_lock::StylesheetGuards;
|
use shared_lock::StylesheetGuards;
|
||||||
use smallbitvec::SmallBitVec;
|
use smallbitvec::SmallBitVec;
|
||||||
|
use smallvec::SmallVec;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use style_adjuster::StyleAdjuster;
|
use style_adjuster::StyleAdjuster;
|
||||||
|
@ -240,10 +241,12 @@ where
|
||||||
|
|
||||||
let inherited_style = parent_style.unwrap_or(device.default_computed_values());
|
let inherited_style = parent_style.unwrap_or(device.default_computed_values());
|
||||||
|
|
||||||
|
let mut declarations = SmallVec::<[(&_, CascadeLevel); 32]>::new();
|
||||||
let custom_properties = {
|
let custom_properties = {
|
||||||
let mut builder = CustomPropertiesBuilder::new(inherited_style.custom_properties());
|
let mut builder = CustomPropertiesBuilder::new(inherited_style.custom_properties());
|
||||||
|
|
||||||
for (declaration, _cascade_level) in iter_declarations() {
|
for (declaration, cascade_level) in iter_declarations() {
|
||||||
|
declarations.push((declaration, cascade_level));
|
||||||
if let PropertyDeclaration::Custom(ref declaration) = *declaration {
|
if let PropertyDeclaration::Custom(ref declaration) = *declaration {
|
||||||
builder.cascade(&declaration.name, &declaration.value);
|
builder.cascade(&declaration.name, &declaration.value);
|
||||||
}
|
}
|
||||||
|
@ -278,7 +281,7 @@ where
|
||||||
let mut cascade = Cascade::new(&mut context, cascade_mode);
|
let mut cascade = Cascade::new(&mut context, cascade_mode);
|
||||||
|
|
||||||
cascade
|
cascade
|
||||||
.apply_properties::<EarlyProperties, I>(ApplyResetProperties::Yes, iter_declarations());
|
.apply_properties::<EarlyProperties, _>(ApplyResetProperties::Yes, declarations.iter().cloned());
|
||||||
|
|
||||||
cascade.compute_visited_style_if_needed(
|
cascade.compute_visited_style_if_needed(
|
||||||
element,
|
element,
|
||||||
|
@ -297,7 +300,7 @@ where
|
||||||
ApplyResetProperties::Yes
|
ApplyResetProperties::Yes
|
||||||
};
|
};
|
||||||
|
|
||||||
cascade.apply_properties::<LateProperties, I>(apply_reset, iter_declarations());
|
cascade.apply_properties::<LateProperties, _>(apply_reset, declarations.iter().cloned());
|
||||||
|
|
||||||
using_cached_reset_properties
|
using_cached_reset_properties
|
||||||
};
|
};
|
||||||
|
|
|
@ -4005,7 +4005,6 @@ fn static_assert() {
|
||||||
pub fn clone_${shorthand}_size(&self) -> longhands::${shorthand}_size::computed_value::T {
|
pub fn clone_${shorthand}_size(&self) -> longhands::${shorthand}_size::computed_value::T {
|
||||||
use gecko_bindings::structs::nsStyleCoord_CalcValue as CalcValue;
|
use gecko_bindings::structs::nsStyleCoord_CalcValue as CalcValue;
|
||||||
use gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType as DimensionType;
|
use gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType as DimensionType;
|
||||||
use values::generics::NonNegative;
|
|
||||||
use values::computed::NonNegativeLengthOrPercentageOrAuto;
|
use values::computed::NonNegativeLengthOrPercentageOrAuto;
|
||||||
use values::generics::background::BackgroundSize;
|
use values::generics::background::BackgroundSize;
|
||||||
|
|
||||||
|
@ -4014,7 +4013,7 @@ fn static_assert() {
|
||||||
NonNegativeLengthOrPercentageOrAuto::auto()
|
NonNegativeLengthOrPercentageOrAuto::auto()
|
||||||
} else {
|
} else {
|
||||||
debug_assert_eq!(ty, DimensionType::eLengthPercentage as u8);
|
debug_assert_eq!(ty, DimensionType::eLengthPercentage as u8);
|
||||||
NonNegative(value.into())
|
value.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4447,7 +4446,7 @@ fn static_assert() {
|
||||||
Some(Au(self.gecko.mClip.x + self.gecko.mClip.width).into())
|
Some(Au(self.gecko.mClip.x + self.gecko.mClip.width).into())
|
||||||
};
|
};
|
||||||
|
|
||||||
Either::First(ClipRect { top: top, right: right, bottom: bottom, left: left, })
|
Either::First(ClipRect { top, right, bottom, left })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ ${helpers.predefined_type(
|
||||||
"ui::ScrollbarColor",
|
"ui::ScrollbarColor",
|
||||||
"Default::default()",
|
"Default::default()",
|
||||||
spec="https://drafts.csswg.org/css-scrollbars-1/#scrollbar-color",
|
spec="https://drafts.csswg.org/css-scrollbars-1/#scrollbar-color",
|
||||||
gecko_pref="layout.css.scrollbar-colors.enabled",
|
gecko_pref="layout.css.scrollbar-color.enabled",
|
||||||
animation_value_type="ScrollbarColor",
|
animation_value_type="ScrollbarColor",
|
||||||
boxed=True,
|
boxed=True,
|
||||||
ignored_when_colors_disabled=True,
|
ignored_when_colors_disabled=True,
|
||||||
|
|
|
@ -1134,7 +1134,7 @@ impl Stylist {
|
||||||
|
|
||||||
let rule_hash_target = element.rule_hash_target();
|
let rule_hash_target = element.rule_hash_target();
|
||||||
|
|
||||||
let matches_user_rules = rule_hash_target.matches_user_and_author_rules();
|
let matches_user_and_author_rules = rule_hash_target.matches_user_and_author_rules();
|
||||||
|
|
||||||
// Normal user-agent rules.
|
// Normal user-agent rules.
|
||||||
if let Some(map) = self
|
if let Some(map) = self
|
||||||
|
@ -1162,7 +1162,7 @@ impl Stylist {
|
||||||
// rule_hash_target.matches_user_and_author_rules())
|
// rule_hash_target.matches_user_and_author_rules())
|
||||||
//
|
//
|
||||||
// Which may be more what you would probably expect.
|
// Which may be more what you would probably expect.
|
||||||
if matches_user_rules {
|
if matches_user_and_author_rules {
|
||||||
// User normal rules.
|
// User normal rules.
|
||||||
if let Some(map) = self.cascade_data.user.normal_rules(pseudo_element) {
|
if let Some(map) = self.cascade_data.user.normal_rules(pseudo_element) {
|
||||||
map.get_all_matching_rules(
|
map.get_all_matching_rules(
|
||||||
|
@ -1204,16 +1204,15 @@ impl Stylist {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut match_document_author_rules = matches_user_rules;
|
let mut match_document_author_rules = matches_user_and_author_rules;
|
||||||
let mut shadow_cascade_order = 0;
|
let mut shadow_cascade_order = 0;
|
||||||
|
|
||||||
// XBL / Shadow DOM rules, which are author rules too.
|
// XBL / Shadow DOM rules, which are author rules too.
|
||||||
//
|
|
||||||
// TODO(emilio): Cascade order here is wrong for Shadow DOM. In
|
|
||||||
// particular, normally document rules override ::slotted() rules, but
|
|
||||||
// for !important it should be the other way around. So probably we need
|
|
||||||
// to add some sort of AuthorScoped cascade level or something.
|
|
||||||
if let Some(shadow) = rule_hash_target.shadow_root() {
|
if let Some(shadow) = rule_hash_target.shadow_root() {
|
||||||
|
debug_assert!(
|
||||||
|
matches_user_and_author_rules,
|
||||||
|
"NAC should not be a shadow host"
|
||||||
|
);
|
||||||
if let Some(map) = shadow
|
if let Some(map) = shadow
|
||||||
.style_data()
|
.style_data()
|
||||||
.and_then(|data| data.host_rules(pseudo_element))
|
.and_then(|data| data.host_rules(pseudo_element))
|
||||||
|
@ -1238,6 +1237,10 @@ impl Stylist {
|
||||||
let mut slots = SmallVec::<[_; 3]>::new();
|
let mut slots = SmallVec::<[_; 3]>::new();
|
||||||
let mut current = rule_hash_target.assigned_slot();
|
let mut current = rule_hash_target.assigned_slot();
|
||||||
while let Some(slot) = current {
|
while let Some(slot) = current {
|
||||||
|
debug_assert!(
|
||||||
|
matches_user_and_author_rules,
|
||||||
|
"We should not slot NAC anywhere"
|
||||||
|
);
|
||||||
slots.push(slot);
|
slots.push(slot);
|
||||||
current = slot.assigned_slot();
|
current = slot.assigned_slot();
|
||||||
}
|
}
|
||||||
|
@ -1263,55 +1266,57 @@ impl Stylist {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut current_containing_shadow = rule_hash_target.containing_shadow();
|
if matches_user_and_author_rules {
|
||||||
while let Some(containing_shadow) = current_containing_shadow {
|
let mut current_containing_shadow = rule_hash_target.containing_shadow();
|
||||||
let cascade_data = containing_shadow.style_data();
|
while let Some(containing_shadow) = current_containing_shadow {
|
||||||
let host = containing_shadow.host();
|
let cascade_data = containing_shadow.style_data();
|
||||||
if let Some(map) = cascade_data.and_then(|data| data.normal_rules(pseudo_element)) {
|
let host = containing_shadow.host();
|
||||||
context.with_shadow_host(Some(host), |context| {
|
if let Some(map) = cascade_data.and_then(|data| data.normal_rules(pseudo_element)) {
|
||||||
map.get_all_matching_rules(
|
context.with_shadow_host(Some(host), |context| {
|
||||||
element,
|
map.get_all_matching_rules(
|
||||||
rule_hash_target,
|
element,
|
||||||
applicable_declarations,
|
rule_hash_target,
|
||||||
context,
|
applicable_declarations,
|
||||||
flags_setter,
|
context,
|
||||||
CascadeLevel::SameTreeAuthorNormal,
|
flags_setter,
|
||||||
shadow_cascade_order,
|
CascadeLevel::SameTreeAuthorNormal,
|
||||||
);
|
shadow_cascade_order,
|
||||||
});
|
);
|
||||||
shadow_cascade_order += 1;
|
});
|
||||||
|
shadow_cascade_order += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let host_is_svg_use_element =
|
||||||
|
host.is_svg_element() && host.local_name() == &*local_name!("use");
|
||||||
|
|
||||||
|
if !host_is_svg_use_element {
|
||||||
|
match_document_author_rules = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert!(
|
||||||
|
cascade_data.is_none(),
|
||||||
|
"We allow no stylesheets in <svg:use> subtrees"
|
||||||
|
);
|
||||||
|
|
||||||
|
// NOTE(emilio): Hack so <svg:use> matches the rules of the
|
||||||
|
// enclosing tree.
|
||||||
|
//
|
||||||
|
// This is not a problem for invalidation and that kind of stuff
|
||||||
|
// because they still don't match rules based on elements
|
||||||
|
// outside of the shadow tree, and because the <svg:use>
|
||||||
|
// subtrees are immutable and recreated each time the source
|
||||||
|
// tree changes.
|
||||||
|
//
|
||||||
|
// We historically allow cross-document <svg:use> to have these
|
||||||
|
// rules applied, but I think that's not great. Gecko is the
|
||||||
|
// only engine supporting that.
|
||||||
|
//
|
||||||
|
// See https://github.com/w3c/svgwg/issues/504 for the relevant
|
||||||
|
// spec discussion.
|
||||||
|
current_containing_shadow = host.containing_shadow();
|
||||||
|
match_document_author_rules = current_containing_shadow.is_none();
|
||||||
}
|
}
|
||||||
|
|
||||||
let host_is_svg_use_element =
|
|
||||||
host.is_svg_element() && host.local_name() == &*local_name!("use");
|
|
||||||
|
|
||||||
if !host_is_svg_use_element {
|
|
||||||
match_document_author_rules = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_assert!(
|
|
||||||
cascade_data.is_none(),
|
|
||||||
"We allow no stylesheets in <svg:use> subtrees"
|
|
||||||
);
|
|
||||||
|
|
||||||
// NOTE(emilio): Hack so <svg:use> matches the rules of the
|
|
||||||
// enclosing tree.
|
|
||||||
//
|
|
||||||
// This is not a problem for invalidation and that kind of stuff
|
|
||||||
// because they still don't match rules based on elements
|
|
||||||
// outside of the shadow tree, and because the <svg:use>
|
|
||||||
// subtrees are immutable and recreated each time the source
|
|
||||||
// tree changes.
|
|
||||||
//
|
|
||||||
// We historically allow cross-document <svg:use> to have these
|
|
||||||
// rules applied, but I think that's not great. Gecko is the
|
|
||||||
// only engine supporting that.
|
|
||||||
//
|
|
||||||
// See https://github.com/w3c/svgwg/issues/504 for the relevant
|
|
||||||
// spec discussion.
|
|
||||||
current_containing_shadow = host.containing_shadow();
|
|
||||||
match_document_author_rules = current_containing_shadow.is_none();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let cut_xbl_binding_inheritance =
|
let cut_xbl_binding_inheritance =
|
||||||
|
|
|
@ -747,6 +747,7 @@ pub type FontVariationSettings = FontSettings<VariationValue<Number>>;
|
||||||
/// it and store it as a 32-bit integer
|
/// it and store it as a 32-bit integer
|
||||||
/// (see http://www.microsoft.com/typography/otspec/languagetags.htm).
|
/// (see http://www.microsoft.com/typography/otspec/languagetags.htm).
|
||||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct FontLanguageOverride(pub u32);
|
pub struct FontLanguageOverride(pub u32);
|
||||||
|
|
||||||
impl FontLanguageOverride {
|
impl FontLanguageOverride {
|
||||||
|
|
|
@ -202,21 +202,34 @@ impl ToCss for CalcLengthOrPercentage {
|
||||||
{
|
{
|
||||||
use num_traits::Zero;
|
use num_traits::Zero;
|
||||||
|
|
||||||
let (length, percentage) = match (self.length, self.percentage) {
|
let length = self.unclamped_length();
|
||||||
(l, None) => return l.to_css(dest),
|
match self.percentage {
|
||||||
(l, Some(p)) if l.px() == 0. => return p.to_css(dest),
|
Some(p) => {
|
||||||
(l, Some(p)) => (l, p),
|
if length.px() == 0. && self.clamping_mode.clamp(p.0) == p.0 {
|
||||||
};
|
return p.to_css(dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if self.clamping_mode.clamp(length.px()) == length.px() {
|
||||||
|
return length.to_css(dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dest.write_str("calc(")?;
|
dest.write_str("calc(")?;
|
||||||
percentage.to_css(dest)?;
|
if let Some(percentage) = self.percentage {
|
||||||
|
percentage.to_css(dest)?;
|
||||||
dest.write_str(if length.px() < Zero::zero() {
|
if length.px() != 0. {
|
||||||
" - "
|
dest.write_str(if length.px() < Zero::zero() {
|
||||||
|
" - "
|
||||||
|
} else {
|
||||||
|
" + "
|
||||||
|
})?;
|
||||||
|
length.abs().to_css(dest)?;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
" + "
|
length.to_css(dest)?;
|
||||||
})?;
|
}
|
||||||
length.abs().to_css(dest)?;
|
|
||||||
|
|
||||||
dest.write_str(")")
|
dest.write_str(")")
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ use values::generics::NonNegative;
|
||||||
ToAnimatedZero,
|
ToAnimatedZero,
|
||||||
ToComputedValue,
|
ToComputedValue,
|
||||||
)]
|
)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct Percentage(pub CSSFloat);
|
pub struct Percentage(pub CSSFloat);
|
||||||
|
|
||||||
impl Percentage {
|
impl Percentage {
|
||||||
|
|
|
@ -292,14 +292,16 @@ pub const FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES: f32 = 90.;
|
||||||
pub const FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES: f32 = -90.;
|
pub const FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES: f32 = -90.;
|
||||||
|
|
||||||
impl SpecifiedFontStyle {
|
impl SpecifiedFontStyle {
|
||||||
/// Gets a clamped angle from a specified Angle.
|
/// Gets a clamped angle in degrees from a specified Angle.
|
||||||
pub fn compute_angle(angle: &Angle) -> ComputedAngle {
|
pub fn compute_angle_degrees(angle: &Angle) -> f32 {
|
||||||
ComputedAngle::Deg(
|
angle
|
||||||
angle
|
.degrees()
|
||||||
.degrees()
|
.max(FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES)
|
||||||
.max(FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES)
|
.min(FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES)
|
||||||
.min(FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES),
|
}
|
||||||
)
|
|
||||||
|
fn compute_angle(angle: &Angle) -> ComputedAngle {
|
||||||
|
ComputedAngle::Deg(Self::compute_angle_degrees(angle))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a suitable angle for font-style: oblique.
|
/// Parse a suitable angle for font-style: oblique.
|
||||||
|
@ -380,6 +382,7 @@ impl Parse for FontStyle {
|
||||||
/// https://drafts.csswg.org/css-fonts-4/#font-stretch-prop
|
/// https://drafts.csswg.org/css-fonts-4/#font-stretch-prop
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
|
||||||
|
#[repr(u8)]
|
||||||
pub enum FontStretch {
|
pub enum FontStretch {
|
||||||
Stretch(Percentage),
|
Stretch(Percentage),
|
||||||
Keyword(FontStretchKeyword),
|
Keyword(FontStretchKeyword),
|
||||||
|
@ -2057,6 +2060,29 @@ impl FontLanguageOverride {
|
||||||
FontLanguageOverride::Normal
|
FontLanguageOverride::Normal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The ToComputedValue implementation for non-system-font
|
||||||
|
/// FontLanguageOverride, used for @font-face descriptors.
|
||||||
|
#[inline]
|
||||||
|
pub fn compute_non_system(&self) -> computed::FontLanguageOverride {
|
||||||
|
match *self {
|
||||||
|
FontLanguageOverride::Normal => computed::FontLanguageOverride(0),
|
||||||
|
FontLanguageOverride::Override(ref lang) => {
|
||||||
|
if lang.is_empty() || lang.len() > 4 {
|
||||||
|
return computed::FontLanguageOverride(0);
|
||||||
|
}
|
||||||
|
let mut bytes = [b' '; 4];
|
||||||
|
for (byte, lang_byte) in bytes.iter_mut().zip(lang.as_bytes()) {
|
||||||
|
if !lang_byte.is_ascii() {
|
||||||
|
return computed::FontLanguageOverride(0);
|
||||||
|
}
|
||||||
|
*byte = *lang_byte;
|
||||||
|
}
|
||||||
|
computed::FontLanguageOverride(BigEndian::read_u32(&bytes))
|
||||||
|
},
|
||||||
|
FontLanguageOverride::System(..) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
system_font_methods!(FontLanguageOverride, font_language_override);
|
system_font_methods!(FontLanguageOverride, font_language_override);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2066,19 +2092,8 @@ impl ToComputedValue for FontLanguageOverride {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_computed_value(&self, context: &Context) -> computed::FontLanguageOverride {
|
fn to_computed_value(&self, context: &Context) -> computed::FontLanguageOverride {
|
||||||
match *self {
|
match *self {
|
||||||
FontLanguageOverride::Normal => computed::FontLanguageOverride(0),
|
|
||||||
FontLanguageOverride::Override(ref lang) => {
|
|
||||||
if lang.is_empty() || lang.len() > 4 || !lang.is_ascii() {
|
|
||||||
return computed::FontLanguageOverride(0);
|
|
||||||
}
|
|
||||||
let mut computed_lang = lang.to_string();
|
|
||||||
while computed_lang.len() < 4 {
|
|
||||||
computed_lang.push(' ');
|
|
||||||
}
|
|
||||||
let bytes = computed_lang.into_bytes();
|
|
||||||
computed::FontLanguageOverride(BigEndian::read_u32(&bytes))
|
|
||||||
},
|
|
||||||
FontLanguageOverride::System(_) => self.compute_system(context),
|
FontLanguageOverride::System(_) => self.compute_system(context),
|
||||||
|
_ => self.compute_non_system(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//! [image]: https://drafts.csswg.org/css-images/#image-values
|
//! [image]: https://drafts.csswg.org/css-images/#image-values
|
||||||
|
|
||||||
use Atom;
|
use Atom;
|
||||||
use cssparser::{Parser, Token};
|
use cssparser::{Parser, Token, Delimiter};
|
||||||
use custom_properties::SpecifiedValue;
|
use custom_properties::SpecifiedValue;
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
use selectors::parser::SelectorParseErrorKind;
|
use selectors::parser::SelectorParseErrorKind;
|
||||||
|
@ -956,17 +956,43 @@ impl GradientItem {
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Vec<Self>, ParseError<'i>> {
|
) -> Result<Vec<Self>, ParseError<'i>> {
|
||||||
|
let mut items = Vec::new();
|
||||||
let mut seen_stop = false;
|
let mut seen_stop = false;
|
||||||
let items = input.parse_comma_separated(|input| {
|
|
||||||
if seen_stop {
|
loop {
|
||||||
if let Ok(hint) = input.try(|i| LengthOrPercentage::parse(context, i)) {
|
input.parse_until_before(Delimiter::Comma, |input| {
|
||||||
seen_stop = false;
|
if seen_stop {
|
||||||
return Ok(generic::GradientItem::InterpolationHint(hint));
|
if let Ok(hint) = input.try(|i| LengthOrPercentage::parse(context, i)) {
|
||||||
|
seen_stop = false;
|
||||||
|
items.push(generic::GradientItem::InterpolationHint(hint));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let stop = ColorStop::parse(context, input)?;
|
||||||
|
|
||||||
|
if let Ok(multi_position) = input.try(|i| LengthOrPercentage::parse(context, i)) {
|
||||||
|
let stop_color = stop.color.clone();
|
||||||
|
items.push(generic::GradientItem::ColorStop(stop));
|
||||||
|
items.push(generic::GradientItem::ColorStop(ColorStop {
|
||||||
|
color: stop_color,
|
||||||
|
position: Some(multi_position),
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
items.push(generic::GradientItem::ColorStop(stop));
|
||||||
|
}
|
||||||
|
|
||||||
|
seen_stop = true;
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
match input.next() {
|
||||||
|
Err(_) => break,
|
||||||
|
Ok(&Token::Comma) => continue,
|
||||||
|
Ok(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
seen_stop = true;
|
}
|
||||||
ColorStop::parse(context, input).map(generic::GradientItem::ColorStop)
|
|
||||||
})?;
|
|
||||||
if !seen_stop || items.len() < 2 {
|
if !seen_stop || items.len() < 2 {
|
||||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,51 +1,4 @@
|
||||||
[color-stops-parsing.html]
|
[color-stops-parsing.html]
|
||||||
[linear-gradient(black 0% 50%, white) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[linear-gradient(black 0% 50%, white 50% 100%) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[linear-gradient(black 0% 50%, green 25% 75%, white 50% 100%) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[linear-gradient(black 0% calc(100% / 5), 25%, green 30% 60%, calc(100% * 3 / 4), white calc(100% - 20%) 100%) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[repeating-linear-gradient(black 0% 50%, white) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[repeating-linear-gradient(black 0% 50%, white 50% 100%) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[repeating-linear-gradient(black 0% 50%, green 25% 75%, white 50% 100%) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[repeating-linear-gradient(black 0% calc(100% / 5), 25%, green 30% 60%, calc(100% * 3 / 4), white calc(100% - 20%) 100%) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[radial-gradient(black 0% 50%, white) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[radial-gradient(black 0% 50%, white 50% 100%) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[radial-gradient(black 0% 50%, green 25% 75%, white 50% 100%) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[radial-gradient(black 0% calc(100% / 5), 25%, green 30% 60%, calc(100% * 3 / 4), white calc(100% - 20%) 100%) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[repeating-radial-gradient(black 0% 50%, white) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[repeating-radial-gradient(black 0% 50%, white 50% 100%) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[repeating-radial-gradient(black 0% 50%, green 25% 75%, white 50% 100%) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[repeating-radial-gradient(black 0% calc(100% / 5), 25%, green 30% 60%, calc(100% * 3 / 4), white calc(100% - 20%) 100%) [ parsable \]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[conic-gradient(black, white) [ parsable \]]
|
[conic-gradient(black, white) [ parsable \]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[multiple-position-color-stop-linear-2.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[multiple-position-color-stop-linear.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[multiple-position-color-stop-radial.html]
|
|
||||||
expected: FAIL
|
|
Loading…
Add table
Add a link
Reference in a new issue