summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorSébastien d'Herbais de Thun <sebastien.d.herbais@gmail.com>2023-11-08 15:51:25 +0100
committerGitHub <noreply@github.com>2023-11-08 15:51:25 +0100
commitd7fea7077ebe4df44edff32b2b3a6e4a00775974 (patch)
tree810edbfd0090668497b098bd6ac893cb574d0c55 /crates
parentccbe901cb70f963a546b0950543f77d5536cce67 (diff)
Gradient Part 5c: Fix gradient rotation on text & math (#2606)
Diffstat (limited to 'crates')
-rw-r--r--crates/typst-pdf/src/color.rs15
-rw-r--r--crates/typst-pdf/src/gradient.rs90
-rw-r--r--crates/typst-pdf/src/page.rs17
3 files changed, 42 insertions, 80 deletions
diff --git a/crates/typst-pdf/src/color.rs b/crates/typst-pdf/src/color.rs
index 80d277ed..999f604e 100644
--- a/crates/typst-pdf/src/color.rs
+++ b/crates/typst-pdf/src/color.rs
@@ -277,7 +277,7 @@ pub(super) trait PaintEncode {
fn set_as_fill(&self, ctx: &mut PageContext, on_text: bool, transforms: Transforms);
/// Set the paint as the stroke color.
- fn set_as_stroke(&self, ctx: &mut PageContext, on_text: bool, transforms: Transforms);
+ fn set_as_stroke(&self, ctx: &mut PageContext, transforms: Transforms);
}
impl PaintEncode for Paint {
@@ -288,15 +288,10 @@ impl PaintEncode for Paint {
}
}
- fn set_as_stroke(
- &self,
- ctx: &mut PageContext,
- on_text: bool,
- transforms: Transforms,
- ) {
+ fn set_as_stroke(&self, ctx: &mut PageContext, transforms: Transforms) {
match self {
- Self::Solid(c) => c.set_as_stroke(ctx, on_text, transforms),
- Self::Gradient(gradient) => gradient.set_as_stroke(ctx, on_text, transforms),
+ Self::Solid(c) => c.set_as_stroke(ctx, transforms),
+ Self::Gradient(gradient) => gradient.set_as_stroke(ctx, transforms),
}
}
}
@@ -355,7 +350,7 @@ impl PaintEncode for Color {
}
}
- fn set_as_stroke(&self, ctx: &mut PageContext, _: bool, _: Transforms) {
+ fn set_as_stroke(&self, ctx: &mut PageContext, _: Transforms) {
match self {
Color::Luma(_) => {
ctx.parent.colors.d65_gray(&mut ctx.parent.alloc);
diff --git a/crates/typst-pdf/src/gradient.rs b/crates/typst-pdf/src/gradient.rs
index 37702cea..3d508415 100644
--- a/crates/typst-pdf/src/gradient.rs
+++ b/crates/typst-pdf/src/gradient.rs
@@ -26,21 +26,21 @@ pub struct PdfGradient {
pub aspect_ratio: Ratio,
/// The gradient.
pub gradient: Gradient,
- /// Whether the gradient is applied to text.
- pub on_text: bool,
+ /// The corrected angle of the gradient.
+ pub angle: Angle,
}
/// Writes the actual gradients (shading patterns) to the PDF.
/// This is performed once after writing all pages.
pub(crate) fn write_gradients(ctx: &mut PdfContext) {
- for PdfGradient { transform, aspect_ratio, gradient, on_text } in
+ for PdfGradient { transform, aspect_ratio, gradient, angle } in
ctx.gradient_map.items().cloned().collect::<Vec<_>>()
{
let shading = ctx.alloc.bump();
ctx.gradient_refs.push(shading);
let mut shading_pattern = match &gradient {
- Gradient::Linear(linear) => {
+ Gradient::Linear(_) => {
let shading_function = shading_function(ctx, &gradient);
let mut shading_pattern = ctx.pdf.shading_pattern(shading);
let mut shading = shading_pattern.function_shading();
@@ -49,14 +49,24 @@ pub(crate) fn write_gradients(ctx: &mut PdfContext) {
ctx.colors
.write(gradient.space(), shading.color_space(), &mut ctx.alloc);
- let angle = Gradient::correct_aspect_ratio(linear.angle, aspect_ratio);
let (sin, cos) = (angle.sin(), angle.cos());
- let length = sin.abs() + cos.abs();
+ let (x1, y1, x2, y2): (f64, f64, f64, f64) = match angle.quadrant() {
+ Quadrant::First => (0.0, 0.0, cos, sin),
+ Quadrant::Second => (1.0, 0.0, cos + 1.0, sin),
+ Quadrant::Third => (1.0, 1.0, cos + 1.0, sin + 1.0),
+ Quadrant::Fourth => (0.0, 1.0, cos, sin + 1.0),
+ };
+
+ let clamp = |i: f64| if i < 1e-4 { 0.0 } else { i.clamp(0.0, 1.0) };
+ let x1 = clamp(x1);
+ let y1 = clamp(y1);
+ let x2 = clamp(x2);
+ let y2 = clamp(y2);
shading
.anti_alias(gradient.anti_alias())
.function(shading_function)
- .coords([0.0, 0.0, length as f32, 0.0])
+ .coords([x1 as f32, y1 as f32, x2 as f32, y2 as f32])
.extend([true; 2]);
shading.finish();
@@ -90,7 +100,7 @@ pub(crate) fn write_gradients(ctx: &mut PdfContext) {
shading_pattern
}
Gradient::Conic(conic) => {
- let vertices = compute_vertex_stream(conic, aspect_ratio, on_text);
+ let vertices = compute_vertex_stream(conic, aspect_ratio);
let stream_shading_id = ctx.alloc.bump();
let mut stream_shading =
@@ -265,15 +275,10 @@ impl PaintEncode for Gradient {
ctx.content.set_fill_pattern(None, name);
}
- fn set_as_stroke(
- &self,
- ctx: &mut PageContext,
- on_text: bool,
- transforms: Transforms,
- ) {
+ fn set_as_stroke(&self, ctx: &mut PageContext, transforms: Transforms) {
ctx.reset_stroke_color_space();
- let id = register_gradient(ctx, self, on_text, transforms);
+ let id = register_gradient(ctx, self, false, transforms);
let name = Name(id.as_bytes());
ctx.content.set_stroke_color_space(ColorSpaceOperand::Pattern);
@@ -296,33 +301,20 @@ fn register_gradient(
if transforms.size.y.is_zero() {
transforms.size.y = Abs::pt(1.0);
}
-
let size = match gradient.unwrap_relative(on_text) {
Relative::Self_ => transforms.size,
Relative::Parent => transforms.container_size,
};
- // Correction for y-axis flipping on text.
- let angle = gradient.angle().unwrap_or_else(Angle::zero);
- let angle = if on_text { Angle::rad(TAU as f64) - angle } else { angle };
-
let (offset_x, offset_y) = match gradient {
Gradient::Conic(conic) => (
-size.x * (1.0 - conic.center.x.get() / 2.0) / 2.0,
-size.y * (1.0 - conic.center.y.get() / 2.0) / 2.0,
),
- _ => match angle.quadrant() {
- Quadrant::First => (Abs::zero(), Abs::zero()),
- Quadrant::Second => (size.x, Abs::zero()),
- Quadrant::Third => (size.x, size.y),
- Quadrant::Fourth => (Abs::zero(), size.y),
- },
+ _ => (Abs::zero(), Abs::zero()),
};
- let rotation = match gradient {
- Gradient::Conic(_) => Angle::zero(),
- _ => angle,
- };
+ let rotation = gradient.angle().unwrap_or_else(Angle::zero);
let transform = match gradient.unwrap_relative(on_text) {
Relative::Self_ => transforms.transform,
@@ -344,13 +336,9 @@ fn register_gradient(
.pre_concat(Transform::scale(
Ratio::new(size.x.to_pt() * scale_offset),
Ratio::new(size.y.to_pt() * scale_offset),
- ))
- .pre_concat(Transform::rotate(Gradient::correct_aspect_ratio(
- rotation,
- size.aspect_ratio(),
- ))),
+ )),
gradient: gradient.clone(),
- on_text,
+ angle: Gradient::correct_aspect_ratio(rotation, size.aspect_ratio()),
};
let index = ctx.parent.gradient_map.insert(pdf_gradient);
@@ -383,16 +371,9 @@ fn write_patch(
c0: [u16; 3],
c1: [u16; 3],
angle: Angle,
- on_text: bool,
) {
- let mut theta = -TAU * t + angle.to_rad() as f32 + PI;
- let mut theta1 = -TAU * t1 + angle.to_rad() as f32 + PI;
-
- // Correction for y-axis flipping on text.
- if on_text {
- theta = (TAU - theta).rem_euclid(TAU);
- theta1 = (TAU - theta1).rem_euclid(TAU);
- }
+ let theta = -TAU * t + angle.to_rad() as f32 + PI;
+ let theta1 = -TAU * t1 + angle.to_rad() as f32 + PI;
let (cp1, cp2) =
control_point(Point::new(Abs::pt(0.5), Abs::pt(0.5)), 0.5, theta, theta1);
@@ -453,11 +434,7 @@ fn control_point(c: Point, r: f32, angle_start: f32, angle_end: f32) -> (Point,
}
#[comemo::memoize]
-fn compute_vertex_stream(
- conic: &ConicGradient,
- aspect_ratio: Ratio,
- on_text: bool,
-) -> Arc<Vec<u8>> {
+fn compute_vertex_stream(conic: &ConicGradient, aspect_ratio: Ratio) -> Arc<Vec<u8>> {
// Generated vertices for the Coons patches
let mut vertices = Vec::new();
@@ -534,18 +511,9 @@ fn compute_vertex_stream(
conic.space.convert(c),
c0,
angle,
- on_text,
);
- write_patch(
- &mut vertices,
- t_prime,
- t_prime,
- c0,
- c1,
- angle,
- on_text,
- );
+ write_patch(&mut vertices, t_prime, t_prime, c0, c1, angle);
write_patch(
&mut vertices,
@@ -554,7 +522,6 @@ fn compute_vertex_stream(
c1,
conic.space.convert(c_next),
angle,
- on_text,
);
t_x = t_next;
@@ -570,7 +537,6 @@ fn compute_vertex_stream(
conic.space.convert(c),
conic.space.convert(c_next),
angle,
- on_text,
);
t_x = t_next;
diff --git a/crates/typst-pdf/src/page.rs b/crates/typst-pdf/src/page.rs
index c842a01f..04640945 100644
--- a/crates/typst-pdf/src/page.rs
+++ b/crates/typst-pdf/src/page.rs
@@ -322,7 +322,7 @@ impl State {
}
/// Subset of the state used to calculate the transform of gradients and patterns.
-#[derive(Clone, Copy)]
+#[derive(Debug, Clone, Copy)]
pub(super) struct Transforms {
/// The transform of the current item.
pub transform: Transform,
@@ -385,6 +385,9 @@ impl PageContext<'_, '_> {
fn transform(&mut self, transform: Transform) {
let Transform { sx, ky, kx, sy, tx, ty } = transform;
self.state.transform = self.state.transform.pre_concat(transform);
+ if self.state.container_transform.is_identity() {
+ self.state.container_transform = self.state.transform;
+ }
self.content.transform([
sx.get() as _,
ky.get() as _,
@@ -449,7 +452,7 @@ impl PageContext<'_, '_> {
miter_limit,
} = stroke;
- paint.set_as_stroke(self, false, transforms);
+ paint.set_as_stroke(self, transforms);
self.content.set_line_width(thickness.to_f32());
if self.state.stroke.as_ref().map(|s| &s.line_cap) != Some(line_cap) {
@@ -517,12 +520,10 @@ fn write_group(ctx: &mut PageContext, pos: Point, group: &GroupItem) {
if group.frame.kind().is_hard() {
ctx.group_transform(
- translation
- .pre_concat(
- ctx.state
- .transform
- .post_concat(ctx.state.container_transform.invert().unwrap()),
- )
+ ctx.state
+ .transform
+ .post_concat(ctx.state.container_transform.invert().unwrap())
+ .pre_concat(translation)
.pre_concat(group.transform),
);
ctx.size(group.frame.size());