diff --git a/crates/typst-pdf/src/image.rs b/crates/typst-pdf/src/image.rs index 4cfedf2b5..f3ca6d79c 100644 --- a/crates/typst-pdf/src/image.rs +++ b/crates/typst-pdf/src/image.rs @@ -21,7 +21,7 @@ pub(crate) fn handle_image( surface: &mut Surface, span: Span, ) -> SourceResult<()> { - surface.push_transform(&fc.state().transform.to_krilla()); + surface.push_transform(&fc.state().transform().to_krilla()); match image.kind() { ImageKind::Raster(raster) => { diff --git a/crates/typst-pdf/src/krilla.rs b/crates/typst-pdf/src/krilla.rs index f3c5dcfba..99634463f 100644 --- a/crates/typst-pdf/src/krilla.rs +++ b/crates/typst-pdf/src/krilla.rs @@ -31,7 +31,7 @@ use typst_syntax::Span; /// which is mainly needed to resolve gradients and patterns correctly. #[derive(Debug, Clone)] pub(crate) struct State { - pub(crate) transform: Transform, + transform: Transform, /// The transform of first hard frame in the hierarchy. container_transform: Transform, /// The size of the first hard frame in the hierarchy. diff --git a/crates/typst-pdf/src/link.rs b/crates/typst-pdf/src/link.rs index 761017c18..02ecbad26 100644 --- a/crates/typst-pdf/src/link.rs +++ b/crates/typst-pdf/src/link.rs @@ -28,7 +28,7 @@ pub(crate) fn handle_link( pos + Point::with_y(size.y), pos + size.to_point(), ] { - let t = point.transform(fc.state().transform); + let t = point.transform(fc.state().transform()); min_x.set_min(t.x); min_y.set_min(t.y); max_x.set_max(t.x); diff --git a/crates/typst-pdf/src/paint.rs b/crates/typst-pdf/src/paint.rs index da013fbd0..8eb183ad6 100644 --- a/crates/typst-pdf/src/paint.rs +++ b/crates/typst-pdf/src/paint.rs @@ -119,15 +119,7 @@ fn convert_pattern( surface: &mut Surface, state: &State, ) -> SourceResult<(krilla::paint::Paint, u8)> { - let transform = match pattern.unwrap_relative(on_text) { - RelativeTo::Self_ => Transform::identity(), - RelativeTo::Parent => state - .transform - .invert() - .unwrap() - .pre_concat(state.container_transform()), - } - .to_krilla(); + let transform = correct_transform(state, pattern.unwrap_relative(on_text)); let mut stream_builder = surface.stream_builder(); let mut surface = stream_builder.surface(); @@ -137,7 +129,7 @@ fn convert_pattern( let stream = stream_builder.finish(); let pattern = krilla::paint::Pattern { stream, - transform, + transform: transform.to_krilla(), width: (pattern.size().x + pattern.spacing().x).to_pt() as _, height: (pattern.size().y + pattern.spacing().y).to_pt() as _, }; @@ -155,12 +147,9 @@ fn convert_gradient( RelativeTo::Self_ => size, RelativeTo::Parent => state.container_size(), }; - let rotation = gradient.angle().unwrap_or_else(Angle::zero); - let transform = match gradient.unwrap_relative(on_text) { - RelativeTo::Self_ => state.transform, - RelativeTo::Parent => state.container_transform(), - }; + let rotation = gradient.angle().unwrap_or_else(Angle::zero); + let base_transform = correct_transform(state, gradient.unwrap_relative(on_text)); let angle = rotation; @@ -176,9 +165,6 @@ fn convert_gradient( match &gradient { Gradient::Linear(linear) => { - let actual_transform = - state.transform().invert().unwrap().pre_concat(transform); - if let Some((c, t)) = linear.stops.first() { add_single(c, *t); } @@ -223,7 +209,7 @@ fn convert_gradient( y1, x2, y2, - transform: actual_transform.to_krilla().pre_concat( + transform: base_transform.to_krilla().pre_concat( krilla::geom::Transform::from_scale(size.x.to_f32(), size.y.to_f32()), ), spread_method: SpreadMethod::Pad, @@ -234,9 +220,6 @@ fn convert_gradient( (linear.into(), 255) } Gradient::Radial(radial) => { - let actual_transform = - state.transform.invert().unwrap().pre_concat(transform); - if let Some((c, t)) = radial.stops.first() { add_single(c, *t); } @@ -269,7 +252,7 @@ fn convert_gradient( cx: radial.center.x.get() as f32, cy: radial.center.y.get() as f32, cr: radial.radius.get() as f32, - transform: actual_transform.to_krilla().pre_concat( + transform: base_transform.to_krilla().pre_concat( krilla::geom::Transform::from_scale(size.x.to_f32(), size.y.to_f32()), ), spread_method: SpreadMethod::Pad, @@ -283,11 +266,7 @@ fn convert_gradient( // Correct the gradient's angle 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 actual_transform = state - .transform - .invert() - .unwrap() - .pre_concat(transform) + let actual_transform = base_transform .pre_concat(Transform::rotate_at( angle, Abs::pt(cx as f64), @@ -365,3 +344,20 @@ fn convert_gradient( } } } + +fn correct_transform(state: &State, relative: RelativeTo) -> Transform { + // In krilla, if we have a shape with a transform and a complex paint, + // then the paint will inherit the transform of the shape. + match relative { + // Because of the above, we don't need to apply an additional transform here. + RelativeTo::Self_ => Transform::identity(), + // Because of the above, we need to first reverse the transform that will be + // applied from the shape, and then re-apply the transform that is used for + // the next parent container. + RelativeTo::Parent => state + .transform() + .invert() + .unwrap() + .pre_concat(state.container_transform()), + } +} diff --git a/crates/typst-pdf/src/shape.rs b/crates/typst-pdf/src/shape.rs index 7e58b9f2c..135a2728a 100644 --- a/crates/typst-pdf/src/shape.rs +++ b/crates/typst-pdf/src/shape.rs @@ -13,7 +13,7 @@ pub(crate) fn handle_shape( surface: &mut Surface, gc: &mut GlobalContext, ) -> SourceResult<()> { - surface.push_transform(&fc.state().transform.to_krilla()); + surface.push_transform(&fc.state().transform().to_krilla()); if let Some(path) = convert_geometry(&shape.geometry) { if let Some(paint) = &shape.fill { diff --git a/crates/typst-pdf/src/text.rs b/crates/typst-pdf/src/text.rs index 8187e6849..7e4d5856f 100644 --- a/crates/typst-pdf/src/text.rs +++ b/crates/typst-pdf/src/text.rs @@ -34,7 +34,7 @@ pub(crate) fn handle_text( let size = t.size; let glyphs: &[PdfGlyph] = TransparentWrapper::wrap_slice(t.glyphs.as_slice()); - surface.push_transform(&fc.state().transform.to_krilla()); + surface.push_transform(&fc.state().transform().to_krilla()); surface.fill_glyphs( krilla::geom::Point::from_xy(0.0, 0.0), fill,