New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
use std ::ops ::RangeInclusive ;
2022-04-15 13:18:04 +00:00
use std ::sync ::Arc ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
2022-01-24 13:32:36 +00:00
use super ::{ FontsImpl , Galley , Glyph , LayoutJob , LayoutSection , Row , RowVisuals } ;
2022-04-15 13:18:04 +00:00
use crate ::{ Color32 , Mesh , Stroke , Vertex } ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
use emath ::* ;
2022-01-24 13:32:36 +00:00
// ----------------------------------------------------------------------------
/// Represents GUI scale and convenience methods for rounding to pixels.
#[ derive(Clone, Copy) ]
struct PointScale {
pub pixels_per_point : f32 ,
}
impl PointScale {
#[ inline(always) ]
pub fn new ( pixels_per_point : f32 ) -> Self {
Self { pixels_per_point }
}
#[ inline(always) ]
pub fn pixels_per_point ( & self ) -> f32 {
self . pixels_per_point
}
#[ inline(always) ]
pub fn round_to_pixel ( & self , point : f32 ) -> f32 {
( point * self . pixels_per_point ) . round ( ) / self . pixels_per_point
}
#[ inline(always) ]
pub fn floor_to_pixel ( & self , point : f32 ) -> f32 {
( point * self . pixels_per_point ) . floor ( ) / self . pixels_per_point
}
}
// ----------------------------------------------------------------------------
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
/// Temporary storage before line-wrapping.
#[ derive(Default, Clone) ]
struct Paragraph {
/// Start of the next glyph to be added.
pub cursor_x : f32 ,
pub glyphs : Vec < Glyph > ,
/// In case of an empty paragraph ("\n"), use this as height.
pub empty_paragraph_height : f32 ,
}
/// Layout text into a [`Galley`].
///
2022-01-24 13:32:36 +00:00
/// In most cases you should use [`crate::Fonts::layout_job`] instead
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
/// since that memoizes the input, making subsequent layouting of the same text much faster.
2022-01-24 13:32:36 +00:00
pub fn layout ( fonts : & mut FontsImpl , job : Arc < LayoutJob > ) -> Galley {
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let mut paragraphs = vec! [ Paragraph ::default ( ) ] ;
for ( section_index , section ) in job . sections . iter ( ) . enumerate ( ) {
layout_section ( fonts , & job , section_index as u32 , section , & mut paragraphs ) ;
}
2022-01-24 13:32:36 +00:00
let point_scale = PointScale ::new ( fonts . pixels_per_point ( ) ) ;
2022-04-03 18:28:47 +00:00
let mut rows = rows_from_paragraphs ( fonts , paragraphs , & job ) ;
2021-09-07 18:37:50 +00:00
2022-04-03 18:28:47 +00:00
let justify = job . justify & & job . wrap . max_width . is_finite ( ) ;
2021-09-07 18:37:50 +00:00
if justify | | job . halign ! = Align ::LEFT {
let num_rows = rows . len ( ) ;
for ( i , row ) in rows . iter_mut ( ) . enumerate ( ) {
let is_last_row = i + 1 = = num_rows ;
let justify_row = justify & & ! row . ends_with_newline & & ! is_last_row ;
2022-04-03 18:28:47 +00:00
halign_and_jusitfy_row (
point_scale ,
row ,
job . halign ,
job . wrap . max_width ,
justify_row ,
) ;
2021-09-07 18:37:50 +00:00
}
}
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
2022-01-24 13:32:36 +00:00
galley_from_rows ( point_scale , job , rows )
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
}
fn layout_section (
2022-01-24 13:32:36 +00:00
fonts : & mut FontsImpl ,
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
job : & LayoutJob ,
section_index : u32 ,
section : & LayoutSection ,
out_paragraphs : & mut Vec < Paragraph > ,
) {
let LayoutSection {
leading_space ,
byte_range ,
format ,
} = section ;
2022-01-24 13:32:36 +00:00
let font = fonts . font ( & format . font_id ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let font_height = font . row_height ( ) ;
let mut paragraph = out_paragraphs . last_mut ( ) . unwrap ( ) ;
if paragraph . glyphs . is_empty ( ) {
paragraph . empty_paragraph_height = font_height ; // TODO: replace this hack with actually including `\n` in the glyphs?
}
paragraph . cursor_x + = leading_space ;
let mut last_glyph_id = None ;
for chr in job . text [ byte_range . clone ( ) ] . chars ( ) {
if job . break_on_newline & & chr = = '\n' {
out_paragraphs . push ( Paragraph ::default ( ) ) ;
paragraph = out_paragraphs . last_mut ( ) . unwrap ( ) ;
paragraph . empty_paragraph_height = font_height ; // TODO: replace this hack with actually including `\n` in the glyphs?
} else {
let ( font_impl , glyph_info ) = font . glyph_info_and_font_impl ( chr ) ;
2021-10-20 13:40:06 +00:00
if let Some ( font_impl ) = font_impl {
if let Some ( last_glyph_id ) = last_glyph_id {
2021-10-20 14:43:40 +00:00
paragraph . cursor_x + = font_impl . pair_kerning ( last_glyph_id , glyph_info . id ) ;
2021-10-20 13:40:06 +00:00
}
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
}
paragraph . glyphs . push ( Glyph {
chr ,
pos : pos2 ( paragraph . cursor_x , f32 ::NAN ) ,
size : vec2 ( glyph_info . advance_width , font_height ) ,
uv_rect : glyph_info . uv_rect ,
section_index ,
} ) ;
paragraph . cursor_x + = glyph_info . advance_width ;
paragraph . cursor_x = font . round_to_pixel ( paragraph . cursor_x ) ;
last_glyph_id = Some ( glyph_info . id ) ;
}
}
}
/// We ignore y at this stage
fn rect_from_x_range ( x_range : RangeInclusive < f32 > ) -> Rect {
Rect ::from_x_y_ranges ( x_range , 0. 0 ..= 0.0 )
}
2022-04-03 18:28:47 +00:00
fn rows_from_paragraphs (
fonts : & mut FontsImpl ,
paragraphs : Vec < Paragraph > ,
job : & LayoutJob ,
) -> Vec < Row > {
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let num_paragraphs = paragraphs . len ( ) ;
let mut rows = vec! [ ] ;
for ( i , paragraph ) in paragraphs . into_iter ( ) . enumerate ( ) {
let is_last_paragraph = ( i + 1 ) = = num_paragraphs ;
if paragraph . glyphs . is_empty ( ) {
rows . push ( Row {
glyphs : vec ! [ ] ,
visuals : Default ::default ( ) ,
rect : Rect ::from_min_size (
pos2 ( paragraph . cursor_x , 0.0 ) ,
vec2 ( 0.0 , paragraph . empty_paragraph_height ) ,
) ,
ends_with_newline : ! is_last_paragraph ,
} ) ;
} else {
let paragraph_max_x = paragraph . glyphs . last ( ) . unwrap ( ) . max_x ( ) ;
2022-04-03 18:28:47 +00:00
if paragraph_max_x < = job . wrap . max_width {
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
// early-out optimization
let paragraph_min_x = paragraph . glyphs [ 0 ] . pos . x ;
rows . push ( Row {
glyphs : paragraph . glyphs ,
visuals : Default ::default ( ) ,
rect : rect_from_x_range ( paragraph_min_x ..= paragraph_max_x ) ,
ends_with_newline : ! is_last_paragraph ,
} ) ;
} else {
2022-04-03 18:28:47 +00:00
line_break ( fonts , & paragraph , job , & mut rows ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
rows . last_mut ( ) . unwrap ( ) . ends_with_newline = ! is_last_paragraph ;
}
}
}
rows
}
2022-04-03 18:28:47 +00:00
fn line_break (
fonts : & mut FontsImpl ,
paragraph : & Paragraph ,
job : & LayoutJob ,
out_rows : & mut Vec < Row > ,
) {
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
// Keeps track of good places to insert row break if we exceed `wrap_width`.
let mut row_break_candidates = RowBreakCandidates ::default ( ) ;
let mut first_row_indentation = paragraph . glyphs [ 0 ] . pos . x ;
let mut row_start_x = 0.0 ;
let mut row_start_idx = 0 ;
2022-04-03 18:28:47 +00:00
let mut non_empty_rows = 0 ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
for ( i , glyph ) in paragraph . glyphs . iter ( ) . enumerate ( ) {
2021-09-07 18:37:50 +00:00
let potential_row_width = glyph . max_x ( ) - row_start_x ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
2022-04-03 18:28:47 +00:00
if job . wrap . max_rows > 0 & & non_empty_rows > = job . wrap . max_rows {
break ;
}
if potential_row_width > job . wrap . max_width {
if first_row_indentation > 0.0
& & ! row_break_candidates . has_good_candidate ( job . wrap . break_anywhere )
{
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
// Allow the first row to be completely empty, because we know there will be more space on the next row:
// TODO: this records the height of this first row as zero, though that is probably fine since first_row_indentation usually comes with a first_row_min_height.
out_rows . push ( Row {
glyphs : vec ! [ ] ,
visuals : Default ::default ( ) ,
rect : rect_from_x_range ( first_row_indentation ..= first_row_indentation ) ,
ends_with_newline : false ,
} ) ;
row_start_x + = first_row_indentation ;
first_row_indentation = 0.0 ;
2022-04-03 18:28:47 +00:00
} else if let Some ( last_kept_index ) = row_break_candidates . get ( job . wrap . break_anywhere )
{
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let glyphs : Vec < Glyph > = paragraph . glyphs [ row_start_idx ..= last_kept_index ]
. iter ( )
. copied ( )
. map ( | mut glyph | {
glyph . pos . x - = row_start_x ;
glyph
} )
. collect ( ) ;
let paragraph_min_x = glyphs [ 0 ] . pos . x ;
let paragraph_max_x = glyphs . last ( ) . unwrap ( ) . max_x ( ) ;
out_rows . push ( Row {
glyphs ,
visuals : Default ::default ( ) ,
rect : rect_from_x_range ( paragraph_min_x ..= paragraph_max_x ) ,
ends_with_newline : false ,
} ) ;
row_start_idx = last_kept_index + 1 ;
row_start_x = paragraph . glyphs [ row_start_idx ] . pos . x ;
row_break_candidates = Default ::default ( ) ;
2022-04-03 18:28:47 +00:00
non_empty_rows + = 1 ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
} else {
// Found no place to break, so we have to overrun wrap_width.
}
}
row_break_candidates . add ( i , glyph . chr ) ;
}
if row_start_idx < paragraph . glyphs . len ( ) {
2022-04-09 20:43:40 +00:00
if job . wrap . max_rows > 0 & & non_empty_rows = = job . wrap . max_rows {
2022-04-07 15:03:19 +00:00
if let Some ( last_row ) = out_rows . last_mut ( ) {
replace_last_glyph_with_overflow_character ( fonts , job , last_row ) ;
}
2022-04-03 18:28:47 +00:00
} else {
let glyphs : Vec < Glyph > = paragraph . glyphs [ row_start_idx .. ]
. iter ( )
. copied ( )
. map ( | mut glyph | {
glyph . pos . x - = row_start_x ;
glyph
} )
. collect ( ) ;
let paragraph_min_x = glyphs [ 0 ] . pos . x ;
let paragraph_max_x = glyphs . last ( ) . unwrap ( ) . max_x ( ) ;
out_rows . push ( Row {
glyphs ,
visuals : Default ::default ( ) ,
rect : rect_from_x_range ( paragraph_min_x ..= paragraph_max_x ) ,
ends_with_newline : false ,
} ) ;
}
}
}
fn replace_last_glyph_with_overflow_character (
fonts : & mut FontsImpl ,
job : & LayoutJob ,
2022-04-07 15:03:19 +00:00
row : & mut Row ,
2022-04-03 18:28:47 +00:00
) {
let overflow_character = match job . wrap . overflow_character {
Some ( c ) = > c ,
None = > return ,
} ;
loop {
let ( prev_glyph , last_glyph ) = match row . glyphs . as_mut_slice ( ) {
[ .. , prev , last ] = > ( Some ( prev ) , last ) ,
[ .. , last ] = > ( None , last ) ,
_ = > break ,
} ;
let section = & job . sections [ last_glyph . section_index as usize ] ;
let font = fonts . font ( & section . format . font_id ) ;
let font_height = font . row_height ( ) ;
let prev_glyph_id = prev_glyph . map ( | prev_glyph | {
let ( _ , prev_glyph_info ) = font . glyph_info_and_font_impl ( prev_glyph . chr ) ;
prev_glyph_info . id
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
} ) ;
2022-04-03 18:28:47 +00:00
// undo kerning with previous glyph
let ( font_impl , glyph_info ) = font . glyph_info_and_font_impl ( last_glyph . chr ) ;
last_glyph . pos . x - = font_impl
. zip ( prev_glyph_id )
. map ( | ( font_impl , prev_glyph_id ) | font_impl . pair_kerning ( prev_glyph_id , glyph_info . id ) )
. unwrap_or_default ( ) ;
// replace the glyph
last_glyph . chr = overflow_character ;
let ( font_impl , glyph_info ) = font . glyph_info_and_font_impl ( last_glyph . chr ) ;
last_glyph . size = vec2 ( glyph_info . advance_width , font_height ) ;
last_glyph . uv_rect = glyph_info . uv_rect ;
// reapply kerning
last_glyph . pos . x + = font_impl
. zip ( prev_glyph_id )
. map ( | ( font_impl , prev_glyph_id ) | font_impl . pair_kerning ( prev_glyph_id , glyph_info . id ) )
. unwrap_or_default ( ) ;
// check if we're still within width budget
let row_end_x = last_glyph . max_x ( ) ;
let row_start_x = row . glyphs . first ( ) . unwrap ( ) . pos . x ; // if `last_mut()` returned `Some`, then so will `first()`
let row_width = row_end_x - row_start_x ;
if row_width < = job . wrap . max_width {
break ;
}
row . glyphs . pop ( ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
}
}
2021-09-07 18:37:50 +00:00
fn halign_and_jusitfy_row (
2022-01-24 13:32:36 +00:00
point_scale : PointScale ,
2021-09-07 18:37:50 +00:00
row : & mut Row ,
halign : Align ,
wrap_width : f32 ,
justify : bool ,
) {
if row . glyphs . is_empty ( ) {
return ;
}
let num_leading_spaces = row
. glyphs
. iter ( )
. take_while ( | glyph | glyph . chr . is_whitespace ( ) )
. count ( ) ;
let glyph_range = if num_leading_spaces = = row . glyphs . len ( ) {
// There is only whitespace
( 0 , row . glyphs . len ( ) )
} else {
let num_trailing_spaces = row
. glyphs
. iter ( )
. rev ( )
. take_while ( | glyph | glyph . chr . is_whitespace ( ) )
. count ( ) ;
( num_leading_spaces , row . glyphs . len ( ) - num_trailing_spaces )
} ;
let num_glyphs_in_range = glyph_range . 1 - glyph_range . 0 ;
assert! ( num_glyphs_in_range > 0 ) ;
let original_min_x = row . glyphs [ glyph_range . 0 ] . logical_rect ( ) . min . x ;
let original_max_x = row . glyphs [ glyph_range . 1 - 1 ] . logical_rect ( ) . max . x ;
let original_width = original_max_x - original_min_x ;
let target_width = if justify & & num_glyphs_in_range > 1 {
wrap_width
} else {
original_width
} ;
let ( target_min_x , target_max_x ) = match halign {
Align ::LEFT = > ( 0.0 , target_width ) ,
Align ::Center = > ( - target_width / 2.0 , target_width / 2.0 ) ,
Align ::RIGHT = > ( - target_width , 0.0 ) ,
} ;
let num_spaces_in_range = row . glyphs [ glyph_range . 0 .. glyph_range . 1 ]
. iter ( )
. filter ( | glyph | glyph . chr . is_whitespace ( ) )
. count ( ) ;
let mut extra_x_per_glyph = if num_glyphs_in_range = = 1 {
0.0
} else {
( target_width - original_width ) / ( num_glyphs_in_range as f32 - 1.0 )
} ;
extra_x_per_glyph = extra_x_per_glyph . at_least ( 0.0 ) ; // Don't contract
let mut extra_x_per_space = 0.0 ;
if 0 < num_spaces_in_range & & num_spaces_in_range < num_glyphs_in_range {
// Add an integral number of pixels between each glyph,
// and add the balance to the spaces:
2022-01-24 13:32:36 +00:00
extra_x_per_glyph = point_scale . floor_to_pixel ( extra_x_per_glyph ) ;
2021-09-07 18:37:50 +00:00
extra_x_per_space = ( target_width
- original_width
- extra_x_per_glyph * ( num_glyphs_in_range as f32 - 1.0 ) )
/ ( num_spaces_in_range as f32 ) ;
}
let mut translate_x = target_min_x - original_min_x - extra_x_per_glyph * glyph_range . 0 as f32 ;
for glyph in & mut row . glyphs {
glyph . pos . x + = translate_x ;
2022-01-24 13:32:36 +00:00
glyph . pos . x = point_scale . round_to_pixel ( glyph . pos . x ) ;
2021-09-07 18:37:50 +00:00
translate_x + = extra_x_per_glyph ;
if glyph . chr . is_whitespace ( ) {
translate_x + = extra_x_per_space ;
}
}
// Note we ignore the leading/trailing whitespace here!
row . rect . min . x = target_min_x ;
row . rect . max . x = target_max_x ;
}
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
/// Calculate the Y positions and tessellate the text.
2022-01-24 13:32:36 +00:00
fn galley_from_rows ( point_scale : PointScale , job : Arc < LayoutJob > , mut rows : Vec < Row > ) -> Galley {
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let mut first_row_min_height = job . first_row_min_height ;
let mut cursor_y = 0.0 ;
2021-09-07 18:37:50 +00:00
let mut min_x : f32 = 0.0 ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let mut max_x : f32 = 0.0 ;
for row in & mut rows {
let mut row_height = first_row_min_height . max ( row . rect . height ( ) ) ;
first_row_min_height = 0.0 ;
for glyph in & row . glyphs {
row_height = row_height . max ( glyph . size . y ) ;
}
2022-01-24 13:32:36 +00:00
row_height = point_scale . round_to_pixel ( row_height ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
// Now positions each glyph:
for glyph in & mut row . glyphs {
let format = & job . sections [ glyph . section_index as usize ] . format ;
glyph . pos . y = cursor_y + format . valign . to_factor ( ) * ( row_height - glyph . size . y ) ;
2022-01-24 13:32:36 +00:00
glyph . pos . y = point_scale . round_to_pixel ( glyph . pos . y ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
}
row . rect . min . y = cursor_y ;
row . rect . max . y = cursor_y + row_height ;
2021-09-07 18:37:50 +00:00
min_x = min_x . min ( row . rect . min . x ) ;
max_x = max_x . max ( row . rect . max . x ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
cursor_y + = row_height ;
2022-01-24 13:32:36 +00:00
cursor_y = point_scale . round_to_pixel ( cursor_y ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
}
let format_summary = format_summary ( & job ) ;
2021-09-20 19:36:56 +00:00
let mut mesh_bounds = Rect ::NOTHING ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let mut num_vertices = 0 ;
let mut num_indices = 0 ;
for row in & mut rows {
2022-01-24 13:32:36 +00:00
row . visuals = tessellate_row ( point_scale , & job , & format_summary , row ) ;
2021-09-20 19:36:56 +00:00
mesh_bounds = mesh_bounds . union ( row . visuals . mesh_bounds ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
num_vertices + = row . visuals . mesh . vertices . len ( ) ;
num_indices + = row . visuals . mesh . indices . len ( ) ;
}
2021-09-07 18:37:50 +00:00
let rect = Rect ::from_min_max ( pos2 ( min_x , 0.0 ) , pos2 ( max_x , cursor_y ) ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
Galley {
job ,
rows ,
2021-09-07 18:37:50 +00:00
rect ,
2021-09-20 19:36:56 +00:00
mesh_bounds ,
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
num_vertices ,
num_indices ,
}
}
#[ derive(Default) ]
struct FormatSummary {
any_background : bool ,
any_underline : bool ,
any_strikethrough : bool ,
}
fn format_summary ( job : & LayoutJob ) -> FormatSummary {
let mut format_summary = FormatSummary ::default ( ) ;
for section in & job . sections {
format_summary . any_background | = section . format . background ! = Color32 ::TRANSPARENT ;
format_summary . any_underline | = section . format . underline ! = Stroke ::none ( ) ;
format_summary . any_strikethrough | = section . format . strikethrough ! = Stroke ::none ( ) ;
}
format_summary
}
fn tessellate_row (
2022-01-24 13:32:36 +00:00
point_scale : PointScale ,
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
job : & LayoutJob ,
format_summary : & FormatSummary ,
row : & mut Row ,
) -> RowVisuals {
if row . glyphs . is_empty ( ) {
return Default ::default ( ) ;
}
let mut mesh = Mesh ::default ( ) ;
mesh . reserve_triangles ( row . glyphs . len ( ) * 2 ) ;
mesh . reserve_vertices ( row . glyphs . len ( ) * 4 ) ;
if format_summary . any_background {
add_row_backgrounds ( job , row , & mut mesh ) ;
}
let glyph_vertex_start = mesh . vertices . len ( ) ;
2022-01-24 13:32:36 +00:00
tessellate_glyphs ( point_scale , job , row , & mut mesh ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let glyph_vertex_end = mesh . vertices . len ( ) ;
if format_summary . any_underline {
2022-01-24 13:32:36 +00:00
add_row_hline ( point_scale , row , & mut mesh , | glyph | {
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let format = & job . sections [ glyph . section_index as usize ] . format ;
let stroke = format . underline ;
let y = glyph . logical_rect ( ) . bottom ( ) ;
( stroke , y )
} ) ;
}
if format_summary . any_strikethrough {
2022-01-24 13:32:36 +00:00
add_row_hline ( point_scale , row , & mut mesh , | glyph | {
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let format = & job . sections [ glyph . section_index as usize ] . format ;
let stroke = format . strikethrough ;
let y = glyph . logical_rect ( ) . center ( ) . y ;
( stroke , y )
} ) ;
}
let mesh_bounds = mesh . calc_bounds ( ) ;
RowVisuals {
mesh ,
mesh_bounds ,
glyph_vertex_range : glyph_vertex_start .. glyph_vertex_end ,
}
}
/// Create background for glyphs that have them.
/// Creates as few rectangular regions as possible.
fn add_row_backgrounds ( job : & LayoutJob , row : & Row , mesh : & mut Mesh ) {
if row . glyphs . is_empty ( ) {
return ;
}
let mut end_run = | start : Option < ( Color32 , Rect ) > , stop_x : f32 | {
if let Some ( ( color , start_rect ) ) = start {
let rect = Rect ::from_min_max ( start_rect . left_top ( ) , pos2 ( stop_x , start_rect . bottom ( ) ) ) ;
let rect = rect . expand ( 1.0 ) ; // looks better
mesh . add_colored_rect ( rect , color ) ;
}
} ;
let mut run_start = None ;
let mut last_rect = Rect ::NAN ;
for glyph in & row . glyphs {
let format = & job . sections [ glyph . section_index as usize ] . format ;
let color = format . background ;
let rect = glyph . logical_rect ( ) ;
if color = = Color32 ::TRANSPARENT {
end_run ( run_start . take ( ) , last_rect . right ( ) ) ;
} else if let Some ( ( existing_color , start ) ) = run_start {
if existing_color = = color
& & start . top ( ) = = rect . top ( )
& & start . bottom ( ) = = rect . bottom ( )
{
// continue the same background rectangle
} else {
end_run ( run_start . take ( ) , last_rect . right ( ) ) ;
run_start = Some ( ( color , rect ) ) ;
}
} else {
run_start = Some ( ( color , rect ) ) ;
}
last_rect = rect ;
}
end_run ( run_start . take ( ) , last_rect . right ( ) ) ;
}
2022-01-24 13:32:36 +00:00
fn tessellate_glyphs ( point_scale : PointScale , job : & LayoutJob , row : & Row , mesh : & mut Mesh ) {
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
for glyph in & row . glyphs {
let uv_rect = glyph . uv_rect ;
if ! uv_rect . is_nothing ( ) {
let mut left_top = glyph . pos + uv_rect . offset ;
2022-01-24 13:32:36 +00:00
left_top . x = point_scale . round_to_pixel ( left_top . x ) ;
left_top . y = point_scale . round_to_pixel ( left_top . y ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let rect = Rect ::from_min_max ( left_top , left_top + uv_rect . size ) ;
let uv = Rect ::from_min_max (
pos2 ( uv_rect . min [ 0 ] as f32 , uv_rect . min [ 1 ] as f32 ) ,
pos2 ( uv_rect . max [ 0 ] as f32 , uv_rect . max [ 1 ] as f32 ) ,
) ;
let format = & job . sections [ glyph . section_index as usize ] . format ;
let color = format . color ;
if format . italics {
let idx = mesh . vertices . len ( ) as u32 ;
mesh . add_triangle ( idx , idx + 1 , idx + 2 ) ;
mesh . add_triangle ( idx + 2 , idx + 1 , idx + 3 ) ;
let top_offset = rect . height ( ) * 0.25 * Vec2 ::X ;
mesh . vertices . push ( Vertex {
pos : rect . left_top ( ) + top_offset ,
uv : uv . left_top ( ) ,
color ,
} ) ;
mesh . vertices . push ( Vertex {
pos : rect . right_top ( ) + top_offset ,
uv : uv . right_top ( ) ,
color ,
} ) ;
mesh . vertices . push ( Vertex {
pos : rect . left_bottom ( ) ,
uv : uv . left_bottom ( ) ,
color ,
} ) ;
mesh . vertices . push ( Vertex {
pos : rect . right_bottom ( ) ,
uv : uv . right_bottom ( ) ,
color ,
} ) ;
} else {
mesh . add_rect_with_uv ( rect , uv , color ) ;
}
}
}
}
/// Add a horizontal line over a row of glyphs with a stroke and y decided by a callback.
fn add_row_hline (
2022-01-24 13:32:36 +00:00
point_scale : PointScale ,
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
row : & Row ,
mesh : & mut Mesh ,
stroke_and_y : impl Fn ( & Glyph ) -> ( Stroke , f32 ) ,
) {
let mut end_line = | start : Option < ( Stroke , Pos2 ) > , stop_x : f32 | {
if let Some ( ( stroke , start ) ) = start {
2022-01-24 13:32:36 +00:00
add_hline ( point_scale , [ start , pos2 ( stop_x , start . y ) ] , stroke , mesh ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
}
} ;
let mut line_start = None ;
let mut last_right_x = f32 ::NAN ;
for glyph in & row . glyphs {
let ( stroke , y ) = stroke_and_y ( glyph ) ;
if stroke = = Stroke ::none ( ) {
end_line ( line_start . take ( ) , last_right_x ) ;
} else if let Some ( ( existing_stroke , start ) ) = line_start {
if existing_stroke = = stroke & & start . y = = y {
// continue the same line
} else {
end_line ( line_start . take ( ) , last_right_x ) ;
line_start = Some ( ( stroke , pos2 ( glyph . pos . x , y ) ) ) ;
}
} else {
line_start = Some ( ( stroke , pos2 ( glyph . pos . x , y ) ) ) ;
}
last_right_x = glyph . max_x ( ) ;
}
end_line ( line_start . take ( ) , last_right_x ) ;
}
2022-01-24 13:32:36 +00:00
fn add_hline ( point_scale : PointScale , [ start , stop ] : [ Pos2 ; 2 ] , stroke : Stroke , mesh : & mut Mesh ) {
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let antialiased = true ;
if antialiased {
let mut path = crate ::tessellator ::Path ::default ( ) ; // TODO: reuse this to avoid re-allocations.
path . add_line_segment ( [ start , stop ] ) ;
2022-03-23 10:41:38 +00:00
let feathering = 1.0 / point_scale . pixels_per_point ( ) ;
path . stroke_open ( feathering , stroke , mesh ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
} else {
// Thin lines often lost, so this is a bad idea
assert_eq! ( start . y , stop . y ) ;
2022-01-24 13:32:36 +00:00
let min_y = point_scale . round_to_pixel ( start . y - 0.5 * stroke . width ) ;
let max_y = point_scale . round_to_pixel ( min_y + stroke . width ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let rect = Rect ::from_min_max (
2022-01-24 13:32:36 +00:00
pos2 ( point_scale . round_to_pixel ( start . x ) , min_y ) ,
pos2 ( point_scale . round_to_pixel ( stop . x ) , max_y ) ,
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
) ;
mesh . add_colored_rect ( rect , stroke . color ) ;
}
}
// ----------------------------------------------------------------------------
/// Keeps track of good places to break a long row of text.
/// Will focus primarily on spaces, secondarily on things like `-`
#[ derive(Clone, Copy, Default) ]
struct RowBreakCandidates {
/// Breaking at ` ` or other whitespace
/// is always the primary candidate.
space : Option < usize > ,
/// Logograms (single character representing a whole word) are good candidates for line break.
logogram : Option < usize > ,
/// Breaking at a dash is a super-
/// good idea.
dash : Option < usize > ,
/// This is nicer for things like URLs, e.g. www.
/// example.com.
punctuation : Option < usize > ,
/// Breaking after just random character is some
/// times necessary.
any : Option < usize > ,
}
impl RowBreakCandidates {
fn add ( & mut self , index : usize , chr : char ) {
const NON_BREAKING_SPACE : char = '\u{A0}' ;
if chr . is_whitespace ( ) & & chr ! = NON_BREAKING_SPACE {
self . space = Some ( index ) ;
} else if is_chinese ( chr ) {
self . logogram = Some ( index ) ;
} else if chr = = '-' {
self . dash = Some ( index ) ;
} else if chr . is_ascii_punctuation ( ) {
self . punctuation = Some ( index ) ;
}
2022-04-03 18:28:47 +00:00
self . any = Some ( index ) ;
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
}
fn has_word_boundary ( & self ) -> bool {
self . space . is_some ( ) | | self . logogram . is_some ( )
}
2022-04-03 18:28:47 +00:00
fn has_good_candidate ( & self , break_anywhere : bool ) -> bool {
if break_anywhere {
self . any . is_some ( )
} else {
self . has_word_boundary ( )
}
}
fn get ( & self , break_anywhere : bool ) -> Option < usize > {
if break_anywhere {
self . any
} else {
self . space
. or ( self . logogram )
. or ( self . dash )
. or ( self . punctuation )
. or ( self . any )
}
New text layout (#682)
This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`.
This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor.
One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley.
## Performance
Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!).
Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that.
All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
}
}
#[ inline ]
fn is_chinese ( c : char ) -> bool {
( '\u{4E00}' < = c & & c < = '\u{9FFF}' )
| | ( '\u{3400}' < = c & & c < = '\u{4DBF}' )
| | ( '\u{2B740}' < = c & & c < = '\u{2B81F}' )
}
2022-04-09 20:43:40 +00:00
// ----------------------------------------------------------------------------
#[ test ]
fn test_zero_max_width ( ) {
let mut fonts = FontsImpl ::new ( 1.0 , 1024 , super ::FontDefinitions ::default ( ) ) ;
let mut layout_job = LayoutJob ::single_section ( " W " . into ( ) , super ::TextFormat ::default ( ) ) ;
layout_job . wrap . max_width = 0.0 ;
let galley = super ::layout ( & mut fonts , layout_job . into ( ) ) ;
assert_eq! ( galley . rows . len ( ) , 1 ) ;
}