diff --git a/crates/gosub_cairo/src/elements/text.rs b/crates/gosub_cairo/src/elements/text.rs index 001884c8..72b2c81f 100644 --- a/crates/gosub_cairo/src/elements/text.rs +++ b/crates/gosub_cairo/src/elements/text.rs @@ -2,7 +2,7 @@ use crate::CairoBackend; use gosub_interface::layout::{Decoration, TextLayout}; use gosub_interface::render_backend::{RenderText, Text as TText}; use gosub_shared::font::{Glyph, GlyphID}; -use gosub_shared::geo::FP; +use gosub_shared::geo::{Point, FP}; use peniko::Font; use skrifa::instance::NormalizedCoord; use std::cell::RefCell; @@ -122,6 +122,8 @@ pub struct GsText { coords: Vec, // Text decoration (strike-through, underline, etc.) decoration: Decoration, + // offset in the element + offset: Point, } impl TText for GsText { @@ -152,6 +154,7 @@ impl TText for GsText { fs, coords, decoration: layout.decorations().clone(), + offset: layout.offset(), } } } @@ -169,7 +172,6 @@ impl GsText { cr.move_to(base_x, base_y); // Setup brush for rendering text - GsBrush::render(&obj.brush, cr); // This should be moved to the GosubFontContext::get_cairo_font_face(family: &str) method) let font_face = unsafe { @@ -184,49 +186,57 @@ impl GsText { }; cr.set_font_face(&font_face); - cr.set_font_size(obj.text.fs.into()); - - // Convert glyphs that are in parley / taffy format to cairo glyphs. Also make sure we - // offset the glyphs by the base_x and base_y. - let mut cairo_glyphs = vec![]; - for glyph in &obj.text.glyphs { - let cairo_glyph = cairo::Glyph::new(glyph.id as u64, base_x + glyph.x as f64, base_y + glyph.y as f64); - cairo_glyphs.push(cairo_glyph); - } + for text in &obj.text { + GsBrush::render(&obj.brush, cr); + cr.move_to(base_x + text.offset.x as f64, base_y + text.offset.y as f64); + cr.set_font_size(text.fs.into()); + + // Convert glyphs that are in parley / taffy format to cairo glyphs. Also make sure we + // offset the glyphs by the base_x and base_y. + let mut cairo_glyphs = vec![]; + for glyph in &text.glyphs { + let cairo_glyph = cairo::Glyph::new( + glyph.id as u64, + base_x + glyph.x as f64 + text.offset.x as f64, + base_y + glyph.y as f64 + text.offset.y as f64, + ); + cairo_glyphs.push(cairo_glyph); + } - _ = cr.show_glyphs(&cairo_glyphs); + _ = cr.show_glyphs(&cairo_glyphs); - // Set decoration (underline, overline, line-through) - { - let decoration = &obj.text.decoration; - let _stroke = Stroke::new(decoration.width as f64); + // Set decoration (underline, overline, line-through) + { + let decoration = &text.decoration; + let _stroke = Stroke::new(decoration.width as f64); - let c = decoration.color; - let brush = GsBrush::solid(GsColor::rgba32(c.0, c.1, c.2, 1.0)); - GsBrush::render(&brush, cr); + let c = decoration.color; + let brush = GsBrush::solid(GsColor::rgba32(c.0, c.1, c.2, 1.0)); + GsBrush::render(&brush, cr); - let offset = decoration.x_offset as f64; - if decoration.underline { - let y = base_y + decoration.underline_offset as f64; + let offset = decoration.x_offset as f64; + if decoration.underline { + let y = base_y + decoration.underline_offset as f64 + obj.rect.height; - cr.move_to(base_x + offset, y); - cr.line_to(base_x + obj.rect.width, y); - _ = cr.stroke(); - } - if decoration.overline { - let y = base_y - obj.rect.height; + cr.move_to(base_x + offset, y); + cr.line_to(base_x + obj.rect.width, y); + _ = cr.stroke(); + } + if decoration.overline { + let y = base_y - obj.rect.height; - cr.move_to(base_x + offset, y); - cr.line_to(base_x + obj.rect.width, y); - _ = cr.stroke(); - } + cr.move_to(base_x + offset, y); + cr.line_to(base_x + obj.rect.width, y); + _ = cr.stroke(); + } - if decoration.line_through { - let y = base_y - obj.rect.height / 2.0; + if decoration.line_through { + let y = base_y + obj.rect.height / 2.0; - cr.move_to(base_x + offset, y); - cr.line_to(base_x + obj.rect.width, y); - _ = cr.stroke(); + cr.move_to(base_x + offset, y); + cr.line_to(base_x + obj.rect.width, y); + _ = cr.stroke(); + } } } } diff --git a/crates/gosub_interface/src/layout.rs b/crates/gosub_interface/src/layout.rs index bdead5d2..28776451 100644 --- a/crates/gosub_interface/src/layout.rs +++ b/crates/gosub_interface/src/layout.rs @@ -34,7 +34,7 @@ pub trait Layouter: Sized + Clone + Send + 'static { type Cache: LayoutCache; type Layout: Layout + Send; - type TextLayout: TextLayout + Send; + type TextLayout: TextLayout + Send + Debug; const COLLAPSE_INLINE: bool; @@ -127,21 +127,20 @@ pub trait LayoutNode: HasTextLayout { fn get_property(&self, name: &str) -> Option<&C::CssProperty>; fn text_data(&self) -> Option<&str>; - fn text_size(&self) -> Option; - /// This can only return true if the `Layout::COLLAPSE_INLINE` is set true for the layouter /// fn is_anon_inline_parent(&self) -> bool; } pub trait HasTextLayout { - fn set_text_layout(&mut self, layout: ::TextLayout); + fn clear_text_layout(&mut self); + fn add_text_layout(&mut self, layout: ::TextLayout); + fn get_text_layouts(&self) -> Option<&[::TextLayout]>; + fn get_text_layouts_mut(&mut self) -> Option<&mut Vec<::TextLayout>>; } pub trait TextLayout { type Font: Font; - fn dbg_layout(&self) -> String; - fn size(&self) -> Size; fn glyphs(&self) -> &[Glyph]; @@ -153,6 +152,8 @@ pub trait TextLayout { fn coords(&self) -> &[i16]; fn decorations(&self) -> &Decoration; + + fn offset(&self) -> Point; } #[derive(Debug, Clone, Default)] diff --git a/crates/gosub_interface/src/render_backend.rs b/crates/gosub_interface/src/render_backend.rs index 5dc63ebe..7ee80905 100644 --- a/crates/gosub_interface/src/render_backend.rs +++ b/crates/gosub_interface/src/render_backend.rs @@ -128,7 +128,7 @@ impl RenderRect { #[derive(Clone, Debug)] pub struct RenderText { - pub text: B::Text, + pub text: Vec, pub rect: B::Rect, pub transform: Option, pub brush: B::Brush, @@ -136,7 +136,7 @@ pub struct RenderText { } impl RenderText { - pub fn new(text: B::Text, rect: B::Rect, brush: B::Brush) -> Self { + pub fn new(text: Vec, rect: B::Rect, brush: B::Brush) -> Self { Self { text, rect, diff --git a/crates/gosub_interface/src/render_tree.rs b/crates/gosub_interface/src/render_tree.rs index eae1e308..ab3c61f6 100644 --- a/crates/gosub_interface/src/render_tree.rs +++ b/crates/gosub_interface/src/render_tree.rs @@ -34,6 +34,6 @@ pub trait RenderTreeNode: Debug { fn layout_mut(&mut self) -> &mut ::Layout; fn element_attributes(&self) -> Option<&HashMap>; - fn text_data(&self) -> Option<(&str, Option<&::TextLayout>)>; + fn text_data(&self) -> Option<(&str, &[::TextLayout])>; fn name(&self) -> &str; } diff --git a/crates/gosub_renderer/src/draw.rs b/crates/gosub_renderer/src/draw.rs index 8ef68404..fc04fa9f 100644 --- a/crates/gosub_renderer/src/draw.rs +++ b/crates/gosub_renderer/src/draw.rs @@ -23,7 +23,7 @@ use gosub_rendering::render_tree::RenderTree; use gosub_shared::geo::{Size, SizeU32, FP}; use gosub_shared::node::NodeId; use gosub_shared::types::Result; -use log::{error, info, warn}; +use log::{error, info}; use std::future::Future; use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex}; @@ -495,13 +495,15 @@ fn render_text( .unwrap_or(Color::BLACK); if let Some((_, layout)) = &node.text_data() { - let Some(layout) = layout else { - warn!("No layout for text node"); - return; - }; - - let text: ::Text = - Text::new::<::TextLayout>(layout); + let text = layout + .iter() + .map(|layout| { + let text: ::Text = + Text::new::<::TextLayout>(layout); + + text + }) + .collect::>(); let size = node.layout().size(); diff --git a/crates/gosub_renderer/src/draw/testing.rs b/crates/gosub_renderer/src/draw/testing.rs index daa7d09b..db3c6ab0 100644 --- a/crates/gosub_renderer/src/draw/testing.rs +++ b/crates/gosub_renderer/src/draw/testing.rs @@ -34,7 +34,7 @@ pub(crate) fn test_add_element, "#text".to_string(), RenderNodeData::Text(Box::new(TextData { text: "test add element".to_string(), - layout: None, + layout: Vec::new(), })), props, ); diff --git a/crates/gosub_rendering/src/render_tree.rs b/crates/gosub_rendering/src/render_tree.rs index eac3cae7..8c076f9a 100644 --- a/crates/gosub_rendering/src/render_tree.rs +++ b/crates/gosub_rendering/src/render_tree.rs @@ -3,10 +3,9 @@ use gosub_interface::config::{HasDocument, HasLayouter, HasRenderTree}; use gosub_interface::css3::{CssProperty, CssPropertyMap, CssSystem}; use gosub_interface::document::Document; use gosub_interface::document_handle::DocumentHandle; -use gosub_interface::layout::{HasTextLayout, Layout, LayoutCache, LayoutNode, LayoutTree, Layouter, TextLayout}; +use gosub_interface::layout::{HasTextLayout, Layout, LayoutCache, LayoutNode, LayoutTree, Layouter}; use gosub_interface::node::NodeData; use gosub_interface::node::{ElementDataType, Node as DocumentNode, TextDataType}; -use gosub_interface::render_backend::Size; use gosub_interface::render_tree; use gosub_shared::node::NodeId; use gosub_shared::types::Result; @@ -603,9 +602,9 @@ impl render_tree::RenderTreeNode for RenderTreeNode { None } - fn text_data(&self) -> Option<(&str, Option<&::TextLayout>)> { + fn text_data(&self) -> Option<(&str, &[::TextLayout])> { if let RenderNodeData::Text(data) = &self.data { - return Some((&data.text, data.layout.as_ref())); + return Some((&data.text, &data.layout)); } None @@ -654,14 +653,14 @@ impl Debug for RenderNodeData { pub struct TextData { pub text: String, - pub layout: Option, + pub layout: Vec, } impl Debug for TextData { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("TextData") .field("text", &self.text) - .field("layout", &self.layout.as_ref().map(|x| x.dbg_layout())) + .field("layout", &self.layout) .finish() } } @@ -681,7 +680,10 @@ impl RenderNodeData { NodeData::Text(data) => { let text = pre_transform_text(data.string_value()); - RenderNodeData::Text(Box::new(TextData { text, layout: None })) + RenderNodeData::Text(Box::new(TextData { + text, + layout: Vec::new(), + })) } NodeData::Document(_) => RenderNodeData::Document, _ => return ControlFlow::Drop, @@ -780,28 +782,42 @@ impl RenderTreeNode { } impl HasTextLayout for RenderTreeNode { - fn set_text_layout(&mut self, layout: ::TextLayout) { + fn clear_text_layout(&mut self) { if let RenderNodeData::Text(text) = &mut self.data { - text.layout = Some(layout); + text.layout.clear(); } } -} -impl LayoutNode for RenderTreeNode { - fn get_property(&self, name: &str) -> Option<&C::CssProperty> { - self.properties.get(name) + fn add_text_layout(&mut self, layout: ::TextLayout) { + if let RenderNodeData::Text(text) = &mut self.data { + text.layout.push(layout); + } } - fn text_data(&self) -> Option<&str> { + + fn get_text_layouts(&self) -> Option<&[::TextLayout]> { if let RenderNodeData::Text(text) = &self.data { - Some(&text.text) + Some(&text.layout) + } else { + None + } + } + + fn get_text_layouts_mut(&mut self) -> Option<&mut Vec<::TextLayout>> { + if let RenderNodeData::Text(text) = &mut self.data { + Some(&mut text.layout) } else { None } } +} - fn text_size(&self) -> Option { +impl LayoutNode for RenderTreeNode { + fn get_property(&self, name: &str) -> Option<&C::CssProperty> { + self.properties.get(name) + } + fn text_data(&self) -> Option<&str> { if let RenderNodeData::Text(text) = &self.data { - text.layout.as_ref().map(|layout| layout.size()) + Some(&text.text) } else { None } diff --git a/crates/gosub_taffy/src/compute/inline.rs b/crates/gosub_taffy/src/compute/inline.rs index f94df053..f819b0f4 100644 --- a/crates/gosub_taffy/src/compute/inline.rs +++ b/crates/gosub_taffy/src/compute/inline.rs @@ -15,6 +15,7 @@ use gosub_interface::css3::{CssProperty, CssValue}; use gosub_interface::layout::{Decoration, DecorationStyle, HasTextLayout, LayoutNode, LayoutTree}; use gosub_shared::font::Glyph; use gosub_shared::geo; +use gosub_shared::geo::FP; use gosub_shared::ROBOTO_FONT; use crate::text::{Font, TextLayout}; @@ -54,6 +55,7 @@ pub fn compute_inline_layout>( let Some(node) = tree.0.get_node_mut(*child) else { continue; }; + node.clear_text_layout(); if let Some(text) = node.text_data() { if text.is_empty() { @@ -225,6 +227,12 @@ pub fn compute_inline_layout>( let mut builder = layout_cx.ranged_builder(&mut lock, &str_buf, 1.0); let mut align = Alignment::default(); + println!("============================="); + + for d in &text_node_data { + dbg!(d); + } + if let Some(default) = text_node_data.first() { builder.push_default(StyleProperty::FontStack(FontStack::Source( (&default.font_family).into(), @@ -368,6 +376,8 @@ pub fn compute_inline_layout>( let mut current_glyph_idx = 0; + let mut ids = Vec::with_capacity(text_node_data.len()); + 'lines: for line in layout.lines() { let metrics = line.metrics(); @@ -418,10 +428,9 @@ pub fn compute_inline_layout>( let coords = grun.normalized_coords().to_owned(); - let mut decoration = text_node_data - .get(run.style().brush) - .map(|x| x.decoration.clone()) - .unwrap_or_default(); + let data = text_node_data.get(run.style().brush); + + let mut decoration = data.map(|x| x.decoration.clone()).unwrap_or_default(); if let Some(text) = str_buf.get(grun.text_range()) { let first_non_ws = text.chars().position(|c| !c.is_whitespace()); @@ -445,34 +454,23 @@ pub fn compute_inline_layout>( glyphs, coords, decoration, + offset: geo::Point { + x: run.offset() as FP, + y: run_y as FP, + }, }; - let Some(node) = tree.0.get_node_mut(current_node_id) else { - continue; - }; + let node_id = data + .map(|x| >::NodeId::from(x.id.into())) + .unwrap_or(current_node_id); - node.set_text_layout(text_layout); + ids.push(node_id); - let size = Size { - width: size.width, - height: size.height, + let Some(node) = tree.0.get_node_mut(node_id) else { + continue; }; - tree.set_unrounded_layout( - NodeId::new(current_node_id.into()), - &Layout { - size, - content_size: size, - scrollbar_size: Size::ZERO, - border: Rect::ZERO, - location: Point { - x: run.offset(), - y: run_y, - }, - order: 0, - padding: Rect::ZERO, - margin: Rect::ZERO, - }, - ); + + node.add_text_layout(text_layout); } PositionedLayoutItem::InlineBox(inline_box) => { let id = NodeId::from(inline_box.id); @@ -503,6 +501,47 @@ pub fn compute_inline_layout>( } } + for id in ids { + let Some(node) = tree.0.get_node_mut(id) else { continue }; + + let Some(layouts) = node.get_text_layouts_mut() else { + continue; + }; + + let mut location = Point { + x: f32::INFINITY, + y: f32::INFINITY, + }; + let mut size = Size::ZERO; + + for layout in &*layouts { + location.x = location.x.min(layout.offset.x); + location.y = location.y.min(layout.offset.y - layout.size.height); + + size.width = size.width.max(layout.size.width + layout.offset.x); + size.height = size.height.max(layout.offset.y); + } + + for layout in layouts { + layout.offset.x -= location.x; + layout.offset.y -= location.y; + } + + tree.set_unrounded_layout( + NodeId::new(current_node_id.into()), + &Layout { + size, + content_size: size, + scrollbar_size: Size::ZERO, + border: Rect::ZERO, + location, + order: 0, + padding: Rect::ZERO, + margin: Rect::ZERO, + }, + ); + } + let mut size = content_size; if let AvailableSpace::Definite(width) = layout_input.available_space.width { diff --git a/crates/gosub_taffy/src/style/parse.rs b/crates/gosub_taffy/src/style/parse.rs index ed5d2cfe..78fc6f8b 100644 --- a/crates/gosub_taffy/src/style/parse.rs +++ b/crates/gosub_taffy/src/style/parse.rs @@ -7,7 +7,6 @@ use taffy::{ use gosub_interface::config::HasLayouter; use gosub_interface::css3::CssProperty; use gosub_interface::layout::LayoutNode; -use gosub_shared::geo::Size; pub fn parse_len(node: &mut impl LayoutNode, name: &str) -> LengthPercentage { let Some(property) = node.get_property(name) else { @@ -57,16 +56,6 @@ pub fn parse_dimension(node: &mut impl LayoutNode, name: &str Dimension::Length(property.unit_to_px()) } -pub fn parse_text_dim(size: Size, name: &str) -> Dimension { - if name == "width" || name == "max-width" || name == "min-width" { - Dimension::Length(size.width) - } else if name == "height" || name == "max-height" || name == "min-height" { - Dimension::Length(size.height) - } else { - Dimension::Auto - } -} - pub fn parse_align_i(node: &mut impl LayoutNode, name: &str) -> Option { let display = node.get_property(name)?; let value = display.as_string()?; diff --git a/crates/gosub_taffy/src/style/parse_properties.rs b/crates/gosub_taffy/src/style/parse_properties.rs index 119f672e..297ebf74 100644 --- a/crates/gosub_taffy/src/style/parse_properties.rs +++ b/crates/gosub_taffy/src/style/parse_properties.rs @@ -4,7 +4,7 @@ use taffy::{Overflow, Point, TextAlign}; use crate::style::parse::{ parse_align_c, parse_align_i, parse_dimension, parse_grid_auto, parse_grid_placement, parse_len, parse_len_auto, - parse_text_dim, parse_tracking_sizing_function, + parse_tracking_sizing_function, }; use gosub_interface::config::HasLayouter; use gosub_interface::css3::CssProperty; @@ -89,13 +89,6 @@ pub fn parse_inset(node: &mut impl LayoutNode) -> Rect(node: &mut impl LayoutNode) -> Size { - if let Some(t) = node.text_size() { - return Size { - width: parse_text_dim(t, "width"), - height: parse_text_dim(t, "height"), - }; - } - Size { width: parse_dimension(node, "width"), height: parse_dimension(node, "height"), @@ -103,13 +96,6 @@ pub fn parse_size(node: &mut impl LayoutNode) -> Size(node: &mut impl LayoutNode) -> Size { - if let Some(t) = node.text_size() { - return Size { - width: parse_text_dim(t, "min-width"), - height: parse_text_dim(t, "min-height"), - }; - } - Size { width: parse_dimension(node, "min-width"), height: parse_dimension(node, "min-height"), @@ -117,13 +103,6 @@ pub fn parse_min_size(node: &mut impl LayoutNode) -> Size(node: &mut impl LayoutNode) -> Size { - if let Some(t) = node.text_size() { - return Size { - width: parse_text_dim(t, "max-width"), - height: parse_text_dim(t, "max-height"), - }; - } - Size { width: parse_dimension(node, "max-width"), height: parse_dimension(node, "max-height"), diff --git a/crates/gosub_taffy/src/text.rs b/crates/gosub_taffy/src/text.rs index 0a4c526e..f765761e 100644 --- a/crates/gosub_taffy/src/text.rs +++ b/crates/gosub_taffy/src/text.rs @@ -1,8 +1,10 @@ use gosub_interface::layout::{Decoration, TextLayout as TLayout}; use gosub_shared::font::Font as TFont; use gosub_shared::font::Glyph; -use gosub_shared::geo::Size; +use gosub_shared::geo::{Point, Size}; use parley::Font as PFont; +use std::fmt; +use std::fmt::{Debug, Formatter}; #[derive(Debug, Clone)] pub struct Font(pub PFont); @@ -19,7 +21,6 @@ impl From for PFont { } } -#[derive(Debug)] pub struct TextLayout { pub glyphs: Vec, pub font: Font, @@ -27,15 +28,23 @@ pub struct TextLayout { pub size: Size, pub coords: Vec, pub decoration: Decoration, + pub offset: Point, +} + +impl Debug for TextLayout { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("TextLayout") + .field("size", &self.size) + .field("font_size", &self.font_size) + .field("decoration", &self.decoration) + .field("offset", &self.offset) + .finish() + } } impl TLayout for TextLayout { type Font = Font; - fn dbg_layout(&self) -> String { - format!("TextLayout: {:?}", self) - } - fn size(&self) -> Size { self.size } @@ -59,4 +68,8 @@ impl TLayout for TextLayout { fn decorations(&self) -> &Decoration { &self.decoration } + + fn offset(&self) -> Point { + self.offset + } } diff --git a/crates/gosub_vello/src/text.rs b/crates/gosub_vello/src/text.rs index a073c0c5..21cddb13 100644 --- a/crates/gosub_vello/src/text.rs +++ b/crates/gosub_vello/src/text.rs @@ -1,7 +1,7 @@ use crate::VelloBackend; use gosub_interface::layout::{Decoration, TextLayout}; use gosub_interface::render_backend::{RenderText, Text as TText}; -use gosub_shared::geo::FP; +use gosub_shared::geo::{Point, FP}; use vello::kurbo::{Affine, Line, Stroke}; use vello::peniko::{Brush, Color, Fill, Font, StyleRef}; use vello::skrifa::instance::NormalizedCoord; @@ -15,6 +15,7 @@ pub struct Text { fs: FP, coords: Vec, decoration: Decoration, + offset: Point, } impl TText for Text { @@ -44,6 +45,7 @@ impl TText for Text { fs, coords, decoration: layout.decorations().clone(), + offset: layout.offset(), } } } @@ -61,48 +63,50 @@ impl Text { let transform = transform.with_translation((x, y).into()); - scene - .draw_glyphs(&render.text.font) - .font_size(render.text.fs) - .transform(transform) - .glyph_transform(brush_transform) - .normalized_coords(&render.text.coords) - .brush(brush) - .draw(style, render.text.glyphs.iter().copied()); + for text in &render.text { + let transform = transform.then_translate((text.offset.x as f64, text.offset.y as f64).into()); - { - let decoration = &render.text.decoration; + scene + .draw_glyphs(&text.font) + .font_size(text.fs) + .transform(transform) + .glyph_transform(brush_transform) + .normalized_coords(&text.coords) + .brush(brush) + .draw(style, text.glyphs.iter().copied()); - let stroke = Stroke::new(decoration.width as f64); + { + let decoration = &text.decoration; - let c = decoration.color; + let stroke = Stroke::new(decoration.width as f64); - let brush = Brush::Solid(Color::rgba(c.0 as f64, c.1 as f64, c.2 as f64, c.3 as f64)); + let c = decoration.color; - let offset = decoration.x_offset as f64; + let brush = Brush::Solid(Color::rgba(c.0 as f64, c.1 as f64, c.2 as f64, c.3 as f64)); - if decoration.underline { - let y = y + decoration.underline_offset as f64; + let offset = decoration.x_offset as f64; - let line = Line::new((x + offset, y), (x + render.rect.0.width(), y)); + if decoration.underline { + let y = y + decoration.underline_offset as f64 + render.rect.0.height(); - scene.stroke(&stroke, Affine::IDENTITY, &brush, None, &line); - } + let line = Line::new((x + offset, y), (x + render.rect.0.width(), y)); - if decoration.overline { - let y = y - render.rect.0.height(); + scene.stroke(&stroke, Affine::IDENTITY, &brush, None, &line); + } - let line = Line::new((x + offset, y), (x + render.rect.0.width(), y)); + if decoration.overline { + let line = Line::new((x + offset, y), (x + render.rect.0.width(), y)); - scene.stroke(&stroke, Affine::IDENTITY, &brush, None, &line); - } + scene.stroke(&stroke, Affine::IDENTITY, &brush, None, &line); + } - if decoration.line_through { - let y = y - render.rect.0.height() / 2.0; + if decoration.line_through { + let y = y + render.rect.0.height() / 2.0; - let line = Line::new((x + offset, y), (x + render.rect.0.width(), y)); + let line = Line::new((x + offset, y), (x + render.rect.0.width(), y)); - scene.stroke(&stroke, Affine::IDENTITY, &brush, None, &line); + scene.stroke(&stroke, Affine::IDENTITY, &brush, None, &line); + } } } }