Add rounded corners and strokes to highlight (#3526)

This commit is contained in:
frozolotl 2024-03-01 09:18:32 +00:00 committed by GitHub
parent 030041466b
commit 67ba8d6c0e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 66 additions and 11 deletions

View File

@ -5,12 +5,14 @@ use ttf_parser::{GlyphId, OutlineBuilder};
use crate::diag::SourceResult; use crate::diag::SourceResult;
use crate::engine::Engine; use crate::engine::Engine;
use crate::foundations::{elem, Content, Packed, Show, Smart, StyleChain}; use crate::foundations::{elem, Content, Packed, Show, Smart, StyleChain};
use crate::layout::{Abs, Em, Frame, FrameItem, Length, Point, Size}; use crate::layout::{
Abs, Corners, Em, Frame, FrameItem, Length, Point, Rel, Sides, Size,
};
use crate::syntax::Span; use crate::syntax::Span;
use crate::text::{ use crate::text::{
BottomEdge, BottomEdgeMetric, TextElem, TextItem, TopEdge, TopEdgeMetric, BottomEdge, BottomEdgeMetric, TextElem, TextItem, TopEdge, TopEdgeMetric,
}; };
use crate::visualize::{Color, FixedStroke, Geometry, Paint, Stroke}; use crate::visualize::{styled_rect, Color, FixedStroke, Geometry, Paint, Stroke};
/// Underlines text. /// Underlines text.
/// ///
@ -283,6 +285,12 @@ pub struct HighlightElem {
#[default(Color::from_u8(0xFF, 0xFD, 0x11, 0xA1).into())] #[default(Color::from_u8(0xFF, 0xFD, 0x11, 0xA1).into())]
pub fill: Paint, pub fill: Paint,
/// The highlight's border color. See the
/// [rectangle's documentation]($rect.stroke) for more details.
#[resolve]
#[fold]
pub stroke: Sides<Option<Option<Stroke>>>,
/// The top end of the background rectangle. /// The top end of the background rectangle.
/// ///
/// ```example /// ```example
@ -316,6 +324,12 @@ pub struct HighlightElem {
#[resolve] #[resolve]
pub extent: Length, pub extent: Length,
/// How much to round the highlight's corners. See the
/// [rectangle's documentation]($rect.radius) for more details.
#[resolve]
#[fold]
pub radius: Corners<Option<Rel<Length>>>,
/// The content that should be highlighted. /// The content that should be highlighted.
#[required] #[required]
pub body: Content, pub body: Content,
@ -327,8 +341,13 @@ impl Show for Packed<HighlightElem> {
Ok(self.body().clone().styled(TextElem::set_deco(smallvec![Decoration { Ok(self.body().clone().styled(TextElem::set_deco(smallvec![Decoration {
line: DecoLine::Highlight { line: DecoLine::Highlight {
fill: self.fill(styles), fill: self.fill(styles),
stroke: self
.stroke(styles)
.unwrap_or_default()
.map(|stroke| stroke.map(Stroke::unwrap_or_default)),
top_edge: self.top_edge(styles), top_edge: self.top_edge(styles),
bottom_edge: self.bottom_edge(styles), bottom_edge: self.bottom_edge(styles),
radius: self.radius(styles).unwrap_or_default(),
}, },
extent: self.extent(styles), extent: self.extent(styles),
}]))) }])))
@ -348,10 +367,30 @@ pub struct Decoration {
/// A kind of decorative line. /// A kind of decorative line.
#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum DecoLine { enum DecoLine {
Underline { stroke: Stroke<Abs>, offset: Smart<Abs>, evade: bool, background: bool }, Underline {
Strikethrough { stroke: Stroke<Abs>, offset: Smart<Abs>, background: bool }, stroke: Stroke<Abs>,
Overline { stroke: Stroke<Abs>, offset: Smart<Abs>, evade: bool, background: bool }, offset: Smart<Abs>,
Highlight { fill: Paint, top_edge: TopEdge, bottom_edge: BottomEdge }, evade: bool,
background: bool,
},
Strikethrough {
stroke: Stroke<Abs>,
offset: Smart<Abs>,
background: bool,
},
Overline {
stroke: Stroke<Abs>,
offset: Smart<Abs>,
evade: bool,
background: bool,
},
Highlight {
fill: Paint,
stroke: Sides<Option<FixedStroke>>,
top_edge: TopEdge,
bottom_edge: BottomEdge,
radius: Corners<Rel<Abs>>,
},
} }
/// Add line decorations to a single run of shaped text. /// Add line decorations to a single run of shaped text.
@ -365,12 +404,18 @@ pub(crate) fn decorate(
) { ) {
let font_metrics = text.font.metrics(); let font_metrics = text.font.metrics();
if let DecoLine::Highlight { fill, top_edge, bottom_edge } = &deco.line { if let DecoLine::Highlight { fill, stroke, top_edge, bottom_edge, radius } =
&deco.line
{
let (top, bottom) = determine_edges(text, *top_edge, *bottom_edge); let (top, bottom) = determine_edges(text, *top_edge, *bottom_edge);
let rect = Geometry::Rect(Size::new(width + 2.0 * deco.extent, top - bottom)) let size = Size::new(width + 2.0 * deco.extent, top - bottom);
.filled(fill.clone()); let rects = styled_rect(size, *radius, Some(fill.clone()), stroke.clone());
let origin = Point::new(pos.x - deco.extent, pos.y - top - shift); let origin = Point::new(pos.x - deco.extent, pos.y - top - shift);
frame.prepend(origin, FrameItem::Shape(rect, Span::detached())); frame.prepend_multiple(
rects
.into_iter()
.map(|shape| (origin, FrameItem::Shape(shape, Span::detached()))),
);
return; return;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 63 KiB

View File

@ -58,6 +58,17 @@ We can also specify a customized value
#highlight[abc] #highlight[abc]
#highlight[abc #sym.integral] #highlight[abc #sym.integral]
---
// Test highlight radius
#highlight(radius: 3pt)[abc],
#highlight(radius: 1em)[#lorem(5)]
---
// Test highlight stroke
#highlight(stroke: 2pt + blue)[abc]
#highlight(stroke: (top: blue, left: red, bottom: green, right: orange))[abc]
#highlight(stroke: 1pt, radius: 3pt)[#lorem(5)]
--- ---
// Test underline background // Test underline background
#set underline(background: true, stroke: (thickness: 0.5em, paint: red, cap: "round")) #set underline(background: true, stroke: (thickness: 0.5em, paint: red, cap: "round"))
@ -68,7 +79,6 @@ We can also specify a customized value
#set overline(background: true, stroke: (thickness: 0.5em, paint: red, cap: "round")) #set overline(background: true, stroke: (thickness: 0.5em, paint: red, cap: "round"))
#overline[This is in the background] #overline[This is in the background]
--- ---
// Test strike background // Test strike background
#set strike(background: true, stroke: 5pt + red) #set strike(background: true, stroke: 5pt + red)