<!-- Please describe your changes on the following line: --> This fixes bugzilla bug [1403170](https://bugzilla.mozilla.org/show_bug.cgi?id=1403170). We've missed a few updates of the nsstring bindings in servo compared to the changes in gecko, so we really ought to find a better solution than these manual updates. For example, recently the way flags in nsstring are implemented was completely redone, and this version wasn't updated. It happened to be that the representation of the new form was identical to the old one, so it wasn't a problem, but technically this was wrong. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build-geckolib` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix bugzilla bug [1403170](https://bugzilla.mozilla.org/show_bug.cgi?id=1403170) <!-- Either: --> - [ ] There are tests for these changes OR - [x] These changes do not require tests because they are a dependency version bump. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: e68509b2e37983179a33c9f8cf4ad41c8a85d9a9
512 lines
20 KiB
Rust
512 lines
20 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/. */
|
|
|
|
#![allow(unsafe_code)]
|
|
|
|
//! Different kind of helpers to interact with Gecko values.
|
|
|
|
use Atom;
|
|
use app_units::Au;
|
|
use counter_style::{Symbol, Symbols};
|
|
use cssparser::RGBA;
|
|
use gecko_bindings::structs::{CounterStylePtr, nsStyleCoord};
|
|
use gecko_bindings::structs::{StyleGridTrackBreadth, StyleShapeRadius};
|
|
use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
|
|
use media_queries::Device;
|
|
use nsstring::{nsACString, nsCStr};
|
|
use std::cmp::max;
|
|
use values::{Auto, Either, ExtremumLength, None_, Normal};
|
|
use values::computed::{Angle, Length, LengthOrPercentage, LengthOrPercentageOrAuto};
|
|
use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
|
|
use values::computed::{MaxLength, MozLength, Percentage};
|
|
use values::computed::{NonNegativeLength, NonNegativeLengthOrPercentage, NonNegativeNumber};
|
|
use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
|
|
use values::generics::{CounterStyleOrNone, NonNegative};
|
|
use values::generics::basic_shape::ShapeRadius;
|
|
use values::generics::gecko::ScrollSnapPoint;
|
|
use values::generics::grid::{TrackBreadth, TrackKeyword};
|
|
|
|
/// A trait that defines an interface to convert from and to `nsStyleCoord`s.
|
|
pub trait GeckoStyleCoordConvertible : Sized {
|
|
/// Convert this to a `nsStyleCoord`.
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T);
|
|
/// Given a `nsStyleCoord`, try to get a value of this type..
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self>;
|
|
}
|
|
|
|
impl nsStyleCoord {
|
|
#[inline]
|
|
/// Set this `nsStyleCoord` value to `val`.
|
|
pub fn set<T: GeckoStyleCoordConvertible>(&mut self, val: T) {
|
|
val.to_gecko_style_coord(self);
|
|
}
|
|
}
|
|
|
|
impl<A: GeckoStyleCoordConvertible, B: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for Either<A, B> {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
match *self {
|
|
Either::First(ref v) => v.to_gecko_style_coord(coord),
|
|
Either::Second(ref v) => v.to_gecko_style_coord(coord),
|
|
}
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
A::from_gecko_style_coord(coord)
|
|
.map(Either::First)
|
|
.or_else(|| B::from_gecko_style_coord(coord).map(Either::Second))
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for Number {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
coord.set_value(CoordDataValue::Factor(*self));
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
match coord.as_value() {
|
|
CoordDataValue::Factor(f) => Some(f),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for Percentage {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
coord.set_value(CoordDataValue::Percent(self.0));
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
match coord.as_value() {
|
|
CoordDataValue::Percent(p) => Some(Percentage(p)),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for NumberOrPercentage {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
match *self {
|
|
NumberOrPercentage::Number(ref n) => n.to_gecko_style_coord(coord),
|
|
NumberOrPercentage::Percentage(ref p) => p.to_gecko_style_coord(coord),
|
|
}
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
match coord.as_value() {
|
|
CoordDataValue::Factor(f) => Some(NumberOrPercentage::Number(f)),
|
|
CoordDataValue::Percent(p) => {
|
|
Some(NumberOrPercentage::Percentage(Percentage(p)))
|
|
},
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for LengthOrPercentage {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
let value = match *self {
|
|
LengthOrPercentage::Length(px) => CoordDataValue::Coord(px.to_i32_au()),
|
|
LengthOrPercentage::Percentage(p) => CoordDataValue::Percent(p.0),
|
|
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).into())),
|
|
CoordDataValue::Percent(p) => Some(LengthOrPercentage::Percentage(Percentage(p))),
|
|
CoordDataValue::Calc(calc) => Some(LengthOrPercentage::Calc(calc.into())),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for NonNegativeLengthOrPercentage {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
self.0.to_gecko_style_coord(coord);
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
LengthOrPercentage::from_gecko_style_coord(coord).map(NonNegative::<LengthOrPercentage>)
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for Length {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
coord.set_value(CoordDataValue::Coord(self.to_i32_au()));
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
match coord.as_value() {
|
|
CoordDataValue::Coord(coord) => Some(Au(coord).into()),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for NonNegativeLength {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
self.0.to_gecko_style_coord(coord);
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
Length::from_gecko_style_coord(coord).map(NonNegative::<Length>)
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for NonNegativeNumber {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
self.0.to_gecko_style_coord(coord);
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
Number::from_gecko_style_coord(coord).map(NonNegative::<Number>)
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
let value = match *self {
|
|
LengthOrPercentageOrAuto::Length(px) => CoordDataValue::Coord(px.to_i32_au()),
|
|
LengthOrPercentageOrAuto::Percentage(p) => CoordDataValue::Percent(p.0),
|
|
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).into())),
|
|
CoordDataValue::Percent(p) => Some(LengthOrPercentageOrAuto::Percentage(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(px) => CoordDataValue::Coord(px.to_i32_au()),
|
|
LengthOrPercentageOrNone::Percentage(p) => CoordDataValue::Percent(p.0),
|
|
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).into())),
|
|
CoordDataValue::Percent(p) => Some(LengthOrPercentageOrNone::Percentage(Percentage(p))),
|
|
CoordDataValue::None => Some(LengthOrPercentageOrNone::None),
|
|
CoordDataValue::Calc(calc) => Some(LengthOrPercentageOrNone::Calc(calc.into())),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<L: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for TrackBreadth<L> {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
match *self {
|
|
TrackBreadth::Breadth(ref lop) => lop.to_gecko_style_coord(coord),
|
|
TrackBreadth::Flex(fr) => coord.set_value(CoordDataValue::FlexFraction(fr)),
|
|
TrackBreadth::Keyword(TrackKeyword::Auto) => coord.set_value(CoordDataValue::Auto),
|
|
TrackBreadth::Keyword(TrackKeyword::MinContent) =>
|
|
coord.set_value(CoordDataValue::Enumerated(StyleGridTrackBreadth::MinContent as u32)),
|
|
TrackBreadth::Keyword(TrackKeyword::MaxContent) =>
|
|
coord.set_value(CoordDataValue::Enumerated(StyleGridTrackBreadth::MaxContent as u32)),
|
|
}
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
L::from_gecko_style_coord(coord).map(TrackBreadth::Breadth).or_else(|| {
|
|
match coord.as_value() {
|
|
CoordDataValue::Enumerated(v) => {
|
|
if v == StyleGridTrackBreadth::MinContent as u32 {
|
|
Some(TrackBreadth::Keyword(TrackKeyword::MinContent))
|
|
} else if v == StyleGridTrackBreadth::MaxContent as u32 {
|
|
Some(TrackBreadth::Keyword(TrackKeyword::MaxContent))
|
|
} else {
|
|
None
|
|
}
|
|
},
|
|
CoordDataValue::FlexFraction(fr) => Some(TrackBreadth::Flex(fr)),
|
|
CoordDataValue::Auto => Some(TrackBreadth::Keyword(TrackKeyword::Auto)),
|
|
_ => L::from_gecko_style_coord(coord).map(TrackBreadth::Breadth),
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for ComputedShapeRadius {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
match *self {
|
|
ShapeRadius::ClosestSide =>
|
|
coord.set_value(CoordDataValue::Enumerated(StyleShapeRadius::ClosestSide as u32)),
|
|
ShapeRadius::FarthestSide =>
|
|
coord.set_value(CoordDataValue::Enumerated(StyleShapeRadius::FarthestSide as u32)),
|
|
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(v) => {
|
|
if v == StyleShapeRadius::ClosestSide as u32 {
|
|
Some(ShapeRadius::ClosestSide)
|
|
} else if v == StyleShapeRadius::FarthestSide as u32 {
|
|
Some(ShapeRadius::FarthestSide)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
_ => 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::from(*self));
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
match coord.as_value() {
|
|
CoordDataValue::Degree(val) => Some(Angle::Degree(val)),
|
|
CoordDataValue::Grad(val) => Some(Angle::Gradian(val)),
|
|
CoordDataValue::Radian(val) => Some(Angle::Radian(val)),
|
|
CoordDataValue::Turn(val) => Some(Angle::Turn(val)),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for Auto {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
coord.set_value(CoordDataValue::Auto)
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
if let CoordDataValue::Auto = coord.as_value() {
|
|
Some(Auto)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for None_ {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
coord.set_value(CoordDataValue::None)
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
if let CoordDataValue::None = coord.as_value() {
|
|
Some(None_)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for Normal {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
coord.set_value(CoordDataValue::Normal)
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
if let CoordDataValue::Normal = coord.as_value() {
|
|
Some(Normal)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for ExtremumLength {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
use gecko_bindings::structs::{NS_STYLE_WIDTH_AVAILABLE, NS_STYLE_WIDTH_FIT_CONTENT};
|
|
use gecko_bindings::structs::{NS_STYLE_WIDTH_MAX_CONTENT, NS_STYLE_WIDTH_MIN_CONTENT};
|
|
coord.set_value(CoordDataValue::Enumerated(
|
|
match *self {
|
|
ExtremumLength::MaxContent => NS_STYLE_WIDTH_MAX_CONTENT,
|
|
ExtremumLength::MinContent => NS_STYLE_WIDTH_MIN_CONTENT,
|
|
ExtremumLength::FitContent => NS_STYLE_WIDTH_FIT_CONTENT,
|
|
ExtremumLength::FillAvailable => NS_STYLE_WIDTH_AVAILABLE,
|
|
}
|
|
))
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
use gecko_bindings::structs::{NS_STYLE_WIDTH_AVAILABLE, NS_STYLE_WIDTH_FIT_CONTENT};
|
|
use gecko_bindings::structs::{NS_STYLE_WIDTH_MAX_CONTENT, NS_STYLE_WIDTH_MIN_CONTENT};
|
|
match coord.as_value() {
|
|
CoordDataValue::Enumerated(NS_STYLE_WIDTH_MAX_CONTENT) =>
|
|
Some(ExtremumLength::MaxContent),
|
|
CoordDataValue::Enumerated(NS_STYLE_WIDTH_MIN_CONTENT) =>
|
|
Some(ExtremumLength::MinContent),
|
|
CoordDataValue::Enumerated(NS_STYLE_WIDTH_FIT_CONTENT) =>
|
|
Some(ExtremumLength::FitContent),
|
|
CoordDataValue::Enumerated(NS_STYLE_WIDTH_AVAILABLE) => Some(ExtremumLength::FillAvailable),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for MozLength {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
match *self {
|
|
MozLength::LengthOrPercentageOrAuto(ref lopoa) => lopoa.to_gecko_style_coord(coord),
|
|
MozLength::ExtremumLength(ref e) => e.to_gecko_style_coord(coord),
|
|
}
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
LengthOrPercentageOrAuto::from_gecko_style_coord(coord).map(MozLength::LengthOrPercentageOrAuto)
|
|
.or_else(|| ExtremumLength::from_gecko_style_coord(coord).map(MozLength::ExtremumLength))
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for MaxLength {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
match *self {
|
|
MaxLength::LengthOrPercentageOrNone(ref lopon) => lopon.to_gecko_style_coord(coord),
|
|
MaxLength::ExtremumLength(ref e) => e.to_gecko_style_coord(coord),
|
|
}
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
LengthOrPercentageOrNone::from_gecko_style_coord(coord).map(MaxLength::LengthOrPercentageOrNone)
|
|
.or_else(|| ExtremumLength::from_gecko_style_coord(coord).map(MaxLength::ExtremumLength))
|
|
}
|
|
}
|
|
|
|
impl GeckoStyleCoordConvertible for ScrollSnapPoint<LengthOrPercentage> {
|
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
|
match self.repeated() {
|
|
None => coord.set_value(CoordDataValue::None),
|
|
Some(l) => l.to_gecko_style_coord(coord),
|
|
};
|
|
}
|
|
|
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
|
use gecko_bindings::structs::root::nsStyleUnit;
|
|
use values::generics::gecko::ScrollSnapPoint;
|
|
|
|
Some(
|
|
match coord.unit() {
|
|
nsStyleUnit::eStyleUnit_None => ScrollSnapPoint::None,
|
|
_ => ScrollSnapPoint::Repeat(LengthOrPercentage::from_gecko_style_coord(coord)
|
|
.expect("coord could not convert to LengthOrPercentage")),
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
/// Convert a given RGBA value to `nscolor`.
|
|
pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 {
|
|
((rgba.alpha as u32) << 24) |
|
|
((rgba.blue as u32) << 16) |
|
|
((rgba.green as u32) << 8) |
|
|
(rgba.red as u32)
|
|
}
|
|
|
|
/// Convert a given `nscolor` to a Servo RGBA value.
|
|
pub fn convert_nscolor_to_rgba(color: u32) -> RGBA {
|
|
RGBA::new((color & 0xff) as u8,
|
|
(color >> 8 & 0xff) as u8,
|
|
(color >> 16 & 0xff) as u8,
|
|
(color >> 24 & 0xff) as u8)
|
|
}
|
|
|
|
/// 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.
|
|
#[inline]
|
|
pub fn round_border_to_device_pixels(width: Au, au_per_device_px: Au) -> Au {
|
|
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))
|
|
}
|
|
}
|
|
|
|
impl CounterStyleOrNone {
|
|
/// Convert this counter style to a Gecko CounterStylePtr.
|
|
pub fn to_gecko_value(self, gecko_value: &mut CounterStylePtr, device: &Device) {
|
|
use gecko_bindings::bindings::Gecko_SetCounterStyleToName as set_name;
|
|
use gecko_bindings::bindings::Gecko_SetCounterStyleToSymbols as set_symbols;
|
|
let pres_context = device.pres_context();
|
|
match self {
|
|
CounterStyleOrNone::None => unsafe {
|
|
set_name(gecko_value, atom!("none").into_addrefed(), pres_context);
|
|
},
|
|
CounterStyleOrNone::Name(name) => unsafe {
|
|
set_name(gecko_value, name.0.into_addrefed(), pres_context);
|
|
},
|
|
CounterStyleOrNone::Symbols(symbols_type, symbols) => {
|
|
let symbols: Vec<_> = symbols.0.iter().map(|symbol| match *symbol {
|
|
Symbol::String(ref s) => nsCStr::from(s),
|
|
Symbol::Ident(_) => unreachable!("Should not have identifier in symbols()"),
|
|
}).collect();
|
|
let symbols: Vec<_> = symbols.iter()
|
|
.map(|symbol| symbol as &nsACString as *const _)
|
|
.collect();
|
|
unsafe { set_symbols(gecko_value, symbols_type.to_gecko_keyword(),
|
|
symbols.as_ptr(), symbols.len() as u32) };
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Convert Gecko CounterStylePtr to CounterStyleOrNone or String.
|
|
pub fn from_gecko_value(gecko_value: &CounterStylePtr) -> Either<Self, String> {
|
|
use gecko_bindings::bindings;
|
|
use values::CustomIdent;
|
|
use values::generics::SymbolsType;
|
|
|
|
let name = unsafe { bindings::Gecko_CounterStyle_GetName(gecko_value) };
|
|
if !name.is_null() {
|
|
let name = Atom::from(name);
|
|
if name == atom!("none") {
|
|
Either::First(CounterStyleOrNone::None)
|
|
} else {
|
|
Either::First(CounterStyleOrNone::Name(CustomIdent(name)))
|
|
}
|
|
} else {
|
|
let anonymous = unsafe {
|
|
bindings::Gecko_CounterStyle_GetAnonymous(gecko_value).as_ref()
|
|
}.unwrap();
|
|
let symbols = &anonymous.mSymbols;
|
|
if anonymous.mSingleString {
|
|
debug_assert_eq!(symbols.len(), 1);
|
|
Either::Second(symbols[0].to_string())
|
|
} else {
|
|
let symbol_type = SymbolsType::from_gecko_keyword(anonymous.mSystem as u32);
|
|
let symbols = symbols.iter().map(|gecko_symbol| {
|
|
Symbol::String(gecko_symbol.to_string())
|
|
}).collect();
|
|
Either::First(CounterStyleOrNone::Symbols(symbol_type, Symbols(symbols)))
|
|
}
|
|
}
|
|
}
|
|
}
|