This commit is contained in:
Laurenz Stampfl 2024-12-17 17:44:16 +01:00
parent db412f4387
commit 4186ef2c77
4 changed files with 56 additions and 58 deletions

View File

@ -6,7 +6,7 @@ use crate::page::PageLabelExt;
use crate::shape::handle_shape; use crate::shape::handle_shape;
use crate::text::handle_text; use crate::text::handle_text;
use crate::util::{convert_path, display_font, AbsExt, TransformExt}; use crate::util::{convert_path, display_font, AbsExt, TransformExt};
use crate::{paint, PdfOptions}; use crate::PdfOptions;
use krilla::destination::{NamedDestination, XyzDestination}; use krilla::destination::{NamedDestination, XyzDestination};
use krilla::error::KrillaError; use krilla::error::KrillaError;
use krilla::page::PageLabel; use krilla::page::PageLabel;
@ -24,19 +24,20 @@ use typst_library::layout::{
}; };
use typst_library::model::HeadingElem; use typst_library::model::HeadingElem;
use typst_library::text::{Font, Lang}; use typst_library::text::{Font, Lang};
use typst_library::visualize::{Geometry, Paint, Shape}; use typst_library::visualize::{Geometry, Paint};
use typst_syntax::Span; use typst_syntax::Span;
/// A state allowing us to keep track of transforms and container sizes,
/// which is mainly needed to resolve gradients and patterns correctly.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct State { pub(crate) struct State {
pub(crate) transform: Transform,
/// The full transform chain /// The full transform chain
transform_chain: Transform, transform_chain: Transform,
/// The transform of the current item.
pub(crate) transform: Transform,
/// The transform of first hard frame in the hierarchy. /// The transform of first hard frame in the hierarchy.
container_transform_chain: Transform, container_transform_chain: Transform,
/// The size of the first hard frame in the hierarchy. /// The size of the first hard frame in the hierarchy.
size: Size, container_size: Size,
} }
impl State { impl State {
@ -50,29 +51,26 @@ impl State {
transform_chain, transform_chain,
transform: Transform::identity(), transform: Transform::identity(),
container_transform_chain, container_transform_chain,
size, container_size: size,
} }
} }
pub(crate) fn size(&mut self, size: Size) { pub(crate) fn register_container(&mut self, size: Size) {
self.size = size; self.container_transform_chain = self.transform_chain;
self.container_size = size;
} }
pub(crate) fn transform(&mut self, transform: Transform) { pub(crate) fn pre_concat(&mut self, transform: Transform) {
self.transform = self.transform.pre_concat(transform); self.transform = self.transform.pre_concat(transform);
self.transform_chain = self.transform_chain.pre_concat(transform); self.transform_chain = self.transform_chain.pre_concat(transform);
} }
fn set_container_transform(&mut self) {
self.container_transform_chain = self.transform_chain;
}
/// Creates the [`Transforms`] structure for the current item. /// Creates the [`Transforms`] structure for the current item.
pub(crate) fn transforms(&self, size: Size) -> Transforms { pub(crate) fn transforms(&self, size: Size) -> Transforms {
Transforms { Transforms {
transform_chain_: self.transform_chain, transform_chain_: self.transform_chain,
container_transform_chain: self.container_transform_chain, container_transform_chain: self.container_transform_chain,
container_size: self.size, container_size: self.container_size,
size, size,
} }
} }
@ -296,8 +294,7 @@ pub(crate) fn handle_frame(
fc.push(); fc.push();
if frame.kind().is_hard() { if frame.kind().is_hard() {
fc.state_mut().set_container_transform(); fc.state_mut().register_container(frame.size());
fc.state_mut().size(frame.size());
} }
if let Some(fill) = fill { if let Some(fill) = fill {
@ -307,7 +304,7 @@ pub(crate) fn handle_frame(
for (point, item) in frame.items() { for (point, item) in frame.items() {
fc.push(); fc.push();
fc.state_mut().transform(Transform::translate(point.x, point.y)); fc.state_mut().pre_concat(Transform::translate(point.x, point.y));
match item { match item {
FrameItem::Group(g) => handle_group(fc, g, surface, gc)?, FrameItem::Group(g) => handle_group(fc, g, surface, gc)?,
@ -335,7 +332,7 @@ pub(crate) fn handle_group(
context: &mut GlobalContext, context: &mut GlobalContext,
) -> SourceResult<()> { ) -> SourceResult<()> {
fc.push(); fc.push();
fc.state_mut().transform(group.transform); fc.state_mut().pre_concat(group.transform);
let clip_path = group let clip_path = group
.clip_path .clip_path

View File

@ -13,7 +13,7 @@ use typst_library::visualize::{
}; };
use typst_utils::Numeric; use typst_utils::Numeric;
pub(crate) fn fill( pub(crate) fn convert_fill(
gc: &mut GlobalContext, gc: &mut GlobalContext,
paint_: &Paint, paint_: &Paint,
fill_rule_: FillRule, fill_rule_: FillRule,
@ -21,7 +21,7 @@ pub(crate) fn fill(
surface: &mut Surface, surface: &mut Surface,
transforms: Transforms, transforms: Transforms,
) -> SourceResult<krilla::path::Fill> { ) -> SourceResult<krilla::path::Fill> {
let (paint, opacity) = paint(gc, paint_, on_text, surface, transforms)?; let (paint, opacity) = convert_paint(gc, paint_, on_text, surface, transforms)?;
Ok(krilla::path::Fill { Ok(krilla::path::Fill {
paint, paint,
@ -30,14 +30,14 @@ pub(crate) fn fill(
}) })
} }
pub(crate) fn stroke( pub(crate) fn convert_stroke(
fc: &mut GlobalContext, fc: &mut GlobalContext,
stroke: &FixedStroke, stroke: &FixedStroke,
on_text: bool, on_text: bool,
surface: &mut Surface, surface: &mut Surface,
transforms: Transforms, transforms: Transforms,
) -> SourceResult<krilla::path::Stroke> { ) -> SourceResult<krilla::path::Stroke> {
let (paint, opacity) = paint(fc, &stroke.paint, on_text, surface, transforms)?; let (paint, opacity) = convert_paint(fc, &stroke.paint, on_text, surface, transforms)?;
Ok(krilla::path::Stroke { Ok(krilla::path::Stroke {
paint, paint,
@ -46,18 +46,18 @@ pub(crate) fn stroke(
line_join: stroke.join.to_krilla(), line_join: stroke.join.to_krilla(),
line_cap: stroke.cap.to_krilla(), line_cap: stroke.cap.to_krilla(),
opacity: NormalizedF32::new(opacity as f32 / 255.0).unwrap(), opacity: NormalizedF32::new(opacity as f32 / 255.0).unwrap(),
dash: stroke.dash.as_ref().map(|d| dash(d)), dash: stroke.dash.as_ref().map(|d| convert_dash(d)),
}) })
} }
fn dash(dash: &DashPattern<Abs, Abs>) -> krilla::path::StrokeDash { fn convert_dash(dash: &DashPattern<Abs, Abs>) -> krilla::path::StrokeDash {
krilla::path::StrokeDash { krilla::path::StrokeDash {
array: dash.array.iter().map(|e| e.to_f32()).collect(), array: dash.array.iter().map(|e| e.to_f32()).collect(),
offset: dash.phase.to_f32(), offset: dash.phase.to_f32(),
} }
} }
fn paint( fn convert_paint(
gc: &mut GlobalContext, gc: &mut GlobalContext,
paint: &Paint, paint: &Paint,
on_text: bool, on_text: bool,
@ -65,14 +65,20 @@ fn paint(
transforms: Transforms, transforms: Transforms,
) -> SourceResult<(krilla::paint::Paint, u8)> { ) -> SourceResult<(krilla::paint::Paint, u8)> {
match paint { match paint {
Paint::Solid(c) => { Paint::Solid(c) => Ok(convert_solid(c)),
let (p, alpha) = match c.space() { Paint::Gradient(g) => Ok(convert_gradient(g, on_text, transforms)),
Paint::Tiling(p) => convert_pattern(gc, p, on_text, surface, transforms),
}
}
fn convert_solid(color: &Color) -> (krilla::paint::Paint, u8) {
match color.space() {
ColorSpace::D65Gray => { ColorSpace::D65Gray => {
let components = c.to_vec4_u8(); let components = color.to_vec4_u8();
(krilla::color::luma::Color::new(components[0]).into(), components[3]) (krilla::color::luma::Color::new(components[0]).into(), components[3])
} }
ColorSpace::Cmyk => { ColorSpace::Cmyk => {
let components = c.to_vec4_u8(); let components = color.to_vec4_u8();
( (
krilla::color::cmyk::Color::new( krilla::color::cmyk::Color::new(
components[0], components[0],
@ -85,20 +91,15 @@ fn paint(
255, 255,
) )
} }
// Convert all remaining colors into RGB
_ => { _ => {
let (c, a) = c.to_krilla_rgb(); let (c, a) = color.to_krilla_rgb();
(c.into(), a) (c.into(), a)
} }
};
Ok((p, alpha))
}
Paint::Gradient(g) => Ok(convert_gradient(g, on_text, transforms)),
Paint::Tiling(p) => convert_pattern(gc, p, on_text, surface, transforms),
} }
} }
pub(crate) fn convert_pattern( fn convert_pattern(
gc: &mut GlobalContext, gc: &mut GlobalContext,
pattern: &Tiling, pattern: &Tiling,
on_text: bool, on_text: bool,

View File

@ -17,7 +17,7 @@ pub(crate) fn handle_shape(
if let Some(path) = convert_geometry(&shape.geometry) { if let Some(path) = convert_geometry(&shape.geometry) {
if let Some(paint) = &shape.fill { if let Some(paint) = &shape.fill {
let fill = paint::fill( let fill = paint::convert_fill(
gc, gc,
&paint, &paint,
shape.fill_rule, shape.fill_rule,
@ -38,7 +38,7 @@ pub(crate) fn handle_shape(
}); });
if let Some(stroke) = &stroke { if let Some(stroke) = &stroke {
let stroke = paint::stroke( let stroke = paint::convert_stroke(
gc, gc,
stroke, stroke,
false, false,

View File

@ -21,7 +21,7 @@ pub(crate) fn handle_text(
*gc.languages.entry(t.lang).or_insert(0) += t.glyphs.len(); *gc.languages.entry(t.lang).or_insert(0) += t.glyphs.len();
let font = convert_font(gc, t.font.clone())?; let font = convert_font(gc, t.font.clone())?;
let fill = paint::fill( let fill = paint::convert_fill(
gc, gc,
&t.fill, &t.fill,
FillRule::NonZero, FillRule::NonZero,
@ -48,7 +48,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::stroke(gc, s, true, surface, fc.state().transforms(Size::zero()))) .map(|s| paint::convert_stroke(gc, s, true, surface, fc.state().transforms(Size::zero())))
{ {
let stroke = stroke?; let stroke = stroke?;