Implement draw_paragraph in iced_tiny_skia

This commit is contained in:
Héctor Ramón Jiménez 2023-09-03 08:08:27 +02:00
parent 601e5563d1
commit 8129e2c208
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
3 changed files with 115 additions and 68 deletions

View file

@ -405,7 +405,7 @@ impl Backend {
let clip_mask = (!physical_bounds.is_within(&clip_bounds))
.then_some(clip_mask as &_);
self.text_pipeline.draw(
self.text_pipeline.draw_cached(
content,
*bounds + translation,
*color,

View file

@ -41,16 +41,34 @@ impl Pipeline {
pub fn draw_paragraph(
&mut self,
_paragraph: &paragraph::Weak,
_position: Point,
_color: Color,
_scale_factor: f32,
_pixels: &mut tiny_skia::PixmapMut<'_>,
_clip_mask: Option<&tiny_skia::Mask>,
paragraph: &paragraph::Weak,
position: Point,
color: Color,
scale_factor: f32,
pixels: &mut tiny_skia::PixmapMut<'_>,
clip_mask: Option<&tiny_skia::Mask>,
) {
use crate::core::text::Paragraph as _;
let Some(paragraph) = paragraph.upgrade() else {
return;
};
draw(
&mut self.font_system.get_mut(),
&mut self.glyph_cache,
paragraph.buffer(),
Rectangle::new(position, paragraph.min_bounds()),
color,
paragraph.horizontal_alignment(),
paragraph.vertical_alignment(),
scale_factor,
pixels,
clip_mask,
);
}
pub fn draw(
pub fn draw_cached(
&mut self,
content: &str,
bounds: Rectangle,
@ -79,54 +97,25 @@ impl Pipeline {
let (_, entry) = self.cache.get_mut().allocate(font_system, key);
let max_width = entry.min_bounds.width * scale_factor;
let total_height = entry.min_bounds.height * scale_factor;
let width = entry.min_bounds.width;
let height = entry.min_bounds.height;
let bounds = bounds * scale_factor;
let x = match horizontal_alignment {
alignment::Horizontal::Left => bounds.x,
alignment::Horizontal::Center => bounds.x - max_width / 2.0,
alignment::Horizontal::Right => bounds.x - max_width,
};
let y = match vertical_alignment {
alignment::Vertical::Top => bounds.y,
alignment::Vertical::Center => bounds.y - total_height / 2.0,
alignment::Vertical::Bottom => bounds.y - total_height,
};
let mut swash = cosmic_text::SwashCache::new();
for run in entry.buffer.layout_runs() {
for glyph in run.glyphs {
let physical_glyph = glyph.physical((x, y), scale_factor);
if let Some((buffer, placement)) = self.glyph_cache.allocate(
physical_glyph.cache_key,
color,
font_system,
&mut swash,
) {
let pixmap = tiny_skia::PixmapRef::from_bytes(
buffer,
placement.width,
placement.height,
)
.expect("Create glyph pixel map");
pixels.draw_pixmap(
physical_glyph.x + placement.left,
physical_glyph.y - placement.top
+ (run.line_y * scale_factor).round() as i32,
pixmap,
&tiny_skia::PixmapPaint::default(),
tiny_skia::Transform::identity(),
clip_mask,
);
}
}
}
draw(
font_system,
&mut self.glyph_cache,
&entry.buffer,
Rectangle {
width,
height,
..bounds
},
color,
horizontal_alignment,
vertical_alignment,
scale_factor,
pixels,
clip_mask,
);
}
pub fn trim_cache(&mut self) {
@ -135,6 +124,65 @@ impl Pipeline {
}
}
fn draw(
font_system: &mut cosmic_text::FontSystem,
glyph_cache: &mut GlyphCache,
buffer: &cosmic_text::Buffer,
bounds: Rectangle,
color: Color,
horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical,
scale_factor: f32,
pixels: &mut tiny_skia::PixmapMut<'_>,
clip_mask: Option<&tiny_skia::Mask>,
) {
let bounds = bounds * scale_factor;
let x = match horizontal_alignment {
alignment::Horizontal::Left => bounds.x,
alignment::Horizontal::Center => bounds.x - bounds.width / 2.0,
alignment::Horizontal::Right => bounds.x - bounds.width,
};
let y = match vertical_alignment {
alignment::Vertical::Top => bounds.y,
alignment::Vertical::Center => bounds.y - bounds.height / 2.0,
alignment::Vertical::Bottom => bounds.y - bounds.height,
};
let mut swash = cosmic_text::SwashCache::new();
for run in buffer.layout_runs() {
for glyph in run.glyphs {
let physical_glyph = glyph.physical((x, y), scale_factor);
if let Some((buffer, placement)) = glyph_cache.allocate(
physical_glyph.cache_key,
color,
font_system,
&mut swash,
) {
let pixmap = tiny_skia::PixmapRef::from_bytes(
buffer,
placement.width,
placement.height,
)
.expect("Create glyph pixel map");
pixels.draw_pixmap(
physical_glyph.x + placement.left,
physical_glyph.y - placement.top
+ (run.line_y * scale_factor).round() as i32,
pixmap,
&tiny_skia::PixmapPaint::default(),
tiny_skia::Transform::identity(),
clip_mask,
);
}
}
}
}
#[derive(Debug, Clone, Default)]
struct GlyphCache {
entries: FxHashMap<

View file

@ -159,29 +159,28 @@ impl Pipeline {
}
};
let x = bounds.x * scale_factor;
let y = bounds.y * scale_factor;
let max_width = bounds.width * scale_factor;
let total_height = bounds.height * scale_factor;
let bounds = bounds * scale_factor;
let left = match horizontal_alignment {
alignment::Horizontal::Left => x,
alignment::Horizontal::Center => x - max_width / 2.0,
alignment::Horizontal::Right => x - max_width,
alignment::Horizontal::Left => bounds.x,
alignment::Horizontal::Center => {
bounds.x - bounds.width / 2.0
}
alignment::Horizontal::Right => bounds.x - bounds.width,
};
let top = match vertical_alignment {
alignment::Vertical::Top => y,
alignment::Vertical::Center => y - total_height / 2.0,
alignment::Vertical::Bottom => y - total_height,
alignment::Vertical::Top => bounds.y,
alignment::Vertical::Center => {
bounds.y - bounds.height / 2.0
}
alignment::Vertical::Bottom => bounds.y - bounds.height,
};
let section_bounds = Rectangle {
x: left,
y: top,
width: max_width,
height: total_height,
..bounds
};
let clip_bounds = layer_bounds.intersection(&section_bounds)?;