1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 //! CSS handling for the computed value of
6 //! [`image`][image]s
7 //!
8 //! [image]: https://drafts.csswg.org/css-images/#image-values
9 
10 use cssparser::RGBA;
11 use std::f32::consts::PI;
12 use std::fmt::{self, Write};
13 use style_traits::{CssWriter, ToCss};
14 use values::{Either, None_};
15 use values::computed::{Angle, ComputedImageUrl, Context};
16 use values::computed::{Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue};
17 #[cfg(feature = "gecko")]
18 use values::computed::Percentage;
19 use values::computed::position::Position;
20 use values::generics::image::{CompatMode, ColorStop as GenericColorStop, EndingShape as GenericEndingShape};
21 use values::generics::image::{Gradient as GenericGradient, GradientItem as GenericGradientItem};
22 use values::generics::image::{Image as GenericImage, GradientKind as GenericGradientKind};
23 use values::generics::image::{LineDirection as GenericLineDirection, MozImageRect as GenericMozImageRect};
24 use values::specified::image::LineDirection as SpecifiedLineDirection;
25 use values::specified::position::{X, Y};
26 
27 /// A computed image layer.
28 pub type ImageLayer = Either<None_, Image>;
29 
30 /// Computed values for an image according to CSS-IMAGES.
31 /// <https://drafts.csswg.org/css-images/#image-values>
32 pub type Image = GenericImage<Gradient, MozImageRect, ComputedImageUrl>;
33 
34 /// Computed values for a CSS gradient.
35 /// <https://drafts.csswg.org/css-images/#gradients>
36 pub type Gradient = GenericGradient<
37     LineDirection,
38     Length,
39     LengthOrPercentage,
40     Position,
41     RGBA,
42     Angle,
43 >;
44 
45 /// A computed gradient kind.
46 pub type GradientKind = GenericGradientKind<
47     LineDirection,
48     Length,
49     LengthOrPercentage,
50     Position,
51     Angle,
52 >;
53 
54 /// A computed gradient line direction.
55 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
56 pub enum LineDirection {
57     /// An angle.
58     Angle(Angle),
59     /// A horizontal direction.
60     Horizontal(X),
61     /// A vertical direction.
62     Vertical(Y),
63     /// A corner.
64     Corner(X, Y),
65     /// A Position and an Angle for legacy `-moz-` prefixed gradient.
66     #[cfg(feature = "gecko")]
67     MozPosition(Option<Position>, Option<Angle>),
68 }
69 
70 /// A computed radial gradient ending shape.
71 pub type EndingShape = GenericEndingShape<Length, LengthOrPercentage>;
72 
73 /// A computed gradient item.
74 pub type GradientItem = GenericGradientItem<RGBA, LengthOrPercentage>;
75 
76 /// A computed color stop.
77 pub type ColorStop = GenericColorStop<RGBA, LengthOrPercentage>;
78 
79 /// Computed values for `-moz-image-rect(...)`.
80 pub type MozImageRect = GenericMozImageRect<NumberOrPercentage, ComputedImageUrl>;
81 
82 impl GenericLineDirection for LineDirection {
points_downwards(&self, compat_mode: CompatMode) -> bool83     fn points_downwards(&self, compat_mode: CompatMode) -> bool {
84         match *self {
85             LineDirection::Angle(angle) => angle.radians() == PI,
86             LineDirection::Vertical(Y::Bottom)
87                 if compat_mode == CompatMode::Modern => true,
88             LineDirection::Vertical(Y::Top)
89                 if compat_mode != CompatMode::Modern => true,
90             LineDirection::Corner(..) => false,
91             #[cfg(feature = "gecko")]
92             LineDirection::MozPosition(Some(Position {
93                 horizontal: LengthOrPercentage::Percentage(Percentage(x)),
94                 vertical: LengthOrPercentage::Percentage(Percentage(y)),
95             }), None) => {
96                 // `50% 0%` is the default value for line direction.
97                 x == 0.5 && y == 0.0
98             },
99             _ => false,
100         }
101     }
102 
to_css<W>( &self, dest: &mut CssWriter<W>, compat_mode: CompatMode, ) -> fmt::Result where W: Write,103     fn to_css<W>(
104         &self,
105         dest: &mut CssWriter<W>,
106         compat_mode: CompatMode,
107     ) -> fmt::Result
108     where
109         W: Write,
110     {
111         match *self {
112             LineDirection::Angle(ref angle) => angle.to_css(dest),
113             LineDirection::Horizontal(x) => {
114                 if compat_mode == CompatMode::Modern {
115                     dest.write_str("to ")?;
116                 }
117                 x.to_css(dest)
118             },
119             LineDirection::Vertical(y) => {
120                 if compat_mode == CompatMode::Modern {
121                     dest.write_str("to ")?;
122                 }
123                 y.to_css(dest)
124             },
125             LineDirection::Corner(x, y) => {
126                 if compat_mode == CompatMode::Modern {
127                     dest.write_str("to ")?;
128                 }
129                 x.to_css(dest)?;
130                 dest.write_str(" ")?;
131                 y.to_css(dest)
132             },
133             #[cfg(feature = "gecko")]
134             LineDirection::MozPosition(position, angle) => {
135                 let mut need_space = false;
136                 if let Some(position) = position {
137                     position.to_css(dest)?;
138                     need_space = true;
139                 }
140                 if let Some(angle) = angle {
141                     if need_space {
142                         dest.write_str(" ")?;
143                     }
144                     angle.to_css(dest)?;
145                 }
146                 Ok(())
147             }
148         }
149     }
150 }
151 
152 impl ToComputedValue for SpecifiedLineDirection {
153     type ComputedValue = LineDirection;
154 
to_computed_value(&self, context: &Context) -> Self::ComputedValue155     fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
156         match *self {
157             SpecifiedLineDirection::Angle(ref angle) => {
158                 LineDirection::Angle(angle.to_computed_value(context))
159             },
160             SpecifiedLineDirection::Horizontal(x) => {
161                 LineDirection::Horizontal(x)
162             },
163             SpecifiedLineDirection::Vertical(y) => {
164                 LineDirection::Vertical(y)
165             },
166             SpecifiedLineDirection::Corner(x, y) => {
167                 LineDirection::Corner(x, y)
168             },
169             #[cfg(feature = "gecko")]
170             SpecifiedLineDirection::MozPosition(ref position, ref angle) => {
171                 LineDirection::MozPosition(position.to_computed_value(context),
172                                            angle.to_computed_value(context))
173             },
174         }
175     }
176 
from_computed_value(computed: &Self::ComputedValue) -> Self177     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
178         match *computed {
179             LineDirection::Angle(ref angle) => {
180                 SpecifiedLineDirection::Angle(ToComputedValue::from_computed_value(angle))
181             },
182             LineDirection::Horizontal(x) => {
183                 SpecifiedLineDirection::Horizontal(x)
184             },
185             LineDirection::Vertical(y) => {
186                 SpecifiedLineDirection::Vertical(y)
187             },
188             LineDirection::Corner(x, y) => {
189                 SpecifiedLineDirection::Corner(x, y)
190             },
191             #[cfg(feature = "gecko")]
192             LineDirection::MozPosition(ref position, ref angle) => {
193                 SpecifiedLineDirection::MozPosition(ToComputedValue::from_computed_value(position),
194                                                     ToComputedValue::from_computed_value(angle))
195             },
196         }
197     }
198 }
199