⎇ fd8f81fc639e71cecef3a6bb618bca6606bdf644
benches/benches/mixed.rs
Ñawpa willay
Pi imata llamkarqan
ch'uya
1use cosmic_text::{Attrs, Buffer, FontSystem, Metrics, Shaping};
2use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
3use rand::prelude::*;
4use rand_chacha::ChaCha8Rng;
5use std::iter;
6use taffy::prelude::*;
7use taffy::style::Style;
8
9pub const LOREM_IPSUM : &str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
10
11struct CosmicTextContext {
12 buffer: cosmic_text::Buffer,
13}
14
15impl CosmicTextContext {
16 fn new(metrics: Metrics, text: &str, attrs: Attrs, font_system: &mut FontSystem) -> Self {
17 let mut buffer = Buffer::new_empty(metrics);
18 buffer.set_size(font_system, None, None);
19 buffer.set_text(font_system, text, attrs, Shaping::Advanced);
20 buffer.shape_until_scroll(font_system, false);
21 Self { buffer }
22 }
23
24 fn measure(
25 &mut self,
26 known_dimensions: taffy::Size<Option<f32>>,
27 available_space: taffy::Size<taffy::AvailableSpace>,
28 font_system: &mut FontSystem,
29 ) -> taffy::Size<f32> {
30 let width_constraint = known_dimensions.width.or(match available_space.width {
31 AvailableSpace::MinContent => Some(0.0),
32 AvailableSpace::MaxContent => None,
33 AvailableSpace::Definite(width) => Some(width),
34 });
35 self.buffer.set_size(font_system, width_constraint, None);
36
37 let (width, total_lines) = self
38 .buffer
39 .layout_runs()
40 .fold((0.0, 0usize), |(width, total_lines), run| (run.line_w.max(width), total_lines + 1));
41 let height = total_lines as f32 * self.buffer.metrics().line_height;
42
43 taffy::Size { width, height }
44 }
45}
46
47fn measure_function(
48 known_dimensions: taffy::Size<Option<f32>>,
49 available_space: taffy::Size<taffy::AvailableSpace>,
50 node_context: Option<&mut CosmicTextContext>,
51 font_system: &mut FontSystem,
52) -> Size<f32> {
53 if let Size { width: Some(width), height: Some(height) } = known_dimensions {
54 return Size { width, height };
55 }
56
57 match node_context {
58 None => Size::ZERO,
59 Some(text_context) => text_context.measure(known_dimensions, available_space, font_system),
60 }
61}
62
63fn random_grid_track<R: Rng>(rng: &mut R) -> GridTemplateComponent<String> {
64 let switch: f32 = rng.random_range(0.0..=1.0);
65 if switch < 0.1 {
66 auto()
67 } else if switch < 0.2 {
68 min_content()
69 } else if switch < 0.3 {
70 max_content()
71 } else if switch < 0.5 {
72 fr(1.0)
73 } else if switch < 0.6 {
74 minmax(length(0.0), fr(1.0))
75 } else if switch < 0.8 {
76 length(40.0)
77 } else {
78 percent(0.3)
79 }
80}
81
82fn random_nxn_grid_style<R: Rng>(rng: &mut R, track_count: usize) -> Style {
83 Style {
84 display: Display::Grid,
85 grid_template_columns: iter::from_fn(|| Some(random_grid_track(rng))).take(track_count).collect(),
86 grid_template_rows: iter::from_fn(|| Some(random_grid_track(rng))).take(track_count).collect(),
87 ..Default::default()
88 }
89}
90
91fn random_flex_style<R: Rng>(rng: &mut R) -> Style {
92 Style {
93 display: Display::Flex,
94 flex_direction: if rng.random_bool(0.5) { FlexDirection::Row } else { FlexDirection::Column },
95 flex_wrap: if rng.random_bool(0.5) { FlexWrap::Wrap } else { FlexWrap::NoWrap },
96 ..Default::default()
97 }
98}
99
100fn build_mixed_tree(
101 taffy: &mut TaffyTree<CosmicTextContext>,
102 font_system: &mut FontSystem,
103 depth: usize,
104 width: usize,
105 rng: &mut ChaCha8Rng,
106 is_grid: bool,
107) -> NodeId {
108 if depth == 0 {
109 let metrics = Metrics { font_size: 14.0, line_height: 16.0 };
110 let context = CosmicTextContext::new(metrics, LOREM_IPSUM, Attrs::new(), font_system);
111 return taffy.new_leaf_with_context(Style::default(), context).unwrap();
112 }
113
114 let children: Vec<NodeId> =
115 (0..width).map(|_| build_mixed_tree(taffy, font_system, depth - 1, width, rng, !is_grid)).collect();
116
117 let style = if is_grid {
118 random_nxn_grid_style(rng, (width as f32).sqrt().ceil() as usize)
119 } else {
120 random_flex_style(rng)
121 };
122
123 taffy.new_with_children(style, &children).unwrap()
124}
125
126fn mixed_benchmark(c: &mut Criterion) {
127 let font_system = std::cell::RefCell::new(FontSystem::new());
128 let mut group = c.benchmark_group("mixed_flex_grid");
129
130 let depths = [2, 4];
131 let widths = [4, 8];
132
133 for &depth in &depths {
134 for &width in &widths {
135 let benchmark_id = BenchmarkId::new("mixed", format!("depth_{}_width_{}", depth, width));
136 group.bench_with_input(benchmark_id, &(depth, width), |b, &(depth, width)| {
137 b.iter_batched(
138 || {
139 let mut taffy = TaffyTree::new();
140 let mut rng = ChaCha8Rng::seed_from_u64(12345);
141 let root =
142 build_mixed_tree(&mut taffy, &mut font_system.borrow_mut(), depth, width, &mut rng, true);
143 (taffy, root)
144 },
145 |(mut taffy, root)| {
146 taffy
147 .compute_layout_with_measure(
148 root,
149 Size::MAX_CONTENT,
150 |known_dimensions, available_space, _node_id, node_context, _style| {
151 measure_function(
152 known_dimensions,
153 available_space,
154 node_context,
155 &mut font_system.borrow_mut(),
156 )
157 },
158 )
159 .unwrap();
160 },
161 criterion::BatchSize::SmallInput,
162 )
163 });
164 }
165 }
166 group.finish();
167}
168
169criterion_group!(benches, mixed_benchmark);
170criterion_main!(benches);