mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Remove unncessary wrappers and typedefs 🛑
This commit is contained in:
parent
105f70867d
commit
c1dd872b34
@ -9,7 +9,7 @@ use fontdock::{FontStretch, FontStyle, FontWeight};
|
|||||||
use super::dict::{Dict, SpannedEntry};
|
use super::dict::{Dict, SpannedEntry};
|
||||||
use crate::color::RgbaColor;
|
use crate::color::RgbaColor;
|
||||||
use crate::geom::Linear;
|
use crate::geom::Linear;
|
||||||
use crate::layout::{Command, Commands, Dir, LayoutContext, SpecAlign};
|
use crate::layout::{Command, Dir, LayoutContext, SpecAlign};
|
||||||
use crate::paper::Paper;
|
use crate::paper::Paper;
|
||||||
use crate::syntax::{Ident, Span, SpanWith, Spanned, SynNode, SynTree};
|
use crate::syntax::{Ident, Span, SpanWith, Spanned, SynNode, SynTree};
|
||||||
use crate::{DynFuture, Feedback};
|
use crate::{DynFuture, Feedback};
|
||||||
@ -49,7 +49,7 @@ pub enum Value {
|
|||||||
/// An executable function.
|
/// An executable function.
|
||||||
Func(ValueFunc),
|
Func(ValueFunc),
|
||||||
/// Layouting commands.
|
/// Layouting commands.
|
||||||
Commands(Commands),
|
Commands(Vec<Command>),
|
||||||
/// The result of invalid operations.
|
/// The result of invalid operations.
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ impl Spanned<Value> {
|
|||||||
///
|
///
|
||||||
/// If this is already a command-value, it is simply unwrapped, otherwise
|
/// If this is already a command-value, it is simply unwrapped, otherwise
|
||||||
/// the value is represented as layoutable content in a reasonable way.
|
/// the value is represented as layoutable content in a reasonable way.
|
||||||
pub fn into_commands(self) -> Commands {
|
pub fn into_commands(self) -> Vec<Command> {
|
||||||
match self.v {
|
match self.v {
|
||||||
// Pass-through.
|
// Pass-through.
|
||||||
Value::Commands(commands) => commands,
|
Value::Commands(commands) => commands,
|
||||||
|
@ -138,7 +138,7 @@ impl<'a, W: Write> PdfExporter<'a, W> {
|
|||||||
let mut face = FaceId::MAX;
|
let mut face = FaceId::MAX;
|
||||||
let mut size = 0.0;
|
let mut size = 0.0;
|
||||||
|
|
||||||
for (pos, element) in &page.elements.0 {
|
for (pos, element) in &page.elements {
|
||||||
match element {
|
match element {
|
||||||
LayoutElement::Text(shaped) => {
|
LayoutElement::Text(shaped) => {
|
||||||
if shaped.face != face || shaped.size != size {
|
if shaped.face != face || shaped.size != size {
|
||||||
@ -287,7 +287,7 @@ fn remap_fonts(layouts: &[BoxLayout]) -> (HashMap<FaceId, usize>, Vec<FaceId>) {
|
|||||||
// We want to find out which font faces are used at all. To do that, look at
|
// We want to find out which font faces are used at all. To do that, look at
|
||||||
// each text element to find out which face is uses.
|
// each text element to find out which face is uses.
|
||||||
for layout in layouts {
|
for layout in layouts {
|
||||||
for (_, element) in &layout.elements.0 {
|
for (_, element) in &layout.elements {
|
||||||
let LayoutElement::Text(shaped) = element;
|
let LayoutElement::Text(shaped) = element;
|
||||||
to_pdf.entry(shaped.face).or_insert_with(|| {
|
to_pdf.entry(shaped.face).or_insert_with(|| {
|
||||||
let next_id = to_layout.len();
|
let next_id = to_layout.len();
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
//! Basic building blocks of layouts.
|
|
||||||
|
|
||||||
use std::fmt::{self, Debug, Formatter};
|
|
||||||
|
|
||||||
use fontdock::FaceId;
|
|
||||||
use ttf_parser::GlyphId;
|
|
||||||
|
|
||||||
use crate::geom::Point;
|
|
||||||
|
|
||||||
/// A collection of absolutely positioned layout elements.
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq)]
|
|
||||||
pub struct LayoutElements(pub Vec<(Point, LayoutElement)>);
|
|
||||||
|
|
||||||
impl LayoutElements {
|
|
||||||
/// Create an new empty collection.
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self(vec![])
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add an element at a position.
|
|
||||||
pub fn push(&mut self, pos: Point, element: LayoutElement) {
|
|
||||||
self.0.push((pos, element));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add all elements of another collection, placing them relative to the
|
|
||||||
/// given position.
|
|
||||||
pub fn push_elements(&mut self, pos: Point, more: Self) {
|
|
||||||
for (subpos, element) in more.0 {
|
|
||||||
self.0.push((pos + subpos.to_vec2(), element));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A layout element, the basic building block layouts are composed of.
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum LayoutElement {
|
|
||||||
Text(Shaped),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A shaped run of text.
|
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
pub struct Shaped {
|
|
||||||
/// The shaped text.
|
|
||||||
pub text: String,
|
|
||||||
/// The font face the text was shaped with.
|
|
||||||
pub face: FaceId,
|
|
||||||
/// The shaped glyphs.
|
|
||||||
pub glyphs: Vec<GlyphId>,
|
|
||||||
/// The horizontal offsets of the glyphs. This is indexed parallel to `glyphs`.
|
|
||||||
/// Vertical offets are not yet supported.
|
|
||||||
pub offsets: Vec<f64>,
|
|
||||||
/// The font size.
|
|
||||||
pub size: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Shaped {
|
|
||||||
/// Create a new shape run with empty `text`, `glyphs` and `offsets`.
|
|
||||||
pub fn new(face: FaceId, size: f64) -> Self {
|
|
||||||
Self {
|
|
||||||
text: String::new(),
|
|
||||||
face,
|
|
||||||
glyphs: vec![],
|
|
||||||
offsets: vec![],
|
|
||||||
size,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for Shaped {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
write!(f, "Shaped({})", self.text)
|
|
||||||
}
|
|
||||||
}
|
|
@ -22,7 +22,7 @@ pub struct LineLayouter {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LineContext {
|
pub struct LineContext {
|
||||||
/// The spaces to layout into.
|
/// The spaces to layout into.
|
||||||
pub spaces: LayoutSpaces,
|
pub spaces: Vec<LayoutSpace>,
|
||||||
/// The initial layouting system, which can be updated through `set_sys`.
|
/// The initial layouting system, which can be updated through `set_sys`.
|
||||||
pub sys: LayoutSystem,
|
pub sys: LayoutSystem,
|
||||||
/// The alignment of the _resulting_ layout. This does not effect the line
|
/// The alignment of the _resulting_ layout. This does not effect the line
|
||||||
@ -132,15 +132,6 @@ impl LineLayouter {
|
|||||||
self.run.last_spacing = LastSpacing::None;
|
self.run.last_spacing = LastSpacing::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add multiple layouts.
|
|
||||||
///
|
|
||||||
/// This is equivalent to calling `add` repeatedly for each layout.
|
|
||||||
pub fn add_multiple(&mut self, layouts: MultiLayout) {
|
|
||||||
for layout in layouts {
|
|
||||||
self.add(layout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The remaining usable size of the line.
|
/// The remaining usable size of the line.
|
||||||
///
|
///
|
||||||
/// This specifies how much more would fit before a line break would be
|
/// This specifies how much more would fit before a line break would be
|
||||||
@ -201,7 +192,7 @@ impl LineLayouter {
|
|||||||
/// If `replace_empty` is true, the current space is replaced if there are
|
/// If `replace_empty` is true, the current space is replaced if there are
|
||||||
/// no boxes laid out into it yet. Otherwise, the followup spaces are
|
/// no boxes laid out into it yet. Otherwise, the followup spaces are
|
||||||
/// replaced.
|
/// replaced.
|
||||||
pub fn set_spaces(&mut self, spaces: LayoutSpaces, replace_empty: bool) {
|
pub fn set_spaces(&mut self, spaces: Vec<LayoutSpace>, replace_empty: bool) {
|
||||||
self.stack.set_spaces(spaces, replace_empty && self.line_is_empty());
|
self.stack.set_spaces(spaces, replace_empty && self.line_is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +203,7 @@ impl LineLayouter {
|
|||||||
|
|
||||||
/// The remaining inner spaces. If something is laid out into these spaces,
|
/// The remaining inner spaces. If something is laid out into these spaces,
|
||||||
/// it will fit into this layouter's underlying stack.
|
/// it will fit into this layouter's underlying stack.
|
||||||
pub fn remaining(&self) -> LayoutSpaces {
|
pub fn remaining(&self) -> Vec<LayoutSpace> {
|
||||||
let mut spaces = self.stack.remaining();
|
let mut spaces = self.stack.remaining();
|
||||||
*spaces[0].size.secondary_mut(self.ctx.sys) -= self.run.size.height;
|
*spaces[0].size.secondary_mut(self.ctx.sys) -= self.run.size.height;
|
||||||
spaces
|
spaces
|
||||||
@ -224,7 +215,7 @@ impl LineLayouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish everything up and return the final collection of boxes.
|
/// Finish everything up and return the final collection of boxes.
|
||||||
pub fn finish(mut self) -> MultiLayout {
|
pub fn finish(mut self) -> Vec<BoxLayout> {
|
||||||
self.finish_line_if_not_empty();
|
self.finish_line_if_not_empty();
|
||||||
self.stack.finish()
|
self.stack.finish()
|
||||||
}
|
}
|
||||||
@ -239,27 +230,25 @@ impl LineLayouter {
|
|||||||
|
|
||||||
/// Finish the active line and start a new one.
|
/// Finish the active line and start a new one.
|
||||||
pub fn finish_line(&mut self) {
|
pub fn finish_line(&mut self) {
|
||||||
let mut elements = LayoutElements::new();
|
let mut layout = BoxLayout::new(
|
||||||
|
self.run.size.specialized(self.ctx.sys),
|
||||||
|
self.run.align.unwrap_or_default(),
|
||||||
|
);
|
||||||
|
|
||||||
let layouts = std::mem::take(&mut self.run.layouts);
|
let layouts = std::mem::take(&mut self.run.layouts);
|
||||||
for (offset, layout) in layouts {
|
for (offset, child) in layouts {
|
||||||
let x = match self.ctx.sys.primary.is_positive() {
|
let x = match self.ctx.sys.primary.is_positive() {
|
||||||
true => offset,
|
true => offset,
|
||||||
false => self.run.size.width - offset - layout.size.primary(self.ctx.sys),
|
false => self.run.size.width - offset - child.size.primary(self.ctx.sys),
|
||||||
};
|
};
|
||||||
|
|
||||||
let pos = Point::new(x, 0.0);
|
let pos = Point::new(x, 0.0);
|
||||||
elements.push_elements(pos, layout.elements);
|
layout.push_layout(pos, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stack.add(BoxLayout {
|
self.stack.add(layout);
|
||||||
size: self.run.size.specialized(self.ctx.sys),
|
|
||||||
align: self.run.align.unwrap_or(LayoutAlign::START),
|
|
||||||
elements,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.run = LineRun::new();
|
self.run = LineRun::new();
|
||||||
|
|
||||||
self.stack.add_spacing(self.ctx.line_spacing, SpacingKind::LINE);
|
self.stack.add_spacing(self.ctx.line_spacing, SpacingKind::LINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
//! Layouting of syntax trees into box layouts.
|
//! Layouting of syntax trees.
|
||||||
|
|
||||||
pub mod primitive;
|
pub mod primitive;
|
||||||
|
|
||||||
mod elements;
|
|
||||||
mod line;
|
mod line;
|
||||||
mod stack;
|
mod stack;
|
||||||
mod tree;
|
mod tree;
|
||||||
|
|
||||||
pub use elements::*;
|
|
||||||
pub use line::*;
|
pub use line::*;
|
||||||
pub use primitive::*;
|
pub use primitive::*;
|
||||||
pub use stack::*;
|
pub use stack::*;
|
||||||
@ -17,6 +15,7 @@ use crate::geom::{Insets, Point, Rect, RectExt, Sides, Size, SizeExt};
|
|||||||
|
|
||||||
use crate::eval::{PageState, State, TextState};
|
use crate::eval::{PageState, State, TextState};
|
||||||
use crate::font::SharedFontLoader;
|
use crate::font::SharedFontLoader;
|
||||||
|
use crate::shaping::Shaped;
|
||||||
use crate::syntax::SynTree;
|
use crate::syntax::SynTree;
|
||||||
use crate::{Feedback, Pass};
|
use crate::{Feedback, Pass};
|
||||||
|
|
||||||
@ -25,7 +24,7 @@ pub async fn layout(
|
|||||||
tree: &SynTree,
|
tree: &SynTree,
|
||||||
state: State,
|
state: State,
|
||||||
loader: SharedFontLoader,
|
loader: SharedFontLoader,
|
||||||
) -> Pass<MultiLayout> {
|
) -> Pass<Vec<BoxLayout>> {
|
||||||
let space = LayoutSpace {
|
let space = LayoutSpace {
|
||||||
size: state.page.size,
|
size: state.page.size,
|
||||||
insets: state.page.insets(),
|
insets: state.page.insets(),
|
||||||
@ -51,9 +50,6 @@ pub async fn layout(
|
|||||||
Pass::new(layouts, ctx.f)
|
Pass::new(layouts, ctx.f)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A collection of layouts.
|
|
||||||
pub type MultiLayout = Vec<BoxLayout>;
|
|
||||||
|
|
||||||
/// A finished box with content at fixed positions.
|
/// A finished box with content at fixed positions.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct BoxLayout {
|
pub struct BoxLayout {
|
||||||
@ -62,7 +58,34 @@ pub struct BoxLayout {
|
|||||||
/// How to align this box in a parent container.
|
/// How to align this box in a parent container.
|
||||||
pub align: LayoutAlign,
|
pub align: LayoutAlign,
|
||||||
/// The elements composing this layout.
|
/// The elements composing this layout.
|
||||||
pub elements: LayoutElements,
|
pub elements: Vec<(Point, LayoutElement)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BoxLayout {
|
||||||
|
/// Create an new empty collection.
|
||||||
|
pub fn new(size: Size, align: LayoutAlign) -> Self {
|
||||||
|
Self { size, align, elements: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add an element at a position.
|
||||||
|
pub fn push(&mut self, pos: Point, element: LayoutElement) {
|
||||||
|
self.elements.push((pos, element));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add all elements of another collection, placing them relative to the
|
||||||
|
/// given position.
|
||||||
|
pub fn push_layout(&mut self, pos: Point, more: Self) {
|
||||||
|
for (subpos, element) in more.elements {
|
||||||
|
self.push(pos + subpos.to_vec2(), element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A layout element, the basic building block layouts are composed of.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum LayoutElement {
|
||||||
|
/// Shaped text.
|
||||||
|
Text(Shaped),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The context for layouting.
|
/// The context for layouting.
|
||||||
@ -86,15 +109,12 @@ pub struct LayoutConstraints {
|
|||||||
/// The unpadded size of this container (the base 100% for relative sizes).
|
/// The unpadded size of this container (the base 100% for relative sizes).
|
||||||
pub base: Size,
|
pub base: Size,
|
||||||
/// The spaces to layout into.
|
/// The spaces to layout into.
|
||||||
pub spaces: LayoutSpaces,
|
pub spaces: Vec<LayoutSpace>,
|
||||||
/// Whether to spill over into copies of the last space or finish layouting
|
/// Whether to spill over into copies of the last space or finish layouting
|
||||||
/// when the last space is used up.
|
/// when the last space is used up.
|
||||||
pub repeat: bool,
|
pub repeat: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A collection of layout spaces.
|
|
||||||
pub type LayoutSpaces = Vec<LayoutSpace>;
|
|
||||||
|
|
||||||
/// The space into which content is laid out.
|
/// The space into which content is laid out.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct LayoutSpace {
|
pub struct LayoutSpace {
|
||||||
@ -129,9 +149,6 @@ impl LayoutSpace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A sequence of layouting commands.
|
|
||||||
pub type Commands = Vec<Command>;
|
|
||||||
|
|
||||||
/// Commands executable by the layouting engine.
|
/// Commands executable by the layouting engine.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
@ -146,10 +163,6 @@ pub enum Command {
|
|||||||
|
|
||||||
/// Add a finished layout.
|
/// Add a finished layout.
|
||||||
Add(BoxLayout),
|
Add(BoxLayout),
|
||||||
/// Add multiple layouts, one after another. This is equivalent to multiple
|
|
||||||
/// `Add` commands.
|
|
||||||
AddMultiple(MultiLayout),
|
|
||||||
|
|
||||||
/// Add spacing of the given kind along the primary or secondary axis. The
|
/// Add spacing of the given kind along the primary or secondary axis. The
|
||||||
/// kind defines how the spacing interacts with surrounding spacing.
|
/// kind defines how the spacing interacts with surrounding spacing.
|
||||||
AddSpacing(f64, SpacingKind, GenAxis),
|
AddSpacing(f64, SpacingKind, GenAxis),
|
||||||
|
@ -17,12 +17,10 @@ impl Default for LayoutSystem {
|
|||||||
/// Specifies where to align a layout in a parent container.
|
/// Specifies where to align a layout in a parent container.
|
||||||
pub type LayoutAlign = Gen2<GenAlign>;
|
pub type LayoutAlign = Gen2<GenAlign>;
|
||||||
|
|
||||||
impl LayoutAlign {
|
impl Default for LayoutAlign {
|
||||||
/// The layout alignment that has both components set to `Start`.
|
fn default() -> Self {
|
||||||
pub const START: Self = Self {
|
Self::new(GenAlign::Start, GenAlign::Start)
|
||||||
primary: GenAlign::Start,
|
}
|
||||||
secondary: GenAlign::Start,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether to expand a layout to an area's full size or shrink it to fit its content.
|
/// Whether to expand a layout to an area's full size or shrink it to fit its content.
|
||||||
|
@ -24,7 +24,7 @@ use super::*;
|
|||||||
/// Performs the stack layouting.
|
/// Performs the stack layouting.
|
||||||
pub struct StackLayouter {
|
pub struct StackLayouter {
|
||||||
ctx: StackContext,
|
ctx: StackContext,
|
||||||
layouts: MultiLayout,
|
layouts: Vec<BoxLayout>,
|
||||||
/// The in-progress space.
|
/// The in-progress space.
|
||||||
space: Space,
|
space: Space,
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ pub struct StackLayouter {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct StackContext {
|
pub struct StackContext {
|
||||||
/// The spaces to layout into.
|
/// The spaces to layout into.
|
||||||
pub spaces: LayoutSpaces,
|
pub spaces: Vec<LayoutSpace>,
|
||||||
/// The initial layouting system, which can be updated through `set_sys`.
|
/// The initial layouting system, which can be updated through `set_sys`.
|
||||||
pub sys: LayoutSystem,
|
pub sys: LayoutSystem,
|
||||||
/// The alignment of the _resulting_ layout. This does not effect the line
|
/// The alignment of the _resulting_ layout. This does not effect the line
|
||||||
@ -75,7 +75,7 @@ impl StackLayouter {
|
|||||||
let space = ctx.spaces[0];
|
let space = ctx.spaces[0];
|
||||||
Self {
|
Self {
|
||||||
ctx,
|
ctx,
|
||||||
layouts: MultiLayout::new(),
|
layouts: vec![],
|
||||||
space: Space::new(0, true, space.usable()),
|
space: Space::new(0, true, space.usable()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,15 +110,6 @@ impl StackLayouter {
|
|||||||
self.space.last_spacing = LastSpacing::None;
|
self.space.last_spacing = LastSpacing::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add multiple layouts to the stack.
|
|
||||||
///
|
|
||||||
/// This is equivalent to calling `add` repeatedly for each layout.
|
|
||||||
pub fn add_multiple(&mut self, layouts: MultiLayout) {
|
|
||||||
for layout in layouts {
|
|
||||||
self.add(layout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add spacing to the stack.
|
/// Add spacing to the stack.
|
||||||
pub fn add_spacing(&mut self, mut spacing: f64, kind: SpacingKind) {
|
pub fn add_spacing(&mut self, mut spacing: f64, kind: SpacingKind) {
|
||||||
match kind {
|
match kind {
|
||||||
@ -129,11 +120,13 @@ impl StackLayouter {
|
|||||||
let size = Size::new(0.0, spacing);
|
let size = Size::new(0.0, spacing);
|
||||||
|
|
||||||
self.update_metrics(size);
|
self.update_metrics(size);
|
||||||
self.space.layouts.push((self.ctx.sys, BoxLayout {
|
self.space.layouts.push((
|
||||||
size: size.specialized(self.ctx.sys),
|
self.ctx.sys,
|
||||||
align: LayoutAlign::START,
|
BoxLayout::new(
|
||||||
elements: LayoutElements::new(),
|
size.specialized(self.ctx.sys),
|
||||||
}));
|
LayoutAlign::default(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
self.space.last_spacing = LastSpacing::Hard;
|
self.space.last_spacing = LastSpacing::Hard;
|
||||||
}
|
}
|
||||||
@ -208,7 +201,7 @@ impl StackLayouter {
|
|||||||
/// If `replace_empty` is true, the current space is replaced if there are
|
/// If `replace_empty` is true, the current space is replaced if there are
|
||||||
/// no boxes laid out into it yet. Otherwise, the followup spaces are
|
/// no boxes laid out into it yet. Otherwise, the followup spaces are
|
||||||
/// replaced.
|
/// replaced.
|
||||||
pub fn set_spaces(&mut self, spaces: LayoutSpaces, replace_empty: bool) {
|
pub fn set_spaces(&mut self, spaces: Vec<LayoutSpace>, replace_empty: bool) {
|
||||||
if replace_empty && self.space_is_empty() {
|
if replace_empty && self.space_is_empty() {
|
||||||
self.ctx.spaces = spaces;
|
self.ctx.spaces = spaces;
|
||||||
self.start_space(0, self.space.hard);
|
self.start_space(0, self.space.hard);
|
||||||
@ -233,7 +226,7 @@ impl StackLayouter {
|
|||||||
|
|
||||||
/// The remaining inner spaces. If something is laid out into these spaces,
|
/// The remaining inner spaces. If something is laid out into these spaces,
|
||||||
/// it will fit into this stack.
|
/// it will fit into this stack.
|
||||||
pub fn remaining(&self) -> LayoutSpaces {
|
pub fn remaining(&self) -> Vec<LayoutSpace> {
|
||||||
let size = self.usable();
|
let size = self.usable();
|
||||||
|
|
||||||
let mut spaces = vec![LayoutSpace {
|
let mut spaces = vec![LayoutSpace {
|
||||||
@ -267,7 +260,7 @@ impl StackLayouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish everything up and return the final collection of boxes.
|
/// Finish everything up and return the final collection of boxes.
|
||||||
pub fn finish(mut self) -> MultiLayout {
|
pub fn finish(mut self) -> Vec<BoxLayout> {
|
||||||
if self.space.hard || !self.space_is_empty() {
|
if self.space.hard || !self.space_is_empty() {
|
||||||
self.finish_space(false);
|
self.finish_space(false);
|
||||||
}
|
}
|
||||||
@ -360,12 +353,12 @@ impl StackLayouter {
|
|||||||
// Step 4: Align each layout in its bounding box and collect everything
|
// Step 4: Align each layout in its bounding box and collect everything
|
||||||
// into a single finished layout.
|
// into a single finished layout.
|
||||||
|
|
||||||
let mut elements = LayoutElements::new();
|
let mut layout = BoxLayout::new(size, self.ctx.align);
|
||||||
|
|
||||||
let layouts = std::mem::take(&mut self.space.layouts);
|
let layouts = std::mem::take(&mut self.space.layouts);
|
||||||
for ((sys, layout), bound) in layouts.into_iter().zip(bounds) {
|
for ((sys, child), bound) in layouts.into_iter().zip(bounds) {
|
||||||
let size = layout.size.specialized(sys);
|
let size = child.size.specialized(sys);
|
||||||
let align = layout.align;
|
let align = child.align;
|
||||||
|
|
||||||
// The space in which this layout is aligned is given by the
|
// The space in which this layout is aligned is given by the
|
||||||
// distances between the borders of its bounding box.
|
// distances between the borders of its bounding box.
|
||||||
@ -373,10 +366,10 @@ impl StackLayouter {
|
|||||||
let local = usable.anchor(align, sys) - size.anchor(align, sys);
|
let local = usable.anchor(align, sys) - size.anchor(align, sys);
|
||||||
let pos = bound.origin() + local.to_size().specialized(sys).to_vec2();
|
let pos = bound.origin() + local.to_size().specialized(sys).to_vec2();
|
||||||
|
|
||||||
elements.push_elements(pos, layout.elements);
|
layout.push_layout(pos, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.layouts.push(BoxLayout { size, align: self.ctx.align, elements });
|
self.layouts.push(layout);
|
||||||
|
|
||||||
// ------------------------------------------------------------------ //
|
// ------------------------------------------------------------------ //
|
||||||
// Step 5: Start the next space.
|
// Step 5: Start the next space.
|
||||||
|
@ -8,7 +8,7 @@ use crate::syntax::{
|
|||||||
use crate::DynFuture;
|
use crate::DynFuture;
|
||||||
|
|
||||||
/// Layout a syntax tree in a given context.
|
/// Layout a syntax tree in a given context.
|
||||||
pub async fn layout_tree(tree: &SynTree, ctx: &mut LayoutContext) -> MultiLayout {
|
pub async fn layout_tree(tree: &SynTree, ctx: &mut LayoutContext) -> Vec<BoxLayout> {
|
||||||
let mut layouter = TreeLayouter::new(ctx);
|
let mut layouter = TreeLayouter::new(ctx);
|
||||||
layouter.layout_tree(tree).await;
|
layouter.layout_tree(tree).await;
|
||||||
layouter.finish()
|
layouter.finish()
|
||||||
@ -38,7 +38,7 @@ impl<'a> TreeLayouter<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(self) -> MultiLayout {
|
fn finish(self) -> Vec<BoxLayout> {
|
||||||
self.layouter.finish()
|
self.layouter.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +175,6 @@ impl<'a> TreeLayouter<'a> {
|
|||||||
LayoutSyntaxTree(tree) => self.layout_tree(&tree).await,
|
LayoutSyntaxTree(tree) => self.layout_tree(&tree).await,
|
||||||
|
|
||||||
Add(layout) => self.layouter.add(layout),
|
Add(layout) => self.layouter.add(layout),
|
||||||
AddMultiple(layouts) => self.layouter.add_multiple(layouts),
|
|
||||||
AddSpacing(space, kind, axis) => match axis {
|
AddSpacing(space, kind, axis) => match axis {
|
||||||
GenAxis::Primary => self.layouter.add_primary_spacing(space, kind),
|
GenAxis::Primary => self.layouter.add_primary_spacing(space, kind),
|
||||||
GenAxis::Secondary => self.layouter.add_secondary_spacing(space, kind),
|
GenAxis::Secondary => self.layouter.add_secondary_spacing(space, kind),
|
||||||
|
13
src/lib.rs
13
src/lib.rs
@ -43,9 +43,9 @@ use std::future::Future;
|
|||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::eval::{State, Value};
|
use crate::eval::State;
|
||||||
use crate::font::SharedFontLoader;
|
use crate::font::SharedFontLoader;
|
||||||
use crate::layout::{Commands, MultiLayout};
|
use crate::layout::BoxLayout;
|
||||||
use crate::syntax::{Decoration, Offset, Pos, SpanVec};
|
use crate::syntax::{Decoration, Offset, Pos, SpanVec};
|
||||||
|
|
||||||
/// Process source code directly into a collection of layouts.
|
/// Process source code directly into a collection of layouts.
|
||||||
@ -53,7 +53,7 @@ pub async fn typeset(
|
|||||||
src: &str,
|
src: &str,
|
||||||
state: State,
|
state: State,
|
||||||
loader: SharedFontLoader,
|
loader: SharedFontLoader,
|
||||||
) -> Pass<MultiLayout> {
|
) -> Pass<Vec<BoxLayout>> {
|
||||||
let parsed = parse::parse(src);
|
let parsed = parse::parse(src);
|
||||||
let layouted = layout::layout(&parsed.output, state, loader).await;
|
let layouted = layout::layout(&parsed.output, state, loader).await;
|
||||||
let feedback = Feedback::merge(parsed.feedback, layouted.feedback);
|
let feedback = Feedback::merge(parsed.feedback, layouted.feedback);
|
||||||
@ -93,13 +93,6 @@ impl<T> Pass<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pass<Value> {
|
|
||||||
/// Create a new pass with a list of layouting commands.
|
|
||||||
pub fn commands(commands: Commands, feedback: Feedback) -> Self {
|
|
||||||
Pass::new(Value::Commands(commands), feedback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Diagnostic and semantic syntax highlighting data.
|
/// Diagnostic and semantic syntax highlighting data.
|
||||||
#[derive(Debug, Default, Clone, Eq, PartialEq)]
|
#[derive(Debug, Default, Clone, Eq, PartialEq)]
|
||||||
pub struct Feedback {
|
pub struct Feedback {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
pub use crate::eval::{Dict, Value, ValueDict};
|
pub use crate::eval::{Dict, Value, ValueDict};
|
||||||
pub use crate::layout::primitive::*;
|
pub use crate::layout::primitive::*;
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use crate::layout::{layout_tree, Command, Commands, LayoutContext};
|
pub use crate::layout::{layout_tree, Command, LayoutContext};
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use crate::syntax::{Span, Spanned, SynTree};
|
pub use crate::syntax::{Span, Spanned, SynTree};
|
||||||
pub use crate::{Feedback, Pass};
|
pub use crate::{Feedback, Pass};
|
||||||
|
@ -4,15 +4,17 @@
|
|||||||
//! font for each individual character. When the direction is right-to-left, the
|
//! font for each individual character. When the direction is right-to-left, the
|
||||||
//! word is spelled backwards. Vertical shaping is not supported.
|
//! word is spelled backwards. Vertical shaping is not supported.
|
||||||
|
|
||||||
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
|
||||||
use fontdock::{FaceId, FaceQuery, FallbackTree, FontStyle, FontVariant};
|
use fontdock::{FaceId, FaceQuery, FallbackTree, FontStyle, FontVariant};
|
||||||
use ttf_parser::GlyphId;
|
use ttf_parser::GlyphId;
|
||||||
|
|
||||||
use crate::eval::TextState;
|
use crate::eval::TextState;
|
||||||
use crate::font::FontLoader;
|
use crate::font::FontLoader;
|
||||||
use crate::geom::{Point, Size};
|
use crate::geom::{Point, Size};
|
||||||
use crate::layout::{BoxLayout, Dir, LayoutAlign, LayoutElement, LayoutElements, Shaped};
|
use crate::layout::{BoxLayout, Dir, LayoutAlign, LayoutElement};
|
||||||
|
|
||||||
/// Shape text into a box.
|
/// Shape text into a box containing shaped runs.
|
||||||
pub async fn shape(
|
pub async fn shape(
|
||||||
text: &str,
|
text: &str,
|
||||||
dir: Dir,
|
dir: Dir,
|
||||||
@ -23,6 +25,51 @@ pub async fn shape(
|
|||||||
Shaper::new(text, dir, align, state, loader).shape().await
|
Shaper::new(text, dir, align, state, loader).shape().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A shaped run of text.
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub struct Shaped {
|
||||||
|
/// The shaped text.
|
||||||
|
pub text: String,
|
||||||
|
/// The font face the text was shaped with.
|
||||||
|
pub face: FaceId,
|
||||||
|
/// The shaped glyphs.
|
||||||
|
pub glyphs: Vec<GlyphId>,
|
||||||
|
/// The horizontal offsets of the glyphs. This is indexed parallel to `glyphs`.
|
||||||
|
/// Vertical offets are not yet supported.
|
||||||
|
pub offsets: Vec<f64>,
|
||||||
|
/// The font size.
|
||||||
|
pub size: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shaped {
|
||||||
|
/// Create a new shape run with empty `text`, `glyphs` and `offsets`.
|
||||||
|
pub fn new(face: FaceId, size: f64) -> Self {
|
||||||
|
Self {
|
||||||
|
text: String::new(),
|
||||||
|
face,
|
||||||
|
glyphs: vec![],
|
||||||
|
offsets: vec![],
|
||||||
|
size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Shaped {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(f, "Shaped({})", self.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Performs super-basic text shaping.
|
/// Performs super-basic text shaping.
|
||||||
struct Shaper<'a> {
|
struct Shaper<'a> {
|
||||||
text: &'a str,
|
text: &'a str,
|
||||||
@ -64,11 +111,7 @@ impl<'a> Shaper<'a> {
|
|||||||
fallback: &state.fallback,
|
fallback: &state.fallback,
|
||||||
loader,
|
loader,
|
||||||
shaped: Shaped::new(FaceId::MAX, state.font_size()),
|
shaped: Shaped::new(FaceId::MAX, state.font_size()),
|
||||||
layout: BoxLayout {
|
layout: BoxLayout::new(Size::new(0.0, state.font_size()), align),
|
||||||
size: Size::new(0.0, state.font_size()),
|
|
||||||
align,
|
|
||||||
elements: LayoutElements::new(),
|
|
||||||
},
|
|
||||||
offset: 0.0,
|
offset: 0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,7 +131,7 @@ impl<'a> Shaper<'a> {
|
|||||||
// Flush the last buffered parts of the word.
|
// Flush the last buffered parts of the word.
|
||||||
if !self.shaped.text.is_empty() {
|
if !self.shaped.text.is_empty() {
|
||||||
let pos = Point::new(self.offset, 0.0);
|
let pos = Point::new(self.offset, 0.0);
|
||||||
self.layout.elements.push(pos, LayoutElement::Text(self.shaped));
|
self.layout.push(pos, LayoutElement::Text(self.shaped));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.layout
|
self.layout
|
||||||
@ -111,7 +154,7 @@ impl<'a> Shaper<'a> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let pos = Point::new(self.offset, 0.0);
|
let pos = Point::new(self.offset, 0.0);
|
||||||
self.layout.elements.push(pos, LayoutElement::Text(shaped));
|
self.layout.push(pos, LayoutElement::Text(shaped));
|
||||||
self.offset = self.layout.size.width;
|
self.offset = self.layout.size.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,8 +15,9 @@ use typstc::eval::State;
|
|||||||
use typstc::export::pdf;
|
use typstc::export::pdf;
|
||||||
use typstc::font::{FontLoader, SharedFontLoader};
|
use typstc::font::{FontLoader, SharedFontLoader};
|
||||||
use typstc::geom::{Point, Vec2};
|
use typstc::geom::{Point, Vec2};
|
||||||
use typstc::layout::{LayoutElement, MultiLayout, Shaped};
|
use typstc::layout::{BoxLayout, LayoutElement};
|
||||||
use typstc::parse::LineMap;
|
use typstc::parse::LineMap;
|
||||||
|
use typstc::shaping::Shaped;
|
||||||
use typstc::{typeset, Feedback, Pass};
|
use typstc::{typeset, Feedback, Pass};
|
||||||
|
|
||||||
const TEST_DIR: &str = "tests";
|
const TEST_DIR: &str = "tests";
|
||||||
@ -136,7 +137,7 @@ impl TestFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(layouts: &MultiLayout, loader: &FontLoader, scale: f64) -> DrawTarget {
|
fn render(layouts: &[BoxLayout], loader: &FontLoader, scale: f64) -> DrawTarget {
|
||||||
let pad = scale * 10.0;
|
let pad = scale * 10.0;
|
||||||
let width = 2.0 * pad
|
let width = 2.0 * pad
|
||||||
+ layouts
|
+ layouts
|
||||||
@ -167,7 +168,7 @@ fn render(layouts: &MultiLayout, loader: &FontLoader, scale: f64) -> DrawTarget
|
|||||||
&Default::default(),
|
&Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
for &(pos, ref element) in &layout.elements.0 {
|
for (pos, element) in &layout.elements {
|
||||||
match element {
|
match element {
|
||||||
LayoutElement::Text(shaped) => render_shaped(
|
LayoutElement::Text(shaped) => render_shaped(
|
||||||
&mut surface,
|
&mut surface,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user