WIP
This commit is contained in:
parent
1a3650ef2a
commit
847376cd8f
7 changed files with 66 additions and 28 deletions
|
@ -74,12 +74,13 @@ impl<S: 'static + Send + Sync> Element for Text<S> {
|
||||||
let rem_size = cx.rem_size();
|
let rem_size = cx.rem_size();
|
||||||
let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
|
let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
|
||||||
let element_state = element_state.clone();
|
let element_state = element_state.clone();
|
||||||
move |_, _| {
|
move |known_dimensions, _| {
|
||||||
let Some(line_layout) = text_system
|
let Some(line_layout) = text_system
|
||||||
.layout_line(
|
.layout_text(
|
||||||
text.as_ref(),
|
text.as_ref(),
|
||||||
font_size,
|
font_size,
|
||||||
&[(text.len(), text_style.to_run())],
|
&[(text.len(), text_style.to_run())],
|
||||||
|
known_dimensions.width, // Wrap if we know the width.
|
||||||
)
|
)
|
||||||
.log_err()
|
.log_err()
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -6,8 +6,8 @@ mod test;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyWindowHandle, Bounds, DevicePixels, Event, Executor, Font, FontId, FontMetrics,
|
AnyWindowHandle, Bounds, DevicePixels, Event, Executor, Font, FontId, FontMetrics,
|
||||||
GlobalPixels, GlyphId, Pixels, Point, RenderGlyphParams, RenderImageParams, RenderSvgParams,
|
GlobalPixels, GlyphId, LineLayout, Pixels, Point, RenderGlyphParams, RenderImageParams,
|
||||||
Result, Scene, ShapedLine, SharedString, Size,
|
RenderSvgParams, Result, Scene, SharedString, Size,
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use async_task::Runnable;
|
use async_task::Runnable;
|
||||||
|
@ -171,7 +171,7 @@ pub trait PlatformTextSystem: Send + Sync {
|
||||||
fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId>;
|
fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId>;
|
||||||
fn glyph_raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>>;
|
fn glyph_raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>>;
|
||||||
fn rasterize_glyph(&self, params: &RenderGlyphParams) -> Result<(Size<DevicePixels>, Vec<u8>)>;
|
fn rasterize_glyph(&self, params: &RenderGlyphParams) -> Result<(Size<DevicePixels>, Vec<u8>)>;
|
||||||
fn layout_line(&self, text: &str, font_size: Pixels, runs: &[(usize, FontId)]) -> ShapedLine;
|
fn layout_line(&self, text: &str, font_size: Pixels, runs: &[(usize, FontId)]) -> LineLayout;
|
||||||
fn wrap_line(
|
fn wrap_line(
|
||||||
&self,
|
&self,
|
||||||
text: &str,
|
text: &str,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
point, px, size, Bounds, DevicePixels, Font, FontFeatures, FontId, FontMetrics, FontStyle,
|
point, px, size, Bounds, DevicePixels, Font, FontFeatures, FontId, FontMetrics, FontStyle,
|
||||||
FontWeight, GlyphId, Pixels, PlatformTextSystem, Point, RenderGlyphParams, Result, ShapedGlyph,
|
FontWeight, GlyphId, LineLayout, Pixels, PlatformTextSystem, Point, RenderGlyphParams, Result,
|
||||||
ShapedLine, ShapedRun, SharedString, Size, SUBPIXEL_VARIANTS,
|
ShapedGlyph, ShapedRun, SharedString, Size, SUBPIXEL_VARIANTS,
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use cocoa::appkit::{CGFloat, CGPoint};
|
use cocoa::appkit::{CGFloat, CGPoint};
|
||||||
|
@ -154,7 +154,7 @@ impl PlatformTextSystem for MacTextSystem {
|
||||||
text: &str,
|
text: &str,
|
||||||
font_size: Pixels,
|
font_size: Pixels,
|
||||||
font_runs: &[(usize, FontId)],
|
font_runs: &[(usize, FontId)],
|
||||||
) -> ShapedLine {
|
) -> LineLayout {
|
||||||
self.0.write().layout_line(text, font_size, font_runs)
|
self.0.write().layout_line(text, font_size, font_runs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,7 +342,7 @@ impl MacTextSystemState {
|
||||||
text: &str,
|
text: &str,
|
||||||
font_size: Pixels,
|
font_size: Pixels,
|
||||||
font_runs: &[(usize, FontId)],
|
font_runs: &[(usize, FontId)],
|
||||||
) -> ShapedLine {
|
) -> LineLayout {
|
||||||
// Construct the attributed string, converting UTF8 ranges to UTF16 ranges.
|
// Construct the attributed string, converting UTF8 ranges to UTF16 ranges.
|
||||||
let mut string = CFMutableAttributedString::new();
|
let mut string = CFMutableAttributedString::new();
|
||||||
{
|
{
|
||||||
|
@ -394,7 +394,7 @@ impl MacTextSystemState {
|
||||||
let font_id = self.id_for_native_font(font);
|
let font_id = self.id_for_native_font(font);
|
||||||
|
|
||||||
let mut ix_converter = StringIndexConverter::new(text);
|
let mut ix_converter = StringIndexConverter::new(text);
|
||||||
let mut glyphs = Vec::new();
|
let mut glyphs = SmallVec::new();
|
||||||
for ((glyph_id, position), glyph_utf16_ix) in run
|
for ((glyph_id, position), glyph_utf16_ix) in run
|
||||||
.glyphs()
|
.glyphs()
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -415,7 +415,7 @@ impl MacTextSystemState {
|
||||||
}
|
}
|
||||||
|
|
||||||
let typographic_bounds = line.get_typographic_bounds();
|
let typographic_bounds = line.get_typographic_bounds();
|
||||||
ShapedLine {
|
LineLayout {
|
||||||
width: typographic_bounds.width.into(),
|
width: typographic_bounds.width.into(),
|
||||||
ascent: typographic_bounds.ascent.into(),
|
ascent: typographic_bounds.ascent.into(),
|
||||||
descent: typographic_bounds.descent.into(),
|
descent: typographic_bounds.descent.into(),
|
||||||
|
|
|
@ -7,6 +7,7 @@ use anyhow::anyhow;
|
||||||
pub use font_features::*;
|
pub use font_features::*;
|
||||||
pub use line::*;
|
pub use line::*;
|
||||||
use line_wrapper::*;
|
use line_wrapper::*;
|
||||||
|
use smallvec::SmallVec;
|
||||||
pub use text_layout_cache::*;
|
pub use text_layout_cache::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -143,13 +144,15 @@ impl TextSystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout_line(
|
pub fn layout_text(
|
||||||
&self,
|
&self,
|
||||||
text: &str,
|
text: &str,
|
||||||
font_size: Pixels,
|
font_size: Pixels,
|
||||||
runs: &[(usize, RunStyle)],
|
runs: &[(usize, RunStyle)],
|
||||||
) -> Result<Line> {
|
wrap_width: Option<Pixels>,
|
||||||
let mut font_runs = self.font_runs_pool.lock().pop().unwrap_or_default();
|
) -> Result<SmallVec<[Line; 1]>> {
|
||||||
|
let mut font_runs: Vec<(usize, FontId)> =
|
||||||
|
self.font_runs_pool.lock().pop().unwrap_or_default();
|
||||||
|
|
||||||
let mut last_font: Option<&Font> = None;
|
let mut last_font: Option<&Font> = None;
|
||||||
for (len, style) in runs {
|
for (len, style) in runs {
|
||||||
|
@ -163,14 +166,47 @@ impl TextSystem {
|
||||||
font_runs.push((*len, self.font_id(&style.font)?));
|
font_runs.push((*len, self.font_id(&style.font)?));
|
||||||
}
|
}
|
||||||
|
|
||||||
let layout = self
|
let mut layouts = SmallVec::new();
|
||||||
.text_layout_cache
|
let mut start = 0;
|
||||||
.layout_line(text, font_size, &font_runs);
|
let mut run_start = 0;
|
||||||
|
for line in text.lines() {
|
||||||
|
let end = start + line.len();
|
||||||
|
let mut run_end = run_start;
|
||||||
|
let mut line_length = 0;
|
||||||
|
for (len, _) in font_runs[run_start..].iter() {
|
||||||
|
line_length += len;
|
||||||
|
if *len >= line_length {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
run_end += 1;
|
||||||
|
}
|
||||||
|
// If a run lands in the middle of a line, create an additional run for the remaining characters.
|
||||||
|
if line_length < end - start {
|
||||||
|
// Create a run for the part that fits this line.
|
||||||
|
let partial_run = font_runs[run_end];
|
||||||
|
partial_run.0 = line_length;
|
||||||
|
layouts.push(self.text_layout_cache.layout_line(
|
||||||
|
&text[start..start + line_length],
|
||||||
|
font_size,
|
||||||
|
&font_runs[run_start..=run_end],
|
||||||
|
));
|
||||||
|
// Update the original run to only include the part that does not fit this line.
|
||||||
|
font_runs[run_end].0 -= line_length;
|
||||||
|
} else {
|
||||||
|
layouts.push(self.text_layout_cache.layout_line(
|
||||||
|
&text[start..end],
|
||||||
|
font_size,
|
||||||
|
&font_runs[run_start..run_end],
|
||||||
|
));
|
||||||
|
run_start = run_end;
|
||||||
|
}
|
||||||
|
start = end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
font_runs.clear();
|
font_runs.clear();
|
||||||
self.font_runs_pool.lock().push(font_runs);
|
self.font_runs_pool.lock().push(font_runs);
|
||||||
|
|
||||||
Ok(Line::new(layout.clone(), runs))
|
Ok(layouts)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end_frame(&self) {
|
pub fn end_frame(&self) {
|
||||||
|
@ -346,7 +382,7 @@ impl From<u32> for GlyphId {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct ShapedLine {
|
pub struct LineLayout {
|
||||||
pub font_size: Pixels,
|
pub font_size: Pixels,
|
||||||
pub width: Pixels,
|
pub width: Pixels,
|
||||||
pub ascent: Pixels,
|
pub ascent: Pixels,
|
||||||
|
@ -358,7 +394,7 @@ pub struct ShapedLine {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ShapedRun {
|
pub struct ShapedRun {
|
||||||
pub font_id: FontId,
|
pub font_id: FontId,
|
||||||
pub glyphs: Vec<ShapedGlyph>,
|
pub glyphs: SmallVec<[ShapedGlyph; 8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
black, point, px, Bounds, FontId, Hsla, Pixels, Point, RunStyle, ShapedBoundary, ShapedLine,
|
black, point, px, Bounds, FontId, Hsla, LineLayout, Pixels, Point, RunStyle, ShapedBoundary,
|
||||||
ShapedRun, UnderlineStyle, WindowContext,
|
ShapedRun, UnderlineStyle, WindowContext,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
@ -8,7 +8,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct Line {
|
pub struct Line {
|
||||||
layout: Arc<ShapedLine>,
|
layout: Arc<LineLayout>,
|
||||||
style_runs: SmallVec<[StyleRun; 32]>,
|
style_runs: SmallVec<[StyleRun; 32]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ struct StyleRun {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Line {
|
impl Line {
|
||||||
pub fn new(layout: Arc<ShapedLine>, runs: &[(usize, RunStyle)]) -> Self {
|
pub fn new(layout: Arc<LineLayout>, runs: &[(usize, RunStyle)]) -> Self {
|
||||||
let mut style_runs = SmallVec::new();
|
let mut style_runs = SmallVec::new();
|
||||||
for (len, style) in runs {
|
for (len, style) in runs {
|
||||||
style_runs.push(StyleRun {
|
style_runs.push(StyleRun {
|
||||||
|
|
|
@ -287,7 +287,7 @@ mod tests {
|
||||||
|
|
||||||
let text = "aa bbb cccc ddddd eeee";
|
let text = "aa bbb cccc ddddd eeee";
|
||||||
let line = text_system
|
let line = text_system
|
||||||
.layout_line(
|
.layout_text(
|
||||||
text,
|
text,
|
||||||
px(16.),
|
px(16.),
|
||||||
&[
|
&[
|
||||||
|
@ -297,6 +297,7 @@ mod tests {
|
||||||
(1, bold.clone()),
|
(1, bold.clone()),
|
||||||
(7, normal.clone()),
|
(7, normal.clone()),
|
||||||
],
|
],
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{FontId, Pixels, PlatformTextSystem, ShapedGlyph, ShapedLine, ShapedRun};
|
use crate::{FontId, LineLayout, Pixels, PlatformTextSystem, ShapedGlyph, ShapedRun};
|
||||||
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
|
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -9,8 +9,8 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) struct TextLayoutCache {
|
pub(crate) struct TextLayoutCache {
|
||||||
prev_frame: Mutex<HashMap<CacheKeyValue, Arc<ShapedLine>>>,
|
prev_frame: Mutex<HashMap<CacheKeyValue, Arc<LineLayout>>>,
|
||||||
curr_frame: RwLock<HashMap<CacheKeyValue, Arc<ShapedLine>>>,
|
curr_frame: RwLock<HashMap<CacheKeyValue, Arc<LineLayout>>>,
|
||||||
platform_text_system: Arc<dyn PlatformTextSystem>,
|
platform_text_system: Arc<dyn PlatformTextSystem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ impl TextLayoutCache {
|
||||||
text: &'a str,
|
text: &'a str,
|
||||||
font_size: Pixels,
|
font_size: Pixels,
|
||||||
runs: &[(usize, FontId)],
|
runs: &[(usize, FontId)],
|
||||||
) -> Arc<ShapedLine> {
|
) -> Arc<LineLayout> {
|
||||||
let key = &CacheKeyRef {
|
let key = &CacheKeyRef {
|
||||||
text,
|
text,
|
||||||
font_size,
|
font_size,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue