1#![doc(hidden)]
2#![cfg(feature = "ffi")]
3
4use alloc::{
5 boxed::Box,
6 ffi::CString,
7 string::{String, ToString},
8 vec::Vec,
9};
10use bit_set::BitSet;
11use core::ffi::{c_char, CStr};
12use core::ptr::{null, null_mut};
13use hashbrown::HashMap;
14
15use crate::parser::parse_color_to_rgba;
16use crate::property::{Property, PropertyMeta};
17use crate::sheet::borrow::{InlineRule, Selector};
18use crate::typing::ImportantBitSet;
19
20use crate::group;
21use crate::parser;
22use crate::parser::property_value::var::{
23 CustomPropertyContext, CustomPropertyGetter, CustomPropertySetter,
24};
25use crate::sheet;
26use group::drop_css_extension;
27use group::StyleSheetImportIndex as StyleSheetImportIndexImpl;
28use parser::Warning;
29use sheet::borrow::{Array, StyleSheet};
30use sheet::str_store::StrRef;
31
32#[cfg(feature = "deserialize")]
33use sheet::borrow::de_static_ref_zero_copy_env;
34
35#[macro_export]
36macro_rules! check_null {
37 ($arg:expr, $error:expr, $default:expr) => {
38 if $arg.is_null() {
39 return FfiResult::error($error, $default);
40 }
41 };
42}
43
44#[macro_export]
45macro_rules! raw_ptr_as_mut_ref {
46 ($from:expr, $type:ty) => {
47 &mut *($from as *mut $type)
48 };
49}
50
51pub type RawMutPtr = *mut ();
52
53pub type NullPtr = *const ();
54
55#[repr(C)]
56pub enum FfiErrorCode {
57 None,
58 ThisNullPointer,
59 PathNullPointer,
60 PrefixNullPointer,
61 SourceNullPointer,
62 BufferNullPointer,
63 ExprPtrNullPointer,
64 StrNullPointer,
65 InlineStyleTextNullPointer,
66 InlineRuleNullPointer,
67 StyleTextNullPointer,
68 SelectorTextNullPointer,
69 InvalidPath,
70 JsonNullPointer,
71 ArrayNullPointer,
72 SelectorNullPointer,
73 StyleSheetNullPointer,
74 MapNullPointer,
75 Unknown,
76}
77
78#[repr(C)]
79pub struct FfiResult<T> {
80 pub value: T,
81 pub err: FfiErrorCode,
82}
83
84impl<T> FfiResult<T> {
85 pub fn ok(value: T) -> Self {
86 Self {
87 value,
88 err: FfiErrorCode::None,
89 }
90 }
91 pub fn error(err: FfiErrorCode, default: T) -> Self {
92 Self {
93 value: default,
94 err,
95 }
96 }
97}
98
99#[export_name = "FPStyleSheetResourceNew"]
120pub unsafe extern "C" fn style_sheet_resource_new() -> FfiResult<RawMutPtr> {
121 FfiResult::ok(Box::into_raw(Box::new(group::StyleSheetResource::new())) as RawMutPtr)
122}
123
124#[export_name = "FPStyleSheetResourceFree"]
141pub unsafe extern "C" fn style_sheet_resource_free(this: RawMutPtr) -> FfiResult<NullPtr> {
142 check_null!(this, FfiErrorCode::ThisNullPointer, null());
143 drop(Box::from_raw(this as *mut group::StyleSheetResource));
144 FfiResult::ok(null())
145}
146
147#[export_name = "FPStyleSheetResourceAddTagNamePrefix"]
165pub unsafe extern "C" fn style_sheet_resource_add_tag_name_prefix(
166 this: RawMutPtr,
167 path: *const c_char,
168 prefix: *const c_char,
169) -> FfiResult<NullPtr> {
170 check_null!(this, FfiErrorCode::ThisNullPointer, null());
171 check_null!(path, FfiErrorCode::PathNullPointer, null());
172 check_null!(prefix, FfiErrorCode::PrefixNullPointer, null());
173 let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
174 let path = CStr::from_ptr(path).to_string_lossy();
175 let prefix = CStr::from_ptr(prefix).to_string_lossy();
176 res.add_tag_name_prefix(&path, &prefix);
177 FfiResult::ok(null())
178}
179
180#[cfg(all(feature = "serialize", feature = "serialize_json"))]
198#[export_name = "FPStyleSheetResourceSerializeJson"]
199pub unsafe extern "C" fn style_sheet_resource_serialize_json(
200 this: RawMutPtr,
201 path: *const c_char,
202 ret_buffer_len: &mut usize,
203) -> FfiResult<*mut u8> {
204 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
205 check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
206 let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
207 let path = CStr::from_ptr(path).to_string_lossy();
208 let serial = res.serialize_json(&path).unwrap_or_default();
209 *ret_buffer_len = serial.len();
210 let ret = Box::into_raw(serial.into_boxed_str());
211 FfiResult::ok(ret as *mut u8)
212}
213
214#[cfg(feature = "serialize")]
233#[export_name = "FPStyleSheetResourceSerializeBincode"]
234pub unsafe extern "C" fn style_sheet_resource_serialize_bincode(
235 this: RawMutPtr,
236 path: *const c_char,
237 ret_buffer_len: &mut usize,
238) -> FfiResult<*mut u8> {
239 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
240 check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
241 let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
242 let path = CStr::from_ptr(path).to_string_lossy();
243 let serial = res.serialize_bincode(&path).unwrap_or_default();
244 *ret_buffer_len = serial.len();
245 let ret = Box::into_raw(serial.into_boxed_slice());
246 FfiResult::ok(ret as *mut u8)
247}
248#[export_name = "FPStyleSheetResourceAddSource"]
265pub unsafe extern "C" fn style_sheet_resource_add_source(
266 this: RawMutPtr,
267 path: *const c_char,
268 source: *const c_char,
269 warnings: *mut *mut Array<Warning>,
270) -> FfiResult<NullPtr> {
271 check_null!(this, FfiErrorCode::ThisNullPointer, null());
272 check_null!(path, FfiErrorCode::PathNullPointer, null());
273 check_null!(source, FfiErrorCode::SourceNullPointer, null());
274 let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
275 let path = CStr::from_ptr(path).to_string_lossy();
276 let source = CStr::from_ptr(source).to_string_lossy();
277 let w = res.add_source(&path, &source);
278 if !warnings.is_null() {
279 *warnings = Box::into_raw(Box::new(w.into()));
280 }
281 FfiResult::ok(null())
282}
283
284#[export_name = "FPStyleSheetResourceAddSourceWithHooks"]
302pub unsafe extern "C" fn style_sheet_resource_add_source_with_hooks(
303 this: RawMutPtr,
304 hooks: parser::hooks::CParserHooks,
305 path: *const c_char,
306 source: *const c_char,
307 warnings: *mut *mut Array<Warning>,
308) -> FfiResult<NullPtr> {
309 check_null!(this, FfiErrorCode::ThisNullPointer, null());
310 check_null!(path, FfiErrorCode::PathNullPointer, null());
311 check_null!(source, FfiErrorCode::SourceNullPointer, null());
312 let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
313 let path = CStr::from_ptr(path).to_string_lossy();
314 let source = CStr::from_ptr(source).to_string_lossy();
315 let w = res.add_source_with_hooks(&path, &source, Some(Box::new(hooks)));
316 if !warnings.is_null() {
317 *warnings = Box::into_raw(Box::new(w.into()));
318 }
319 FfiResult::ok(null())
320}
321
322#[cfg(feature = "deserialize")]
341#[export_name = "FPStyleSheetResourceAddBincode"]
342pub unsafe extern "C" fn style_sheet_resource_add_bincode(
343 this: RawMutPtr,
344 path: *const c_char,
345 buffer_ptr: *mut u8,
346 buffer_len: usize,
347 drop_fn: Option<unsafe extern "C" fn(RawMutPtr)>,
348 drop_args: RawMutPtr,
349 warnings: *mut *mut Array<Warning>,
350) -> FfiResult<NullPtr> {
351 check_null!(this, FfiErrorCode::ThisNullPointer, null());
352 check_null!(path, FfiErrorCode::PathNullPointer, null());
353 check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null());
354 let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
355 let bincode: *mut [u8] = core::slice::from_raw_parts_mut(buffer_ptr, buffer_len);
356 let path = CStr::from_ptr(path).to_string_lossy();
357 let w = res.add_bincode_zero_copy(&path, bincode, move || {
358 if let Some(drop_fn) = drop_fn {
359 drop_fn(drop_args);
360 }
361 });
362 if !warnings.is_null() {
363 *warnings = Box::into_raw(Box::new(w.into()));
364 }
365 FfiResult::ok(null())
366}
367
368#[export_name = "FPStyleSheetResourceDirectDependencies"]
382pub unsafe extern "C" fn style_sheet_resource_direct_dependencies(
383 this: RawMutPtr,
384 path: *const c_char,
385) -> FfiResult<*mut Array<StrRef>> {
386 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
387 check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
388 let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
389 let path = CStr::from_ptr(path).to_string_lossy();
390 let deps = res.direct_dependencies(&path);
391 let deps: Vec<_> = deps.into_iter().map(StrRef::from).collect();
392 FfiResult::ok(Box::into_raw(Box::new(deps.into())))
393}
394
395#[export_name = "FPStyleSheetResourceGenerateImportIndex"]
409pub unsafe extern "C" fn style_sheet_resource_generate_import_index(
410 this: RawMutPtr,
411) -> FfiResult<RawMutPtr> {
412 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
413 let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
414 FfiResult::ok(
415 StyleSheetImportIndex {
416 inner: res.generate_import_indexes(),
417 map: StyleSheetMap::default(),
418 }
419 .into_raw(),
420 )
421}
422
423type StyleSheetMap = HashMap<String, StyleSheet>;
424
425struct StyleSheetImportIndex {
426 inner: StyleSheetImportIndexImpl,
427 map: StyleSheetMap,
428}
429
430impl StyleSheetImportIndex {
431 fn into_raw(self) -> RawMutPtr {
432 Box::into_raw(Box::new(self)) as RawMutPtr
433 }
434}
435
436#[export_name = "FPStyleSheetImportIndexNew"]
446pub unsafe extern "C" fn style_sheet_import_index_new() -> FfiResult<RawMutPtr> {
447 FfiResult::ok(
448 StyleSheetImportIndex {
449 inner: StyleSheetImportIndexImpl::new(),
450 map: StyleSheetMap::default(),
451 }
452 .into_raw(),
453 )
454}
455
456#[export_name = "FPStyleSheetImportIndexFree"]
469pub unsafe extern "C" fn style_sheet_import_index_free(this: RawMutPtr) -> FfiResult<NullPtr> {
470 check_null!(this, FfiErrorCode::ThisNullPointer, null());
471 drop(Box::from_raw(this as *mut StyleSheetImportIndex));
472 FfiResult::ok(null())
473}
474
475#[export_name = "FPStyleSheetImportIndexQueryAndMarkDependencies"]
489pub unsafe extern "C" fn style_sheet_import_index_query_and_mark_dependencies(
490 this: RawMutPtr,
491 path: *const c_char,
492) -> FfiResult<*mut Array<StrRef>> {
493 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
494 check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
495 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
496 let path = CStr::from_ptr(path).to_string_lossy();
497 let deps = style_sheet_import_index
498 .inner
499 .query_and_mark_dependencies(&path);
500 let deps: Vec<_> = deps.into_iter().map(StrRef::from).collect();
501 FfiResult::ok(Box::into_raw(Box::new(deps.into())))
502}
503
504#[export_name = "FPStyleSheetImportIndexListDependencies"]
518pub unsafe extern "C" fn style_sheet_import_index_list_dependencies(
519 this: RawMutPtr,
520 path: *const c_char,
521) -> FfiResult<*mut Array<StrRef>> {
522 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
523 check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
524 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
525 let path = CStr::from_ptr(path).to_string_lossy();
526 let deps = style_sheet_import_index
527 .inner
528 .list_dependencies(&path, true);
529 let deps: Vec<_> = deps.into_iter().map(StrRef::from).collect();
530 FfiResult::ok(Box::into_raw(Box::new(deps.into())))
531}
532
533#[export_name = "FPStyleSheetImportIndexListDependency"]
547pub unsafe extern "C" fn style_sheet_import_index_list_dependency(
548 this: RawMutPtr,
549 path: *const c_char,
550) -> FfiResult<*mut Array<StrRef>> {
551 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
552 check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
553 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
554 let path = CStr::from_ptr(path).to_string_lossy();
555 let deps = style_sheet_import_index
556 .inner
557 .list_dependencies(&path, false);
558 let deps: Vec<_> = deps.into_iter().map(StrRef::from).collect();
559 FfiResult::ok(Box::into_raw(Box::new(deps.into())))
560}
561
562#[cfg(feature = "deserialize")]
581#[export_name = "FPStyleSheetImportIndexAddBincode"]
582pub unsafe extern "C" fn style_sheet_import_index_add_bincode(
583 this: RawMutPtr,
584 path: *const c_char,
585 buffer_ptr: *mut u8,
586 buffer_len: usize,
587 drop_fn: Option<unsafe extern "C" fn(RawMutPtr)>,
588 drop_args: RawMutPtr,
589 warnings: *mut *mut Array<Warning>,
590) -> FfiResult<NullPtr> {
591 use float_pigment_consistent_bincode::Options;
592 use parser::WarningKind;
593 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
594 check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
595 check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null_mut());
596 let path = CStr::from_ptr(path).to_string_lossy();
597 let sheet = de_static_ref_zero_copy_env(
598 core::slice::from_raw_parts_mut(buffer_ptr, buffer_len),
599 |s| {
600 let s: Result<StyleSheet, _> = float_pigment_consistent_bincode::DefaultOptions::new()
601 .allow_trailing_bytes()
602 .deserialize(s);
603 match s {
604 Ok(ss) => ss,
605 Err(err) => {
606 let w = vec![Warning {
607 kind: WarningKind::DeserializationFailed,
608 message: format!(
609 "failed to deserialize bincode formatted style sheet: {err}"
610 )
611 .into(),
612 start_line: 0,
613 start_col: 0,
614 end_line: 0,
615 end_col: 0,
616 }];
617 if !warnings.is_null() {
618 *warnings = Box::into_raw(Box::new(w.into()));
619 }
620 StyleSheet::from_sheet(&sheet::CompiledStyleSheet::new())
621 }
622 }
623 },
624 move || {
625 if let Some(drop_fn) = drop_fn {
626 drop_fn(drop_args);
627 }
628 },
629 );
630 let path = drop_css_extension(&path).into();
631 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
632 style_sheet_import_index.map.insert(path, sheet);
633 FfiResult::ok(null())
634}
635
636#[export_name = "FPStyleSheetImportIndexRemoveBincode"]
650pub unsafe extern "C" fn style_sheet_import_index_remove_bincode(
651 this: RawMutPtr,
652 path: *const c_char,
653) -> FfiResult<NullPtr> {
654 check_null!(this, FfiErrorCode::ThisNullPointer, null());
655 check_null!(path, FfiErrorCode::PathNullPointer, null());
656 let path = CStr::from_ptr(path).to_string_lossy();
657 let path = drop_css_extension(&path);
658 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
659 style_sheet_import_index.map.remove(path);
660 FfiResult::ok(null())
661}
662#[export_name = "FPStyleSheetImportIndexGetStyleSheet"]
676pub unsafe extern "C" fn style_sheet_import_index_get_style_sheet(
677 this: RawMutPtr,
678 path: *const c_char,
679) -> FfiResult<*mut StyleSheet> {
680 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
681 check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
682 let path = CStr::from_ptr(path).to_string_lossy();
683 let path = drop_css_extension(&path);
684 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
685 match style_sheet_import_index.map.get_mut(path) {
686 None => FfiResult::error(FfiErrorCode::InvalidPath, null_mut()),
687 Some(x) => FfiResult::ok(x as *mut StyleSheet),
688 }
689}
690#[cfg(all(feature = "serialize", feature = "serialize_json"))]
704#[export_name = "FPStyleSheetImportIndexSerializeJson"]
705pub unsafe extern "C" fn style_sheet_import_index_serialize_json(
706 this: RawMutPtr,
707 ret_buffer_len: &mut usize,
708) -> FfiResult<*mut u8> {
709 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
710 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
711 let serial = style_sheet_import_index.inner.serialize_json();
712 *ret_buffer_len = serial.len();
713 let ret = Box::into_raw(serial.into_boxed_str());
714 FfiResult::ok(ret as *mut u8)
715}
716#[cfg(feature = "serialize")]
730#[export_name = "FPStyleSheetImportIndexSerializeBincode"]
731pub unsafe extern "C" fn style_sheet_import_index_serialize_bincode(
732 this: RawMutPtr,
733 ret_buffer_len: &mut usize,
734) -> FfiResult<*mut u8> {
735 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
736 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
737 let serial = style_sheet_import_index.inner.serialize_bincode();
738 *ret_buffer_len = serial.len();
739 let ret = Box::into_raw(serial.into_boxed_slice());
740 FfiResult::ok(ret as *mut u8)
741}
742#[cfg(all(feature = "deserialize", feature = "deserialize_json"))]
755#[export_name = "FPStyleSheetImportIndexDeserializeJson"]
756pub unsafe extern "C" fn style_sheet_import_index_deserialize_json(
757 json: *const c_char,
758) -> FfiResult<RawMutPtr> {
759 check_null!(json, FfiErrorCode::JsonNullPointer, null_mut());
760 let json = CStr::from_ptr(json).to_string_lossy();
761 FfiResult::ok(
762 StyleSheetImportIndex {
763 inner: StyleSheetImportIndexImpl::deserialize_json(&json),
764 map: StyleSheetMap::default(),
765 }
766 .into_raw(),
767 )
768}
769#[cfg(feature = "deserialize")]
785#[export_name = "FPStyleSheetImportIndexDeserializeBincode"]
786pub unsafe extern "C" fn style_sheet_import_index_deserialize_bincode(
787 buffer_ptr: *mut u8,
788 buffer_len: usize,
789 drop_fn: Option<unsafe extern "C" fn(RawMutPtr)>,
790 drop_args: RawMutPtr,
791) -> FfiResult<RawMutPtr> {
792 check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null_mut());
793 let bincode: *mut [u8] = core::slice::from_raw_parts_mut(buffer_ptr, buffer_len);
794 FfiResult::ok(
795 StyleSheetImportIndex {
796 inner: StyleSheetImportIndexImpl::deserialize_bincode_zero_copy(bincode, move || {
797 if let Some(drop_fn) = drop_fn {
798 drop_fn(drop_args);
799 }
800 }),
801 map: StyleSheetMap::default(),
802 }
803 .into_raw(),
804 )
805}
806#[cfg(feature = "deserialize")]
823#[export_name = "FPStyleSheetImportIndexMergeBincode"]
824pub unsafe extern "C" fn style_sheet_import_index_merge_bincode(
825 this: RawMutPtr,
826 buffer_ptr: *mut u8,
827 buffer_len: usize,
828 drop_fn: Option<unsafe extern "C" fn(*mut ())>,
829 drop_args: *mut (),
830) -> FfiResult<NullPtr> {
831 check_null!(this, FfiErrorCode::ThisNullPointer, null());
832 check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null());
833 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
834 let bincode: *mut [u8] = core::slice::from_raw_parts_mut(buffer_ptr, buffer_len);
835 style_sheet_import_index
836 .inner
837 .merge_bincode_zero_copy(bincode, move || {
838 if let Some(drop_fn) = drop_fn {
839 drop_fn(drop_args);
840 }
841 });
842 FfiResult::ok(null())
843}
844
845#[export_name = "FPBufferFree"]
859pub unsafe extern "C" fn buffer_free(buffer_ptr: *mut u8, buffer_len: usize) -> FfiResult<NullPtr> {
860 check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null());
861 let x: *mut [u8] = core::slice::from_raw_parts_mut(buffer_ptr, buffer_len);
862 drop(Box::from_raw(x));
863 FfiResult::ok(null())
864}
865
866#[export_name = "FPArrayStrRefFree"]
879pub unsafe extern "C" fn array_str_ref_free(x: *mut Array<StrRef>) -> FfiResult<NullPtr> {
880 check_null!(x, FfiErrorCode::ArrayNullPointer, null());
881 drop(Box::from_raw(x));
882 FfiResult::ok(null())
883}
884
885#[export_name = "FPArrayWarningFree"]
898pub unsafe extern "C" fn array_warning_free(
899 warnings: *mut Array<parser::Warning>,
900) -> FfiResult<NullPtr> {
901 check_null!(warnings, FfiErrorCode::ArrayNullPointer, null());
902 drop(Box::from_raw(warnings));
903 FfiResult::ok(null())
904}
905
906#[export_name = "FPParseInlineStyle"]
920pub unsafe extern "C" fn parse_inline_style(
921 inline_style_text_ptr: *const c_char,
922 warnings: *mut *mut Array<parser::Warning>,
923) -> FfiResult<*mut InlineRule> {
924 check_null!(
925 inline_style_text_ptr,
926 FfiErrorCode::InlineStyleTextNullPointer,
927 null_mut()
928 );
929 let inline_style_text = CStr::from_ptr(inline_style_text_ptr).to_string_lossy();
930 let (prop, w) =
931 parser::parse_inline_style(&inline_style_text, parser::StyleParsingDebugMode::None);
932 if !warnings.is_null() {
933 *warnings = Box::into_raw(Box::new(w.into()));
934 }
935 let mut important = BitSet::new();
936 let mut bs_empty = true;
937 let properties = prop
938 .into_iter()
939 .enumerate()
940 .map(|(index, x)| match x {
941 PropertyMeta::Normal { property } => property,
942 PropertyMeta::Important { property } => {
943 important.insert(index);
944 bs_empty = false;
945 property
946 }
947 PropertyMeta::DebugGroup { .. } => Property::Unknown,
948 })
949 .collect();
950 let important = if bs_empty {
951 ImportantBitSet::None
952 } else {
953 ImportantBitSet::Array(important.into_bit_vec().to_bytes().into())
954 };
955 let inline_rule = InlineRule::new(properties, important);
956 FfiResult::ok(Box::into_raw(Box::new(inline_rule)))
957}
958
959#[export_name = "FPInlineStyleFree"]
972pub unsafe extern "C" fn inline_style_free(inline_rule: *mut InlineRule) -> FfiResult<NullPtr> {
973 check_null!(inline_rule, FfiErrorCode::InlineRuleNullPointer, null());
974 drop(Box::from_raw(inline_rule));
975 FfiResult::ok(null())
976}
977
978#[export_name = "FPParseStyleSheetFromString"]
991pub unsafe extern "C" fn parse_style_sheet_from_string(
992 style_text_ptr: *const c_char,
993) -> FfiResult<*mut StyleSheet> {
994 check_null!(
995 style_text_ptr,
996 FfiErrorCode::StyleTextNullPointer,
997 null_mut()
998 );
999 let style_text = CStr::from_ptr(style_text_ptr).to_string_lossy();
1000 let (compiled_style_sheet, _) = parser::parse_style_sheet("string", &style_text);
1001 let style_sheet = StyleSheet::from_sheet(&compiled_style_sheet);
1002 FfiResult::ok(Box::into_raw(Box::new(style_sheet)))
1003}
1004
1005#[export_name = "FPParseSelectorFromString"]
1018pub unsafe extern "C" fn parse_selector_from_string(
1019 selector_text_ptr: *const c_char,
1020) -> FfiResult<*mut Selector> {
1021 check_null!(
1022 selector_text_ptr,
1023 FfiErrorCode::SelectorTextNullPointer,
1024 null_mut()
1025 );
1026 let selector_text = CStr::from_ptr(selector_text_ptr).to_string_lossy();
1027 let selector = Selector::from_string(&selector_text);
1028 FfiResult::ok(Box::into_raw(Box::new(selector)))
1029}
1030
1031#[export_name = "FPSelectorFree"]
1044pub unsafe extern "C" fn selector_free(selector: *mut Selector) -> FfiResult<NullPtr> {
1045 check_null!(selector, FfiErrorCode::SelectorNullPointer, null());
1046 drop(Box::from_raw(selector));
1047 FfiResult::ok(null())
1048}
1049
1050#[export_name = "FPStyleSheetFree"]
1063pub unsafe extern "C" fn style_sheet_free(style_sheet: *mut StyleSheet) -> FfiResult<NullPtr> {
1064 check_null!(style_sheet, FfiErrorCode::StyleSheetNullPointer, null());
1065 drop(Box::from_raw(style_sheet));
1066 FfiResult::ok(null())
1067}
1068
1069#[cfg(feature = "deserialize")]
1083#[export_name = "FPStyleSheetBincodeVersion"]
1084pub unsafe extern "C" fn style_sheet_bincode_version(
1085 buffer_ptr: *mut u8,
1086 buffer_len: usize,
1087) -> FfiResult<*mut StrRef> {
1088 use float_pigment_consistent_bincode::Options;
1089 check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null_mut());
1090 let sheet = de_static_ref_zero_copy_env(
1091 core::slice::from_raw_parts_mut(buffer_ptr, buffer_len),
1092 |s| {
1093 let s: Result<StyleSheet, _> = float_pigment_consistent_bincode::DefaultOptions::new()
1094 .allow_trailing_bytes()
1095 .deserialize(s);
1096 match s {
1097 Ok(ss) => ss,
1098 Err(err) => {
1099 let mut ss = StyleSheet::from_sheet(&sheet::CompiledStyleSheet::new());
1100 if let StyleSheet::V1(ssv) = &mut ss {
1101 ssv.version = Box::new(
1102 format!("Failed to deserialize bincode formatted style sheet: {err}")
1103 .into(),
1104 );
1105 }
1106 ss
1107 }
1108 }
1109 },
1110 move || {},
1111 );
1112 let version = match sheet {
1113 StyleSheet::V1(v1) => v1.version,
1114 _ => Box::new("unknown version".into()),
1115 };
1116 FfiResult::ok(Box::into_raw(version))
1117}
1118
1119#[export_name = "FPCssParserVersion"]
1128pub unsafe extern "C" fn css_parser_version() -> FfiResult<*mut StrRef> {
1129 let version = env!("CARGO_PKG_VERSION").to_string().into();
1130 FfiResult::ok(Box::into_raw(Box::new(version)))
1131}
1132
1133#[repr(C)]
1134#[derive(Debug, Default)]
1135pub struct ColorValue {
1136 red: u8,
1137 green: u8,
1138 blue: u8,
1139 alpha: u8,
1140}
1141
1142#[export_name = "FPParseColorFromString"]
1155pub unsafe extern "C" fn parse_color_from_string(source: *const c_char) -> FfiResult<ColorValue> {
1156 check_null!(
1157 source,
1158 FfiErrorCode::SourceNullPointer,
1159 ColorValue::default()
1160 );
1161 let source = CStr::from_ptr(source).to_string_lossy();
1162 let ret = parse_color_to_rgba(&source);
1163 FfiResult::ok(ColorValue {
1164 red: ret.0,
1165 green: ret.1,
1166 blue: ret.2,
1167 alpha: ret.3,
1168 })
1169}
1170
1171#[export_name = "FPSubstituteVariable"]
1187pub unsafe extern "C" fn substitute_variable(
1188 expr_ptr: *const c_char,
1189 map: RawMutPtr,
1190 getter: CustomPropertyGetter,
1191 setter: CustomPropertySetter,
1192) -> FfiResult<*const c_char> {
1193 check_null!(expr_ptr, FfiErrorCode::ExprPtrNullPointer, null());
1194 check_null!(map, FfiErrorCode::MapNullPointer, null());
1195 let expr = CStr::from_ptr(expr_ptr).to_string_lossy();
1196 let context = CustomPropertyContext::create(map, getter, setter);
1197 if let Some(ret) = parser::property_value::var::substitute_variable(&expr, &context) {
1198 if let Ok(r) = CString::new(ret) {
1199 return FfiResult::ok(r.into_raw());
1200 }
1201 }
1202 FfiResult::ok(null())
1203}
1204
1205#[export_name = "FPStrFree"]
1218pub unsafe extern "C" fn str_free(ptr: *const c_char) -> FfiResult<NullPtr> {
1219 check_null!(ptr, FfiErrorCode::StrNullPointer, null());
1220 drop(CString::from_raw(ptr as *mut c_char));
1221 FfiResult::ok(null())
1222}