mirror of
https://github.com/typst/typst
synced 2025-05-19 11:35:27 +08:00
- Shapes text with rustybuzz - Font fallback with family list - Tofus are shown in the first font Co-Authored-By: Martin <mhaug@live.de>
143 lines
3.6 KiB
Rust
143 lines
3.6 KiB
Rust
use fontdock::FaceId;
|
|
use ttf_parser::GlyphId;
|
|
|
|
use crate::color::Color;
|
|
use crate::env::ResourceId;
|
|
use crate::geom::{Length, Path, Point, Size};
|
|
|
|
/// A finished layout with elements at fixed positions.
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct Frame {
|
|
/// The size of the frame.
|
|
pub size: Size,
|
|
/// The elements composing this layout.
|
|
pub elements: Vec<(Point, Element)>,
|
|
}
|
|
|
|
impl Frame {
|
|
/// Create a new, empty frame.
|
|
pub fn new(size: Size) -> Self {
|
|
Self { size, elements: vec![] }
|
|
}
|
|
|
|
/// Add an element at a position.
|
|
pub fn push(&mut self, pos: Point, element: Element) {
|
|
self.elements.push((pos, element));
|
|
}
|
|
|
|
/// Add all elements of another frame, placing them relative to the given
|
|
/// position.
|
|
pub fn push_frame(&mut self, pos: Point, subframe: Self) {
|
|
for (subpos, element) in subframe.elements {
|
|
self.push(pos + subpos, element);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The building block frames are composed of.
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum Element {
|
|
/// Shaped text.
|
|
Text(ShapedText),
|
|
/// A geometric shape.
|
|
Geometry(Geometry),
|
|
/// A raster image.
|
|
Image(Image),
|
|
}
|
|
|
|
/// A shaped run of text.
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct ShapedText {
|
|
/// The font face the text was shaped with.
|
|
pub face: FaceId,
|
|
/// The font size.
|
|
pub size: Length,
|
|
/// The width.
|
|
pub width: Length,
|
|
/// The extent to the top.
|
|
pub top: Length,
|
|
/// The extent to the bottom.
|
|
pub bottom: Length,
|
|
/// The glyph fill color / texture.
|
|
pub color: Fill,
|
|
/// The shaped glyphs.
|
|
pub glyphs: Vec<GlyphId>,
|
|
/// The horizontal offsets of the glyphs. This is indexed parallel to
|
|
/// `glyphs`. Vertical offsets are not yet supported.
|
|
pub offsets: Vec<Length>,
|
|
}
|
|
|
|
impl ShapedText {
|
|
/// Create a new shape run with `width` zero and empty `glyphs` and `offsets`.
|
|
pub fn new(
|
|
face: FaceId,
|
|
size: Length,
|
|
top: Length,
|
|
bottom: Length,
|
|
color: Fill,
|
|
) -> Self {
|
|
Self {
|
|
face,
|
|
size,
|
|
width: Length::ZERO,
|
|
top,
|
|
bottom,
|
|
glyphs: vec![],
|
|
offsets: vec![],
|
|
color,
|
|
}
|
|
}
|
|
|
|
/// Encode the glyph ids into a big-endian byte buffer.
|
|
pub fn encode_glyphs_be(&self) -> Vec<u8> {
|
|
let mut bytes = Vec::with_capacity(2 * self.glyphs.len());
|
|
for &GlyphId(g) in &self.glyphs {
|
|
bytes.push((g >> 8) as u8);
|
|
bytes.push((g & 0xff) as u8);
|
|
}
|
|
bytes
|
|
}
|
|
}
|
|
|
|
/// A shape with some kind of fill.
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct Geometry {
|
|
/// The shape to draw.
|
|
pub shape: Shape,
|
|
/// How the shape looks on the inside.
|
|
//
|
|
// TODO: This could be made into a Vec<Fill> or something such that
|
|
// the user can compose multiple fills with alpha values less
|
|
// than one to achieve cool effects.
|
|
pub fill: Fill,
|
|
}
|
|
|
|
/// Some shape.
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum Shape {
|
|
/// A rectangle with its origin in the topleft corner.
|
|
Rect(Size),
|
|
/// An ellipse with its origin in the center.
|
|
Ellipse(Size),
|
|
/// A bezier path.
|
|
Path(Path),
|
|
}
|
|
|
|
/// The kind of graphic fill to be applied to a [`Shape`].
|
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
|
pub enum Fill {
|
|
/// The fill is a color.
|
|
Color(Color),
|
|
/// The fill is an image.
|
|
Image(Image),
|
|
}
|
|
|
|
/// An image element.
|
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
|
pub struct Image {
|
|
/// The image resource.
|
|
pub res: ResourceId,
|
|
/// The size of the image in the document.
|
|
pub size: Size,
|
|
}
|