1use alloc::{boxed::Box, rc::Rc, string::String, vec::Vec};
4use core::{cell::RefCell, num::NonZeroUsize};
5use parser::WarningKind;
6
7use hashbrown::HashMap;
8
9use super::property::*;
10use super::query::*;
11use super::*;
12use crate::group::StyleSheetResource;
13use crate::length_num::LengthNum;
14use crate::parser::Warning;
15
16mod selector;
17pub use selector::PseudoElements;
18pub(crate) use selector::{
19 Attribute, AttributeFlags, AttributeOperator, PseudoClasses, Selector, SelectorFragment,
20 SelectorRelationType, SELECTOR_WHITESPACE,
21};
22mod rule;
23pub use rule::Rule;
24mod media;
25pub use media::*;
26pub(crate) mod keyframes;
27pub use keyframes::*;
28mod font_face;
29pub use font_face::*;
30pub mod borrow;
31pub mod borrow_resource;
32pub mod str_store;
33pub use rule::PropertyMeta;
34
35#[derive(Debug, Clone)]
36pub(crate) struct CompiledStyleSheet {
37 imports: Vec<(String, Option<Rc<Media>>)>,
38 linked: bool,
39 ss: Rc<RefCell<StyleSheet>>,
40}
41
42impl CompiledStyleSheet {
43 pub(crate) fn new() -> Self {
44 Self {
45 imports: Vec::with_capacity(0),
46 linked: false,
47 ss: Rc::new(RefCell::new(StyleSheet {
48 rules: vec![],
49 index: StyleSheetIndex::NeedUpdate,
50 font_face: vec![],
51 keyframes: vec![],
52 })),
53 }
54 }
55
56 #[cfg(feature = "deserialize")]
57 pub(crate) fn new_with_config(
58 imports: Vec<(String, Option<Rc<Media>>)>,
59 rules: Vec<Rc<Rule>>,
60 font_face: Vec<Rc<FontFace>>,
61 keyframes: Vec<Rc<KeyFrames>>,
62 ) -> Self {
63 Self {
64 imports,
65 linked: false,
66 ss: Rc::new(RefCell::new(StyleSheet {
67 rules,
68 index: StyleSheetIndex::NeedUpdate,
69 font_face,
70 keyframes,
71 })),
72 }
73 }
74
75 pub(crate) fn list_deps(&self) -> Vec<String> {
76 self.imports.iter().map(|(s, _)| s.clone()).collect()
77 }
78
79 pub(crate) fn add_import(&mut self, path: String, media: Option<Rc<Media>>) {
80 self.imports.push((path, media));
81 }
82
83 pub(crate) fn add_rule(&mut self, rule: Box<Rule>) {
84 self.ss.borrow_mut().add_rule(rule);
85 }
86
87 pub(crate) fn add_font_face(&mut self, ff: FontFace) {
88 self.ss.borrow_mut().add_font_face(ff)
89 }
90
91 pub(crate) fn add_keyframes(&mut self, keyframes: KeyFrames) {
92 self.ss.borrow_mut().add_keyframes(keyframes)
93 }
94
95 pub(crate) fn add_tag_name_prefix(&mut self, prefix: &str) {
96 let mut ss = self.ss.borrow_mut();
97 for rule in ss.rules.iter_mut() {
98 let rule = Rc::make_mut(rule);
99 for frag in rule.selector.fragments.iter_mut() {
100 frag.add_tag_name_prefix(prefix)
101 }
102 }
103 }
104
105 pub(crate) fn link(
106 &mut self,
107 res: &StyleSheetResource,
108 scope: Option<NonZeroUsize>,
109 ) -> (LinkedStyleSheet, Vec<Warning>) {
110 let mut sheets = vec![];
111 let mut warnings = vec![];
112 self.link_self(res, &mut sheets, None, &mut warnings);
113 (LinkedStyleSheet { sheets, scope }, warnings)
114 }
115
116 #[allow(clippy::type_complexity)]
117 fn link_self(
118 &mut self,
119 res: &StyleSheetResource,
120 sheets: &mut Vec<(Rc<RefCell<StyleSheet>>, Option<Rc<Media>>)>,
121 parent_media: Option<Rc<Media>>,
122 warnings: &mut Vec<Warning>,
123 ) {
124 if !self.linked {
125 self.ss.borrow_mut().update_index();
126 self.linked = true;
127 }
128 for (target_path, media) in self.imports.iter() {
129 if let Some(target) = res.refs.get(target_path) {
130 if let Ok(mut target) = target.try_borrow_mut() {
131 let m = match media.clone() {
132 None => parent_media.clone(),
133 Some(mut m) => {
134 Rc::make_mut(&mut m).parent.clone_from(&parent_media);
135 Some(m)
136 }
137 };
138 target.link_self(res, sheets, m, warnings);
139 } else {
140 warnings.push(Warning {
141 kind: WarningKind::RecursiveImports,
142 message: format!(
143 "detected recursive style sheet import for {:?}",
144 target_path
145 )
146 .into(),
147 start_line: 0,
148 start_col: 0,
149 end_line: 0,
150 end_col: 0,
151 });
152 }
153 } else {
154 warnings.push(Warning {
155 kind: WarningKind::MissingImportTarget,
156 message: format!(r#"target style sheet {:?} not found"#, target_path).into(),
157 start_line: 0,
158 start_col: 0,
159 end_line: 0,
160 end_col: 0,
161 });
162 }
163 }
164 sheets.push((self.ss.clone(), parent_media));
165 }
166
167 #[cfg(feature = "serialize")]
168 pub(crate) fn serialize_bincode(&self) -> Vec<u8> {
169 use float_pigment_consistent_bincode::Options;
170 let s = borrow::StyleSheet::from_sheet(self);
171 float_pigment_consistent_bincode::DefaultOptions::new()
172 .allow_trailing_bytes()
173 .serialize(&s)
174 .unwrap()
175 }
176
177 #[cfg(feature = "deserialize")]
178 pub(crate) fn deserialize_bincode(s: Vec<u8>) -> Result<Self, String> {
179 use float_pigment_consistent_bincode::Options;
180 let s: Result<borrow::StyleSheet, _> =
181 float_pigment_consistent_bincode::DefaultOptions::new()
182 .allow_trailing_bytes()
183 .deserialize(&s);
184 match s {
185 Ok(ss) => Ok(ss.into_sheet()),
186 Err(err) => Err(format!(
187 "Failed to deserialize bincode formatted style sheet: {}",
188 err
189 )),
190 }
191 }
192
193 #[cfg(feature = "deserialize")]
194 pub(crate) unsafe fn deserialize_bincode_zero_copy(
195 ptr: *const [u8],
196 drop_callback: impl 'static + FnOnce(),
197 ) -> Result<Self, String> {
198 use float_pigment_consistent_bincode::Options;
199 borrow::de_static_ref_zero_copy_env(
200 ptr,
201 |s| {
202 let s: Result<borrow::StyleSheet, _> =
203 float_pigment_consistent_bincode::DefaultOptions::new()
204 .allow_trailing_bytes()
205 .deserialize(s);
206 match s {
207 Ok(ss) => Ok(ss.into_sheet()),
208 Err(err) => Err(format!(
209 "Failed to deserialize bincode formatted style sheet: {}",
210 err
211 )),
212 }
213 },
214 drop_callback,
215 )
216 }
217
218 #[cfg(all(feature = "serialize", feature = "serialize_json"))]
219 pub(crate) fn serialize_json(&self) -> String {
220 let s = borrow::StyleSheet::from_sheet(self);
221 serde_json::to_string(&s).unwrap()
222 }
223
224 #[cfg(all(feature = "serialize", feature = "deserialize_json"))]
225 pub(crate) fn deserialize_json(s: &str) -> Result<Self, String> {
226 let s: Result<borrow::StyleSheet, _> = serde_json::from_str(s);
227 match s {
228 Ok(ss) => Ok(ss.into_sheet()),
229 Err(err) => Err(format!(
230 "Failed to deserialize json formatted style sheet: {}",
231 err
232 )),
233 }
234 }
235
236 #[cfg(all(feature = "serialize", feature = "deserialize_json"))]
237 pub(crate) unsafe fn deserialize_json_zero_copy(
238 ptr: *mut [u8],
239 drop_callback: impl 'static + FnOnce(),
240 ) -> Result<Self, String> {
241 borrow::de_static_ref_zero_copy_env(
242 ptr,
243 |s| {
244 let s: Result<borrow::StyleSheet, _> =
245 serde_json::from_str(std::str::from_utf8_unchecked(s));
246 match s {
247 Ok(ss) => Ok(ss.into_sheet()),
248 Err(err) => Err(format!(
249 "Failed to deserialize json formatted style sheet: {}",
250 err
251 )),
252 }
253 },
254 drop_callback,
255 )
256 }
257}
258
259#[allow(clippy::type_complexity)]
264#[derive(Debug, Clone)]
265pub struct LinkedStyleSheet {
266 sheets: Vec<(Rc<RefCell<StyleSheet>>, Option<Rc<Media>>)>,
267 scope: Option<NonZeroUsize>,
268}
269
270impl LinkedStyleSheet {
271 pub fn new_empty() -> Self {
273 let mut ss = CompiledStyleSheet::new();
274 ss.link(&StyleSheetResource::new(), None).0
275 }
276
277 pub fn scope(&self) -> Option<NonZeroUsize> {
279 self.scope
280 }
281
282 pub fn sheets(&self) -> Vec<Rc<RefCell<StyleSheet>>> {
290 self.sheets.iter().map(|x| x.0.clone()).collect::<Vec<_>>()
291 }
292
293 #[doc(hidden)]
294 pub fn rules_count(&self, sheet_index: Option<usize>) -> Option<u32> {
295 if let Some(idx) = sheet_index {
296 if self.sheets.len() > (idx + 1usize) {
297 return None;
298 }
299 return Some(self.sheets.get(idx).unwrap().0.borrow().rules_count());
300 }
301 let mut count = 0;
302 self.sheets.iter().for_each(|item| {
303 count += item.0.borrow().rules_count();
304 });
305 Some(count)
306 }
307
308 pub fn parse(source: &str, scope: Option<NonZeroUsize>) -> (Self, Vec<Warning>) {
313 let (mut ss, mut warnings) = parser::parse_style_sheet("", source);
314 let (ret, mut w2) = ss.link(&StyleSheetResource::new(), scope);
315 warnings.append(&mut w2);
316 (ret, warnings)
317 }
318
319 pub fn get_rule(&self, mut rule_index: u32) -> Option<Rc<Rule>> {
321 for (sheet, _media) in self.sheets.iter() {
322 let sheet = sheet.borrow();
323 if rule_index < sheet.rules_count() {
324 return sheet.get_rule(rule_index).cloned();
325 }
326 rule_index -= sheet.rules_count();
327 }
328 None
329 }
330
331 pub fn add_rule(&mut self, rule: Box<Rule>) -> u32 {
336 let mut rule_index = 0;
337 for (sheet, _media) in self.sheets.iter() {
338 rule_index += sheet.borrow().rules_count();
339 }
340 self.sheets
341 .last_mut()
342 .unwrap()
343 .0
344 .borrow_mut()
345 .add_rule(rule);
346 rule_index
347 }
348
349 pub fn replace_rule(
355 &mut self,
356 mut rule_index: u32,
357 rule: Box<Rule>,
358 ) -> Result<Rc<Rule>, Box<Rule>> {
359 for (sheet, _media) in self.sheets.iter_mut() {
360 let mut sheet = sheet.borrow_mut();
361 if rule_index < sheet.rules_count() {
362 return sheet.replace_rule(rule_index, rule);
363 }
364 rule_index -= sheet.rules_count();
365 }
366 Err(rule)
367 }
368
369 pub(crate) fn for_each_matched_rule<L: LengthNum, T: StyleNode>(
370 &self,
371 query: &[T],
372 media_query_status: &MediaQueryStatus<L>,
373 sheet_index: u16,
374 mut f: impl FnMut(MatchedRuleRef),
375 ) {
376 let mut rule_index_offset = 1;
378 for (sheet, media) in self.sheets.iter() {
379 if let Some(media) = media {
380 if !media.is_valid(media_query_status) {
381 continue;
382 }
383 }
384 sheet.borrow_mut().for_each_matched_rule(
385 query,
386 media_query_status,
387 self.scope,
388 sheet_index,
389 rule_index_offset,
390 &mut f,
391 );
392 rule_index_offset += sheet.borrow().rules_count();
393 }
394 }
395
396 pub(crate) fn search_keyframes<L: LengthNum>(
397 &self,
398 style_scope: Option<NonZeroUsize>,
399 name: &str,
400 media_query_status: &MediaQueryStatus<L>,
401 ) -> Option<Rc<KeyFrames>> {
402 if self.scope.is_some() && self.scope != style_scope {
403 return None;
404 }
405 for (sheet, media) in self.sheets.iter() {
406 if let Some(media) = media {
407 if !media.is_valid(media_query_status) {
408 continue;
409 }
410 }
411 for k in sheet.borrow().keyframes.iter().rev() {
413 if k.ident.as_str() == name {
414 return Some(k.clone());
415 }
416 }
417 }
418 None
419 }
420
421 pub fn get_font_face(&self) -> Vec<Rc<FontFace>> {
423 let mut ret = vec![];
424 for (sheet, _) in self.sheets.iter() {
425 let sheet = sheet.borrow();
426 sheet.font_face().iter().for_each(|ff| ret.push(ff.clone()));
427 }
428 ret
429 }
430}
431
432#[derive(Clone)]
434pub struct StyleSheet {
435 rules: Vec<Rc<Rule>>,
436 index: StyleSheetIndex,
437 font_face: Vec<Rc<FontFace>>,
438 keyframes: Vec<Rc<KeyFrames>>,
439}
440
441#[derive(Clone)]
442enum StyleSheetIndex {
443 NeedUpdate,
444 Updated {
445 class_index: HashMap<String, Vec<Rc<Rule>>>,
446 class_unindexed: Vec<Rc<Rule>>,
447 },
448}
449
450impl core::fmt::Debug for StyleSheet {
451 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
452 write!(f, "StyleSheet {{")?;
453 for rule in self.rules.iter() {
454 write!(f, " {:?}", rule)?;
455 }
456 for font_face in self.font_face.iter() {
457 write!(f, " {:?}", font_face)?;
458 }
459 for keyframes in self.keyframes.iter() {
460 write!(f, " {:?}", keyframes)?;
461 }
462 write!(f, " }}")
463 }
464}
465
466impl core::fmt::Display for StyleSheet {
467 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
468 for rule in self.rules.iter() {
469 write!(f, " {}", rule)?;
470 }
471 for font_face in self.font_face.iter() {
472 write!(f, " {}", font_face)?;
473 }
474 for keyframes in self.keyframes.iter() {
475 write!(f, " {}", keyframes)?;
476 }
477 Ok(())
478 }
479}
480
481impl StyleSheet {
482 #[doc(hidden)]
483 #[allow(clippy::should_implement_trait)]
484 pub fn from_str(s: &str) -> LinkedStyleSheet {
485 let (mut ss, warnings) = parser::parse_style_sheet("", s);
486 for warning in warnings {
487 warn!("{:?}", warning);
488 }
489 let ret = ss.link(&StyleSheetResource::new(), None);
490 ret.0
491 }
492
493 #[doc(hidden)]
494 pub fn from_str_with_path(path: &str, s: &str) -> LinkedStyleSheet {
495 let (mut ss, warnings) = parser::parse_style_sheet(path, s);
496 for warning in warnings {
497 warn!("{:?}", warning);
498 }
499 let ret = ss.link(&StyleSheetResource::new(), None);
500 ret.0
501 }
502
503 fn rules_count(&self) -> u32 {
504 self.rules.len().min(u32::MAX as usize) as u32
505 }
506
507 fn get_rule(&self, rule_index: u32) -> Option<&Rc<Rule>> {
508 self.rules.get(rule_index as usize)
509 }
510
511 fn add_rule(&mut self, mut rule: Box<Rule>) {
512 rule.index = self.rules.len() as u32;
513 self.rules.push(Rc::from(rule));
514 self.index = StyleSheetIndex::NeedUpdate;
515 }
516
517 fn replace_rule(
518 &mut self,
519 rule_index: u32,
520 mut rule: Box<Rule>,
521 ) -> Result<Rc<Rule>, Box<Rule>> {
522 let index = rule_index as usize;
523 if index < self.rules.len() {
524 rule.index = rule_index;
525 let mut rule = Rc::from(rule);
526 core::mem::swap(&mut self.rules[index], &mut rule);
527 self.index = StyleSheetIndex::NeedUpdate;
528 Ok(rule)
529 } else {
530 Err(rule)
531 }
532 }
533
534 fn update_index(&mut self) {
535 if let StyleSheetIndex::NeedUpdate = &self.index {
536 let mut class_index: HashMap<String, Vec<Rc<Rule>>> = HashMap::default();
537 let mut class_unindexed = vec![];
538 for rule in self.rules.iter() {
539 let index_classes = rule.selector.get_index_classes();
540 for c in index_classes {
541 if !c.is_empty() {
542 let c = class_index.entry(c).or_default();
543 c.push(rule.clone());
544 } else {
545 class_unindexed.push(rule.clone());
546 }
547 }
548 }
549 self.index = StyleSheetIndex::Updated {
550 class_index,
551 class_unindexed,
552 };
553 }
554 }
555
556 fn for_each_matched_rule<L: LengthNum, T: StyleNode>(
557 &mut self,
558 query: &[T],
559 media_query_status: &MediaQueryStatus<L>,
560 sheet_style_scope: Option<NonZeroUsize>,
561 sheet_index: u16,
562 rule_index_offset: u32,
563 mut f: impl FnMut(MatchedRuleRef),
564 ) {
565 self.update_index();
566 if let StyleSheetIndex::Updated {
567 class_index,
568 class_unindexed,
569 } = &self.index
570 {
571 if sheet_style_scope.is_none()
572 || query
573 .last()
574 .is_some_and(|x| x.contain_scope(sheet_style_scope))
575 {
576 for r in class_unindexed.iter() {
577 if let Some(selector_weight) =
578 r.match_query(query, media_query_status, sheet_style_scope)
579 {
580 let weight = RuleWeight::new(
581 selector_weight,
582 sheet_index,
583 rule_index_offset + r.index,
584 );
585 f(MatchedRuleRef { rule: r, weight });
586 }
587 }
588 }
589 let query_last = match query.last() {
590 Some(x) => x,
591 None => return,
592 };
593 for class in query_last.classes() {
594 if sheet_style_scope.is_none() || sheet_style_scope == class.scope() {
595 if let Some(rules) = class_index.get(class.name()) {
596 for r in rules {
597 if let Some(selector_weight) =
598 r.match_query(query, media_query_status, sheet_style_scope)
599 {
600 let weight = RuleWeight::new(
601 selector_weight,
602 sheet_index,
603 rule_index_offset + r.index,
604 );
605 f(MatchedRuleRef { rule: r, weight });
606 }
607 }
608 }
609 }
610 }
611 }
612 }
613
614 pub fn add_font_face(&mut self, ff: FontFace) {
616 self.font_face.push(Rc::new(ff));
617 }
618
619 pub fn font_face(&self) -> &[Rc<FontFace>] {
621 &self.font_face
622 }
623
624 pub(crate) fn add_keyframes(&mut self, keyframes: KeyFrames) {
625 self.keyframes.push(Rc::new(keyframes));
626 }
627}
628
629#[derive(Debug, Clone, Copy, PartialEq, Eq)]
642pub struct RuleWeight(u64);
643
644impl RuleWeight {
645 pub(crate) fn new(selector_weight: u16, sheet_index: u16, rule_index: u32) -> Self {
646 let weight =
647 ((selector_weight as u64) << 48) + ((sheet_index as u64) << 32) + rule_index as u64;
648 Self(weight)
649 }
650
651 pub(crate) fn inline() -> Self {
652 Self(1 << 62)
653 }
654
655 pub fn normal(&self) -> u64 {
657 self.0
658 }
659
660 pub fn important(&self) -> u64 {
662 self.0 + (1 << 63)
663 }
664
665 pub fn sheet_index(&self) -> u16 {
667 (self.0 >> 32) as u16
668 }
669
670 pub fn rule_index(&self) -> u32 {
672 (self.0 as u32) - 1
673 }
674}