Add byte information to PositionedGlyph (#17900)
# Objective Adds information about the byte length and index of a glyph to `PositionedGlyph`. Useful for text picking, allows for picking with multi-byte characters. Also adds a `line` field that helps with converting back and forth from cosmic's `Cursor`. ## Solution Retrieve the relevant data from cosmic and add it to the glyph in the text pipeline. ## Testing `cargo r -p ci` --- ## Migration Guide `PositionedGlyph::new()` has been removed as there is no longer an unused field. Create new `PositionedGlyph`s directly.
This commit is contained in:
parent
ab38b61001
commit
64d57fad08
@ -20,24 +20,12 @@ pub struct PositionedGlyph {
|
|||||||
pub atlas_info: GlyphAtlasInfo,
|
pub atlas_info: GlyphAtlasInfo,
|
||||||
/// The index of the glyph in the [`ComputedTextBlock`](crate::ComputedTextBlock)'s tracked spans.
|
/// The index of the glyph in the [`ComputedTextBlock`](crate::ComputedTextBlock)'s tracked spans.
|
||||||
pub span_index: usize,
|
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.
|
/// The index of the glyph's line.
|
||||||
/// For example, to figure out where to place the cursor in an input box from the mouse's position.
|
pub line_index: usize,
|
||||||
/// Without this, it's only possible in texts where each glyph is one byte. Cosmic text has methods for this
|
/// The byte index of the glyph in it's line.
|
||||||
/// cosmic-texts [hit detection](https://pop-os.github.io/cosmic-text/cosmic_text/struct.Buffer.html#method.hit)
|
pub byte_index: usize,
|
||||||
byte_index: usize,
|
/// The byte length of the glyph.
|
||||||
}
|
pub byte_length: 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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about a glyph in an atlas.
|
/// Information about a glyph in an atlas.
|
||||||
|
|||||||
@ -263,77 +263,84 @@ impl TextPipeline {
|
|||||||
let buffer = &mut computed.buffer;
|
let buffer = &mut computed.buffer;
|
||||||
let box_size = buffer_dimensions(buffer);
|
let box_size = buffer_dimensions(buffer);
|
||||||
|
|
||||||
let result = buffer
|
let result = buffer.layout_runs().try_for_each(|run| {
|
||||||
.layout_runs()
|
let result = run
|
||||||
.flat_map(|run| {
|
.glyphs
|
||||||
run.glyphs
|
.iter()
|
||||||
.iter()
|
.map(move |layout_glyph| (layout_glyph, run.line_y, run.line_i))
|
||||||
.map(move |layout_glyph| (layout_glyph, run.line_y))
|
.try_for_each(|(layout_glyph, line_y, line_i)| {
|
||||||
})
|
let mut temp_glyph;
|
||||||
.try_for_each(|(layout_glyph, line_y)| {
|
let span_index = layout_glyph.metadata;
|
||||||
let mut temp_glyph;
|
let font_id = glyph_info[span_index].0;
|
||||||
let span_index = layout_glyph.metadata;
|
let font_smoothing = glyph_info[span_index].1;
|
||||||
let font_id = glyph_info[span_index].0;
|
|
||||||
let font_smoothing = glyph_info[span_index].1;
|
|
||||||
|
|
||||||
let layout_glyph = if font_smoothing == FontSmoothing::None {
|
let layout_glyph = if font_smoothing == FontSmoothing::None {
|
||||||
// If font smoothing is disabled, round the glyph positions and sizes,
|
// If font smoothing is disabled, round the glyph positions and sizes,
|
||||||
// effectively discarding all subpixel layout.
|
// effectively discarding all subpixel layout.
|
||||||
temp_glyph = layout_glyph.clone();
|
temp_glyph = layout_glyph.clone();
|
||||||
temp_glyph.x = temp_glyph.x.round();
|
temp_glyph.x = temp_glyph.x.round();
|
||||||
temp_glyph.y = temp_glyph.y.round();
|
temp_glyph.y = temp_glyph.y.round();
|
||||||
temp_glyph.w = temp_glyph.w.round();
|
temp_glyph.w = temp_glyph.w.round();
|
||||||
temp_glyph.x_offset = temp_glyph.x_offset.round();
|
temp_glyph.x_offset = temp_glyph.x_offset.round();
|
||||||
temp_glyph.y_offset = temp_glyph.y_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.line_height_opt = temp_glyph.line_height_opt.map(f32::round);
|
||||||
|
|
||||||
&temp_glyph
|
&temp_glyph
|
||||||
} else {
|
} else {
|
||||||
layout_glyph
|
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
|
let atlas_info = font_atlas_set
|
||||||
.get_glyph_atlas_info(physical_glyph.cache_key, font_smoothing)
|
.get_glyph_atlas_info(physical_glyph.cache_key, font_smoothing)
|
||||||
.map(Ok)
|
.map(Ok)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
font_atlas_set.add_glyph_to_atlas(
|
font_atlas_set.add_glyph_to_atlas(
|
||||||
texture_atlases,
|
texture_atlases,
|
||||||
textures,
|
textures,
|
||||||
&mut font_system.0,
|
&mut font_system.0,
|
||||||
&mut swash_cache.0,
|
&mut swash_cache.0,
|
||||||
layout_glyph,
|
layout_glyph,
|
||||||
font_smoothing,
|
font_smoothing,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let texture_atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap();
|
let texture_atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap();
|
||||||
let location = atlas_info.location;
|
let location = atlas_info.location;
|
||||||
let glyph_rect = texture_atlas.textures[location.glyph_index];
|
let glyph_rect = texture_atlas.textures[location.glyph_index];
|
||||||
let left = location.offset.x as f32;
|
let left = location.offset.x as f32;
|
||||||
let top = location.offset.y as f32;
|
let top = location.offset.y as f32;
|
||||||
let glyph_size = UVec2::new(glyph_rect.width(), glyph_rect.height());
|
let glyph_size = UVec2::new(glyph_rect.width(), glyph_rect.height());
|
||||||
|
|
||||||
// offset by half the size because the origin is center
|
// 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 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 =
|
||||||
let y = match y_axis_orientation {
|
line_y.round() + physical_glyph.y as f32 - top + glyph_size.y as f32 / 2.0;
|
||||||
YAxisOrientation::TopToBottom => y,
|
let y = match y_axis_orientation {
|
||||||
YAxisOrientation::BottomToTop => box_size.y - y,
|
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,
|
let pos_glyph = PositionedGlyph {
|
||||||
// when glyphs are not limited to single byte representation, relevant for #1319
|
position,
|
||||||
let pos_glyph =
|
size: glyph_size.as_vec2(),
|
||||||
PositionedGlyph::new(position, glyph_size.as_vec2(), atlas_info, span_index);
|
atlas_info,
|
||||||
layout_info.glyphs.push(pos_glyph);
|
span_index,
|
||||||
Ok(())
|
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.
|
// Return the scratch vec.
|
||||||
self.glyph_info = glyph_info;
|
self.glyph_info = glyph_info;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user