1use super::border_image::*;
4use super::border_radius::*;
5use crate::compat::Feature;
6use crate::context::PropertyHandlerContext;
7use crate::declaration::{DeclarationBlock, DeclarationList};
8use crate::error::{ParserError, PrinterError};
9use crate::logical::PropertyCategory;
10use crate::macros::*;
11use crate::printer::Printer;
12use crate::properties::custom::UnparsedProperty;
13use crate::properties::{Property, PropertyId};
14use crate::targets::Browsers;
15use crate::targets::Targets;
16use crate::traits::{FallbackValues, IsCompatible, Parse, PropertyHandler, Shorthand, ToCss};
17use crate::values::color::{ColorFallbackKind, CssColor};
18use crate::values::length::*;
19use crate::values::rect::Rect;
20use crate::values::size::Size2D;
21#[cfg(feature = "visitor")]
22use crate::visitor::Visit;
23use cssparser::*;
24
25#[derive(Debug, Clone, PartialEq, Parse, ToCss)]
27#[cfg_attr(feature = "visitor", derive(Visit))]
28#[cfg_attr(
29 feature = "serde",
30 derive(serde::Serialize, serde::Deserialize),
31 serde(tag = "type", content = "value", rename_all = "kebab-case")
32)]
33#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
34#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
35pub enum BorderSideWidth {
36 Thin,
38 Medium,
40 Thick,
42 Length(Length),
44}
45
46impl Default for BorderSideWidth {
47 fn default() -> BorderSideWidth {
48 BorderSideWidth::Medium
49 }
50}
51
52impl IsCompatible for BorderSideWidth {
53 fn is_compatible(&self, browsers: Browsers) -> bool {
54 match self {
55 BorderSideWidth::Length(length) => length.is_compatible(browsers),
56 _ => true,
57 }
58 }
59}
60
61enum_property! {
62 pub enum LineStyle {
64 None,
66 Hidden,
68 Inset,
70 Groove,
72 Outset,
74 Ridge,
76 Dotted,
78 Dashed,
80 Solid,
82 Double,
84 }
85}
86
87impl Default for LineStyle {
88 fn default() -> LineStyle {
89 LineStyle::None
90 }
91}
92
93impl IsCompatible for LineStyle {
94 fn is_compatible(&self, _browsers: Browsers) -> bool {
95 true
96 }
97}
98
99#[derive(Debug, Clone, PartialEq)]
101#[cfg_attr(feature = "visitor", derive(Visit))]
102#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
103#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
104pub struct GenericBorder<S, const P: u8> {
105 pub width: BorderSideWidth,
107 pub style: S,
109 pub color: CssColor,
111}
112
113#[cfg(feature = "into_owned")]
114impl<'any, S, const P: u8> static_self::IntoOwned<'any> for GenericBorder<S, P>
115where
116 S: static_self::IntoOwned<'any>,
117{
118 type Owned = GenericBorder<S::Owned, P>;
119 fn into_owned(self) -> Self::Owned {
120 GenericBorder {
121 width: self.width,
122 style: self.style.into_owned(),
123 color: self.color,
124 }
125 }
126}
127
128impl<S: Default, const P: u8> Default for GenericBorder<S, P> {
129 fn default() -> GenericBorder<S, P> {
130 GenericBorder {
131 width: BorderSideWidth::Medium,
132 style: S::default(),
133 color: CssColor::current_color(),
134 }
135 }
136}
137
138impl<'i, S: Parse<'i> + Default, const P: u8> Parse<'i> for GenericBorder<S, P> {
139 fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
140 let mut color = None;
142 let mut style = None;
143 let mut width = None;
144 let mut any = false;
145 loop {
146 if width.is_none() {
147 if let Ok(value) = input.try_parse(|i| BorderSideWidth::parse(i)) {
148 width = Some(value);
149 any = true;
150 }
151 }
152 if style.is_none() {
153 if let Ok(value) = input.try_parse(S::parse) {
154 style = Some(value);
155 any = true;
156 continue;
157 }
158 }
159 if color.is_none() {
160 if let Ok(value) = input.try_parse(|i| CssColor::parse(i)) {
161 color = Some(value);
162 any = true;
163 continue;
164 }
165 }
166 break;
167 }
168 if any {
169 Ok(GenericBorder {
170 width: width.unwrap_or(BorderSideWidth::Medium),
171 style: style.unwrap_or_default(),
172 color: color.unwrap_or_else(|| CssColor::current_color()),
173 })
174 } else {
175 Err(input.new_custom_error(ParserError::InvalidDeclaration))
176 }
177 }
178}
179
180impl<S: ToCss + Default + PartialEq, const P: u8> ToCss for GenericBorder<S, P> {
181 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
182 where
183 W: std::fmt::Write,
184 {
185 if *self == Self::default() {
186 self.style.to_css(dest)?;
187 return Ok(());
188 }
189
190 let mut needs_space = false;
191 if self.width != BorderSideWidth::default() {
192 self.width.to_css(dest)?;
193 needs_space = true;
194 }
195 if self.style != S::default() {
196 if needs_space {
197 dest.write_str(" ")?;
198 }
199 self.style.to_css(dest)?;
200 needs_space = true;
201 }
202 if self.color != CssColor::current_color() {
203 if needs_space {
204 dest.write_str(" ")?;
205 }
206 self.color.to_css(dest)?;
207 }
208 Ok(())
209 }
210}
211
212impl<S: Clone, const P: u8> FallbackValues for GenericBorder<S, P> {
213 fn get_fallbacks(&mut self, targets: Targets) -> Vec<Self> {
214 self
215 .color
216 .get_fallbacks(targets)
217 .into_iter()
218 .map(|color| GenericBorder {
219 color,
220 width: self.width.clone(),
221 style: self.style.clone(),
222 })
223 .collect()
224 }
225}
226
227pub type BorderTop = GenericBorder<LineStyle, 0>;
229pub type BorderRight = GenericBorder<LineStyle, 1>;
231pub type BorderBottom = GenericBorder<LineStyle, 2>;
233pub type BorderLeft = GenericBorder<LineStyle, 3>;
235pub type BorderBlockStart = GenericBorder<LineStyle, 4>;
237pub type BorderBlockEnd = GenericBorder<LineStyle, 5>;
239pub type BorderInlineStart = GenericBorder<LineStyle, 6>;
241pub type BorderInlineEnd = GenericBorder<LineStyle, 7>;
243pub type BorderBlock = GenericBorder<LineStyle, 8>;
245pub type BorderInline = GenericBorder<LineStyle, 9>;
247pub type Border = GenericBorder<LineStyle, 10>;
249
250impl_shorthand! {
251 BorderTop(BorderTop) {
252 width: [BorderTopWidth],
253 style: [BorderTopStyle],
254 color: [BorderTopColor],
255 }
256}
257
258impl_shorthand! {
259 BorderRight(BorderRight) {
260 width: [BorderRightWidth],
261 style: [BorderRightStyle],
262 color: [BorderRightColor],
263 }
264}
265
266impl_shorthand! {
267 BorderBottom(BorderBottom) {
268 width: [BorderBottomWidth],
269 style: [BorderBottomStyle],
270 color: [BorderBottomColor],
271 }
272}
273
274impl_shorthand! {
275 BorderLeft(BorderLeft) {
276 width: [BorderLeftWidth],
277 style: [BorderLeftStyle],
278 color: [BorderLeftColor],
279 }
280}
281
282impl_shorthand! {
283 BorderBlockStart(BorderBlockStart) {
284 width: [BorderBlockStartWidth],
285 style: [BorderBlockStartStyle],
286 color: [BorderBlockStartColor],
287 }
288}
289
290impl_shorthand! {
291 BorderBlockEnd(BorderBlockEnd) {
292 width: [BorderBlockEndWidth],
293 style: [BorderBlockEndStyle],
294 color: [BorderBlockEndColor],
295 }
296}
297
298impl_shorthand! {
299 BorderInlineStart(BorderInlineStart) {
300 width: [BorderInlineStartWidth],
301 style: [BorderInlineStartStyle],
302 color: [BorderInlineStartColor],
303 }
304}
305
306impl_shorthand! {
307 BorderInlineEnd(BorderInlineEnd) {
308 width: [BorderInlineEndWidth],
309 style: [BorderInlineEndStyle],
310 color: [BorderInlineEndColor],
311 }
312}
313
314impl_shorthand! {
315 BorderBlock(BorderBlock) {
316 width: [BorderBlockStartWidth, BorderBlockEndWidth],
317 style: [BorderBlockStartStyle, BorderBlockEndStyle],
318 color: [BorderBlockStartColor, BorderBlockEndColor],
319 }
320}
321
322impl_shorthand! {
323 BorderInline(BorderInline) {
324 width: [BorderInlineStartWidth, BorderInlineEndWidth],
325 style: [BorderInlineStartStyle, BorderInlineEndStyle],
326 color: [BorderInlineStartColor, BorderInlineEndColor],
327 }
328}
329
330impl_shorthand! {
331 Border(Border) {
332 width: [BorderTopWidth, BorderRightWidth, BorderBottomWidth, BorderLeftWidth],
333 style: [BorderTopStyle, BorderRightStyle, BorderBottomStyle, BorderLeftStyle],
334 color: [BorderTopColor, BorderRightColor, BorderBottomColor, BorderLeftColor],
335 }
336}
337
338size_shorthand! {
339 pub struct BorderBlockColor<CssColor> {
341 start: BorderBlockStartColor,
343 end: BorderBlockEndColor,
345 }
346}
347
348size_shorthand! {
349 pub struct BorderBlockStyle<LineStyle> {
351 start: BorderBlockStartStyle,
353 end: BorderBlockEndStyle,
355 }
356}
357
358size_shorthand! {
359 pub struct BorderBlockWidth<BorderSideWidth> {
361 start: BorderBlockStartWidth,
363 end: BorderBlockEndWidth,
365 }
366}
367
368size_shorthand! {
369 pub struct BorderInlineColor<CssColor> {
371 start: BorderInlineStartColor,
373 end: BorderInlineEndColor,
375 }
376}
377
378size_shorthand! {
379 pub struct BorderInlineStyle<LineStyle> {
381 start: BorderInlineStartStyle,
383 end: BorderInlineEndStyle,
385 }
386}
387
388size_shorthand! {
389 pub struct BorderInlineWidth<BorderSideWidth> {
391 start: BorderInlineStartWidth,
393 end: BorderInlineEndWidth,
395 }
396}
397
398rect_shorthand! {
399 pub struct BorderColor<CssColor> {
401 BorderTopColor,
402 BorderRightColor,
403 BorderBottomColor,
404 BorderLeftColor
405 }
406}
407
408rect_shorthand! {
409 pub struct BorderStyle<LineStyle> {
411 BorderTopStyle,
412 BorderRightStyle,
413 BorderBottomStyle,
414 BorderLeftStyle
415 }
416}
417
418rect_shorthand! {
419 pub struct BorderWidth<BorderSideWidth> {
421 BorderTopWidth,
422 BorderRightWidth,
423 BorderBottomWidth,
424 BorderLeftWidth
425 }
426}
427
428macro_rules! impl_fallbacks {
429 ($t: ident $(, $name: ident)+) => {
430 impl FallbackValues for $t {
431 fn get_fallbacks(&mut self, targets: Targets) -> Vec<Self> {
432 let mut fallbacks = ColorFallbackKind::empty();
433 $(
434 fallbacks |= self.$name.get_necessary_fallbacks(targets);
435 )+
436
437 let mut res = Vec::new();
438 if fallbacks.contains(ColorFallbackKind::RGB) {
439 res.push($t {
440 $(
441 $name: self.$name.get_fallback(ColorFallbackKind::RGB),
442 )+
443 });
444 }
445
446 if fallbacks.contains(ColorFallbackKind::P3) {
447 res.push($t {
448 $(
449 $name: self.$name.get_fallback(ColorFallbackKind::P3),
450 )+
451 });
452 }
453
454 if fallbacks.contains(ColorFallbackKind::LAB) {
455 $(
456 self.$name = self.$name.get_fallback(ColorFallbackKind::LAB);
457 )+
458 }
459
460 res
461 }
462 }
463 }
464}
465
466impl_fallbacks!(BorderBlockColor, start, end);
467impl_fallbacks!(BorderInlineColor, start, end);
468impl_fallbacks!(BorderColor, top, right, bottom, left);
469
470#[derive(Default, Debug, PartialEq)]
471struct BorderShorthand {
472 pub width: Option<BorderSideWidth>,
473 pub style: Option<LineStyle>,
474 pub color: Option<CssColor>,
475}
476
477impl BorderShorthand {
478 pub fn set_border<const P: u8>(&mut self, border: &GenericBorder<LineStyle, P>) {
479 self.width = Some(border.width.clone());
480 self.style = Some(border.style.clone());
481 self.color = Some(border.color.clone());
482 }
483
484 pub fn is_valid(&self) -> bool {
485 self.width.is_some() && self.style.is_some() && self.color.is_some()
486 }
487
488 pub fn reset(&mut self) {
489 self.width = None;
490 self.style = None;
491 self.color = None;
492 }
493
494 pub fn to_border<const P: u8>(&self) -> GenericBorder<LineStyle, P> {
495 GenericBorder {
496 width: self.width.clone().unwrap(),
497 style: self.style.clone().unwrap(),
498 color: self.color.clone().unwrap(),
499 }
500 }
501}
502
503property_bitflags! {
504 #[derive(Debug, Default)]
505 struct BorderProperty: u32 {
506 const BorderTopColor = 1 << 0;
507 const BorderBottomColor = 1 << 1;
508 const BorderLeftColor = 1 << 2;
509 const BorderRightColor = 1 << 3;
510 const BorderBlockStartColor = 1 << 4;
511 const BorderBlockEndColor = 1 << 5;
512 const BorderBlockColor = Self::BorderBlockStartColor.bits() | Self::BorderBlockEndColor.bits();
513 const BorderInlineStartColor = 1 << 6;
514 const BorderInlineEndColor = 1 << 7;
515 const BorderInlineColor = Self::BorderInlineStartColor.bits() | Self::BorderInlineEndColor.bits();
516 const BorderTopWidth = 1 << 8;
517 const BorderBottomWidth = 1 << 9;
518 const BorderLeftWidth = 1 << 10;
519 const BorderRightWidth = 1 << 11;
520 const BorderBlockStartWidth = 1 << 12;
521 const BorderBlockEndWidth = 1 << 13;
522 const BorderBlockWidth = Self::BorderBlockStartWidth.bits() | Self::BorderBlockEndWidth.bits();
523 const BorderInlineStartWidth = 1 << 14;
524 const BorderInlineEndWidth = 1 << 15;
525 const BorderInlineWidth = Self::BorderInlineStartWidth.bits() | Self::BorderInlineEndWidth.bits();
526 const BorderTopStyle = 1 << 16;
527 const BorderBottomStyle = 1 << 17;
528 const BorderLeftStyle = 1 << 18;
529 const BorderRightStyle = 1 << 19;
530 const BorderBlockStartStyle = 1 << 20;
531 const BorderBlockEndStyle = 1 << 21;
532 const BorderBlockStyle = Self::BorderBlockStartStyle.bits() | Self::BorderBlockEndStyle.bits();
533 const BorderInlineStartStyle = 1 << 22;
534 const BorderInlineEndStyle = 1 << 23;
535 const BorderInlineStyle = Self::BorderInlineStartStyle.bits() | Self::BorderInlineEndStyle.bits();
536 const BorderTop = Self::BorderTopColor.bits() | Self::BorderTopWidth.bits() | Self::BorderTopStyle.bits();
537 const BorderBottom = Self::BorderBottomColor.bits() | Self::BorderBottomWidth.bits() | Self::BorderBottomStyle.bits();
538 const BorderLeft = Self::BorderLeftColor.bits() | Self::BorderLeftWidth.bits() | Self::BorderLeftStyle.bits();
539 const BorderRight = Self::BorderRightColor.bits() | Self::BorderRightWidth.bits() | Self::BorderRightStyle.bits();
540 const BorderBlockStart = Self::BorderBlockStartColor.bits() | Self::BorderBlockStartWidth.bits() | Self::BorderBlockStartStyle.bits();
541 const BorderBlockEnd = Self::BorderBlockEndColor.bits() | Self::BorderBlockEndWidth.bits() | Self::BorderBlockEndStyle.bits();
542 const BorderInlineStart = Self::BorderInlineStartColor.bits() | Self::BorderInlineStartWidth.bits() | Self::BorderInlineStartStyle.bits();
543 const BorderInlineEnd = Self::BorderInlineEndColor.bits() | Self::BorderInlineEndWidth.bits() | Self::BorderInlineEndStyle.bits();
544 const BorderBlock = Self::BorderBlockStart.bits() | Self::BorderBlockEnd.bits();
545 const BorderInline = Self::BorderInlineStart.bits() | Self::BorderInlineEnd.bits();
546 const BorderWidth = Self::BorderLeftWidth.bits() | Self::BorderRightWidth.bits() | Self::BorderTopWidth.bits() | Self::BorderBottomWidth.bits();
547 const BorderStyle = Self::BorderLeftStyle.bits() | Self::BorderRightStyle.bits() | Self::BorderTopStyle.bits() | Self::BorderBottomStyle.bits();
548 const BorderColor = Self::BorderLeftColor.bits() | Self::BorderRightColor.bits() | Self::BorderTopColor.bits() | Self::BorderBottomColor.bits();
549 const Border = Self::BorderWidth.bits() | Self::BorderStyle.bits() | Self::BorderColor.bits();
550 }
551}
552
553#[derive(Debug, Default)]
554pub(crate) struct BorderHandler<'i> {
555 border_top: BorderShorthand,
556 border_bottom: BorderShorthand,
557 border_left: BorderShorthand,
558 border_right: BorderShorthand,
559 border_block_start: BorderShorthand,
560 border_block_end: BorderShorthand,
561 border_inline_start: BorderShorthand,
562 border_inline_end: BorderShorthand,
563 category: PropertyCategory,
564 border_image_handler: BorderImageHandler<'i>,
565 border_radius_handler: BorderRadiusHandler<'i>,
566 flushed_properties: BorderProperty,
567 has_any: bool,
568}
569
570impl<'i> PropertyHandler<'i> for BorderHandler<'i> {
571 fn handle_property(
572 &mut self,
573 property: &Property<'i>,
574 dest: &mut DeclarationList<'i>,
575 context: &mut PropertyHandlerContext<'i, '_>,
576 ) -> bool {
577 use Property::*;
578
579 macro_rules! flush {
580 ($key: ident, $prop: ident, $val: expr, $category: ident) => {{
581 if PropertyCategory::$category != self.category {
582 self.flush(dest, context);
583 }
584
585 if self.$key.$prop.is_some() && self.$key.$prop.as_ref().unwrap() != $val && matches!(context.targets.browsers, Some(targets) if !$val.is_compatible(targets)) {
586 self.flush(dest, context);
587 }
588 }};
589 }
590
591 macro_rules! property {
592 ($key: ident, $prop: ident, $val: expr, $category: ident) => {{
593 flush!($key, $prop, $val, $category);
594 self.$key.$prop = Some($val.clone());
595 self.category = PropertyCategory::$category;
596 self.has_any = true;
597 }};
598 }
599
600 macro_rules! set_border {
601 ($key: ident, $val: ident, $category: ident) => {{
602 if PropertyCategory::$category != self.category {
603 self.flush(dest, context);
604 }
605 self.$key.set_border($val);
606 self.category = PropertyCategory::$category;
607 self.has_any = true;
608 }};
609 }
610
611 match &property {
612 BorderTopColor(val) => property!(border_top, color, val, Physical),
613 BorderBottomColor(val) => property!(border_bottom, color, val, Physical),
614 BorderLeftColor(val) => property!(border_left, color, val, Physical),
615 BorderRightColor(val) => property!(border_right, color, val, Physical),
616 BorderBlockStartColor(val) => property!(border_block_start, color, val, Logical),
617 BorderBlockEndColor(val) => property!(border_block_end, color, val, Logical),
618 BorderBlockColor(val) => {
619 property!(border_block_start, color, &val.start, Logical);
620 property!(border_block_end, color, &val.end, Logical);
621 }
622 BorderInlineStartColor(val) => property!(border_inline_start, color, val, Logical),
623 BorderInlineEndColor(val) => property!(border_inline_end, color, val, Logical),
624 BorderInlineColor(val) => {
625 property!(border_inline_start, color, &val.start, Logical);
626 property!(border_inline_end, color, &val.end, Logical);
627 }
628 BorderTopWidth(val) => property!(border_top, width, val, Physical),
629 BorderBottomWidth(val) => property!(border_bottom, width, val, Physical),
630 BorderLeftWidth(val) => property!(border_left, width, val, Physical),
631 BorderRightWidth(val) => property!(border_right, width, val, Physical),
632 BorderBlockStartWidth(val) => property!(border_block_start, width, val, Logical),
633 BorderBlockEndWidth(val) => property!(border_block_end, width, val, Logical),
634 BorderBlockWidth(val) => {
635 property!(border_block_start, width, &val.start, Logical);
636 property!(border_block_end, width, &val.end, Logical);
637 }
638 BorderInlineStartWidth(val) => property!(border_inline_start, width, val, Logical),
639 BorderInlineEndWidth(val) => property!(border_inline_end, width, val, Logical),
640 BorderInlineWidth(val) => {
641 property!(border_inline_start, width, &val.start, Logical);
642 property!(border_inline_end, width, &val.end, Logical);
643 }
644 BorderTopStyle(val) => property!(border_top, style, val, Physical),
645 BorderBottomStyle(val) => property!(border_bottom, style, val, Physical),
646 BorderLeftStyle(val) => property!(border_left, style, val, Physical),
647 BorderRightStyle(val) => property!(border_right, style, val, Physical),
648 BorderBlockStartStyle(val) => property!(border_block_start, style, val, Logical),
649 BorderBlockEndStyle(val) => property!(border_block_end, style, val, Logical),
650 BorderBlockStyle(val) => {
651 property!(border_block_start, style, &val.start, Logical);
652 property!(border_block_end, style, &val.end, Logical);
653 }
654 BorderInlineStartStyle(val) => property!(border_inline_start, style, val, Logical),
655 BorderInlineEndStyle(val) => property!(border_inline_end, style, val, Logical),
656 BorderInlineStyle(val) => {
657 property!(border_inline_start, style, &val.start, Logical);
658 property!(border_inline_end, style, &val.end, Logical);
659 }
660 BorderTop(val) => set_border!(border_top, val, Physical),
661 BorderBottom(val) => set_border!(border_bottom, val, Physical),
662 BorderLeft(val) => set_border!(border_left, val, Physical),
663 BorderRight(val) => set_border!(border_right, val, Physical),
664 BorderBlockStart(val) => set_border!(border_block_start, val, Logical),
665 BorderBlockEnd(val) => set_border!(border_block_end, val, Logical),
666 BorderInlineStart(val) => set_border!(border_inline_start, val, Logical),
667 BorderInlineEnd(val) => set_border!(border_inline_end, val, Logical),
668 BorderBlock(val) => {
669 set_border!(border_block_start, val, Logical);
670 set_border!(border_block_end, val, Logical);
671 }
672 BorderInline(val) => {
673 set_border!(border_inline_start, val, Logical);
674 set_border!(border_inline_end, val, Logical);
675 }
676 BorderWidth(val) => {
677 property!(border_top, width, &val.top, Physical);
678 property!(border_right, width, &val.right, Physical);
679 property!(border_bottom, width, &val.bottom, Physical);
680 property!(border_left, width, &val.left, Physical);
681 self.border_block_start.width = None;
682 self.border_block_end.width = None;
683 self.border_inline_start.width = None;
684 self.border_inline_end.width = None;
685 self.has_any = true;
686 }
687 BorderStyle(val) => {
688 property!(border_top, style, &val.top, Physical);
689 property!(border_right, style, &val.right, Physical);
690 property!(border_bottom, style, &val.bottom, Physical);
691 property!(border_left, style, &val.left, Physical);
692 self.border_block_start.style = None;
693 self.border_block_end.style = None;
694 self.border_inline_start.style = None;
695 self.border_inline_end.style = None;
696 self.has_any = true;
697 }
698 BorderColor(val) => {
699 property!(border_top, color, &val.top, Physical);
700 property!(border_right, color, &val.right, Physical);
701 property!(border_bottom, color, &val.bottom, Physical);
702 property!(border_left, color, &val.left, Physical);
703 self.border_block_start.color = None;
704 self.border_block_end.color = None;
705 self.border_inline_start.color = None;
706 self.border_inline_end.color = None;
707 self.has_any = true;
708 }
709 Border(val) => {
710 self.border_top.set_border(val);
712 self.border_bottom.set_border(val);
713 self.border_left.set_border(val);
714 self.border_right.set_border(val);
715 self.border_block_start.reset();
716 self.border_block_end.reset();
717 self.border_inline_start.reset();
718 self.border_inline_end.reset();
719
720 self.border_image_handler.reset();
722 self.has_any = true;
723 }
724 Unparsed(val) if is_border_property(&val.property_id) => {
725 self.flush(dest, context);
726 self.flush_unparsed(&val, dest, context);
727 }
728 _ => {
729 if self.border_image_handler.will_flush(property) {
730 self.flush(dest, context);
731 }
732
733 return self.border_image_handler.handle_property(property, dest, context)
734 || self.border_radius_handler.handle_property(property, dest, context);
735 }
736 }
737
738 true
739 }
740
741 fn finalize(&mut self, dest: &mut DeclarationList<'i>, context: &mut PropertyHandlerContext<'i, '_>) {
742 self.flush(dest, context);
743 self.flushed_properties = BorderProperty::empty();
744 self.border_image_handler.finalize(dest, context);
745 self.border_radius_handler.finalize(dest, context);
746 }
747}
748
749impl<'i> BorderHandler<'i> {
750 fn flush(&mut self, dest: &mut DeclarationList, context: &mut PropertyHandlerContext<'i, '_>) {
751 if !self.has_any {
752 return;
753 }
754
755 self.has_any = false;
756
757 let logical_supported = !context.should_compile_logical(Feature::LogicalBorders);
758 let logical_shorthand_supported = !context.should_compile_logical(Feature::LogicalBorderShorthand);
759 macro_rules! logical_prop {
760 ($ltr: ident, $ltr_key: ident, $rtl: ident, $rtl_key: ident, $val: expr) => {{
761 context.add_logical_rule(Property::$ltr($val.clone()), Property::$rtl($val.clone()));
762 }};
763 }
764
765 macro_rules! push {
766 ($prop: ident, $val: expr) => {{
767 self.flushed_properties.insert(BorderProperty::$prop);
768 dest.push(Property::$prop($val));
769 }};
770 }
771
772 macro_rules! fallbacks {
773 ($prop: ident => $val: expr) => {{
774 let mut val = $val;
775 if !self.flushed_properties.contains(BorderProperty::$prop) {
776 let fallbacks = val.get_fallbacks(context.targets);
777 for fallback in fallbacks {
778 dest.push(Property::$prop(fallback))
779 }
780 }
781 push!($prop, val);
782 }};
783 }
784
785 macro_rules! prop {
786 (BorderInlineStart => $val: expr) => {
787 if logical_supported {
788 fallbacks!(BorderInlineStart => $val);
789 } else {
790 logical_prop!(BorderLeft, border_left, BorderRight, border_right, $val);
791 }
792 };
793 (BorderInlineStartWidth => $val: expr) => {
794 if logical_supported {
795 push!(BorderInlineStartWidth, $val);
796 } else {
797 logical_prop!(BorderLeftWidth, border_left_width, BorderRightWidth, border_right_width, $val);
798 }
799 };
800 (BorderInlineStartColor => $val: expr) => {
801 if logical_supported {
802 fallbacks!(BorderInlineStartColor => $val);
803 } else {
804 logical_prop!(BorderLeftColor, border_left_color, BorderRightColor, border_right_color, $val);
805 }
806 };
807 (BorderInlineStartStyle => $val: expr) => {
808 if logical_supported {
809 push!(BorderInlineStartStyle, $val);
810 } else {
811 logical_prop!(BorderLeftStyle, border_left_style, BorderRightStyle, border_right_style, $val);
812 }
813 };
814 (BorderInlineEnd => $val: expr) => {
815 if logical_supported {
816 fallbacks!(BorderInlineEnd => $val);
817 } else {
818 logical_prop!(BorderRight, border_right, BorderLeft, border_left, $val);
819 }
820 };
821 (BorderInlineEndWidth => $val: expr) => {
822 if logical_supported {
823 push!(BorderInlineEndWidth, $val);
824 } else {
825 logical_prop!(BorderRightWidth, border_right_width, BorderLeftWidth, border_left_width, $val);
826 }
827 };
828 (BorderInlineEndColor => $val: expr) => {
829 if logical_supported {
830 fallbacks!(BorderInlineEndColor => $val);
831 } else {
832 logical_prop!(BorderRightColor, border_right_color, BorderLeftColor, border_left_color, $val);
833 }
834 };
835 (BorderInlineEndStyle => $val: expr) => {
836 if logical_supported {
837 push!(BorderInlineEndStyle, $val);
838 } else {
839 logical_prop!(BorderRightStyle, border_right_style, BorderLeftStyle, border_left_style, $val);
840 }
841 };
842 (BorderBlockStart => $val: expr) => {
843 if logical_supported {
844 fallbacks!(BorderBlockStart => $val);
845 } else {
846 fallbacks!(BorderTop => $val);
847 }
848 };
849 (BorderBlockStartWidth => $val: expr) => {
850 if logical_supported {
851 push!(BorderBlockStartWidth, $val);
852 } else {
853 push!(BorderTopWidth, $val);
854 }
855 };
856 (BorderBlockStartColor => $val: expr) => {
857 if logical_supported {
858 fallbacks!(BorderBlockStartColor => $val);
859 } else {
860 fallbacks!(BorderTopColor => $val);
861 }
862 };
863 (BorderBlockStartStyle => $val: expr) => {
864 if logical_supported {
865 push!(BorderBlockStartStyle, $val);
866 } else {
867 push!(BorderTopStyle, $val);
868 }
869 };
870 (BorderBlockEnd => $val: expr) => {
871 if logical_supported {
872 fallbacks!(BorderBlockEnd => $val);
873 } else {
874 fallbacks!(BorderBottom => $val);
875 }
876 };
877 (BorderBlockEndWidth => $val: expr) => {
878 if logical_supported {
879 push!(BorderBlockEndWidth, $val);
880 } else {
881 push!(BorderBottomWidth, $val);
882 }
883 };
884 (BorderBlockEndColor => $val: expr) => {
885 if logical_supported {
886 fallbacks!(BorderBlockEndColor => $val);
887 } else {
888 fallbacks!(BorderBottomColor => $val);
889 }
890 };
891 (BorderBlockEndStyle => $val: expr) => {
892 if logical_supported {
893 push!(BorderBlockEndStyle, $val);
894 } else {
895 push!(BorderBottomStyle, $val);
896 }
897 };
898 (BorderLeftColor => $val: expr) => {
899 fallbacks!(BorderLeftColor => $val);
900 };
901 (BorderRightColor => $val: expr) => {
902 fallbacks!(BorderRightColor => $val);
903 };
904 (BorderTopColor => $val: expr) => {
905 fallbacks!(BorderTopColor => $val);
906 };
907 (BorderBottomColor => $val: expr) => {
908 fallbacks!(BorderBottomColor => $val);
909 };
910 (BorderColor => $val: expr) => {
911 fallbacks!(BorderColor => $val);
912 };
913 (BorderBlockColor => $val: expr) => {
914 fallbacks!(BorderBlockColor => $val);
915 };
916 (BorderInlineColor => $val: expr) => {
917 fallbacks!(BorderInlineColor => $val);
918 };
919 (BorderLeft => $val: expr) => {
920 fallbacks!(BorderLeft => $val);
921 };
922 (BorderRight => $val: expr) => {
923 fallbacks!(BorderRight => $val);
924 };
925 (BorderTop => $val: expr) => {
926 fallbacks!(BorderTop => $val);
927 };
928 (BorderBottom => $val: expr) => {
929 fallbacks!(BorderBottom => $val);
930 };
931 (BorderBlockStart => $val: expr) => {
932 fallbacks!(BorderBlockStart => $val);
933 };
934 (BorderBlockEnd => $val: expr) => {
935 fallbacks!(BorderBlockEnd => $val);
936 };
937 (BorderInlineStart => $val: expr) => {
938 fallbacks!(BorderInlineStart => $val);
939 };
940 (BorderInlineEnd => $val: expr) => {
941 fallbacks!(BorderInlineEnd => $val);
942 };
943 (BorderInline => $val: expr) => {
944 fallbacks!(BorderInline => $val);
945 };
946 (BorderBlock => $val: expr) => {
947 fallbacks!(BorderBlock => $val);
948 };
949 (Border => $val: expr) => {
950 fallbacks!(Border => $val);
951 };
952 ($prop: ident => $val: expr) => {
953 push!($prop, $val);
954 };
955 }
956
957 macro_rules! flush_category {
958 (
959 $block_start_prop: ident,
960 $block_start_width: ident,
961 $block_start_style: ident,
962 $block_start_color: ident,
963 $block_start: expr,
964 $block_end_prop: ident,
965 $block_end_width: ident,
966 $block_end_style: ident,
967 $block_end_color: ident,
968 $block_end: expr,
969 $inline_start_prop: ident,
970 $inline_start_width: ident,
971 $inline_start_style: ident,
972 $inline_start_color: ident,
973 $inline_start: expr,
974 $inline_end_prop: ident,
975 $inline_end_width: ident,
976 $inline_end_style: ident,
977 $inline_end_color: ident,
978 $inline_end: expr,
979 $is_logical: expr
980 ) => {
981 macro_rules! shorthand {
982 ($prop: ident, $key: ident) => {{
983 let has_prop = $block_start.$key.is_some() && $block_end.$key.is_some() && $inline_start.$key.is_some() && $inline_end.$key.is_some();
984 if has_prop {
985 if !$is_logical || ($block_start.$key == $block_end.$key && $block_end.$key == $inline_start.$key && $inline_start.$key == $inline_end.$key) {
986 let rect = $prop {
987 top: std::mem::take(&mut $block_start.$key).unwrap(),
988 right: std::mem::take(&mut $inline_end.$key).unwrap(),
989 bottom: std::mem::take(&mut $block_end.$key).unwrap(),
990 left: std::mem::take(&mut $inline_start.$key).unwrap()
991 };
992 prop!($prop => rect);
993 }
994 }
995 }};
996 }
997
998 macro_rules! logical_shorthand {
999 ($prop: ident, $key: ident, $start: expr, $end: expr) => {{
1000 let has_prop = $start.$key.is_some() && $end.$key.is_some();
1001 if has_prop {
1002 prop!($prop => $prop {
1003 start: std::mem::take(&mut $start.$key).unwrap(),
1004 end: std::mem::take(&mut $end.$key).unwrap(),
1005 });
1006 $end.$key = None;
1007 }
1008 has_prop
1009 }};
1010 }
1011
1012 if $block_start.is_valid() && $block_end.is_valid() && $inline_start.is_valid() && $inline_end.is_valid() {
1013 let top_eq_bottom = $block_start == $block_end;
1014 let left_eq_right = $inline_start == $inline_end;
1015 let top_eq_left = $block_start == $inline_start;
1016 let top_eq_right = $block_start == $inline_end;
1017 let bottom_eq_left = $block_end == $inline_start;
1018 let bottom_eq_right = $block_end == $inline_end;
1019
1020 macro_rules! is_eq {
1021 ($key: ident) => {
1022 $block_start.$key == $block_end.$key &&
1023 $inline_start.$key == $inline_end.$key &&
1024 $inline_start.$key == $block_start.$key
1025 };
1026 }
1027
1028 macro_rules! prop_diff {
1029 ($border: expr, $fallback: expr, $border_fallback: literal) => {
1030 if !$is_logical && is_eq!(color) && is_eq!(style) {
1031 prop!(Border => $border.to_border());
1032 shorthand!(BorderWidth, width);
1033 } else if !$is_logical && is_eq!(width) && is_eq!(style) {
1034 prop!(Border => $border.to_border());
1035 shorthand!(BorderColor, color);
1036 } else if !$is_logical && is_eq!(width) && is_eq!(color) {
1037 prop!(Border => $border.to_border());
1038 shorthand!(BorderStyle, style);
1039 } else {
1040 if $border_fallback {
1041 prop!(Border => $border.to_border());
1042 }
1043 $fallback
1044 }
1045 };
1046 }
1047
1048 macro_rules! side_diff {
1049 ($border: expr, $other: expr, $prop: ident, $width: ident, $style: ident, $color: ident) => {
1050 let eq_width = $border.width == $other.width;
1051 let eq_style = $border.style == $other.style;
1052 let eq_color = $border.color == $other.color;
1053
1054 if eq_width && eq_style {
1057 prop!($color => $other.color.clone().unwrap());
1058 } else if eq_width && eq_color {
1059 prop!($style => $other.style.clone().unwrap());
1060 } else if eq_style && eq_color {
1061 prop!($width => $other.width.clone().unwrap());
1062 } else {
1063 prop!($prop => $other.to_border());
1064 }
1065 };
1066 }
1067
1068 if top_eq_bottom && top_eq_left && top_eq_right {
1069 prop!(Border => $block_start.to_border());
1070 } else if top_eq_bottom && top_eq_left {
1071 prop!(Border => $block_start.to_border());
1072 side_diff!($block_start, $inline_end, $inline_end_prop, $inline_end_width, $inline_end_style, $inline_end_color);
1073 } else if top_eq_bottom && top_eq_right {
1074 prop!(Border => $block_start.to_border());
1075 side_diff!($block_start, $inline_start, $inline_start_prop, $inline_start_width, $inline_start_style, $inline_start_color);
1076 } else if left_eq_right && bottom_eq_left {
1077 prop!(Border => $inline_start.to_border());
1078 side_diff!($inline_start, $block_start, $block_start_prop, $block_start_width, $block_start_style, $block_start_color);
1079 } else if left_eq_right && top_eq_left {
1080 prop!(Border => $inline_start.to_border());
1081 side_diff!($inline_start, $block_end, $block_end_prop, $block_end_width, $block_end_style, $block_end_color);
1082 } else if top_eq_bottom {
1083 prop_diff!($block_start, {
1084 let mut handled = false;
1086 if $is_logical {
1087 let mut diff = 0;
1088 if $inline_start.width != $block_start.width || $inline_end.width != $block_start.width {
1089 diff += 1;
1090 }
1091 if $inline_start.style != $block_start.style || $inline_end.style != $block_start.style {
1092 diff += 1;
1093 }
1094 if $inline_start.color != $block_start.color || $inline_end.color != $block_start.color {
1095 diff += 1;
1096 }
1097
1098 if diff == 1 {
1099 if $inline_start.width != $block_start.width {
1100 prop!(BorderInlineWidth => BorderInlineWidth {
1101 start: $inline_start.width.clone().unwrap(),
1102 end: $inline_end.width.clone().unwrap(),
1103 });
1104 handled = true;
1105 } else if $inline_start.style != $block_start.style {
1106 prop!(BorderInlineStyle => BorderInlineStyle {
1107 start: $inline_start.style.clone().unwrap(),
1108 end: $inline_end.style.clone().unwrap()
1109 });
1110 handled = true;
1111 } else if $inline_start.color != $block_start.color {
1112 prop!(BorderInlineColor => BorderInlineColor {
1113 start: $inline_start.color.clone().unwrap(),
1114 end: $inline_end.color.clone().unwrap()
1115 });
1116 handled = true;
1117 }
1118 } else if diff > 1 && $inline_start.width == $inline_end.width && $inline_start.style == $inline_end.style && $inline_start.color == $inline_end.color {
1119 prop!(BorderInline => $inline_start.to_border());
1120 handled = true;
1121 }
1122 }
1123
1124 if !handled {
1125 side_diff!($block_start, $inline_start, $inline_start_prop, $inline_start_width, $inline_start_style, $inline_start_color);
1126 side_diff!($block_start, $inline_end, $inline_end_prop, $inline_end_width, $inline_end_style, $inline_end_color);
1127 }
1128 }, true);
1129 } else if left_eq_right {
1130 prop_diff!($inline_start, {
1131 side_diff!($inline_start, $block_start, $block_start_prop, $block_start_width, $block_start_style, $block_start_color);
1133 side_diff!($inline_start, $block_end, $block_end_prop, $block_end_width, $block_end_style, $block_end_color);
1134 }, true);
1135 } else if bottom_eq_right {
1136 prop_diff!($block_end, {
1137 side_diff!($block_end, $block_start, $block_start_prop, $block_start_width, $block_start_style, $block_start_color);
1138 side_diff!($block_end, $inline_start, $inline_start_prop, $inline_start_width, $inline_start_style, $inline_start_color);
1139 }, true);
1140 } else {
1141 prop_diff!($block_start, {
1142 prop!($block_start_prop => $block_start.to_border());
1143 prop!($block_end_prop => $block_end.to_border());
1144 prop!($inline_start_prop => $inline_start.to_border());
1145 prop!($inline_end_prop => $inline_end.to_border());
1146 }, false);
1147 }
1148 } else {
1149 shorthand!(BorderStyle, style);
1150 shorthand!(BorderWidth, width);
1151 shorthand!(BorderColor, color);
1152
1153 macro_rules! side {
1154 ($val: expr, $shorthand: ident, $width: ident, $style: ident, $color: ident) => {
1155 if $val.is_valid() {
1156 prop!($shorthand => $val.to_border());
1157 } else {
1158 if let Some(style) = &$val.style {
1159 prop!($style => style.clone());
1160 }
1161
1162 if let Some(width) = &$val.width {
1163 prop!($width => width.clone());
1164 }
1165
1166 if let Some(color) = &$val.color {
1167 prop!($color => color.clone());
1168 }
1169 }
1170 };
1171 }
1172
1173 if $is_logical && $block_start == $block_end && $block_start.is_valid() {
1174 if logical_supported {
1175 if logical_shorthand_supported {
1176 prop!(BorderBlock => $block_start.to_border());
1177 } else {
1178 prop!(BorderBlockStart => $block_start.to_border());
1179 prop!(BorderBlockEnd => $block_start.to_border());
1180 }
1181 } else {
1182 prop!(BorderTop => $block_start.to_border());
1183 prop!(BorderBottom => $block_start.to_border());
1184 }
1185 } else {
1186 if $is_logical && logical_shorthand_supported && !$block_start.is_valid() && !$block_end.is_valid() {
1187 logical_shorthand!(BorderBlockStyle, style, $block_start, $block_end);
1188 logical_shorthand!(BorderBlockWidth, width, $block_start, $block_end);
1189 logical_shorthand!(BorderBlockColor, color, $block_start, $block_end);
1190 }
1191
1192 side!($block_start, $block_start_prop, $block_start_width, $block_start_style, $block_start_color);
1193 side!($block_end, $block_end_prop, $block_end_width, $block_end_style, $block_end_color);
1194 }
1195
1196 if $is_logical && $inline_start == $inline_end && $inline_start.is_valid() {
1197 if logical_supported {
1198 if logical_shorthand_supported {
1199 prop!(BorderInline => $inline_start.to_border());
1200 } else {
1201 prop!(BorderInlineStart => $inline_start.to_border());
1202 prop!(BorderInlineEnd => $inline_start.to_border());
1203 }
1204 } else {
1205 prop!(BorderLeft => $inline_start.to_border());
1206 prop!(BorderRight => $inline_start.to_border());
1207 }
1208 } else {
1209 if $is_logical && !$inline_start.is_valid() && !$inline_end.is_valid() {
1210 if logical_shorthand_supported {
1211 logical_shorthand!(BorderInlineStyle, style, $inline_start, $inline_end);
1212 logical_shorthand!(BorderInlineWidth, width, $inline_start, $inline_end);
1213 logical_shorthand!(BorderInlineColor, color, $inline_start, $inline_end);
1214 } else {
1215 macro_rules! inline_prop {
1217 ($key: ident, $left: ident, $right: ident) => {
1218 if $inline_start.$key.is_some() && $inline_start.$key == $inline_end.$key {
1219 prop!($left => std::mem::take(&mut $inline_start.$key).unwrap());
1220 prop!($right => std::mem::take(&mut $inline_end.$key).unwrap());
1221 }
1222 }
1223 }
1224
1225 inline_prop!(style, BorderLeftStyle, BorderRightStyle);
1226 inline_prop!(width, BorderLeftWidth, BorderRightWidth);
1227 inline_prop!(color, BorderLeftColor, BorderRightColor);
1228 }
1229 }
1230
1231 side!($inline_start, $inline_start_prop, $inline_start_width, $inline_start_style, $inline_start_color);
1232 side!($inline_end, $inline_end_prop, $inline_end_width, $inline_end_style, $inline_end_color);
1233 }
1234 }
1235 };
1236 }
1237
1238 flush_category!(
1239 BorderTop,
1240 BorderTopWidth,
1241 BorderTopStyle,
1242 BorderTopColor,
1243 self.border_top,
1244 BorderBottom,
1245 BorderBottomWidth,
1246 BorderBottomStyle,
1247 BorderBottomColor,
1248 self.border_bottom,
1249 BorderLeft,
1250 BorderLeftWidth,
1251 BorderLeftStyle,
1252 BorderLeftColor,
1253 self.border_left,
1254 BorderRight,
1255 BorderRightWidth,
1256 BorderRightStyle,
1257 BorderRightColor,
1258 self.border_right,
1259 false
1260 );
1261
1262 flush_category!(
1263 BorderBlockStart,
1264 BorderBlockStartWidth,
1265 BorderBlockStartStyle,
1266 BorderBlockStartColor,
1267 self.border_block_start,
1268 BorderBlockEnd,
1269 BorderBlockEndWidth,
1270 BorderBlockEndStyle,
1271 BorderBlockEndColor,
1272 self.border_block_end,
1273 BorderInlineStart,
1274 BorderInlineStartWidth,
1275 BorderInlineStartStyle,
1276 BorderInlineStartColor,
1277 self.border_inline_start,
1278 BorderInlineEnd,
1279 BorderInlineEndWidth,
1280 BorderInlineEndStyle,
1281 BorderInlineEndColor,
1282 self.border_inline_end,
1283 true
1284 );
1285
1286 self.border_top.reset();
1287 self.border_bottom.reset();
1288 self.border_left.reset();
1289 self.border_right.reset();
1290 self.border_block_start.reset();
1291 self.border_block_end.reset();
1292 self.border_inline_start.reset();
1293 self.border_inline_end.reset();
1294 }
1295
1296 fn flush_unparsed(
1297 &mut self,
1298 unparsed: &UnparsedProperty<'i>,
1299 dest: &mut DeclarationList<'i>,
1300 context: &mut PropertyHandlerContext<'i, '_>,
1301 ) {
1302 let logical_supported = !context.should_compile_logical(Feature::LogicalBorders);
1303 if logical_supported {
1304 let mut unparsed = unparsed.clone();
1305 context.add_unparsed_fallbacks(&mut unparsed);
1306 self
1307 .flushed_properties
1308 .insert(BorderProperty::try_from(&unparsed.property_id).unwrap());
1309 dest.push(Property::Unparsed(unparsed));
1310 return;
1311 }
1312
1313 macro_rules! prop {
1314 ($id: ident) => {{
1315 let mut unparsed = unparsed.with_property_id(PropertyId::$id);
1316 context.add_unparsed_fallbacks(&mut unparsed);
1317 dest.push(Property::Unparsed(unparsed));
1318 self.flushed_properties.insert(BorderProperty::$id);
1319 }};
1320 }
1321
1322 macro_rules! logical_prop {
1323 ($ltr: ident, $ltr_key: ident, $rtl: ident, $rtl_key: ident) => {{
1324 context.add_logical_rule(
1325 Property::Unparsed(unparsed.with_property_id(PropertyId::$ltr)),
1326 Property::Unparsed(unparsed.with_property_id(PropertyId::$rtl)),
1327 );
1328 }};
1329 }
1330
1331 use PropertyId::*;
1332 match &unparsed.property_id {
1333 BorderInlineStart => logical_prop!(BorderLeft, border_left, BorderRight, border_right),
1334 BorderInlineStartWidth => {
1335 logical_prop!(BorderLeftWidth, border_left_width, BorderRightWidth, border_right_width)
1336 }
1337 BorderInlineStartColor => {
1338 logical_prop!(BorderLeftColor, border_left_color, BorderRightColor, border_right_color)
1339 }
1340 BorderInlineStartStyle => {
1341 logical_prop!(BorderLeftStyle, border_left_style, BorderRightStyle, border_right_style)
1342 }
1343 BorderInlineEnd => logical_prop!(BorderRight, border_right, BorderLeft, border_left),
1344 BorderInlineEndWidth => {
1345 logical_prop!(BorderRightWidth, border_right_width, BorderLeftWidth, border_left_width)
1346 }
1347 BorderInlineEndColor => {
1348 logical_prop!(BorderRightColor, border_right_color, BorderLeftColor, border_left_color)
1349 }
1350 BorderInlineEndStyle => {
1351 logical_prop!(BorderRightStyle, border_right_style, BorderLeftStyle, border_left_style)
1352 }
1353 BorderBlockStart => prop!(BorderTop),
1354 BorderBlockStartWidth => prop!(BorderTopWidth),
1355 BorderBlockStartColor => prop!(BorderTopColor),
1356 BorderBlockStartStyle => prop!(BorderTopStyle),
1357 BorderBlockEnd => prop!(BorderBottom),
1358 BorderBlockEndWidth => prop!(BorderBottomWidth),
1359 BorderBlockEndColor => prop!(BorderBottomColor),
1360 BorderBlockEndStyle => prop!(BorderBottomStyle),
1361 property_id => {
1362 let mut unparsed = unparsed.clone();
1363 context.add_unparsed_fallbacks(&mut unparsed);
1364 dest.push(Property::Unparsed(unparsed));
1365 self.flushed_properties.insert(BorderProperty::try_from(property_id).unwrap());
1366 }
1367 }
1368 }
1369}
1370
1371fn is_border_property(property_id: &PropertyId) -> bool {
1372 match property_id {
1373 PropertyId::BorderTopColor
1374 | PropertyId::BorderBottomColor
1375 | PropertyId::BorderLeftColor
1376 | PropertyId::BorderRightColor
1377 | PropertyId::BorderBlockStartColor
1378 | PropertyId::BorderBlockEndColor
1379 | PropertyId::BorderBlockColor
1380 | PropertyId::BorderInlineStartColor
1381 | PropertyId::BorderInlineEndColor
1382 | PropertyId::BorderInlineColor
1383 | PropertyId::BorderTopWidth
1384 | PropertyId::BorderBottomWidth
1385 | PropertyId::BorderLeftWidth
1386 | PropertyId::BorderRightWidth
1387 | PropertyId::BorderBlockStartWidth
1388 | PropertyId::BorderBlockEndWidth
1389 | PropertyId::BorderBlockWidth
1390 | PropertyId::BorderInlineStartWidth
1391 | PropertyId::BorderInlineEndWidth
1392 | PropertyId::BorderInlineWidth
1393 | PropertyId::BorderTopStyle
1394 | PropertyId::BorderBottomStyle
1395 | PropertyId::BorderLeftStyle
1396 | PropertyId::BorderRightStyle
1397 | PropertyId::BorderBlockStartStyle
1398 | PropertyId::BorderBlockEndStyle
1399 | PropertyId::BorderBlockStyle
1400 | PropertyId::BorderInlineStartStyle
1401 | PropertyId::BorderInlineEndStyle
1402 | PropertyId::BorderInlineStyle
1403 | PropertyId::BorderTop
1404 | PropertyId::BorderBottom
1405 | PropertyId::BorderLeft
1406 | PropertyId::BorderRight
1407 | PropertyId::BorderBlockStart
1408 | PropertyId::BorderBlockEnd
1409 | PropertyId::BorderInlineStart
1410 | PropertyId::BorderInlineEnd
1411 | PropertyId::BorderBlock
1412 | PropertyId::BorderInline
1413 | PropertyId::BorderWidth
1414 | PropertyId::BorderStyle
1415 | PropertyId::BorderColor
1416 | PropertyId::Border => true,
1417 _ => false,
1418 }
1419}