diff --git a/examples/editor-libcosmic/src/main.rs b/examples/editor-libcosmic/src/main.rs index 073ffbe..525f2dc 100644 --- a/examples/editor-libcosmic/src/main.rs +++ b/examples/editor-libcosmic/src/main.rs @@ -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) diff --git a/examples/editor-libcosmic/src/text_new.rs b/examples/editor-libcosmic/src/text.rs similarity index 67% rename from examples/editor-libcosmic/src/text_new.rs rename to examples/editor-libcosmic/src/text.rs index 55ec352..2767e62 100644 --- a/examples/editor-libcosmic/src/text_new.rs +++ b/examples/editor-libcosmic/src/text.rs @@ -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 Widget for Text where - Renderer: renderer::Renderer, + Renderer: renderer::Renderer + image::Renderer, 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 for Element<'a, Message, Renderer> where - Renderer: renderer::Renderer, + Renderer: renderer::Renderer + image::Renderer, Renderer::Theme: StyleSheet, { fn from(text: Text) -> Self { diff --git a/src/buffer_line.rs b/src/buffer_line.rs index c9fecba..673d968 100644 --- a/src/buffer_line.rs +++ b/src/buffer_line.rs @@ -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); diff --git a/src/shape.rs b/src/shape.rs index f484427..8e96636 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -480,10 +480,10 @@ impl ShapeLine { &self, font_size: i32, line_width: i32, - layout_lines: &mut Vec, - mut layout_i: usize, wrap_simple: bool, - ) { + ) -> Vec { + 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 } }