diff --git a/crates/bevy_text/src/glyph.rs b/crates/bevy_text/src/glyph.rs index 6de501266c..752b7e6e0c 100644 --- a/crates/bevy_text/src/glyph.rs +++ b/crates/bevy_text/src/glyph.rs @@ -20,24 +20,12 @@ pub struct PositionedGlyph { pub atlas_info: GlyphAtlasInfo, /// The index of the glyph in the [`ComputedTextBlock`](crate::ComputedTextBlock)'s tracked spans. pub span_index: usize, - /// TODO: In order to do text editing, we need access to the size of glyphs and their index in the associated String. - /// For example, to figure out where to place the cursor in an input box from the mouse's position. - /// Without this, it's only possible in texts where each glyph is one byte. Cosmic text has methods for this - /// cosmic-texts [hit detection](https://pop-os.github.io/cosmic-text/cosmic_text/struct.Buffer.html#method.hit) - byte_index: usize, -} - -impl PositionedGlyph { - /// Creates a new [`PositionedGlyph`] - pub fn new(position: Vec2, size: Vec2, atlas_info: GlyphAtlasInfo, span_index: usize) -> Self { - Self { - position, - size, - atlas_info, - span_index, - byte_index: 0, - } - } + /// The index of the glyph's line. + pub line_index: usize, + /// The byte index of the glyph in it's line. + pub byte_index: usize, + /// The byte length of the glyph. + pub byte_length: usize, } /// Information about a glyph in an atlas. diff --git a/crates/bevy_text/src/pipeline.rs b/crates/bevy_text/src/pipeline.rs index e7774569cf..2b2e013059 100644 --- a/crates/bevy_text/src/pipeline.rs +++ b/crates/bevy_text/src/pipeline.rs @@ -263,77 +263,84 @@ impl TextPipeline { let buffer = &mut computed.buffer; let box_size = buffer_dimensions(buffer); - let result = buffer - .layout_runs() - .flat_map(|run| { - run.glyphs - .iter() - .map(move |layout_glyph| (layout_glyph, run.line_y)) - }) - .try_for_each(|(layout_glyph, line_y)| { - let mut temp_glyph; - let span_index = layout_glyph.metadata; - let font_id = glyph_info[span_index].0; - let font_smoothing = glyph_info[span_index].1; + let result = buffer.layout_runs().try_for_each(|run| { + let result = run + .glyphs + .iter() + .map(move |layout_glyph| (layout_glyph, run.line_y, run.line_i)) + .try_for_each(|(layout_glyph, line_y, line_i)| { + let mut temp_glyph; + let span_index = layout_glyph.metadata; + let font_id = glyph_info[span_index].0; + let font_smoothing = glyph_info[span_index].1; - let layout_glyph = if font_smoothing == FontSmoothing::None { - // If font smoothing is disabled, round the glyph positions and sizes, - // effectively discarding all subpixel layout. - temp_glyph = layout_glyph.clone(); - temp_glyph.x = temp_glyph.x.round(); - temp_glyph.y = temp_glyph.y.round(); - temp_glyph.w = temp_glyph.w.round(); - temp_glyph.x_offset = temp_glyph.x_offset.round(); - temp_glyph.y_offset = temp_glyph.y_offset.round(); - temp_glyph.line_height_opt = temp_glyph.line_height_opt.map(f32::round); + let layout_glyph = if font_smoothing == FontSmoothing::None { + // If font smoothing is disabled, round the glyph positions and sizes, + // effectively discarding all subpixel layout. + temp_glyph = layout_glyph.clone(); + temp_glyph.x = temp_glyph.x.round(); + temp_glyph.y = temp_glyph.y.round(); + temp_glyph.w = temp_glyph.w.round(); + temp_glyph.x_offset = temp_glyph.x_offset.round(); + temp_glyph.y_offset = temp_glyph.y_offset.round(); + temp_glyph.line_height_opt = temp_glyph.line_height_opt.map(f32::round); - &temp_glyph - } else { - layout_glyph - }; + &temp_glyph + } else { + layout_glyph + }; - let font_atlas_set = font_atlas_sets.sets.entry(font_id).or_default(); + let font_atlas_set = font_atlas_sets.sets.entry(font_id).or_default(); - let physical_glyph = layout_glyph.physical((0., 0.), 1.); + let physical_glyph = layout_glyph.physical((0., 0.), 1.); - let atlas_info = font_atlas_set - .get_glyph_atlas_info(physical_glyph.cache_key, font_smoothing) - .map(Ok) - .unwrap_or_else(|| { - font_atlas_set.add_glyph_to_atlas( - texture_atlases, - textures, - &mut font_system.0, - &mut swash_cache.0, - layout_glyph, - font_smoothing, - ) - })?; + let atlas_info = font_atlas_set + .get_glyph_atlas_info(physical_glyph.cache_key, font_smoothing) + .map(Ok) + .unwrap_or_else(|| { + font_atlas_set.add_glyph_to_atlas( + texture_atlases, + textures, + &mut font_system.0, + &mut swash_cache.0, + layout_glyph, + font_smoothing, + ) + })?; - let texture_atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap(); - let location = atlas_info.location; - let glyph_rect = texture_atlas.textures[location.glyph_index]; - let left = location.offset.x as f32; - let top = location.offset.y as f32; - let glyph_size = UVec2::new(glyph_rect.width(), glyph_rect.height()); + let texture_atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap(); + let location = atlas_info.location; + let glyph_rect = texture_atlas.textures[location.glyph_index]; + let left = location.offset.x as f32; + let top = location.offset.y as f32; + let glyph_size = UVec2::new(glyph_rect.width(), glyph_rect.height()); - // offset by half the size because the origin is center - let x = glyph_size.x as f32 / 2.0 + left + physical_glyph.x as f32; - let y = line_y.round() + physical_glyph.y as f32 - top + glyph_size.y as f32 / 2.0; - let y = match y_axis_orientation { - YAxisOrientation::TopToBottom => y, - YAxisOrientation::BottomToTop => box_size.y - y, - }; + // offset by half the size because the origin is center + let x = glyph_size.x as f32 / 2.0 + left + physical_glyph.x as f32; + let y = + line_y.round() + physical_glyph.y as f32 - top + glyph_size.y as f32 / 2.0; + let y = match y_axis_orientation { + YAxisOrientation::TopToBottom => y, + YAxisOrientation::BottomToTop => box_size.y - y, + }; - let position = Vec2::new(x, y); + let position = Vec2::new(x, y); - // TODO: recreate the byte index, that keeps track of where a cursor is, - // when glyphs are not limited to single byte representation, relevant for #1319 - let pos_glyph = - PositionedGlyph::new(position, glyph_size.as_vec2(), atlas_info, span_index); - layout_info.glyphs.push(pos_glyph); - Ok(()) - }); + let pos_glyph = PositionedGlyph { + position, + size: glyph_size.as_vec2(), + atlas_info, + span_index, + byte_index: layout_glyph.start, + byte_length: layout_glyph.end - layout_glyph.start, + line_index: line_i, + }; + layout_info.glyphs.push(pos_glyph); + Ok(()) + }); + + result + }); // Return the scratch vec. self.glyph_info = glyph_info;