servo/components/style/gecko_bindings/sugar/ns_css_value.rs
Jonathan Watt 36cef8ec68
style: Use user defined types for font-stretch / font-style.
Co-authored-by: Emilio Cobos Álvarez <emilio@crisal.io>
Bug: 1436048
Reviewed-by: jfkthame,jwatt
MozReview-Commit-ID: 7ONYtICeAqb
2018-04-28 10:26:06 +02:00

445 lines
14 KiB
Rust

/* 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/. */
//! Little helpers for `nsCSSValue`.
use gecko_bindings::bindings;
use gecko_bindings::structs;
use gecko_bindings::structs::{nsCSSUnit, nsCSSValue};
use gecko_bindings::structs::{nsCSSValueList, nsCSSValue_Array};
use gecko_string_cache::Atom;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Index, IndexMut};
use std::slice;
use values::computed::{Angle, Length, LengthOrPercentage, Percentage};
use values::specified::url::SpecifiedUrl;
impl nsCSSValue {
/// Create a CSSValue with null unit, useful to be used as a return value.
#[inline]
pub fn null() -> Self {
unsafe { mem::zeroed() }
}
/// Returns true if this nsCSSValue is none.
#[inline]
pub fn is_none(&self) -> bool {
self.mUnit == nsCSSUnit::eCSSUnit_None
}
/// Returns this nsCSSValue value as an integer, unchecked in release
/// builds.
pub fn integer_unchecked(&self) -> i32 {
debug_assert!(
self.mUnit == nsCSSUnit::eCSSUnit_Integer ||
self.mUnit == nsCSSUnit::eCSSUnit_Enumerated
);
unsafe { *self.mValue.mInt.as_ref() }
}
/// Checks if it is an integer and returns it if so
pub fn integer(&self) -> Option<i32> {
if self.mUnit == nsCSSUnit::eCSSUnit_Integer || self.mUnit == nsCSSUnit::eCSSUnit_Enumerated
{
Some(unsafe { *self.mValue.mInt.as_ref() })
} else {
None
}
}
/// Returns this nsCSSValue value as a floating point value, unchecked in
/// release builds.
pub fn float_unchecked(&self) -> f32 {
debug_assert!(nsCSSUnit::eCSSUnit_Number as u32 <= self.mUnit as u32);
unsafe { *self.mValue.mFloat.as_ref() }
}
/// Returns this nsCSSValue as a nsCSSValue::Array, unchecked in release
/// builds.
pub unsafe fn array_unchecked(&self) -> &nsCSSValue_Array {
debug_assert!(
nsCSSUnit::eCSSUnit_Array as u32 <= self.mUnit as u32 &&
self.mUnit as u32 <= nsCSSUnit::eCSSUnit_Calc_Divided as u32
);
let array = *self.mValue.mArray.as_ref();
debug_assert!(!array.is_null());
&*array
}
/// Sets LengthOrPercentage value to this nsCSSValue.
pub unsafe fn set_lop(&mut self, lop: LengthOrPercentage) {
match lop {
LengthOrPercentage::Length(px) => self.set_px(px.px()),
LengthOrPercentage::Percentage(pc) => self.set_percentage(pc.0),
LengthOrPercentage::Calc(calc) => bindings::Gecko_CSSValue_SetCalc(self, calc.into()),
}
}
/// Sets a px value to this nsCSSValue.
pub unsafe fn set_px(&mut self, px: f32) {
bindings::Gecko_CSSValue_SetPixelLength(self, px)
}
/// Sets a percentage value to this nsCSSValue.
pub unsafe fn set_percentage(&mut self, unit_value: f32) {
bindings::Gecko_CSSValue_SetPercentage(self, unit_value)
}
/// Returns LengthOrPercentage value.
pub unsafe fn get_lop(&self) -> LengthOrPercentage {
match self.mUnit {
nsCSSUnit::eCSSUnit_Pixel => {
LengthOrPercentage::Length(Length::new(bindings::Gecko_CSSValue_GetNumber(self)))
},
nsCSSUnit::eCSSUnit_Percent => LengthOrPercentage::Percentage(Percentage(
bindings::Gecko_CSSValue_GetPercentage(self),
)),
nsCSSUnit::eCSSUnit_Calc => {
LengthOrPercentage::Calc(bindings::Gecko_CSSValue_GetCalc(self).into())
},
_ => panic!("Unexpected unit"),
}
}
/// Returns Length value.
pub unsafe fn get_length(&self) -> Length {
match self.mUnit {
nsCSSUnit::eCSSUnit_Pixel => Length::new(bindings::Gecko_CSSValue_GetNumber(self)),
_ => panic!("Unexpected unit"),
}
}
fn set_valueless_unit(&mut self, unit: nsCSSUnit) {
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null);
debug_assert!(
unit as u32 <= nsCSSUnit::eCSSUnit_DummyInherit as u32,
"Not a valueless unit"
);
self.mUnit = unit;
}
/// Set to an auto value
///
/// This method requires the current value to be null.
pub fn set_auto(&mut self) {
self.set_valueless_unit(nsCSSUnit::eCSSUnit_Auto);
}
/// Set to a normal value
///
/// This method requires the current value to be null.
pub fn set_normal(&mut self) {
self.set_valueless_unit(nsCSSUnit::eCSSUnit_Normal);
}
fn set_string_internal(&mut self, s: &str, unit: nsCSSUnit) {
unsafe { bindings::Gecko_CSSValue_SetString(self, s.as_ptr(), s.len() as u32, unit) }
}
fn set_string_from_atom_internal(&mut self, s: &Atom, unit: nsCSSUnit) {
unsafe { bindings::Gecko_CSSValue_SetStringFromAtom(self, s.as_ptr(), unit) }
}
/// Set to a string value
pub fn set_string(&mut self, s: &str) {
self.set_string_internal(s, nsCSSUnit::eCSSUnit_String)
}
/// Set to a string value from the given atom
pub fn set_string_from_atom(&mut self, s: &Atom) {
self.set_string_from_atom_internal(s, nsCSSUnit::eCSSUnit_String)
}
/// Set to a ident value from the given atom
pub fn set_ident_from_atom(&mut self, s: &Atom) {
self.set_string_from_atom_internal(s, nsCSSUnit::eCSSUnit_Ident)
}
/// Set to an identifier value
pub fn set_ident(&mut self, s: &str) {
self.set_string_internal(s, nsCSSUnit::eCSSUnit_Ident)
}
/// Set to an atom identifier value
pub fn set_atom_ident(&mut self, s: Atom) {
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) {
unsafe { bindings::Gecko_CSSValue_SetInt(self, value, unit) }
}
/// Set to an integer value
pub fn set_integer(&mut self, value: i32) {
self.set_int_internal(value, nsCSSUnit::eCSSUnit_Integer)
}
/// Set to an enumerated value
pub fn set_enum<T: Into<i32>>(&mut self, value: T) {
self.set_int_internal(value.into(), nsCSSUnit::eCSSUnit_Enumerated);
}
/// Set to a number value
pub fn set_number(&mut self, number: f32) {
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
pub fn set_array(&mut self, len: i32) -> &mut nsCSSValue_Array {
unsafe { bindings::Gecko_CSSValue_SetArray(self, len) }
unsafe { self.mValue.mArray.as_mut().as_mut() }.unwrap()
}
/// Generic set from any value that implements the ToNsCssValue trait.
pub fn set_from<T: ToNsCssValue>(&mut self, value: T) {
value.convert(self)
}
/// Returns an `Angle` value from this `nsCSSValue`.
///
/// Panics if the unit is not `eCSSUnit_Degree` `eCSSUnit_Grad`, `eCSSUnit_Turn`
/// or `eCSSUnit_Radian`.
pub fn get_angle(&self) -> Angle {
Angle::from_gecko_values(self.float_unchecked(), self.mUnit)
}
/// Sets Angle value to this nsCSSValue.
pub fn set_angle(&mut self, angle: Angle) {
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null);
let (value, unit) = angle.to_gecko_values();
self.mUnit = unit;
unsafe {
*self.mValue.mFloat.as_mut() = value;
}
}
/// Set to a pair value
///
/// This is only supported on the main thread.
pub fn set_pair(&mut self, x: &nsCSSValue, y: &nsCSSValue) {
unsafe { bindings::Gecko_CSSValue_SetPair(self, x, y) }
}
/// Set to a list value
///
/// This is only supported on the main thread.
pub fn set_list<I>(&mut self, values: I)
where
I: ExactSizeIterator<Item = nsCSSValue>,
{
debug_assert!(values.len() > 0, "Empty list is not supported");
unsafe {
bindings::Gecko_CSSValue_SetList(self, values.len() as u32);
}
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_List);
let list: &mut structs::nsCSSValueList = &mut unsafe {
self.mValue.mList.as_ref() // &*nsCSSValueList_heap
.as_mut().expect("List pointer should be non-null")
}._base;
for (item, new_value) in list.into_iter().zip(values) {
*item = new_value;
}
}
/// Set to a pair list value
///
/// This is only supported on the main thread.
pub fn set_pair_list<I>(&mut self, mut values: I)
where
I: ExactSizeIterator<Item = (nsCSSValue, nsCSSValue)>,
{
debug_assert!(values.len() > 0, "Empty list is not supported");
unsafe {
bindings::Gecko_CSSValue_SetPairList(self, values.len() as u32);
}
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_PairList);
let mut item_ptr = &mut unsafe {
self.mValue.mPairList.as_ref() // &*nsCSSValuePairList_heap
.as_mut().expect("List pointer should be non-null")
}._base as *mut structs::nsCSSValuePairList;
while let Some(item) = unsafe { item_ptr.as_mut() } {
let value = values.next().expect("Values shouldn't have been exhausted");
item.mXValue = value.0;
item.mYValue = value.1;
item_ptr = item.mNext;
}
debug_assert!(values.next().is_none(), "Values should have been exhausted");
}
/// Set a shared list
pub fn set_shared_list<I>(&mut self, values: I)
where
I: ExactSizeIterator<Item = nsCSSValue>,
{
debug_assert!(values.len() > 0, "Empty list is not supported");
unsafe { bindings::Gecko_CSSValue_InitSharedList(self, values.len() as u32) };
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_SharedList);
let list = unsafe {
self.mValue
.mSharedList
.as_ref()
.as_mut()
.expect("List pointer should be non-null")
.mHead
.as_mut()
};
debug_assert!(list.is_some(), "New created shared list shouldn't be null");
for (item, new_value) in list.unwrap().into_iter().zip(values) {
*item = new_value;
}
}
}
impl Drop for nsCSSValue {
fn drop(&mut self) {
unsafe { bindings::Gecko_CSSValue_Drop(self) };
}
}
/// Iterator of nsCSSValueList.
#[allow(non_camel_case_types)]
pub struct nsCSSValueListIterator<'a> {
current: Option<&'a nsCSSValueList>,
}
impl<'a> Iterator for nsCSSValueListIterator<'a> {
type Item = &'a nsCSSValue;
fn next(&mut self) -> Option<Self::Item> {
match self.current {
Some(item) => {
self.current = unsafe { item.mNext.as_ref() };
Some(&item.mValue)
},
None => None,
}
}
}
impl<'a> IntoIterator for &'a nsCSSValueList {
type Item = &'a nsCSSValue;
type IntoIter = nsCSSValueListIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
nsCSSValueListIterator {
current: Some(self),
}
}
}
/// Mutable Iterator of nsCSSValueList.
#[allow(non_camel_case_types)]
pub struct nsCSSValueListMutIterator<'a> {
current: *mut nsCSSValueList,
phantom: PhantomData<&'a mut nsCSSValue>,
}
impl<'a> Iterator for nsCSSValueListMutIterator<'a> {
type Item = &'a mut nsCSSValue;
fn next(&mut self) -> Option<Self::Item> {
match unsafe { self.current.as_mut() } {
Some(item) => {
self.current = item.mNext;
Some(&mut item.mValue)
},
None => None,
}
}
}
impl<'a> IntoIterator for &'a mut nsCSSValueList {
type Item = &'a mut nsCSSValue;
type IntoIter = nsCSSValueListMutIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
nsCSSValueListMutIterator {
current: self as *mut nsCSSValueList,
phantom: PhantomData,
}
}
}
impl nsCSSValue_Array {
/// Return the length of this `nsCSSValue::Array`
#[inline]
pub fn len(&self) -> usize {
self.mCount
}
#[inline]
fn buffer(&self) -> *const nsCSSValue {
self.mArray.as_ptr()
}
/// Get the array as a slice of nsCSSValues.
#[inline]
pub fn as_slice(&self) -> &[nsCSSValue] {
unsafe { slice::from_raw_parts(self.buffer(), self.len()) }
}
/// Get the array as a mutable slice of nsCSSValues.
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [nsCSSValue] {
unsafe { slice::from_raw_parts_mut(self.buffer() as *mut _, self.len()) }
}
}
impl Index<usize> for nsCSSValue_Array {
type Output = nsCSSValue;
#[inline]
fn index(&self, i: usize) -> &nsCSSValue {
&self.as_slice()[i]
}
}
impl IndexMut<usize> for nsCSSValue_Array {
#[inline]
fn index_mut(&mut self, i: usize) -> &mut nsCSSValue {
&mut self.as_mut_slice()[i]
}
}
/// Generic conversion to nsCSSValue
pub trait ToNsCssValue {
/// Convert
fn convert(self, nscssvalue: &mut nsCSSValue);
}
impl<T: ToNsCssValue> From<T> for nsCSSValue {
fn from(value: T) -> nsCSSValue {
let mut result = nsCSSValue::null();
value.convert(&mut result);
result
}
}