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 {target_path:?}"
144 )
145 .into(),
146 start_line: 0,
147 start_col: 0,
148 end_line: 0,
149 end_col: 0,
150 });
151 }
152 } else {
153 warnings.push(Warning {
154 kind: WarningKind::MissingImportTarget,
155 message: format!(r#"target style sheet {target_path:?} not found"#).into(),
156 start_line: 0,
157 start_col: 0,
158 end_line: 0,
159 end_col: 0,
160 });
161 }
162 }
163 sheets.push((self.ss.clone(), parent_media));
164 }
165
166 #[cfg(feature = "serialize")]
167 pub(crate) fn serialize_bincode(&self) -> Vec<u8> {
168 use float_pigment_consistent_bincode::Options;
169 let s = borrow::StyleSheet::from_sheet(self);
170 float_pigment_consistent_bincode::DefaultOptions::new()
171 .allow_trailing_bytes()
172 .serialize(&s)
173 .unwrap()
174 }
175
176 #[cfg(feature = "deserialize")]
177 pub(crate) fn deserialize_bincode(s: Vec<u8>) -> Result<Self, String> {
178 use float_pigment_consistent_bincode::Options;
179 let s: Result<borrow::StyleSheet, _> =
180 float_pigment_consistent_bincode::DefaultOptions::new()
181 .allow_trailing_bytes()
182 .deserialize(&s);
183 match s {
184 Ok(ss) => Ok(ss.into_sheet()),
185 Err(err) => Err(format!(
186 "Failed to deserialize bincode formatted style sheet: {err}"
187 )),
188 }
189 }
190
191 #[cfg(feature = "deserialize")]
192 pub(crate) unsafe fn deserialize_bincode_zero_copy(
193 ptr: *const [u8],
194 drop_callback: impl 'static + FnOnce(),
195 ) -> Result<Self, String> {
196 use float_pigment_consistent_bincode::Options;
197 borrow::de_static_ref_zero_copy_env(
198 ptr,
199 |s| {
200 let s: Result<borrow::StyleSheet, _> =
201 float_pigment_consistent_bincode::DefaultOptions::new()
202 .allow_trailing_bytes()
203 .deserialize(s);
204 match s {
205 Ok(ss) => Ok(ss.into_sheet()),
206 Err(err) => Err(format!(
207 "Failed to deserialize bincode formatted style sheet: {err}"
208 )),
209 }
210 },
211 drop_callback,
212 )
213 }
214
215 #[cfg(all(feature = "serialize", feature = "serialize_json"))]
216 pub(crate) fn serialize_json(&self) -> String {
217 let s = borrow::StyleSheet::from_sheet(self);
218 serde_json::to_string(&s).unwrap()
219 }
220
221 #[cfg(all(feature = "serialize", feature = "deserialize_json"))]
222 pub(crate) fn deserialize_json(s: &str) -> Result<Self, String> {
223 let s: Result<borrow::StyleSheet, _> = serde_json::from_str(s);
224 match s {
225 Ok(ss) => Ok(ss.into_sheet()),
226 Err(err) => Err(format!(
227 "Failed to deserialize json formatted style sheet: {err}"
228 )),
229 }
230 }
231
232 #[cfg(all(feature = "serialize", feature = "deserialize_json"))]
233 pub(crate) unsafe fn deserialize_json_zero_copy(
234 ptr: *mut [u8],
235 drop_callback: impl 'static + FnOnce(),
236 ) -> Result<Self, String> {
237 borrow::de_static_ref_zero_copy_env(
238 ptr,
239 |s| {
240 let s: Result<borrow::StyleSheet, _> =
241 serde_json::from_str(std::str::from_utf8_unchecked(s));
242 match s {
243 Ok(ss) => Ok(ss.into_sheet()),
244 Err(err) => Err(format!(
245 "Failed to deserialize json formatted style sheet: {err}"
246 )),
247 }
248 },
249 drop_callback,
250 )
251 }
252}
253
254#[allow(clippy::type_complexity)]
259#[derive(Debug, Clone)]
260pub struct LinkedStyleSheet {
261 sheets: Vec<(Rc<RefCell<StyleSheet>>, Option<Rc<Media>>)>,
262 scope: Option<NonZeroUsize>,
263}
264
265impl LinkedStyleSheet {
266 pub fn new_empty() -> Self {
268 let mut ss = CompiledStyleSheet::new();
269 ss.link(&StyleSheetResource::new(), None).0
270 }
271
272 pub fn scope(&self) -> Option<NonZeroUsize> {
274 self.scope
275 }
276
277 pub fn sheets(&self) -> Vec<Rc<RefCell<StyleSheet>>> {
285 self.sheets.iter().map(|x| x.0.clone()).collect::<Vec<_>>()
286 }
287
288 #[doc(hidden)]
289 pub fn rules_count(&self, sheet_index: Option<usize>) -> Option<u32> {
290 if let Some(idx) = sheet_index {
291 if self.sheets.len() > (idx + 1usize) {
292 return None;
293 }
294 return Some(self.sheets.get(idx).unwrap().0.borrow().rules_count());
295 }
296 let mut count = 0;
297 self.sheets.iter().for_each(|item| {
298 count += item.0.borrow().rules_count();
299 });
300 Some(count)
301 }
302
303 pub fn parse(source: &str, scope: Option<NonZeroUsize>) -> (Self, Vec<Warning>) {
308 let (mut ss, mut warnings) = parser::parse_style_sheet("", source);
309 let (ret, mut w2) = ss.link(&StyleSheetResource::new(), scope);
310 warnings.append(&mut w2);
311 (ret, warnings)
312 }
313
314 pub fn get_rule(&self, mut rule_index: u32) -> Option<Rc<Rule>> {
316 for (sheet, _media) in self.sheets.iter() {
317 let sheet = sheet.borrow();
318 if rule_index < sheet.rules_count() {
319 return sheet.get_rule(rule_index).cloned();
320 }
321 rule_index -= sheet.rules_count();
322 }
323 None
324 }
325
326 pub fn add_rule(&mut self, rule: Box<Rule>) -> u32 {
331 let mut rule_index = 0;
332 for (sheet, _media) in self.sheets.iter() {
333 rule_index += sheet.borrow().rules_count();
334 }
335 self.sheets
336 .last_mut()
337 .unwrap()
338 .0
339 .borrow_mut()
340 .add_rule(rule);
341 rule_index
342 }
343
344 pub fn replace_rule(
350 &mut self,
351 mut rule_index: u32,
352 rule: Box<Rule>,
353 ) -> Result<Rc<Rule>, Box<Rule>> {
354 for (sheet, _media) in self.sheets.iter_mut() {
355 let mut sheet = sheet.borrow_mut();
356 if rule_index < sheet.rules_count() {
357 return sheet.replace_rule(rule_index, rule);
358 }
359 rule_index -= sheet.rules_count();
360 }
361 Err(rule)
362 }
363
364 pub(crate) fn for_each_matched_rule<L: LengthNum, T: StyleNode>(
365 &self,
366 query: &[T],
367 media_query_status: &MediaQueryStatus<L>,
368 sheet_index: u16,
369 mut f: impl FnMut(MatchedRuleRef),
370 ) {
371 let mut rule_index_offset = 1;
373 for (sheet, media) in self.sheets.iter() {
374 if let Some(media) = media {
375 if !media.is_valid(media_query_status) {
376 continue;
377 }
378 }
379 sheet.borrow_mut().for_each_matched_rule(
380 query,
381 media_query_status,
382 self.scope,
383 sheet_index,
384 rule_index_offset,
385 &mut f,
386 );
387 rule_index_offset += sheet.borrow().rules_count();
388 }
389 }
390
391 pub(crate) fn search_keyframes<L: LengthNum>(
392 &self,
393 style_scope: Option<NonZeroUsize>,
394 name: &str,
395 media_query_status: &MediaQueryStatus<L>,
396 ) -> Option<Rc<KeyFrames>> {
397 if self.scope.is_some() && self.scope != style_scope {
398 return None;
399 }
400 for (sheet, media) in self.sheets.iter() {
401 if let Some(media) = media {
402 if !media.is_valid(media_query_status) {
403 continue;
404 }
405 }
406 for k in sheet.borrow().keyframes.iter().rev() {
408 if k.ident.as_str() == name {
409 return Some(k.clone());
410 }
411 }
412 }
413 None
414 }
415
416 pub fn get_font_face(&self) -> Vec<Rc<FontFace>> {
418 let mut ret = vec![];
419 for (sheet, _) in self.sheets.iter() {
420 let sheet = sheet.borrow();
421 sheet.font_face().iter().for_each(|ff| ret.push(ff.clone()));
422 }
423 ret
424 }
425}
426
427#[derive(Clone)]
429pub struct StyleSheet {
430 rules: Vec<Rc<Rule>>,
431 index: StyleSheetIndex,
432 font_face: Vec<Rc<FontFace>>,
433 keyframes: Vec<Rc<KeyFrames>>,
434}
435
436#[derive(Clone)]
437enum StyleSheetIndex {
438 NeedUpdate,
439 Updated {
440 class_index: HashMap<String, Vec<Rc<Rule>>>,
441 class_unindexed: Vec<Rc<Rule>>,
442 },
443}
444
445impl core::fmt::Debug for StyleSheet {
446 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
447 write!(f, "StyleSheet {{")?;
448 for rule in self.rules.iter() {
449 write!(f, " {rule:?}")?;
450 }
451 for font_face in self.font_face.iter() {
452 write!(f, " {font_face:?}")?;
453 }
454 for keyframes in self.keyframes.iter() {
455 write!(f, " {keyframes:?}")?;
456 }
457 write!(f, " }}")
458 }
459}
460
461impl core::fmt::Display for StyleSheet {
462 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
463 for rule in self.rules.iter() {
464 write!(f, " {rule}")?;
465 }
466 for font_face in self.font_face.iter() {
467 write!(f, " {font_face}")?;
468 }
469 for keyframes in self.keyframes.iter() {
470 write!(f, " {keyframes}")?;
471 }
472 Ok(())
473 }
474}
475
476impl StyleSheet {
477 #[doc(hidden)]
478 #[allow(clippy::should_implement_trait)]
479 pub fn from_str(s: &str) -> LinkedStyleSheet {
480 let (mut ss, warnings) = parser::parse_style_sheet("", s);
481 for warning in warnings {
482 warn!("{:?}", warning);
483 }
484 let ret = ss.link(&StyleSheetResource::new(), None);
485 ret.0
486 }
487
488 #[doc(hidden)]
489 pub fn from_str_with_path(path: &str, s: &str) -> LinkedStyleSheet {
490 let (mut ss, warnings) = parser::parse_style_sheet(path, s);
491 for warning in warnings {
492 warn!("{:?}", warning);
493 }
494 let ret = ss.link(&StyleSheetResource::new(), None);
495 ret.0
496 }
497
498 fn rules_count(&self) -> u32 {
499 self.rules.len().min(u32::MAX as usize) as u32
500 }
501
502 fn get_rule(&self, rule_index: u32) -> Option<&Rc<Rule>> {
503 self.rules.get(rule_index as usize)
504 }
505
506 fn add_rule(&mut self, mut rule: Box<Rule>) {
507 rule.index = self.rules.len() as u32;
508 self.rules.push(Rc::from(rule));
509 self.index = StyleSheetIndex::NeedUpdate;
510 }
511
512 fn replace_rule(
513 &mut self,
514 rule_index: u32,
515 mut rule: Box<Rule>,
516 ) -> Result<Rc<Rule>, Box<Rule>> {
517 let index = rule_index as usize;
518 if index < self.rules.len() {
519 rule.index = rule_index;
520 let mut rule = Rc::from(rule);
521 core::mem::swap(&mut self.rules[index], &mut rule);
522 self.index = StyleSheetIndex::NeedUpdate;
523 Ok(rule)
524 } else {
525 Err(rule)
526 }
527 }
528
529 fn update_index(&mut self) {
530 if let StyleSheetIndex::NeedUpdate = &self.index {
531 let mut class_index: HashMap<String, Vec<Rc<Rule>>> = HashMap::default();
532 let mut class_unindexed = vec![];
533 for rule in self.rules.iter() {
534 let index_classes = rule.selector.get_index_classes();
535 for c in index_classes {
536 if !c.is_empty() {
537 let c = class_index.entry(c).or_default();
538 c.push(rule.clone());
539 } else {
540 class_unindexed.push(rule.clone());
541 }
542 }
543 }
544 self.index = StyleSheetIndex::Updated {
545 class_index,
546 class_unindexed,
547 };
548 }
549 }
550
551 fn for_each_matched_rule<L: LengthNum, T: StyleNode>(
552 &mut self,
553 query: &[T],
554 media_query_status: &MediaQueryStatus<L>,
555 sheet_style_scope: Option<NonZeroUsize>,
556 sheet_index: u16,
557 rule_index_offset: u32,
558 mut f: impl FnMut(MatchedRuleRef),
559 ) {
560 self.update_index();
561 if let StyleSheetIndex::Updated {
562 class_index,
563 class_unindexed,
564 } = &self.index
565 {
566 if sheet_style_scope.is_none()
567 || query
568 .last()
569 .is_some_and(|x| x.contain_scope(sheet_style_scope))
570 {
571 for r in class_unindexed.iter() {
572 if let Some(selector_weight) =
573 r.match_query(query, media_query_status, sheet_style_scope)
574 {
575 let weight = RuleWeight::new(
576 selector_weight,
577 sheet_index,
578 rule_index_offset + r.index,
579 );
580 f(MatchedRuleRef { rule: r, weight });
581 }
582 }
583 }
584 let query_last = match query.last() {
585 Some(x) => x,
586 None => return,
587 };
588 for class in query_last.classes() {
589 if sheet_style_scope.is_none() || sheet_style_scope == class.scope() {
590 if let Some(rules) = class_index.get(class.name()) {
591 for r in rules {
592 if let Some(selector_weight) =
593 r.match_query(query, media_query_status, sheet_style_scope)
594 {
595 let weight = RuleWeight::new(
596 selector_weight,
597 sheet_index,
598 rule_index_offset + r.index,
599 );
600 f(MatchedRuleRef { rule: r, weight });
601 }
602 }
603 }
604 }
605 }
606 }
607 }
608
609 pub fn add_font_face(&mut self, ff: FontFace) {
611 self.font_face.push(Rc::new(ff));
612 }
613
614 pub fn font_face(&self) -> &[Rc<FontFace>] {
616 &self.font_face
617 }
618
619 pub(crate) fn add_keyframes(&mut self, keyframes: KeyFrames) {
620 self.keyframes.push(Rc::new(keyframes));
621 }
622}
623
624#[derive(Debug, Clone, Copy, PartialEq, Eq)]
637pub struct RuleWeight(u64);
638
639impl RuleWeight {
640 pub(crate) fn new(selector_weight: u16, sheet_index: u16, rule_index: u32) -> Self {
641 let weight =
642 ((selector_weight as u64) << 48) + ((sheet_index as u64) << 32) + rule_index as u64;
643 Self(weight)
644 }
645
646 pub(crate) fn inline() -> Self {
647 Self(1 << 62)
648 }
649
650 pub fn normal(&self) -> u64 {
652 self.0
653 }
654
655 pub fn important(&self) -> u64 {
657 self.0 + (1 << 63)
658 }
659
660 pub fn sheet_index(&self) -> u16 {
662 (self.0 >> 32) as u16
663 }
664
665 pub fn rule_index(&self) -> u32 {
667 (self.0 as u32) - 1
668 }
669}