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: {}",
610 err
611 )
612 .into(),
613 start_line: 0,
614 start_col: 0,
615 end_line: 0,
616 end_col: 0,
617 }];
618 if !warnings.is_null() {
619 *warnings = Box::into_raw(Box::new(w.into()));
620 }
621 StyleSheet::from_sheet(&sheet::CompiledStyleSheet::new())
622 }
623 }
624 },
625 move || {
626 if let Some(drop_fn) = drop_fn {
627 drop_fn(drop_args);
628 }
629 },
630 );
631 let path = drop_css_extension(&path).into();
632 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
633 style_sheet_import_index.map.insert(path, sheet);
634 FfiResult::ok(null())
635}
636
637#[export_name = "FPStyleSheetImportIndexRemoveBincode"]
651pub unsafe extern "C" fn style_sheet_import_index_remove_bincode(
652 this: RawMutPtr,
653 path: *const c_char,
654) -> FfiResult<NullPtr> {
655 check_null!(this, FfiErrorCode::ThisNullPointer, null());
656 check_null!(path, FfiErrorCode::PathNullPointer, null());
657 let path = CStr::from_ptr(path).to_string_lossy();
658 let path = drop_css_extension(&path);
659 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
660 style_sheet_import_index.map.remove(path);
661 FfiResult::ok(null())
662}
663#[export_name = "FPStyleSheetImportIndexGetStyleSheet"]
677pub unsafe extern "C" fn style_sheet_import_index_get_style_sheet(
678 this: RawMutPtr,
679 path: *const c_char,
680) -> FfiResult<*mut StyleSheet> {
681 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
682 check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
683 let path = CStr::from_ptr(path).to_string_lossy();
684 let path = drop_css_extension(&path);
685 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
686 match style_sheet_import_index.map.get_mut(path) {
687 None => FfiResult::error(FfiErrorCode::InvalidPath, null_mut()),
688 Some(x) => FfiResult::ok(x as *mut StyleSheet),
689 }
690}
691#[cfg(all(feature = "serialize", feature = "serialize_json"))]
705#[export_name = "FPStyleSheetImportIndexSerializeJson"]
706pub unsafe extern "C" fn style_sheet_import_index_serialize_json(
707 this: RawMutPtr,
708 ret_buffer_len: &mut usize,
709) -> FfiResult<*mut u8> {
710 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
711 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
712 let serial = style_sheet_import_index.inner.serialize_json();
713 *ret_buffer_len = serial.len();
714 let ret = Box::into_raw(serial.into_boxed_str());
715 FfiResult::ok(ret as *mut u8)
716}
717#[cfg(feature = "serialize")]
731#[export_name = "FPStyleSheetImportIndexSerializeBincode"]
732pub unsafe extern "C" fn style_sheet_import_index_serialize_bincode(
733 this: RawMutPtr,
734 ret_buffer_len: &mut usize,
735) -> FfiResult<*mut u8> {
736 check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
737 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
738 let serial = style_sheet_import_index.inner.serialize_bincode();
739 *ret_buffer_len = serial.len();
740 let ret = Box::into_raw(serial.into_boxed_slice());
741 FfiResult::ok(ret as *mut u8)
742}
743#[cfg(all(feature = "deserialize", feature = "deserialize_json"))]
756#[export_name = "FPStyleSheetImportIndexDeserializeJson"]
757pub unsafe extern "C" fn style_sheet_import_index_deserialize_json(
758 json: *const c_char,
759) -> FfiResult<RawMutPtr> {
760 check_null!(json, FfiErrorCode::JsonNullPointer, null_mut());
761 let json = CStr::from_ptr(json).to_string_lossy();
762 FfiResult::ok(
763 StyleSheetImportIndex {
764 inner: StyleSheetImportIndexImpl::deserialize_json(&json),
765 map: StyleSheetMap::default(),
766 }
767 .into_raw(),
768 )
769}
770#[cfg(feature = "deserialize")]
786#[export_name = "FPStyleSheetImportIndexDeserializeBincode"]
787pub unsafe extern "C" fn style_sheet_import_index_deserialize_bincode(
788 buffer_ptr: *mut u8,
789 buffer_len: usize,
790 drop_fn: Option<unsafe extern "C" fn(RawMutPtr)>,
791 drop_args: RawMutPtr,
792) -> FfiResult<RawMutPtr> {
793 check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null_mut());
794 let bincode: *mut [u8] = core::slice::from_raw_parts_mut(buffer_ptr, buffer_len);
795 FfiResult::ok(
796 StyleSheetImportIndex {
797 inner: StyleSheetImportIndexImpl::deserialize_bincode_zero_copy(bincode, move || {
798 if let Some(drop_fn) = drop_fn {
799 drop_fn(drop_args);
800 }
801 }),
802 map: StyleSheetMap::default(),
803 }
804 .into_raw(),
805 )
806}
807#[cfg(feature = "deserialize")]
824#[export_name = "FPStyleSheetImportIndexMergeBincode"]
825pub unsafe extern "C" fn style_sheet_import_index_merge_bincode(
826 this: RawMutPtr,
827 buffer_ptr: *mut u8,
828 buffer_len: usize,
829 drop_fn: Option<unsafe extern "C" fn(*mut ())>,
830 drop_args: *mut (),
831) -> FfiResult<NullPtr> {
832 check_null!(this, FfiErrorCode::ThisNullPointer, null());
833 check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null());
834 let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
835 let bincode: *mut [u8] = core::slice::from_raw_parts_mut(buffer_ptr, buffer_len);
836 style_sheet_import_index
837 .inner
838 .merge_bincode_zero_copy(bincode, move || {
839 if let Some(drop_fn) = drop_fn {
840 drop_fn(drop_args);
841 }
842 });
843 FfiResult::ok(null())
844}
845
846#[export_name = "FPBufferFree"]
860pub unsafe extern "C" fn buffer_free(buffer_ptr: *mut u8, buffer_len: usize) -> FfiResult<NullPtr> {
861 check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null());
862 let x: *mut [u8] = core::slice::from_raw_parts_mut(buffer_ptr, buffer_len);
863 drop(Box::from_raw(x));
864 FfiResult::ok(null())
865}
866
867#[export_name = "FPArrayStrRefFree"]
880pub unsafe extern "C" fn array_str_ref_free(x: *mut Array<StrRef>) -> FfiResult<NullPtr> {
881 check_null!(x, FfiErrorCode::ArrayNullPointer, null());
882 drop(Box::from_raw(x));
883 FfiResult::ok(null())
884}
885
886#[export_name = "FPArrayWarningFree"]
899pub unsafe extern "C" fn array_warning_free(
900 warnings: *mut Array<parser::Warning>,
901) -> FfiResult<NullPtr> {
902 check_null!(warnings, FfiErrorCode::ArrayNullPointer, null());
903 drop(Box::from_raw(warnings));
904 FfiResult::ok(null())
905}
906
907#[export_name = "FPParseInlineStyle"]
921pub unsafe extern "C" fn parse_inline_style(
922 inline_style_text_ptr: *const c_char,
923 warnings: *mut *mut Array<parser::Warning>,
924) -> FfiResult<*mut InlineRule> {
925 check_null!(
926 inline_style_text_ptr,
927 FfiErrorCode::InlineStyleTextNullPointer,
928 null_mut()
929 );
930 let inline_style_text = CStr::from_ptr(inline_style_text_ptr).to_string_lossy();
931 let (prop, w) =
932 parser::parse_inline_style(&inline_style_text, parser::StyleParsingDebugMode::None);
933 if !warnings.is_null() {
934 *warnings = Box::into_raw(Box::new(w.into()));
935 }
936 let mut important = BitSet::new();
937 let mut bs_empty = true;
938 let properties = prop
939 .into_iter()
940 .enumerate()
941 .map(|(index, x)| match x {
942 PropertyMeta::Normal { property } => property,
943 PropertyMeta::Important { property } => {
944 important.insert(index);
945 bs_empty = false;
946 property
947 }
948 PropertyMeta::DebugGroup { .. } => Property::Unknown,
949 })
950 .collect();
951 let important = if bs_empty {
952 ImportantBitSet::None
953 } else {
954 ImportantBitSet::Array(important.into_bit_vec().to_bytes().into())
955 };
956 let inline_rule = InlineRule::new(properties, important);
957 FfiResult::ok(Box::into_raw(Box::new(inline_rule)))
958}
959
960#[export_name = "FPInlineStyleFree"]
973pub unsafe extern "C" fn inline_style_free(inline_rule: *mut InlineRule) -> FfiResult<NullPtr> {
974 check_null!(inline_rule, FfiErrorCode::InlineRuleNullPointer, null());
975 drop(Box::from_raw(inline_rule));
976 FfiResult::ok(null())
977}
978
979#[export_name = "FPParseStyleSheetFromString"]
992pub unsafe extern "C" fn parse_style_sheet_from_string(
993 style_text_ptr: *const c_char,
994) -> FfiResult<*mut StyleSheet> {
995 check_null!(
996 style_text_ptr,
997 FfiErrorCode::StyleTextNullPointer,
998 null_mut()
999 );
1000 let style_text = CStr::from_ptr(style_text_ptr).to_string_lossy();
1001 let (compiled_style_sheet, _) = parser::parse_style_sheet("string", &style_text);
1002 let style_sheet = StyleSheet::from_sheet(&compiled_style_sheet);
1003 FfiResult::ok(Box::into_raw(Box::new(style_sheet)))
1004}
1005
1006#[export_name = "FPParseSelectorFromString"]
1019pub unsafe extern "C" fn parse_selector_from_string(
1020 selector_text_ptr: *const c_char,
1021) -> FfiResult<*mut Selector> {
1022 check_null!(
1023 selector_text_ptr,
1024 FfiErrorCode::SelectorTextNullPointer,
1025 null_mut()
1026 );
1027 let selector_text = CStr::from_ptr(selector_text_ptr).to_string_lossy();
1028 let selector = Selector::from_string(&selector_text);
1029 FfiResult::ok(Box::into_raw(Box::new(selector)))
1030}
1031
1032#[export_name = "FPSelectorFree"]
1045pub unsafe extern "C" fn selector_free(selector: *mut Selector) -> FfiResult<NullPtr> {
1046 check_null!(selector, FfiErrorCode::SelectorNullPointer, null());
1047 drop(Box::from_raw(selector));
1048 FfiResult::ok(null())
1049}
1050
1051#[export_name = "FPStyleSheetFree"]
1064pub unsafe extern "C" fn style_sheet_free(style_sheet: *mut StyleSheet) -> FfiResult<NullPtr> {
1065 check_null!(style_sheet, FfiErrorCode::StyleSheetNullPointer, null());
1066 drop(Box::from_raw(style_sheet));
1067 FfiResult::ok(null())
1068}
1069
1070#[cfg(feature = "deserialize")]
1084#[export_name = "FPStyleSheetBincodeVersion"]
1085pub unsafe extern "C" fn style_sheet_bincode_version(
1086 buffer_ptr: *mut u8,
1087 buffer_len: usize,
1088) -> FfiResult<*mut StrRef> {
1089 use float_pigment_consistent_bincode::Options;
1090 check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null_mut());
1091 let sheet = de_static_ref_zero_copy_env(
1092 core::slice::from_raw_parts_mut(buffer_ptr, buffer_len),
1093 |s| {
1094 let s: Result<StyleSheet, _> = float_pigment_consistent_bincode::DefaultOptions::new()
1095 .allow_trailing_bytes()
1096 .deserialize(s);
1097 match s {
1098 Ok(ss) => ss,
1099 Err(err) => {
1100 let mut ss = StyleSheet::from_sheet(&sheet::CompiledStyleSheet::new());
1101 if let StyleSheet::V1(ssv) = &mut ss {
1102 ssv.version = Box::new(
1103 format!(
1104 "Failed to deserialize bincode formatted style sheet: {}",
1105 err
1106 )
1107 .into(),
1108 );
1109 }
1110 ss
1111 }
1112 }
1113 },
1114 move || {},
1115 );
1116 let version = match sheet {
1117 StyleSheet::V1(v1) => v1.version,
1118 _ => Box::new("unknown version".into()),
1119 };
1120 FfiResult::ok(Box::into_raw(version))
1121}
1122
1123#[export_name = "FPCssParserVersion"]
1132pub unsafe extern "C" fn css_parser_version() -> FfiResult<*mut StrRef> {
1133 let version = env!("CARGO_PKG_VERSION").to_string().into();
1134 FfiResult::ok(Box::into_raw(Box::new(version)))
1135}
1136
1137#[repr(C)]
1138#[derive(Debug, Default)]
1139pub struct ColorValue {
1140 red: u8,
1141 green: u8,
1142 blue: u8,
1143 alpha: u8,
1144}
1145
1146#[export_name = "FPParseColorFromString"]
1159pub unsafe extern "C" fn parse_color_from_string(source: *const c_char) -> FfiResult<ColorValue> {
1160 check_null!(
1161 source,
1162 FfiErrorCode::SourceNullPointer,
1163 ColorValue::default()
1164 );
1165 let source = CStr::from_ptr(source).to_string_lossy();
1166 let ret = parse_color_to_rgba(&source);
1167 FfiResult::ok(ColorValue {
1168 red: ret.0,
1169 green: ret.1,
1170 blue: ret.2,
1171 alpha: ret.3,
1172 })
1173}
1174
1175#[export_name = "FPSubstituteVariable"]
1191pub unsafe extern "C" fn substitute_variable(
1192 expr_ptr: *const c_char,
1193 map: RawMutPtr,
1194 getter: CustomPropertyGetter,
1195 setter: CustomPropertySetter,
1196) -> FfiResult<*const c_char> {
1197 check_null!(expr_ptr, FfiErrorCode::ExprPtrNullPointer, null());
1198 check_null!(map, FfiErrorCode::MapNullPointer, null());
1199 let expr = CStr::from_ptr(expr_ptr).to_string_lossy();
1200 let context = CustomPropertyContext::create(map, getter, setter);
1201 if let Some(ret) = parser::property_value::var::substitute_variable(&expr, &context) {
1202 if let Ok(r) = CString::new(ret) {
1203 return FfiResult::ok(r.into_raw());
1204 }
1205 }
1206 FfiResult::ok(null())
1207}
1208
1209#[export_name = "FPStrFree"]
1222pub unsafe extern "C" fn str_free(ptr: *const c_char) -> FfiResult<NullPtr> {
1223 check_null!(ptr, FfiErrorCode::StrNullPointer, null());
1224 drop(CString::from_raw(ptr as *mut c_char));
1225 FfiResult::ok(null())
1226}