This commit is contained in:
Laurenz Stampfl 2024-12-17 17:53:09 +01:00
parent 0c4cffb475
commit 59a1bbed55
4 changed files with 55 additions and 68 deletions

View File

@ -40,9 +40,7 @@ pub(crate) struct State {
impl State { impl State {
/// Creates a new, clean state for a given `size`. /// Creates a new, clean state for a given `size`.
fn new( fn new(size: Size) -> Self {
size: Size,
) -> Self {
Self { Self {
transform: Transform::identity(), transform: Transform::identity(),
container_transform: Transform::identity(), container_transform: Transform::identity(),
@ -59,14 +57,16 @@ impl State {
self.transform = self.transform.pre_concat(transform); self.transform = self.transform.pre_concat(transform);
} }
/// Creates the [`Transforms`] structure for the current item. pub(crate) fn transform(&self) -> Transform {
pub(crate) fn transforms(&self, size: Size) -> Transforms { self.transform
Transforms { }
transform_chain_: self.transform,
container_transform_chain: self.container_transform, pub(crate) fn container_transform(&self) -> Transform {
container_size: self.container_size, self.container_transform
size, }
}
pub(crate) fn container_size(&self) -> Size {
self.container_size
} }
} }
@ -100,19 +100,6 @@ impl FrameContext {
} }
} }
/// Subset of the state used to calculate the transform of gradients and patterns.
#[derive(Debug, Clone, Copy)]
pub(super) struct Transforms {
/// The full transform chain.
pub(crate) transform_chain_: Transform,
/// The transform of first hard frame in the hierarchy.
pub(crate) container_transform_chain: Transform,
/// The size of the first hard frame in the hierarchy.
pub(crate) container_size: Size,
/// The size of the item.
pub(crate) size: Size,
}
pub(crate) struct GlobalContext<'a> { pub(crate) struct GlobalContext<'a> {
/// Cache the conversion between krilla and Typst fonts (forward and backward). /// Cache the conversion between krilla and Typst fonts (forward and backward).
pub(crate) fonts_forward: HashMap<Font, krilla::font::Font>, pub(crate) fonts_forward: HashMap<Font, krilla::font::Font>,

View File

@ -1,12 +1,12 @@
//! Convert paint types from typst to krilla. //! Convert paint types from typst to krilla.
use crate::krilla::{handle_frame, FrameContext, GlobalContext, Transforms}; use crate::krilla::{handle_frame, FrameContext, GlobalContext, State};
use crate::util::{AbsExt, ColorExt, FillRuleExt, LineCapExt, LineJoinExt, TransformExt}; use crate::util::{AbsExt, ColorExt, FillRuleExt, LineCapExt, LineJoinExt, TransformExt};
use krilla::geom::NormalizedF32; use krilla::geom::NormalizedF32;
use krilla::paint::SpreadMethod; use krilla::paint::SpreadMethod;
use krilla::surface::Surface; use krilla::surface::Surface;
use typst_library::diag::SourceResult; use typst_library::diag::SourceResult;
use typst_library::layout::{Abs, Angle, Quadrant, Ratio, Transform}; use typst_library::layout::{Abs, Angle, Quadrant, Ratio, Size, Transform};
use typst_library::visualize::{ use typst_library::visualize::{
Color, ColorSpace, DashPattern, FillRule, FixedStroke, Gradient, Paint, RatioOrAngle, Color, ColorSpace, DashPattern, FillRule, FixedStroke, Gradient, Paint, RatioOrAngle,
RelativeTo, Tiling, WeightedColor, RelativeTo, Tiling, WeightedColor,
@ -19,9 +19,10 @@ pub(crate) fn convert_fill(
fill_rule_: FillRule, fill_rule_: FillRule,
on_text: bool, on_text: bool,
surface: &mut Surface, surface: &mut Surface,
transforms: Transforms, state: &State,
size: Size,
) -> SourceResult<krilla::path::Fill> { ) -> SourceResult<krilla::path::Fill> {
let (paint, opacity) = convert_paint(gc, paint_, on_text, surface, transforms)?; let (paint, opacity) = convert_paint(gc, paint_, on_text, surface, state, size)?;
Ok(krilla::path::Fill { Ok(krilla::path::Fill {
paint, paint,
@ -35,9 +36,11 @@ pub(crate) fn convert_stroke(
stroke: &FixedStroke, stroke: &FixedStroke,
on_text: bool, on_text: bool,
surface: &mut Surface, surface: &mut Surface,
transforms: Transforms, state: &State,
size: Size,
) -> SourceResult<krilla::path::Stroke> { ) -> SourceResult<krilla::path::Stroke> {
let (paint, opacity) = convert_paint(fc, &stroke.paint, on_text, surface, transforms)?; let (paint, opacity) =
convert_paint(fc, &stroke.paint, on_text, surface, state, size)?;
Ok(krilla::path::Stroke { Ok(krilla::path::Stroke {
paint, paint,
@ -62,12 +65,22 @@ fn convert_paint(
paint: &Paint, paint: &Paint,
on_text: bool, on_text: bool,
surface: &mut Surface, surface: &mut Surface,
transforms: Transforms, state: &State,
mut size: Size,
) -> SourceResult<(krilla::paint::Paint, u8)> { ) -> SourceResult<(krilla::paint::Paint, u8)> {
// Edge cases for strokes.
if size.x.is_zero() {
size.x = Abs::pt(1.0);
}
if size.y.is_zero() {
size.y = Abs::pt(1.0);
}
match paint { match paint {
Paint::Solid(c) => Ok(convert_solid(c)), Paint::Solid(c) => Ok(convert_solid(c)),
Paint::Gradient(g) => Ok(convert_gradient(g, on_text, transforms)), Paint::Gradient(g) => Ok(convert_gradient(g, on_text, state, size)),
Paint::Tiling(p) => convert_pattern(gc, p, on_text, surface, transforms), Paint::Tiling(p) => convert_pattern(gc, p, on_text, surface, state),
} }
} }
@ -86,7 +99,7 @@ fn convert_solid(color: &Color) -> (krilla::paint::Paint, u8) {
components[2], components[2],
components[3], components[3],
) )
.into(), .into(),
// Typst doesn't support alpha on CMYK colors. // Typst doesn't support alpha on CMYK colors.
255, 255,
) )
@ -104,24 +117,15 @@ fn convert_pattern(
pattern: &Tiling, pattern: &Tiling,
on_text: bool, on_text: bool,
surface: &mut Surface, surface: &mut Surface,
mut transforms: Transforms, state: &State,
) -> SourceResult<(krilla::paint::Paint, u8)> { ) -> SourceResult<(krilla::paint::Paint, u8)> {
// Edge cases for strokes.
if transforms.size.x.is_zero() {
transforms.size.x = Abs::pt(1.0);
}
if transforms.size.y.is_zero() {
transforms.size.y = Abs::pt(1.0);
}
let transform = match pattern.unwrap_relative(on_text) { let transform = match pattern.unwrap_relative(on_text) {
RelativeTo::Self_ => Transform::identity(), RelativeTo::Self_ => Transform::identity(),
RelativeTo::Parent => transforms RelativeTo::Parent => state
.transform_chain_ .transform
.invert() .invert()
.unwrap() .unwrap()
.pre_concat(transforms.container_transform_chain), .pre_concat(state.container_transform()),
} }
.to_krilla(); .to_krilla();
@ -144,25 +148,18 @@ fn convert_pattern(
fn convert_gradient( fn convert_gradient(
gradient: &Gradient, gradient: &Gradient,
on_text: bool, on_text: bool,
mut transforms: Transforms, state: &State,
size: Size,
) -> (krilla::paint::Paint, u8) { ) -> (krilla::paint::Paint, u8) {
// Edge cases for strokes.
if transforms.size.x.is_zero() {
transforms.size.x = Abs::pt(1.0);
}
if transforms.size.y.is_zero() {
transforms.size.y = Abs::pt(1.0);
}
let size = match gradient.unwrap_relative(on_text) { let size = match gradient.unwrap_relative(on_text) {
RelativeTo::Self_ => transforms.size, RelativeTo::Self_ => size,
RelativeTo::Parent => transforms.container_size, RelativeTo::Parent => state.container_size(),
}; };
let rotation = gradient.angle().unwrap_or_else(Angle::zero); let rotation = gradient.angle().unwrap_or_else(Angle::zero);
let transform = match gradient.unwrap_relative(on_text) { let transform = match gradient.unwrap_relative(on_text) {
RelativeTo::Self_ => transforms.transform_chain_, RelativeTo::Self_ => state.transform,
RelativeTo::Parent => transforms.container_transform_chain, RelativeTo::Parent => state.container_transform(),
}; };
let angle = rotation; let angle = rotation;
@ -180,7 +177,7 @@ fn convert_gradient(
match &gradient { match &gradient {
Gradient::Linear(linear) => { Gradient::Linear(linear) => {
let actual_transform = let actual_transform =
transforms.transform_chain_.invert().unwrap().pre_concat(transform); state.transform().invert().unwrap().pre_concat(transform);
if let Some((c, t)) = linear.stops.first() { if let Some((c, t)) = linear.stops.first() {
add_single(c, *t); add_single(c, *t);
@ -238,7 +235,7 @@ fn convert_gradient(
} }
Gradient::Radial(radial) => { Gradient::Radial(radial) => {
let actual_transform = let actual_transform =
transforms.transform_chain_.invert().unwrap().pre_concat(transform); state.transform.invert().unwrap().pre_concat(transform);
if let Some((c, t)) = radial.stops.first() { if let Some((c, t)) = radial.stops.first() {
add_single(c, *t); add_single(c, *t);
@ -286,8 +283,8 @@ fn convert_gradient(
// Correct the gradient's angle // Correct the gradient's angle
let cx = size.x.to_f32() * conic.center.x.get() as f32; let cx = size.x.to_f32() * conic.center.x.get() as f32;
let cy = size.y.to_f32() * conic.center.y.get() as f32; let cy = size.y.to_f32() * conic.center.y.get() as f32;
let actual_transform = transforms let actual_transform = state
.transform_chain_ .transform
.invert() .invert()
.unwrap() .unwrap()
.pre_concat(transform) .pre_concat(transform)

View File

@ -23,7 +23,8 @@ pub(crate) fn handle_shape(
shape.fill_rule, shape.fill_rule,
false, false,
surface, surface,
fc.state().transforms(shape.geometry.bbox_size()), fc.state(),
shape.geometry.bbox_size(),
)?; )?;
surface.fill_path(&path, fill); surface.fill_path(&path, fill);
@ -43,7 +44,8 @@ pub(crate) fn handle_shape(
stroke, stroke,
false, false,
surface, surface,
fc.state().transforms(shape.geometry.bbox_size()), fc.state(),
shape.geometry.bbox_size(),
)?; )?;
surface.stroke_path(&path, stroke); surface.stroke_path(&path, stroke);

View File

@ -27,7 +27,8 @@ pub(crate) fn handle_text(
FillRule::NonZero, FillRule::NonZero,
true, true,
surface, surface,
fc.state().transforms(Size::zero()), fc.state(),
Size::zero(),
)?; )?;
let text = t.text.as_str(); let text = t.text.as_str();
let size = t.size; let size = t.size;
@ -48,7 +49,7 @@ pub(crate) fn handle_text(
if let Some(stroke) = t if let Some(stroke) = t
.stroke .stroke
.as_ref() .as_ref()
.map(|s| paint::convert_stroke(gc, s, true, surface, fc.state().transforms(Size::zero()))) .map(|s| paint::convert_stroke(gc, s, true, surface, fc.state(), Size::zero()))
{ {
let stroke = stroke?; let stroke = stroke?;