1use std::borrow::Cow;
4use std::ops::Range;
5
6use crate::context::PropertyHandlerContext;
7use crate::error::{ParserError, PrinterError};
8use crate::parser::ParserOptions;
9use crate::printer::Printer;
10use crate::properties::box_shadow::BoxShadowHandler;
11use crate::properties::masking::MaskHandler;
12use crate::properties::{
13 align::AlignHandler,
14 animation::AnimationHandler,
15 background::BackgroundHandler,
16 border::BorderHandler,
17 contain::ContainerHandler,
18 display::DisplayHandler,
19 flex::FlexHandler,
20 font::FontHandler,
21 grid::GridHandler,
22 list::ListStyleHandler,
23 margin_padding::*,
24 outline::OutlineHandler,
25 overflow::OverflowHandler,
26 position::PositionHandler,
27 prefix_handler::{FallbackHandler, PrefixHandler},
28 size::SizeHandler,
29 text::TextDecorationHandler,
30 transform::TransformHandler,
31 transition::TransitionHandler,
32};
33use crate::properties::{Property, PropertyId};
34use crate::targets::Browsers;
35use crate::traits::{PropertyHandler, ToCss};
36use crate::values::string::CowArcStr;
37use cssparser::*;
38
39#[derive(Debug, PartialEq, Clone)]
45#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
46pub struct DeclarationBlock<'i> {
47 #[cfg_attr(feature = "serde", serde(borrow))]
49 pub important_declarations: Vec<Property<'i>>,
50 pub declarations: Vec<Property<'i>>,
52}
53
54impl<'i> DeclarationBlock<'i> {
55 pub fn parse<'a, 'o, 't>(
57 input: &mut Parser<'i, 't>,
58 options: &'a ParserOptions<'o, 'i>,
59 ) -> Result<Self, ParseError<'i, ParserError<'i>>> {
60 let mut important_declarations = DeclarationList::new();
61 let mut declarations = DeclarationList::new();
62 let mut parser = DeclarationListParser::new(
63 input,
64 PropertyDeclarationParser {
65 important_declarations: &mut important_declarations,
66 declarations: &mut declarations,
67 options,
68 },
69 );
70 while let Some(res) = parser.next() {
71 if let Err((err, _)) = res {
72 if options.error_recovery {
73 options.warn(err);
74 continue;
75 }
76 return Err(err);
77 }
78 }
79
80 Ok(DeclarationBlock {
81 important_declarations,
82 declarations,
83 })
84 }
85
86 pub fn parse_string<'o>(
88 input: &'i str,
89 options: ParserOptions<'o, 'i>,
90 ) -> Result<Self, ParseError<'i, ParserError<'i>>> {
91 let mut input = ParserInput::new(input);
92 let mut parser = Parser::new(&mut input);
93 let result = Self::parse(&mut parser, &options)?;
94 parser.expect_exhausted()?;
95 Ok(result)
96 }
97}
98
99impl<'i> ToCss for DeclarationBlock<'i> {
100 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
101 where
102 W: std::fmt::Write,
103 {
104 let len = self.declarations.len() + self.important_declarations.len();
105 let mut i = 0;
106
107 macro_rules! write {
108 ($decls: expr, $important: literal) => {
109 for decl in &$decls {
110 decl.to_css(dest, $important)?;
111 if i != len - 1 {
112 dest.write_char(';')?;
113 dest.whitespace()?;
114 }
115 i += 1;
116 }
117 };
118 }
119
120 write!(self.declarations, false);
121 write!(self.important_declarations, true);
122 Ok(())
123 }
124}
125
126impl<'i> DeclarationBlock<'i> {
127 pub(crate) fn to_css_block<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
128 where
129 W: std::fmt::Write,
130 {
131 dest.whitespace()?;
132 dest.write_char('{')?;
133 dest.indent();
134
135 let mut i = 0;
136 let len = self.declarations.len() + self.important_declarations.len();
137
138 macro_rules! write {
139 ($decls: expr, $important: literal) => {
140 for decl in &$decls {
141 dest.newline()?;
142 decl.to_css(dest, $important)?;
143 if i != len - 1 || !dest.minify {
144 dest.write_char(';')?;
145 }
146 i += 1;
147 }
148 };
149 }
150
151 write!(self.declarations, false);
152 write!(self.important_declarations, true);
153
154 dest.dedent();
155 dest.newline()?;
156 dest.write_char('}')
157 }
158}
159
160impl<'i> DeclarationBlock<'i> {
161 pub(crate) fn minify(
162 &mut self,
163 handler: &mut DeclarationHandler<'i>,
164 important_handler: &mut DeclarationHandler<'i>,
165 context: &mut PropertyHandlerContext<'i, '_>,
166 ) {
167 macro_rules! handle {
168 ($decls: expr, $handler: expr, $important: literal) => {
169 for decl in $decls.iter() {
170 context.is_important = $important;
171 let handled = $handler.handle_property(decl, context);
172
173 if !handled {
174 $handler.decls.push(decl.clone());
175 }
176 }
177 };
178 }
179
180 handle!(self.important_declarations, important_handler, true);
181 handle!(self.declarations, handler, false);
182
183 handler.finalize(context);
184 important_handler.finalize(context);
185 self.important_declarations = std::mem::take(&mut important_handler.decls);
186 self.declarations = std::mem::take(&mut handler.decls);
187 }
188
189 pub fn is_empty(&self) -> bool {
191 return self.declarations.is_empty() && self.important_declarations.is_empty();
192 }
193
194 pub(crate) fn property_location<'t>(
195 &self,
196 input: &mut Parser<'i, 't>,
197 index: usize,
198 ) -> Result<(Range<SourceLocation>, Range<SourceLocation>), ParseError<'i, ParserError<'i>>> {
199 for _ in 0..index {
201 input.expect_ident()?;
202 input.expect_colon()?;
203 input.parse_until_after(Delimiter::Semicolon, |parser| {
204 while parser.next().is_ok() {}
205 Ok(())
206 })?;
207 }
208
209 input.skip_whitespace();
211 let key_start = input.current_source_location();
212 input.expect_ident()?;
213 let key_end = input.current_source_location();
214 let key_range = key_start..key_end;
215
216 input.expect_colon()?;
217 input.skip_whitespace();
218
219 let val_start = input.current_source_location();
221 input.parse_until_before(Delimiter::Semicolon, |parser| {
222 while parser.next().is_ok() {}
223 Ok(())
224 })?;
225 let val_end = input.current_source_location();
226 let val_range = val_start..val_end;
227
228 Ok((key_range, val_range))
229 }
230}
231
232impl<'i> DeclarationBlock<'i> {
233 pub fn iter(&self) -> impl std::iter::DoubleEndedIterator<Item = (&Property<'i>, bool)> {
235 self
236 .declarations
237 .iter()
238 .map(|property| (property, false))
239 .chain(self.important_declarations.iter().map(|property| (property, true)))
240 }
241
242 pub fn iter_mut(&mut self) -> impl std::iter::DoubleEndedIterator<Item = &mut Property<'i>> {
244 self.declarations.iter_mut().chain(self.important_declarations.iter_mut())
245 }
246
247 pub fn get<'a>(&'a self, property_id: &PropertyId) -> Option<(Cow<'a, Property<'i>>, bool)> {
253 if property_id.is_shorthand() {
254 if let Some((shorthand, important)) = property_id.shorthand_value(&self) {
255 return Some((Cow::Owned(shorthand), important));
256 }
257 } else {
258 for (property, important) in self.iter().rev() {
259 if property.property_id() == *property_id {
260 return Some((Cow::Borrowed(property), important));
261 }
262
263 if let Some(val) = property.longhand(&property_id) {
264 return Some((Cow::Owned(val), important));
265 }
266 }
267 }
268
269 None
270 }
271
272 pub fn set(&mut self, property: Property<'i>, important: bool) {
278 let property_id = property.property_id();
279 let declarations = if important {
280 self.declarations.retain(|decl| decl.property_id() != property_id);
282 &mut self.important_declarations
283 } else {
284 self.important_declarations.retain(|decl| decl.property_id() != property_id);
286 &mut self.declarations
287 };
288
289 let longhands = property_id.longhands().unwrap_or_else(|| vec![property.property_id()]);
290
291 for decl in declarations.iter_mut().rev() {
292 {
293 let id = decl.property_id();
297 let id_longhands = id.longhands().unwrap_or_else(|| vec![id]);
298 if longhands.iter().any(|longhand| {
299 let logical_group = longhand.logical_group();
300 let category = longhand.category();
301
302 logical_group.is_some()
303 && id_longhands.iter().any(|id_longhand| {
304 logical_group == id_longhand.logical_group() && category != id_longhand.category()
305 })
306 }) {
307 break;
308 }
309 }
310
311 if decl.property_id() == property_id {
312 *decl = property;
313 return;
314 }
315
316 if decl.set_longhand(&property).is_ok() {
318 return;
319 }
320 }
321
322 declarations.push(property)
323 }
324
325 pub fn remove(&mut self, property_id: &PropertyId) {
331 fn remove<'i, 'a>(declarations: &mut Vec<Property<'i>>, property_id: &PropertyId<'a>) {
332 let longhands = property_id.longhands().unwrap_or(vec![]);
333 let mut i = 0;
334 while i < declarations.len() {
335 let replacement = {
336 let property = &declarations[i];
337 let id = property.property_id();
338 if id == *property_id || longhands.contains(&id) {
339 None
342 } else if longhands.is_empty() && id.longhands().unwrap_or(vec![]).contains(&property_id) {
343 Some(
346 id.longhands()
347 .unwrap()
348 .iter()
349 .filter_map(|longhand| {
350 if *longhand == *property_id {
351 None
352 } else {
353 property.longhand(longhand)
354 }
355 })
356 .collect::<Vec<Property>>(),
357 )
358 } else {
359 i += 1;
360 continue;
361 }
362 };
363
364 match replacement {
365 Some(properties) => {
366 let count = properties.len();
367 declarations.splice(i..i + 1, properties);
368 i += count;
369 }
370 None => {
371 declarations.remove(i);
372 }
373 }
374 }
375 }
376
377 remove(&mut self.declarations, property_id);
378 remove(&mut self.important_declarations, property_id);
379 }
380}
381
382struct PropertyDeclarationParser<'a, 'o, 'i> {
383 important_declarations: &'a mut Vec<Property<'i>>,
384 declarations: &'a mut Vec<Property<'i>>,
385 options: &'a ParserOptions<'o, 'i>,
386}
387
388impl<'a, 'o, 'i> cssparser::DeclarationParser<'i> for PropertyDeclarationParser<'a, 'o, 'i> {
390 type Declaration = ();
391 type Error = ParserError<'i>;
392
393 fn parse_value<'t>(
394 &mut self,
395 name: CowRcStr<'i>,
396 input: &mut cssparser::Parser<'i, 't>,
397 ) -> Result<Self::Declaration, cssparser::ParseError<'i, Self::Error>> {
398 parse_declaration(
399 name,
400 input,
401 &mut self.declarations,
402 &mut self.important_declarations,
403 &self.options,
404 )
405 }
406}
407
408impl<'a, 'o, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a, 'o, 'i> {
410 type Prelude = ();
411 type AtRule = ();
412 type Error = ParserError<'i>;
413}
414
415pub(crate) fn parse_declaration<'i, 't>(
416 name: CowRcStr<'i>,
417 input: &mut cssparser::Parser<'i, 't>,
418 declarations: &mut DeclarationList<'i>,
419 important_declarations: &mut DeclarationList<'i>,
420 options: &ParserOptions,
421) -> Result<(), cssparser::ParseError<'i, ParserError<'i>>> {
422 let property = input.parse_until_before(Delimiter::Bang, |input| {
423 Property::parse(PropertyId::from(CowArcStr::from(name)), input, options)
424 })?;
425 let important = input
426 .try_parse(|input| {
427 input.expect_delim('!')?;
428 input.expect_ident_matching("important")
429 })
430 .is_ok();
431 if important {
432 important_declarations.push(property);
433 } else {
434 declarations.push(property);
435 }
436 Ok(())
437}
438
439pub(crate) type DeclarationList<'i> = Vec<Property<'i>>;
440
441pub(crate) struct DeclarationHandler<'i> {
442 background: BackgroundHandler<'i>,
443 border: BorderHandler<'i>,
444 outline: OutlineHandler,
445 flex: FlexHandler,
446 grid: GridHandler<'i>,
447 align: AlignHandler,
448 size: SizeHandler,
449 margin: MarginHandler<'i>,
450 padding: PaddingHandler<'i>,
451 scroll_margin: ScrollMarginHandler<'i>,
452 scroll_padding: ScrollPaddingHandler<'i>,
453 font: FontHandler<'i>,
454 text: TextDecorationHandler<'i>,
455 list: ListStyleHandler<'i>,
456 transition: TransitionHandler<'i>,
457 animation: AnimationHandler<'i>,
458 display: DisplayHandler<'i>,
459 position: PositionHandler,
460 inset: InsetHandler<'i>,
461 overflow: OverflowHandler,
462 transform: TransformHandler,
463 box_shadow: BoxShadowHandler,
464 mask: MaskHandler<'i>,
465 container: ContainerHandler<'i>,
466 fallback: FallbackHandler,
467 prefix: PrefixHandler,
468 decls: DeclarationList<'i>,
469}
470
471impl<'i> DeclarationHandler<'i> {
472 pub fn new(targets: Option<Browsers>) -> Self {
473 DeclarationHandler {
474 background: BackgroundHandler::new(targets),
475 border: BorderHandler::new(targets),
476 outline: OutlineHandler::new(targets),
477 flex: FlexHandler::new(targets),
478 grid: GridHandler::default(),
479 align: AlignHandler::new(targets),
480 size: SizeHandler::default(),
481 margin: MarginHandler::default(),
482 padding: PaddingHandler::default(),
483 scroll_margin: ScrollMarginHandler::default(),
484 scroll_padding: ScrollPaddingHandler::default(),
485 font: FontHandler::default(),
486 text: TextDecorationHandler::new(targets),
487 list: ListStyleHandler::new(targets),
488 transition: TransitionHandler::new(targets),
489 animation: AnimationHandler::new(targets),
490 display: DisplayHandler::new(targets),
491 position: PositionHandler::new(targets),
492 inset: InsetHandler::default(),
493 overflow: OverflowHandler::new(targets),
494 transform: TransformHandler::new(targets),
495 box_shadow: BoxShadowHandler::new(targets),
496 mask: MaskHandler::default(),
497 container: ContainerHandler::default(),
498 fallback: FallbackHandler::new(targets),
499 prefix: PrefixHandler::new(targets),
500 decls: DeclarationList::new(),
501 }
502 }
503
504 pub fn handle_property(
505 &mut self,
506 property: &Property<'i>,
507 context: &mut PropertyHandlerContext<'i, '_>,
508 ) -> bool {
509 if !context.unused_symbols.is_empty()
510 && matches!(property, Property::Custom(custom) if context.unused_symbols.contains(custom.name.as_ref()))
511 {
512 return true;
513 }
514
515 self.background.handle_property(property, &mut self.decls, context)
516 || self.border.handle_property(property, &mut self.decls, context)
517 || self.outline.handle_property(property, &mut self.decls, context)
518 || self.flex.handle_property(property, &mut self.decls, context)
519 || self.grid.handle_property(property, &mut self.decls, context)
520 || self.align.handle_property(property, &mut self.decls, context)
521 || self.size.handle_property(property, &mut self.decls, context)
522 || self.margin.handle_property(property, &mut self.decls, context)
523 || self.padding.handle_property(property, &mut self.decls, context)
524 || self.scroll_margin.handle_property(property, &mut self.decls, context)
525 || self.scroll_padding.handle_property(property, &mut self.decls, context)
526 || self.font.handle_property(property, &mut self.decls, context)
527 || self.text.handle_property(property, &mut self.decls, context)
528 || self.list.handle_property(property, &mut self.decls, context)
529 || self.transition.handle_property(property, &mut self.decls, context)
530 || self.animation.handle_property(property, &mut self.decls, context)
531 || self.display.handle_property(property, &mut self.decls, context)
532 || self.position.handle_property(property, &mut self.decls, context)
533 || self.inset.handle_property(property, &mut self.decls, context)
534 || self.overflow.handle_property(property, &mut self.decls, context)
535 || self.transform.handle_property(property, &mut self.decls, context)
536 || self.box_shadow.handle_property(property, &mut self.decls, context)
537 || self.mask.handle_property(property, &mut self.decls, context)
538 || self.container.handle_property(property, &mut self.decls, context)
539 || self.fallback.handle_property(property, &mut self.decls, context)
540 || self.prefix.handle_property(property, &mut self.decls, context)
541 }
542
543 pub fn finalize(&mut self, context: &mut PropertyHandlerContext<'i, '_>) {
544 self.background.finalize(&mut self.decls, context);
545 self.border.finalize(&mut self.decls, context);
546 self.outline.finalize(&mut self.decls, context);
547 self.flex.finalize(&mut self.decls, context);
548 self.grid.finalize(&mut self.decls, context);
549 self.align.finalize(&mut self.decls, context);
550 self.size.finalize(&mut self.decls, context);
551 self.margin.finalize(&mut self.decls, context);
552 self.padding.finalize(&mut self.decls, context);
553 self.scroll_margin.finalize(&mut self.decls, context);
554 self.scroll_padding.finalize(&mut self.decls, context);
555 self.font.finalize(&mut self.decls, context);
556 self.text.finalize(&mut self.decls, context);
557 self.list.finalize(&mut self.decls, context);
558 self.transition.finalize(&mut self.decls, context);
559 self.animation.finalize(&mut self.decls, context);
560 self.display.finalize(&mut self.decls, context);
561 self.position.finalize(&mut self.decls, context);
562 self.inset.finalize(&mut self.decls, context);
563 self.overflow.finalize(&mut self.decls, context);
564 self.transform.finalize(&mut self.decls, context);
565 self.box_shadow.finalize(&mut self.decls, context);
566 self.mask.finalize(&mut self.decls, context);
567 self.container.finalize(&mut self.decls, context);
568 self.fallback.finalize(&mut self.decls, context);
569 self.prefix.finalize(&mut self.decls, context);
570 }
571}