mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
151 lines
4.0 KiB
Rust
151 lines
4.0 KiB
Rust
#[path = "box.rs"]
|
|
mod box_;
|
|
mod collect;
|
|
mod deco;
|
|
mod finalize;
|
|
mod line;
|
|
mod linebreak;
|
|
mod prepare;
|
|
mod shaping;
|
|
|
|
pub use self::box_::layout_box;
|
|
|
|
use comemo::{Track, Tracked, TrackedMut};
|
|
use typst_library::diag::SourceResult;
|
|
use typst_library::engine::{Engine, Route, Sink, Traced};
|
|
use typst_library::foundations::{Packed, StyleChain};
|
|
use typst_library::introspection::{Introspector, Locator, LocatorLink, SplitLocator};
|
|
use typst_library::layout::{Fragment, Size};
|
|
use typst_library::model::ParElem;
|
|
use typst_library::routines::{Arenas, Pair, RealizationKind, Routines};
|
|
use typst_library::World;
|
|
|
|
use self::collect::{collect, Item, Segment, SpanMapper};
|
|
use self::deco::decorate;
|
|
use self::finalize::finalize;
|
|
use self::line::{apply_baseline_shift, commit, line, Line};
|
|
use self::linebreak::{linebreak, Breakpoint};
|
|
use self::prepare::{prepare, Preparation};
|
|
use self::shaping::{
|
|
cjk_punct_style, is_of_cj_script, shape_range, ShapedGlyph, ShapedText,
|
|
BEGIN_PUNCT_PAT, END_PUNCT_PAT,
|
|
};
|
|
|
|
/// Range of a substring of text.
|
|
type Range = std::ops::Range<usize>;
|
|
|
|
/// Layouts the paragraph.
|
|
pub fn layout_par(
|
|
elem: &Packed<ParElem>,
|
|
engine: &mut Engine,
|
|
locator: Locator,
|
|
styles: StyleChain,
|
|
region: Size,
|
|
expand: bool,
|
|
situation: ParSituation,
|
|
) -> SourceResult<Fragment> {
|
|
layout_par_impl(
|
|
elem,
|
|
engine.routines,
|
|
engine.world,
|
|
engine.introspector,
|
|
engine.traced,
|
|
TrackedMut::reborrow_mut(&mut engine.sink),
|
|
engine.route.track(),
|
|
locator.track(),
|
|
styles,
|
|
region,
|
|
expand,
|
|
situation,
|
|
)
|
|
}
|
|
|
|
/// The internal, memoized implementation of `layout_par`.
|
|
#[comemo::memoize]
|
|
#[allow(clippy::too_many_arguments)]
|
|
fn layout_par_impl(
|
|
elem: &Packed<ParElem>,
|
|
routines: &Routines,
|
|
world: Tracked<dyn World + '_>,
|
|
introspector: Tracked<Introspector>,
|
|
traced: Tracked<Traced>,
|
|
sink: TrackedMut<Sink>,
|
|
route: Tracked<Route>,
|
|
locator: Tracked<Locator>,
|
|
styles: StyleChain,
|
|
region: Size,
|
|
expand: bool,
|
|
situation: ParSituation,
|
|
) -> SourceResult<Fragment> {
|
|
let link = LocatorLink::new(locator);
|
|
let mut locator = Locator::link(&link).split();
|
|
let mut engine = Engine {
|
|
routines,
|
|
world,
|
|
introspector,
|
|
traced,
|
|
sink,
|
|
route: Route::extend(route),
|
|
};
|
|
|
|
let arenas = Arenas::default();
|
|
let children = (engine.routines.realize)(
|
|
RealizationKind::LayoutPar,
|
|
&mut engine,
|
|
&mut locator,
|
|
&arenas,
|
|
&elem.body,
|
|
styles,
|
|
)?;
|
|
|
|
layout_inline(
|
|
&mut engine,
|
|
&children,
|
|
&mut locator,
|
|
styles,
|
|
region,
|
|
expand,
|
|
Some(situation),
|
|
)
|
|
}
|
|
|
|
/// Lays out realized content with inline layout.
|
|
#[allow(clippy::too_many_arguments)]
|
|
pub fn layout_inline<'a>(
|
|
engine: &mut Engine,
|
|
children: &[Pair<'a>],
|
|
locator: &mut SplitLocator<'a>,
|
|
styles: StyleChain<'a>,
|
|
region: Size,
|
|
expand: bool,
|
|
par: Option<ParSituation>,
|
|
) -> SourceResult<Fragment> {
|
|
// Collect all text into one string for BiDi analysis.
|
|
let (text, segments, spans) =
|
|
collect(children, engine, locator, styles, region, par)?;
|
|
|
|
// Perform BiDi analysis and performs some preparation steps before we
|
|
// proceed to line breaking.
|
|
let p = prepare(engine, children, &text, segments, spans, styles, par)?;
|
|
|
|
// Break the text into lines.
|
|
let lines = linebreak(engine, &p, region.x - p.hang);
|
|
|
|
// Turn the selected lines into frames.
|
|
finalize(engine, &p, &lines, styles, region, expand, locator)
|
|
}
|
|
|
|
/// Distinguishes between a few different kinds of paragraphs.
|
|
///
|
|
/// In the form `Option<ParSituation>`, `None` implies that we are creating an
|
|
/// inline layout that isn't a semantic paragraph.
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
|
pub enum ParSituation {
|
|
/// The paragraph is the first thing in the flow.
|
|
First,
|
|
/// The paragraph follows another paragraph.
|
|
Consecutive,
|
|
/// Any other kind of paragraph.
|
|
Other,
|
|
}
|