Skip to content

Commit

Permalink
Added decorations in examples (underline & strikethrough) (#167)
Browse files Browse the repository at this point in the history
This is related to #142.
  • Loading branch information
spirali authored Nov 9, 2024
1 parent a35e00f commit b10ba60
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 7 deletions.
56 changes: 54 additions & 2 deletions examples/swash_render/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use zeno::{Format, Vector};
fn main() {
// The text we are going to style and lay out
let text = String::from(
"Some text here. Let's make it a bit longer so that line wrapping kicks in 😊. And also some اللغة العربية arabic text.",
"Some text here. Let's make it a bit longer so that line wrapping kicks in 😊. And also some اللغة العربية arabic text.\nThis is underline and strikethrough text",
);

// The display scale for HiDPI rendering
Expand Down Expand Up @@ -48,6 +48,8 @@ fn main() {
let brush_style = StyleProperty::Brush(text_color);
let font_stack = FontStack::from("system-ui");
let bold_style = StyleProperty::FontWeight(FontWeight::new(600.0));
let underline_style = StyleProperty::Underline(true);
let strikethrough_style = StyleProperty::Strikethrough(true);

let mut layout = if std::env::args().any(|arg| arg == "--tree") {
// TREE BUILDER
Expand Down Expand Up @@ -87,7 +89,18 @@ fn main() {
height: 30.0,
});

builder.push_text(&text[50..]);
builder.push_text(&text[50..141]);

// Set the underline style
builder.push_style_modification_span(&[underline_style]);
builder.push_text(&text[141..150]);

builder.pop_style_span();
builder.push_text(&text[150..155]);

// Set the strikethrough style
builder.push_style_modification_span(&[strikethrough_style]);
builder.push_text(&text[155..168]);

// Build the builder into a Layout
// let mut layout: Layout<Color> = builder.build(&text);
Expand All @@ -111,6 +124,10 @@ fn main() {
// Set the first 4 characters to bold
builder.push(bold_style, 0..4);

// Set the underline & stoked style
builder.push(underline_style, 141..150);
builder.push(strikethrough_style, 155..168);

builder.push_inline_box(InlineBox {
id: 0,
index: 40,
Expand Down Expand Up @@ -217,6 +234,41 @@ fn render_glyph_run(

render_glyph(img, &mut scaler, color, glyph, glyph_x, glyph_y);
}

// Draw decorations: underline & strikethrough
let style = glyph_run.style();
let run_metrics = run.metrics();
if let Some(decoration) = &style.underline {
let offset = decoration.offset.unwrap_or(run_metrics.underline_offset);
let size = decoration.size.unwrap_or(run_metrics.underline_size);
render_decoration(img, glyph_run, decoration.brush, offset, size, padding);
}
if let Some(decoration) = &style.strikethrough {
let offset = decoration
.offset
.unwrap_or(run_metrics.strikethrough_offset);
let size = decoration.size.unwrap_or(run_metrics.strikethrough_size);
render_decoration(img, glyph_run, decoration.brush, offset, size, padding);
}
}

fn render_decoration(
img: &mut RgbaImage,
glyph_run: &GlyphRun<Color>,
color: Color,
offset: f32,
width: f32,
padding: u32,
) {
let y = glyph_run.baseline() - offset;
let color = Rgba([color.r, color.g, color.b, color.a]);
for pixel_y in y as u32..(y + width) as u32 {
for pixel_x in glyph_run.offset() as u32..(glyph_run.offset() + glyph_run.advance()) as u32
{
img.get_pixel_mut(pixel_x + padding, pixel_y + padding)
.blend(&color);
}
}
}

fn render_glyph(
Expand Down
45 changes: 40 additions & 5 deletions examples/tiny_skia_render/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use tiny_skia::{
fn main() {
// The text we are going to style and lay out
let text = String::from(
"Some text here. Let's make it a bit longer so that line wrapping kicks in 😊. And also some اللغة العربية arabic text.",
"Some text here. Let's make it a bit longer so that line wrapping kicks in 😊. And also some اللغة العربية arabic text.\nThis is underline and strikethrough text",
);

// The display scale for HiDPI rendering
Expand Down Expand Up @@ -64,6 +64,10 @@ fn main() {
let bold = FontWeight::new(600.0);
builder.push(StyleProperty::FontWeight(bold), 0..4);

// Set the underline & stoked style
builder.push(StyleProperty::Underline(true), 141..150);
builder.push(StyleProperty::Strikethrough(true), 155..168);

builder.push_inline_box(InlineBox {
id: 0,
index: 40,
Expand Down Expand Up @@ -158,12 +162,43 @@ fn render_glyph_run(glyph_run: &GlyphRun<PenikoColor>, pen: &mut TinySkiaPen<'_>
run_x += glyph.advance;

let glyph_id = GlyphId::from(glyph.id);
let glyph_outline = outlines.get(glyph_id).unwrap();
if let Some(glyph_outline) = outlines.get(glyph_id) {
pen.set_origin(glyph_x, glyph_y);
pen.set_color(to_tiny_skia(color));
pen.draw_glyph(&glyph_outline, font_size, &normalized_coords);
}
}

pen.set_origin(glyph_x, glyph_y);
pen.set_color(to_tiny_skia(color));
pen.draw_glyph(&glyph_outline, font_size, &normalized_coords);
// Draw decorations: underline & strikethrough
let style = glyph_run.style();
let run_metrics = run.metrics();
if let Some(decoration) = &style.underline {
let offset = decoration.offset.unwrap_or(run_metrics.underline_offset);
let size = decoration.size.unwrap_or(run_metrics.underline_size);
render_decoration(pen, glyph_run, decoration.brush, offset, size, padding);
}
if let Some(decoration) = &style.strikethrough {
let offset = decoration
.offset
.unwrap_or(run_metrics.strikethrough_offset);
let size = decoration.size.unwrap_or(run_metrics.strikethrough_size);
render_decoration(pen, glyph_run, decoration.brush, offset, size, padding);
}
}

fn render_decoration(
pen: &mut TinySkiaPen<'_>,
glyph_run: &GlyphRun<PenikoColor>,
color: PenikoColor,
offset: f32,
width: f32,
padding: u32,
) {
let y = glyph_run.baseline() - offset + padding as f32;
let x = glyph_run.offset() + padding as f32;
pen.set_color(to_tiny_skia(color));
pen.set_origin(x, y);
pen.fill_rect(glyph_run.advance(), width);
}

struct TinySkiaPen<'a> {
Expand Down

0 comments on commit b10ba60

Please sign in to comment.