mirror of
https://github.com/servo/servo.git
synced 2025-08-21 05:15:33 +01:00
Move gecko_* into style::gecko
Prepping for the next stage where most of geckolib/ is popped in here
This commit is contained in:
parent
c6787458d9
commit
bc9cbc87ba
8 changed files with 14 additions and 16 deletions
286
components/style/gecko/conversions.rs
Normal file
286
components/style/gecko/conversions.rs
Normal file
|
@ -0,0 +1,286 @@
|
|||
/* 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/. */
|
||||
|
||||
//! This module contains conversion helpers between Servo and Gecko types
|
||||
//! Ideally, it would be in geckolib itself, but coherence
|
||||
//! forces us to keep the traits and implementations here
|
||||
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use app_units::Au;
|
||||
use gecko_bindings::bindings::{RawServoStyleSheet, ServoComputedValues};
|
||||
use gecko_bindings::structs::nsStyleCoord_CalcValue;
|
||||
use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI};
|
||||
use properties::ComputedValues;
|
||||
use stylesheets::Stylesheet;
|
||||
use values::computed::{CalcLengthOrPercentage, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||
|
||||
unsafe impl HasFFI for Stylesheet {
|
||||
type FFIType = RawServoStyleSheet;
|
||||
}
|
||||
unsafe impl HasArcFFI for Stylesheet {}
|
||||
unsafe impl HasFFI for ComputedValues {
|
||||
type FFIType = ServoComputedValues;
|
||||
}
|
||||
unsafe impl HasArcFFI for ComputedValues {}
|
||||
|
||||
impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
|
||||
fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
|
||||
let has_percentage = other.percentage.is_some();
|
||||
nsStyleCoord_CalcValue {
|
||||
mLength: other.length.map_or(0, |l| l.0),
|
||||
mPercent: other.percentage.unwrap_or(0.0),
|
||||
mHasPercent: has_percentage,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nsStyleCoord_CalcValue> for CalcLengthOrPercentage {
|
||||
fn from(other: nsStyleCoord_CalcValue) -> CalcLengthOrPercentage {
|
||||
let percentage = if other.mHasPercent {
|
||||
Some(other.mPercent)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
CalcLengthOrPercentage {
|
||||
length: Some(Au(other.mLength)),
|
||||
percentage: percentage,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LengthOrPercentage> for nsStyleCoord_CalcValue {
|
||||
fn from(other: LengthOrPercentage) -> nsStyleCoord_CalcValue {
|
||||
match other {
|
||||
LengthOrPercentage::Length(au) => {
|
||||
nsStyleCoord_CalcValue {
|
||||
mLength: au.0,
|
||||
mPercent: 0.0,
|
||||
mHasPercent: false,
|
||||
}
|
||||
},
|
||||
LengthOrPercentage::Percentage(pc) => {
|
||||
nsStyleCoord_CalcValue {
|
||||
mLength: 0,
|
||||
mPercent: pc,
|
||||
mHasPercent: true,
|
||||
}
|
||||
},
|
||||
LengthOrPercentage::Calc(calc) => calc.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LengthOrPercentageOrAuto {
|
||||
pub fn to_calc_value(&self) -> Option<nsStyleCoord_CalcValue> {
|
||||
match *self {
|
||||
LengthOrPercentageOrAuto::Length(au) => {
|
||||
Some(nsStyleCoord_CalcValue {
|
||||
mLength: au.0,
|
||||
mPercent: 0.0,
|
||||
mHasPercent: false,
|
||||
})
|
||||
},
|
||||
LengthOrPercentageOrAuto::Percentage(pc) => {
|
||||
Some(nsStyleCoord_CalcValue {
|
||||
mLength: 0,
|
||||
mPercent: pc,
|
||||
mHasPercent: true,
|
||||
})
|
||||
},
|
||||
LengthOrPercentageOrAuto::Calc(calc) => Some(calc.into()),
|
||||
LengthOrPercentageOrAuto::Auto => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nsStyleCoord_CalcValue> for LengthOrPercentage {
|
||||
fn from(other: nsStyleCoord_CalcValue) -> LengthOrPercentage {
|
||||
match (other.mHasPercent, other.mLength) {
|
||||
(false, _) => LengthOrPercentage::Length(Au(other.mLength)),
|
||||
(true, 0) => LengthOrPercentage::Percentage(other.mPercent),
|
||||
_ => LengthOrPercentage::Calc(other.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod basic_shape {
|
||||
use euclid::size::Size2D;
|
||||
use gecko_bindings::structs;
|
||||
use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleFillRule};
|
||||
use gecko_bindings::structs::{nsStyleCoord, nsStyleCorners};
|
||||
use gecko_bindings::structs::StyleClipPathGeometryBox;
|
||||
use gecko_bindings::sugar::ns_style_coord::{CoordDataMut, CoordDataValue};
|
||||
use gecko::values::GeckoStyleCoordConvertible;
|
||||
use std::borrow::Borrow;
|
||||
use values::computed::{BorderRadiusSize, LengthOrPercentage};
|
||||
use values::computed::basic_shape::*;
|
||||
use values::computed::position;
|
||||
|
||||
// using Borrow so that we can have a non-moving .into()
|
||||
impl<T: Borrow<StyleBasicShape>> From<T> for BasicShape {
|
||||
fn from(other: T) -> Self {
|
||||
let other = other.borrow();
|
||||
match other.mType {
|
||||
StyleBasicShapeType::Inset => {
|
||||
let t = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[0]);
|
||||
let r = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[1]);
|
||||
let b = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[2]);
|
||||
let l = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[3]);
|
||||
let round = (&other.mRadius).into();
|
||||
BasicShape::Inset(InsetRect {
|
||||
top: t.expect("inset() offset should be a length, percentage, or calc value"),
|
||||
right: r.expect("inset() offset should be a length, percentage, or calc value"),
|
||||
bottom: b.expect("inset() offset should be a length, percentage, or calc value"),
|
||||
left: l.expect("inset() offset should be a length, percentage, or calc value"),
|
||||
round: Some(round),
|
||||
})
|
||||
}
|
||||
StyleBasicShapeType::Circle => {
|
||||
BasicShape::Circle(Circle {
|
||||
radius: (&other.mCoordinates[0]).into(),
|
||||
position: (&other.mPosition).into()
|
||||
})
|
||||
}
|
||||
StyleBasicShapeType::Ellipse => {
|
||||
BasicShape::Ellipse(Ellipse {
|
||||
semiaxis_x: (&other.mCoordinates[0]).into(),
|
||||
semiaxis_y: (&other.mCoordinates[1]).into(),
|
||||
position: (&other.mPosition).into()
|
||||
})
|
||||
}
|
||||
StyleBasicShapeType::Polygon => {
|
||||
let fill_rule = if other.mFillRule == StyleFillRule::Evenodd {
|
||||
FillRule::EvenOdd
|
||||
} else {
|
||||
FillRule::NonZero
|
||||
};
|
||||
let mut coords = Vec::with_capacity(other.mCoordinates.len() / 2);
|
||||
for i in 0..(other.mCoordinates.len() / 2) {
|
||||
let x = 2 * i;
|
||||
let y = x + 1;
|
||||
coords.push((LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[x])
|
||||
.expect("polygon() coordinate should be a length, percentage, or calc value"),
|
||||
LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[y])
|
||||
.expect("polygon() coordinate should be a length, percentage, or calc value")
|
||||
))
|
||||
}
|
||||
BasicShape::Polygon(Polygon {
|
||||
fill: fill_rule,
|
||||
coordinates: coords,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Borrow<nsStyleCorners>> From<T> for BorderRadius {
|
||||
fn from(other: T) -> Self {
|
||||
let other = other.borrow();
|
||||
let get_corner = |index| {
|
||||
BorderRadiusSize(Size2D::new(
|
||||
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index))
|
||||
.expect("<border-radius> should be a length, percentage, or calc value"),
|
||||
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1))
|
||||
.expect("<border-radius> should be a length, percentage, or calc value")))
|
||||
};
|
||||
|
||||
BorderRadius {
|
||||
top_left: get_corner(0),
|
||||
top_right: get_corner(2),
|
||||
bottom_right: get_corner(4),
|
||||
bottom_left: get_corner(6),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Can't be a From impl since we need to set an existing
|
||||
// nsStyleCorners, not create a new one
|
||||
impl BorderRadius {
|
||||
pub fn set_corners(&self, other: &mut nsStyleCorners) {
|
||||
let mut set_corner = |field: &BorderRadiusSize, index| {
|
||||
field.0.width.to_gecko_style_coord(&mut other.data_at_mut(index));
|
||||
field.0.height.to_gecko_style_coord(&mut other.data_at_mut(index + 1));
|
||||
};
|
||||
set_corner(&self.top_left, 0);
|
||||
set_corner(&self.top_right, 2);
|
||||
set_corner(&self.bottom_right, 4);
|
||||
set_corner(&self.bottom_left, 6);
|
||||
}
|
||||
}
|
||||
|
||||
/// We use None for a nonexistant radius, but Gecko uses (0 0 0 0 / 0 0 0 0)
|
||||
pub fn set_corners_from_radius(radius: Option<BorderRadius>, other: &mut nsStyleCorners) {
|
||||
if let Some(radius) = radius {
|
||||
radius.set_corners(other);
|
||||
} else {
|
||||
for i in 0..8 {
|
||||
other.data_at_mut(i).set_value(CoordDataValue::Coord(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Can't be a From impl since we need to set an existing
|
||||
// Position, not create a new one
|
||||
impl From<position::Position> for structs::Position {
|
||||
fn from(other: position::Position) -> Self {
|
||||
structs::Position {
|
||||
mXPosition: other.horizontal.into(),
|
||||
mYPosition: other.vertical.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Borrow<nsStyleCoord>> From<T> for ShapeRadius {
|
||||
fn from(other: T) -> Self {
|
||||
let other = other.borrow();
|
||||
ShapeRadius::from_gecko_style_coord(other)
|
||||
.expect("<shape-radius> should be a length, percentage, calc, or keyword value")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Borrow<structs::Position>> From<T> for position::Position {
|
||||
fn from(other: T) -> Self {
|
||||
let other = other.borrow();
|
||||
position::Position {
|
||||
horizontal: other.mXPosition.into(),
|
||||
vertical: other.mYPosition.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GeometryBox> for StyleClipPathGeometryBox {
|
||||
fn from(reference: GeometryBox) -> Self {
|
||||
use gecko_bindings::structs::StyleClipPathGeometryBox::*;
|
||||
match reference {
|
||||
GeometryBox::ShapeBox(ShapeBox::Content) => Content,
|
||||
GeometryBox::ShapeBox(ShapeBox::Padding) => Padding,
|
||||
GeometryBox::ShapeBox(ShapeBox::Border) => Border,
|
||||
GeometryBox::ShapeBox(ShapeBox::Margin) => Margin,
|
||||
GeometryBox::Fill => Fill,
|
||||
GeometryBox::Stroke => Stroke,
|
||||
GeometryBox::View => View,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Will panic on NoBox
|
||||
// Ideally these would be implemented on Option<T>,
|
||||
// but coherence doesn't like that and TryFrom isn't stable
|
||||
impl From<StyleClipPathGeometryBox> for GeometryBox {
|
||||
fn from(reference: StyleClipPathGeometryBox) -> Self {
|
||||
use gecko_bindings::structs::StyleClipPathGeometryBox::*;
|
||||
match reference {
|
||||
NoBox => panic!("Shouldn't convert NoBox to GeometryBox"),
|
||||
Content => GeometryBox::ShapeBox(ShapeBox::Content),
|
||||
Padding => GeometryBox::ShapeBox(ShapeBox::Padding),
|
||||
Border => GeometryBox::ShapeBox(ShapeBox::Border),
|
||||
Margin => GeometryBox::ShapeBox(ShapeBox::Margin),
|
||||
Fill => GeometryBox::Fill,
|
||||
Stroke => GeometryBox::Stroke,
|
||||
View => GeometryBox::View,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
254
components/style/gecko/selector_impl.rs
Normal file
254
components/style/gecko/selector_impl.rs
Normal file
|
@ -0,0 +1,254 @@
|
|||
/* 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/. */
|
||||
|
||||
use cssparser::ToCss;
|
||||
use element_state::ElementState;
|
||||
use selector_impl::{attr_equals_selector_is_shareable, attr_exists_selector_is_shareable};
|
||||
use selector_impl::PseudoElementCascadeType;
|
||||
use selectors::parser::{AttrSelector, ParserContext, SelectorImpl};
|
||||
use std::fmt;
|
||||
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct GeckoSelectorImpl;
|
||||
|
||||
/// NOTE: The boolean field represents whether this element is an anonymous box.
|
||||
///
|
||||
/// This is just for convenience, instead of recomputing it. Also, note that
|
||||
/// Atom is always a static atom, so if space is a concern, we can use the
|
||||
/// raw pointer and use the lower bit to represent it without space overhead.
|
||||
///
|
||||
/// FIXME(emilio): we know all these atoms are static. Patches are starting to
|
||||
/// pile up, but a further potential optimisation is generating bindings without
|
||||
/// `-no-gen-bitfield-methods` (that was removed to compile on stable, but it no
|
||||
/// longer depends on it), and using the raw *mut nsIAtom (properly asserting
|
||||
/// we're a static atom).
|
||||
///
|
||||
/// This should allow us to avoid random FFI overhead when cloning/dropping
|
||||
/// pseudos.
|
||||
///
|
||||
/// Also, we can further optimize PartialEq and hash comparing/hashing only the
|
||||
/// atoms.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct PseudoElement(Atom, bool);
|
||||
|
||||
impl PseudoElement {
|
||||
#[inline]
|
||||
pub fn as_atom(&self) -> &Atom {
|
||||
&self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_anon_box(&self) -> bool {
|
||||
self.1
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_atom_unchecked(atom: Atom, is_anon_box: bool) -> Self {
|
||||
if cfg!(debug_assertions) {
|
||||
// Do the check on debug regardless.
|
||||
match Self::from_atom(&*atom, true) {
|
||||
Some(pseudo) => {
|
||||
assert_eq!(pseudo.is_anon_box(), is_anon_box);
|
||||
return pseudo;
|
||||
}
|
||||
None => panic!("Unknown pseudo: {:?}", atom),
|
||||
}
|
||||
}
|
||||
|
||||
PseudoElement(atom, is_anon_box)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_atom(atom: &WeakAtom, in_ua: bool) -> Option<Self> {
|
||||
macro_rules! pseudo_element {
|
||||
($pseudo_str_with_colon:expr, $atom:expr, $is_anon_box:expr) => {{
|
||||
if atom == &*$atom {
|
||||
return Some(PseudoElement($atom, $is_anon_box));
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
include!("../generated/gecko_pseudo_element_helper.rs");
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_slice(s: &str, in_ua_stylesheet: bool) -> Option<Self> {
|
||||
use std::ascii::AsciiExt;
|
||||
macro_rules! pseudo_element {
|
||||
($pseudo_str_with_colon:expr, $atom:expr, $is_anon_box:expr) => {{
|
||||
if !$is_anon_box || in_ua_stylesheet {
|
||||
if s.eq_ignore_ascii_case(&$pseudo_str_with_colon[1..]) {
|
||||
return Some(PseudoElement($atom, $is_anon_box))
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
include!("../generated/gecko_pseudo_element_helper.rs");
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for PseudoElement {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
// FIXME: why does the atom contain one colon? Pseudo-element has two
|
||||
debug_assert!(self.0.as_slice().starts_with(&[b':' as u16]) &&
|
||||
!self.0.as_slice().starts_with(&[b':' as u16, b':' as u16]));
|
||||
try!(dest.write_char(':'));
|
||||
write!(dest, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum NonTSPseudoClass {
|
||||
AnyLink,
|
||||
Link,
|
||||
Visited,
|
||||
Active,
|
||||
Focus,
|
||||
Hover,
|
||||
Enabled,
|
||||
Disabled,
|
||||
Checked,
|
||||
Indeterminate,
|
||||
ReadWrite,
|
||||
ReadOnly,
|
||||
}
|
||||
|
||||
impl ToCss for NonTSPseudoClass {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
use self::NonTSPseudoClass::*;
|
||||
dest.write_str(match *self {
|
||||
AnyLink => ":any-link",
|
||||
Link => ":link",
|
||||
Visited => ":visited",
|
||||
Active => ":active",
|
||||
Focus => ":focus",
|
||||
Hover => ":hover",
|
||||
Enabled => ":enabled",
|
||||
Disabled => ":disabled",
|
||||
Checked => ":checked",
|
||||
Indeterminate => ":indeterminate",
|
||||
ReadWrite => ":read-write",
|
||||
ReadOnly => ":read-only",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl NonTSPseudoClass {
|
||||
pub fn state_flag(&self) -> ElementState {
|
||||
use element_state::*;
|
||||
use self::NonTSPseudoClass::*;
|
||||
match *self {
|
||||
Active => IN_ACTIVE_STATE,
|
||||
Focus => IN_FOCUS_STATE,
|
||||
Hover => IN_HOVER_STATE,
|
||||
Enabled => IN_ENABLED_STATE,
|
||||
Disabled => IN_DISABLED_STATE,
|
||||
Checked => IN_CHECKED_STATE,
|
||||
Indeterminate => IN_INDETERMINATE_STATE,
|
||||
ReadOnly | ReadWrite => IN_READ_WRITE_STATE,
|
||||
|
||||
AnyLink |
|
||||
Link |
|
||||
Visited => ElementState::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SelectorImpl for GeckoSelectorImpl {
|
||||
type AttrValue = Atom;
|
||||
type Identifier = Atom;
|
||||
type ClassName = Atom;
|
||||
type LocalName = Atom;
|
||||
type NamespacePrefix = Atom;
|
||||
type NamespaceUrl = Namespace;
|
||||
type BorrowedNamespaceUrl = WeakNamespace;
|
||||
type BorrowedLocalName = WeakAtom;
|
||||
|
||||
type PseudoElement = PseudoElement;
|
||||
type NonTSPseudoClass = NonTSPseudoClass;
|
||||
|
||||
fn attr_exists_selector_is_shareable(attr_selector: &AttrSelector<Self>) -> bool {
|
||||
attr_exists_selector_is_shareable(attr_selector)
|
||||
}
|
||||
|
||||
fn attr_equals_selector_is_shareable(attr_selector: &AttrSelector<Self>,
|
||||
value: &Self::AttrValue) -> bool {
|
||||
attr_equals_selector_is_shareable(attr_selector, value)
|
||||
}
|
||||
|
||||
fn parse_non_ts_pseudo_class(_context: &ParserContext<Self>,
|
||||
name: &str) -> Result<NonTSPseudoClass, ()> {
|
||||
use self::NonTSPseudoClass::*;
|
||||
let pseudo_class = match_ignore_ascii_case! { name,
|
||||
"any-link" => AnyLink,
|
||||
"link" => Link,
|
||||
"visited" => Visited,
|
||||
"active" => Active,
|
||||
"focus" => Focus,
|
||||
"hover" => Hover,
|
||||
"enabled" => Enabled,
|
||||
"disabled" => Disabled,
|
||||
"checked" => Checked,
|
||||
"indeterminate" => Indeterminate,
|
||||
"read-write" => ReadWrite,
|
||||
"read-only" => ReadOnly,
|
||||
_ => return Err(())
|
||||
};
|
||||
|
||||
Ok(pseudo_class)
|
||||
}
|
||||
|
||||
fn parse_pseudo_element(context: &ParserContext<Self>,
|
||||
name: &str) -> Result<PseudoElement, ()> {
|
||||
match PseudoElement::from_slice(name, context.in_user_agent_stylesheet) {
|
||||
Some(pseudo) => Ok(pseudo),
|
||||
None => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GeckoSelectorImpl {
|
||||
#[inline]
|
||||
pub fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType {
|
||||
if Self::pseudo_is_before_or_after(pseudo) {
|
||||
return PseudoElementCascadeType::Eager
|
||||
}
|
||||
|
||||
if pseudo.is_anon_box() {
|
||||
return PseudoElementCascadeType::Precomputed
|
||||
}
|
||||
|
||||
PseudoElementCascadeType::Lazy
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn each_pseudo_element<F>(mut fun: F)
|
||||
where F: FnMut(PseudoElement)
|
||||
{
|
||||
macro_rules! pseudo_element {
|
||||
($pseudo_str_with_colon:expr, $atom:expr, $is_anon_box:expr) => {{
|
||||
fun(PseudoElement($atom, $is_anon_box));
|
||||
}}
|
||||
}
|
||||
|
||||
include!("../generated/gecko_pseudo_element_helper.rs")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool {
|
||||
*pseudo.as_atom() == atom!(":before") ||
|
||||
*pseudo.as_atom() == atom!(":after")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
|
||||
pc.state_flag()
|
||||
}
|
||||
}
|
175
components/style/gecko/values.rs
Normal file
175
components/style/gecko/values.rs
Normal file
|
@ -0,0 +1,175 @@
|
|||
/* 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/. */
|
||||
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use app_units::Au;
|
||||
use cssparser::RGBA;
|
||||
use gecko_bindings::structs::{NS_RADIUS_CLOSEST_SIDE, NS_RADIUS_FARTHEST_SIDE};
|
||||
use gecko_bindings::structs::nsStyleCoord;
|
||||
use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
|
||||
use std::cmp::max;
|
||||
use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
|
||||
use values::computed::Angle;
|
||||
use values::computed::basic_shape::ShapeRadius;
|
||||
|
||||
pub trait StyleCoordHelpers {
|
||||
fn set<T: GeckoStyleCoordConvertible>(&mut self, val: T);
|
||||
}
|
||||
|
||||
impl StyleCoordHelpers for nsStyleCoord {
|
||||
#[inline]
|
||||
fn set<T: GeckoStyleCoordConvertible>(&mut self, val: T) {
|
||||
val.to_gecko_style_coord(self);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait GeckoStyleCoordConvertible : Sized {
|
||||
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T);
|
||||
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self>;
|
||||
}
|
||||
|
||||
impl GeckoStyleCoordConvertible for LengthOrPercentage {
|
||||
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
||||
let value = match *self {
|
||||
LengthOrPercentage::Length(au) => CoordDataValue::Coord(au.0),
|
||||
LengthOrPercentage::Percentage(p) => CoordDataValue::Percent(p),
|
||||
LengthOrPercentage::Calc(calc) => CoordDataValue::Calc(calc.into()),
|
||||
};
|
||||
coord.set_value(value);
|
||||
}
|
||||
|
||||
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
||||
match coord.as_value() {
|
||||
CoordDataValue::Coord(coord) => Some(LengthOrPercentage::Length(Au(coord))),
|
||||
CoordDataValue::Percent(p) => Some(LengthOrPercentage::Percentage(p)),
|
||||
CoordDataValue::Calc(calc) => Some(LengthOrPercentage::Calc(calc.into())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto {
|
||||
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
||||
let value = match *self {
|
||||
LengthOrPercentageOrAuto::Length(au) => CoordDataValue::Coord(au.0),
|
||||
LengthOrPercentageOrAuto::Percentage(p) => CoordDataValue::Percent(p),
|
||||
LengthOrPercentageOrAuto::Auto => CoordDataValue::Auto,
|
||||
LengthOrPercentageOrAuto::Calc(calc) => CoordDataValue::Calc(calc.into()),
|
||||
};
|
||||
coord.set_value(value);
|
||||
}
|
||||
|
||||
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
||||
match coord.as_value() {
|
||||
CoordDataValue::Coord(coord) => Some(LengthOrPercentageOrAuto::Length(Au(coord))),
|
||||
CoordDataValue::Percent(p) => Some(LengthOrPercentageOrAuto::Percentage(p)),
|
||||
CoordDataValue::Auto => Some(LengthOrPercentageOrAuto::Auto),
|
||||
CoordDataValue::Calc(calc) => Some(LengthOrPercentageOrAuto::Calc(calc.into())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GeckoStyleCoordConvertible for LengthOrPercentageOrNone {
|
||||
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
||||
let value = match *self {
|
||||
LengthOrPercentageOrNone::Length(au) => CoordDataValue::Coord(au.0),
|
||||
LengthOrPercentageOrNone::Percentage(p) => CoordDataValue::Percent(p),
|
||||
LengthOrPercentageOrNone::None => CoordDataValue::None,
|
||||
LengthOrPercentageOrNone::Calc(calc) => CoordDataValue::Calc(calc.into()),
|
||||
};
|
||||
coord.set_value(value);
|
||||
}
|
||||
|
||||
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
||||
match coord.as_value() {
|
||||
CoordDataValue::Coord(coord) => Some(LengthOrPercentageOrNone::Length(Au(coord))),
|
||||
CoordDataValue::Percent(p) => Some(LengthOrPercentageOrNone::Percentage(p)),
|
||||
CoordDataValue::None => Some(LengthOrPercentageOrNone::None),
|
||||
CoordDataValue::Calc(calc) => Some(LengthOrPercentageOrNone::Calc(calc.into())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GeckoStyleCoordConvertible for ShapeRadius {
|
||||
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
||||
match *self {
|
||||
ShapeRadius::ClosestSide => {
|
||||
coord.set_value(CoordDataValue::Enumerated(NS_RADIUS_CLOSEST_SIDE))
|
||||
}
|
||||
ShapeRadius::FarthestSide => {
|
||||
coord.set_value(CoordDataValue::Enumerated(NS_RADIUS_FARTHEST_SIDE))
|
||||
}
|
||||
ShapeRadius::Length(lop) => lop.to_gecko_style_coord(coord),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
||||
match coord.as_value() {
|
||||
CoordDataValue::Enumerated(NS_RADIUS_CLOSEST_SIDE) => Some(ShapeRadius::ClosestSide),
|
||||
CoordDataValue::Enumerated(NS_RADIUS_FARTHEST_SIDE) => Some(ShapeRadius::FarthestSide),
|
||||
_ => LengthOrPercentage::from_gecko_style_coord(coord).map(ShapeRadius::Length),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for Option<T> {
|
||||
fn to_gecko_style_coord<U: CoordDataMut>(&self, coord: &mut U) {
|
||||
if let Some(ref me) = *self {
|
||||
me.to_gecko_style_coord(coord);
|
||||
} else {
|
||||
coord.set_value(CoordDataValue::None);
|
||||
}
|
||||
}
|
||||
|
||||
fn from_gecko_style_coord<U: CoordData>(coord: &U) -> Option<Self> {
|
||||
Some(T::from_gecko_style_coord(coord))
|
||||
}
|
||||
}
|
||||
|
||||
impl GeckoStyleCoordConvertible for Angle {
|
||||
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
||||
coord.set_value(CoordDataValue::Radian(self.radians()))
|
||||
}
|
||||
|
||||
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
||||
if let CoordDataValue::Radian(r) = coord.as_value() {
|
||||
Some(Angle::from_radians(r))
|
||||
// XXXManishearth should this handle Degree too?
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 {
|
||||
(((rgba.alpha * 255.0).round() as u32) << 24) |
|
||||
(((rgba.blue * 255.0).round() as u32) << 16) |
|
||||
(((rgba.green * 255.0).round() as u32) << 8) |
|
||||
((rgba.red * 255.0).round() as u32)
|
||||
}
|
||||
|
||||
pub fn convert_nscolor_to_rgba(color: u32) -> RGBA {
|
||||
RGBA {
|
||||
red: ((color & 0xff) as f32) / 255.0,
|
||||
green: (((color >> 8) & 0xff) as f32) / 255.0,
|
||||
blue: (((color >> 16) & 0xff) as f32) / 255.0,
|
||||
alpha: (((color >> 24) & 0xff) as f32) / 255.0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn round_border_to_device_pixels(width: Au, au_per_device_px: Au) -> Au {
|
||||
// Round width down to the nearest device pixel, but any non-zero value that
|
||||
// would round down to zero is clamped to 1 device pixel. Used for storing
|
||||
// computed values of border-*-width and outline-width.
|
||||
if width == Au(0) {
|
||||
Au(0)
|
||||
} else {
|
||||
max(au_per_device_px, Au(width.0 / au_per_device_px.0 * au_per_device_px.0))
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue