Skip to content

Commit a06de1f

Browse files
authored
UI text module refactor (#21630)
# Objective The `measure_text_system` and `text_system` systems don't do anything except iterate a query and then delegate to two other functions, `create_text_measure` and `queue_text`, respectively. This doesn't serve any purpose and just makes these systems harder to understand. ## Solution Flatten the module by moving the code from `create_text_measure` and `queue_text` into the systems and remove those functions.
1 parent 71114e1 commit a06de1f

File tree

1 file changed

+97
-152
lines changed

1 file changed

+97
-152
lines changed

crates/bevy_ui/src/widget/text.rs

Lines changed: 97 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use bevy_ecs::{
1212
query::With,
1313
reflect::ReflectComponent,
1414
system::{Query, Res, ResMut},
15-
world::{Mut, Ref},
15+
world::Ref,
1616
};
1717
use bevy_image::prelude::*;
1818
use bevy_math::Vec2;
@@ -223,55 +223,6 @@ impl Measure for TextMeasure {
223223
}
224224
}
225225

226-
#[inline]
227-
fn create_text_measure<'a>(
228-
entity: Entity,
229-
fonts: &Assets<Font>,
230-
scale_factor: f64,
231-
spans: impl Iterator<Item = (Entity, usize, &'a str, &'a TextFont, Color, LineHeight)>,
232-
block: Ref<TextLayout>,
233-
text_pipeline: &mut TextPipeline,
234-
mut content_size: Mut<ContentSize>,
235-
mut text_flags: Mut<TextNodeFlags>,
236-
mut computed: Mut<ComputedTextBlock>,
237-
font_system: &mut CosmicFontSystem,
238-
) {
239-
match text_pipeline.create_text_measure(
240-
entity,
241-
fonts,
242-
spans,
243-
scale_factor,
244-
&block,
245-
computed.as_mut(),
246-
font_system,
247-
) {
248-
Ok(measure) => {
249-
if block.linebreak == LineBreak::NoWrap {
250-
content_size.set(NodeMeasure::Fixed(FixedMeasure { size: measure.max }));
251-
} else {
252-
content_size.set(NodeMeasure::Text(TextMeasure { info: measure }));
253-
}
254-
255-
// Text measure func created successfully, so set `TextNodeFlags` to schedule a recompute
256-
text_flags.needs_measure_fn = false;
257-
text_flags.needs_recompute = true;
258-
}
259-
Err(TextError::NoSuchFont) => {
260-
// Try again next frame
261-
text_flags.needs_measure_fn = true;
262-
}
263-
Err(
264-
e @ (TextError::FailedToAddGlyph(_)
265-
| TextError::FailedToGetGlyphImage(_)
266-
| TextError::MissingAtlasLayout
267-
| TextError::MissingAtlasTexture
268-
| TextError::InconsistentAtlasState),
269-
) => {
270-
panic!("Fatal error when processing text: {e}.");
271-
}
272-
};
273-
}
274-
275226
/// Generates a new [`Measure`] for a text node on changes to its [`Text`] component.
276227
///
277228
/// A `Measure` is used by the UI's layout algorithm to determine the appropriate amount of space
@@ -300,98 +251,61 @@ pub fn measure_text_system(
300251
mut text_pipeline: ResMut<TextPipeline>,
301252
mut font_system: ResMut<CosmicFontSystem>,
302253
) {
303-
for (entity, block, content_size, text_flags, computed, computed_target, computed_node) in
304-
&mut text_query
254+
for (
255+
entity,
256+
block,
257+
mut content_size,
258+
mut text_flags,
259+
mut computed,
260+
computed_target,
261+
computed_node,
262+
) in &mut text_query
305263
{
306264
// Note: the ComputedTextBlock::needs_rerender bool is cleared in create_text_measure().
307265
// 1e-5 epsilon to ignore tiny scale factor float errors
308-
if 1e-5
266+
if !(1e-5
309267
< (computed_target.scale_factor() - computed_node.inverse_scale_factor.recip()).abs()
310268
|| computed.needs_rerender()
311269
|| text_flags.needs_measure_fn
312-
|| content_size.is_added()
270+
|| content_size.is_added())
313271
{
314-
create_text_measure(
315-
entity,
316-
&fonts,
317-
computed_target.scale_factor.into(),
318-
text_reader.iter(entity),
319-
block,
320-
&mut text_pipeline,
321-
content_size,
322-
text_flags,
323-
computed,
324-
&mut font_system,
325-
);
272+
continue;
326273
}
327-
}
328-
}
329-
330-
#[inline]
331-
fn queue_text(
332-
entity: Entity,
333-
fonts: &Assets<Font>,
334-
text_pipeline: &mut TextPipeline,
335-
font_atlas_set: &mut FontAtlasSet,
336-
texture_atlases: &mut Assets<TextureAtlasLayout>,
337-
textures: &mut Assets<Image>,
338-
scale_factor: f32,
339-
inverse_scale_factor: f32,
340-
block: &TextLayout,
341-
node: Ref<ComputedNode>,
342-
mut text_flags: Mut<TextNodeFlags>,
343-
text_layout_info: Mut<TextLayoutInfo>,
344-
computed: &mut ComputedTextBlock,
345-
text_reader: &mut TextUiReader,
346-
font_system: &mut CosmicFontSystem,
347-
swash_cache: &mut SwashCache,
348-
) {
349-
// Skip the text node if it is waiting for a new measure func
350-
if text_flags.needs_measure_fn {
351-
return;
352-
}
353274

354-
let physical_node_size = if block.linebreak == LineBreak::NoWrap {
355-
// With `NoWrap` set, no constraints are placed on the width of the text.
356-
TextBounds::UNBOUNDED
357-
} else {
358-
// `scale_factor` is already multiplied by `UiScale`
359-
TextBounds::new(node.unrounded_size.x, node.unrounded_size.y)
360-
};
275+
match text_pipeline.create_text_measure(
276+
entity,
277+
fonts.as_ref(),
278+
text_reader.iter(entity),
279+
computed_target.scale_factor.into(),
280+
&block,
281+
computed.as_mut(),
282+
&mut font_system,
283+
) {
284+
Ok(measure) => {
285+
if block.linebreak == LineBreak::NoWrap {
286+
content_size.set(NodeMeasure::Fixed(FixedMeasure { size: measure.max }));
287+
} else {
288+
content_size.set(NodeMeasure::Text(TextMeasure { info: measure }));
289+
}
361290

362-
let text_layout_info = text_layout_info.into_inner();
363-
match text_pipeline.queue_text(
364-
text_layout_info,
365-
fonts,
366-
text_reader.iter(entity),
367-
scale_factor.into(),
368-
block,
369-
physical_node_size,
370-
font_atlas_set,
371-
texture_atlases,
372-
textures,
373-
computed,
374-
font_system,
375-
swash_cache,
376-
) {
377-
Err(TextError::NoSuchFont) => {
378-
// There was an error processing the text layout, try again next frame
379-
text_flags.needs_recompute = true;
380-
}
381-
Err(
382-
e @ (TextError::FailedToAddGlyph(_)
383-
| TextError::FailedToGetGlyphImage(_)
384-
| TextError::MissingAtlasLayout
385-
| TextError::MissingAtlasTexture
386-
| TextError::InconsistentAtlasState),
387-
) => {
388-
panic!("Fatal error when processing text: {e}.");
389-
}
390-
Ok(()) => {
391-
text_layout_info.scale_factor = scale_factor;
392-
text_layout_info.size *= inverse_scale_factor;
393-
text_flags.needs_recompute = false;
394-
}
291+
// Text measure func created successfully, so set `TextNodeFlags` to schedule a recompute
292+
text_flags.needs_measure_fn = false;
293+
text_flags.needs_recompute = true;
294+
}
295+
Err(TextError::NoSuchFont) => {
296+
// Try again next frame
297+
text_flags.needs_measure_fn = true;
298+
}
299+
Err(
300+
e @ (TextError::FailedToAddGlyph(_)
301+
| TextError::FailedToGetGlyphImage(_)
302+
| TextError::MissingAtlasLayout
303+
| TextError::MissingAtlasTexture
304+
| TextError::InconsistentAtlasState),
305+
) => {
306+
panic!("Fatal error when processing text: {e}.");
307+
}
308+
};
395309
}
396310
}
397311

