diff options
Diffstat (limited to 'packages/dev-libs')
3 files changed, 223 insertions, 0 deletions
diff --git a/packages/dev-libs/libbpf/libbpf-1.8.0.exheres-0 b/packages/dev-libs/libbpf/libbpf-1.8.0.exheres-0 new file mode 100644 index 0000000..9d6e2fd --- /dev/null +++ b/packages/dev-libs/libbpf/libbpf-1.8.0.exheres-0 @@ -0,0 +1,33 @@ +# Copyright 2026 Gurov <thuggerthugger1@duck.com> +# Distributed under the terms of the GNU General Public License v2 + +require github [ user=libbpf tag=v${PV} ] + +SUMMARY="Library for loading and managing eBPF programs" + +LICENCES="|| ( LGPL-2.1 BSD-2 )" +SLOT="0" +PLATFORMS="~amd64" + +DEPENDENCIES=" + build: + dev-util/pkgconf + sys-kernel/linux-headers + + build+run: + dev-util/elfutils + sys-libs/zlib +" + +src_compile() { + emake -C src +} + +src_install() { + emake -C src install \ + DESTDIR="${IMAGE}" \ + PREFIX="/usr/$(exhost --target)" \ + LIBDIR="/usr/$(exhost --target)/lib" + edo rm "${IMAGE}/usr/$(exhost --target)/lib/libbpf.a" + emagicdocs +} diff --git a/packages/dev-libs/tlottie/files/tlottie-0_pre20260911-tdesktop-compat.patch b/packages/dev-libs/tlottie/files/tlottie-0_pre20260911-tdesktop-compat.patch new file mode 100644 index 0000000..595e044 --- /dev/null +++ b/packages/dev-libs/tlottie/files/tlottie-0_pre20260911-tdesktop-compat.patch @@ -0,0 +1,160 @@ +diff --git a/src/composition/limits.rs b/src/composition/limits.rs +index f8de04c..d4715ab 100644 +--- a/src/composition/limits.rs ++++ b/src/composition/limits.rs +@@ -87,7 +87,9 @@ pub struct Limits { + pub max_render_points: usize, + /// Maximum cumulative dash output allocation estimate per frame, in bytes. + pub max_render_dash_bytes: usize, +- /// Maximum geometry/raster work units charged per frame. ++ /// Maximum geometry/raster work units charged per frame. Telegram's gift ++ /// models peak near 5M (~1.25ms/frame, half of what rlottie spends on ++ /// them uncapped), so the cap keeps headroom above real content. + pub max_render_work: usize, + /// Maximum weighted pixel visits per frame at 64x64 or smaller. + /// Larger outputs scale this allowance proportionally to canvas area. +@@ -140,7 +142,7 @@ impl Default for Limits { + max_dimension: 8192, + max_render_points: 1_048_576, + max_render_dash_bytes: 6_330_240, +- max_render_work: 4_194_304, ++ max_render_work: 8_388_608, + max_render_pixels: 64 * 1024 * 1024, + max_render_bytes: 36 * 1024 * 1024, + } +diff --git a/src/composition/parse.rs b/src/composition/parse.rs +index 47fdaa6..4a0aac8 100644 +--- a/src/composition/parse.rs ++++ b/src/composition/parse.rs +@@ -222,7 +222,9 @@ fn parse_vec2(c: &mut Cursor<'_>) -> Result<Vec2> { + match got { + [Some(x), Some(y)] => Ok(Vec2::new(x, y)), + [Some(x), None] => Ok(Vec2::new(x, x)), +- _ => Err(invalid(c, "expected [x, y]")), ++ // rlottie zero-fills a missing component, and optimized .tgs files write ++ // `[]` for every straight-line tangent; rejecting those loses the file. ++ _ => Ok(Vec2::ZERO), + } + } + +@@ -1060,6 +1062,14 @@ fn parse_shape_item(c: &mut Cursor<'_>, limits: &Limits) -> Result<ParsedItem> { + + let mut seen = SeenFields::default(); + let inline_group = for_each_field_until(c, |c, key| { ++ // rlottie dispatches a shape item on `ty` and Skip()s every key ahead of ++ // it, so fields authored before `ty` never reach the reference parser. ++ // Telegram's gift patterns write {"d":3,"ty":"el"} and rely on that: the ++ // ellipses keep the exporter's winding and punch holes in the body path. ++ if ty.is_none() && !matches!(key, b"ty") { ++ c.skip_value()?; ++ return Ok(false); ++ } + match_once!(seen, key, { + b"t" => { + grad_type = parse_f32(c)?; +@@ -1208,9 +1218,8 @@ fn parse_shape_item(c: &mut Cursor<'_>, limits: &Limits) -> Result<ParsedItem> { + None => Ok(Property::Static(default)), + } + }; +- // Path direction on primitives: `d` == 3 reverses the winding. rlottie +- // supports this too, but accidentally ignores `d` if it appears before +- // `ty`; honor the authored field order-independently. ++ // Path direction on primitives: `d` == 3 reverses the winding, for a `d` ++ // that the field loop above accepted (it is dropped before `ty`). + let direction_reversed = |c: &Cursor<'_>, pos: Option<usize>| -> bool { pos.is_some_and(|p| parse_f32(&mut c.fork_at(p)).unwrap_or(1.0) == 3.0) }; + + match &ty { +diff --git a/src/composition/tests/parse.rs b/src/composition/tests/parse.rs +index abbdbba..00aceab 100644 +--- a/src/composition/tests/parse.rs ++++ b/src/composition/tests/parse.rs +@@ -113,21 +113,29 @@ fn parses_shape_layer() { + } + + #[test] +-fn primitive_direction_is_order_independent() { +- let comp = parse( +- r#"{"fr":30,"ip":0,"op":30,"w":100,"h":100,"layers":[ +- {"ty":4,"ind":1,"ip":0,"op":30,"st":0,"ks":{}, ++fn primitive_direction_before_ty_is_dropped() { ++ // rlottie dispatches on `ty` and Skip()s every key ahead of it, so a `d` ++ // written first never reaches the reference parser. Telegram's gift ++ // patterns are authored against that: {"d":3,"ty":"el"} keeps the ++ // exporter's winding so the ellipses punch holes in the body path. ++ let ellipse = |shape: &str| { ++ let json = alloc::format!( ++ r#"{{"fr":30,"ip":0,"op":30,"w":100,"h":100,"layers":[ ++ {{"ty":4,"ind":1,"ip":0,"op":30,"st":0,"ks":{{}}, + "shapes":[ +- {"d":3,"ty":"el","p":{"a":0,"k":[50,50]},"s":{"a":0,"k":[10,10]}}, +- {"ty":"fl","c":{"a":0,"k":[1,0,0,1]},"o":{"a":0,"k":100},"r":1} +- ]} +- ]}"#, +- ) +- .unwrap(); +- let Some(Shape::Ellipse(ellipse)) = comp.layers[0].shapes.first() else { +- panic!("expected ellipse"); ++ {shape}, ++ {{"ty":"fl","c":{{"a":0,"k":[1,0,0,1]}},"o":{{"a":0,"k":100}},"r":1}} ++ ]}} ++ ]}}"# ++ ); ++ let comp = parse(&json).unwrap(); ++ let Some(Shape::Ellipse(ellipse)) = comp.layers[0].shapes.first() else { ++ panic!("expected ellipse"); ++ }; ++ ellipse.reversed + }; +- assert!(ellipse.reversed); ++ assert!(!ellipse(r#"{"d":3,"ty":"el","p":{"a":0,"k":[50,50]},"s":{"a":0,"k":[10,10]}}"#)); ++ assert!(ellipse(r#"{"ty":"el","p":{"a":0,"k":[50,50]},"s":{"a":0,"k":[10,10]},"d":3}"#)); + } + + #[test] +@@ -394,6 +402,19 @@ fn inherited_keyframe_heap_budget_is_cumulative_and_preserves_end_values() { + } + } + ++#[test] ++fn empty_tangent_points_parse_as_zero_corners() { ++ // Optimized .tgs files write `[]` for every straight-line tangent, and ++ // rlottie zero-fills a point it cannot read; rejecting them loses the ++ // whole animation (Telegram's "21_heart_white" typing sticker). ++ let json = br#"{"i":[[],[]],"o":[[],[]],"v":[[2,0],[4,0]],"c":true}"#; ++ let limits = Limits::default(); ++ let path = parse_path_value(&mut Cursor::new(json.as_slice(), 128), &limits).unwrap(); ++ assert_eq!(path.vertices, alloc::vec![Vec2::new(2.0, 0.0), Vec2::new(4.0, 0.0)]); ++ assert!(path.in_tangents.iter().all(|t| *t == Vec2::ZERO)); ++ assert!(path.out_tangents.iter().all(|t| *t == Vec2::ZERO)); ++} ++ + #[test] + fn inherited_path_budget_charges_padded_tangents_before_cloning() { + let json = br#"[{"t":0,"s":[{"v":[[1,2],[3,4]],"i":[],"o":[]}]},{"t":1}]"#; +@@ -412,10 +433,9 @@ fn inherited_path_budget_charges_padded_tangents_before_cloning() { + + #[test] + fn group_walk_preserves_siblings_transforms_and_shared_limits() { +- // Exercise both field orders and resume the parent after the child list. ++ // Resume the parent after the child list. + for group in [ + r#"{"ty":"gr","it":[{"ty":"tr","p":{"k":[3,4]}},{"ty":"gr","it":[{"ty":"rc","p":{"k":[5,6]},"s":{"k":[7,8]}}]},{"ty":"el","p":{"k":[9,10]},"s":{"k":[11,12]}}]}"#, +- r#"{"it":[{"ty":"tr","p":{"k":[3,4]}},{"it":[{"ty":"rc","p":{"k":[5,6]},"s":{"k":[7,8]}}],"ty":"gr"},{"ty":"el","p":{"k":[9,10]},"s":{"k":[11,12]}}],"ty":"gr"}"#, + ] { + let json = alloc::format!(r#"[{group},{{"ty":"fl","c":{{"k":[1,0,0,1]}}}}]"#); + let mut counts = ShapeCounts::default(); +@@ -440,3 +460,14 @@ fn group_walk_preserves_siblings_transforms_and_shared_limits() { + assert!(parse_shape_list(&mut Cursor::new(json, 128), &Limits::default(), 0, &mut ShapeCounts::default()).is_err()); + } + } ++ ++#[test] ++fn group_items_before_ty_are_dropped() { ++ // Same rlottie rule as primitive_direction_before_ty_is_dropped: an `it` ++ // written ahead of `ty` is skipped, so the reference walks an empty group. ++ let json = br#"[{"it":[{"ty":"el","p":{"k":[9,10]},"s":{"k":[11,12]}}],"ty":"gr"},{"ty":"fl","c":{"k":[1,0,0,1]}}]"#; ++ let mut counts = ShapeCounts::default(); ++ let (shapes, _) = parse_shape_list(&mut Cursor::new(json.as_slice(), 128), &Limits::default(), 0, &mut counts).unwrap(); ++ assert!(matches!(&shapes[..], [Shape::Fill(_)])); ++ assert_eq!(counts.paints, 1); ++} diff --git a/packages/dev-libs/tlottie/tlottie-0_pre20260911.exheres-0 b/packages/dev-libs/tlottie/tlottie-0_pre20260911.exheres-0 new file mode 100644 index 0000000..faf85da --- /dev/null +++ b/packages/dev-libs/tlottie/tlottie-0_pre20260911.exheres-0 @@ -0,0 +1,30 @@ +# Copyright 2026 Gurov <thuggerthugger1@duck.com> +# Distributed under the terms of the GNU General Public License v2 + +require cargo [ rust_minimum_version=1.96.1 ] + +TLOTTIE_COMMIT="31f1b542f88e7b4be9a01e749920d857535fc715" + +SUMMARY="Rust library for rendering Lottie animations" +HOMEPAGE="https://github.com/dkaraush/tlottie" +DOWNLOADS="${HOMEPAGE}/archive/${TLOTTIE_COMMIT}.tar.gz -> ${PNV}.tar.gz" +WORK="${WORKBASE}/tlottie-${TLOTTIE_COMMIT}" + +LICENCES="MIT" +SLOT="0" +PLATFORMS="~amd64" + +DEFAULT_SRC_PREPARE_PATCHES=( "${FILES}/${PNV}-tdesktop-compat.patch" ) + +src_compile() { + ecargo rustc --frozen --release --features c-api --lib --crate-type staticlib \ + -- --print native-static-libs +} + +src_install() { + insinto /usr/$(exhost --target)/lib + doins "target/$(rust_target_arch_name)/release/libtlottie.a" + insinto /usr/$(exhost --target)/include/tlottie + doins include/tlottie.h + emagicdocs +} |
