Skip to content

Commit

Permalink
Implement draw_paragraph in iced_tiny_skia
Browse files Browse the repository at this point in the history
  • Loading branch information
hecrj committed Sep 3, 2023
1 parent 601e556 commit 8129e2c
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 69 deletions.
2 changes: 1 addition & 1 deletion tiny_skia/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
158 changes: 103 additions & 55 deletions tiny_skia/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),

Check failure on line 58 in tiny_skia/src/text.rs

View workflow job for this annotation

GitHub Actions / all

this expression creates a reference which is immediately dereferenced by the compiler

Check failure on line 58 in tiny_skia/src/text.rs

View workflow job for this annotation

GitHub Actions / all

this expression creates a reference which is immediately dereferenced by the compiler
&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,
Expand Down Expand Up @@ -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 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,
);
}
}
}
let width = entry.min_bounds.width;
let height = entry.min_bounds.height;

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) {
Expand All @@ -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<
Expand Down
25 changes: 12 additions & 13 deletions wgpu/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand Down

0 comments on commit 8129e2c

Please sign in to comment.