Use image renderer for iced text widget

This commit is contained in:
Jeremy Soller 2022-10-31 12:04:33 -06:00
parent b0ec548a5e
commit d49e8881fd
No known key found for this signature in database
GPG key ID: 87F211AF2BE4C2FE
4 changed files with 74 additions and 58 deletions

View file

@ -38,12 +38,12 @@ use std::{
sync::Mutex,
};
use self::text::text;
mod text;
use self::text_box::text_box;
mod text_box;
use self::text_new::text as text_new;
mod text_new;
lazy_static::lazy_static! {
static ref FONT_SYSTEM: FontSystem<'static> = FontSystem::new();
}
@ -248,15 +248,15 @@ impl Application for Window {
button!("Open").on_press(Message::Open),
button!("Save").on_press(Message::Save),
horizontal_space(Length::Fill),
text_new("Bold:"),
text("Bold:"),
toggler(None, self.attrs.weight == cosmic_text::Weight::BOLD, Message::Bold),
text_new("Italic:"),
text("Italic:"),
toggler(None, self.attrs.style == cosmic_text::Style::Italic, Message::Italic),
text_new("Monospaced:"),
text("Monospaced:"),
toggler(None, self.attrs.monospaced, Message::Monospaced),
text_new("Theme:"),
text("Theme:"),
theme_picker,
text_new("Font Size:"),
text("Font Size:"),
font_size_picker,
]
.align_items(Alignment::Center)

View file