@@ -421,26 +335,57 @@ pub fn text_system(
421335
mut font_system: ResMut<CosmicFontSystem>,
422336
mut swash_cache: ResMut<SwashCache>,
423337
) {
424-
for (entity, node, block, text_layout_info, text_flags, mut computed) in &mut text_query {
425-
if node.is_changed() || text_flags.needs_recompute {
426-
queue_text(
427-
entity,
428-
&fonts,
429-
&mut text_pipeline,
430-
&mut font_atlas_set,
431-
&mut texture_atlases,
432-
&mut textures,
433-
node.inverse_scale_factor.recip(),
434-
node.inverse_scale_factor,
435-
block,
436-
node,
437-
text_flags,
438-
text_layout_info,
439-
computed.as_mut(),
440-
&mut text_reader,
441-
&mut font_system,
442-
&mut swash_cache,
443-
);
338+
for (entity, node, block, text_layout_info, mut text_flags, mut computed) in &mut text_query {
339+
// Skip the text node if it is waiting for a new measure func
340+
if text_flags.needs_measure_fn {
341+
continue;
342+
}
343+
344+
if !(node.is_changed() || text_flags.needs_recompute) {
345+
continue;
346+
}
347+
348+
let physical_node_size = if block.linebreak == LineBreak::NoWrap {
349+
// With `NoWrap` set, no constraints are placed on the width of the text.
350+
TextBounds::UNBOUNDED
351+
} else {
352+
// `scale_factor` is already multiplied by `UiScale`
353+
TextBounds::new(node.unrounded_size.x, node.unrounded_size.y)
354+
};
355+
356+
let text_layout_info = text_layout_info.into_inner();
357+
match text_pipeline.queue_text(
358+
text_layout_info,
359+
&fonts,
360+
text_reader.iter(entity),
361+
node.inverse_scale_factor.recip() as f64,
362+
block,
363+
physical_node_size,
364+
&mut font_atlas_set,
365+
&mut texture_atlases,
366+
&mut textures,
367+
&mut computed,
368+
&mut font_system,
369+
&mut swash_cache,
370+
) {
371+
Err(TextError::NoSuchFont) => {
372+
// There was an error processing the text layout, try again next frame
373+
text_flags.needs_recompute = true;
374+
}
375+
Err(
376+
e @ (TextError::FailedToAddGlyph(_)
377+
| TextError::FailedToGetGlyphImage(_)
378+
| TextError::MissingAtlasLayout
379+
| TextError::MissingAtlasTexture
380+
| TextError::InconsistentAtlasState),
381+
) => {
382+
panic!("Fatal error when processing text: {e}.");
383+
}
384+
Ok(()) => {
385+
text_layout_info.scale_factor = node.inverse_scale_factor.recip();
386+
text_layout_info.size *= node.inverse_scale_factor;
387+
text_flags.needs_recompute = false;
388+
}
444389
}
445390
}
446391
}

0 commit comments

Comments
 (0)