margin_rule.rs (7195B)
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 //! A [`@margin`][margin] rule. 6 //! 7 //! [margin]: https://drafts.csswg.org/css-page-3/#margin-boxes 8 9 use crate::derives::*; 10 use crate::properties::PropertyDeclarationBlock; 11 use crate::shared_lock::{DeepCloneWithLock, Locked}; 12 use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; 13 use cssparser::{match_ignore_ascii_case, SourceLocation}; 14 #[cfg(feature = "gecko")] 15 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalShallowSizeOf}; 16 use servo_arc::Arc; 17 use std::fmt::{self, Write}; 18 use style_traits::CssStringWriter; 19 20 macro_rules! margin_rule_types { 21 ($($(#[$($meta:tt)+])* $id:ident => $val:literal,)+) => { 22 /// [`@margin`][margin] rule names. 23 /// 24 /// https://drafts.csswg.org/css-page-3/#margin-at-rules 25 #[derive(Clone, Copy, Eq, MallocSizeOf, PartialEq, ToShmem)] 26 #[repr(u8)] 27 pub enum MarginRuleType { 28 $($(#[$($meta)+])* $id,)+ 29 } 30 31 /// All [`@margin`][margin] rule names, with a preceding '@'. 32 /// 33 /// This array lets us have just one single memory region used for 34 /// to_str, name, and the Debug implementation. 35 const MARGIN_RULE_AT_NAMES:&[&'static str] = &[ 36 $( concat!('@', $val), )+ 37 ]; 38 39 impl MarginRuleType { 40 /// Matches the rule type for this name. This does not expect a 41 /// leading '@'. 42 pub fn match_name(name: &str) -> Option<Self> { 43 Some(match_ignore_ascii_case! { name, 44 $( $val => MarginRuleType::$id, )+ 45 _ => return None, 46 }) 47 } 48 } 49 } 50 } 51 52 margin_rule_types! { 53 /// [`@top-left-corner`][top-left-corner] margin rule 54 /// 55 /// [top-left-corner] https://drafts.csswg.org/css-page-3/#top-left-corner-box-def 56 TopLeftCorner => "top-left-corner", 57 /// [`@top-left`][top-left] margin rule 58 /// 59 /// [top-left] https://drafts.csswg.org/css-page-3/#top-left-box-def 60 TopLeft => "top-left", 61 /// [`@top-center`][top-center] margin rule 62 /// 63 /// [top-center] https://drafts.csswg.org/css-page-3/#top-center-box-def 64 TopCenter => "top-center", 65 /// [`@top-right`][top-right] margin rule 66 /// 67 /// [top-right] https://drafts.csswg.org/css-page-3/#top-right-box-def 68 TopRight => "top-right", 69 /// [`@top-right-corner`][top-right-corner] margin rule 70 /// 71 /// [top-right-corner] https://drafts.csswg.org/css-page-3/#top-right-corner-box-def 72 TopRightCorner => "top-right-corner", 73 /// [`@bottom-left-corner`][bottom-left-corner] margin rule 74 /// 75 /// [bottom-left-corner] https://drafts.csswg.org/css-page-3/#bottom-left-corner-box-def 76 BottomLeftCorner => "bottom-left-corner", 77 /// [`@bottom-left`][bottom-left] margin rule 78 /// 79 /// [bottom-left] https://drafts.csswg.org/css-page-3/#bottom-left-box-def 80 BottomLeft => "bottom-left", 81 /// [`@bottom-center`][bottom-center] margin rule 82 /// 83 /// [bottom-center] https://drafts.csswg.org/css-page-3/#bottom-center-box-def 84 BottomCenter => "bottom-center", 85 /// [`@bottom-right`][bottom-right] margin rule 86 /// 87 /// [bottom-right] https://drafts.csswg.org/css-page-3/#bottom-right-box-def 88 BottomRight => "bottom-right", 89 /// [`@bottom-right-corner`][bottom-right-corner] margin rule 90 /// 91 /// [bottom-right-corner] https://drafts.csswg.org/css-page-3/#bottom-right-corner-box-def 92 BottomRightCorner => "bottom-right-corner", 93 /// [`@left-top`][left-top] margin rule 94 /// 95 /// [left-top] https://drafts.csswg.org/css-page-3/#left-top-box-def 96 LeftTop => "left-top", 97 /// [`@left-middle`][left-middle] margin rule 98 /// 99 /// [left-middle] https://drafts.csswg.org/css-page-3/#left-middle-box-def 100 LeftMiddle => "left-middle", 101 /// [`@left-bottom`][left-bottom] margin rule 102 /// 103 /// [left-bottom] https://drafts.csswg.org/css-page-3/#left-bottom-box-def 104 LeftBottom => "left-bottom", 105 /// [`@right-top`][right-top] margin rule 106 /// 107 /// [right-top] https://drafts.csswg.org/css-page-3/#right-top-box-def 108 RightTop => "right-top", 109 /// [`@right-middle`][right-middle] margin rule 110 /// 111 /// [right-middle] https://drafts.csswg.org/css-page-3/#right-middle-box-def 112 RightMiddle => "right-middle", 113 /// [`@right-bottom`][right-bottom] margin rule 114 /// 115 /// [right-bottom] https://drafts.csswg.org/css-page-3/#right-bottom-box-def 116 RightBottom => "right-bottom", 117 } 118 119 impl MarginRuleType { 120 #[inline] 121 fn to_str(&self) -> &'static str { 122 &MARGIN_RULE_AT_NAMES[*self as usize] 123 } 124 #[inline] 125 fn name(&self) -> &'static str { 126 // Use the at-name array, skipping the first character to get 127 // the name without the @ sign. 128 &MARGIN_RULE_AT_NAMES[*self as usize][1..] 129 } 130 } 131 132 // Implement Debug manually so that it will share the same string memory as 133 // MarginRuleType::name and MarginRuleType::to_str. 134 impl fmt::Debug for MarginRuleType { 135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { 136 f.write_str(self.name()) 137 } 138 } 139 140 /// A [`@margin`][margin] rule. 141 /// 142 /// [margin]: https://drafts.csswg.org/css-page-3/#margin-at-rules 143 #[derive(Clone, Debug, ToShmem)] 144 pub struct MarginRule { 145 /// Type of this margin rule. 146 pub rule_type: MarginRuleType, 147 /// The declaration block this margin rule contains. 148 pub block: Arc<Locked<PropertyDeclarationBlock>>, 149 /// The source position this rule was found at. 150 pub source_location: SourceLocation, 151 } 152 153 impl MarginRule { 154 /// Measure heap usage. 155 #[cfg(feature = "gecko")] 156 pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize { 157 // Measurement of other fields may be added later. 158 self.block.unconditional_shallow_size_of(ops) + self.block.read_with(guard).size_of(ops) 159 } 160 /// Gets the name for this margin rule. 161 #[inline] 162 pub fn name(&self) -> &'static str { 163 self.rule_type.name() 164 } 165 } 166 167 impl ToCssWithGuard for MarginRule { 168 /// Serialization of a margin-rule is not specced, this is adapted from how 169 /// page-rules and style-rules are serialized. 170 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result { 171 dest.write_str(self.rule_type.to_str())?; 172 dest.write_str(" { ")?; 173 let declaration_block = self.block.read_with(guard); 174 declaration_block.to_css(dest)?; 175 if !declaration_block.declarations().is_empty() { 176 dest.write_char(' ')?; 177 } 178 dest.write_char('}') 179 } 180 } 181 182 impl DeepCloneWithLock for MarginRule { 183 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self { 184 MarginRule { 185 rule_type: self.rule_type, 186 block: Arc::new(lock.wrap(self.block.read_with(&guard).clone())), 187 source_location: self.source_location.clone(), 188 } 189 } 190 }