@ -2,6 +2,7 @@
use cosmic::iced_native::{
{Color, Element, Length, Point, Rectangle, Size, Theme},
image,
layout::{self, Layout},
renderer,
widget::{self, tree, Widget},
@ -78,7 +79,7 @@ pub fn text(string: &str) -> Text {
impl<Message, Renderer> Widget<Message, Renderer> for Text
where
Renderer: renderer::Renderer,
Renderer: renderer::Renderer + image::Renderer<Handle = image::Handle>,
Renderer::Theme: StyleSheet,
{
fn tag(&self) -> tree::Tag {
@ -107,12 +108,9 @@ where
let shape = self.line.shape_opt().as_ref().unwrap();
//TODO: can we cache this?
let mut layout_lines = Vec::new();
shape.layout(
let layout_lines = shape.layout(
self.metrics.font_size,
limits.max().width as i32,
&mut layout_lines,
0,
self.line.wrap_simple()
);
@ -168,20 +166,22 @@ where
cmp::max(0, cmp::min(255, (appearance.text_color.a * 255.0) as i32)) as u8,
);
let layout_w = layout.bounds().width as i32;
let layout_h = layout.bounds().height as i32;
let shape = self.line.shape_opt().as_ref().unwrap();
//TODO: can we cache this?
let mut layout_lines = Vec::new();
shape.layout(
let layout_lines = shape.layout(
self.metrics.font_size,
layout.bounds().width as i32,
&mut layout_lines,
0,
layout_w,
self.line.wrap_simple()
);
let mut cache = state.cache.lock().unwrap();
let mut pixels = vec![0; layout_w as usize * layout_h as usize * 4];
let mut line_y = self.metrics.font_size;
for layout_line in layout_lines {
for glyph in layout_line.glyphs.iter() {
@ -192,40 +192,64 @@ where
None => text_color,
};
cache.with_pixels(cache_key, glyph_color, |x, y, color| {
let a = color.a();
if a > 0 {
let r = color.r();
let g = color.g();
let b = color.b();
renderer.fill_quad(
renderer::Quad {
bounds: Rectangle::new(
Point::new(
layout.bounds().x + (x_int + x) as f32,
layout.bounds().y + (line_y + y_int + y) as f32
),
Size::new(1.0, 1.0)
),
border_radius: 0.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
Color::from_rgba8(r, g, b, a as f32 / 255.0),
);
cache.with_pixels(cache_key, glyph_color, |pixel_x, pixel_y, color| {
let alpha = (color.0 >> 24) & 0xFF;
if alpha == 0 {
// Do not draw if alpha is zero
return;
}
let y = line_y + y_int + pixel_y;
if y < 0 || y >= layout_h {
// Skip if y out of bounds
return;
}
let x = x_int + pixel_x;
if x < 0 || x >= layout_w {
// Skip if x out of bounds
return;
}
let offset = (y as usize * layout_w as usize + x as usize) * 4;
let mut current =
pixels[offset] as u32 |
(pixels[offset + 1] as u32) << 8 |
(pixels[offset + 2] as u32) << 16 |
(pixels[offset + 3] as u32) << 24;
if alpha >= 255 || current == 0 {
// Alpha is 100% or current is null, replace with no blending
current = color.0;
} else {
// Alpha blend with current value
let n_alpha = 255 - alpha;
let rb = ((n_alpha * (current & 0x00FF00FF)) + (alpha * (color.0 & 0x00FF00FF))) >> 8;
let ag = (n_alpha * ((current & 0xFF00FF00) >> 8))
+ (alpha * (0x01000000 | ((color.0 & 0x0000FF00) >> 8)));
current = (rb & 0x00FF00FF) | (ag & 0xFF00FF00);
}
pixels[offset] = current as u8;
pixels[offset + 1] = (current >> 8) as u8;
pixels[offset + 2] = (current >> 16) as u8;
pixels[offset + 3] = (current >> 24) as u8;
});
}
line_y += self.metrics.line_height;
}
let handle = image::Handle::from_pixels(layout_w as u32, layout_h as u32, pixels);
image::Renderer::draw(renderer, handle, layout.bounds());
log::trace!("draw {:?} in {:?}", layout.bounds(), instant.elapsed());
}
}
impl<'a, Message, Renderer> From<Text> for Element<'a, Message, Renderer>
where
Renderer: renderer::Renderer,
Renderer: renderer::Renderer + image::Renderer<Handle = image::Handle>,
Renderer::Theme: StyleSheet,
{
fn from(text: Text) -> Self {

View file

@ -148,14 +148,11 @@ impl<'a> BufferLine<'a> {
/// Layout line, will cache results
pub fn layout(&mut self, font_system: &'a FontSystem<'a>, font_size: i32, width: i32) -> &[LayoutLine] {
if self.layout_opt.is_none() {
let mut layout = Vec::new();
let wrap_simple = self.wrap_simple;
let shape = self.shape(font_system);
shape.layout(
let layout = shape.layout(
font_size,
width,
&mut layout,
0,
wrap_simple
);
self.layout_opt = Some(layout);

View file

@ -480,10 +480,10 @@ impl ShapeLine {
&self,
font_size: i32,
line_width: i32,
layout_lines: &mut Vec<LayoutLine>,
mut layout_i: usize,
wrap_simple: bool,
) {
) -> Vec<LayoutLine> {
let mut layout_lines = Vec::with_capacity(1);
let mut push_line = true;
let mut glyphs = Vec::new();
@ -593,13 +593,11 @@ impl ShapeLine {
if word_wrap && !wrap_simple && !glyphs.is_empty() {
let mut glyphs_swap = Vec::new();
std::mem::swap(&mut glyphs, &mut glyphs_swap);
layout_lines.insert(
layout_i,
layout_lines.push(
LayoutLine {
glyphs: glyphs_swap,
},
);
layout_i += 1;
x = start_x;
y = 0.0;
@ -619,13 +617,11 @@ impl ShapeLine {
if glyph_wrap {
let mut glyphs_swap = Vec::new();
std::mem::swap(&mut glyphs, &mut glyphs_swap);
layout_lines.insert(
layout_i,
layout_lines.push(
LayoutLine {
glyphs: glyphs_swap,
},
);
layout_i += 1;
x = start_x;
y = 0.0;
@ -648,13 +644,11 @@ impl ShapeLine {
if wrap {
let mut glyphs_swap = Vec::new();
std::mem::swap(&mut glyphs, &mut glyphs_swap);
layout_lines.insert(
layout_i,
layout_lines.push(
LayoutLine {
glyphs: glyphs_swap,
},
);
layout_i += 1;
x = start_x;
y = 0.0;
@ -663,12 +657,13 @@ impl ShapeLine {
}
if push_line {
layout_lines.insert(
layout_i,
layout_lines.push(
LayoutLine {
glyphs,
},
);
}
layout_lines
}
}