origin.rs (7020B)
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 https://mozilla.org/MPL/2.0/. */ 4 5 //! [CSS cascade origins](https://drafts.csswg.org/css-cascade/#cascading-origins). 6 7 use crate::derives::*; 8 use std::marker::PhantomData; 9 use std::ops::BitOrAssign; 10 11 /// Each style rule has an origin, which determines where it enters the cascade. 12 /// 13 /// <https://drafts.csswg.org/css-cascade/#cascading-origins> 14 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem, PartialOrd, Ord)] 15 #[repr(u8)] 16 pub enum Origin { 17 /// <https://drafts.csswg.org/css-cascade/#cascade-origin-user-agent> 18 UserAgent = 0x1, 19 20 /// <https://drafts.csswg.org/css-cascade/#cascade-origin-user> 21 User = 0x2, 22 23 /// <https://drafts.csswg.org/css-cascade/#cascade-origin-author> 24 Author = 0x4, 25 } 26 27 impl Origin { 28 /// Returns an origin that goes in order for `index`. 29 /// 30 /// This is used for iterating across origins. 31 fn from_index(index: i8) -> Option<Self> { 32 Some(match index { 33 0 => Origin::Author, 34 1 => Origin::User, 35 2 => Origin::UserAgent, 36 _ => return None, 37 }) 38 } 39 40 fn to_index(self) -> i8 { 41 match self { 42 Origin::Author => 0, 43 Origin::User => 1, 44 Origin::UserAgent => 2, 45 } 46 } 47 48 /// Returns an iterator from this origin, towards all the less specific 49 /// origins. So for `UserAgent`, it'd iterate through all origins. 50 #[inline] 51 pub fn following_including(self) -> OriginSetIterator { 52 OriginSetIterator { 53 set: OriginSet::ORIGIN_USER | OriginSet::ORIGIN_AUTHOR | OriginSet::ORIGIN_USER_AGENT, 54 cur: self.to_index(), 55 rev: true, 56 } 57 } 58 } 59 60 /// A set of origins. This is equivalent to Gecko's OriginFlags. 61 #[derive(Clone, Copy, PartialEq, MallocSizeOf)] 62 pub struct OriginSet(u8); 63 bitflags! { 64 impl OriginSet: u8 { 65 /// <https://drafts.csswg.org/css-cascade/#cascade-origin-user-agent> 66 const ORIGIN_USER_AGENT = Origin::UserAgent as u8; 67 /// <https://drafts.csswg.org/css-cascade/#cascade-origin-user> 68 const ORIGIN_USER = Origin::User as u8; 69 /// <https://drafts.csswg.org/css-cascade/#cascade-origin-author> 70 const ORIGIN_AUTHOR = Origin::Author as u8; 71 } 72 } 73 74 impl OriginSet { 75 /// Returns an iterator over the origins present in this `OriginSet`. 76 /// 77 /// See the `OriginSet` documentation for information about the order 78 /// origins are iterated. 79 pub fn iter_origins(&self) -> OriginSetIterator { 80 OriginSetIterator { 81 set: *self, 82 cur: 0, 83 rev: false, 84 } 85 } 86 } 87 88 impl From<Origin> for OriginSet { 89 fn from(origin: Origin) -> Self { 90 Self::from_bits_retain(origin as u8) 91 } 92 } 93 94 impl BitOrAssign<Origin> for OriginSet { 95 fn bitor_assign(&mut self, origin: Origin) { 96 *self |= OriginSet::from(origin); 97 } 98 } 99 100 /// Iterates over the origins present in an `OriginSet`, in order from 101 /// highest priority (author) to lower (user agent). 102 #[derive(Clone)] 103 pub struct OriginSetIterator { 104 set: OriginSet, 105 cur: i8, 106 rev: bool, 107 } 108 109 impl Iterator for OriginSetIterator { 110 type Item = Origin; 111 112 fn next(&mut self) -> Option<Origin> { 113 loop { 114 let origin = Origin::from_index(self.cur)?; 115 116 if self.rev { 117 self.cur -= 1; 118 } else { 119 self.cur += 1; 120 } 121 122 if self.set.contains(origin.into()) { 123 return Some(origin); 124 } 125 } 126 } 127 } 128 129 /// An object that stores a `T` for each origin of the CSS cascade. 130 #[derive(Debug, Default, MallocSizeOf)] 131 pub struct PerOrigin<T> { 132 /// Data for `Origin::UserAgent`. 133 pub user_agent: T, 134 135 /// Data for `Origin::User`. 136 pub user: T, 137 138 /// Data for `Origin::Author`. 139 pub author: T, 140 } 141 142 impl<T> PerOrigin<T> { 143 /// Returns a reference to the per-origin data for the specified origin. 144 #[inline] 145 pub fn borrow_for_origin(&self, origin: &Origin) -> &T { 146 match *origin { 147 Origin::UserAgent => &self.user_agent, 148 Origin::User => &self.user, 149 Origin::Author => &self.author, 150 } 151 } 152 153 /// Returns a mutable reference to the per-origin data for the specified 154 /// origin. 155 #[inline] 156 pub fn borrow_mut_for_origin(&mut self, origin: &Origin) -> &mut T { 157 match *origin { 158 Origin::UserAgent => &mut self.user_agent, 159 Origin::User => &mut self.user, 160 Origin::Author => &mut self.author, 161 } 162 } 163 164 /// Iterates over references to per-origin extra style data, from highest 165 /// level (author) to lowest (user agent). 166 pub fn iter_origins(&self) -> PerOriginIter<'_, T> { 167 PerOriginIter { 168 data: &self, 169 cur: 0, 170 rev: false, 171 } 172 } 173 174 /// Iterates over references to per-origin extra style data, from lowest 175 /// level (user agent) to highest (author). 176 pub fn iter_origins_rev(&self) -> PerOriginIter<'_, T> { 177 PerOriginIter { 178 data: &self, 179 cur: 2, 180 rev: true, 181 } 182 } 183 184 /// Iterates over mutable references to per-origin extra style data, from 185 /// highest level (author) to lowest (user agent). 186 pub fn iter_mut_origins(&mut self) -> PerOriginIterMut<'_, T> { 187 PerOriginIterMut { 188 data: self, 189 cur: 0, 190 _marker: PhantomData, 191 } 192 } 193 } 194 195 /// Iterator over `PerOrigin<T>`, from highest level (author) to lowest 196 /// (user agent). 197 /// 198 /// We rely on this specific order for correctly looking up @font-face, 199 /// @counter-style and @keyframes rules. 200 pub struct PerOriginIter<'a, T: 'a> { 201 data: &'a PerOrigin<T>, 202 cur: i8, 203 rev: bool, 204 } 205 206 impl<'a, T> Iterator for PerOriginIter<'a, T> 207 where 208 T: 'a, 209 { 210 type Item = (&'a T, Origin); 211 212 fn next(&mut self) -> Option<Self::Item> { 213 let origin = Origin::from_index(self.cur)?; 214 215 self.cur += if self.rev { -1 } else { 1 }; 216 217 Some((self.data.borrow_for_origin(&origin), origin)) 218 } 219 } 220 221 /// Like `PerOriginIter<T>`, but iterates over mutable references to the 222 /// per-origin data. 223 /// 224 /// We must use unsafe code here since it's not possible for the borrow 225 /// checker to know that we are safely returning a different reference 226 /// each time from `next()`. 227 pub struct PerOriginIterMut<'a, T: 'a> { 228 data: *mut PerOrigin<T>, 229 cur: i8, 230 _marker: PhantomData<&'a mut PerOrigin<T>>, 231 } 232 233 impl<'a, T> Iterator for PerOriginIterMut<'a, T> 234 where 235 T: 'a, 236 { 237 type Item = (&'a mut T, Origin); 238 239 fn next(&mut self) -> Option<Self::Item> { 240 let origin = Origin::from_index(self.cur)?; 241 242 self.cur += 1; 243 244 Some(( 245 unsafe { (*self.data).borrow_mut_for_origin(&origin) }, 246 origin, 247 )) 248 } 249 }